| From cc84e464e882528286dffb8cefb463478690c4e1 Mon Sep 17 00:00:00 2001 |
| From: Nicolas Boichat <drinkcat@chromium.org> |
| Date: Thu, 7 Mar 2019 18:17:32 +0800 |
| Subject: [PATCH 1/3] MTK-TOT 202 |
| |
| https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1317245/202 |
| |
| Add regulators, change required DT entries. |
| |
| BUG=b:124335972 |
| TEST=Boot kukui P2 |
| |
| Change-Id: I9992bb3b1427a3baf20fe99c08e2252d9900d83d |
| Signed-off-by: Nicolas Boichat <drinkcat@chromium.org> |
| Signed-off-by: Eddie Huang <eddie.huang@mediatek.com> |
| |
| Revert "FROMLIST: arm64: dts: add display nodes for mt8183" |
| |
| This reverts commit a19d712b63adaa622bdb7b43ddb1323b81de5847. |
| |
| BUG=b:130781510 |
| TEST=boot to shell |
| |
| Change-Id: I082ce8df0b38f35abb6605cda40058dd44174957 |
| Signed-off-by: CK Hu <ck.hu@mediatek.com> |
| |
| BACKPORT: FROMLIST: arm64: dts: add display nodes for mt8183 |
| |
| This patch add display nodes for mt8183 |
| |
| Signed-off-by: Yongqiang Niu <yongqiang.niu@mediatek.com> |
| |
| (am from https://patchwork.kernel.org/patch/10976719/) |
| BUG=b:130781510 |
| TEST=boot to welcome screen |
| |
| Change-Id: Ia099f934da5d1f762e6337e9f48667883518a3fa |
| Signed-off-by: CK Hu <ck.hu@mediatek.com> |
| Signed-off-by: Eddie Huang <eddie.huang@mediatek.com> |
| |
| CHROMIUM: drm/panel: panel-innolux: Allow 2 reset pins for panel |
| |
| This is useful when there is a bridge between the SoC and the |
| panel. |
| |
| BUG=b:123669273 |
| TEST=Boot rev2 |
| |
| [rebase note: see b/124335972 for justification of CHROMIUM tag] |
| |
| Change-Id: I487b27f858a262c9bfea16aab8b0321229846025 |
| Signed-off-by: Nicolas Boichat <drinkcat@chromium.org> |
| |
| CHROMIUM: drm/panel: panel-innolux: Add support for P097PFZ behind SSD2858 |
| |
| Add commands to setup P097PFZ behing SSD2858 (4 to 8 lanes bridge). |
| |
| For some unclear reasons, the initialization commands that P097PFZ |
| is supposed to require... don't seem to be required (and actually |
| break display if we sent them). |
| |
| We also need to change the code that sends the MIPI commands to add |
| necessary delays. |
| |
| BUG=b:123669273 |
| TEST=Boot kukui rev2 |
| |
| [rebase note: see b/124335972 for justification of CHROMIUM tag. |
| To make this cleaner, we should probably use a proper DRM bridge to |
| setup the bridge (instead of hacking the panel driver).] |
| |
| Change-Id: I0cbe84a496bfd029be4db1fe05e316659eab3468 |
| Signed-off-by: Nicolas Boichat <drinkcat@chromium.org> |
| Signed-off-by: Jitao Shi <jitao.shi@mediatek.com> |
| |
| DO-NOT-SUBMIT: QCA wifi patches SQUASH |
| |
| SQUASH of kukui wifi tot #32 |
| |
| including: |
| |
| basic functionality: |
| None |
| |
| bug fix: |
| DO-NOT-SUBMIT: kukui: ath10k: move some warning msg to dbg(CL:1639747/1) |
| FROMLIST: ath10k: add report MIC error for sdio chip(CL:1630539/2) |
| FROMLIST: ath10k: change firmware file name for UTF mode of SDIO/USB(CL:1628527/2) |
| FROMLIST: ath10k: add missing error handling(CL:1627070/4) |
| FROMLIST: ath10k: acquire lock to fix lockdep's warning(CL:1594406/10) |
| FROMLIST: ath10k: remove mmc_hw_reset while hif power down(CL:1585667/14) |
| FROMLIST: ath10k: add support for firmware crash recovery on SDIO chip(CL:1568867/19) |
| |
| BUG=b:121980879 |
| TEST=1) checkout CL:1317245/195 |
| 2) revert 1b6091c(old suqash) |
| 3) rebase on m/master |
| 4) cherry-pick this one |
| 5) build, boot and check wifi connection |
| |
| Change-Id: Iaebb8cf6f4604ec52b6a0b8500aef5d2d20b182c |
| |
| DO-NOT-SUBMIT: Kukui ToT |
| |
| Minimal set of patches to boot kukui |
| |
| BUG=b:109911488 |
| TEST=Boot to shell |
| |
| Change-Id: I4b8194d5cd0b31670bb2ed7310747bed38775545 |
| |
| FROMLIST: pinctrl: mediatek: Ignore interrupts that are wake only during resume |
| |
| Before suspending, mtk-eint would set the interrupt mask to the |
| one in wake_mask. However, some of these interrupts may not have a |
| corresponding interrupt handler, or the interrupt may be disabled. |
| |
| On resume, the eint irq handler would trigger nevertheless, |
| and irq/pm.c:irq_pm_check_wakeup would be called, which would |
| try to call irq_disable. However, if the interrupt is not enabled |
| (irqd_irq_disabled(&desc->irq_data) is true), the call does nothing, |
| and the interrupt is left enabled in the eint driver. |
| |
| Especially for level-sensitive interrupts, this will lead to an |
| interrupt storm on resume. |
| |
| If we detect that an interrupt is only in wake_mask, but not in |
| cur_mask, we can just mask it out immediately (as mtk_eint_resume |
| would do anyway at a later stage in the resume sequence, when |
| restoring cur_mask). |
| |
| Fixes: bf22ff45bed ("genirq: Avoid unnecessary low level irq function calls") |
| Signed-off-by: Nicolas Boichat <drinkcat@chromium.org> |
| (am from https://patchwork.kernel.org/patch/10921143/) |
| (also found at https://lkml.kernel.org/r/20190429035515.73611-2-drinkcat@chromium.org) |
| |
| BUG=b:129240721 |
| TEST=on kukui, EC can wake system from suspend |
| |
| Change-Id: Ic38985aa7c4dd4a4c5ad6595809ac8a4bc320ace |
| Signed-off-by: Nicolas Boichat <drinkcat@chromium.org> |
| |
| FROMLIST: pinctrl: mediatek: Update cur_mask in mask/mask ops |
| |
| During suspend/resume, mtk_eint_mask may be called while |
| wake_mask is active. For example, this happens if a wake-source |
| with an active interrupt handler wakes the system: |
| irq/pm.c:irq_pm_check_wakeup would disable the interrupt, so |
| that it can be handled later on in the resume flow. |
| |
| However, this may happen before mtk_eint_do_resume is called: |
| in this case, wake_mask is loaded, and cur_mask is restored |
| from an older copy, re-enabling the interrupt, and causing |
| an interrupt storm (especially for level interrupts). |
| |
| Instead, we just record mask/unmask changes in cur_mask. This |
| also avoids the need to read the current mask in eint_do_suspend, |
| and we can remove mtk_eint_chip_read_mask function. |
| |
| Signed-off-by: Nicolas Boichat <drinkcat@chromium.org> |
| (am from https://patchwork.kernel.org/patch/10921147/) |
| (also found at https://lkml.kernel.org/r/20190429035515.73611-3-drinkcat@chromium.org) |
| |
| BUG=b:129240721 |
| TEST=on kukui, EC can wake system from suspend |
| |
| Change-Id: I77d55cfb9ad3a0a0078f931695d6aeb8a6e5c217 |
| Signed-off-by: Nicolas Boichat <drinkcat@chromium.org> |
| |
| WIP: usb: mtu3: Modification for MTU3 dualrole mode switch |
| |
| Usage: |
| to host: |
| echo host > /sys/kernel/debug/usb/11201000.usb/mode |
| to device: |
| echo device > /sys/kernel/debug/usb/11201000.usb/mode |
| |
| BUG=b:109911488 |
| TEST=Boot to shell and do host/device mode change |
| |
| Change-Id: Ie6d5b864ea36a40b959df6d06d4e038b7c3d74ee |
| Signed-off-by: Jumin Li <jumin.li@mediatek.com> |
| |
| CHROMIUM: arm64: dts: mt8183: Add manual switch property |
| |
| Enable manual dual mode |
| Set maximum-speed as high-speed |
| |
| BUG=b:109911488 |
| TEST=build and boot to shell and do usb features test |
| |
| Change-Id: Iea92b3d15823229cf9816275b22cc582ad470aa9 |
| Signed-off-by: Jumin Li <jumin.li@mediatek.com> |
| |
| DO-NOT-SUBMIT: Snapshot of CMDQ ToT |
| |
| Snapshot of CMDQ ToT patch set 11 (FROMLIST v3) |
| |
| BUG=b:109911488 |
| TEST=Display UI |
| |
| Change-Id: Ie936fd7f2c16875d16a1cb87402a23d2609fa303 |
| Signed-off-by: CK Hu <ck.hu@mediatek.com> |
| |
| BACKPORT: FROMLIST: arm64: dts: add gce node for mt8183 |
| |
| add gce device node for mt8183 |
| (am from https://patchwork.kernel.org/patch/10932479/) |
| |
| BUG=b:109911488 |
| TEST=build and boot to shell |
| |
| Change-Id: I1edbdd1be9db1f128d984adc81895cb80c61e4eb |
| Signed-off-by: Bibby Hsieh <bibby.hsieh@mediatek.com> |
| Signed-off-by: CK Hu <ck.hu@mediatek.com> |
| |
| DO-NOT-SUBMIT: Snapshot of VPU patches |
| |
| Snapshot of VPU patches. |
| |
| BUG=b:109911488 |
| TEST=Boot to shell |
| |
| Change-Id: I47a3afb7edafea353eea566d3fe6468feeedf9cd |
| Signed-off-by: CK Hu <ck.hu@mediatek.com> |
| Signed-off-by: Eddie Huang <eddie.huang@mediatek.com> |
| |
| DO-NOT-SUBMIT: arm64: dts: mt8183: add vpu node |
| |
| New add vpu node |
| |
| BUG=b:109911488 |
| TEST=build and boot to shell |
| |
| Change-Id: I0868a628e8c9f30e550ad034fd786ea566ca044b |
| Signed-off-by: Erin Lo <erin.lo@mediatek.com> |
| Signed-off-by: Eddie Huang <eddie.huang@mediatek.com> |
| |
| FROMLIST: dt-bindings: soc: Add MT8183 emi dt-bindings |
| |
| Add emi dt-bindings of MT8183 in binding document. |
| |
| Signed-off-by: Xi Chen <xixi.chen@mediatek.com> |
| (am from https://patchwork.kernel.org/patch/10921319/) |
| [eddie.huang: remove change-id in commit message] |
| |
| BUG=b:109911488 |
| TEST=build pass and boot to shell |
| |
| Change-Id: I7182f3eda5835af8bf081d1056228bf73cb63f61 |
| Signed-off-by: Eddie Huang <eddie.huang@mediatek.com> |
| |
| BACKPORT: FROMLIST: arm64: dts: mt8183: add emi node |
| |
| Add emi dts node. |
| |
| (am from https://patchwork.kernel.org/patch/10921629/) |
| [eddie.huang: remove change-id in commit message. |
| Fix context confclit] |
| |
| BUG=b:109911488 |
| TEST=build pass and boot to shell |
| |
| Change-Id: I0b84e566d20af6fcb33b91f69be2f14f40a6e540 |
| Signed-off-by: Eddie Huang <eddie.huang@mediatek.com> |
| |
| BACKPORT: FROMLIST: mt8183: emi: add bandwidth driver support |
| |
| EMI provides interface for get bandwidth on every 1 miliseconds. |
| Currently, just support GPU bandwidth info. |
| |
| Signed-off-by: Xi Chen <xixi.chen@mediatek.com> |
| |
| (am from https://patchwork.kernel.org/patch/10921627/) |
| [eddie.huang: fix context confclit. Remove change-id in commit message. |
| Add MTK_EMI_MBW description to let defconfig to select] |
| |
| BUG=b:109911488 |
| TEST=build pass and boot to shell |
| |
| Change-Id: I10d8f36d78c1dca8d91bc0e242fe83209a6c8190 |
| Signed-off-by: Eddie Huang <eddie.huang@mediatek.com> |
| |
| WIP: clk: mediatek: mt8183: Register 13MHz clock earlier for clocksource |
| |
| The 13MHz clock should be registered before clocksource driver is |
| initialized. Use CLK_OF_DECLARE_DRIVER() to guarantee. |
| |
| BUG=b:126007177 |
| TEST=build and boot to shell |
| |
| Change-Id: I63f1c881bb4053da4214ddb14d725b37fd108ffd |
| Signed-off-by: Weiyi Lu <weiyi.lu@mediatek.com> |
| Signed-off-by: Dehui Sun <dehui.sun@mediatek.com> |
| |
| WIP: arm64: dts: mt8183: add systimer0 node |
| |
| Add systimer0 node to the mt8183's devicetree. |
| |
| BUG=b:109911488 |
| BUG=None |
| TEST=build and boot to shell |
| |
| Change-Id: I816152c47ad0aa86eb269b654d3a22d953f60c81 |
| Signed-off-by: Dehui Sun <dehui.sun@mediatek.com> |
| |
| WIP: serial: 8250-mtk: modify serial driver |
| |
| modify serial power management function. |
| |
| BUG=b:129106594 |
| TEST=build and boot to shell |
| |
| Change-Id: I23051b5f23ad314be518fce994d7affb2a8b1a27 |
| Signed-off-by: Changqi Hu <changqi.hu@mediatek.com> |
| |
| WIP: thermal: mtk_thermal: add suspend/resume callback |
| |
| Added suspend/resume callback to disable/enable Mediatek thermal sensor |
| respectively. Since thermal power domain is off in suspend, thermal driver |
| needs re-initialization during resume. |
| |
| BUG=none |
| TEST: boot to shell |
| |
| Change-Id: I43f9af5c2d2b682f985eb570d6ed984243772e91 |
| Signed-off-by: Louis Yu <louis.yu@mediatek.com> |
| Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org> |
| |
| HACK: clkdbg: clkdbg support for 8183 |
| |
| Clkdbg provides commands to view clock info and operate clocks, |
| such as enable/disable clocks and change their rate. Use the |
| following command to see available clkdbg commands: |
| . |
| echo cmds > /proc/clkdbg ; cat /proc/clkdbg |
| . |
| |
| BUG=b:109911488 |
| TEST=build and boot to shell |
| |
| Change-Id: Ieb6a05b7f5ee9330cd10a02fafbdfc6654163f5e |
| Signed-off-by: Weiyi Lu <weiyi.lu@mediatek.com> |
| |
| HACK: clkchk: add clkchk support for 8183 |
| |
| dump the clocks those still ON during system suspend |
| |
| BUG=b:109911488 |
| TEST=build and boot to shell |
| |
| Change-Id: Ifb7a0d683aed75b57161b27d76efd4318395dbca |
| Signed-off-by: Weiyi Lu <weiyi.lu@mediatek.com> |
| |
| HACK: sdio: mediatek: add sdio debug driver |
| |
| New add sdio debug driver |
| |
| BUG=b:109911488 |
| TEST=cmd test is ok |
| |
| Change-Id: Id1f53eb395a035caffc03a3a6f0e6c554c63a9ad |
| Signed-off-by: jjian zhou <jjian.zhou@mediatek.com> |
| |
| CHROMIUM: config: Enable MT8183 usb dualrole mode configs |
| |
| Features be enabled as follow: |
| USB mtu3 dualrole mode |
| USB gadget configfs functions |
| USB gadget ACM/MASS_STORAGE/SERIAL features |
| |
| The change is generated from the following commands: |
| |
| cat <<EOF | tee -a \ |
| chromeos/config/arm64/chromiumos-arm64.flavour.config \ |
| chromeos/config/arm64/chromiumos-mediatek.flavour.config |
| |
| CONFIG_USB_CONFIGFS=m |
| CONFIG_USB_CONFIGFS_ACM=y |
| CONFIG_USB_CONFIGFS_MASS_STORAGE=y |
| CONFIG_USB_CONFIGFS_SERIAL=y |
| CONFIG_USB_F_ACM=y |
| CONFIG_USB_F_FS=m |
| CONFIG_USB_F_MASS_STORAGE=y |
| CONFIG_USB_F_SERIAL=y |
| CONFIG_USB_MTU3_DEBUG=y |
| CONFIG_USB_MTU3_DUAL_ROLE=y |
| |
| EOF |
| |
| ./chromeos/scripts/kernelconfig olddefconfig |
| |
| BUG=b:109911488 |
| TEST=build and boot to shell and test the function of these configs |
| |
| Change-Id: Ie957cae98b3331668f4e29332c25714776e5fe80 |
| Signed-off-by: Jumin Li <jumin.li@mediatek.com> |
| Signed-off-by: Eddie Huang <eddie.huang@mediatek.com> |
| |
| CHROMIUM: config: Enable MT8183 emi configs |
| |
| The change is generated from the following commands: |
| |
| cat <<EOF | tee -a \ |
| chromeos/config/arm64/chromiumos-arm64.flavour.config \ |
| chromeos/config/arm64/chromiumos-mediatek.flavour.config |
| |
| CONFIG_MTK_EMI_MBW=y |
| |
| EOF |
| |
| ./chromeos/scripts/kernelconfig olddefconfig |
| |
| BUG=b:109911488 |
| TEST=build and boot to shell |
| |
| Change-Id: I9c92096719b72c077258a5d2b52b3ccec272af39 |
| Signed-off-by: Xi Chen <xixi.chen@mediatek.com> |
| Signed-off-by: Eddie Huang <eddie.huang@mediatek.com> |
| |
| FROMLIST: PM / devfreq: Generic CPU frequency to device frequency mapping governor |
| |
| Many CPU architectures have caches that can scale independent of the CPUs. |
| Frequency scaling of the caches is necessary to make sure the cache is not |
| a performance bottleneck that leads to poor performance and power. The same |
| idea applies for RAM/DDR. |
| |
| To achieve this, this patch adds a generic devfreq governor that takes the |
| current frequency of each CPU frequency domain and then adjusts the |
| frequency of the cache (or any devfreq device) based on the frequency of |
| the CPUs. It listens to CPU frequency transition notifiers to keep itself |
| up to date on the current CPU frequency. |
| |
| To decide the frequency of the device, the governor does one of the |
| following: |
| |
| * Uses a CPU frequency to device frequency mapping table |
| - Either one mapping table used for all CPU freq policies (typically used |
| for system with homogeneous cores/clusters that have the same OPPs). |
| - One mapping table per CPU freq policy (typically used for ASMP systems |
| with heterogeneous CPUs with different OPPs) |
| |
| OR |
| |
| * Scales the device frequency in proportion to the CPU frequency. So, if |
| the CPUs are running at their max frequency, the device runs at its max |
| frequency. If the CPUs are running at their min frequency, the device |
| runs at its min frequency. And interpolated for frequencies in between. |
| |
| Signed-off-by: Saravana Kannan <skannan@codeaurora.org> |
| |
| (am from https://patchwork.kernel.org/patch/10553171/) |
| |
| BUG=b:122571050 |
| TEST=boot to kukui |
| |
| Change-Id: I299eecb1f1bb12679fcb394a28fb2655760568d2 |
| Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org> |
| |
| CHROMIUM: config: Enable cpufreq-map governor for mtk-cci |
| |
| cat <<EOF | tee -a \ |
| chromeos/config/arm64/chromiumos-mediatek.flavour.config |
| |
| CONFIG_DEVFREQ_GOV_CPUFREQ_MAP=y |
| |
| EOF |
| |
| ./chromeos/scripts/kernelconfig olddefconfig |
| |
| BUG=b:122571050 |
| TEST=echo cpufreq-map > /sys/class/devfreq/devfreq0/governor; |
| observe /sys/class/devfreq/devfreq0/trans_stat |
| |
| Change-Id: Ie822b0fc47dc04a9019383dd079854b73e8840e9 |
| Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org> |
| Signed-off-by: Eddie Huang <eddie.huang@mediatek.com> |
| |
| CHROMIUM: arm64: dts: mt8183: set devfreq-cpufreq-map for mt8183-cci |
| |
| Set cpu frequency to cci frequency mapping table. |
| |
| BUG=b:122571050 |
| TEST=boot to kukui |
| |
| Change-Id: I531cd70c98fc86155eb99a932737cb3ed0d02fb5 |
| Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org> |
| |
| WIP: devfreq: mt8183-cci: using cpufreq-map governor in cci dvfs driver |
| |
| 1. remove mtk_cci_vmon governor, using cpufreq-map |
| 2. SVS: TBD |
| |
| BUG=b:122571050 |
| TEST=cat /sys/class/devfreq/devfreq0/governor |
| TEST=run speedometer |
| |
| Change-Id: I4c4da92dde5f369aaf07a55761f3f9cdc9e80f44 |
| Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org> |
| |
| BACKPORT: FROMLIST: arm64: dts: mt8183: Enable CPU idle-states |
| |
| Enable mcdi-cpu and mcdi-cluster on MT8183 CPUs. |
| |
| Signed-off-by: James Liao <jamesjj.liao@mediatek.com> |
| |
| (am from https://patchwork.kernel.org/patch/10966475/) |
| [eddie.huang: fix context conflicts] |
| |
| BUG=b:109911488 |
| TEST=build pass and boot to shell |
| |
| Change-Id: Ic8c577b296ab4416cfb60267120c0da990dd49f7 |
| Signed-off-by: Eddie Huang <eddie.huang@mediatek.com> |
| |
| FIXUP: arm64: dts: mediatek: Modify opp table for cpu big cluster for mt8183 |
| |
| Modify opp table for cpu big cluster for mt8183 |
| |
| BUG=b:129039370 |
| TEST=build and boot to shell |
| |
| Change-Id: I54569c513c36db0e08011d0a4f474b1e8808ae3a |
| Signed-off-by: Andrew-sh.Cheng <andrew-sh.cheng@mediatek.com> |
| |
| DO-NOT-SUBMIT: Snapshot of iommu tot |
| |
| Snapshot of iommu tot. (CL:1369894/26) |
| |
| BUG=b:109911488 |
| TEST=Boot to shell |
| |
| Change-Id: Iec62b81c8e3162110723d7b6e6e759d3672b3af8 |
| Signed-off-by: CK Hu <ck.hu@mediatek.com> |
| Signed-off-by: Eddie Huang <eddie.huang@mediatek.com> |
| |
| WIP: arm64: dts: mediatek: Get rid of mediatek,larb for MM nodes |
| |
| After adding device_link between the IOMMU consumer and smi, |
| the mediatek,larb is unnecessary now. |
| |
| Change-Id: I3b4457af3df3bc51705af618cb09085953fbcd12 |
| Signed-off-by: Yong Wu <yong.wu@mediatek.com> |
| |
| WIP: drm/panel: add panel driver for boe-tv101wum |
| |
| BUG=b:129299873 |
| TEST=build and boot to shell |
| |
| Change-Id: I08d1ddb1a2d368ccbcd1e358cb5e302b8161328b |
| Signed-off-by: Jitao Shi <jitao.shi@mediatek.com> |
| |
| CHROMIUM: config: enable boe TV101WUM panel support |
| |
| The change is generated from the following commands: |
| |
| cat <<EOF | tee -a \ |
| chromeos/config/arm64/chromiumos-arm64.flavour.config \ |
| chromeos/config/arm64/chromiumos-mediatek.flavour.config |
| |
| CONFIG_DRM_PANEL_BOE_TV101WUM=y |
| |
| EOF |
| |
| ./chromeos/scripts/kernelconfig olddefconfig |
| |
| BUG=b:129299873 |
| TEST=build and boot to shell |
| |
| Change-Id: Ice61a327f17e69bd2207a9033dda7460ec078765 |
| Signed-off-by: Jitao Shi <jitao.shi@mediatek.com> |
| Signed-off-by: Eddie Huang <eddie.huang@mediatek.com> |
| |
| CHROMIUM: arm64: dts: mt8183: add krane rev3 board dts and Makefile |
| |
| add krane rev3 board dts and Makefile |
| |
| BUG=b:131115073 |
| TEST=build and boot to shell |
| |
| Change-Id: I65906cf9a89353c3040e751b85bd2f9710f74802 |
| Signed-off-by: Ben Ho <Ben.Ho@mediatek.com> |
| |
| CHROMIUM: arm64: dts: mt8183-kukui: add wifi power controller |
| |
| To comply with schematic design, remove gpio119 from |
| mmc1_fixed_power and add it back as wlan_en pin in |
| mmc1default. msdcpll is only for mmc module. Assign |
| msdcpll to mmc1 clk for avoiding unexpected changes. |
| |
| BUG=b:131043339 |
| TEST=Cherry-pick and update kernel with |
| https://crrev.com/c/1585667. Make sure SDIO clk |
| is running at 200MHz correctly by checking |
| /sys/kernel/debug/mmc1/ios |
| |
| Change-Id: I325df93ae939e929618f7234f18c674cce4e4138 |
| Signed-off-by: jjian zhou <jjian.zhou@mediatek.com> |
| Signed-off-by: Ayo Wu <ayowu@chromium.org> |
| |
| DO-NOT-SUBMIT: Kukui MTK ToT |
| |
| Collect MTK patches on chromeos-4.19 |
| |
| BUG=b:109911488 |
| TEST=Boot to shell |
| |
| Change-Id: Ifed5c7cb2dacf916c2ac41c4a70f07215f46f0d7 |
| Signed-off-by: Eddie Huang <eddie.huang@mediatek.com> |
| --- |
| .../bindings/devfreq/devfreq-cpufreq-map.txt | 53 + |
| .../display/mediatek/mediatek,disp.txt | 9 - |
| .../devicetree/bindings/mailbox/mtk-gce.txt | 37 +- |
| .../bindings/media/mediatek-jpeg-decoder.txt | 4 - |
| .../bindings/media/mediatek-mdp.txt | 8 - |
| .../bindings/media/mediatek-vcodec.txt | 4 - |
| .../bindings/media/mediatek-vpu.txt | 2 +- |
| .../memory-controllers/mediatek,emi.txt | 19 + |
| Makefile | 1 + |
| README | 1 + |
| arch/arm64/boot/dts/mediatek/Makefile | 1 + |
| .../boot/dts/mediatek/mt8183-krane-rev3.dts | 325 +++ |
| .../boot/dts/mediatek/mt8183-kukui-rev2.dts | 139 + |
| .../arm64/boot/dts/mediatek/mt8183-kukui.dtsi | 25 +- |
| arch/arm64/boot/dts/mediatek/mt8183.dtsi | 152 +- |
| .../arm64/chromiumos-arm64.flavour.config | 7 +- |
| .../arm64/chromiumos-mediatek.flavour.config | 8 +- |
| drivers/clk/mediatek/Makefile | 2 + |
| drivers/clk/mediatek/clk-mt8183.c | 49 +- |
| drivers/clk/mediatek/clkchk-mt8183.c | 387 +++ |
| drivers/clk/mediatek/clkchk.c | 188 ++ |
| drivers/clk/mediatek/clkchk.h | 18 + |
| drivers/clk/mediatek/clkdbg-mt8183.c | 865 +++++++ |
| drivers/clk/mediatek/clkdbg.c | 2242 +++++++++++++++++ |
| drivers/clk/mediatek/clkdbg.h | 83 + |
| drivers/devfreq/Kconfig | 8 + |
| drivers/devfreq/Makefile | 1 + |
| drivers/devfreq/governor_cpufreq_map.c | 583 +++++ |
| drivers/devfreq/mt8183-cci-devfreq.c | 194 +- |
| drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 11 - |
| drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 27 - |
| drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 1 - |
| drivers/gpu/drm/panel/Kconfig | 9 + |
| drivers/gpu/drm/panel/Makefile | 1 + |
| drivers/gpu/drm/panel/panel-boe-tv101wum.c | 708 ++++++ |
| drivers/gpu/drm/panel/panel-innolux-p079zca.c | 139 +- |
| drivers/iommu/mtk_iommu.c | 40 +- |
| drivers/iommu/mtk_iommu_v1.c | 32 +- |
| drivers/mailbox/Kconfig | 18 + |
| drivers/mailbox/Makefile | 1 + |
| drivers/mailbox/mtk-cmdq-debug.c | 582 +++++ |
| drivers/mailbox/mtk-cmdq-debug.h | 21 + |
| drivers/mailbox/mtk-cmdq-mailbox.c | 99 +- |
| .../media/platform/mtk-jpeg/mtk_jpeg_core.c | 22 - |
| .../media/platform/mtk-jpeg/mtk_jpeg_core.h | 2 - |
| drivers/media/platform/mtk-mdp/mtk_mdp_comp.c | 38 - |
| drivers/media/platform/mtk-mdp/mtk_mdp_comp.h | 2 - |
| drivers/media/platform/mtk-mdp/mtk_mdp_core.c | 1 - |
| .../platform/mtk-vcodec/mtk_vcodec_dec_pm.c | 19 - |
| .../platform/mtk-vcodec/mtk_vcodec_drv.h | 3 - |
| .../platform/mtk-vcodec/mtk_vcodec_enc.c | 1 - |
| .../platform/mtk-vcodec/mtk_vcodec_enc_pm.c | 44 - |
| drivers/media/platform/mtk-vpu/mtk_vpu.c | 425 +++- |
| drivers/media/platform/mtk-vpu/mtk_vpu.h | 25 + |
| drivers/memory/Kconfig | 9 + |
| drivers/memory/Makefile | 1 + |
| drivers/memory/mtk-emi.c | 412 +++ |
| drivers/memory/mtk-smi.c | 30 +- |
| drivers/mmc/host/Makefile | 2 +- |
| drivers/mmc/host/mtk-sd.c | 5 + |
| drivers/mmc/host/mtk-sdio-proc.c | 342 +++ |
| drivers/mmc/host/mtk-sdio-proc.h | 48 + |
| drivers/net/wireless/ath/ath10k/htt_rx.c | 22 +- |
| drivers/net/wireless/ath/ath10k/hw.h | 3 + |
| drivers/net/wireless/ath/ath10k/sdio.c | 18 +- |
| drivers/net/wireless/ath/ath10k/testmode.c | 17 +- |
| drivers/pinctrl/mediatek/mtk-eint.c | 34 +- |
| drivers/soc/mediatek/mtk-cmdq-helper.c | 215 +- |
| drivers/thermal/mtk_thermal.c | 140 +- |
| drivers/tty/serial/8250/8250_mtk.c | 50 +- |
| drivers/usb/mtu3/mtu3_core.c | 14 +- |
| drivers/usb/mtu3/mtu3_dr.c | 2 +- |
| include/dt-bindings/gce/mt8183-gce.h | 177 ++ |
| include/linux/mailbox/mtk-cmdq-mailbox.h | 5 + |
| include/linux/soc/mediatek/mtk-cmdq.h | 62 +- |
| include/soc/mediatek/emi.h | 116 + |
| include/soc/mediatek/smi.h | 20 - |
| 77 files changed, 8709 insertions(+), 721 deletions(-) |
| create mode 100644 Documentation/devicetree/bindings/devfreq/devfreq-cpufreq-map.txt |
| create mode 100644 Documentation/devicetree/bindings/memory-controllers/mediatek,emi.txt |
| create mode 100644 arch/arm64/boot/dts/mediatek/mt8183-krane-rev3.dts |
| create mode 100644 drivers/clk/mediatek/clkchk-mt8183.c |
| create mode 100644 drivers/clk/mediatek/clkchk.c |
| create mode 100644 drivers/clk/mediatek/clkchk.h |
| create mode 100644 drivers/clk/mediatek/clkdbg-mt8183.c |
| create mode 100644 drivers/clk/mediatek/clkdbg.c |
| create mode 100644 drivers/clk/mediatek/clkdbg.h |
| create mode 100644 drivers/devfreq/governor_cpufreq_map.c |
| create mode 100644 drivers/gpu/drm/panel/panel-boe-tv101wum.c |
| create mode 100644 drivers/mailbox/mtk-cmdq-debug.c |
| create mode 100644 drivers/mailbox/mtk-cmdq-debug.h |
| create mode 100644 drivers/memory/mtk-emi.c |
| create mode 100644 drivers/mmc/host/mtk-sdio-proc.c |
| create mode 100644 drivers/mmc/host/mtk-sdio-proc.h |
| mode change 100644 => 100755 drivers/tty/serial/8250/8250_mtk.c |
| create mode 100644 include/dt-bindings/gce/mt8183-gce.h |
| create mode 100644 include/soc/mediatek/emi.h |
| |
| diff --git a/Documentation/devicetree/bindings/devfreq/devfreq-cpufreq-map.txt b/Documentation/devicetree/bindings/devfreq/devfreq-cpufreq-map.txt |
| new file mode 100644 |
| index 000000000000..982a30bcfc86 |
| --- /dev/null |
| +++ b/Documentation/devicetree/bindings/devfreq/devfreq-cpufreq-map.txt |
| @@ -0,0 +1,53 @@ |
| +Devfreq CPUfreq governor |
| + |
| +devfreq-cpufreq-map is a parent device that contains one or more child devices. |
| +Each child device provides CPU frequency to device frequency mapping for a |
| +specific device. Examples of devices that could use this are: DDR, cache and |
| +CCI. |
| + |
| +Parent device name shall be "devfreq-cpufreq-map". |
| + |
| +Required child device properties: |
| +- cpu-to-dev-map, or cpu-to-dev-map-<X>: |
| + A list of tuples where each tuple consists of a |
| + CPU frequency (KHz) and the corresponding device |
| + frequency. CPU frequencies not listed in the table |
| + will use the device frequency that corresponds to the |
| + next rounded up CPU frequency. |
| + Use "cpu-to-dev-map" if all CPUs in the system should |
| + share same mapping. |
| + Use cpu-to-dev-map-<cpuid> to describe different |
| + mappings for different CPUs. The property should be |
| + listed only for the first CPU if multiple CPUs are |
| + synchronous. |
| +- target-dev: Phandle to device that this mapping applies to. |
| + |
| +Example: |
| + devfreq-cpufreq-map { |
| + cpubw-cpufreq { |
| + target-dev = <&cpubw>; |
| + cpu-to-dev-map = |
| + < 300000 1144000 >, |
| + < 422400 2288000 >, |
| + < 652800 3051000 >, |
| + < 883200 5996000 >, |
| + < 1190400 8056000 >, |
| + < 1497600 10101000 >, |
| + < 1728000 12145000 >, |
| + < 2649600 16250000 >; |
| + }; |
| + |
| + cache-cpufreq { |
| + target-dev = <&cache>; |
| + cpu-to-dev-map = |
| + < 300000 300000 >, |
| + < 422400 422400 >, |
| + < 652800 499200 >, |
| + < 883200 576000 >, |
| + < 960000 960000 >, |
| + < 1497600 1036800 >, |
| + < 1574400 1574400 >, |
| + < 1728000 1651200 >, |
| + < 2649600 1728000 >; |
| + }; |
| + }; |
| diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,disp.txt b/Documentation/devicetree/bindings/display/mediatek/mediatek,disp.txt |
| index 5467470c7b8a..bc8e30c20c64 100644 |
| --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,disp.txt |
| +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,disp.txt |
| @@ -59,8 +59,6 @@ Required properties (DMA function blocks): |
| "mediatek,<chip>-disp-rdma" |
| "mediatek,<chip>-disp-wdma" |
| the supported chips are mt2701 and mt8173. |
| -- larb: Should contain a phandle pointing to the local arbiter device as defined |
| - in Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt |
| - iommus: Should point to the respective IOMMU block with master port as |
| argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt |
| for details. |
| @@ -87,7 +85,6 @@ ovl0: ovl@1400c000 { |
| power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; |
| clocks = <&mmsys CLK_MM_DISP_OVL0>; |
| iommus = <&iommu M4U_PORT_DISP_OVL0>; |
| - mediatek,larb = <&larb0>; |
| }; |
| |
| ovl1: ovl@1400d000 { |
| @@ -97,7 +94,6 @@ ovl1: ovl@1400d000 { |
| power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; |
| clocks = <&mmsys CLK_MM_DISP_OVL1>; |
| iommus = <&iommu M4U_PORT_DISP_OVL1>; |
| - mediatek,larb = <&larb4>; |
| }; |
| |
| rdma0: rdma@1400e000 { |
| @@ -107,7 +103,6 @@ rdma0: rdma@1400e000 { |
| power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; |
| clocks = <&mmsys CLK_MM_DISP_RDMA0>; |
| iommus = <&iommu M4U_PORT_DISP_RDMA0>; |
| - mediatek,larb = <&larb0>; |
| }; |
| |
| rdma1: rdma@1400f000 { |
| @@ -117,7 +112,6 @@ rdma1: rdma@1400f000 { |
| power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; |
| clocks = <&mmsys CLK_MM_DISP_RDMA1>; |
| iommus = <&iommu M4U_PORT_DISP_RDMA1>; |
| - mediatek,larb = <&larb4>; |
| }; |
| |
| rdma2: rdma@14010000 { |
| @@ -127,7 +121,6 @@ rdma2: rdma@14010000 { |
| power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; |
| clocks = <&mmsys CLK_MM_DISP_RDMA2>; |
| iommus = <&iommu M4U_PORT_DISP_RDMA2>; |
| - mediatek,larb = <&larb4>; |
| }; |
| |
| wdma0: wdma@14011000 { |
| @@ -137,7 +130,6 @@ wdma0: wdma@14011000 { |
| power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; |
| clocks = <&mmsys CLK_MM_DISP_WDMA0>; |
| iommus = <&iommu M4U_PORT_DISP_WDMA0>; |
| - mediatek,larb = <&larb0>; |
| }; |
| |
| wdma1: wdma@14012000 { |
| @@ -147,7 +139,6 @@ wdma1: wdma@14012000 { |
| power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; |
| clocks = <&mmsys CLK_MM_DISP_WDMA1>; |
| iommus = <&iommu M4U_PORT_DISP_WDMA1>; |
| - mediatek,larb = <&larb4>; |
| }; |
| |
| color0: color@14013000 { |
| diff --git a/Documentation/devicetree/bindings/mailbox/mtk-gce.txt b/Documentation/devicetree/bindings/mailbox/mtk-gce.txt |
| index 7d72b21c9e94..755b30fd6041 100644 |
| --- a/Documentation/devicetree/bindings/mailbox/mtk-gce.txt |
| +++ b/Documentation/devicetree/bindings/mailbox/mtk-gce.txt |
| @@ -9,7 +9,7 @@ CMDQ driver uses mailbox framework for communication. Please refer to |
| mailbox.txt for generic information about mailbox device-tree bindings. |
| |
| Required properties: |
| -- compatible: Must be "mediatek,mt8173-gce" |
| +- compatible: can be "mediatek,mt8173-gce" or "mediatek,mt8183-gce" |
| - reg: Address range of the GCE unit |
| - interrupts: The interrupt signal from the GCE block |
| - clock: Clocks according to the common clock binding |
| @@ -21,15 +21,31 @@ Required properties: |
| priority: Priority of GCE thread. |
| atomic_exec: GCE processing continuous packets of commands in atomic |
| way. |
| +- #event-cells: Should be 1. |
| + <&phandle event_number> |
| + phandle: Label name of a gce node. |
| + event_number: the event number defined in 'dt-bindings/gce/mt8173-gce.h' |
| + or 'dt-binding/gce/mt8183-gce.h'. |
| +- #subsys-cells: Should be 3. |
| + <&phandle subsys_number start_offset size> |
| + phandle: Label name of a gce node. |
| + subsys_number: specify the sub-system id which is corresponding |
| + to the register address. |
| + start_offset: the start offset of register address that GCE can access. |
| + size: the total size of register address that GCE can access. |
| |
| Required properties for a client device: |
| - mboxes: Client use mailbox to communicate with GCE, it should have this |
| property and list of phandle, mailbox specifiers. |
| -- mediatek,gce-subsys: u32, specify the sub-system id which is corresponding |
| +Optional propertier for a client device: |
| +- mediatek,gce-client-reg: u32, specify the sub-system id which is corresponding |
| to the register address. |
| +- mediatek,gce-event-names: the event name can be defined by user. |
| +- mediatek,gce-events: u32, the event number defined in |
| + 'dt-bindings/gce/mt8173-gce.h' or 'dt-binding/gce/mt8183-gce.h'. |
| |
| -Some vaules of properties are defined in 'dt-bindings/gce/mt8173-gce.h'. Such as |
| -sub-system ids, thread priority, event ids. |
| +Some vaules of properties are defined in 'dt-bindings/gce/mt8173-gce.h' |
| +or 'dt-binding/gce/mt8183-gce.h'. Such as sub-system ids, thread priority, event ids. |
| |
| Example: |
| |
| @@ -39,8 +55,9 @@ Example: |
| interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_LOW>; |
| clocks = <&infracfg CLK_INFRA_GCE>; |
| clock-names = "gce"; |
| - thread-num = CMDQ_THR_MAX_COUNT; |
| #mbox-cells = <3>; |
| + #event-cells = <1>; |
| + #subsys-cells = <2>; |
| }; |
| |
| Example for a client device: |
| @@ -49,9 +66,11 @@ Example for a client device: |
| compatible = "mediatek,mt8173-mmsys"; |
| mboxes = <&gce 0 CMDQ_THR_PRIO_LOWEST 1>, |
| <&gce 1 CMDQ_THR_PRIO_LOWEST 1>; |
| - mediatek,gce-subsys = <SUBSYS_1400XXXX>; |
| - mutex-event-eof = <CMDQ_EVENT_MUTEX0_STREAM_EOF |
| - CMDQ_EVENT_MUTEX1_STREAM_EOF>; |
| - |
| + mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x3000 0x1000>, |
| + <&gce SUBSYS_1401XXXX 0x2000 0x100>; |
| + mediatek,gce-event-names = "rdma0_sof", |
| + "rsz0_sof"; |
| + mediatek,gce-events = <&gce CMDQ_EVENT_MDP_RDMA0_SOF>, |
| + <&gce CMDQ_EVENT_MDP_RSZ0_SOF>; |
| ... |
| }; |
| diff --git a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt |
| index 3813947b4d4f..c9f89132830c 100644 |
| --- a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt |
| +++ b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt |
| @@ -14,9 +14,6 @@ Required properties: |
| - clock-names: must contain "jpgdec-smi" and "jpgdec". |
| - power-domains: a phandle to the power domain, see |
| Documentation/devicetree/bindings/power/power_domain.txt for details. |
| -- mediatek,larb: must contain the local arbiters in the current Socs, see |
| - Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt |
| - for details. |
| - iommus: should point to the respective IOMMU block with master port as |
| argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt |
| for details. |
| @@ -31,7 +28,6 @@ Example: |
| clock-names = "jpgdec-smi", |
| "jpgdec"; |
| power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>; |
| - mediatek,larb = <&larb2>; |
| iommus = <&iommu MT2701_M4U_PORT_JPGDEC_WDMA>, |
| <&iommu MT2701_M4U_PORT_JPGDEC_BSDMA>; |
| }; |
| diff --git a/Documentation/devicetree/bindings/media/mediatek-mdp.txt b/Documentation/devicetree/bindings/media/mediatek-mdp.txt |
| index 0d03e3ae2be2..df69c5a06250 100644 |
| --- a/Documentation/devicetree/bindings/media/mediatek-mdp.txt |
| +++ b/Documentation/devicetree/bindings/media/mediatek-mdp.txt |
| @@ -27,9 +27,6 @@ Required properties (DMA function blocks, child node): |
| - iommus: should point to the respective IOMMU block with master port as |
| argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt |
| for details. |
| -- mediatek,larb: must contain the local arbiters in the current Socs, see |
| - Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt |
| - for details. |
| |
| Example: |
| mdp_rdma0: rdma@14001000 { |
| @@ -40,7 +37,6 @@ Example: |
| <&mmsys CLK_MM_MUTEX_32K>; |
| power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; |
| iommus = <&iommu M4U_PORT_MDP_RDMA0>; |
| - mediatek,larb = <&larb0>; |
| mediatek,vpu = <&vpu>; |
| }; |
| |
| @@ -51,7 +47,6 @@ Example: |
| <&mmsys CLK_MM_MUTEX_32K>; |
| power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; |
| iommus = <&iommu M4U_PORT_MDP_RDMA1>; |
| - mediatek,larb = <&larb4>; |
| }; |
| |
| mdp_rsz0: rsz@14003000 { |
| @@ -81,7 +76,6 @@ Example: |
| clocks = <&mmsys CLK_MM_MDP_WDMA>; |
| power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; |
| iommus = <&iommu M4U_PORT_MDP_WDMA>; |
| - mediatek,larb = <&larb0>; |
| }; |
| |
| mdp_wrot0: wrot@14007000 { |
| @@ -90,7 +84,6 @@ Example: |
| clocks = <&mmsys CLK_MM_MDP_WROT0>; |
| power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; |
| iommus = <&iommu M4U_PORT_MDP_WROT0>; |
| - mediatek,larb = <&larb0>; |
| }; |
| |
| mdp_wrot1: wrot@14008000 { |
| @@ -99,5 +92,4 @@ Example: |
| clocks = <&mmsys CLK_MM_MDP_WROT1>; |
| power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; |
| iommus = <&iommu M4U_PORT_MDP_WROT1>; |
| - mediatek,larb = <&larb4>; |
| }; |
| diff --git a/Documentation/devicetree/bindings/media/mediatek-vcodec.txt b/Documentation/devicetree/bindings/media/mediatek-vcodec.txt |
| index b6b5dde6abd8..5c9ee6af3cfa 100644 |
| --- a/Documentation/devicetree/bindings/media/mediatek-vcodec.txt |
| +++ b/Documentation/devicetree/bindings/media/mediatek-vcodec.txt |
| @@ -9,7 +9,6 @@ Required properties: |
| - reg : Physical base address of the video codec registers and length of |
| memory mapped region. |
| - interrupts : interrupt number to the cpu. |
| -- mediatek,larb : must contain the local arbiters in the current Socs. |
| - clocks : list of clock specifiers, corresponding to entries in |
| the clock-names property. |
| - clock-names: encoder must contain "venc_sel_src", "venc_sel",, |
| @@ -39,7 +38,6 @@ vcodec_dec: vcodec@16000000 { |
| <0 0x16027800 0 0x800>, /*VP8_VL*/ |
| <0 0x16028400 0 0x400>; /*VP9_VD*/ |
| interrupts = <GIC_SPI 204 IRQ_TYPE_LEVEL_LOW>; |
| - mediatek,larb = <&larb1>; |
| iommus = <&iommu M4U_PORT_HW_VDEC_MC_EXT>, |
| <&iommu M4U_PORT_HW_VDEC_PP_EXT>, |
| <&iommu M4U_PORT_HW_VDEC_AVC_MV_EXT>, |
| @@ -83,8 +81,6 @@ vcodec_dec: vcodec@16000000 { |
| <0 0x19002000 0 0x1000>; /*VENC_LT_SYS*/ |
| interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_LOW>, |
| <GIC_SPI 202 IRQ_TYPE_LEVEL_LOW>; |
| - mediatek,larb = <&larb3>, |
| - <&larb5>; |
| iommus = <&iommu M4U_PORT_VENC_RCPU>, |
| <&iommu M4U_PORT_VENC_REC>, |
| <&iommu M4U_PORT_VENC_BSDMA>, |
| diff --git a/Documentation/devicetree/bindings/media/mediatek-vpu.txt b/Documentation/devicetree/bindings/media/mediatek-vpu.txt |
| index 2a5bac37f9a2..015123250b82 100644 |
| --- a/Documentation/devicetree/bindings/media/mediatek-vpu.txt |
| +++ b/Documentation/devicetree/bindings/media/mediatek-vpu.txt |
| @@ -4,7 +4,7 @@ Video Processor Unit is a HW video controller. It controls HW Codec including |
| H.264/VP8/VP9 Decode, H.264/VP8 Encode and Image Processor (scale/rotate/color convert). |
| |
| Required properties: |
| - - compatible: "mediatek,mt8173-vpu" |
| + - compatible:"mediatek,mt8173-vpu", "mediatek,mt8183-vpu", "mediatek,reserve-memory-vpu_share" |
| - reg: Must contain an entry for each entry in reg-names. |
| - reg-names: Must include the following entries: |
| "tcm": tcm base |
| diff --git a/Documentation/devicetree/bindings/memory-controllers/mediatek,emi.txt b/Documentation/devicetree/bindings/memory-controllers/mediatek,emi.txt |
| new file mode 100644 |
| index 000000000000..a19e3b39ba66 |
| --- /dev/null |
| +++ b/Documentation/devicetree/bindings/memory-controllers/mediatek,emi.txt |
| @@ -0,0 +1,19 @@ |
| +EMI (External Memory Interface) |
| + |
| +Required properties: |
| +- compatible : must be one of : |
| + "mediatek,mt8183-emi" |
| +- reg : the register and size of the EMI block. |
| +- interrupts : includes MPU, CGM, ELM. |
| + |
| +Example: |
| + emi@10219000 { |
| + compatible = "mediatek,mt8183-emi"; |
| + reg = <0 0x10219000 0 0x1000>, /* CEN EMI */ |
| + <0 0x10226000 0 0x1000>, /* EMI MPU */ |
| + <0 0x1022d000 0 0x1000>, /* CHA EMI */ |
| + <0 0x10235000 0 0x1000>; /* CHB EMI */ |
| + interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_LOW>, /* MPU */ |
| + <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>, /* CGM */ |
| + <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>; /* ELM */ |
| +}; |
| diff --git a/Makefile b/Makefile |
| index 1241e0120740..434373aa4d87 100644 |
| --- a/Makefile |
| +++ b/Makefile |
| @@ -1,3 +1,4 @@ |
| +# kukui ToT! |
| # SPDX-License-Identifier: GPL-2.0 |
| VERSION = 4 |
| PATCHLEVEL = 19 |
| diff --git a/README b/README |
| index 2c927ccbd970..768caa3970ef 100644 |
| --- a/README |
| +++ b/README |
| @@ -1,3 +1,4 @@ |
| +MTK TOT |
| Linux kernel |
| ============ |
| |
| diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile |
| index 3a55c454b65d..d09409979c84 100644 |
| --- a/arch/arm64/boot/dts/mediatek/Makefile |
| +++ b/arch/arm64/boot/dts/mediatek/Makefile |
| @@ -8,5 +8,6 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7622-rfb1.dtb |
| dtb-$(CONFIG_ARCH_MEDIATEK) += mt7622-bananapi-bpi-r64.dtb |
| dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-evb.dtb |
| dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-evb.dtb |
| +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-krane-rev3.dtb |
| dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-rev1.dtb |
| dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-rev2.dtb |
| diff --git a/arch/arm64/boot/dts/mediatek/mt8183-krane-rev3.dts b/arch/arm64/boot/dts/mediatek/mt8183-krane-rev3.dts |
| new file mode 100644 |
| index 000000000000..4c71b09e26a3 |
| --- /dev/null |
| +++ b/arch/arm64/boot/dts/mediatek/mt8183-krane-rev3.dts |
| @@ -0,0 +1,325 @@ |
| +// SPDX-License-Identifier: (GPL-2.0 OR MIT) |
| +/* |
| + * Copyright (c) 2018 Google LLC |
| + */ |
| + |
| +/dts-v1/; |
| +#include "mt8183-kukui.dtsi" |
| + |
| +/ { |
| + model = "MediaTek krane rev3 board"; |
| + compatible = "google,krane-rev3", "google,krane", "google,kukui", "mediatek,mt8183"; |
| +}; |
| + |
| +&i2c0 { |
| + status = "okay"; |
| + |
| + touchscreen4: touchscreen@5d { |
| + compatible = "hid-over-i2c"; |
| + reg = <0x5d>; |
| + pinctrl-names = "default"; |
| + pinctrl-0 = <&open_touch>; |
| + |
| + interrupt-parent = <&pio>; |
| + interrupts = <155 IRQ_TYPE_EDGE_FALLING>; |
| + |
| + post-power-on-delay-ms = <10>; |
| + hid-descr-addr = <0x0001>; |
| + }; |
| +}; |
| + |
| +&pio { |
| + /* 192 lines */ |
| + gpio-line-names = |
| + "SPI_AP_EC_CS_L", |
| + "SPI_AP_EC_MOSI", |
| + "SPI_AP_EC_CLK", |
| + "I2S3_DO", |
| + "USB_PD_INT_ODL", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "IT6505_HPD_L", |
| + "I2S3_TDM_D3", |
| + "SOC_I2C6_1V8_SCL", |
| + "SOC_I2C6_1V8_SDA", |
| + "DPI_D0", |
| + "DPI_D1", |
| + "DPI_D2", |
| + "DPI_D3", |
| + "DPI_D4", |
| + "DPI_D5", |
| + "DPI_D6", |
| + "DPI_D7", |
| + "DPI_D8", |
| + "DPI_D9", |
| + "DPI_D10", |
| + "DPI_D11", |
| + "DPI_HSYNC", |
| + "DPI_VSYNC", |
| + "DPI_DE", |
| + "DPI_CK", |
| + "AP_MSDC1_CLK", |
| + "AP_MSDC1_DAT3", |
| + "AP_MSDC1_CMD", |
| + "AP_MSDC1_DAT0", |
| + "AP_MSDC1_DAT2", |
| + "AP_MSDC1_DAT1", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "OTG_EN", |
| + "DRVBUS", |
| + "DISP_PWM", |
| + "DSI_TE", |
| + "LCM_RST_1V8", |
| + "AP_CTS_WIFI_RTS", |
| + "AP_RTS_WIFI_CTS", |
| + "SOC_I2C5_1V8_SCL", |
| + "SOC_I2C5_1V8_SDA", |
| + "SOC_I2C3_1V8_SCL", |
| + "SOC_I2C3_1V8_SDA", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "SOC_I2C1_1V8_SDA", |
| + "SOC_I2C0_1V8_SDA", |
| + "SOC_I2C0_1V8_SCL", |
| + "SOC_I2C1_1V8_SCL", |
| + "AP_SPI_H1_MISO", |
| + "AP_SPI_H1_CS_L", |
| + "AP_SPI_H1_MOSI", |
| + "AP_SPI_H1_CLK", |
| + "I2S5_BCK", |
| + "I2S5_LRCK", |
| + "I2S5_DO", |
| + "BOOTBLOCK_EN_L", |
| + "MT8183_KPCOL0", |
| + "SPI_AP_EC_MISO", |
| + "UART_DBG_TX_AP_RX", |
| + "UART_AP_TX_DBG_RX", |
| + "I2S2_MCK", |
| + "I2S2_BCK", |
| + "CLK_5M_WCAM", |
| + "CLK_2M_UCAM", |
| + "I2S2_LRCK", |
| + "I2S2_DI", |
| + "SOC_I2C2_1V8_SCL", |
| + "SOC_I2C2_1V8_SDA", |
| + "SOC_I2C4_1V8_SCL", |
| + "SOC_I2C4_1V8_SDA", |
| + "", |
| + "SCL8", |
| + "SDA8", |
| + "FCAM_PWDN_L", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "I2S_PMIC", |
| + "I2S_PMIC", |
| + "I2S_PMIC", |
| + "I2S_PMIC", |
| + "I2S_PMIC", |
| + "I2S_PMIC", |
| + "I2S_PMIC", |
| + "I2S_PMIC", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + /* |
| + * AP_FLASH_WP_L is crossystem ABI. Rev1 schematics |
| + * call it BIOS_FLASH_WP_R_L. |
| + */ |
| + "AP_FLASH_WP_L", |
| + "EC_AP_INT_ODL", |
| + "IT6505_INT_ODL", |
| + "H1_INT_OD_L", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "AP_SPI_FLASH_MISO", |
| + "AP_SPI_FLASH_CS_L", |
| + "AP_SPI_FLASH_MOSI", |
| + "AP_SPI_FLASH_CLK", |
| + "DA7219_IRQ", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + "", |
| + ""; |
| +}; |
| + |
| +/ { |
| + ppvarn_lcd: ppvarn-lcd { |
| + compatible = "regulator-fixed"; |
| + regulator-name = "ppvarn_lcd"; |
| + pinctrl-names = "default"; |
| + pinctrl-0 = <&ppvarn_lcd_en>; |
| + |
| + enable-active-high; |
| + |
| + gpio = <&pio 66 GPIO_ACTIVE_HIGH>; |
| + }; |
| + |
| + ppvarp_lcd: ppvarp-lcd { |
| + compatible = "regulator-fixed"; |
| + regulator-name = "ppvarp_lcd"; |
| + pinctrl-names = "default"; |
| + pinctrl-0 = <&ppvarp_lcd_en>; |
| + |
| + enable-active-high; |
| + |
| + gpio = <&pio 166 GPIO_ACTIVE_HIGH>; |
| + }; |
| + |
| + pp1800_lcd: pp1800-lcd { |
| + compatible = "regulator-fixed"; |
| + regulator-name = "pp1800_lcd"; |
| + pinctrl-names = "default"; |
| + pinctrl-0 = <&pp1800_lcm_en>; |
| + |
| + enable-active-high; |
| + |
| + gpio = <&pio 36 GPIO_ACTIVE_HIGH>; |
| + }; |
| +}; |
| + |
| +&panel { |
| + status = "okay"; |
| + compatible = "boe,tv101wum"; |
| + reg = <0>; |
| + enable-gpios = <&pio 45 0>; |
| + pinctrl-names = "default"; |
| + pinctrl-0 = <&panel_pins_default>; |
| + avdd-supply = <&ppvarn_lcd>; |
| + avee-supply = <&ppvarp_lcd>; |
| + pp1800-supply = <&pp1800_lcd>; |
| +}; |
| + |
| +&pio { |
| + ppvarp_lcd_en: ppvarp-lcd-en { |
| + pins1 { |
| + pinmux = <PINMUX_GPIO66__FUNC_GPIO66>; |
| + output-low; |
| + }; |
| + }; |
| + |
| + ppvarn_lcd_en: ppvarn-lcd-en { |
| + pins1 { |
| + pinmux = <PINMUX_GPIO166__FUNC_GPIO166>; |
| + output-low; |
| + }; |
| + }; |
| + |
| + pp1800_lcm_en: pp1800-lcd-en { |
| + pins1 { |
| + pinmux = <PINMUX_GPIO36__FUNC_GPIO36>; |
| + output-low; |
| + }; |
| + }; |
| + |
| + open_touch: open_touch { |
| + irq_pin { |
| + pinmux = <PINMUX_GPIO155__FUNC_GPIO155>; |
| + input-enable; |
| + bias-pull-up; |
| + }; |
| + |
| + rst_pin { |
| + pinmux = <PINMUX_GPIO156__FUNC_GPIO156>; |
| + |
| + /* |
| + * The pen driver doesn't currently support driving |
| + * this reset line. By specifying output-high here |
| + * we're relying on the fact that this pin has a default |
| + * pulldown at boot (which makes sure the pen was in |
| + * reset if it was powered) and then we set it high here |
| + * to take it out of reset. Better would be if the pen |
| + * driver could control this and we could remove |
| + * "output-high" here. |
| + */ |
| + output-high; |
| + }; |
| + }; |
| +}; |
| + |
| diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-rev2.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-rev2.dts |
| index f950c87b1672..7ac53e3bbfff 100644 |
| --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-rev2.dts |
| +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-rev2.dts |
| @@ -4,6 +4,7 @@ |
| */ |
| |
| /dts-v1/; |
| +#include <dt-bindings/gpio/gpio.h> |
| #include "mt8183-kukui.dtsi" |
| |
| / { |
| @@ -24,6 +25,72 @@ |
| wakeup-source; |
| }; |
| }; |
| + |
| + pp1200_mipibrdg: pp1200-mipibrdg { |
| + compatible = "regulator-fixed"; |
| + regulator-name = "pp1200_mipibrdg"; |
| + pinctrl-names = "default"; |
| + pinctrl-0 = <&pp1200_mipibrdg_en>; |
| + |
| + enable-active-high; |
| + |
| + gpio = <&pio 54 GPIO_ACTIVE_HIGH>; |
| + }; |
| + |
| + pp1800_lcd: pp1800-lcd { |
| + compatible = "regulator-fixed"; |
| + regulator-name = "pp1800_lcd"; |
| + pinctrl-names = "default"; |
| + pinctrl-0 = <&pp1800_lcm_en>; |
| + |
| + enable-active-high; |
| + |
| + gpio = <&pio 36 GPIO_ACTIVE_HIGH>; |
| + }; |
| + |
| + pp3300_lcd: pp3300-lcd { |
| + compatible = "regulator-fixed"; |
| + regulator-name = "pp3300_lcd"; |
| + pinctrl-names = "default"; |
| + pinctrl-0 = <&pp3300_lcm_en>; |
| + |
| + enable-active-high; |
| + |
| + gpio = <&pio 35 GPIO_ACTIVE_HIGH>; |
| + }; |
| + |
| + ppvarn_lcd: ppvarn-lcd { |
| + compatible = "regulator-fixed"; |
| + regulator-name = "ppvarn_lcd"; |
| + pinctrl-names = "default"; |
| + pinctrl-0 = <&ppvarn_lcd_en>; |
| + |
| + enable-active-high; |
| + |
| + gpio = <&pio 66 GPIO_ACTIVE_HIGH>; |
| + }; |
| + |
| + ppvarp_lcd: ppvarp-lcd { |
| + compatible = "regulator-fixed"; |
| + regulator-name = "ppvarp_lcd"; |
| + pinctrl-names = "default"; |
| + pinctrl-0 = <&ppvarp_lcd_en>; |
| + |
| + enable-active-high; |
| + |
| + gpio = <&pio 166 GPIO_ACTIVE_HIGH>; |
| + }; |
| + |
| + vddio_mipibrdg: vddio-mipibrdg { |
| + compatible = "regulator-fixed"; |
| + regulator-name = "vddio_mipibrdg"; |
| + pinctrl-names = "default"; |
| + pinctrl-0 = <&vddio_mipibrdg_en>; |
| + |
| + enable-active-high; |
| + |
| + gpio = <&pio 37 GPIO_ACTIVE_HIGH>; |
| + }; |
| }; |
| |
| &i2c0 { |
| @@ -52,6 +119,36 @@ |
| }; |
| }; |
| |
| +&panel { |
| + compatible = "innolux,p097pfg_ssd2858"; |
| + reg = <0>; |
| + enable-gpios = <&pio 45 0 &pio 73 0>; |
| + pinctrl-names = "default"; |
| + pinctrl-0 = <&panel_pins_default>; |
| + /delete-property/ power-supply; |
| + avdd-supply = <&ppvarp_lcd>; |
| + avee-supply = <&ppvarn_lcd>; |
| + pp1800-supply = <&pp1800_lcd>; |
| + pp3300-supply = <&pp3300_lcd>; |
| + pp1200-bridge-supply = <&pp1200_mipibrdg>; |
| + vddio-bridge-supply = <&vddio_mipibrdg>; |
| + backlight = <&backlight_lcd0>; |
| + status = "okay"; |
| + port { |
| + panel_in: endpoint { |
| + remote-endpoint = <&dsi_out>; |
| + }; |
| + }; |
| +}; |
| + |
| +&panel_pins_default { |
| + bridge_reset { |
| + pinmux = <PINMUX_GPIO73__FUNC_GPIO73>; |
| + output-low; |
| + bias-pull-up; |
| + }; |
| +}; |
| + |
| &pio { |
| /* 192 lines */ |
| gpio-line-names = |
| @@ -285,6 +382,41 @@ |
| }; |
| }; |
| |
| + pp1200_mipibrdg_en: pp1200-mipibrdg-en { |
| + pins1 { |
| + pinmux = <PINMUX_GPIO54__FUNC_GPIO54>; |
| + output-low; |
| + }; |
| + }; |
| + |
| + pp1800_lcm_en: pp1800-lcd-en { |
| + pins1 { |
| + pinmux = <PINMUX_GPIO36__FUNC_GPIO36>; |
| + output-low; |
| + }; |
| + }; |
| + |
| + pp3300_lcm_en: pp3300-lcd-en { |
| + pins1 { |
| + pinmux = <PINMUX_GPIO35__FUNC_GPIO35>; |
| + output-low; |
| + }; |
| + }; |
| + |
| + ppvarp_lcd_en: ppvarp-lcd-en { |
| + pins1 { |
| + pinmux = <PINMUX_GPIO66__FUNC_GPIO66>; |
| + output-low; |
| + }; |
| + }; |
| + |
| + ppvarn_lcd_en: ppvarn-lcd-en { |
| + pins1 { |
| + pinmux = <PINMUX_GPIO166__FUNC_GPIO166>; |
| + output-low; |
| + }; |
| + }; |
| + |
| touch_default: touchdefault { |
| pin_irq { |
| pinmux = <PINMUX_GPIO155__FUNC_GPIO155>; |
| @@ -297,6 +429,13 @@ |
| output-low; |
| }; |
| }; |
| + |
| + vddio_mipibrdg_en: vddio_mipibrdg_en { |
| + pins1 { |
| + pinmux = <PINMUX_GPIO37__FUNC_GPIO37>; |
| + output-low; |
| + }; |
| + }; |
| }; |
| |
| &scp_pins { |
| diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi |
| index e30bc9517fbb..e93b0587cfbc 100644 |
| --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi |
| +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi |
| @@ -59,6 +59,20 @@ |
| regulator-boot-on; |
| }; |
| |
| + mmc1_fixed_power: regulator@3 { |
| + compatible = "regulator-fixed"; |
| + regulator-name = "mmc1_power"; |
| + regulator-min-microvolt = <3300000>; |
| + regulator-max-microvolt = <3300000>; |
| + }; |
| + |
| + mmc1_fixed_io: regulator@4 { |
| + compatible = "regulator-fixed"; |
| + regulator-name = "mmc1_io"; |
| + regulator-min-microvolt = <1800000>; |
| + regulator-max-microvolt = <1800000>; |
| + }; |
| + |
| reserved_memory: reserved-memory { |
| #address-cells = <2>; |
| #size-cells = <2>; |
| @@ -294,8 +308,8 @@ |
| pinctrl-names = "default", "state_uhs"; |
| pinctrl-0 = <&mmc1_pins_default>; |
| pinctrl-1 = <&mmc1_pins_uhs>; |
| - vmmc-supply = <&mt6358_vmch_reg>; |
| - vqmmc-supply = <&mt6358_vmc_reg>; |
| + vmmc-supply = <&mmc1_fixed_power>; |
| + vqmmc-supply = <&mmc1_fixed_io>; |
| bus-width = <4>; |
| max-frequency = <200000000>; |
| drv-type = <2>; |
| @@ -308,6 +322,8 @@ |
| non-removable; |
| no-mmc; |
| no-sd; |
| + assigned-clocks = <&topckgen CLK_TOP_MUX_MSDC30_1>; |
| + assigned-clock-parents = <&topckgen CLK_TOP_MSDCPLL_D2>; |
| }; |
| |
| &mt6358_vdram2_reg { |
| @@ -520,7 +536,7 @@ |
| mediatek,pull-down-adv = <10>; |
| }; |
| |
| - pins_wifi { |
| + pins_wlan_en { |
| pinmux = <PINMUX_GPIO119__FUNC_GPIO119>; |
| output-high; |
| }; |
| @@ -801,7 +817,8 @@ |
| }; |
| |
| &ssusb { |
| - dr_mode = "host"; |
| + maximum-speed = "high-speed"; |
| + enable-manual-drd; |
| vusb33-supply = <&mt6358_vusb_reg>; |
| status = "okay"; |
| }; |
| diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi b/arch/arm64/boot/dts/mediatek/mt8183.dtsi |
| index ba43207e2ecc..ff9ce0f93a3e 100644 |
| --- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi |
| +++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi |
| @@ -6,6 +6,7 @@ |
| */ |
| |
| #include <dt-bindings/clock/mt8183-clk.h> |
| +#include <dt-bindings/gce/mt8183-gce.h> |
| #include <dt-bindings/interrupt-controller/arm-gic.h> |
| #include <dt-bindings/interrupt-controller/irq.h> |
| #include <dt-bindings/memory/mt8183-larb-port.h> |
| @@ -22,11 +23,6 @@ |
| #size-cells = <2>; |
| |
| aliases { |
| - ovl0 = &ovl0; |
| - ovl_2l0 = &ovl0_2l; |
| - ovl_2l1 = &ovl1_2l; |
| - rdma0 = &rdma0; |
| - rdma1 = &rdma1; |
| i2c0 = &i2c0; |
| i2c1 = &i2c1; |
| i2c2 = &i2c2; |
| @@ -39,6 +35,11 @@ |
| i2c9 = &i2c9; |
| i2c10 = &i2c10; |
| i2c11 = &i2c11; |
| + ovl0 = &ovl0; |
| + ovl_2l0 = &ovl_2l0; |
| + ovl_2l1 = &ovl_2l1; |
| + rdma0 = &rdma0; |
| + rdma1 = &rdma1; |
| }; |
| |
| cluster0_opp: opp_table0 { |
| @@ -114,67 +115,67 @@ |
| opp-shared; |
| opp00 { |
| opp-hz = /bits/ 64 <793000000>; |
| - opp-microvolt = <650000>; |
| + opp-microvolt = <700000>; |
| }; |
| opp01 { |
| opp-hz = /bits/ 64 <910000000>; |
| - opp-microvolt = <675000>; |
| + opp-microvolt = <725000>; |
| }; |
| opp02 { |
| opp-hz = /bits/ 64 <1014000000>; |
| - opp-microvolt = <700000>; |
| + opp-microvolt = <750000>; |
| }; |
| opp03 { |
| opp-hz = /bits/ 64 <1131000000>; |
| - opp-microvolt = <725000>; |
| + opp-microvolt = <775000>; |
| }; |
| opp04 { |
| opp-hz = /bits/ 64 <1248000000>; |
| - opp-microvolt = <750000>; |
| + opp-microvolt = <800000>; |
| }; |
| opp05 { |
| opp-hz = /bits/ 64 <1326000000>; |
| - opp-microvolt = <775000>; |
| + opp-microvolt = <825000>; |
| }; |
| opp06 { |
| opp-hz = /bits/ 64 <1417000000>; |
| - opp-microvolt = <800000>; |
| + opp-microvolt = <850000>; |
| }; |
| opp07 { |
| opp-hz = /bits/ 64 <1508000000>; |
| - opp-microvolt = <825000>; |
| + opp-microvolt = <875000>; |
| }; |
| opp08 { |
| opp-hz = /bits/ 64 <1586000000>; |
| - opp-microvolt = <850000>; |
| + opp-microvolt = <900000>; |
| }; |
| opp09 { |
| opp-hz = /bits/ 64 <1625000000>; |
| - opp-microvolt = <862500>; |
| + opp-microvolt = <912500>; |
| }; |
| opp10 { |
| opp-hz = /bits/ 64 <1677000000>; |
| - opp-microvolt = <881250>; |
| + opp-microvolt = <931250>; |
| }; |
| opp11 { |
| opp-hz = /bits/ 64 <1716000000>; |
| - opp-microvolt = <900000>; |
| + opp-microvolt = <950000>; |
| }; |
| opp12 { |
| opp-hz = /bits/ 64 <1781000000>; |
| - opp-microvolt = <925000>; |
| + opp-microvolt = <975000>; |
| }; |
| opp13 { |
| opp-hz = /bits/ 64 <1846000000>; |
| - opp-microvolt = <950000>; |
| + opp-microvolt = <1000000>; |
| }; |
| opp14 { |
| opp-hz = /bits/ 64 <1924000000>; |
| - opp-microvolt = <975000>; |
| + opp-microvolt = <1025000>; |
| }; |
| opp15 { |
| opp-hz = /bits/ 64 <1989000000>; |
| - opp-microvolt = <1000000>; |
| + opp-microvolt = <1050000>; |
| }; |
| }; |
| |
| @@ -254,6 +255,29 @@ |
| operating-points-v2 = <&cci_opp>; |
| }; |
| |
| + devfreq-cpufreq-map { |
| + cci-cpufreq { |
| + target-dev = <&cci>; |
| + cpu-to-dev-map = |
| + < 793000 273000000 >, |
| + < 910000 403000000 >, |
| + < 1014000 463000000 >, |
| + < 1131000 546000000 >, |
| + < 1248000 624000000 >, |
| + < 1326000 689000000 >, |
| + < 1417000 767000000 >, |
| + < 1508000 871000000 >, |
| + < 1586000 923000000 >, |
| + < 1625000 962000000 >, |
| + < 1677000 1027000000 >, |
| + < 1716000 1092000000 >, |
| + < 1781000 1144000000 >, |
| + < 1846000 1196000000 >, |
| + < 1924000 1196000000 >, |
| + < 1989000 1196000000 >; |
| + }; |
| + }; |
| + |
| cpus { |
| #address-cells = <1>; |
| #size-cells = <0>; |
| @@ -302,6 +326,7 @@ |
| <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>; |
| clock-names = "cpu", "intermediate"; |
| operating-points-v2 = <&cluster0_opp>; |
| + cpu-idle-states = <&MCDI_CPU &MCDI_CLUSTER>; |
| }; |
| |
| cpu1: cpu@1 { |
| @@ -316,6 +341,7 @@ |
| <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>; |
| clock-names = "cpu", "intermediate"; |
| operating-points-v2 = <&cluster0_opp>; |
| + cpu-idle-states = <&MCDI_CPU &MCDI_CLUSTER>; |
| }; |
| |
| cpu2: cpu@2 { |
| @@ -330,6 +356,7 @@ |
| <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>; |
| clock-names = "cpu", "intermediate"; |
| operating-points-v2 = <&cluster0_opp>; |
| + cpu-idle-states = <&MCDI_CPU &MCDI_CLUSTER>; |
| }; |
| |
| cpu3: cpu@3 { |
| @@ -344,6 +371,7 @@ |
| <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>; |
| clock-names = "cpu", "intermediate"; |
| operating-points-v2 = <&cluster0_opp>; |
| + cpu-idle-states = <&MCDI_CPU &MCDI_CLUSTER>; |
| }; |
| |
| cpu4: cpu@100 { |
| @@ -358,6 +386,7 @@ |
| <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>; |
| clock-names = "cpu", "intermediate"; |
| operating-points-v2 = <&cluster1_opp>; |
| + cpu-idle-states = <&MCDI_CPU &MCDI_CLUSTER>; |
| }; |
| |
| cpu5: cpu@101 { |
| @@ -372,6 +401,7 @@ |
| <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>; |
| clock-names = "cpu", "intermediate"; |
| operating-points-v2 = <&cluster1_opp>; |
| + cpu-idle-states = <&MCDI_CPU &MCDI_CLUSTER>; |
| }; |
| |
| cpu6: cpu@102 { |
| @@ -386,6 +416,7 @@ |
| <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>; |
| clock-names = "cpu", "intermediate"; |
| operating-points-v2 = <&cluster1_opp>; |
| + cpu-idle-states = <&MCDI_CPU &MCDI_CLUSTER>; |
| }; |
| |
| cpu7: cpu@103 { |
| @@ -400,6 +431,29 @@ |
| <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>; |
| clock-names = "cpu", "intermediate"; |
| operating-points-v2 = <&cluster1_opp>; |
| + cpu-idle-states = <&MCDI_CPU &MCDI_CLUSTER>; |
| + }; |
| + |
| + idle-states { |
| + entry-method = "arm,psci"; |
| + |
| + MCDI_CPU: mcdi-cpu { |
| + compatible = "arm,idle-state"; |
| + local-timer-stop; |
| + arm,psci-suspend-param = <0x00010001>; |
| + entry-latency-us = <200>; |
| + exit-latency-us = <200>; |
| + min-residency-us = <800>; |
| + }; |
| + |
| + MCDI_CLUSTER: mcdi-cluster { |
| + compatible = "arm,idle-state"; |
| + local-timer-stop; |
| + arm,psci-suspend-param = <0x01010001>; |
| + entry-latency-us = <250>; |
| + exit-latency-us = <400>; |
| + min-residency-us = <1300>; |
| + }; |
| }; |
| }; |
| |
| @@ -603,6 +657,14 @@ |
| clock-names = "spi", "wrap"; |
| }; |
| |
| + systimer@10017000 { |
| + compatible = "mediatek,mt8183-timer", |
| + "mediatek,mt6765-timer"; |
| + reg = <0 0x10017000 0 0x1000>; |
| + interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH>; |
| + clocks = <&topckgen CLK_TOP_CLK13M>; |
| + }; |
| + |
| iommu: iommu@10205000 { |
| compatible = "mediatek,mt8183-m4u"; |
| reg = <0 0x10205000 0 0x1000>; |
| @@ -612,6 +674,38 @@ |
| #iommu-cells = <1>; |
| }; |
| |
| + emi@10219000 { |
| + compatible = "mediatek,mt8183-emi"; |
| + reg = <0 0x10219000 0 0x1000>, /* CEN EMI */ |
| + <0 0x10226000 0 0x1000>, /* EMI MPU */ |
| + <0 0x1022d000 0 0x1000>, /* CHA EMI */ |
| + <0 0x10235000 0 0x1000>; /* CHB EMI */ |
| + interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_LOW>, /* MPU */ |
| + <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>, /* CGM */ |
| + <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>; /* ELM */ |
| + }; |
| + |
| + gce: gce@10238000 { |
| + compatible = "mediatek,mt8183-gce"; |
| + reg = <0 0x10238000 0 0x4000>; |
| + interrupts = <GIC_SPI 162 IRQ_TYPE_LEVEL_LOW>; |
| + #mbox-cells = <3>; |
| + #subsys-cells = <3>; |
| + clocks = <&infracfg CLK_INFRA_GCE>; |
| + clock-names = "gce"; |
| + }; |
| + |
| + vpu: vpu@10500000 { |
| + compatible = "mediatek,mt8183-vpu", "mediatek,mt8173-vpu"; |
| + reg = <0 0x10500000 0 0x80000>, |
| + <0 0x105c0000 0 0x1000>; |
| + reg-names = "tcm", "cfg_reg"; |
| + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; |
| + clocks = <&infracfg CLK_INFRA_SCPSYS>; |
| + clock-names = "main"; |
| + status = "disabled"; |
| + }; |
| + |
| scp: scp@10500000 { |
| compatible = "mediatek,mt8183-scp"; |
| reg = <0 0x10500000 0 0x80000>, |
| @@ -1436,27 +1530,24 @@ |
| power-domains = <&scpsys MT8183_POWER_DOMAIN_DISP>; |
| clocks = <&mmsys CLK_MM_DISP_OVL0>; |
| iommus = <&iommu M4U_PORT_DISP_OVL0>; |
| - mediatek,larb = <&larb0>; |
| }; |
| |
| - ovl0_2l: ovl@14009000 { |
| + ovl_2l0: ovl@14009000 { |
| compatible = "mediatek,mt8183-disp-ovl-2l"; |
| reg = <0 0x14009000 0 0x1000>; |
| interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_LOW>; |
| power-domains = <&scpsys MT8183_POWER_DOMAIN_DISP>; |
| clocks = <&mmsys CLK_MM_DISP_OVL0_2L>; |
| iommus = <&iommu M4U_PORT_DISP_2L_OVL0_LARB0>; |
| - mediatek,larb = <&larb0>; |
| }; |
| |
| - ovl1_2l: ovl@1400a000 { |
| + ovl_2l1: ovl@1400a000 { |
| compatible = "mediatek,mt8183-disp-ovl-2l"; |
| reg = <0 0x1400a000 0 0x1000>; |
| interrupts = <GIC_SPI 227 IRQ_TYPE_LEVEL_LOW>; |
| power-domains = <&scpsys MT8183_POWER_DOMAIN_DISP>; |
| clocks = <&mmsys CLK_MM_DISP_OVL1_2L>; |
| iommus = <&iommu M4U_PORT_DISP_2L_OVL1_LARB0>; |
| - mediatek,larb = <&larb0>; |
| }; |
| |
| rdma0: rdma@1400b000 { |
| @@ -1466,7 +1557,6 @@ |
| power-domains = <&scpsys MT8183_POWER_DOMAIN_DISP>; |
| clocks = <&mmsys CLK_MM_DISP_RDMA0>; |
| iommus = <&iommu M4U_PORT_DISP_RDMA0>; |
| - mediatek,larb = <&larb0>; |
| }; |
| |
| rdma1: rdma@1400c000 { |
| @@ -1476,7 +1566,6 @@ |
| power-domains = <&scpsys MT8183_POWER_DOMAIN_DISP>; |
| clocks = <&mmsys CLK_MM_DISP_RDMA1>; |
| iommus = <&iommu M4U_PORT_DISP_RDMA1>; |
| - mediatek,larb = <&larb0>; |
| }; |
| |
| color0: color@1400e000 { |
| @@ -1536,6 +1625,13 @@ |
| phy-names = "dphy"; |
| }; |
| |
| + mutex: mutex@14016000 { |
| + compatible = "mediatek,mt8183-disp-mutex"; |
| + reg = <0 0x14016000 0 0x1000>; |
| + interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_LOW>; |
| + power-domains = <&scpsys MT8183_POWER_DOMAIN_DISP>; |
| + }; |
| + |
| larb0: larb@14017000 { |
| compatible = "mediatek,mt8183-smi-larb"; |
| reg = <0 0x14017000 0 0x1000>; |
| diff --git a/chromeos/config/arm64/chromiumos-arm64.flavour.config b/chromeos/config/arm64/chromiumos-arm64.flavour.config |
| index de753bd63ded..ba263ecb9cd9 100644 |
| --- a/chromeos/config/arm64/chromiumos-arm64.flavour.config |
| +++ b/chromeos/config/arm64/chromiumos-arm64.flavour.config |
| @@ -40,6 +40,7 @@ CONFIG_DRM_ANALOGIX_ANX78XX=y |
| CONFIG_DRM_MEDIATEK=y |
| CONFIG_DRM_MEDIATEK_HDMI=y |
| # CONFIG_DRM_MSM_HDMI_HDCP is not set |
| +CONFIG_DRM_PANEL_BOE_TV101WUM=y |
| CONFIG_DRM_PANEL_INNOLUX_P079ZCA=y |
| CONFIG_DRM_TI_SN65DSI86=y |
| CONFIG_DRM_VIRTIO_GPU=y |
| @@ -75,6 +76,7 @@ CONFIG_MSM_GCC_8916=y |
| CONFIG_MTD_MT81xx_NOR=y |
| CONFIG_MTK_CMDQ=y |
| CONFIG_MTK_EFUSE=y |
| +CONFIG_MTK_EMI_MBW=y |
| CONFIG_MTK_IOMMU=y |
| CONFIG_MTK_PMIC_WRAP=y |
| CONFIG_MTK_SCP=m |
| @@ -183,8 +185,11 @@ CONFIG_SPI_QCOM_QSPI=y |
| CONFIG_SPI_ROCKCHIP=y |
| CONFIG_SPMI=y |
| CONFIG_TOUCHSCREEN_MELFAS_MIP4=y |
| +CONFIG_USB_CONFIGFS_ACM=y |
| +CONFIG_USB_CONFIGFS_MASS_STORAGE=y |
| +CONFIG_USB_CONFIGFS_SERIAL=y |
| CONFIG_USB_MTU3=y |
| -CONFIG_USB_MTU3_HOST=y |
| +CONFIG_USB_MTU3_DEBUG=y |
| CONFIG_VIDEO_MEDIATEK_MDP=y |
| CONFIG_VIDEO_MEDIATEK_VCODEC=y |
| CONFIG_VIRTIO_BLK=y |
| diff --git a/chromeos/config/arm64/chromiumos-mediatek.flavour.config b/chromeos/config/arm64/chromiumos-mediatek.flavour.config |
| index e02669621c75..9a2ddb58a7d7 100644 |
| --- a/chromeos/config/arm64/chromiumos-mediatek.flavour.config |
| +++ b/chromeos/config/arm64/chromiumos-mediatek.flavour.config |
| @@ -25,10 +25,12 @@ CONFIG_COMMON_CLK_MT8183_MMSYS=y |
| CONFIG_COMMON_CLK_MT8183_VDECSYS=y |
| CONFIG_COMMON_CLK_MT8183_VENCSYS=y |
| CONFIG_CROS_EC_RPMSG=m |
| +CONFIG_DEVFREQ_GOV_CPUFREQ_MAP=y |
| CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y |
| CONFIG_DRM_ANALOGIX_ANX78XX=y |
| CONFIG_DRM_MEDIATEK=y |
| CONFIG_DRM_MEDIATEK_HDMI=y |
| +CONFIG_DRM_PANEL_BOE_TV101WUM=y |
| CONFIG_DRM_PANEL_INNOLUX_P079ZCA=y |
| # CONFIG_EFI is not set |
| CONFIG_ENERGY_MODEL=y |
| @@ -46,6 +48,7 @@ CONFIG_MMC_MTK=y |
| CONFIG_MTD_MT81xx_NOR=y |
| CONFIG_MTK_CMDQ=y |
| CONFIG_MTK_EFUSE=y |
| +CONFIG_MTK_EMI_MBW=y |
| CONFIG_MTK_IOMMU=y |
| CONFIG_MTK_PMIC_WRAP=y |
| CONFIG_MTK_SCP=m |
| @@ -77,7 +80,10 @@ CONFIG_STAGING_MEDIA=y |
| CONFIG_TCG_CR50_I2C=y |
| CONFIG_TMPFS=y |
| CONFIG_TOUCHSCREEN_MELFAS_MIP4=y |
| +CONFIG_USB_CONFIGFS_ACM=y |
| +CONFIG_USB_CONFIGFS_MASS_STORAGE=y |
| +CONFIG_USB_CONFIGFS_SERIAL=y |
| CONFIG_USB_MTU3=y |
| -CONFIG_USB_MTU3_HOST=y |
| +CONFIG_USB_MTU3_DEBUG=y |
| CONFIG_VIDEO_MEDIATEK_MDP=y |
| CONFIG_VIDEO_MEDIATEK_VCODEC=y |
| diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile |
| index 3dc1b9f15ea2..5df0e476e94d 100644 |
| --- a/drivers/clk/mediatek/Makefile |
| +++ b/drivers/clk/mediatek/Makefile |
| @@ -44,3 +44,5 @@ obj-$(CONFIG_COMMON_CLK_MT8183_MFGCFG) += clk-mt8183-mfgcfg.o |
| obj-$(CONFIG_COMMON_CLK_MT8183_MMSYS) += clk-mt8183-mm.o |
| obj-$(CONFIG_COMMON_CLK_MT8183_VDECSYS) += clk-mt8183-vdec.o |
| obj-$(CONFIG_COMMON_CLK_MT8183_VENCSYS) += clk-mt8183-venc.o |
| +obj-$(CONFIG_COMMON_CLK_MT8183) += clkdbg.o clkdbg-mt8183.o |
| +obj-$(CONFIG_COMMON_CLK_MT8183) += clkchk.o clkchk-mt8183.o |
| diff --git a/drivers/clk/mediatek/clk-mt8183.c b/drivers/clk/mediatek/clk-mt8183.c |
| index e8d7bebe2d7a..b35a3c742062 100644 |
| --- a/drivers/clk/mediatek/clk-mt8183.c |
| +++ b/drivers/clk/mediatek/clk-mt8183.c |
| @@ -25,9 +25,11 @@ static const struct mtk_fixed_clk top_fixed_clks[] = { |
| FIXED_CLK(CLK_TOP_UNIVP_192M, "univpll_192m", "univpll", 192000000), |
| }; |
| |
| +static const struct mtk_fixed_factor top_early_divs[] = { |
| + FACTOR(CLK_TOP_CLK13M, "clk13m", "clk26m", 1, 2), |
| +}; |
| + |
| static const struct mtk_fixed_factor top_divs[] = { |
| - FACTOR(CLK_TOP_CLK13M, "clk13m", "clk26m", 1, |
| - 2), |
| FACTOR(CLK_TOP_F26M_CK_D2, "csw_f26m_ck_d2", "clk26m", 1, |
| 2), |
| FACTOR(CLK_TOP_SYSPLL_CK, "syspll_ck", "mainpll", 1, |
| @@ -1148,37 +1150,62 @@ static int clk_mt8183_apmixed_probe(struct platform_device *pdev) |
| return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); |
| } |
| |
| +static struct clk_onecell_data *top_clk_data; |
| + |
| +static void clk_mt8183_top_init_early(struct device_node *node) |
| +{ |
| + int i; |
| + |
| + if (!top_clk_data) { |
| + top_clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); |
| + |
| + for (i = 0; i < CLK_TOP_NR_CLK; i++) |
| + top_clk_data->clks[i] = ERR_PTR(-EPROBE_DEFER); |
| + } |
| + |
| + mtk_clk_register_factors(top_early_divs, ARRAY_SIZE(top_early_divs), |
| + top_clk_data); |
| + |
| + of_clk_add_provider(node, of_clk_src_onecell_get, top_clk_data); |
| +} |
| + |
| +CLK_OF_DECLARE_DRIVER(mt8183_topckgen, "mediatek,mt8183-topckgen", |
| + clk_mt8183_top_init_early); |
| + |
| static int clk_mt8183_top_probe(struct platform_device *pdev) |
| { |
| struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| void __iomem *base; |
| - struct clk_onecell_data *clk_data; |
| struct device_node *node = pdev->dev.of_node; |
| |
| base = devm_ioremap_resource(&pdev->dev, res); |
| if (IS_ERR(base)) |
| return PTR_ERR(base); |
| |
| - clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); |
| + if (!top_clk_data) |
| + top_clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); |
| |
| mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), |
| - clk_data); |
| + top_clk_data); |
| + |
| + mtk_clk_register_factors(top_early_divs, ARRAY_SIZE(top_early_divs), |
| + top_clk_data); |
| |
| - mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data); |
| + mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data); |
| |
| mtk_clk_register_muxes(top_muxes, ARRAY_SIZE(top_muxes), |
| - node, &mt8183_clk_lock, clk_data); |
| + node, &mt8183_clk_lock, top_clk_data); |
| |
| mtk_clk_register_composites(top_aud_muxes, ARRAY_SIZE(top_aud_muxes), |
| - base, &mt8183_clk_lock, clk_data); |
| + base, &mt8183_clk_lock, top_clk_data); |
| |
| mtk_clk_register_composites(top_aud_divs, ARRAY_SIZE(top_aud_divs), |
| - base, &mt8183_clk_lock, clk_data); |
| + base, &mt8183_clk_lock, top_clk_data); |
| |
| mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), |
| - clk_data); |
| + top_clk_data); |
| |
| - return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); |
| + return of_clk_add_provider(node, of_clk_src_onecell_get, top_clk_data); |
| } |
| |
| static int clk_mt8183_infra_probe(struct platform_device *pdev) |
| diff --git a/drivers/clk/mediatek/clkchk-mt8183.c b/drivers/clk/mediatek/clkchk-mt8183.c |
| new file mode 100644 |
| index 000000000000..c7b081fbc44b |
| --- /dev/null |
| +++ b/drivers/clk/mediatek/clkchk-mt8183.c |
| @@ -0,0 +1,387 @@ |
| +// SPDX-License-Identifier: GPL-2.0 |
| +// |
| +// Copyright (c) 2018 MediaTek Inc. |
| +// Author: Weiyi Lu <weiyi.lu@mediatek.com> |
| + |
| +#include <linux/module.h> |
| +#include "clkchk.h" |
| + |
| +static const char * const off_pll_names[] = { |
| + "univ2pll", |
| + "msdcpll", |
| + "mmpll", |
| + "mfgpll", |
| + "tvdpll", |
| + "apll1", |
| + "apll2", |
| + NULL |
| +}; |
| + |
| +static const char * const all_clk_names[] = { |
| + "univ2pll", |
| + "msdcpll", |
| + "mmpll", |
| + "mfgpll", |
| + "tvdpll", |
| + "apll1", |
| + "apll2", |
| + "apmixed_ssusb26m", |
| + "apmixed_mipic026m", |
| + "apmixed_mdpll26m", |
| + "apmixed_mmsys26m", |
| + "apmixed_ufs26m", |
| + "apmixed_mipic126m", |
| + "apmixed_mempll26m", |
| + "apmixed_lvpll26m", |
| + "apmixed_mipid026m", |
| + "apmixed_mipid126m", |
| + "syspll_d3", |
| + "syspll_d5", |
| + "syspll_d2_d2", |
| + "syspll_d2_d4", |
| + "syspll_d2_d16", |
| + "syspll_d3_d2", |
| + "syspll_d3_d4", |
| + "syspll_d3_d8", |
| + "syspll_d5_d2", |
| + "syspll_d5_d4", |
| + "syspll_d7_d2", |
| + "syspll_d7_d4", |
| + "univpll_ck", |
| + "univpll_d2", |
| + "univpll_d3", |
| + "univpll_d5", |
| + "univpll_d7", |
| + "univpll_d2_d2", |
| + "univpll_d2_d4", |
| + "univpll_d2_d8", |
| + "univpll_d3_d2", |
| + "univpll_d3_d4", |
| + "univpll_d3_d8", |
| + "univpll_d5_d2", |
| + "univpll_d5_d4", |
| + "univpll_d5_d8", |
| + "apll1_ck", |
| + "apll1_d2", |
| + "apll1_d4", |
| + "apll1_d8", |
| + "apll2_ck", |
| + "apll2_d2", |
| + "apll2_d4", |
| + "apll2_d8", |
| + "tvdpll_ck", |
| + "tvdpll_d2", |
| + "tvdpll_d4", |
| + "tvdpll_d8", |
| + "tvdpll_d16", |
| + "msdcpll_ck", |
| + "msdcpll_d2", |
| + "msdcpll_d4", |
| + "msdcpll_d8", |
| + "msdcpll_d16", |
| + "ad_osc_ck", |
| + "osc_d2", |
| + "osc_d4", |
| + "osc_d8", |
| + "osc_d16", |
| + "csw_f26m_ck_d2", |
| + "mfgpll_ck", |
| + "univ_192m_ck", |
| + "univ_192m_d2", |
| + "univ_192m_d4", |
| + "univ_192m_d8", |
| + "univ_192m_d16", |
| + "univ_192m_d32", |
| + "mmpll_ck", |
| + "mmpll_d4", |
| + "mmpll_d4_d2", |
| + "mmpll_d4_d4", |
| + "mmpll_d5", |
| + "mmpll_d5_d2", |
| + "mmpll_d5_d4", |
| + "mmpll_d6", |
| + "mmpll_d7", |
| + "osc", |
| + "univpll_192m", |
| + "apll_i2s0_sel", |
| + "apll_i2s1_sel", |
| + "apll_i2s2_sel", |
| + "apll_i2s3_sel", |
| + "apll_i2s4_sel", |
| + "apll_i2s5_sel", |
| + "apll12_div0", |
| + "apll12_div1", |
| + "apll12_div2", |
| + "apll12_div3", |
| + "apll12_div4", |
| + "apll12_divb", |
| + "univpll", |
| + "armpll_div_pll2", |
| + "mm_sel", |
| + "cam_sel", |
| + "mfg_sel", |
| + "camtg_sel", |
| + "spi_sel", |
| + "msdc50_hclk_sel", |
| + "msdc50_0_sel", |
| + "msdc30_1_sel", |
| + "msdc30_2_sel", |
| + "audio_sel", |
| + "aud_intbus_sel", |
| + "fpwrap_ulposc_sel", |
| + "scp_sel", |
| + "atb_sel", |
| + "sspm_sel", |
| + "dpi0_sel", |
| + "scam_sel", |
| + "aud_1_sel", |
| + "aud_2_sel", |
| + "disppwm_sel", |
| + "ssusb_top_xhci_sel", |
| + "usb_top_sel", |
| + "i2c_sel", |
| + "f52m_mfg_sel", |
| + "seninf_sel", |
| + "dxcc_sel", |
| + "camtg2_sel", |
| + "aud_eng1_sel", |
| + "aud_eng2_sel", |
| + "faes_ufsfde_sel", |
| + "fufs_sel", |
| + "img_sel", |
| + "dsp_sel", |
| + "dsp1_sel", |
| + "dsp2_sel", |
| + "ipu_if_sel", |
| + "camtg3_sel", |
| + "camtg4_sel", |
| + "mcu_mp0_sel", |
| + "mcu_mp2_sel", |
| + "mcu_bus_sel", |
| + "infra_pmic_tmr", |
| + "infra_pmic_md", |
| + "infra_pmic_conn", |
| + "infra_scp", |
| + "infra_sej", |
| + "infra_apxgpt", |
| + "infra_icusb", |
| + "infra_gce", |
| + "infra_therm", |
| + "infra_i2c0", |
| + "infra_i2c1", |
| + "infra_i2c2", |
| + "infra_i2c3", |
| + "infra_pwm_hclk", |
| + "infra_pwm1", |
| + "infra_pwm2", |
| + "infra_pwm3", |
| + "infra_pwm4", |
| + "infra_pwm", |
| + "infra_uart1", |
| + "infra_uart2", |
| + "infra_uart3", |
| + "infra_gce_26m", |
| + "infra_cqdma_fpc", |
| + "infra_btif", |
| + "infra_spi0", |
| + "infra_msdc0", |
| + "infra_msdc1", |
| + "infra_msdc2", |
| + "infra_msdc0_sck", |
| + "infra_dvfsrc", |
| + "infra_gcpu", |
| + "infra_trng", |
| + "infra_auxadc", |
| + "infra_cpum", |
| + "infra_ccif1_ap", |
| + "infra_ccif1_md", |
| + "infra_auxadc_md", |
| + "infra_msdc1_sck", |
| + "infra_msdc2_sck", |
| + "infra_apdma", |
| + "infra_xiu", |
| + "infra_device_apc", |
| + "infra_ccif_ap", |
| + "infra_debugsys", |
| + "infra_audio", |
| + "infra_ccif_md", |
| + "infra_dxcc_sec_core", |
| + "infra_dxcc_ao", |
| + "infra_dramc_f26m", |
| + "infra_irtx", |
| + "infra_disppwm", |
| + "infra_cldma_bclk", |
| + "infra_audio_26m_bclk", |
| + "infra_spi1", |
| + "infra_i2c4", |
| + "infra_md_tmp_share", |
| + "infra_spi2", |
| + "infra_spi3", |
| + "infra_unipro_sck", |
| + "infra_unipro_tick", |
| + "infra_ufs_mp_sap_bck", |
| + "infra_md32_bclk", |
| + "infra_sspm", |
| + "infra_unipro_mbist", |
| + "infra_sspm_bus_hclk", |
| + "infra_i2c5", |
| + "infra_i2c5_arbiter", |
| + "infra_i2c5_imm", |
| + "infra_i2c1_arbiter", |
| + "infra_i2c1_imm", |
| + "infra_i2c2_arbiter", |
| + "infra_i2c2_imm", |
| + "infra_spi4", |
| + "infra_spi5", |
| + "infra_cqdma", |
| + "infra_ufs", |
| + "infra_aes_ufsfde", |
| + "infra_ufs_tick", |
| + "infra_msdc0_self", |
| + "infra_msdc1_self", |
| + "infra_msdc2_self", |
| + "infra_sspm_26m_self", |
| + "infra_sspm_32k_self", |
| + "infra_ufs_axi", |
| + "infra_i2c6", |
| + "infra_ap_msdc0", |
| + "infra_md_msdc0", |
| + "infra_usb", |
| + "infra_devmpu_bclk", |
| + "infra_ccif2_ap", |
| + "infra_ccif2_md", |
| + "infra_ccif3_ap", |
| + "infra_ccif3_md", |
| + "infra_sej_f13m", |
| + "infra_aes_bclk", |
| + "infra_i2c7", |
| + "infra_i2c8", |
| + "infra_fbist2fpc", |
| + "aud_tml", |
| + "aud_dac_predis", |
| + "aud_dac", |
| + "aud_adc", |
| + "aud_apll_tuner", |
| + "aud_apll2_tuner", |
| + "aud_24m", |
| + "aud_22m", |
| + "aud_afe", |
| + "aud_i2s4", |
| + "aud_i2s3", |
| + "aud_i2s2", |
| + "aud_i2s1", |
| + "aud_pdn_adda6_adc", |
| + "aud_tdm", |
| + "mfg_bg3d", |
| + "mm_smi_common", |
| + "mm_smi_larb0", |
| + "mm_smi_larb1", |
| + "mm_gals_comm0", |
| + "mm_gals_comm1", |
| + "mm_gals_ccu2mm", |
| + "mm_gals_ipu12mm", |
| + "mm_gals_img2mm", |
| + "mm_gals_cam2mm", |
| + "mm_gals_ipu2mm", |
| + "mm_mdp_dl_txck", |
| + "mm_ipu_dl_txck", |
| + "mm_mdp_rdma0", |
| + "mm_mdp_rdma1", |
| + "mm_mdp_rsz0", |
| + "mm_mdp_rsz1", |
| + "mm_mdp_tdshp", |
| + "mm_mdp_wrot0", |
| + "mm_fake_eng", |
| + "mm_disp_ovl0", |
| + "mm_disp_ovl0_2l", |
| + "mm_disp_ovl1_2l", |
| + "mm_disp_rdma0", |
| + "mm_disp_rdma1", |
| + "mm_disp_wdma0", |
| + "mm_disp_color0", |
| + "mm_disp_ccorr0", |
| + "mm_disp_aal0", |
| + "mm_disp_gamma0", |
| + "mm_disp_dither0", |
| + "mm_disp_split", |
| + "mm_dsi0_mm", |
| + "mm_dsi0_if", |
| + "mm_dpi_mm", |
| + "mm_dpi_if", |
| + "mm_fake_eng2", |
| + "mm_mdp_dl_rx", |
| + "mm_ipu_dl_rx", |
| + "mm_26m", |
| + "mm_mmsys_r2y", |
| + "mm_disp_rsz", |
| + "mm_mdp_wdma0", |
| + "mm_mdp_aal", |
| + "mm_mdp_ccorr", |
| + "mm_dbi_mm", |
| + "mm_dbi_if", |
| + "vdec_vdec", |
| + "vdec_larb1", |
| + "venc_larb", |
| + "venc_venc", |
| + "venc_jpgenc", |
| + "img_owe", |
| + "img_wpe_b", |
| + "img_wpe_a", |
| + "img_mfb", |
| + "img_rsc", |
| + "img_dpe", |
| + "img_fdvt", |
| + "img_dip", |
| + "img_larb2", |
| + "img_larb5", |
| + "cam_larb6", |
| + "cam_dfp_vad", |
| + "cam_cam", |
| + "cam_camtg", |
| + "cam_seninf", |
| + "cam_camsv0", |
| + "cam_camsv1", |
| + "cam_camsv2", |
| + "cam_ccu", |
| + "cam_larb3", |
| + "ipu_conn_ipu", |
| + "ipu_conn_ahb", |
| + "ipu_conn_axi", |
| + "ipu_conn_isp", |
| + "ipu_conn_cam_adl", |
| + "ipu_conn_img_adl", |
| + "ipu_conn_dap_rx", |
| + "ipu_conn_apb2axi", |
| + "ipu_conn_apb2ahb", |
| + "ipu_conn_ipu_cab1to2", |
| + "ipu_conn_ipu1_cab1to2", |
| + "ipu_conn_ipu2_cab1to2", |
| + "ipu_conn_cab3to3", |
| + "ipu_conn_cab2to1", |
| + "ipu_conn_cab3to1_slice", |
| + "ipu_adl_cabgen", |
| + "ipu_core0_jtag", |
| + "ipu_core0_axi", |
| + "ipu_core0_ipu", |
| + "ipu_core1_jtag", |
| + "ipu_core1_axi", |
| + "ipu_core1_ipu", |
| + /* end */ |
| + NULL |
| +}; |
| + |
| +static const char * const compatible[] = {"mediatek,mt8183", NULL}; |
| + |
| +static struct clkchk_cfg_t cfg = { |
| + .aee_excp_on_fail = false, |
| + .warn_on_fail = true, |
| + .compatible = compatible, |
| + .off_pll_names = off_pll_names, |
| + .all_clk_names = all_clk_names, |
| +}; |
| + |
| +static int __init clkchk_platform_init(void) |
| +{ |
| + return clkchk_init(&cfg); |
| +} |
| +subsys_initcall(clkchk_platform_init); |
| diff --git a/drivers/clk/mediatek/clkchk.c b/drivers/clk/mediatek/clkchk.c |
| new file mode 100644 |
| index 000000000000..d50110a0d538 |
| --- /dev/null |
| +++ b/drivers/clk/mediatek/clkchk.c |
| @@ -0,0 +1,188 @@ |
| +// SPDX-License-Identifier: GPL-2.0 |
| +// |
| +// Copyright (c) 2018 MediaTek Inc. |
| +// Author: Weiyi Lu <weiyi.lu@mediatek.com> |
| + |
| +#define pr_fmt(fmt) "[clkchk] " fmt |
| + |
| +#include <linux/clk-provider.h> |
| +#include <linux/syscore_ops.h> |
| +#include "clkchk.h" |
| + |
| +#define AEE_EXCP_CHECK_PLL_FAIL 0 |
| +#define CLKDBG_CCF_API_4_4 1 |
| +#define MAX_PLLS 32 |
| + |
| +#if AEE_EXCP_CHECK_PLL_FAIL |
| +#include <mt-plat/aee.h> |
| +#endif |
| + |
| +#if !CLKDBG_CCF_API_4_4 |
| + |
| +/* backward compatible */ |
| + |
| +static const char *clk_hw_get_name(const struct clk_hw *hw) |
| +{ |
| + return __clk_get_name(hw->clk); |
| +} |
| + |
| +static bool clk_hw_is_prepared(const struct clk_hw *hw) |
| +{ |
| + return __clk_is_prepared(hw->clk); |
| +} |
| + |
| +static bool clk_hw_is_enabled(const struct clk_hw *hw) |
| +{ |
| + return __clk_is_enabled(hw->clk); |
| +} |
| + |
| +static unsigned long clk_hw_get_rate(const struct clk_hw *hw) |
| +{ |
| + return __clk_get_rate(hw->clk); |
| +} |
| + |
| +static struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw) |
| +{ |
| + return __clk_get_hw(clk_get_parent(hw->clk)); |
| +} |
| + |
| +#endif /* !CLKDBG_CCF_API_4_4 */ |
| + |
| +static struct clkchk_cfg_t *clkchk_cfg; |
| + |
| +static const char *ccf_state(struct clk_hw *hw) |
| +{ |
| + if (__clk_get_enable_count(hw->clk)) |
| + return "enabled"; |
| + |
| + if (clk_hw_is_prepared(hw)) |
| + return "prepared"; |
| + |
| + return "disabled"; |
| +} |
| + |
| +static void print_enabled_clks(void) |
| +{ |
| + const char * const *cn = clkchk_cfg->all_clk_names; |
| + |
| + pr_warn("enabled clks:\n"); |
| + |
| + for (; *cn != NULL; cn++) { |
| + struct clk *c = __clk_lookup(*cn); |
| + struct clk_hw *c_hw = __clk_get_hw(c); |
| + struct clk_hw *p_hw; |
| + |
| + if (IS_ERR_OR_NULL(c) || c_hw == NULL) |
| + continue; |
| + |
| + p_hw = clk_hw_get_parent(c_hw); |
| + |
| + if (p_hw == NULL) |
| + continue; |
| + |
| + if (!clk_hw_is_prepared(c_hw) && |
| + __clk_get_enable_count(c) <= 0U) |
| + continue; |
| + |
| + pr_warn("[%-17s: %8s, %3d, %3d, %10ld, %17s]\n", |
| + clk_hw_get_name(c_hw), |
| + ccf_state(c_hw), |
| + clk_hw_is_prepared(c_hw), |
| + __clk_get_enable_count(c), |
| + clk_hw_get_rate(c_hw), |
| + p_hw != NULL ? clk_hw_get_name(p_hw) : "- "); |
| + } |
| +} |
| + |
| +static void check_pll_off(void) |
| +{ |
| + static struct clk *off_plls[MAX_PLLS]; |
| + |
| + struct clk **c; |
| + int invalid = 0; |
| + char buf[128] = {0}; |
| + int n = 0; |
| + |
| + if (off_plls[0] == NULL) { |
| + const char * const *pn = clkchk_cfg->off_pll_names; |
| + struct clk **end = off_plls + MAX_PLLS - 1; |
| + |
| + for (c = off_plls; *pn != NULL && c < end; pn++, c++) |
| + *c = __clk_lookup(*pn); |
| + } |
| + |
| + for (c = off_plls; *c != NULL; c++) { |
| + struct clk_hw *c_hw = __clk_get_hw(*c); |
| + |
| + if (c_hw == NULL) |
| + continue; |
| + |
| + if (!clk_hw_is_prepared(c_hw) && !clk_hw_is_enabled(c_hw)) |
| + continue; |
| + |
| + n += snprintf(buf + n, sizeof(buf) - (size_t)n, "%s ", |
| + clk_hw_get_name(c_hw)); |
| + |
| + invalid++; |
| + } |
| + |
| + if (invalid == 0) |
| + return; |
| + |
| + /* invalid. output debug info */ |
| + |
| + pr_warn("unexpected unclosed PLL: %s\n", buf); |
| + print_enabled_clks(); |
| + |
| +#if AEE_EXCP_CHECK_PLL_FAIL |
| + if (clkchk_cfg->aee_excp_on_fail) |
| + aee_kernel_exception("clkchk", "unclosed PLL: %s\n", buf); |
| +#endif |
| + |
| + if (clkchk_cfg->warn_on_fail) |
| + WARN_ON(true); |
| +} |
| + |
| +static int clkchk_syscore_suspend(void) |
| +{ |
| + check_pll_off(); |
| + |
| + return 0; |
| +} |
| + |
| +static void clkchk_syscore_resume(void) |
| +{ |
| +} |
| + |
| +static struct syscore_ops clkchk_syscore_ops = { |
| + .suspend = clkchk_syscore_suspend, |
| + .resume = clkchk_syscore_resume, |
| +}; |
| + |
| +int clkchk_init(struct clkchk_cfg_t *cfg) |
| +{ |
| + const char * const *c; |
| + bool match = false; |
| + |
| + if (cfg == NULL || cfg->compatible == NULL |
| + || cfg->all_clk_names == NULL || cfg->off_pll_names == NULL) { |
| + pr_warn("Invalid clkchk_cfg.\n"); |
| + return -EINVAL; |
| + } |
| + |
| + clkchk_cfg = cfg; |
| + |
| + for (c = cfg->compatible; *c != NULL; c++) { |
| + if (of_machine_is_compatible(*c) != 0) { |
| + match = true; |
| + break; |
| + } |
| + } |
| + |
| + if (!match) |
| + return -ENODEV; |
| + |
| + register_syscore_ops(&clkchk_syscore_ops); |
| + |
| + return 0; |
| +} |
| diff --git a/drivers/clk/mediatek/clkchk.h b/drivers/clk/mediatek/clkchk.h |
| new file mode 100644 |
| index 000000000000..d99e1acb6477 |
| --- /dev/null |
| +++ b/drivers/clk/mediatek/clkchk.h |
| @@ -0,0 +1,18 @@ |
| +/* SPDX-License-Identifier: GPL-2.0 */ |
| +/* |
| + * Copyright (c) 2018 MediaTek Inc. |
| + * Author: Weiyi Lu <weiyi.lu@mediatek.com> |
| + */ |
| + |
| +#include <stdbool.h> |
| +#include <stddef.h> |
| + |
| +struct clkchk_cfg_t { |
| + bool aee_excp_on_fail; |
| + bool warn_on_fail; |
| + const char * const *compatible; |
| + const char * const *off_pll_names; |
| + const char * const *all_clk_names; |
| +}; |
| + |
| +int clkchk_init(struct clkchk_cfg_t *cfg); |
| diff --git a/drivers/clk/mediatek/clkdbg-mt8183.c b/drivers/clk/mediatek/clkdbg-mt8183.c |
| new file mode 100644 |
| index 000000000000..7b82ef2bce81 |
| --- /dev/null |
| +++ b/drivers/clk/mediatek/clkdbg-mt8183.c |
| @@ -0,0 +1,865 @@ |
| +// SPDX-License-Identifier: GPL-2.0 |
| +// |
| +// Copyright (c) 2018 MediaTek Inc. |
| +// Author: Weiyi Lu <weiyi.lu@mediatek.com> |
| + |
| +#include <linux/clk-provider.h> |
| +#include <linux/io.h> |
| + |
| +#include "clkdbg.h" |
| + |
| +#define DUMP_INIT_STATE 0 |
| + |
| +/* |
| + * clkdbg dump_regs |
| + */ |
| + |
| +enum { |
| + topckgen, |
| + infracfg, |
| + scpsys, |
| + apmixedsys, |
| + audiosys, |
| + mfgsys, |
| + mmsys, |
| + imgsys, |
| + camsys, |
| + vencsys, |
| +}; |
| + |
| +#define REGBASE_V(_phys, _id_name) { .phys = _phys, .name = #_id_name } |
| + |
| +/* |
| + * checkpatch.pl ERROR:COMPLEX_MACRO |
| + * |
| + * #define REGBASE(_phys, _id_name) [_id_name] = REGBASE_V(_phys, _id_name) |
| + */ |
| + |
| +static struct regbase rb[] = { |
| + [topckgen] = REGBASE_V(0x10000000, topckgen), |
| + [infracfg] = REGBASE_V(0x10001000, infracfg), |
| + [scpsys] = REGBASE_V(0x10006000, scpsys), |
| + [apmixedsys] = REGBASE_V(0x1000c000, apmixedsys), |
| + [audiosys] = REGBASE_V(0x11220000, audiosys), |
| + [mfgsys] = REGBASE_V(0x13000000, mfgsys), |
| + [mmsys] = REGBASE_V(0x14000000, mmsys), |
| + [imgsys] = REGBASE_V(0x15020000, imgsys), |
| + [camsys] = REGBASE_V(0x1a000000, camsys), |
| + [vencsys] = REGBASE_V(0x17000000, vencsys), |
| +}; |
| + |
| +#define REGNAME(_base, _ofs, _name) \ |
| + { .base = &rb[_base], .ofs = _ofs, .name = #_name } |
| + |
| +static struct regname rn[] = { |
| + REGNAME(topckgen, 0x040, CLK_CFG_0), |
| + REGNAME(topckgen, 0x050, CLK_CFG_1), |
| + REGNAME(topckgen, 0x060, CLK_CFG_2), |
| + REGNAME(topckgen, 0x070, CLK_CFG_3), |
| + REGNAME(topckgen, 0x080, CLK_CFG_4), |
| + REGNAME(topckgen, 0x090, CLK_CFG_5), |
| + REGNAME(topckgen, 0x0a0, CLK_CFG_6), |
| + REGNAME(topckgen, 0x0b0, CLK_CFG_7), |
| + REGNAME(topckgen, 0x0c0, CLK_CFG_8), |
| + REGNAME(topckgen, 0x0d0, CLK_CFG_9), |
| + REGNAME(topckgen, 0x0e0, CLK_CFG_10), |
| + REGNAME(audiosys, 0x000, AUDIO_TOP_CON0), |
| + REGNAME(audiosys, 0x004, AUDIO_TOP_CON1), |
| + REGNAME(camsys, 0x000, CAMSYS_CG), |
| + REGNAME(imgsys, 0x000, IMG_CG), |
| + REGNAME(infracfg, 0x090, MODULE_SW_CG_0), |
| + REGNAME(infracfg, 0x094, MODULE_SW_CG_1), |
| + REGNAME(infracfg, 0x0ac, MODULE_SW_CG_2), |
| + REGNAME(infracfg, 0x0c8, MODULE_SW_CG_3), |
| + REGNAME(mfgsys, 0x000, MFG_CG), |
| + REGNAME(mmsys, 0x100, MMSYS_CG_CON0), |
| + REGNAME(mmsys, 0x110, MMSYS_CG_CON1), |
| + REGNAME(vencsys, 0x000, VENCSYS_CG), |
| + REGNAME(apmixedsys, 0x200, ARMPLL_LL_CON0), |
| + REGNAME(apmixedsys, 0x204, ARMPLL_LL_CON1), |
| + REGNAME(apmixedsys, 0x20C, ARMPLL_LL_PWR_CON0), |
| + REGNAME(apmixedsys, 0x210, ARMPLL_L_CON0), |
| + REGNAME(apmixedsys, 0x214, ARMPLL_L_CON1), |
| + REGNAME(apmixedsys, 0x21C, ARMPLL_L_PWR_CON0), |
| + REGNAME(apmixedsys, 0x220, MAINPLL_CON0), |
| + REGNAME(apmixedsys, 0x224, MAINPLL_CON1), |
| + REGNAME(apmixedsys, 0x22C, MAINPLL_PWR_CON0), |
| + REGNAME(apmixedsys, 0x230, UNIVPLL_CON0), |
| + REGNAME(apmixedsys, 0x234, UNIVPLL_CON1), |
| + REGNAME(apmixedsys, 0x23C, UNIVPLL_PWR_CON0), |
| + REGNAME(apmixedsys, 0x240, MFGPLL_CON0), |
| + REGNAME(apmixedsys, 0x244, MFGPLL_CON1), |
| + REGNAME(apmixedsys, 0x24C, MFGPLL_PWR_CON0), |
| + REGNAME(apmixedsys, 0x250, MSDCPLL_CON0), |
| + REGNAME(apmixedsys, 0x254, MSDCPLL_CON1), |
| + REGNAME(apmixedsys, 0x25C, MSDCPLL_PWR_CON0), |
| + REGNAME(apmixedsys, 0x260, TVDPLL_CON0), |
| + REGNAME(apmixedsys, 0x264, TVDPLL_CON1), |
| + REGNAME(apmixedsys, 0x26C, TVDPLL_PWR_CON0), |
| + REGNAME(apmixedsys, 0x270, MMPLL_CON0), |
| + REGNAME(apmixedsys, 0x274, MMPLL_CON1), |
| + REGNAME(apmixedsys, 0x27C, MMPLL_PWR_CON0), |
| + REGNAME(apmixedsys, 0x280, MPLL_CON0), |
| + REGNAME(apmixedsys, 0x284, MPLL_CON1), |
| + REGNAME(apmixedsys, 0x28C, MPLL_PWR_CON0), |
| + REGNAME(apmixedsys, 0x290, CCIPLL_CON0), |
| + REGNAME(apmixedsys, 0x294, CCIPLL_CON1), |
| + REGNAME(apmixedsys, 0x29C, CCIPLL_PWR_CON0), |
| + REGNAME(apmixedsys, 0x2A0, APLL1_CON0), |
| + REGNAME(apmixedsys, 0x2A4, APLL1_CON1), |
| + REGNAME(apmixedsys, 0x2B0, APLL1_PWR_CON0), |
| + REGNAME(apmixedsys, 0x2B4, APLL2_CON0), |
| + REGNAME(apmixedsys, 0x2B8, APLL2_CON1), |
| + REGNAME(apmixedsys, 0x2C4, APLL2_PWR_CON0), |
| + REGNAME(scpsys, 0x0180, PWR_STATUS), |
| + REGNAME(scpsys, 0x0184, PWR_STATUS_2ND), |
| + REGNAME(scpsys, 0x0334, MFG_ASYNC_PWR_CON), |
| + REGNAME(scpsys, 0x0338, MFG_PWR_CON), |
| + REGNAME(scpsys, 0x033C, MFG_CORE0_PWR_CON), |
| + REGNAME(scpsys, 0x0340, MFG_CORE1_PWR_CON), |
| + REGNAME(scpsys, 0x0320, MD1_PWR_CON), |
| + REGNAME(scpsys, 0x032C, CONN_PWR_CON), |
| + REGNAME(scpsys, 0x0314, AUD_PWR_CON), |
| + REGNAME(scpsys, 0x030C, DIS_PWR_CON), |
| + REGNAME(scpsys, 0x0344, CAM_PWR_CON), |
| + REGNAME(scpsys, 0x0308, ISP_PWR_CON), |
| + REGNAME(scpsys, 0x0304, VEN_PWR_CON), |
| + {} |
| +}; |
| + |
| +static const struct regname *get_all_regnames(void) |
| +{ |
| + return rn; |
| +} |
| + |
| +static void __init init_regbase(void) |
| +{ |
| + size_t i; |
| + |
| + for (i = 0; i < ARRAY_SIZE(rb); i++) |
| + rb[i].virt = ioremap(rb[i].phys, PAGE_SIZE); |
| +} |
| + |
| +/* |
| + * clkdbg fmeter |
| + */ |
| + |
| +#include <linux/delay.h> |
| + |
| +#define clk_readl(addr) readl(addr) |
| +#define clk_writel(addr, val) \ |
| + do { writel(val, addr); wmb(); } while (0) /* sync write */ |
| + |
| +#define FMCLK(_t, _i, _n) { .type = _t, .id = _i, .name = _n } |
| + |
| +static const struct fmeter_clk fclks[] = { |
| + FMCLK(CKGEN, 1, "hd_faxi_ck"), |
| + FMCLK(CKGEN, 2, "hf_fmm_ck"), |
| + FMCLK(CKGEN, 3, "hf_fimg_ck"), |
| + FMCLK(CKGEN, 4, "hf_fcam_ck"), |
| + FMCLK(CKGEN, 5, "hf_fdsp_ck"), |
| + FMCLK(CKGEN, 6, "hf_fdsp1_ck"), |
| + FMCLK(CKGEN, 7, "hf_fdsp2_ck"), |
| + FMCLK(CKGEN, 8, "hf_fipu_if_ck"), |
| + FMCLK(CKGEN, 9, "hf_fmfg_ck"), |
| + FMCLK(CKGEN, 10, "f52m_mfg_ck"), |
| + FMCLK(CKGEN, 11, "f_fcamtg_ck"), |
| + FMCLK(CKGEN, 12, "f_fcamtg2_ck"), |
| + FMCLK(CKGEN, 13, "f_fcamtg3_ck"), |
| + FMCLK(CKGEN, 14, "f_fcamtg4_ck"), |
| + FMCLK(CKGEN, 15, "f_fuart_ck"), |
| + FMCLK(CKGEN, 16, "hf_fspi_ck"), |
| + FMCLK(CKGEN, 17, "hf_fmsdc50_0_hclk_ck"), |
| + FMCLK(CKGEN, 18, "hf_fmsdc50_0_ck"), |
| + FMCLK(CKGEN, 19, "hf_fmsdc30_1_ck"), |
| + FMCLK(CKGEN, 20, "hf_fmsdc30_2_ck"), |
| + FMCLK(CKGEN, 21, "hf_faudio_ck"), |
| + FMCLK(CKGEN, 22, "hf_faud_intbus_ck"), |
| + FMCLK(CKGEN, 23, "hf_fpmicspi_ck"), |
| + FMCLK(CKGEN, 24, "f_fpwrap_ulposc_ck"), |
| + FMCLK(CKGEN, 25, "hf_fatb_ck"), |
| + FMCLK(CKGEN, 26, "hf_fsspm_ck"), |
| + FMCLK(CKGEN, 27, "hf_fdpi0_ck"), |
| + FMCLK(CKGEN, 28, "hf_fscam_ck"), |
| + FMCLK(CKGEN, 29, "f_fdisp_pwm_ck"), |
| + FMCLK(CKGEN, 30, "f_fusb_top_ck"), |
| + FMCLK(CKGEN, 31, "f_fssusb_xhci_ck"), |
| + FMCLK(CKGEN, 32, "hg_fspm_ck"), |
| + FMCLK(CKGEN, 33, "f_fi2c_ck"), |
| + FMCLK(CKGEN, 34, "hf_fscp_ck"), |
| + FMCLK(CKGEN, 35, "f_fseninf_ck"), |
| + FMCLK(CKGEN, 36, "f_fdxcc_ck"), |
| + FMCLK(CKGEN, 37, "hf_faud_engin1_ck"), |
| + FMCLK(CKGEN, 38, "hf_faud_engin2_ck"), |
| + FMCLK(CKGEN, 39, "hf_faes_ufsfde_ck"), |
| + FMCLK(CKGEN, 40, "hf_fufs_ck"), |
| + FMCLK(CKGEN, 41, "hf_faud_1_ck"), |
| + FMCLK(CKGEN, 42, "hf_faud_2_ck"), |
| + FMCLK(CKGEN, 49, "hf_fref_mm_ck"), |
| + FMCLK(CKGEN, 50, "hf_fref_cam_ck"), |
| + FMCLK(CKGEN, 51, "hf_hddrphycfg_ck"), |
| + FMCLK(CKGEN, 52, "f_ufs_mp_sap_cfg_ck"), |
| + FMCLK(CKGEN, 53, "f_ufs_tick1us_ck"), |
| + FMCLK(CKGEN, 54, "hd_faxi_east_ck"), |
| + FMCLK(CKGEN, 55, "hd_faxi_west_ck"), |
| + FMCLK(CKGEN, 56, "hd_faxi_north_ck"), |
| + FMCLK(CKGEN, 57, "hd_faxi_south_ck"), |
| + FMCLK(CKGEN, 58, "hg_fmipicfg_tx_ck"), |
| + FMCLK(CKGEN, 59, "fmem_ck_bfe_dcm_ch0"), |
| + FMCLK(CKGEN, 60, "fmem_ck_aft_dcm_ch0"), |
| + FMCLK(CKGEN, 61, "fmem_ck_bfe_dcm_ch1"), |
| + FMCLK(CKGEN, 62, "fmem_ck_aft_dcm_ch1"), |
| + FMCLK(CKGEN, 63, "dramc_pll104m_ck"), |
| + FMCLK(ABIST, 1, "AD_WBG_DIG_CK_832M"), |
| + FMCLK(ABIST, 2, "AD_WBG_DIG_CK_960M"), |
| + FMCLK(ABIST, 3, "UFS_MP_CLK2FREQ"), |
| + FMCLK(ABIST, 4, "AD_CSI0A_CDPHY_DELAYCAL_CK"), |
| + FMCLK(ABIST, 5, "AD_CSI0B_CDPHY_DELAYCAL_CK"), |
| + FMCLK(ABIST, 6, "AD_CSI1A_DPHY_DELAYCAL_CK"), |
| + FMCLK(ABIST, 7, "AD_CSI1B_DPHY_DELAYCAL_CK"), |
| + FMCLK(ABIST, 8, "AD_CSI2A_DPHY_DELAYCAL_CK"), |
| + FMCLK(ABIST, 9, "AD_CSI2B_DPHY_DELAYCAL_CK"), |
| + FMCLK(ABIST, 10, "AD_MDBPIPLL_CK"), |
| + FMCLK(ABIST, 11, "AD_MDBRPPLL_CK"), |
| + FMCLK(ABIST, 12, "AD_MDMCUPLL_CK"), |
| + FMCLK(ABIST, 13, "AD_MDTXPLL_CK"), |
| + FMCLK(ABIST, 14, "AD_MDVDSPPLL_CK"), |
| + FMCLK(ABIST, 16, "AD_MDPLL_FS26M_CK"), |
| + FMCLK(ABIST, 20, "AD_ARMPLL_L_CK"), |
| + FMCLK(ABIST, 22, "AD_ARMPLL_LL_CK"), |
| + FMCLK(ABIST, 23, "AD_MAINPLL_1092M_CK"), |
| + FMCLK(ABIST, 24, "AD_UNIVPLL_1248M_CK"), |
| + FMCLK(ABIST, 25, "AD_MFGPLL_CK"), |
| + FMCLK(ABIST, 26, "AD_MSDCPLL_CK"), |
| + FMCLK(ABIST, 27, "AD_MMPLL_CK"), |
| + FMCLK(ABIST, 28, "AD_APLL1_CK"), |
| + FMCLK(ABIST, 29, "AD_APLL2_CK"), |
| + FMCLK(ABIST, 30, "AD_APPLLGP_TST_CK"), |
| + FMCLK(ABIST, 32, "AD_UNIV_192M_CK"), |
| + FMCLK(ABIST, 34, "AD_TVDPLL_CK"), |
| + FMCLK(ABIST, 35, "AD_DSI0_MPPLL_TST_CK"), |
| + FMCLK(ABIST, 36, "AD_DSI0_LNTC_DSICLK"), |
| + FMCLK(ABIST, 37, "AD_OSC_CK_2"), |
| + FMCLK(ABIST, 38, "AD_OSC_CK"), |
| + FMCLK(ABIST, 39, "rtc32k_ck_i"), |
| + FMCLK(ABIST, 40, "mcusys_arm_clk_out_all"), |
| + FMCLK(ABIST, 41, "AD_OSC_SYNC_CK"), |
| + FMCLK(ABIST, 42, "AD_OSC_SYNC_CK_2"), |
| + FMCLK(ABIST, 43, "msdc01_in_ck"), |
| + FMCLK(ABIST, 44, "msdc02_in_ck"), |
| + FMCLK(ABIST, 45, "msdc11_in_ck"), |
| + FMCLK(ABIST, 46, "msdc12_in_ck"), |
| + FMCLK(ABIST, 49, "AD_CCIPLL_CK"), |
| + FMCLK(ABIST, 50, "AD_MPLL_208M_CK"), |
| + FMCLK(ABIST, 51, "AD_WBG_DIG_CK_CK_416M"), |
| + FMCLK(ABIST, 52, "AD_WBG_B_DIG_CK_64M"), |
| + FMCLK(ABIST, 53, "AD_WBG_W_DIG_CK_160M"), |
| + FMCLK(ABIST, 55, "DA_UNIV_48M_DIV_CK"), |
| + FMCLK(ABIST, 57, "DA_MPLL_52M_DIV_CK"), |
| + FMCLK(ABIST, 60, "ckmon1_ck"), |
| + FMCLK(ABIST, 61, "ckmon2_ck"), |
| + FMCLK(ABIST, 62, "ckmon3_ck"), |
| + FMCLK(ABIST, 63, "ckmon4_ck"), |
| + {} |
| +}; |
| + |
| +#define CLK_MISC_CFG_0 (rb[topckgen].virt + 0x104) |
| +#define CLK_DBG_CFG (rb[topckgen].virt + 0x10C) |
| +#define CLK26CALI_0 (rb[topckgen].virt + 0x220) |
| +#define CLK26CALI_1 (rb[topckgen].virt + 0x224) |
| + |
| +static unsigned int mt_get_ckgen_freq(unsigned int ID) |
| +{ |
| + int output = 0, i = 0; |
| + unsigned int temp, clk_dbg_cfg, clk_misc_cfg_0; |
| + |
| + clk_dbg_cfg = clk_readl(CLK_DBG_CFG); |
| + clk_writel(CLK_DBG_CFG, (clk_dbg_cfg & 0xFFFFC0FC)|(ID << 8)|(0x1)); |
| + |
| + clk_misc_cfg_0 = clk_readl(CLK_MISC_CFG_0); |
| + clk_writel(CLK_MISC_CFG_0, (clk_misc_cfg_0 & 0x00FFFFFF)); |
| + |
| + clk_writel(CLK26CALI_0, 0x1000); |
| + clk_writel(CLK26CALI_0, 0x1010); |
| + |
| + while (clk_readl(CLK26CALI_0) & 0x10) { |
| + mdelay(10); |
| + i++; |
| + if (i > 10) |
| + break; |
| + } |
| + |
| + temp = clk_readl(CLK26CALI_1) & 0xFFFF; |
| + |
| + output = (temp * 26000) / 1024; |
| + |
| + clk_writel(CLK_DBG_CFG, clk_dbg_cfg); |
| + clk_writel(CLK_MISC_CFG_0, clk_misc_cfg_0); |
| + |
| + if (i > 10) |
| + return 0; |
| + else |
| + return output; |
| + |
| +} |
| + |
| +static unsigned int mt_get_abist_freq(unsigned int ID) |
| +{ |
| + int output = 0, i = 0; |
| + unsigned int temp, clk_dbg_cfg, clk_misc_cfg_0; |
| + |
| + clk_dbg_cfg = clk_readl(CLK_DBG_CFG); |
| + clk_writel(CLK_DBG_CFG, (clk_dbg_cfg & 0xFFC0FFFC)|(ID << 16)); |
| + |
| + clk_misc_cfg_0 = clk_readl(CLK_MISC_CFG_0); |
| + clk_writel(CLK_MISC_CFG_0, (clk_misc_cfg_0 & 0x00FFFFFF) | (1 << 24)); |
| + |
| + clk_writel(CLK26CALI_0, 0x1000); |
| + clk_writel(CLK26CALI_0, 0x1010); |
| + |
| + while (clk_readl(CLK26CALI_0) & 0x10) { |
| + mdelay(10); |
| + i++; |
| + if (i > 10) |
| + break; |
| + } |
| + |
| + temp = clk_readl(CLK26CALI_1) & 0xFFFF; |
| + |
| + output = (temp * 26000) / 1024; |
| + |
| + clk_writel(CLK_DBG_CFG, clk_dbg_cfg); |
| + clk_writel(CLK_MISC_CFG_0, clk_misc_cfg_0); |
| + |
| + if (i > 10) |
| + return 0; |
| + else |
| + return (output * 2); |
| +} |
| + |
| +static u32 fmeter_freq_op(const struct fmeter_clk *fclk) |
| +{ |
| + if (fclk->type == ABIST) |
| + return mt_get_abist_freq(fclk->id); |
| + else if (fclk->type == CKGEN) |
| + return mt_get_ckgen_freq(fclk->id); |
| + return 0; |
| +} |
| + |
| +static const struct fmeter_clk *get_all_fmeter_clks(void) |
| +{ |
| + return fclks; |
| +} |
| + |
| +/* |
| + * clkdbg dump_state |
| + */ |
| + |
| +static const char * const *get_all_clk_names(void) |
| +{ |
| + static const char * const clks[] = { |
| + "armpll_ll", |
| + "armpll_l", |
| + "ccipll", |
| + "mainpll", |
| + "univ2pll", |
| + "msdcpll", |
| + "mmpll", |
| + "mfgpll", |
| + "tvdpll", |
| + "apll1", |
| + "apll2", |
| + "apmixed_ssusb26m", |
| + "apmixed_appll26m", |
| + "apmixed_mipic026m", |
| + "apmixed_mdpll26m", |
| + "apmixed_mmsys26m", |
| + "apmixed_ufs26m", |
| + "apmixed_mipic126m", |
| + "apmixed_mempll26m", |
| + "apmixed_lvpll26m", |
| + "apmixed_mipid026m", |
| + "apmixed_mipid126m", |
| + "syspll_ck", |
| + "syspll_d2", |
| + "syspll_d3", |
| + "syspll_d5", |
| + "syspll_d7", |
| + "syspll_d2_d2", |
| + "syspll_d2_d4", |
| + "syspll_d2_d8", |
| + "syspll_d2_d16", |
| + "syspll_d3_d2", |
| + "syspll_d3_d4", |
| + "syspll_d3_d8", |
| + "syspll_d5_d2", |
| + "syspll_d5_d4", |
| + "syspll_d7_d2", |
| + "syspll_d7_d4", |
| + "univpll_ck", |
| + "univpll_d2", |
| + "univpll_d3", |
| + "univpll_d5", |
| + "univpll_d7", |
| + "univpll_d2_d2", |
| + "univpll_d2_d4", |
| + "univpll_d2_d8", |
| + "univpll_d3_d2", |
| + "univpll_d3_d4", |
| + "univpll_d3_d8", |
| + "univpll_d5_d2", |
| + "univpll_d5_d4", |
| + "univpll_d5_d8", |
| + "apll1_ck", |
| + "apll1_d2", |
| + "apll1_d4", |
| + "apll1_d8", |
| + "apll2_ck", |
| + "apll2_d2", |
| + "apll2_d4", |
| + "apll2_d8", |
| + "tvdpll_ck", |
| + "tvdpll_d2", |
| + "tvdpll_d4", |
| + "tvdpll_d8", |
| + "tvdpll_d16", |
| + "msdcpll_ck", |
| + "msdcpll_d2", |
| + "msdcpll_d4", |
| + "msdcpll_d8", |
| + "msdcpll_d16", |
| + "ad_osc_ck", |
| + "osc_d2", |
| + "osc_d4", |
| + "osc_d8", |
| + "osc_d16", |
| + "csw_f26m_ck_d2", |
| + "mfgpll_ck", |
| + "univ_192m_ck", |
| + "univ_192m_d2", |
| + "univ_192m_d4", |
| + "univ_192m_d8", |
| + "univ_192m_d16", |
| + "univ_192m_d32", |
| + "mmpll_ck", |
| + "mmpll_d4", |
| + "mmpll_d4_d2", |
| + "mmpll_d4_d4", |
| + "mmpll_d5", |
| + "mmpll_d5_d2", |
| + "mmpll_d5_d4", |
| + "mmpll_d6", |
| + "mmpll_d7", |
| + "f_f26m_ck", |
| + "clk13m", |
| + "osc", |
| + "univpll_192m", |
| + "apll_i2s0_sel", |
| + "apll_i2s1_sel", |
| + "apll_i2s2_sel", |
| + "apll_i2s3_sel", |
| + "apll_i2s4_sel", |
| + "apll_i2s5_sel", |
| + "apll12_div0", |
| + "apll12_div1", |
| + "apll12_div2", |
| + "apll12_div3", |
| + "apll12_div4", |
| + "apll12_divb", |
| + "univpll", |
| + "armpll_div_pll1", |
| + "armpll_div_pll2", |
| + "axi_sel", |
| + "mm_sel", |
| + "cam_sel", |
| + "mfg_sel", |
| + "camtg_sel", |
| + "uart_sel", |
| + "spi_sel", |
| + "msdc50_hclk_sel", |
| + "msdc50_0_sel", |
| + "msdc30_1_sel", |
| + "msdc30_2_sel", |
| + "audio_sel", |
| + "aud_intbus_sel", |
| + "fpwrap_ulposc_sel", |
| + "scp_sel", |
| + "atb_sel", |
| + "sspm_sel", |
| + "dpi0_sel", |
| + "scam_sel", |
| + "aud_1_sel", |
| + "aud_2_sel", |
| + "disppwm_sel", |
| + "ssusb_top_xhci_sel", |
| + "usb_top_sel", |
| + "spm_sel", |
| + "i2c_sel", |
| + "f52m_mfg_sel", |
| + "seninf_sel", |
| + "dxcc_sel", |
| + "camtg2_sel", |
| + "aud_eng1_sel", |
| + "aud_eng2_sel", |
| + "faes_ufsfde_sel", |
| + "fufs_sel", |
| + "img_sel", |
| + "dsp_sel", |
| + "dsp1_sel", |
| + "dsp2_sel", |
| + "ipu_if_sel", |
| + "camtg3_sel", |
| + "camtg4_sel", |
| + "pmicspi_sel", |
| + "mcu_mp0_sel", |
| + "mcu_mp2_sel", |
| + "mcu_bus_sel", |
| + "infra_pmic_tmr", |
| + "infra_pmic_ap", |
| + "infra_pmic_md", |
| + "infra_pmic_conn", |
| + "infra_scp", |
| + "infra_sej", |
| + "infra_apxgpt", |
| + "infra_icusb", |
| + "infra_gce", |
| + "infra_therm", |
| + "infra_i2c0", |
| + "infra_i2c1", |
| + "infra_i2c2", |
| + "infra_i2c3", |
| + "infra_pwm_hclk", |
| + "infra_pwm1", |
| + "infra_pwm2", |
| + "infra_pwm3", |
| + "infra_pwm4", |
| + "infra_pwm", |
| + "infra_uart0", |
| + "infra_uart1", |
| + "infra_uart2", |
| + "infra_uart3", |
| + "infra_gce_26m", |
| + "infra_cqdma_fpc", |
| + "infra_btif", |
| + "infra_spi0", |
| + "infra_msdc0", |
| + "infra_msdc1", |
| + "infra_msdc2", |
| + "infra_msdc0_sck", |
| + "infra_dvfsrc", |
| + "infra_gcpu", |
| + "infra_trng", |
| + "infra_auxadc", |
| + "infra_cpum", |
| + "infra_ccif1_ap", |
| + "infra_ccif1_md", |
| + "infra_auxadc_md", |
| + "infra_msdc1_sck", |
| + "infra_msdc2_sck", |
| + "infra_apdma", |
| + "infra_xiu", |
| + "infra_device_apc", |
| + "infra_ccif_ap", |
| + "infra_debugsys", |
| + "infra_audio", |
| + "infra_ccif_md", |
| + "infra_dxcc_sec_core", |
| + "infra_dxcc_ao", |
| + "infra_dramc_f26m", |
| + "infra_irtx", |
| + "infra_disppwm", |
| + "infra_cldma_bclk", |
| + "infra_audio_26m_bclk", |
| + "infra_spi1", |
| + "infra_i2c4", |
| + "infra_md_tmp_share", |
| + "infra_spi2", |
| + "infra_spi3", |
| + "infra_unipro_sck", |
| + "infra_unipro_tick", |
| + "infra_ufs_mp_sap_bck", |
| + "infra_md32_bclk", |
| + "infra_sspm", |
| + "infra_unipro_mbist", |
| + "infra_sspm_bus_hclk", |
| + "infra_i2c5", |
| + "infra_i2c5_arbiter", |
| + "infra_i2c5_imm", |
| + "infra_i2c1_arbiter", |
| + "infra_i2c1_imm", |
| + "infra_i2c2_arbiter", |
| + "infra_i2c2_imm", |
| + "infra_spi4", |
| + "infra_spi5", |
| + "infra_cqdma", |
| + "infra_ufs", |
| + "infra_aes_ufsfde", |
| + "infra_ufs_tick", |
| + "infra_msdc0_self", |
| + "infra_msdc1_self", |
| + "infra_msdc2_self", |
| + "infra_sspm_26m_self", |
| + "infra_sspm_32k_self", |
| + "infra_ufs_axi", |
| + "infra_i2c6", |
| + "infra_ap_msdc0", |
| + "infra_md_msdc0", |
| + "infra_usb", |
| + "infra_devmpu_bclk", |
| + "infra_ccif2_ap", |
| + "infra_ccif2_md", |
| + "infra_ccif3_ap", |
| + "infra_ccif3_md", |
| + "infra_sej_f13m", |
| + "infra_aes_bclk", |
| + "infra_i2c7", |
| + "infra_i2c8", |
| + "infra_fbist2fpc", |
| + "aud_tml", |
| + "aud_dac_predis", |
| + "aud_dac", |
| + "aud_adc", |
| + "aud_apll_tuner", |
| + "aud_apll2_tuner", |
| + "aud_24m", |
| + "aud_22m", |
| + "aud_afe", |
| + "aud_i2s4", |
| + "aud_i2s3", |
| + "aud_i2s2", |
| + "aud_i2s1", |
| + "aud_pdn_adda6_adc", |
| + "aud_tdm", |
| + "mfg_bg3d", |
| + "mm_smi_common", |
| + "mm_smi_larb0", |
| + "mm_smi_larb1", |
| + "mm_gals_comm0", |
| + "mm_gals_comm1", |
| + "mm_gals_ccu2mm", |
| + "mm_gals_ipu12mm", |
| + "mm_gals_img2mm", |
| + "mm_gals_cam2mm", |
| + "mm_gals_ipu2mm", |
| + "mm_mdp_dl_txck", |
| + "mm_ipu_dl_txck", |
| + "mm_mdp_rdma0", |
| + "mm_mdp_rdma1", |
| + "mm_mdp_rsz0", |
| + "mm_mdp_rsz1", |
| + "mm_mdp_tdshp", |
| + "mm_mdp_wrot0", |
| + "mm_fake_eng", |
| + "mm_disp_ovl0", |
| + "mm_disp_ovl0_2l", |
| + "mm_disp_ovl1_2l", |
| + "mm_disp_rdma0", |
| + "mm_disp_rdma1", |
| + "mm_disp_wdma0", |
| + "mm_disp_color0", |
| + "mm_disp_ccorr0", |
| + "mm_disp_aal0", |
| + "mm_disp_gamma0", |
| + "mm_disp_dither0", |
| + "mm_disp_split", |
| + "mm_dsi0_mm", |
| + "mm_dsi0_if", |
| + "mm_dpi_mm", |
| + "mm_dpi_if", |
| + "mm_fake_eng2", |
| + "mm_mdp_dl_rx", |
| + "mm_ipu_dl_rx", |
| + "mm_26m", |
| + "mm_mmsys_r2y", |
| + "mm_disp_rsz", |
| + "mm_mdp_wdma0", |
| + "mm_mdp_aal", |
| + "mm_mdp_ccorr", |
| + "mm_dbi_mm", |
| + "mm_dbi_if", |
| + "vdec_vdec", |
| + "vdec_larb1", |
| + "venc_larb", |
| + "venc_venc", |
| + "venc_jpgenc", |
| + "img_owe", |
| + "img_wpe_b", |
| + "img_wpe_a", |
| + "img_mfb", |
| + "img_rsc", |
| + "img_dpe", |
| + "img_fdvt", |
| + "img_dip", |
| + "img_larb2", |
| + "img_larb5", |
| + "cam_larb6", |
| + "cam_dfp_vad", |
| + "cam_cam", |
| + "cam_camtg", |
| + "cam_seninf", |
| + "cam_camsv0", |
| + "cam_camsv1", |
| + "cam_camsv2", |
| + "cam_ccu", |
| + "cam_larb3", |
| + "ipu_conn_ipu", |
| + "ipu_conn_ahb", |
| + "ipu_conn_axi", |
| + "ipu_conn_isp", |
| + "ipu_conn_cam_adl", |
| + "ipu_conn_img_adl", |
| + "ipu_conn_dap_rx", |
| + "ipu_conn_apb2axi", |
| + "ipu_conn_apb2ahb", |
| + "ipu_conn_ipu_cab1to2", |
| + "ipu_conn_ipu1_cab1to2", |
| + "ipu_conn_ipu2_cab1to2", |
| + "ipu_conn_cab3to3", |
| + "ipu_conn_cab2to1", |
| + "ipu_conn_cab3to1_slice", |
| + "ipu_adl_cabgen", |
| + "ipu_core0_jtag", |
| + "ipu_core0_axi", |
| + "ipu_core0_ipu", |
| + "ipu_core1_jtag", |
| + "ipu_core1_axi", |
| + "ipu_core1_ipu", |
| + /* end */ |
| + NULL |
| + }; |
| + |
| + return clks; |
| +} |
| + |
| +/* |
| + * clkdbg pwr_status |
| + */ |
| + |
| +static const char * const *get_pwr_names(void) |
| +{ |
| + static const char * const pwr_names[] = { |
| + [0] = "MD1", |
| + [1] = "CONN", |
| + [2] = "DDRPHY", |
| + [3] = "DISP", |
| + [4] = "MFG", |
| + [5] = "ISP", |
| + [6] = "INFRA", |
| + [7] = "MFG_CORE0", |
| + [8] = "MP0_CPUTOP", |
| + [9] = "MP0_CPU0", |
| + [10] = "MP0_CPU1", |
| + [11] = "MP0_CPU2", |
| + [12] = "MP0_CPU3", |
| + [13] = "", |
| + [14] = "", |
| + [15] = "", |
| + [16] = "", |
| + [17] = "", |
| + [18] = "", |
| + [19] = "", |
| + [20] = "MFG_CORE1", |
| + [21] = "VENC", |
| + [22] = "MFG_2D", |
| + [23] = "MFG_ASYNC", |
| + [24] = "AUDIO", |
| + [25] = "CAM", |
| + [26] = "VPU_TOP", |
| + [27] = "VPU_CORE0", |
| + [28] = "VPU_CORE1", |
| + [29] = "VPU_CORE2", |
| + [30] = "", |
| + [31] = "VDEC", |
| + }; |
| + |
| + return pwr_names; |
| +} |
| + |
| +u32 get_spm_pwr_status(void) |
| +{ |
| + static void __iomem *scpsys_base, *pwr_sta, *pwr_sta_2nd; |
| + |
| + if (scpsys_base == NULL || pwr_sta == NULL || pwr_sta_2nd == NULL) { |
| + scpsys_base = ioremap(0x10006000, PAGE_SIZE); |
| + pwr_sta = scpsys_base + 0x180; |
| + pwr_sta_2nd = scpsys_base + 0x184; |
| + } |
| + |
| + return clk_readl(pwr_sta) & clk_readl(pwr_sta_2nd); |
| +} |
| + |
| +/* |
| + * clkdbg dump_clks |
| + */ |
| + |
| +static void setup_provider_clk(struct provider_clk *pvdck) |
| +{ |
| + static const struct { |
| + const char *pvdname; |
| + u32 pwr_mask; |
| + } pvd_pwr_mask[] = { |
| + {"mmsys", BIT(3)}, |
| + {"imgsys", BIT(5)}, |
| + {"camsys", BIT(25)}, |
| + {"ipu_conn", BIT(26)}, |
| + {"ipu_core0", BIT(27)}, |
| + {"ipu_core1", BIT(28)}, |
| + {"audiosys", BIT(24)}, |
| + {"mfgcfg", BIT(22)}, |
| + }; |
| + |
| + size_t i; |
| + const char *pvdname = pvdck->provider_name; |
| + |
| + if (pvdname == NULL) |
| + return; |
| + |
| + for (i = 0; i < ARRAY_SIZE(pvd_pwr_mask); i++) { |
| + if (strcmp(pvdname, pvd_pwr_mask[i].pvdname) == 0) { |
| + pvdck->pwr_mask = pvd_pwr_mask[i].pwr_mask; |
| + return; |
| + } |
| + } |
| +} |
| + |
| +/* |
| + * init functions |
| + */ |
| + |
| +static struct clkdbg_ops clkdbg_mt8183_ops = { |
| + .get_all_fmeter_clks = get_all_fmeter_clks, |
| + .fmeter_freq = fmeter_freq_op, |
| + .get_all_regnames = get_all_regnames, |
| + .get_all_clk_names = get_all_clk_names, |
| + .get_pwr_names = get_pwr_names, |
| + .setup_provider_clk = setup_provider_clk, |
| + .get_spm_pwr_status = get_spm_pwr_status, |
| +}; |
| + |
| +static void __init init_custom_cmds(void) |
| +{ |
| + static const struct cmd_fn cmds[] = { |
| + {} |
| + }; |
| + |
| + set_custom_cmds(cmds); |
| +} |
| + |
| +static int __init clkdbg_mt8183_init(void) |
| +{ |
| + if (of_machine_is_compatible("mediatek,mt8183") == 0) |
| + return -ENODEV; |
| + |
| + init_regbase(); |
| + |
| + init_custom_cmds(); |
| + set_clkdbg_ops(&clkdbg_mt8183_ops); |
| + |
| +#if DUMP_INIT_STATE |
| + print_regs(); |
| + print_fmeter_all(); |
| +#endif /* DUMP_INIT_STATE */ |
| + |
| + return 0; |
| +} |
| +device_initcall(clkdbg_mt8183_init); |
| diff --git a/drivers/clk/mediatek/clkdbg.c b/drivers/clk/mediatek/clkdbg.c |
| new file mode 100644 |
| index 000000000000..8c9f67968160 |
| --- /dev/null |
| +++ b/drivers/clk/mediatek/clkdbg.c |
| @@ -0,0 +1,2242 @@ |
| +// SPDX-License-Identifier: GPL-2.0 |
| +// |
| +// Copyright (c) 2018 MediaTek Inc. |
| +// Author: Weiyi Lu <weiyi.lu@mediatek.com> |
| + |
| +#define pr_fmt(fmt) "[clkdbg] " fmt |
| + |
| +#include <linux/of.h> |
| +#include <linux/of_address.h> |
| +#include <linux/of_platform.h> |
| +#include <linux/slab.h> |
| +#include <linux/delay.h> |
| + |
| +#include <linux/proc_fs.h> |
| +#include <linux/fs.h> |
| +#include <linux/seq_file.h> |
| +#include <linux/uaccess.h> |
| + |
| +#include <linux/clk.h> |
| +#include <linux/clk-provider.h> |
| +#include <linux/pm_domain.h> |
| +#include <linux/pm_runtime.h> |
| +#include <linux/module.h> |
| +#include <linux/version.h> |
| + |
| +#include "clkdbg.h" |
| + |
| +#if defined(CONFIG_PM_DEBUG) |
| +#define CLKDBG_PM_DOMAIN 1 |
| +#else |
| +#define CLKDBG_PM_DOMAIN 0 |
| +#endif |
| +#define CLKDBG_PM_DOMAIN_API_4_9 1 |
| +#define CLKDBG_CCF_API_4_4 1 |
| +#define CLKDBG_HACK_CLK 0 |
| +#define CLKDBG_HACK_CLK_CORE 1 |
| +#define CLKDBG_DROP_GENPD_AS_IN_PARAM 1 |
| + |
| +#if !CLKDBG_CCF_API_4_4 |
| + |
| +/* backward compatible */ |
| + |
| +static const char *clk_hw_get_name(const struct clk_hw *hw) |
| +{ |
| + return __clk_get_name(hw->clk); |
| +} |
| + |
| +static bool clk_hw_is_prepared(const struct clk_hw *hw) |
| +{ |
| + return __clk_is_prepared(hw->clk); |
| +} |
| + |
| +static bool clk_hw_is_enabled(const struct clk_hw *hw) |
| +{ |
| + return __clk_is_enabled(hw->clk); |
| +} |
| + |
| +static unsigned long clk_hw_get_rate(const struct clk_hw *hw) |
| +{ |
| + return __clk_get_rate(hw->clk); |
| +} |
| + |
| +static unsigned int clk_hw_get_num_parents(const struct clk_hw *hw) |
| +{ |
| + return __clk_get_num_parents(hw->clk); |
| +} |
| + |
| +static struct clk_hw *clk_hw_get_parent_by_index(const struct clk_hw *hw, |
| + unsigned int index) |
| +{ |
| + return __clk_get_hw(clk_get_parent_by_index(hw->clk, index)); |
| +} |
| + |
| +#endif /* !CLKDBG_CCF_API_4_4 */ |
| + |
| +#if CLKDBG_HACK_CLK |
| + |
| +#include <linux/clk-private.h> |
| + |
| +static bool clk_hw_is_on(struct clk_hw *hw) |
| +{ |
| + const struct clk_ops *ops = hw->clk->ops; |
| + |
| + if (ops->is_enabled) |
| + return clk_hw_is_enabled(hw); |
| + else if (ops->is_prepared) |
| + return clk_hw_is_prepared(hw); |
| + return clk_hw_is_enabled(hw) || clk_hw_is_prepared(hw); |
| +} |
| + |
| +#elif CLKDBG_HACK_CLK_CORE |
| + |
| +struct clk_core { |
| + const char *name; |
| + const struct clk_ops *ops; |
| + struct clk_hw *hw; |
| +}; |
| + |
| +static bool clk_hw_is_on(struct clk_hw *hw) |
| +{ |
| + const struct clk_ops *ops = hw->core->ops; |
| + |
| + if (ops->is_enabled) |
| + return clk_hw_is_enabled(hw); |
| + else if (ops->is_prepared) |
| + return clk_hw_is_prepared(hw); |
| + return clk_hw_is_enabled(hw) || clk_hw_is_prepared(hw); |
| +} |
| + |
| +#else |
| + |
| +static bool clk_hw_is_on(struct clk_hw *hw) |
| +{ |
| + return __clk_get_enable_count(hw->clk) || clk_hw_is_prepared(hw); |
| +} |
| + |
| +#endif /* !CLKDBG_HACK_CLK && !CLKDBG_HACK_CLK_CORE */ |
| + |
| +static const struct clkdbg_ops *clkdbg_ops; |
| + |
| +void set_clkdbg_ops(const struct clkdbg_ops *ops) |
| +{ |
| + clkdbg_ops = ops; |
| +} |
| + |
| +static const struct fmeter_clk *get_all_fmeter_clks(void) |
| +{ |
| + if (clkdbg_ops == NULL || clkdbg_ops->get_all_fmeter_clks == NULL) |
| + return NULL; |
| + |
| + return clkdbg_ops->get_all_fmeter_clks(); |
| +} |
| + |
| +static void *prepare_fmeter(void) |
| +{ |
| + if (clkdbg_ops == NULL || clkdbg_ops->prepare_fmeter == NULL) |
| + return NULL; |
| + |
| + return clkdbg_ops->prepare_fmeter(); |
| +} |
| + |
| +static void unprepare_fmeter(void *data) |
| +{ |
| + if (clkdbg_ops == NULL || clkdbg_ops->unprepare_fmeter == NULL) |
| + return; |
| + |
| + clkdbg_ops->unprepare_fmeter(data); |
| +} |
| + |
| +static u32 fmeter_freq(const struct fmeter_clk *fclk) |
| +{ |
| + if (clkdbg_ops == NULL || clkdbg_ops->fmeter_freq == NULL) |
| + return 0; |
| + |
| + return clkdbg_ops->fmeter_freq(fclk); |
| +} |
| + |
| +static const struct regname *get_all_regnames(void) |
| +{ |
| + if (clkdbg_ops == NULL || clkdbg_ops->get_all_regnames == NULL) |
| + return NULL; |
| + |
| + return clkdbg_ops->get_all_regnames(); |
| +} |
| + |
| +static const char * const *get_all_clk_names(void) |
| +{ |
| + if (clkdbg_ops == NULL || clkdbg_ops->get_all_clk_names == NULL) |
| + return NULL; |
| + |
| + return clkdbg_ops->get_all_clk_names(); |
| +} |
| + |
| +static const char * const *get_pwr_names(void) |
| +{ |
| + static const char * const default_pwr_names[] = { |
| + [0] = "(MD)", |
| + [1] = "(CONN)", |
| + [2] = "(DDRPHY)", |
| + [3] = "(DISP)", |
| + [4] = "(MFG)", |
| + [5] = "(ISP)", |
| + [6] = "(INFRA)", |
| + [7] = "(VDEC)", |
| + [8] = "(CPU, CA7_CPUTOP)", |
| + [9] = "(FC3, CA7_CPU0, CPUTOP)", |
| + [10] = "(FC2, CA7_CPU1, CPU3)", |
| + [11] = "(FC1, CA7_CPU2, CPU2)", |
| + [12] = "(FC0, CA7_CPU3, CPU1)", |
| + [13] = "(MCUSYS, CA7_DBG, CPU0)", |
| + [14] = "(MCUSYS, VEN, BDP)", |
| + [15] = "(CA15_CPUTOP, ETH, MCUSYS)", |
| + [16] = "(CA15_CPU0, HIF)", |
| + [17] = "(CA15_CPU1, CA15-CX0, INFRA_MISC)", |
| + [18] = "(CA15_CPU2, CA15-CX1)", |
| + [19] = "(CA15_CPU3, CA15-CPU0)", |
| + [20] = "(VEN2, MJC, CA15-CPU1)", |
| + [21] = "(VEN, CA15-CPUTOP)", |
| + [22] = "(MFG_2D)", |
| + [23] = "(MFG_ASYNC, DBG)", |
| + [24] = "(AUDIO, MFG_2D)", |
| + [25] = "(USB, VCORE_PDN, MFG_ASYNC)", |
| + [26] = "(ARMPLL_DIV, CPUTOP_SRM_SLPB)", |
| + [27] = "(MD2, CPUTOP_SRM_PDN)", |
| + [28] = "(CPU3_SRM_PDN)", |
| + [29] = "(CPU2_SRM_PDN)", |
| + [30] = "(CPU1_SRM_PDN)", |
| + [31] = "(CPU0_SRM_PDN)", |
| + }; |
| + |
| + if (clkdbg_ops == NULL || clkdbg_ops->get_pwr_names == NULL) |
| + return default_pwr_names; |
| + |
| + return clkdbg_ops->get_pwr_names(); |
| +} |
| + |
| +static void setup_provider_clk(struct provider_clk *pvdck) |
| +{ |
| + if (clkdbg_ops == NULL || clkdbg_ops->setup_provider_clk == NULL) |
| + return; |
| + |
| + clkdbg_ops->setup_provider_clk(pvdck); |
| +} |
| + |
| +static bool is_valid_reg(void __iomem *addr) |
| +{ |
| +#ifdef CONFIG_64BIT |
| + return ((u64)addr & 0xf0000000) != 0UL || |
| + (((u64)addr >> 32U) & 0xf0000000) != 0UL; |
| +#else |
| + return ((u32)addr & 0xf0000000) != 0U; |
| +#endif |
| +} |
| + |
| +enum clkdbg_opt { |
| + CLKDBG_EN_SUSPEND_SAVE_1, |
| + CLKDBG_EN_SUSPEND_SAVE_2, |
| + CLKDBG_EN_SUSPEND_SAVE_3, |
| + CLKDBG_EN_LOG_SAVE_POINTS, |
| +}; |
| + |
| +static u32 clkdbg_flags; |
| + |
| +static void set_clkdbg_flag(enum clkdbg_opt opt) |
| +{ |
| + clkdbg_flags |= BIT(opt); |
| +} |
| + |
| +static void clr_clkdbg_flag(enum clkdbg_opt opt) |
| +{ |
| + clkdbg_flags &= ~BIT(opt); |
| +} |
| + |
| +static bool has_clkdbg_flag(enum clkdbg_opt opt) |
| +{ |
| + return (clkdbg_flags & BIT(opt)) != 0U; |
| +} |
| + |
| +typedef void (*fn_fclk_freq_proc)(const struct fmeter_clk *fclk, |
| + u32 freq, void *data); |
| + |
| +static void proc_all_fclk_freq(fn_fclk_freq_proc proc, void *data) |
| +{ |
| + void *fmeter_data; |
| + const struct fmeter_clk *fclk; |
| + |
| + fclk = get_all_fmeter_clks(); |
| + |
| + if (fclk == NULL || proc == NULL) |
| + return; |
| + |
| + fmeter_data = prepare_fmeter(); |
| + |
| + for (; fclk->type != FT_NULL; fclk++) { |
| + u32 freq; |
| + |
| + freq = fmeter_freq(fclk); |
| + proc(fclk, freq, data); |
| + } |
| + |
| + unprepare_fmeter(fmeter_data); |
| +} |
| + |
| +static void print_fclk_freq(const struct fmeter_clk *fclk, u32 freq, void *data) |
| +{ |
| + pr_info("%2d: %-29s: %u\n", fclk->id, fclk->name, freq); |
| +} |
| + |
| +void print_fmeter_all(void) |
| +{ |
| + proc_all_fclk_freq(print_fclk_freq, NULL); |
| +} |
| + |
| +static void seq_print_fclk_freq(const struct fmeter_clk *fclk, |
| + u32 freq, void *data) |
| +{ |
| + struct seq_file *s = data; |
| + |
| + seq_printf(s, "%2d: %-29s: %u\n", fclk->id, fclk->name, freq); |
| +} |
| + |
| +static int seq_print_fmeter_all(struct seq_file *s, void *v) |
| +{ |
| + proc_all_fclk_freq(seq_print_fclk_freq, s); |
| + |
| + return 0; |
| +} |
| + |
| +typedef void (*fn_regname_proc)(const struct regname *rn, void *data); |
| + |
| +static void proc_all_regname(fn_regname_proc proc, void *data) |
| +{ |
| + const struct regname *rn = get_all_regnames(); |
| + |
| + if (rn == NULL) |
| + return; |
| + |
| + for (; rn->base != NULL; rn++) |
| + proc(rn, data); |
| +} |
| + |
| +static void print_reg(const struct regname *rn, void *data) |
| +{ |
| + if (!is_valid_reg(ADDR(rn))) |
| + return; |
| + |
| + pr_info("%-21s: [0x%08x][0x%p] = 0x%08x\n", |
| + rn->name, PHYSADDR(rn), ADDR(rn), clk_readl(ADDR(rn))); |
| +} |
| + |
| +void print_regs(void) |
| +{ |
| + proc_all_regname(print_reg, NULL); |
| +} |
| + |
| +static void seq_print_reg(const struct regname *rn, void *data) |
| +{ |
| + struct seq_file *s = data; |
| + |
| + if (!is_valid_reg(ADDR(rn))) |
| + return; |
| + |
| + seq_printf(s, "%-21s: [0x%08x][0x%p] = 0x%08x\n", |
| + rn->name, PHYSADDR(rn), ADDR(rn), clk_readl(ADDR(rn))); |
| +} |
| + |
| +static int seq_print_regs(struct seq_file *s, void *v) |
| +{ |
| + proc_all_regname(seq_print_reg, s); |
| + |
| + return 0; |
| +} |
| + |
| +static void print_reg2(const struct regname *rn, void *data) |
| +{ |
| + if (!is_valid_reg(ADDR(rn))) |
| + return; |
| + |
| + pr_info("%-21s: [0x%08x][0x%p] = 0x%08x\n", |
| + rn->name, PHYSADDR(rn), ADDR(rn), clk_readl(ADDR(rn))); |
| + |
| + msleep(20); |
| +} |
| + |
| +static int clkdbg_dump_regs2(struct seq_file *s, void *v) |
| +{ |
| + proc_all_regname(print_reg2, s); |
| + |
| + return 0; |
| +} |
| + |
| +static u32 read_spm_pwr_status(void) |
| +{ |
| + static void __iomem *scpsys_base, *pwr_sta, *pwr_sta_2nd; |
| + |
| + if (clkdbg_ops == NULL || clkdbg_ops->get_spm_pwr_status == NULL) { |
| + if (scpsys_base == NULL || |
| + pwr_sta == NULL || pwr_sta_2nd == NULL) { |
| + scpsys_base = ioremap(0x10006000, PAGE_SIZE); |
| + pwr_sta = scpsys_base + 0x60c; |
| + pwr_sta_2nd = scpsys_base + 0x610; |
| + } |
| + |
| + return clk_readl(pwr_sta) & clk_readl(pwr_sta_2nd); |
| + } else |
| + return clkdbg_ops->get_spm_pwr_status(); |
| +} |
| + |
| +static bool clk_hw_pwr_is_on(struct clk_hw *c_hw, |
| + u32 spm_pwr_status, u32 pwr_mask) |
| +{ |
| + if ((spm_pwr_status & pwr_mask) != pwr_mask) |
| + return false; |
| + |
| + return clk_hw_is_on(c_hw); |
| +} |
| + |
| +static bool pvdck_pwr_is_on(struct provider_clk *pvdck, u32 spm_pwr_status) |
| +{ |
| + struct clk *c = pvdck->ck; |
| + struct clk_hw *c_hw = __clk_get_hw(c); |
| + |
| + return clk_hw_pwr_is_on(c_hw, spm_pwr_status, pvdck->pwr_mask); |
| +} |
| + |
| +static bool pvdck_is_on(struct provider_clk *pvdck) |
| +{ |
| + u32 spm_pwr_status = 0; |
| + |
| + if (pvdck->pwr_mask != 0U) |
| + spm_pwr_status = read_spm_pwr_status(); |
| + |
| + return pvdck_pwr_is_on(pvdck, spm_pwr_status); |
| +} |
| + |
| +static const char *ccf_state(struct clk_hw *hw) |
| +{ |
| + if (__clk_get_enable_count(hw->clk)) |
| + return "enabled"; |
| + |
| + if (clk_hw_is_prepared(hw)) |
| + return "prepared"; |
| + |
| + return "disabled"; |
| +} |
| + |
| +static void dump_clk_state(const char *clkname, struct seq_file *s) |
| +{ |
| + struct clk *c = __clk_lookup(clkname); |
| + struct clk *p = IS_ERR_OR_NULL(c) ? NULL : clk_get_parent(c); |
| + struct clk_hw *c_hw = __clk_get_hw(c); |
| + struct clk_hw *p_hw = __clk_get_hw(p); |
| + |
| + if (IS_ERR_OR_NULL(c)) { |
| + seq_printf(s, "[%17s: NULL]\n", clkname); |
| + return; |
| + } |
| + |
| + seq_printf(s, "[%-17s: %8s, %3d, %3d, %10ld, %17s]\n", |
| + clk_hw_get_name(c_hw), |
| + ccf_state(c_hw), |
| + clk_hw_is_prepared(c_hw), |
| + __clk_get_enable_count(c), |
| + clk_hw_get_rate(c_hw), |
| + p != NULL ? clk_hw_get_name(p_hw) : "- "); |
| +} |
| + |
| +static int clkdbg_dump_state_all(struct seq_file *s, void *v) |
| +{ |
| + const char * const *ckn = get_all_clk_names(); |
| + |
| + if (ckn == NULL) |
| + return 0; |
| + |
| + for (; *ckn != NULL; ckn++) |
| + dump_clk_state(*ckn, s); |
| + |
| + return 0; |
| +} |
| + |
| +static const char *get_provider_name(struct device_node *node, u32 *cells) |
| +{ |
| + const char *name; |
| + const char *p; |
| + u32 cc; |
| + |
| + if (of_property_read_u32(node, "#clock-cells", &cc) != 0) |
| + cc = 0; |
| + |
| + if (cells != NULL) |
| + *cells = cc; |
| + |
| + if (cc == 0U) { |
| + if (of_property_read_string(node, |
| + "clock-output-names", &name) < 0) |
| + name = node->name; |
| + |
| + return name; |
| + } |
| + |
| + if (of_property_read_string(node, "compatible", &name) < 0) |
| + name = node->name; |
| + |
| + p = strchr(name, (int)'-'); |
| + |
| + if (p != NULL) |
| + return p + 1; |
| + else |
| + return name; |
| +} |
| + |
| +struct provider_clk *get_all_provider_clks(void) |
| +{ |
| + static struct provider_clk provider_clks[512]; |
| + struct device_node *node = NULL; |
| + int n = 0; |
| + |
| + if (provider_clks[0].ck != NULL) |
| + return provider_clks; |
| + |
| + do { |
| + const char *node_name; |
| + u32 cells; |
| + |
| + node = of_find_node_with_property(node, "#clock-cells"); |
| + |
| + if (node == NULL) |
| + break; |
| + |
| + node_name = get_provider_name(node, &cells); |
| + |
| + if (cells == 0U) { |
| + struct clk *ck = __clk_lookup(node_name); |
| + |
| + if (IS_ERR_OR_NULL(ck)) |
| + continue; |
| + |
| + provider_clks[n].ck = ck; |
| + setup_provider_clk(&provider_clks[n]); |
| + ++n; |
| + } else { |
| + unsigned int i; |
| + |
| + for (i = 0; i < 256; i++) { |
| + struct of_phandle_args pa; |
| + struct clk *ck; |
| + |
| + pa.np = node; |
| + pa.args[0] = i; |
| + pa.args_count = 1; |
| + ck = of_clk_get_from_provider(&pa); |
| + |
| + if (PTR_ERR(ck) == -EINVAL) |
| + break; |
| + else if (IS_ERR_OR_NULL(ck)) |
| + continue; |
| + |
| + provider_clks[n].ck = ck; |
| + provider_clks[n].idx = i; |
| + provider_clks[n].provider_name = node_name; |
| + setup_provider_clk(&provider_clks[n]); |
| + ++n; |
| + } |
| + } |
| + } while (node != NULL); |
| + |
| + return provider_clks; |
| +} |
| + |
| +static void dump_provider_clk(struct provider_clk *pvdck, struct seq_file *s) |
| +{ |
| + struct clk *c = pvdck->ck; |
| + struct clk *p = IS_ERR_OR_NULL(c) ? NULL : clk_get_parent(c); |
| + struct clk_hw *c_hw = __clk_get_hw(c); |
| + struct clk_hw *p_hw = __clk_get_hw(p); |
| + |
| + seq_printf(s, "[%10s: %-17s: %3s, %3d, %3d, %10ld, %17s]\n", |
| + pvdck->provider_name != NULL ? pvdck->provider_name : "/ ", |
| + clk_hw_get_name(c_hw), |
| + pvdck_is_on(pvdck) ? "ON" : "off", |
| + clk_hw_is_prepared(c_hw), |
| + __clk_get_enable_count(c), |
| + clk_hw_get_rate(c_hw), |
| + p != NULL ? clk_hw_get_name(p_hw) : "- "); |
| +} |
| + |
| +static int clkdbg_dump_provider_clks(struct seq_file *s, void *v) |
| +{ |
| + struct provider_clk *pvdck = get_all_provider_clks(); |
| + |
| + for (; pvdck->ck != NULL; pvdck++) |
| + dump_provider_clk(pvdck, s); |
| + |
| + return 0; |
| +} |
| + |
| +static void dump_provider_mux(struct provider_clk *pvdck, struct seq_file *s) |
| +{ |
| + unsigned int i; |
| + struct clk *c = pvdck->ck; |
| + struct clk_hw *c_hw = __clk_get_hw(c); |
| + unsigned int np = clk_hw_get_num_parents(c_hw); |
| + |
| + if (np <= 1U) |
| + return; |
| + |
| + dump_provider_clk(pvdck, s); |
| + |
| + for (i = 0; i < np; i++) { |
| + struct clk_hw *p_hw = clk_hw_get_parent_by_index(c_hw, i); |
| + |
| + if (IS_ERR_OR_NULL(p_hw)) |
| + continue; |
| + |
| + seq_printf(s, "\t\t\t(%2d: %-17s: %8s, %10ld)\n", |
| + i, |
| + clk_hw_get_name(p_hw), |
| + ccf_state(p_hw), |
| + clk_hw_get_rate(p_hw)); |
| + } |
| +} |
| + |
| +static int clkdbg_dump_muxes(struct seq_file *s, void *v) |
| +{ |
| + struct provider_clk *pvdck = get_all_provider_clks(); |
| + |
| + for (; pvdck->ck != NULL; pvdck++) |
| + dump_provider_mux(pvdck, s); |
| + |
| + return 0; |
| +} |
| + |
| +static void show_pwr_status(u32 spm_pwr_status) |
| +{ |
| + unsigned int i; |
| + const char * const *pwr_name = get_pwr_names(); |
| + |
| + pr_info("SPM_PWR_STATUS: 0x%08x\n\n", spm_pwr_status); |
| + |
| + for (i = 0; i < 32; i++) { |
| + const char *st = (spm_pwr_status & BIT(i)) != 0U ? "ON" : "off"; |
| + |
| + pr_info("[%2d]: %3s: %s\n", i, st, pwr_name[i]); |
| + mdelay(20); |
| + } |
| +} |
| + |
| +static int dump_pwr_status(u32 spm_pwr_status, struct seq_file *s) |
| +{ |
| + unsigned int i; |
| + const char * const *pwr_name = get_pwr_names(); |
| + |
| + seq_printf(s, "SPM_PWR_STATUS: 0x%08x\n\n", spm_pwr_status); |
| + |
| + for (i = 0; i < 32; i++) { |
| + const char *st = (spm_pwr_status & BIT(i)) != 0U ? "ON" : "off"; |
| + |
| + seq_printf(s, "[%2d]: %3s: %s\n", i, st, pwr_name[i]); |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +static int clkdbg_pwr_status(struct seq_file *s, void *v) |
| +{ |
| + return dump_pwr_status(read_spm_pwr_status(), s); |
| +} |
| + |
| +static char last_cmd[128] = "null"; |
| + |
| +const char *get_last_cmd(void) |
| +{ |
| + return last_cmd; |
| +} |
| + |
| +static int clkop_int_ckname(int (*clkop)(struct clk *clk), |
| + const char *clkop_name, const char *clk_name, |
| + struct clk *ck, struct seq_file *s) |
| +{ |
| + struct clk *clk; |
| + |
| + if (!IS_ERR_OR_NULL(ck)) { |
| + clk = ck; |
| + } else { |
| + clk = __clk_lookup(clk_name); |
| + if (IS_ERR_OR_NULL(clk)) { |
| + seq_printf(s, "clk_lookup(%s): 0x%p\n", clk_name, clk); |
| + return PTR_ERR(clk); |
| + } |
| + } |
| + |
| + return clkop(clk); |
| +} |
| + |
| +static int clkdbg_clkop_int_ckname(int (*clkop)(struct clk *clk), |
| + const char *clkop_name, struct seq_file *s, void *v) |
| +{ |
| + char cmd[sizeof(last_cmd)]; |
| + char *c = cmd; |
| + char *ign; |
| + char *clk_name; |
| + int r = 0; |
| + |
| + strncpy(cmd, last_cmd, sizeof(cmd)); |
| + cmd[sizeof(cmd) - 1UL] = '\0'; |
| + |
| + ign = strsep(&c, " "); |
| + clk_name = strsep(&c, " "); |
| + |
| + if (clk_name == NULL) |
| + return 0; |
| + |
| + if (strcmp(clk_name, "all") == 0) { |
| + struct provider_clk *pvdck = get_all_provider_clks(); |
| + |
| + for (; pvdck->ck != NULL; pvdck++) { |
| + r |= clkop_int_ckname(clkop, clkop_name, NULL, |
| + pvdck->ck, s); |
| + } |
| + |
| + seq_printf(s, "%s(%s): %d\n", clkop_name, clk_name, r); |
| + |
| + return r; |
| + } |
| + |
| + r = clkop_int_ckname(clkop, clkop_name, clk_name, NULL, s); |
| + seq_printf(s, "%s(%s): %d\n", clkop_name, clk_name, r); |
| + |
| + return r; |
| +} |
| + |
| +static void clkop_void_ckname(void (*clkop)(struct clk *clk), |
| + const char *clkop_name, const char *clk_name, |
| + struct clk *ck, struct seq_file *s) |
| +{ |
| + struct clk *clk; |
| + |
| + if (!IS_ERR_OR_NULL(ck)) { |
| + clk = ck; |
| + } else { |
| + clk = __clk_lookup(clk_name); |
| + if (IS_ERR_OR_NULL(clk)) { |
| + seq_printf(s, "clk_lookup(%s): 0x%p\n", clk_name, clk); |
| + return; |
| + } |
| + } |
| + |
| + clkop(clk); |
| +} |
| + |
| +static int clkdbg_clkop_void_ckname(void (*clkop)(struct clk *clk), |
| + const char *clkop_name, struct seq_file *s, void *v) |
| +{ |
| + char cmd[sizeof(last_cmd)]; |
| + char *c = cmd; |
| + char *ign; |
| + char *clk_name; |
| + |
| + strncpy(cmd, last_cmd, sizeof(cmd)); |
| + cmd[sizeof(cmd) - 1UL] = '\0'; |
| + |
| + ign = strsep(&c, " "); |
| + clk_name = strsep(&c, " "); |
| + |
| + if (clk_name == NULL) |
| + return 0; |
| + |
| + if (strcmp(clk_name, "all") == 0) { |
| + struct provider_clk *pvdck = get_all_provider_clks(); |
| + |
| + for (; pvdck->ck != NULL; pvdck++) { |
| + clkop_void_ckname(clkop, clkop_name, NULL, |
| + pvdck->ck, s); |
| + } |
| + |
| + seq_printf(s, "%s(%s)\n", clkop_name, clk_name); |
| + |
| + return 0; |
| + } |
| + |
| + clkop_void_ckname(clkop, clkop_name, clk_name, NULL, s); |
| + seq_printf(s, "%s(%s)\n", clkop_name, clk_name); |
| + |
| + return 0; |
| +} |
| + |
| +static int clkdbg_prepare(struct seq_file *s, void *v) |
| +{ |
| + return clkdbg_clkop_int_ckname(clk_prepare, |
| + "clk_prepare", s, v); |
| +} |
| + |
| +static int clkdbg_unprepare(struct seq_file *s, void *v) |
| +{ |
| + return clkdbg_clkop_void_ckname(clk_unprepare, |
| + "clk_unprepare", s, v); |
| +} |
| + |
| +static int clkdbg_enable(struct seq_file *s, void *v) |
| +{ |
| + return clkdbg_clkop_int_ckname(clk_enable, |
| + "clk_enable", s, v); |
| +} |
| + |
| +static int clkdbg_disable(struct seq_file *s, void *v) |
| +{ |
| + return clkdbg_clkop_void_ckname(clk_disable, |
| + "clk_disable", s, v); |
| +} |
| + |
| +static int clkdbg_prepare_enable(struct seq_file *s, void *v) |
| +{ |
| + return clkdbg_clkop_int_ckname(clk_prepare_enable, |
| + "clk_prepare_enable", s, v); |
| +} |
| + |
| +static int clkdbg_disable_unprepare(struct seq_file *s, void *v) |
| +{ |
| + return clkdbg_clkop_void_ckname(clk_disable_unprepare, |
| + "clk_disable_unprepare", s, v); |
| +} |
| + |
| +void prepare_enable_provider(const char *pvd) |
| +{ |
| + bool allpvd = (pvd == NULL || strcmp(pvd, "all") == 0); |
| + struct provider_clk *pvdck = get_all_provider_clks(); |
| + |
| + for (; pvdck->ck != NULL; pvdck++) { |
| + if (allpvd || (pvdck->provider_name != NULL && |
| + strcmp(pvd, pvdck->provider_name) == 0)) { |
| + int r = clk_prepare_enable(pvdck->ck); |
| + |
| + if (r != 0) |
| + pr_info("clk_prepare_enable(): %d\n", r); |
| + } |
| + } |
| +} |
| + |
| +void disable_unprepare_provider(const char *pvd) |
| +{ |
| + bool allpvd = (pvd == NULL || strcmp(pvd, "all") == 0); |
| + struct provider_clk *pvdck = get_all_provider_clks(); |
| + |
| + for (; pvdck->ck != NULL; pvdck++) { |
| + if (allpvd || (pvdck->provider_name != NULL && |
| + strcmp(pvd, pvdck->provider_name) == 0)) |
| + clk_disable_unprepare(pvdck->ck); |
| + } |
| +} |
| + |
| +static void clkpvdop(void (*pvdop)(const char *), const char *clkpvdop_name, |
| + struct seq_file *s) |
| +{ |
| + char cmd[sizeof(last_cmd)]; |
| + char *c = cmd; |
| + char *ign; |
| + char *pvd_name; |
| + |
| + strncpy(cmd, last_cmd, sizeof(cmd)); |
| + cmd[sizeof(cmd) - 1UL] = '\0'; |
| + |
| + ign = strsep(&c, " "); |
| + pvd_name = strsep(&c, " "); |
| + |
| + if (pvd_name == NULL) |
| + return; |
| + |
| + pvdop(pvd_name); |
| + seq_printf(s, "%s(%s)\n", clkpvdop_name, pvd_name); |
| +} |
| + |
| +static int clkdbg_prepare_enable_provider(struct seq_file *s, void *v) |
| +{ |
| + clkpvdop(prepare_enable_provider, "prepare_enable_provider", s); |
| + return 0; |
| +} |
| + |
| +static int clkdbg_disable_unprepare_provider(struct seq_file *s, void *v) |
| +{ |
| + clkpvdop(disable_unprepare_provider, "disable_unprepare_provider", s); |
| + return 0; |
| +} |
| + |
| +static int clkdbg_set_parent(struct seq_file *s, void *v) |
| +{ |
| + char cmd[sizeof(last_cmd)]; |
| + char *c = cmd; |
| + char *ign; |
| + char *clk_name; |
| + char *parent_name; |
| + struct clk *clk; |
| + struct clk *parent; |
| + int r; |
| + |
| + strncpy(cmd, last_cmd, sizeof(cmd)); |
| + cmd[sizeof(cmd) - 1UL] = '\0'; |
| + |
| + ign = strsep(&c, " "); |
| + clk_name = strsep(&c, " "); |
| + parent_name = strsep(&c, " "); |
| + |
| + if (clk_name == NULL || parent_name == NULL) |
| + return 0; |
| + |
| + seq_printf(s, "clk_set_parent(%s, %s): ", clk_name, parent_name); |
| + |
| + clk = __clk_lookup(clk_name); |
| + if (IS_ERR_OR_NULL(clk)) { |
| + seq_printf(s, "__clk_lookup(): 0x%p\n", clk); |
| + return PTR_ERR(clk); |
| + } |
| + |
| + parent = __clk_lookup(parent_name); |
| + if (IS_ERR_OR_NULL(parent)) { |
| + seq_printf(s, "__clk_lookup(): 0x%p\n", parent); |
| + return PTR_ERR(parent); |
| + } |
| + |
| + r = clk_prepare_enable(clk); |
| + if (r != 0) { |
| + seq_printf(s, "clk_prepare_enable(): %d\n", r); |
| + return r; |
| + } |
| + |
| + r = clk_set_parent(clk, parent); |
| + seq_printf(s, "%d\n", r); |
| + |
| + clk_disable_unprepare(clk); |
| + |
| + return r; |
| +} |
| + |
| +static int clkdbg_set_rate(struct seq_file *s, void *v) |
| +{ |
| + char cmd[sizeof(last_cmd)]; |
| + char *c = cmd; |
| + char *ign; |
| + char *clk_name; |
| + char *rate_str; |
| + struct clk *clk; |
| + unsigned long rate; |
| + int r; |
| + |
| + strncpy(cmd, last_cmd, sizeof(cmd)); |
| + cmd[sizeof(cmd) - 1UL] = '\0'; |
| + |
| + ign = strsep(&c, " "); |
| + clk_name = strsep(&c, " "); |
| + rate_str = strsep(&c, " "); |
| + |
| + if (clk_name == NULL || rate_str == NULL) |
| + return 0; |
| + |
| + r = kstrtoul(rate_str, 0, &rate); |
| + |
| + seq_printf(s, "clk_set_rate(%s, %lu): %d: ", clk_name, rate, r); |
| + |
| + clk = __clk_lookup(clk_name); |
| + if (IS_ERR_OR_NULL(clk)) { |
| + seq_printf(s, "__clk_lookup(): 0x%p\n", clk); |
| + return PTR_ERR(clk); |
| + } |
| + |
| + r = clk_set_rate(clk, rate); |
| + seq_printf(s, "%d\n", r); |
| + |
| + return r; |
| +} |
| + |
| +static void *reg_from_str(const char *str) |
| +{ |
| + static phys_addr_t phys; |
| + static void __iomem *virt; |
| + |
| + if (sizeof(void *) == sizeof(unsigned long)) { |
| + unsigned long v; |
| + |
| + if (kstrtoul(str, 0, &v) == 0U) { |
| + if ((0xf0000000 & v) < 0x20000000) { |
| + if (virt != NULL && v > phys |
| + && v < phys + PAGE_SIZE) |
| + return virt + v - phys; |
| + |
| + if (virt != NULL) |
| + iounmap(virt); |
| + |
| + phys = v & ~(PAGE_SIZE - 1U); |
| + virt = ioremap(phys, PAGE_SIZE); |
| + |
| + return virt + v - phys; |
| + } |
| + |
| + return (void *)((uintptr_t)v); |
| + } |
| + } else if (sizeof(void *) == sizeof(unsigned long long)) { |
| + unsigned long long v; |
| + |
| + if (kstrtoull(str, 0, &v) == 0) { |
| + if ((0xfffffffff0000000ULL & v) < 0x20000000) { |
| + if (virt && v > phys && v < phys + PAGE_SIZE) |
| + return virt + v - phys; |
| + |
| + if (virt != NULL) |
| + iounmap(virt); |
| + |
| + phys = v & ~(PAGE_SIZE - 1); |
| + virt = ioremap(phys, PAGE_SIZE); |
| + |
| + return virt + v - phys; |
| + } |
| + |
| + return (void *)((uintptr_t)v); |
| + } |
| + } else { |
| + pr_warn("unexpected pointer size: sizeof(void *): %zu\n", |
| + sizeof(void *)); |
| + } |
| + |
| + pr_warn("%s(): parsing error: %s\n", __func__, str); |
| + |
| + return NULL; |
| +} |
| + |
| +static int parse_reg_val_from_cmd(void __iomem **preg, unsigned long *pval) |
| +{ |
| + char cmd[sizeof(last_cmd)]; |
| + char *c = cmd; |
| + char *ign; |
| + char *reg_str; |
| + char *val_str; |
| + int r = 0; |
| + |
| + strncpy(cmd, last_cmd, sizeof(cmd)); |
| + cmd[sizeof(cmd) - 1UL] = '\0'; |
| + |
| + ign = strsep(&c, " "); |
| + reg_str = strsep(&c, " "); |
| + val_str = strsep(&c, " "); |
| + |
| + if (preg != NULL && reg_str != NULL) { |
| + *preg = reg_from_str(reg_str); |
| + if (*preg != NULL) |
| + r++; |
| + } |
| + |
| + if (pval != NULL && val_str != NULL && kstrtoul(val_str, 0, pval) == 0) |
| + r++; |
| + |
| + return r; |
| +} |
| + |
| +static int clkdbg_reg_read(struct seq_file *s, void *v) |
| +{ |
| + void __iomem *reg; |
| + unsigned long val; |
| + |
| + if (parse_reg_val_from_cmd(®, NULL) != 1) |
| + return 0; |
| + |
| + seq_printf(s, "readl(0x%p): ", reg); |
| + |
| + val = clk_readl(reg); |
| + seq_printf(s, "0x%08x\n", (u32)val); |
| + |
| + return 0; |
| +} |
| + |
| +static int clkdbg_reg_write(struct seq_file *s, void *v) |
| +{ |
| + void __iomem *reg; |
| + unsigned long val; |
| + |
| + if (parse_reg_val_from_cmd(®, &val) != 2) |
| + return 0; |
| + |
| + seq_printf(s, "writel(0x%p, 0x%08x): ", reg, (u32)val); |
| + |
| + clk_writel(reg, val); |
| + val = clk_readl(reg); |
| + seq_printf(s, "0x%08x\n", (u32)val); |
| + |
| + return 0; |
| +} |
| + |
| +static int clkdbg_reg_set(struct seq_file *s, void *v) |
| +{ |
| + void __iomem *reg; |
| + unsigned long val; |
| + |
| + if (parse_reg_val_from_cmd(®, &val) != 2) |
| + return 0; |
| + |
| + seq_printf(s, "writel(0x%p, 0x%08x): ", reg, (u32)val); |
| + |
| + clk_setl(reg, val); |
| + val = clk_readl(reg); |
| + seq_printf(s, "0x%08x\n", (u32)val); |
| + |
| + return 0; |
| +} |
| + |
| +static int clkdbg_reg_clr(struct seq_file *s, void *v) |
| +{ |
| + void __iomem *reg; |
| + unsigned long val; |
| + |
| + if (parse_reg_val_from_cmd(®, &val) != 2) |
| + return 0; |
| + |
| + seq_printf(s, "writel(0x%p, 0x%08x): ", reg, (u32)val); |
| + |
| + clk_clrl(reg, val); |
| + val = clk_readl(reg); |
| + seq_printf(s, "0x%08x\n", (u32)val); |
| + |
| + return 0; |
| +} |
| + |
| +static int parse_val_from_cmd(unsigned long *pval) |
| +{ |
| + char cmd[sizeof(last_cmd)]; |
| + char *c = cmd; |
| + char *ign; |
| + char *val_str; |
| + int r = 0; |
| + |
| + strncpy(cmd, last_cmd, sizeof(cmd)); |
| + cmd[sizeof(cmd) - 1UL] = '\0'; |
| + |
| + ign = strsep(&c, " "); |
| + val_str = strsep(&c, " "); |
| + |
| + if (pval != NULL && val_str != NULL && kstrtoul(val_str, 0, pval) == 0) |
| + r++; |
| + |
| + return r; |
| +} |
| + |
| +static int clkdbg_show_flags(struct seq_file *s, void *v) |
| +{ |
| + static const char * const clkdbg_opt_name[] = { |
| + "CLKDBG_EN_SUSPEND_SAVE_1", |
| + "CLKDBG_EN_SUSPEND_SAVE_2", |
| + "CLKDBG_EN_SUSPEND_SAVE_3", |
| + "CLKDBG_EN_LOG_SAVE_POINTS", |
| + }; |
| + |
| + size_t i; |
| + |
| + seq_printf(s, "clkdbg_flags: 0x%08x\n", clkdbg_flags); |
| + |
| + for (i = 0; i < ARRAY_SIZE(clkdbg_opt_name); i++) { |
| + const char *onff = |
| + has_clkdbg_flag((enum clkdbg_opt)i) ? "ON" : "off"; |
| + |
| + seq_printf(s, "[%2zd]: %3s: %s\n", i, onff, clkdbg_opt_name[i]); |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +static int clkdbg_set_flag(struct seq_file *s, void *v) |
| +{ |
| + unsigned long val; |
| + |
| + if (parse_val_from_cmd(&val) != 1) |
| + return 0; |
| + |
| + set_clkdbg_flag((enum clkdbg_opt)val); |
| + |
| + seq_printf(s, "clkdbg_flags: 0x%08x\n", clkdbg_flags); |
| + |
| + return 0; |
| +} |
| + |
| +static int clkdbg_clr_flag(struct seq_file *s, void *v) |
| +{ |
| + unsigned long val; |
| + |
| + if (parse_val_from_cmd(&val) != 1) |
| + return 0; |
| + |
| + clr_clkdbg_flag((enum clkdbg_opt)val); |
| + |
| + seq_printf(s, "clkdbg_flags: 0x%08x\n", clkdbg_flags); |
| + |
| + return 0; |
| +} |
| + |
| +#if CLKDBG_PM_DOMAIN |
| + |
| +/* |
| + * pm_domain support |
| + */ |
| + |
| +static struct generic_pm_domain **get_all_genpd(void) |
| +{ |
| + static struct generic_pm_domain *pds[20]; |
| + static int num_pds; |
| + const size_t maxpd = ARRAY_SIZE(pds); |
| + struct device_node *node; |
| +#if CLKDBG_PM_DOMAIN_API_4_9 |
| + struct platform_device *pdev; |
| + int r; |
| +#endif |
| + |
| + if (num_pds != 0) |
| + goto out; |
| + |
| + node = of_find_node_with_property(NULL, "#power-domain-cells"); |
| + |
| + if (node == NULL) |
| + return NULL; |
| + |
| +#if CLKDBG_PM_DOMAIN_API_4_9 |
| + pdev = platform_device_alloc("traverse", 0); |
| +#endif |
| + |
| + for (num_pds = 0; num_pds < maxpd; num_pds++) { |
| + struct of_phandle_args pa; |
| + |
| + pa.np = node; |
| + pa.args[0] = num_pds; |
| + pa.args_count = 1; |
| + |
| +#if CLKDBG_PM_DOMAIN_API_4_9 |
| + r = of_genpd_add_device(&pa, &pdev->dev); |
| + if (r == -EINVAL) |
| + continue; |
| + else if (r != 0) |
| + pr_warn("%s(): of_genpd_add_device(%d)\n", __func__, r); |
| + pds[num_pds] = pd_to_genpd(pdev->dev.pm_domain); |
| +#if CLKDBG_DROP_GENPD_AS_IN_PARAM |
| + r = pm_genpd_remove_device(&pdev->dev); |
| +#else |
| + r = pm_genpd_remove_device(pds[num_pds], &pdev->dev); |
| +#endif |
| + if (r != 0) |
| + pr_warn("%s(): pm_genpd_remove_device(%d)\n", |
| + __func__, r); |
| +#else |
| + pds[num_pds] = of_genpd_get_from_provider(&pa); |
| +#endif |
| + |
| + if (IS_ERR(pds[num_pds])) { |
| + pds[num_pds] = NULL; |
| + break; |
| + } |
| + } |
| + |
| +#if CLKDBG_PM_DOMAIN_API_4_9 |
| + platform_device_put(pdev); |
| +#endif |
| + |
| +out: |
| + return pds; |
| +} |
| + |
| +static struct platform_device *pdev_from_name(const char *name) |
| +{ |
| + struct generic_pm_domain **pds = get_all_genpd(); |
| + |
| + for (; *pds != NULL; pds++) { |
| + struct pm_domain_data *pdd; |
| + struct generic_pm_domain *pd = *pds; |
| + |
| + if (IS_ERR_OR_NULL(pd)) |
| + continue; |
| + |
| + list_for_each_entry(pdd, &pd->dev_list, list_node) { |
| + struct device *dev = pdd->dev; |
| + struct platform_device *pdev = to_platform_device(dev); |
| + |
| + if (strcmp(name, pdev->name) == 0) |
| + return pdev; |
| + } |
| + } |
| + |
| + return NULL; |
| +} |
| + |
| +static struct generic_pm_domain *genpd_from_name(const char *name) |
| +{ |
| + struct generic_pm_domain **pds = get_all_genpd(); |
| + |
| + for (; *pds != NULL; pds++) { |
| + struct generic_pm_domain *pd = *pds; |
| + |
| + if (IS_ERR_OR_NULL(pd)) |
| + continue; |
| + |
| + if (strcmp(name, pd->name) == 0) |
| + return pd; |
| + } |
| + |
| + return NULL; |
| +} |
| + |
| +struct genpd_dev_state { |
| + struct device *dev; |
| + bool active; |
| + atomic_t usage_count; |
| + unsigned int disable_depth; |
| + enum rpm_status runtime_status; |
| +}; |
| + |
| +struct genpd_state { |
| + struct generic_pm_domain *pd; |
| + enum gpd_status status; |
| + struct genpd_dev_state *dev_state; |
| + int num_dev_state; |
| +}; |
| + |
| +static void save_all_genpd_state(struct genpd_state *genpd_states, |
| + struct genpd_dev_state *genpd_dev_states) |
| +{ |
| + struct genpd_state *pdst = genpd_states; |
| + struct genpd_dev_state *devst = genpd_dev_states; |
| + struct generic_pm_domain **pds = get_all_genpd(); |
| + |
| + for (; *pds != NULL; pds++) { |
| + struct pm_domain_data *pdd; |
| + struct generic_pm_domain *pd = *pds; |
| + |
| + if (IS_ERR_OR_NULL(pd)) |
| + continue; |
| + |
| + pdst->pd = pd; |
| + pdst->status = pd->status; |
| + pdst->dev_state = devst; |
| + pdst->num_dev_state = 0; |
| + |
| + list_for_each_entry(pdd, &pd->dev_list, list_node) { |
| + struct device *d = pdd->dev; |
| + |
| + devst->dev = d; |
| + devst->active = pm_runtime_active(d); |
| + devst->usage_count = d->power.usage_count; |
| + devst->disable_depth = d->power.disable_depth; |
| + devst->runtime_status = d->power.runtime_status; |
| + |
| + devst++; |
| + pdst->num_dev_state++; |
| + } |
| + |
| + pdst++; |
| + } |
| + |
| + pdst->pd = NULL; |
| + devst->dev = NULL; |
| +} |
| + |
| +static void show_genpd_state(struct genpd_state *pdst) |
| +{ |
| + static const char * const gpd_status_name[] = { |
| + "ACTIVE", |
| + "POWER_OFF", |
| + }; |
| + |
| + static const char * const prm_status_name[] = { |
| + "active", |
| + "resuming", |
| + "suspended", |
| + "suspending", |
| + }; |
| + |
| + pr_info("domain_on [pmd_name status]\n"); |
| + pr_info("\tdev_on (dev_name usage_count, disable, status)\n"); |
| + pr_info("------------------------------------------------------\n"); |
| + |
| + for (; pdst->pd != NULL; pdst++) { |
| + int i; |
| + struct generic_pm_domain *pd = pdst->pd; |
| + |
| + if (IS_ERR_OR_NULL(pd)) { |
| + pr_info("pd: 0x%p\n", pd); |
| + continue; |
| + } |
| + |
| + pr_info("%c [%-9s %11s]\n", |
| + (pdst->status == GPD_STATE_ACTIVE) ? '+' : '-', |
| + pd->name, gpd_status_name[pdst->status]); |
| + |
| + for (i = 0; i < pdst->num_dev_state; i++) { |
| + struct genpd_dev_state *devst = &pdst->dev_state[i]; |
| + struct device *dev = devst->dev; |
| + struct platform_device *pdev = to_platform_device(dev); |
| + |
| + pr_info("\t%c (%-19s %3d, %d, %10s)\n", |
| + devst->active ? '+' : '-', |
| + pdev->name, |
| + atomic_read(&dev->power.usage_count), |
| + devst->disable_depth, |
| + prm_status_name[devst->runtime_status]); |
| + mdelay(20); |
| + } |
| + } |
| +} |
| + |
| +static void dump_genpd_state(struct genpd_state *pdst, struct seq_file *s) |
| +{ |
| + static const char * const gpd_status_name[] = { |
| + "ACTIVE", |
| + "POWER_OFF", |
| + }; |
| + |
| + static const char * const prm_status_name[] = { |
| + "active", |
| + "resuming", |
| + "suspended", |
| + "suspending", |
| + }; |
| + |
| + seq_puts(s, "domain_on [pmd_name status]\n"); |
| + seq_puts(s, "\tdev_on (dev_name usage_count, disable, status)\n"); |
| + seq_puts(s, "------------------------------------------------------\n"); |
| + |
| + for (; pdst->pd != NULL; pdst++) { |
| + int i; |
| + struct generic_pm_domain *pd = pdst->pd; |
| + |
| + if (IS_ERR_OR_NULL(pd)) { |
| + seq_printf(s, "pd: 0x%p\n", pd); |
| + continue; |
| + } |
| + |
| + seq_printf(s, "%c [%-9s %11s]\n", |
| + (pdst->status == GPD_STATE_ACTIVE) ? '+' : '-', |
| + pd->name, gpd_status_name[pdst->status]); |
| + |
| + for (i = 0; i < pdst->num_dev_state; i++) { |
| + struct genpd_dev_state *devst = &pdst->dev_state[i]; |
| + struct device *dev = devst->dev; |
| + struct platform_device *pdev = to_platform_device(dev); |
| + |
| + seq_printf(s, "\t%c (%-19s %3d, %d, %10s)\n", |
| + devst->active ? '+' : '-', |
| + pdev->name, |
| + atomic_read(&dev->power.usage_count), |
| + devst->disable_depth, |
| + prm_status_name[devst->runtime_status]); |
| + } |
| + } |
| +} |
| + |
| +static void seq_print_all_genpd(struct seq_file *s) |
| +{ |
| + static struct genpd_dev_state devst[100]; |
| + static struct genpd_state pdst[20]; |
| + |
| + save_all_genpd_state(pdst, devst); |
| + dump_genpd_state(pdst, s); |
| +} |
| + |
| +static int clkdbg_dump_genpd(struct seq_file *s, void *v) |
| +{ |
| + seq_print_all_genpd(s); |
| + |
| + return 0; |
| +} |
| + |
| +static int clkdbg_pm_runtime_enable(struct seq_file *s, void *v) |
| +{ |
| + char cmd[sizeof(last_cmd)]; |
| + char *c = cmd; |
| + char *ign; |
| + char *dev_name; |
| + struct platform_device *pdev; |
| + |
| + strncpy(cmd, last_cmd, sizeof(cmd)); |
| + cmd[sizeof(cmd) - 1UL] = '\0'; |
| + |
| + ign = strsep(&c, " "); |
| + dev_name = strsep(&c, " "); |
| + |
| + if (dev_name == NULL) |
| + return 0; |
| + |
| + seq_printf(s, "pm_runtime_enable(%s): ", dev_name); |
| + |
| + pdev = pdev_from_name(dev_name); |
| + if (pdev != NULL) { |
| + pm_runtime_enable(&pdev->dev); |
| + seq_puts(s, "\n"); |
| + } else { |
| + seq_puts(s, "NULL\n"); |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +static int clkdbg_pm_runtime_disable(struct seq_file *s, void *v) |
| +{ |
| + char cmd[sizeof(last_cmd)]; |
| + char *c = cmd; |
| + char *ign; |
| + char *dev_name; |
| + struct platform_device *pdev; |
| + |
| + strncpy(cmd, last_cmd, sizeof(cmd)); |
| + cmd[sizeof(cmd) - 1UL] = '\0'; |
| + |
| + ign = strsep(&c, " "); |
| + dev_name = strsep(&c, " "); |
| + |
| + if (dev_name == NULL) |
| + return 0; |
| + |
| + seq_printf(s, "pm_runtime_disable(%s): ", dev_name); |
| + |
| + pdev = pdev_from_name(dev_name); |
| + if (pdev != NULL) { |
| + pm_runtime_disable(&pdev->dev); |
| + seq_puts(s, "\n"); |
| + } else { |
| + seq_puts(s, "NULL\n"); |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +static int clkdbg_pm_runtime_get_sync(struct seq_file *s, void *v) |
| +{ |
| + char cmd[sizeof(last_cmd)]; |
| + char *c = cmd; |
| + char *ign; |
| + char *dev_name; |
| + struct platform_device *pdev; |
| + |
| + strncpy(cmd, last_cmd, sizeof(cmd)); |
| + cmd[sizeof(cmd) - 1UL] = '\0'; |
| + |
| + ign = strsep(&c, " "); |
| + dev_name = strsep(&c, " "); |
| + |
| + if (dev_name == NULL) |
| + return 0; |
| + |
| + seq_printf(s, "pm_runtime_get_sync(%s): ", dev_name); |
| + |
| + pdev = pdev_from_name(dev_name); |
| + if (pdev != NULL) { |
| + int r = pm_runtime_get_sync(&pdev->dev); |
| + |
| + seq_printf(s, "%d\n", r); |
| + } else { |
| + seq_puts(s, "NULL\n"); |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +static int clkdbg_pm_runtime_put_sync(struct seq_file *s, void *v) |
| +{ |
| + char cmd[sizeof(last_cmd)]; |
| + char *c = cmd; |
| + char *ign; |
| + char *dev_name; |
| + struct platform_device *pdev; |
| + |
| + strncpy(cmd, last_cmd, sizeof(cmd)); |
| + cmd[sizeof(cmd) - 1UL] = '\0'; |
| + |
| + ign = strsep(&c, " "); |
| + dev_name = strsep(&c, " "); |
| + |
| + if (dev_name == NULL) |
| + return 0; |
| + |
| + seq_printf(s, "pm_runtime_put_sync(%s): ", dev_name); |
| + |
| + pdev = pdev_from_name(dev_name); |
| + if (pdev != NULL) { |
| + int r = pm_runtime_put_sync(&pdev->dev); |
| + |
| + seq_printf(s, "%d\n", r); |
| + } else { |
| + seq_puts(s, "NULL\n"); |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +static int genpd_op(const char *gpd_op_name, struct seq_file *s) |
| +{ |
| + char cmd[sizeof(last_cmd)]; |
| + char *c = cmd; |
| + char *ign; |
| + char *pd_name; |
| + struct generic_pm_domain *genpd; |
| + int gpd_op_id; |
| + int (*gpd_op)(struct generic_pm_domain *genpd); |
| + int r = 0; |
| + |
| + strncpy(cmd, last_cmd, sizeof(cmd)); |
| + cmd[sizeof(cmd) - 1UL] = '\0'; |
| + |
| + ign = strsep(&c, " "); |
| + pd_name = strsep(&c, " "); |
| + |
| + if (pd_name == NULL) |
| + return 0; |
| + |
| + if (strcmp(gpd_op_name, "power_on") == 0) |
| + gpd_op_id = 1; |
| + else |
| + gpd_op_id = 0; |
| + |
| + if (strcmp(pd_name, "all") == 0) { |
| + struct generic_pm_domain **pds = get_all_genpd(); |
| + |
| + for (; *pds != NULL; pds++) { |
| + genpd = *pds; |
| + |
| + if (IS_ERR_OR_NULL(genpd)) |
| + continue; |
| + |
| + gpd_op = (gpd_op_id == 1) ? |
| + genpd->power_on : genpd->power_off; |
| + r |= gpd_op(genpd); |
| + } |
| + |
| + seq_printf(s, "%s(%s): %d\n", gpd_op_name, pd_name, r); |
| + |
| + return 0; |
| + } |
| + |
| + genpd = genpd_from_name(pd_name); |
| + if (genpd != NULL) { |
| + gpd_op = (gpd_op_id == 1) ? genpd->power_on : genpd->power_off; |
| + r = gpd_op(genpd); |
| + |
| + seq_printf(s, "%s(%s): %d\n", gpd_op_name, pd_name, r); |
| + } else { |
| + seq_printf(s, "genpd_from_name(%s): NULL\n", pd_name); |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +static int clkdbg_pwr_on(struct seq_file *s, void *v) |
| +{ |
| + return genpd_op("power_on", s); |
| +} |
| + |
| +static int clkdbg_pwr_off(struct seq_file *s, void *v) |
| +{ |
| + return genpd_op("power_off", s); |
| +} |
| + |
| +/* |
| + * clkdbg reg_pdrv/runeg_pdrv support |
| + */ |
| + |
| +static int clkdbg_probe(struct platform_device *pdev) |
| +{ |
| + int r; |
| + |
| + pm_runtime_enable(&pdev->dev); |
| + r = pm_runtime_get_sync(&pdev->dev); |
| + if (r != 0) |
| + pr_warn("%s(): pm_runtime_get_sync(%d)\n", __func__, r); |
| + |
| + return r; |
| +} |
| + |
| +static int clkdbg_remove(struct platform_device *pdev) |
| +{ |
| + int r; |
| + |
| + r = pm_runtime_put_sync(&pdev->dev); |
| + if (r != 0) |
| + pr_warn("%s(): pm_runtime_put_sync(%d)\n", __func__, r); |
| + pm_runtime_disable(&pdev->dev); |
| + |
| + return r; |
| +} |
| + |
| +struct pdev_drv { |
| + struct platform_driver pdrv; |
| + struct platform_device *pdev; |
| + struct generic_pm_domain *genpd; |
| +}; |
| + |
| +#define PDEV_DRV(_name) { \ |
| + .pdrv = { \ |
| + .probe = clkdbg_probe, \ |
| + .remove = clkdbg_remove, \ |
| + .driver = { \ |
| + .name = _name, \ |
| + }, \ |
| + }, \ |
| +} |
| + |
| +static struct pdev_drv pderv[] = { |
| + PDEV_DRV("clkdbg-pd0"), |
| + PDEV_DRV("clkdbg-pd1"), |
| + PDEV_DRV("clkdbg-pd2"), |
| + PDEV_DRV("clkdbg-pd3"), |
| + PDEV_DRV("clkdbg-pd4"), |
| + PDEV_DRV("clkdbg-pd5"), |
| + PDEV_DRV("clkdbg-pd6"), |
| + PDEV_DRV("clkdbg-pd7"), |
| + PDEV_DRV("clkdbg-pd8"), |
| + PDEV_DRV("clkdbg-pd9"), |
| + PDEV_DRV("clkdbg-pd10"), |
| + PDEV_DRV("clkdbg-pd11"), |
| + PDEV_DRV("clkdbg-pd12"), |
| + PDEV_DRV("clkdbg-pd13"), |
| + PDEV_DRV("clkdbg-pd14"), |
| + PDEV_DRV("clkdbg-pd15"), |
| +}; |
| + |
| +static void reg_pdev_drv(const char *pdname, struct seq_file *s) |
| +{ |
| + size_t i; |
| + struct generic_pm_domain **pds = get_all_genpd(); |
| + bool allpd = (pdname == NULL || strcmp(pdname, "all") == 0); |
| + int r; |
| + |
| + for (i = 0; i < ARRAY_SIZE(pderv) && *pds != NULL; i++, pds++) { |
| + const char *name = pderv[i].pdrv.driver.name; |
| + struct generic_pm_domain *pd = *pds; |
| + |
| + if (IS_ERR_OR_NULL(pd) || pderv[i].genpd != NULL) |
| + continue; |
| + |
| + if (!allpd && strcmp(pdname, pd->name) != 0) |
| + continue; |
| + |
| + pderv[i].genpd = pd; |
| + |
| + pderv[i].pdev = platform_device_alloc(name, 0); |
| + r = platform_device_add(pderv[i].pdev); |
| + if (r != 0 && s != NULL) |
| + seq_printf(s, "%s(): platform_device_add(%d)\n", |
| + __func__, r); |
| + |
| + r = pm_genpd_add_device(pd, &pderv[i].pdev->dev); |
| + if (r != 0 && s != NULL) |
| + seq_printf(s, "%s(): pm_genpd_add_device(%d)\n", |
| + __func__, r); |
| + r = platform_driver_register(&pderv[i].pdrv); |
| + if (r != 0 && s != NULL) |
| + seq_printf(s, "%s(): platform_driver_register(%d)\n", |
| + __func__, r); |
| + |
| + if (s != NULL) |
| + seq_printf(s, "%s --> %s\n", name, pd->name); |
| + } |
| +} |
| + |
| +static void unreg_pdev_drv(const char *pdname, struct seq_file *s) |
| +{ |
| + ssize_t i; |
| + bool allpd = (pdname == NULL || strcmp(pdname, "all") == 0); |
| + int r; |
| + |
| + for (i = ARRAY_SIZE(pderv) - 1L; i >= 0L; i--) { |
| + const char *name = pderv[i].pdrv.driver.name; |
| + struct generic_pm_domain *pd = pderv[i].genpd; |
| + |
| + if (IS_ERR_OR_NULL(pd)) |
| + continue; |
| + |
| + if (!allpd && strcmp(pdname, pd->name) != 0) |
| + continue; |
| + |
| +#if CLKDBG_DROP_GENPD_AS_IN_PARAM |
| + r = pm_genpd_remove_device(&pderv[i].pdev->dev); |
| +#else |
| + r = pm_genpd_remove_device(pd, &pderv[i].pdev->dev); |
| +#endif |
| + if (r != 0 && s != NULL) |
| + seq_printf(s, "%s(): pm_genpd_remove_device(%d)\n", |
| + __func__, r); |
| + |
| + platform_driver_unregister(&pderv[i].pdrv); |
| + platform_device_unregister(pderv[i].pdev); |
| + |
| + pderv[i].genpd = NULL; |
| + |
| + if (s != NULL) |
| + seq_printf(s, "%s -x- %s\n", name, pd->name); |
| + } |
| +} |
| + |
| +static int clkdbg_reg_pdrv(struct seq_file *s, void *v) |
| +{ |
| + char cmd[sizeof(last_cmd)]; |
| + char *c = cmd; |
| + char *ign; |
| + char *pd_name; |
| + |
| + strncpy(cmd, last_cmd, sizeof(cmd)); |
| + cmd[sizeof(cmd) - 1UL] = '\0'; |
| + |
| + ign = strsep(&c, " "); |
| + pd_name = strsep(&c, " "); |
| + |
| + if (pd_name == NULL) |
| + return 0; |
| + |
| + reg_pdev_drv(pd_name, s); |
| + |
| + return 0; |
| +} |
| + |
| +static int clkdbg_unreg_pdrv(struct seq_file *s, void *v) |
| +{ |
| + char cmd[sizeof(last_cmd)]; |
| + char *c = cmd; |
| + char *ign; |
| + char *pd_name; |
| + |
| + strncpy(cmd, last_cmd, sizeof(cmd)); |
| + cmd[sizeof(cmd) - 1UL] = '\0'; |
| + |
| + ign = strsep(&c, " "); |
| + pd_name = strsep(&c, " "); |
| + |
| + if (pd_name == NULL) |
| + return 0; |
| + |
| + unreg_pdev_drv(pd_name, s); |
| + |
| + return 0; |
| +} |
| + |
| +#endif /* CLKDBG_PM_DOMAIN */ |
| + |
| +void reg_pdrv(const char *pdname) |
| +{ |
| +#if CLKDBG_PM_DOMAIN |
| + reg_pdev_drv(pdname, NULL); |
| +#endif |
| +} |
| + |
| +void unreg_pdrv(const char *pdname) |
| +{ |
| +#if CLKDBG_PM_DOMAIN |
| + unreg_pdev_drv(pdname, NULL); |
| +#endif |
| +} |
| + |
| +/* |
| + * Suspend / resume handler |
| + */ |
| + |
| +#include <linux/suspend.h> |
| +#include <linux/syscore_ops.h> |
| + |
| +struct provider_clk_state { |
| + struct provider_clk *pvdck; |
| + bool prepared; |
| + bool enabled; |
| + unsigned int enable_count; |
| + unsigned long rate; |
| + struct clk *parent; |
| +}; |
| + |
| +struct save_point { |
| + u32 spm_pwr_status; |
| + struct provider_clk_state clks_states[512]; |
| +#if CLKDBG_PM_DOMAIN |
| + struct genpd_state genpd_states[20]; |
| + struct genpd_dev_state genpd_dev_states[100]; |
| +#endif |
| +}; |
| + |
| +static struct save_point save_point_1; |
| +static struct save_point save_point_2; |
| +static struct save_point save_point_3; |
| + |
| +static void save_pwr_status(u32 *spm_pwr_status) |
| +{ |
| + *spm_pwr_status = read_spm_pwr_status(); |
| +} |
| + |
| +static void save_all_clks_state(struct provider_clk_state *clks_states, |
| + u32 spm_pwr_status) |
| +{ |
| + struct provider_clk *pvdck = get_all_provider_clks(); |
| + struct provider_clk_state *st = clks_states; |
| + |
| + for (; pvdck->ck != NULL; pvdck++, st++) { |
| + struct clk *c = pvdck->ck; |
| + struct clk_hw *c_hw = __clk_get_hw(c); |
| + |
| + st->pvdck = pvdck; |
| + st->prepared = clk_hw_is_prepared(c_hw); |
| + st->enabled = clk_hw_pwr_is_on(c_hw, spm_pwr_status, |
| + pvdck->pwr_mask); |
| + st->enable_count = __clk_get_enable_count(c); |
| + st->rate = clk_hw_get_rate(c_hw); |
| + st->parent = IS_ERR_OR_NULL(c) ? NULL : clk_get_parent(c); |
| + } |
| +} |
| + |
| +static void show_provider_clk_state(struct provider_clk_state *st) |
| +{ |
| + struct provider_clk *pvdck = st->pvdck; |
| + struct clk_hw *c_hw = __clk_get_hw(pvdck->ck); |
| + |
| + pr_info("[%10s: %-17s: %3s, %3d, %3d, %10ld, %17s]\n", |
| + pvdck->provider_name != NULL ? pvdck->provider_name : "/ ", |
| + clk_hw_get_name(c_hw), |
| + st->enabled ? "ON" : "off", |
| + st->prepared, |
| + st->enable_count, |
| + st->rate, |
| + st->parent != NULL ? |
| + clk_hw_get_name(__clk_get_hw(st->parent)) : "- "); |
| + mdelay(20); |
| +} |
| + |
| +static void dump_provider_clk_state(struct provider_clk_state *st, |
| + struct seq_file *s) |
| +{ |
| + struct provider_clk *pvdck = st->pvdck; |
| + struct clk_hw *c_hw = __clk_get_hw(pvdck->ck); |
| + |
| + seq_printf(s, "[%10s: %-17s: %3s, %3d, %3d, %10ld, %17s]\n", |
| + pvdck->provider_name != NULL ? pvdck->provider_name : "/ ", |
| + clk_hw_get_name(c_hw), |
| + st->enabled ? "ON" : "off", |
| + st->prepared, |
| + st->enable_count, |
| + st->rate, |
| + st->parent != NULL ? |
| + clk_hw_get_name(__clk_get_hw(st->parent)) : "- "); |
| +} |
| + |
| +static void show_save_point(struct save_point *sp) |
| +{ |
| + struct provider_clk_state *st = sp->clks_states; |
| + |
| + for (; st->pvdck != NULL; st++) |
| + show_provider_clk_state(st); |
| + |
| + pr_info("\n"); |
| + show_pwr_status(sp->spm_pwr_status); |
| + |
| +#if CLKDBG_PM_DOMAIN |
| + pr_info("\n"); |
| + show_genpd_state(sp->genpd_states); |
| +#endif |
| +} |
| + |
| +static void store_save_point(struct save_point *sp) |
| +{ |
| + save_pwr_status(&sp->spm_pwr_status); |
| + save_all_clks_state(sp->clks_states, sp->spm_pwr_status); |
| + |
| +#if CLKDBG_PM_DOMAIN |
| + save_all_genpd_state(sp->genpd_states, sp->genpd_dev_states); |
| +#endif |
| + |
| + if (has_clkdbg_flag(CLKDBG_EN_LOG_SAVE_POINTS)) |
| + show_save_point(sp); |
| +} |
| + |
| +static void dump_save_point(struct save_point *sp, struct seq_file *s) |
| +{ |
| + struct provider_clk_state *st = sp->clks_states; |
| + |
| + for (; st->pvdck != NULL; st++) |
| + dump_provider_clk_state(st, s); |
| + |
| + seq_puts(s, "\n"); |
| + dump_pwr_status(sp->spm_pwr_status, s); |
| + |
| +#if CLKDBG_PM_DOMAIN |
| + seq_puts(s, "\n"); |
| + dump_genpd_state(sp->genpd_states, s); |
| +#endif |
| +} |
| + |
| +static int clkdbg_dump_suspend_clks_1(struct seq_file *s, void *v) |
| +{ |
| + dump_save_point(&save_point_1, s); |
| + return 0; |
| +} |
| + |
| +static int clkdbg_dump_suspend_clks_2(struct seq_file *s, void *v) |
| +{ |
| + dump_save_point(&save_point_2, s); |
| + return 0; |
| +} |
| + |
| +static int clkdbg_dump_suspend_clks_3(struct seq_file *s, void *v) |
| +{ |
| + dump_save_point(&save_point_3, s); |
| + return 0; |
| +} |
| + |
| +static int clkdbg_dump_suspend_clks(struct seq_file *s, void *v) |
| +{ |
| + if (has_clkdbg_flag(CLKDBG_EN_SUSPEND_SAVE_3) && |
| + save_point_3.spm_pwr_status != 0U) |
| + return clkdbg_dump_suspend_clks_3(s, v); |
| + else if (has_clkdbg_flag(CLKDBG_EN_SUSPEND_SAVE_2) && |
| + save_point_2.spm_pwr_status != 0U) |
| + return clkdbg_dump_suspend_clks_2(s, v); |
| + else if (has_clkdbg_flag(CLKDBG_EN_SUSPEND_SAVE_1) && |
| + save_point_1.spm_pwr_status != 0U) |
| + return clkdbg_dump_suspend_clks_1(s, v); |
| + |
| + return 0; |
| +} |
| + |
| +static int clkdbg_pm_event_handler(struct notifier_block *nb, |
| + unsigned long event, void *ptr) |
| +{ |
| + switch (event) { |
| + case PM_HIBERNATION_PREPARE: |
| + case PM_SUSPEND_PREPARE: |
| + /* suspend */ |
| + if (has_clkdbg_flag(CLKDBG_EN_SUSPEND_SAVE_1)) { |
| + store_save_point(&save_point_1); |
| + return NOTIFY_OK; |
| + } |
| + |
| + break; |
| + case PM_POST_HIBERNATION: |
| + case PM_POST_SUSPEND: |
| + /* resume */ |
| + break; |
| + } |
| + |
| + return NOTIFY_DONE; |
| +} |
| + |
| +static struct notifier_block clkdbg_pm_notifier = { |
| + .notifier_call = clkdbg_pm_event_handler, |
| +}; |
| + |
| +static int clkdbg_syscore_suspend(void) |
| +{ |
| + if (has_clkdbg_flag(CLKDBG_EN_SUSPEND_SAVE_2)) |
| + store_save_point(&save_point_2); |
| + |
| + return 0; |
| +} |
| + |
| +static void clkdbg_syscore_resume(void) |
| +{ |
| +} |
| + |
| +static struct syscore_ops clkdbg_syscore_ops = { |
| + .suspend = clkdbg_syscore_suspend, |
| + .resume = clkdbg_syscore_resume, |
| +}; |
| + |
| +static int __init clkdbg_pm_init(void) |
| +{ |
| + int r; |
| + |
| + register_syscore_ops(&clkdbg_syscore_ops); |
| + r = register_pm_notifier(&clkdbg_pm_notifier); |
| + if (r != 0) |
| + pr_warn("%s(): register_pm_notifier(%d)\n", __func__, r); |
| + |
| + return r; |
| +} |
| +subsys_initcall(clkdbg_pm_init); |
| + |
| +static int clkdbg_suspend_ops_valid(suspend_state_t state) |
| +{ |
| + return state == PM_SUSPEND_MEM ? 1 : 0; |
| +} |
| + |
| +static int clkdbg_suspend_ops_begin(suspend_state_t state) |
| +{ |
| + return 0; |
| +} |
| + |
| +static int clkdbg_suspend_ops_prepare(void) |
| +{ |
| + return 0; |
| +} |
| + |
| +static int clkdbg_suspend_ops_enter(suspend_state_t state) |
| +{ |
| + if (has_clkdbg_flag(CLKDBG_EN_SUSPEND_SAVE_3)) |
| + store_save_point(&save_point_3); |
| + |
| + return 0; |
| +} |
| + |
| +static void clkdbg_suspend_ops_finish(void) |
| +{ |
| +} |
| + |
| +static void clkdbg_suspend_ops_end(void) |
| +{ |
| +} |
| + |
| +static const struct platform_suspend_ops clkdbg_suspend_ops = { |
| + .valid = clkdbg_suspend_ops_valid, |
| + .begin = clkdbg_suspend_ops_begin, |
| + .prepare = clkdbg_suspend_ops_prepare, |
| + .enter = clkdbg_suspend_ops_enter, |
| + .finish = clkdbg_suspend_ops_finish, |
| + .end = clkdbg_suspend_ops_end, |
| +}; |
| + |
| +static int clkdbg_suspend_set_ops(struct seq_file *s, void *v) |
| +{ |
| + suspend_set_ops(&clkdbg_suspend_ops); |
| + |
| + return 0; |
| +} |
| + |
| +static const struct cmd_fn *custom_cmds; |
| + |
| +void set_custom_cmds(const struct cmd_fn *cmds) |
| +{ |
| + custom_cmds = cmds; |
| +} |
| + |
| +static int clkdbg_cmds(struct seq_file *s, void *v); |
| + |
| +static const struct cmd_fn common_cmds[] = { |
| + CMDFN("dump_regs", seq_print_regs), |
| + CMDFN("dump_regs2", clkdbg_dump_regs2), |
| + CMDFN("dump_state", clkdbg_dump_state_all), |
| + CMDFN("dump_clks", clkdbg_dump_provider_clks), |
| + CMDFN("dump_muxes", clkdbg_dump_muxes), |
| + CMDFN("fmeter", seq_print_fmeter_all), |
| + CMDFN("pwr_status", clkdbg_pwr_status), |
| + CMDFN("prepare", clkdbg_prepare), |
| + CMDFN("unprepare", clkdbg_unprepare), |
| + CMDFN("enable", clkdbg_enable), |
| + CMDFN("disable", clkdbg_disable), |
| + CMDFN("prepare_enable", clkdbg_prepare_enable), |
| + CMDFN("disable_unprepare", clkdbg_disable_unprepare), |
| + CMDFN("prepare_enable_provider", clkdbg_prepare_enable_provider), |
| + CMDFN("disable_unprepare_provider", clkdbg_disable_unprepare_provider), |
| + CMDFN("set_parent", clkdbg_set_parent), |
| + CMDFN("set_rate", clkdbg_set_rate), |
| + CMDFN("reg_read", clkdbg_reg_read), |
| + CMDFN("reg_write", clkdbg_reg_write), |
| + CMDFN("reg_set", clkdbg_reg_set), |
| + CMDFN("reg_clr", clkdbg_reg_clr), |
| + CMDFN("show_flags", clkdbg_show_flags), |
| + CMDFN("set_flag", clkdbg_set_flag), |
| + CMDFN("clr_flag", clkdbg_clr_flag), |
| +#if CLKDBG_PM_DOMAIN |
| + CMDFN("dump_genpd", clkdbg_dump_genpd), |
| + CMDFN("pm_runtime_enable", clkdbg_pm_runtime_enable), |
| + CMDFN("pm_runtime_disable", clkdbg_pm_runtime_disable), |
| + CMDFN("pm_runtime_get_sync", clkdbg_pm_runtime_get_sync), |
| + CMDFN("pm_runtime_put_sync", clkdbg_pm_runtime_put_sync), |
| + CMDFN("pwr_on", clkdbg_pwr_on), |
| + CMDFN("pwr_off", clkdbg_pwr_off), |
| + CMDFN("reg_pdrv", clkdbg_reg_pdrv), |
| + CMDFN("unreg_pdrv", clkdbg_unreg_pdrv), |
| +#endif /* CLKDBG_PM_DOMAIN */ |
| + CMDFN("suspend_set_ops", clkdbg_suspend_set_ops), |
| + CMDFN("dump_suspend_clks", clkdbg_dump_suspend_clks), |
| + CMDFN("dump_suspend_clks_1", clkdbg_dump_suspend_clks_1), |
| + CMDFN("dump_suspend_clks_2", clkdbg_dump_suspend_clks_2), |
| + CMDFN("dump_suspend_clks_3", clkdbg_dump_suspend_clks_3), |
| + CMDFN("cmds", clkdbg_cmds), |
| + {} |
| +}; |
| + |
| +static int clkdbg_cmds(struct seq_file *s, void *v) |
| +{ |
| + const struct cmd_fn *cf; |
| + |
| + for (cf = common_cmds; cf->cmd != NULL; cf++) |
| + seq_printf(s, "%s\n", cf->cmd); |
| + |
| + for (cf = custom_cmds; cf != NULL && cf->cmd != NULL; cf++) |
| + seq_printf(s, "%s\n", cf->cmd); |
| + |
| + seq_puts(s, "\n"); |
| + |
| + return 0; |
| +} |
| + |
| +static int clkdbg_show(struct seq_file *s, void *v) |
| +{ |
| + const struct cmd_fn *cf; |
| + char cmd[sizeof(last_cmd)]; |
| + |
| + strncpy(cmd, last_cmd, sizeof(cmd)); |
| + cmd[sizeof(cmd) - 1UL] = '\0'; |
| + |
| + for (cf = custom_cmds; cf != NULL && cf->cmd != NULL; cf++) { |
| + char *c = cmd; |
| + char *token = strsep(&c, " "); |
| + |
| + if (strcmp(cf->cmd, token) == 0) |
| + return cf->fn(s, v); |
| + } |
| + |
| + for (cf = common_cmds; cf->cmd != NULL; cf++) { |
| + char *c = cmd; |
| + char *token = strsep(&c, " "); |
| + |
| + if (strcmp(cf->cmd, token) == 0) |
| + return cf->fn(s, v); |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +static int clkdbg_open(struct inode *inode, struct file *file) |
| +{ |
| + return single_open(file, clkdbg_show, NULL); |
| +} |
| + |
| +static ssize_t clkdbg_write( |
| + struct file *file, |
| + const char __user *buffer, |
| + size_t count, |
| + loff_t *data) |
| +{ |
| + size_t len = 0; |
| + |
| + len = (count < (sizeof(last_cmd) - 1UL)) ? |
| + count : (sizeof(last_cmd) - 1UL); |
| + if (copy_from_user(last_cmd, buffer, len) != 0UL) |
| + return 0; |
| + |
| + last_cmd[len] = '\0'; |
| + |
| + if (last_cmd[len - 1UL] == '\n') |
| + last_cmd[len - 1UL] = '\0'; |
| + |
| + return (ssize_t)len; |
| +} |
| + |
| +static const struct file_operations clkdbg_fops = { |
| + .owner = THIS_MODULE, |
| + .open = clkdbg_open, |
| + .read = seq_read, |
| + .write = clkdbg_write, |
| + .llseek = seq_lseek, |
| + .release = single_release, |
| +}; |
| + |
| +/* |
| + * init functions |
| + */ |
| + |
| +static int __init clkdbg_debug_init(void) |
| +{ |
| + struct proc_dir_entry *entry; |
| + |
| + entry = proc_create("clkdbg", 0644, NULL, &clkdbg_fops); |
| + if (entry == 0) |
| + return -ENOMEM; |
| + |
| + set_clkdbg_flag(CLKDBG_EN_SUSPEND_SAVE_3); |
| + |
| + return 0; |
| +} |
| +module_init(clkdbg_debug_init); |
| diff --git a/drivers/clk/mediatek/clkdbg.h b/drivers/clk/mediatek/clkdbg.h |
| new file mode 100644 |
| index 000000000000..b9cddf3445ff |
| --- /dev/null |
| +++ b/drivers/clk/mediatek/clkdbg.h |
| @@ -0,0 +1,83 @@ |
| +/* SPDX-License-Identifier: GPL-2.0 */ |
| +/* |
| + * Copyright (c) 2018 MediaTek Inc. |
| + * Author: Weiyi Lu <weiyi.lu@mediatek.com> |
| + */ |
| + |
| +struct seq_file; |
| + |
| +#define clk_readl(addr) readl(addr) |
| +#define clk_writel(addr, val) \ |
| + do { writel(val, addr); wmb(); } while (0) /* sync write */ |
| +#define clk_setl(addr, val) clk_writel(addr, clk_readl(addr) | (val)) |
| +#define clk_clrl(addr, val) clk_writel(addr, clk_readl(addr) & ~(val)) |
| + |
| +enum FMETER_TYPE { |
| + FT_NULL, |
| + ABIST, |
| + CKGEN |
| +}; |
| + |
| +struct fmeter_clk { |
| + enum FMETER_TYPE type; |
| + u32 id; |
| + const char *name; |
| +}; |
| + |
| +struct regbase { |
| + u32 phys; |
| + void __iomem *virt; |
| + const char *name; |
| +}; |
| + |
| +struct regname { |
| + struct regbase *base; |
| + u32 ofs; |
| + const char *name; |
| +}; |
| + |
| +#define ADDR(rn) (rn->base->virt + rn->ofs) |
| +#define PHYSADDR(rn) (rn->base->phys + rn->ofs) |
| + |
| +struct cmd_fn { |
| + const char *cmd; |
| + int (*fn)(struct seq_file *s, void *v); |
| +}; |
| + |
| +#define CMDFN(_cmd, _fn) { \ |
| + .cmd = _cmd, \ |
| + .fn = _fn, \ |
| +} |
| + |
| +struct provider_clk { |
| + const char *provider_name; |
| + u32 idx; |
| + struct clk *ck; |
| + u32 pwr_mask; |
| +}; |
| + |
| +struct clkdbg_ops { |
| + const struct fmeter_clk *(*get_all_fmeter_clks)(void); |
| + void *(*prepare_fmeter)(void); |
| + void (*unprepare_fmeter)(void *data); |
| + u32 (*fmeter_freq)(const struct fmeter_clk *fclk); |
| + const struct regname *(*get_all_regnames)(void); |
| + const char * const *(*get_all_clk_names)(void); |
| + const char * const *(*get_pwr_names)(void); |
| + void (*setup_provider_clk)(struct provider_clk *pvdck); |
| + u32 (*get_spm_pwr_status)(void); |
| +}; |
| + |
| +void set_clkdbg_ops(const struct clkdbg_ops *ops); |
| +void set_custom_cmds(const struct cmd_fn *cmds); |
| + |
| +struct provider_clk *get_all_provider_clks(void); |
| +const char *get_last_cmd(void); |
| + |
| +void reg_pdrv(const char *pdname); |
| +void unreg_pdrv(const char *pdname); |
| +void prepare_enable_provider(const char *pvd); |
| +void disable_unprepare_provider(const char *pvd); |
| + |
| +void print_regs(void); |
| +void print_fmeter_all(void); |
| diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig |
| index e178f1473136..6794e6093a47 100644 |
| --- a/drivers/devfreq/Kconfig |
| +++ b/drivers/devfreq/Kconfig |
| @@ -73,6 +73,14 @@ config DEVFREQ_GOV_PASSIVE |
| through sysfs entries. The passive governor recommends that |
| devfreq device uses the OPP table to get the frequency/voltage. |
| |
| +config DEVFREQ_GOV_CPUFREQ_MAP |
| + tristate "CPUfreq Map" |
| + depends on CPU_FREQ |
| + help |
| + Chooses frequency based on the online CPUs' current frequency and a |
| + CPU frequency to device frequency mapping table(s). This governor |
| + can be useful for controlling devices such as DDR, cache, CCI, etc. |
| + |
| comment "DEVFREQ Drivers" |
| |
| config ARM_EXYNOS_BUS_DEVFREQ |
| diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile |
| index 71e7ac084db6..85d48f5744a0 100644 |
| --- a/drivers/devfreq/Makefile |
| +++ b/drivers/devfreq/Makefile |
| @@ -6,6 +6,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE) += governor_performance.o |
| obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o |
| obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o |
| obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o |
| +obj-$(CONFIG_DEVFREQ_GOV_CPUFREQ_MAP) += governor_cpufreq_map.o |
| |
| # DEVFREQ Drivers |
| obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o |
| diff --git a/drivers/devfreq/governor_cpufreq_map.c b/drivers/devfreq/governor_cpufreq_map.c |
| new file mode 100644 |
| index 000000000000..084a3ffb8f54 |
| --- /dev/null |
| +++ b/drivers/devfreq/governor_cpufreq_map.c |
| @@ -0,0 +1,583 @@ |
| +// SPDX-License-Identifier: GPL-2.0 |
| +/* |
| + * Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved. |
| + */ |
| + |
| +#define pr_fmt(fmt) "dev-cpufreq-map: " fmt |
| + |
| +#include <linux/devfreq.h> |
| +#include <linux/cpu.h> |
| +#include <linux/cpufreq.h> |
| +#include <linux/cpumask.h> |
| +#include <linux/slab.h> |
| +#include <linux/platform_device.h> |
| +#include <linux/of.h> |
| +#include <linux/module.h> |
| +#include "governor.h" |
| + |
| +struct cpu_state { |
| + unsigned int freq; |
| + unsigned int min_freq; |
| + unsigned int max_freq; |
| + unsigned int first_cpu; |
| +}; |
| +static struct cpu_state *state[NR_CPUS]; |
| +static int cpufreq_cnt; |
| + |
| +struct freq_map { |
| + unsigned int cpu_khz; |
| + unsigned int target_freq; |
| +}; |
| + |
| +struct devfreq_node { |
| + struct devfreq *df; |
| + void *orig_data; |
| + struct device *dev; |
| + struct device_node *of_node; |
| + struct list_head list; |
| + struct freq_map **map; |
| + struct freq_map *common_map; |
| +}; |
| +static LIST_HEAD(devfreq_list); |
| +static DEFINE_MUTEX(state_lock); |
| +static DEFINE_MUTEX(cpufreq_reg_lock); |
| + |
| +static void update_all_devfreqs(void) |
| +{ |
| + struct devfreq_node *node; |
| + |
| + list_for_each_entry(node, &devfreq_list, list) { |
| + struct devfreq *df = node->df; |
| + |
| + if (!node->df) |
| + continue; |
| + mutex_lock(&df->lock); |
| + update_devfreq(df); |
| + mutex_unlock(&df->lock); |
| + |
| + } |
| +} |
| + |
| +static struct devfreq_node *find_devfreq_node(struct device *dev) |
| +{ |
| + struct devfreq_node *node; |
| + |
| + list_for_each_entry(node, &devfreq_list, list) |
| + if (node->dev == dev || node->of_node == dev->of_node) |
| + return node; |
| + |
| + return NULL; |
| +} |
| + |
| +/* ==================== cpufreq part ==================== */ |
| +static struct cpu_state *add_policy(struct cpufreq_policy *policy) |
| +{ |
| + struct cpu_state *new_state; |
| + unsigned int cpu, first_cpu; |
| + |
| + new_state = kzalloc(sizeof(struct cpu_state), GFP_KERNEL); |
| + if (!new_state) |
| + return NULL; |
| + |
| + first_cpu = cpumask_first(policy->related_cpus); |
| + new_state->first_cpu = first_cpu; |
| + new_state->freq = policy->cur; |
| + new_state->min_freq = policy->cpuinfo.min_freq; |
| + new_state->max_freq = policy->cpuinfo.max_freq; |
| + |
| + for_each_cpu(cpu, policy->related_cpus) |
| + state[cpu] = new_state; |
| + |
| + return new_state; |
| +} |
| + |
| +static int cpufreq_trans_notifier(struct notifier_block *nb, |
| + unsigned long event, void *data) |
| +{ |
| + struct cpufreq_freqs *freq = data; |
| + struct cpu_state *s; |
| + struct cpufreq_policy *policy = NULL; |
| + |
| + if (event != CPUFREQ_POSTCHANGE) |
| + return 0; |
| + |
| + mutex_lock(&state_lock); |
| + |
| + s = state[freq->cpu]; |
| + if (!s) { |
| + policy = cpufreq_cpu_get(freq->cpu); |
| + if (policy) { |
| + s = add_policy(policy); |
| + cpufreq_cpu_put(policy); |
| + } |
| + } |
| + if (!s) |
| + goto out; |
| + |
| + if (s->freq != freq->new || policy) { |
| + s->freq = freq->new; |
| + update_all_devfreqs(); |
| + } |
| + |
| +out: |
| + mutex_unlock(&state_lock); |
| + return 0; |
| +} |
| + |
| +static struct notifier_block cpufreq_trans_nb = { |
| + .notifier_call = cpufreq_trans_notifier |
| +}; |
| + |
| +static int register_cpufreq(void) |
| +{ |
| + int ret = 0; |
| + unsigned int cpu; |
| + struct cpufreq_policy *policy; |
| + |
| + mutex_lock(&cpufreq_reg_lock); |
| + |
| + if (cpufreq_cnt) |
| + goto cnt_not_zero; |
| + |
| + get_online_cpus(); |
| + ret = cpufreq_register_notifier(&cpufreq_trans_nb, |
| + CPUFREQ_TRANSITION_NOTIFIER); |
| + if (ret) |
| + goto out; |
| + |
| + for_each_online_cpu(cpu) { |
| + policy = cpufreq_cpu_get(cpu); |
| + if (policy) { |
| + add_policy(policy); |
| + cpufreq_cpu_put(policy); |
| + } |
| + } |
| +out: |
| + put_online_cpus(); |
| +cnt_not_zero: |
| + if (!ret) |
| + cpufreq_cnt++; |
| + mutex_unlock(&cpufreq_reg_lock); |
| + return ret; |
| +} |
| + |
| +static int unregister_cpufreq(void) |
| +{ |
| + int ret = 0; |
| + int cpu; |
| + |
| + mutex_lock(&cpufreq_reg_lock); |
| + |
| + if (cpufreq_cnt > 1) |
| + goto out; |
| + |
| + cpufreq_unregister_notifier(&cpufreq_trans_nb, |
| + CPUFREQ_TRANSITION_NOTIFIER); |
| + |
| + for (cpu = ARRAY_SIZE(state) - 1; cpu >= 0; cpu--) { |
| + if (!state[cpu]) |
| + continue; |
| + if (state[cpu]->first_cpu == cpu) |
| + kfree(state[cpu]); |
| + state[cpu] = NULL; |
| + } |
| + |
| +out: |
| + cpufreq_cnt--; |
| + mutex_unlock(&cpufreq_reg_lock); |
| + return ret; |
| +} |
| + |
| +/* ==================== devfreq part ==================== */ |
| + |
| +static unsigned int interpolate_freq(struct devfreq *df, unsigned int cpu) |
| +{ |
| + unsigned long *freq_table = df->profile->freq_table; |
| + unsigned int cpu_min = state[cpu]->min_freq; |
| + unsigned int cpu_max = state[cpu]->max_freq; |
| + unsigned int cpu_freq = state[cpu]->freq; |
| + unsigned int dev_min, dev_max, cpu_percent; |
| + |
| + if (freq_table) { |
| + dev_min = freq_table[0]; |
| + dev_max = freq_table[df->profile->max_state - 1]; |
| + } else { |
| + if (df->max_freq <= df->min_freq) |
| + return 0; |
| + dev_min = df->min_freq; |
| + dev_max = df->max_freq; |
| + } |
| + |
| + cpu_percent = ((cpu_freq - cpu_min) * 100) / (cpu_max - cpu_min); |
| + return dev_min + mult_frac(dev_max - dev_min, cpu_percent, 100); |
| +} |
| + |
| +static unsigned int cpu_to_dev_freq(struct devfreq *df, unsigned int cpu) |
| +{ |
| + struct freq_map *map = NULL; |
| + unsigned int cpu_khz = 0, freq; |
| + struct devfreq_node *n = df->data; |
| + |
| + if (!state[cpu] || state[cpu]->first_cpu != cpu) { |
| + freq = 0; |
| + goto out; |
| + } |
| + |
| + if (n->common_map) |
| + map = n->common_map; |
| + else if (n->map) |
| + map = n->map[cpu]; |
| + |
| + cpu_khz = state[cpu]->freq; |
| + |
| + if (!map) { |
| + freq = interpolate_freq(df, cpu); |
| + goto out; |
| + } |
| + |
| + while (map->cpu_khz && map->cpu_khz < cpu_khz) |
| + map++; |
| + if (!map->cpu_khz) |
| + map--; |
| + freq = map->target_freq; |
| + |
| +out: |
| + dev_dbg(df->dev.parent, "CPU%u: %d -> dev: %u\n", cpu, cpu_khz, freq); |
| + return freq; |
| +} |
| + |
| +static int devfreq_cpufreq_get_freq(struct devfreq *df, |
| + unsigned long *freq) |
| +{ |
| + unsigned int cpu, tgt_freq = 0; |
| + struct devfreq_node *node; |
| + |
| + node = df->data; |
| + if (!node) { |
| + pr_err("Unable to find devfreq node!\n"); |
| + return -ENODEV; |
| + } |
| + |
| + for_each_possible_cpu(cpu) |
| + tgt_freq = max(tgt_freq, cpu_to_dev_freq(df, cpu)); |
| + |
| + *freq = tgt_freq; |
| + return 0; |
| +} |
| + |
| +static unsigned int show_table(char *buf, unsigned int len, |
| + struct freq_map *map) |
| +{ |
| + unsigned int cnt = 0; |
| + |
| + cnt += snprintf(buf + cnt, len - cnt, "CPU freq\tDevice freq\n"); |
| + |
| + while (map->cpu_khz && cnt < len) { |
| + cnt += snprintf(buf + cnt, len - cnt, "%8u\t%11u\n", |
| + map->cpu_khz, map->target_freq); |
| + map++; |
| + } |
| + if (cnt < len) |
| + cnt += snprintf(buf + cnt, len - cnt, "\n"); |
| + |
| + return cnt; |
| +} |
| + |
| +static ssize_t freq_map_show(struct device *dev, struct device_attribute *attr, |
| + char *buf) |
| +{ |
| + struct devfreq *df = to_devfreq(dev); |
| + struct devfreq_node *n = df->data; |
| + struct freq_map *map; |
| + unsigned int cnt = 0, cpu; |
| + |
| + mutex_lock(&state_lock); |
| + if (n->common_map) { |
| + map = n->common_map; |
| + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, |
| + "Common table for all CPUs:\n"); |
| + cnt += show_table(buf + cnt, PAGE_SIZE - cnt, map); |
| + } else if (n->map) { |
| + for_each_possible_cpu(cpu) { |
| + map = n->map[cpu]; |
| + if (!map) |
| + continue; |
| + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, |
| + "CPU %u:\n", cpu); |
| + if (cnt >= PAGE_SIZE) |
| + break; |
| + cnt += show_table(buf + cnt, PAGE_SIZE - cnt, map); |
| + if (cnt >= PAGE_SIZE) |
| + break; |
| + } |
| + } else { |
| + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, |
| + "Device freq interpolated based on CPU freq\n"); |
| + } |
| + mutex_unlock(&state_lock); |
| + |
| + return cnt; |
| +} |
| + |
| +static DEVICE_ATTR_RO(freq_map); |
| +static struct attribute *dev_attr[] = { |
| + &dev_attr_freq_map.attr, |
| + NULL, |
| +}; |
| + |
| +static struct attribute_group dev_attr_group = { |
| + .name = "cpufreq-map", |
| + .attrs = dev_attr, |
| +}; |
| + |
| +static int devfreq_cpufreq_gov_start(struct devfreq *devfreq) |
| +{ |
| + int ret = 0; |
| + struct devfreq_node *node; |
| + bool alloc = false; |
| + |
| + ret = register_cpufreq(); |
| + if (ret) |
| + return ret; |
| + |
| + ret = sysfs_create_group(&devfreq->dev.kobj, &dev_attr_group); |
| + if (ret) { |
| + unregister_cpufreq(); |
| + return ret; |
| + } |
| + |
| + mutex_lock(&state_lock); |
| + |
| + node = find_devfreq_node(devfreq->dev.parent); |
| + if (node == NULL) { |
| + node = kzalloc(sizeof(struct devfreq_node), GFP_KERNEL); |
| + if (!node) { |
| + ret = -ENOMEM; |
| + goto alloc_fail; |
| + } |
| + alloc = true; |
| + node->dev = devfreq->dev.parent; |
| + list_add_tail(&node->list, &devfreq_list); |
| + } |
| + node->df = devfreq; |
| + node->orig_data = devfreq->data; |
| + devfreq->data = node; |
| + |
| + mutex_lock(&devfreq->lock); |
| + ret = update_devfreq(devfreq); |
| + mutex_unlock(&devfreq->lock); |
| + if (ret) { |
| + pr_err("Freq update failed!\n"); |
| + goto update_fail; |
| + } |
| + |
| + mutex_unlock(&state_lock); |
| + return 0; |
| + |
| +update_fail: |
| + devfreq->data = node->orig_data; |
| + if (alloc) { |
| + list_del(&node->list); |
| + kfree(node); |
| + } |
| +alloc_fail: |
| + mutex_unlock(&state_lock); |
| + sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group); |
| + unregister_cpufreq(); |
| + return ret; |
| +} |
| + |
| +static void devfreq_cpufreq_gov_stop(struct devfreq *devfreq) |
| +{ |
| + struct devfreq_node *node = devfreq->data; |
| + |
| + mutex_lock(&state_lock); |
| + devfreq->data = node->orig_data; |
| + if (node->map || node->common_map) { |
| + node->df = NULL; |
| + } else { |
| + list_del(&node->list); |
| + kfree(node); |
| + } |
| + mutex_unlock(&state_lock); |
| + |
| + sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group); |
| + unregister_cpufreq(); |
| +} |
| + |
| +static int devfreq_cpufreq_ev_handler(struct devfreq *devfreq, |
| + unsigned int event, void *data) |
| +{ |
| + int ret; |
| + |
| + switch (event) { |
| + case DEVFREQ_GOV_START: |
| + |
| + ret = devfreq_cpufreq_gov_start(devfreq); |
| + if (ret) { |
| + pr_err("Governor start failed!\n"); |
| + return ret; |
| + } |
| + pr_debug("Enabled CPUfreq-map governor\n"); |
| + break; |
| + |
| + case DEVFREQ_GOV_STOP: |
| + |
| + devfreq_cpufreq_gov_stop(devfreq); |
| + pr_debug("Disabled dev CPUfreq-map governor\n"); |
| + break; |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +static struct devfreq_governor devfreq_cpufreq = { |
| + .name = "cpufreq-map", |
| + .get_target_freq = devfreq_cpufreq_get_freq, |
| + .event_handler = devfreq_cpufreq_ev_handler, |
| +}; |
| + |
| +#define NUM_COLS 2 |
| +static struct freq_map *read_tbl(struct device_node *of_node, char *prop_name) |
| +{ |
| + int len, nf, i, j; |
| + u32 data; |
| + struct freq_map *tbl; |
| + |
| + if (!of_find_property(of_node, prop_name, &len)) |
| + return NULL; |
| + len /= sizeof(data); |
| + |
| + if (len % NUM_COLS || len == 0) |
| + return NULL; |
| + nf = len / NUM_COLS; |
| + |
| + tbl = kzalloc((nf + 1) * sizeof(*tbl), GFP_KERNEL); |
| + if (!tbl) |
| + return NULL; |
| + |
| + for (i = 0, j = 0; i < nf; i++, j += 2) { |
| + of_property_read_u32_index(of_node, prop_name, j, &data); |
| + tbl[i].cpu_khz = data; |
| + |
| + of_property_read_u32_index(of_node, prop_name, j + 1, &data); |
| + tbl[i].target_freq = data; |
| + } |
| + tbl[i].cpu_khz = 0; |
| + |
| + return tbl; |
| +} |
| + |
| +#define PROP_TARGET "target-dev" |
| +#define PROP_TABLE "cpu-to-dev-map" |
| +static int add_table_from_of(struct device_node *of_node) |
| +{ |
| + struct device_node *target_of_node; |
| + struct devfreq_node *node; |
| + struct freq_map *common_tbl; |
| + struct freq_map **tbl_list = NULL; |
| + static char prop_name[] = PROP_TABLE "-999999"; |
| + int cpu, ret, cnt = 0, prop_sz = ARRAY_SIZE(prop_name); |
| + |
| + target_of_node = of_parse_phandle(of_node, PROP_TARGET, 0); |
| + if (!target_of_node) |
| + return -EINVAL; |
| + |
| + node = kzalloc(sizeof(struct devfreq_node), GFP_KERNEL); |
| + if (!node) |
| + return -ENOMEM; |
| + |
| + common_tbl = read_tbl(of_node, PROP_TABLE); |
| + if (!common_tbl) { |
| + tbl_list = kzalloc(sizeof(*tbl_list) * NR_CPUS, GFP_KERNEL); |
| + if (!tbl_list) { |
| + ret = -ENOMEM; |
| + goto err_list; |
| + } |
| + |
| + for_each_possible_cpu(cpu) { |
| + ret = snprintf(prop_name, prop_sz, "%s-%d", |
| + PROP_TABLE, cpu); |
| + if (ret >= prop_sz) { |
| + pr_warn("More CPUs than I can handle!\n"); |
| + pr_warn("Skipping rest of the tables!\n"); |
| + break; |
| + } |
| + tbl_list[cpu] = read_tbl(of_node, prop_name); |
| + if (tbl_list[cpu]) |
| + cnt++; |
| + } |
| + } |
| + if (!common_tbl && !cnt) { |
| + ret = -EINVAL; |
| + goto err_tbl; |
| + } |
| + |
| + mutex_lock(&state_lock); |
| + node->of_node = target_of_node; |
| + node->map = tbl_list; |
| + node->common_map = common_tbl; |
| + list_add_tail(&node->list, &devfreq_list); |
| + mutex_unlock(&state_lock); |
| + |
| + return 0; |
| +err_tbl: |
| + kfree(tbl_list); |
| +err_list: |
| + kfree(node); |
| + return ret; |
| +} |
| + |
| +static int __init devfreq_cpufreq_init(void) |
| +{ |
| + int ret; |
| + struct device_node *of_par, *of_child; |
| + |
| + of_par = of_find_node_by_name(NULL, "devfreq-cpufreq-map"); |
| + if (of_par) { |
| + for_each_child_of_node(of_par, of_child) { |
| + ret = add_table_from_of(of_child); |
| + if (ret) |
| + pr_err("Parsing %s failed!\n", of_child->name); |
| + else |
| + pr_debug("Parsed %s.\n", of_child->name); |
| + } |
| + of_node_put(of_par); |
| + } else { |
| + pr_info("No tables parsed from DT.\n"); |
| + } |
| + |
| + ret = devfreq_add_governor(&devfreq_cpufreq); |
| + if (ret) { |
| + pr_err("cpufreq-map governor add failed!\n"); |
| + return ret; |
| + } |
| + |
| + return 0; |
| +} |
| +subsys_initcall(devfreq_cpufreq_init); |
| + |
| +static void __exit devfreq_cpufreq_exit(void) |
| +{ |
| + int ret, cpu; |
| + struct devfreq_node *node, *tmp; |
| + |
| + ret = devfreq_remove_governor(&devfreq_cpufreq); |
| + if (ret) |
| + pr_err("cpufreq-map governor remove failed!\n"); |
| + |
| + mutex_lock(&state_lock); |
| + list_for_each_entry_safe(node, tmp, &devfreq_list, list) { |
| + kfree(node->common_map); |
| + for_each_possible_cpu(cpu) |
| + kfree(node->map[cpu]); |
| + kfree(node->map); |
| + list_del(&node->list); |
| + kfree(node); |
| + } |
| + mutex_unlock(&state_lock); |
| +} |
| +module_exit(devfreq_cpufreq_exit); |
| + |
| +MODULE_DESCRIPTION("devfreq gov that sets dev freq based on current CPU freq"); |
| +MODULE_LICENSE("GPL v2"); |
| diff --git a/drivers/devfreq/mt8183-cci-devfreq.c b/drivers/devfreq/mt8183-cci-devfreq.c |
| index 250c963789f3..a153adee033e 100644 |
| --- a/drivers/devfreq/mt8183-cci-devfreq.c |
| +++ b/drivers/devfreq/mt8183-cci-devfreq.c |
| @@ -17,164 +17,7 @@ |
| struct cci_devfreq { |
| struct devfreq *devfreq; |
| struct regulator *proc_reg; |
| - unsigned long proc_reg_uV; |
| struct clk *cci_clk; |
| - unsigned long freq; |
| - struct notifier_block nb; |
| - struct notifier_block opp_nb; |
| - int cci_min_freq; |
| -}; |
| - |
| -static int cci_devfreq_regulator_notifier(struct notifier_block *nb, |
| - unsigned long val, void *data) |
| -{ |
| - int ret; |
| - struct cci_devfreq *cci_df = |
| - container_of(nb, struct cci_devfreq, nb); |
| - |
| - /* deal with reduce frequency */ |
| - if (val & REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) { |
| - struct pre_voltage_change_data *pvc_data = data; |
| - |
| - if (pvc_data->min_uV < pvc_data->old_uV) { |
| - cci_df->proc_reg_uV = |
| - (unsigned long)(pvc_data->min_uV); |
| - mutex_lock(&cci_df->devfreq->lock); |
| - ret = update_devfreq(cci_df->devfreq); |
| - if (ret) |
| - pr_err("Fail to reduce cci frequency: %d\n", |
| - ret); |
| - mutex_unlock(&cci_df->devfreq->lock); |
| - } |
| - } else if ((val & REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE) && |
| - ((unsigned long)data > cci_df->proc_reg_uV)) { |
| - cci_df->proc_reg_uV = (unsigned long)data; |
| - mutex_lock(&cci_df->devfreq->lock); |
| - ret = update_devfreq(cci_df->devfreq); |
| - if (ret) |
| - pr_err("Fail to raise cci frequency back: %d\n", ret); |
| - mutex_unlock(&cci_df->devfreq->lock); |
| - } else if ((val & REGULATOR_EVENT_VOLTAGE_CHANGE) && |
| - (cci_df->proc_reg_uV < (unsigned long)data)) { |
| - /* deal with increase frequency */ |
| - cci_df->proc_reg_uV = (unsigned long)data; |
| - mutex_lock(&cci_df->devfreq->lock); |
| - ret = update_devfreq(cci_df->devfreq); |
| - if (ret) |
| - pr_err("Fail to raise cci frequency: %d\n", ret); |
| - mutex_unlock(&cci_df->devfreq->lock); |
| - } |
| - |
| - return 0; |
| -} |
| - |
| -static int ccidevfreq_opp_notifier(struct notifier_block *nb, |
| -unsigned long event, void *data) |
| -{ |
| - int ret; |
| - struct dev_pm_opp *opp = data; |
| - struct cci_devfreq *cci_df = container_of(nb, struct cci_devfreq, |
| - opp_nb); |
| - unsigned long freq, volt, cur_volt; |
| - |
| - if (event == OPP_EVENT_ADJUST_VOLTAGE) { |
| - freq = dev_pm_opp_get_freq(opp); |
| - /* current opp item is changed */ |
| - if (freq == cci_df->freq) { |
| - volt = dev_pm_opp_get_voltage(opp); |
| - cur_volt = regulator_get_voltage(cci_df->proc_reg); |
| - |
| - if (volt > cur_volt) { |
| - /* need reduce freq */ |
| - mutex_lock(&cci_df->devfreq->lock); |
| - ret = update_devfreq(cci_df->devfreq); |
| - if (ret) |
| - pr_err("Fail to reduce cci frequency by opp notification: %d\n", |
| - ret); |
| - mutex_unlock(&cci_df->devfreq->lock); |
| - } |
| - } |
| - |
| - if (freq == cci_df->cci_min_freq) { |
| - volt = dev_pm_opp_get_voltage(opp); |
| - regulator_set_voltage(cci_df->proc_reg, volt, INT_MAX); |
| - } |
| - } else if (event == OPP_EVENT_DISABLE) { |
| - } |
| - |
| - return 0; |
| -} |
| - |
| - |
| -static int mtk_cci_governor_get_target(struct devfreq *devfreq, |
| - unsigned long *freq) |
| -{ |
| - struct cci_devfreq *cci_df; |
| - struct dev_pm_opp *opp; |
| - int ret; |
| - |
| - cci_df = dev_get_drvdata(devfreq->dev.parent); |
| - |
| - /* find available frequency */ |
| - opp = dev_pm_opp_find_freq_ceil_by_volt(devfreq->dev.parent, |
| - cci_df->proc_reg_uV); |
| - ret = PTR_ERR_OR_ZERO(opp); |
| - if (ret) { |
| - pr_err("%s[%d], cannot find opp with voltage=%d: %d\n", |
| - __func__, __LINE__, cci_df->proc_reg_uV, ret); |
| - return ret; |
| - } |
| - *freq = dev_pm_opp_get_freq(opp); |
| - |
| - return 0; |
| -} |
| - |
| -static int mtk_cci_governor_event_handler(struct devfreq *devfreq, |
| - unsigned int event, void *data) |
| -{ |
| - int ret; |
| - struct cci_devfreq *cci_df; |
| - struct notifier_block *nb; |
| - struct notifier_block *opp_nb; |
| - |
| - cci_df = dev_get_drvdata(devfreq->dev.parent); |
| - nb = &cci_df->nb; |
| - opp_nb = &cci_df->opp_nb; |
| - |
| - switch (event) { |
| - case DEVFREQ_GOV_START: |
| - case DEVFREQ_GOV_RESUME: |
| - nb->notifier_call = cci_devfreq_regulator_notifier; |
| - ret = regulator_register_notifier(cci_df->proc_reg, |
| - nb); |
| - if (ret) |
| - pr_err("%s: failed to add governor: %d\n", __func__, |
| - ret); |
| - opp_nb->notifier_call = ccidevfreq_opp_notifier; |
| - dev_pm_opp_register_notifier(devfreq->dev.parent, opp_nb); |
| - break; |
| - |
| - case DEVFREQ_GOV_STOP: |
| - case DEVFREQ_GOV_SUSPEND: |
| - ret = regulator_unregister_notifier(cci_df->proc_reg, |
| - nb); |
| - if (ret) |
| - pr_err("%s: failed to add governor: %d\n", __func__, |
| - ret); |
| - break; |
| - |
| - default: |
| - break; |
| - } |
| - |
| - return 0; |
| -} |
| - |
| -static struct devfreq_governor mtk_cci_devfreq_governor = { |
| - .name = "mtk_cci_vmon", |
| - .get_target_freq = mtk_cci_governor_get_target, |
| - .event_handler = mtk_cci_governor_event_handler, |
| - .immutable = true |
| }; |
| |
| static int mtk_cci_devfreq_target(struct device *dev, unsigned long *freq, |
| @@ -193,8 +36,6 @@ static int mtk_cci_devfreq_target(struct device *dev, unsigned long *freq, |
| return ret; |
| } |
| |
| - cci_df->freq = *freq; |
| - |
| return 0; |
| } |
| |
| @@ -206,8 +47,6 @@ static int mtk_cci_devfreq_probe(struct platform_device *pdev) |
| { |
| struct device *cci_dev = &pdev->dev; |
| struct cci_devfreq *cci_df; |
| - unsigned long freq, volt; |
| - struct dev_pm_opp *opp; |
| int ret; |
| |
| cci_df = devm_kzalloc(cci_dev, sizeof(*cci_df), GFP_KERNEL); |
| @@ -237,19 +76,12 @@ static int mtk_cci_devfreq_probe(struct platform_device *pdev) |
| return ret; |
| } |
| |
| - /* set voltage lower bound */ |
| - freq = 1; |
| - opp = dev_pm_opp_find_freq_ceil(cci_dev, &freq); |
| - cci_df->cci_min_freq = dev_pm_opp_get_freq(opp); |
| - volt = dev_pm_opp_get_voltage(opp); |
| - dev_pm_opp_put(opp); |
| - |
| platform_set_drvdata(pdev, cci_df); |
| |
| cci_df->devfreq = devm_devfreq_add_device(cci_dev, |
| - &cci_devfreq_profile, |
| - "mtk_cci_vmon", |
| - NULL); |
| + &cci_devfreq_profile, |
| + "cpufreq-map", |
| + NULL); |
| if (IS_ERR(cci_df->devfreq)) { |
| ret = PTR_ERR(cci_df->devfreq); |
| dev_err(cci_dev, "cannot create cci devfreq device:%d\n", ret); |
| @@ -277,30 +109,12 @@ static struct platform_driver cci_devfreq_driver = { |
| |
| static int __init mtk_cci_devfreq_init(void) |
| { |
| - int ret; |
| - |
| - ret = devfreq_add_governor(&mtk_cci_devfreq_governor); |
| - if (ret) { |
| - pr_err("%s: failed to add governor: %d\n", __func__, ret); |
| - return ret; |
| - } |
| - |
| - ret = platform_driver_register(&cci_devfreq_driver); |
| - if (ret) |
| - devfreq_remove_governor(&mtk_cci_devfreq_governor); |
| - |
| - return ret; |
| + return platform_driver_register(&cci_devfreq_driver); |
| } |
| module_init(mtk_cci_devfreq_init) |
| |
| static void __exit mtk_cci_devfreq_exit(void) |
| { |
| - int ret; |
| - |
| - ret = devfreq_remove_governor(&mtk_cci_devfreq_governor); |
| - if (ret) |
| - pr_err("%s: failed to remove governor: %d\n", __func__, ret); |
| - |
| platform_driver_unregister(&cci_devfreq_driver); |
| } |
| module_exit(mtk_cci_devfreq_exit) |
| diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c |
| index f70d33c8b495..60e101ca9d03 100644 |
| --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c |
| +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c |
| @@ -18,7 +18,6 @@ |
| #include <drm/drm_plane_helper.h> |
| #include <linux/clk.h> |
| #include <linux/pm_runtime.h> |
| -#include <soc/mediatek/smi.h> |
| |
| #include "mtk_drm_drv.h" |
| #include "mtk_drm_crtc.h" |
| @@ -396,20 +395,12 @@ static void mtk_drm_crtc_atomic_enable(struct drm_crtc *crtc, |
| struct drm_crtc_state *old_state) |
| { |
| struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); |
| - struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; |
| int ret; |
| |
| DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id); |
| |
| - ret = mtk_smi_larb_get(comp->larb_dev); |
| - if (ret) { |
| - DRM_ERROR("Failed to get larb: %d\n", ret); |
| - return; |
| - } |
| - |
| ret = mtk_crtc_ddp_hw_init(mtk_crtc); |
| if (ret) { |
| - mtk_smi_larb_put(comp->larb_dev); |
| return; |
| } |
| |
| @@ -421,7 +412,6 @@ static void mtk_drm_crtc_atomic_disable(struct drm_crtc *crtc, |
| struct drm_crtc_state *old_state) |
| { |
| struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); |
| - struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; |
| int i; |
| |
| DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id); |
| @@ -444,7 +434,6 @@ static void mtk_drm_crtc_atomic_disable(struct drm_crtc *crtc, |
| |
| drm_crtc_vblank_off(crtc); |
| mtk_crtc_ddp_hw_fini(mtk_crtc); |
| - mtk_smi_larb_put(comp->larb_dev); |
| |
| mtk_crtc->enabled = false; |
| } |
| diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |
| index bb55d1dc8746..6a66373df6e9 100644 |
| --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |
| +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |
| @@ -351,8 +351,6 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, |
| const struct mtk_ddp_comp_funcs *funcs) |
| { |
| enum mtk_ddp_comp_type type; |
| - struct device_node *larb_node; |
| - struct platform_device *larb_pdev; |
| |
| if (comp_id < 0 || comp_id >= DDP_COMPONENT_ID_MAX) |
| return -EINVAL; |
| @@ -382,31 +380,6 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, |
| if (IS_ERR(comp->clk)) |
| return PTR_ERR(comp->clk); |
| |
| - /* Only DMA capable components need the LARB property */ |
| - comp->larb_dev = NULL; |
| - if (type != MTK_DISP_OVL && |
| - type != MTK_DISP_OVL_2L && |
| - type != MTK_DISP_RDMA && |
| - type != MTK_DISP_WDMA) |
| - return 0; |
| - |
| - larb_node = of_parse_phandle(node, "mediatek,larb", 0); |
| - if (!larb_node) { |
| - dev_err(dev, |
| - "Missing mediadek,larb phandle in %pOF node\n", node); |
| - return -EINVAL; |
| - } |
| - |
| - larb_pdev = of_find_device_by_node(larb_node); |
| - if (!larb_pdev) { |
| - dev_warn(dev, "Waiting for larb device %pOF\n", larb_node); |
| - of_node_put(larb_node); |
| - return -EPROBE_DEFER; |
| - } |
| - of_node_put(larb_node); |
| - |
| - comp->larb_dev = &larb_pdev->dev; |
| - |
| return 0; |
| } |
| |
| diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |
| index 6bf46d1f39b4..9e7969bc755f 100644 |
| --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |
| +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |
| @@ -101,7 +101,6 @@ struct mtk_ddp_comp { |
| struct clk *clk; |
| void __iomem *regs; |
| int irq; |
| - struct device *larb_dev; |
| enum mtk_ddp_comp_id id; |
| const struct mtk_ddp_comp_funcs *funcs; |
| }; |
| diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig |
| index 4aae4a7d9f71..146b88647dfa 100644 |
| --- a/drivers/gpu/drm/panel/Kconfig |
| +++ b/drivers/gpu/drm/panel/Kconfig |
| @@ -197,4 +197,13 @@ config DRM_PANEL_SITRONIX_ST7789V |
| Say Y here if you want to enable support for the Sitronix |
| ST7789V controller for 240x320 LCD panels |
| |
| +config DRM_PANEL_BOE_TV101WUM |
| + tristate "boe TV101WUM WUXGA video mode panel" |
| + depends on OF |
| + depends on DRM_MIPI_DSI |
| + depends on BACKLIGHT_CLASS_DEVICE |
| + help |
| + Say Y here if you want to enable support for boe TV101WUM WUXGA |
| + (1920x1200) DSI panel |
| + |
| endmenu |
| diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile |
| index 7285539d8015..8515ba962381 100644 |
| --- a/drivers/gpu/drm/panel/Makefile |
| +++ b/drivers/gpu/drm/panel/Makefile |
| @@ -20,3 +20,4 @@ obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o |
| obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o |
| obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o |
| obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o |
| +obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM) += panel-boe-tv101wum.o |
| diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum.c b/drivers/gpu/drm/panel/panel-boe-tv101wum.c |
| new file mode 100644 |
| index 000000000000..8089f6360e09 |
| --- /dev/null |
| +++ b/drivers/gpu/drm/panel/panel-boe-tv101wum.c |
| @@ -0,0 +1,708 @@ |
| +// SPDX-License-Identifier: GPL-2.0 |
| +/* |
| + * Copyright (c) 2018 MediaTek Inc. |
| + * Author: Jitao Shi <jitao.shi@mediatek.com> |
| + */ |
| + |
| +#include <linux/backlight.h> |
| +#include <linux/gpio/consumer.h> |
| +#include <linux/module.h> |
| +#include <linux/of.h> |
| +#include <linux/regulator/consumer.h> |
| + |
| +#include <drm/drmP.h> |
| +#include <drm/drm_crtc.h> |
| +#include <drm/drm_mipi_dsi.h> |
| +#include <drm/drm_panel.h> |
| + |
| +#include <video/mipi_display.h> |
| + |
| +struct boe_hx_panel { |
| + struct drm_panel base; |
| + struct mipi_dsi_device *dsi; |
| + |
| + struct backlight_device *backlight; |
| + struct regulator *pp1800; |
| + struct regulator *avee; |
| + struct regulator *avdd; |
| + struct gpio_desc *enable_gpio; |
| + |
| + bool prepared; |
| + bool enabled; |
| + |
| + const struct drm_display_mode *mode; |
| +}; |
| + |
| +enum dsi_cmd_type { |
| + INIT_GENENIC_CMD, |
| + INIT_DCS_CMD, |
| + DELAY_CMD, |
| +}; |
| + |
| +struct panel_init_cmd { |
| + enum dsi_cmd_type type; |
| + size_t len; |
| + const char *data; |
| +}; |
| + |
| +#define _INIT_CMD(...) { \ |
| + .type = INIT_GENENIC_CMD,\ |
| + .len = sizeof((char[]){__VA_ARGS__}), \ |
| + .data = (char[]){__VA_ARGS__} } |
| + |
| +#define _INIT_DCS_CMD(...) { \ |
| + .type = INIT_DCS_CMD, \ |
| + .len = sizeof((char[]){__VA_ARGS__}), \ |
| + .data = (char[]){__VA_ARGS__} } |
| + |
| +#define _INIT_DELAY_CMD(...) { \ |
| + .type = DELAY_CMD,\ |
| + .len = sizeof((char[]){__VA_ARGS__}), \ |
| + .data = (char[]){__VA_ARGS__} } |
| + |
| +static const struct panel_init_cmd boe_hx_init_cmd[] = { |
| + _INIT_DCS_CMD(0x10), |
| + _INIT_DELAY_CMD(34), |
| + _INIT_DCS_CMD(0xB0, 0x05), |
| + _INIT_DCS_CMD(0xB1, 0xE5), |
| + _INIT_DCS_CMD(0xB3, 0x52), |
| + |
| + _INIT_DCS_CMD(0xB0, 0x00), |
| + _INIT_DCS_CMD(0xB3, 0x88), |
| + _INIT_DCS_CMD(0xB0, 0x04), |
| + _INIT_DCS_CMD(0xB8, 0x00), |
| + |
| + _INIT_DCS_CMD(0xB0, 0x00), |
| + _INIT_DCS_CMD(0xB6, 0x03), |
| + _INIT_DCS_CMD(0xBA, 0x8B), |
| + _INIT_DCS_CMD(0xBF, 0x1A), |
| + _INIT_DCS_CMD(0xC0, 0x0F), |
| + _INIT_DCS_CMD(0xC2, 0x0C), |
| + _INIT_DCS_CMD(0xC3, 0x02), |
| + _INIT_DCS_CMD(0xC4, 0x0C), |
| + _INIT_DCS_CMD(0xC5, 0x02), |
| + |
| + _INIT_DCS_CMD(0xB0, 0x01), |
| + _INIT_DCS_CMD(0xE0, 0x26), |
| + _INIT_DCS_CMD(0xE1, 0x26), |
| + _INIT_DCS_CMD(0xDC, 0x00), |
| + _INIT_DCS_CMD(0xDD, 0x00), |
| + _INIT_DCS_CMD(0xCC, 0x26), |
| + _INIT_DCS_CMD(0xCD, 0x26), |
| + _INIT_DCS_CMD(0xC8, 0x00), |
| + _INIT_DCS_CMD(0xC9, 0x00), |
| + _INIT_DCS_CMD(0xD2, 0x03), |
| + _INIT_DCS_CMD(0xD3, 0x03), |
| + _INIT_DCS_CMD(0xE6, 0x04), |
| + _INIT_DCS_CMD(0xE7, 0x04), |
| + _INIT_DCS_CMD(0xC4, 0x09), |
| + _INIT_DCS_CMD(0xC5, 0x09), |
| + _INIT_DCS_CMD(0xD8, 0x0A), |
| + _INIT_DCS_CMD(0xD9, 0x0A), |
| + _INIT_DCS_CMD(0xC2, 0x0B), |
| + _INIT_DCS_CMD(0xC3, 0x0B), |
| + _INIT_DCS_CMD(0xD6, 0x0C), |
| + _INIT_DCS_CMD(0xD7, 0x0C), |
| + _INIT_DCS_CMD(0xC0, 0x05), |
| + _INIT_DCS_CMD(0xC1, 0x05), |
| + _INIT_DCS_CMD(0xD4, 0x06), |
| + _INIT_DCS_CMD(0xD5, 0x06), |
| + _INIT_DCS_CMD(0xCA, 0x07), |
| + _INIT_DCS_CMD(0xCB, 0x07), |
| + _INIT_DCS_CMD(0xDE, 0x08), |
| + _INIT_DCS_CMD(0xDF, 0x08), |
| + |
| + _INIT_DCS_CMD(0xB0, 0x02), |
| + _INIT_DCS_CMD(0xC0, 0x00), |
| + _INIT_DCS_CMD(0xC1, 0x0D), |
| + _INIT_DCS_CMD(0xC2, 0x17), |
| + _INIT_DCS_CMD(0xC3, 0x26), |
| + _INIT_DCS_CMD(0xC4, 0x31), |
| + _INIT_DCS_CMD(0xC5, 0x1C), |
| + _INIT_DCS_CMD(0xC6, 0x2C), |
| + _INIT_DCS_CMD(0xC7, 0x33), |
| + _INIT_DCS_CMD(0xC8, 0x31), |
| + _INIT_DCS_CMD(0xC9, 0x37), |
| + _INIT_DCS_CMD(0xCA, 0x37), |
| + _INIT_DCS_CMD(0xCB, 0x37), |
| + _INIT_DCS_CMD(0xCC, 0x39), |
| + _INIT_DCS_CMD(0xCD, 0x2E), |
| + _INIT_DCS_CMD(0xCE, 0x2F), |
| + _INIT_DCS_CMD(0xCF, 0x2F), |
| + _INIT_DCS_CMD(0xD0, 0x07), |
| + _INIT_DCS_CMD(0xD2, 0x00), |
| + _INIT_DCS_CMD(0xD3, 0x0D), |
| + _INIT_DCS_CMD(0xD4, 0x17), |
| + _INIT_DCS_CMD(0xD5, 0x26), |
| + _INIT_DCS_CMD(0xD6, 0x31), |
| + _INIT_DCS_CMD(0xD7, 0x3F), |
| + _INIT_DCS_CMD(0xD8, 0x3F), |
| + _INIT_DCS_CMD(0xD9, 0x3F), |
| + _INIT_DCS_CMD(0xDA, 0x3F), |
| + _INIT_DCS_CMD(0xDB, 0x37), |
| + _INIT_DCS_CMD(0xDC, 0x37), |
| + _INIT_DCS_CMD(0xDD, 0x37), |
| + _INIT_DCS_CMD(0xDE, 0x39), |
| + _INIT_DCS_CMD(0xDF, 0x2E), |
| + _INIT_DCS_CMD(0xE0, 0x2F), |
| + _INIT_DCS_CMD(0xE1, 0x2F), |
| + _INIT_DCS_CMD(0xE2, 0x07), |
| + |
| + _INIT_DCS_CMD(0xB0, 0x03), |
| + _INIT_DCS_CMD(0xC8, 0x0B), |
| + _INIT_DCS_CMD(0xC9, 0x07), |
| + _INIT_DCS_CMD(0xC3, 0x00), |
| + _INIT_DCS_CMD(0xE7, 0x00), |
| + _INIT_DCS_CMD(0xC5, 0x2A), |
| + _INIT_DCS_CMD(0xDE, 0x2A), |
| + _INIT_DCS_CMD(0xCA, 0x43), |
| + _INIT_DCS_CMD(0xC9, 0x07), |
| + _INIT_DCS_CMD(0xE4, 0xC0), |
| + _INIT_DCS_CMD(0xE5, 0x0D), |
| + _INIT_DCS_CMD(0xCB, 0x00), |
| + |
| + _INIT_DCS_CMD(0xB0, 0x06), |
| + _INIT_DCS_CMD(0xB8, 0xA5), |
| + _INIT_DCS_CMD(0xC0, 0xA5), |
| + _INIT_DCS_CMD(0xC7, 0x0F), |
| + _INIT_DCS_CMD(0xD5, 0x32), |
| + _INIT_DCS_CMD(0xB8, 0x00), |
| + _INIT_DCS_CMD(0xC0, 0x00), |
| + _INIT_DCS_CMD(0xBC, 0x00), |
| + |
| + _INIT_DCS_CMD(0xB0, 0x07), |
| + _INIT_DCS_CMD(0xB1, 0x00), |
| + _INIT_DCS_CMD(0xB2, 0x02), |
| + _INIT_DCS_CMD(0xB3, 0x0F), |
| + _INIT_DCS_CMD(0xB4, 0x25), |
| + _INIT_DCS_CMD(0xB5, 0x39), |
| + _INIT_DCS_CMD(0xB6, 0x4E), |
| + _INIT_DCS_CMD(0xB7, 0x72), |
| + _INIT_DCS_CMD(0xB8, 0x97), |
| + _INIT_DCS_CMD(0xB9, 0xDC), |
| + _INIT_DCS_CMD(0xBA, 0x22), |
| + _INIT_DCS_CMD(0xBB, 0xA4), |
| + _INIT_DCS_CMD(0xBC, 0x2B), |
| + _INIT_DCS_CMD(0xBD, 0x2F), |
| + _INIT_DCS_CMD(0xBE, 0xA9), |
| + _INIT_DCS_CMD(0xBF, 0x25), |
| + _INIT_DCS_CMD(0xC0, 0x61), |
| + _INIT_DCS_CMD(0xC1, 0x97), |
| + _INIT_DCS_CMD(0xC2, 0xB2), |
| + _INIT_DCS_CMD(0xC3, 0xCD), |
| + _INIT_DCS_CMD(0xC4, 0xD9), |
| + _INIT_DCS_CMD(0xC5, 0xE7), |
| + _INIT_DCS_CMD(0xC6, 0xF4), |
| + _INIT_DCS_CMD(0xC7, 0xFA), |
| + _INIT_DCS_CMD(0xC8, 0xFC), |
| + _INIT_DCS_CMD(0xC9, 0x00), |
| + _INIT_DCS_CMD(0xCA, 0x00), |
| + _INIT_DCS_CMD(0xCB, 0x16), |
| + _INIT_DCS_CMD(0xCC, 0xAF), |
| + _INIT_DCS_CMD(0xCD, 0xFF), |
| + _INIT_DCS_CMD(0xCE, 0xFF), |
| + |
| + _INIT_DCS_CMD(0xB0, 0x08), |
| + _INIT_DCS_CMD(0xB1, 0x04), |
| + _INIT_DCS_CMD(0xB2, 0x05), |
| + _INIT_DCS_CMD(0xB3, 0x11), |
| + _INIT_DCS_CMD(0xB4, 0x24), |
| + _INIT_DCS_CMD(0xB5, 0x39), |
| + _INIT_DCS_CMD(0xB6, 0x4F), |
| + _INIT_DCS_CMD(0xB7, 0x72), |
| + _INIT_DCS_CMD(0xB8, 0x98), |
| + _INIT_DCS_CMD(0xB9, 0xDC), |
| + _INIT_DCS_CMD(0xBA, 0x23), |
| + _INIT_DCS_CMD(0xBB, 0xA6), |
| + _INIT_DCS_CMD(0xBC, 0x2C), |
| + _INIT_DCS_CMD(0xBD, 0x30), |
| + _INIT_DCS_CMD(0xBE, 0xAA), |
| + _INIT_DCS_CMD(0xBF, 0x26), |
| + _INIT_DCS_CMD(0xC0, 0x62), |
| + _INIT_DCS_CMD(0xC1, 0x9B), |
| + _INIT_DCS_CMD(0xC2, 0xB5), |
| + _INIT_DCS_CMD(0xC3, 0xCF), |
| + _INIT_DCS_CMD(0xC4, 0xDB), |
| + _INIT_DCS_CMD(0xC5, 0xE8), |
| + _INIT_DCS_CMD(0xC6, 0xF5), |
| + _INIT_DCS_CMD(0xC7, 0xFA), |
| + _INIT_DCS_CMD(0xC8, 0xFC), |
| + _INIT_DCS_CMD(0xC9, 0x00), |
| + _INIT_DCS_CMD(0xCA, 0x00), |
| + _INIT_DCS_CMD(0xCB, 0x16), |
| + _INIT_DCS_CMD(0xCC, 0xAF), |
| + _INIT_DCS_CMD(0xCD, 0xFF), |
| + _INIT_DCS_CMD(0xCE, 0xFF), |
| + |
| + _INIT_DCS_CMD(0xB0, 0x09), |
| + _INIT_DCS_CMD(0xB1, 0x04), |
| + _INIT_DCS_CMD(0xB2, 0x02), |
| + _INIT_DCS_CMD(0xB3, 0x16), |
| + _INIT_DCS_CMD(0xB4, 0x24), |
| + _INIT_DCS_CMD(0xB5, 0x3B), |
| + _INIT_DCS_CMD(0xB6, 0x4F), |
| + _INIT_DCS_CMD(0xB7, 0x73), |
| + _INIT_DCS_CMD(0xB8, 0x99), |
| + _INIT_DCS_CMD(0xB9, 0xE0), |
| + _INIT_DCS_CMD(0xBA, 0x26), |
| + _INIT_DCS_CMD(0xBB, 0xAD), |
| + _INIT_DCS_CMD(0xBC, 0x36), |
| + _INIT_DCS_CMD(0xBD, 0x3A), |
| + _INIT_DCS_CMD(0xBE, 0xAE), |
| + _INIT_DCS_CMD(0xBF, 0x2A), |
| + _INIT_DCS_CMD(0xC0, 0x66), |
| + _INIT_DCS_CMD(0xC1, 0x9E), |
| + _INIT_DCS_CMD(0xC2, 0xB8), |
| + _INIT_DCS_CMD(0xC3, 0xD1), |
| + _INIT_DCS_CMD(0xC4, 0xDD), |
| + _INIT_DCS_CMD(0xC5, 0xE9), |
| + _INIT_DCS_CMD(0xC6, 0xF6), |
| + _INIT_DCS_CMD(0xC7, 0xFA), |
| + _INIT_DCS_CMD(0xC8, 0xFC), |
| + _INIT_DCS_CMD(0xC9, 0x00), |
| + _INIT_DCS_CMD(0xCA, 0x00), |
| + _INIT_DCS_CMD(0xCB, 0x16), |
| + _INIT_DCS_CMD(0xCC, 0xAF), |
| + _INIT_DCS_CMD(0xCD, 0xFF), |
| + _INIT_DCS_CMD(0xCE, 0xFF), |
| + |
| + _INIT_DCS_CMD(0xB0, 0x0A), |
| + _INIT_DCS_CMD(0xB1, 0x00), |
| + _INIT_DCS_CMD(0xB2, 0x02), |
| + _INIT_DCS_CMD(0xB3, 0x0F), |
| + _INIT_DCS_CMD(0xB4, 0x25), |
| + _INIT_DCS_CMD(0xB5, 0x39), |
| + _INIT_DCS_CMD(0xB6, 0x4E), |
| + _INIT_DCS_CMD(0xB7, 0x72), |
| + _INIT_DCS_CMD(0xB8, 0x97), |
| + _INIT_DCS_CMD(0xB9, 0xDC), |
| + _INIT_DCS_CMD(0xBA, 0x22), |
| + _INIT_DCS_CMD(0xBB, 0xA4), |
| + _INIT_DCS_CMD(0xBC, 0x2B), |
| + _INIT_DCS_CMD(0xBD, 0x2F), |
| + _INIT_DCS_CMD(0xBE, 0xA9), |
| + _INIT_DCS_CMD(0xBF, 0x25), |
| + _INIT_DCS_CMD(0xC0, 0x61), |
| + _INIT_DCS_CMD(0xC1, 0x97), |
| + _INIT_DCS_CMD(0xC2, 0xB2), |
| + _INIT_DCS_CMD(0xC3, 0xCD), |
| + _INIT_DCS_CMD(0xC4, 0xD9), |
| + _INIT_DCS_CMD(0xC5, 0xE7), |
| + _INIT_DCS_CMD(0xC6, 0xF4), |
| + _INIT_DCS_CMD(0xC7, 0xFA), |
| + _INIT_DCS_CMD(0xC8, 0xFC), |
| + _INIT_DCS_CMD(0xC9, 0x00), |
| + _INIT_DCS_CMD(0xCA, 0x00), |
| + _INIT_DCS_CMD(0xCB, 0x16), |
| + _INIT_DCS_CMD(0xCC, 0xAF), |
| + _INIT_DCS_CMD(0xCD, 0xFF), |
| + _INIT_DCS_CMD(0xCE, 0xFF), |
| + |
| + _INIT_DCS_CMD(0xB0, 0x0B), |
| + _INIT_DCS_CMD(0xB1, 0x04), |
| + _INIT_DCS_CMD(0xB2, 0x05), |
| + _INIT_DCS_CMD(0xB3, 0x11), |
| + _INIT_DCS_CMD(0xB4, 0x24), |
| + _INIT_DCS_CMD(0xB5, 0x39), |
| + _INIT_DCS_CMD(0xB6, 0x4F), |
| + _INIT_DCS_CMD(0xB7, 0x72), |
| + _INIT_DCS_CMD(0xB8, 0x98), |
| + _INIT_DCS_CMD(0xB9, 0xDC), |
| + _INIT_DCS_CMD(0xBA, 0x23), |
| + _INIT_DCS_CMD(0xBB, 0xA6), |
| + _INIT_DCS_CMD(0xBC, 0x2C), |
| + _INIT_DCS_CMD(0xBD, 0x30), |
| + _INIT_DCS_CMD(0xBE, 0xAA), |
| + _INIT_DCS_CMD(0xBF, 0x26), |
| + _INIT_DCS_CMD(0xC0, 0x62), |
| + _INIT_DCS_CMD(0xC1, 0x9B), |
| + _INIT_DCS_CMD(0xC2, 0xB5), |
| + _INIT_DCS_CMD(0xC3, 0xCF), |
| + _INIT_DCS_CMD(0xC4, 0xDB), |
| + _INIT_DCS_CMD(0xC5, 0xE8), |
| + _INIT_DCS_CMD(0xC6, 0xF5), |
| + _INIT_DCS_CMD(0xC7, 0xFA), |
| + _INIT_DCS_CMD(0xC8, 0xFC), |
| + _INIT_DCS_CMD(0xC9, 0x00), |
| + _INIT_DCS_CMD(0xCA, 0x00), |
| + _INIT_DCS_CMD(0xCB, 0x16), |
| + _INIT_DCS_CMD(0xCC, 0xAF), |
| + _INIT_DCS_CMD(0xCD, 0xFF), |
| + _INIT_DCS_CMD(0xCE, 0xFF), |
| + |
| + _INIT_DCS_CMD(0xB0, 0x0C), |
| + _INIT_DCS_CMD(0xB1, 0x04), |
| + _INIT_DCS_CMD(0xB2, 0x02), |
| + _INIT_DCS_CMD(0xB3, 0x16), |
| + _INIT_DCS_CMD(0xB4, 0x24), |
| + _INIT_DCS_CMD(0xB5, 0x3B), |
| + _INIT_DCS_CMD(0xB6, 0x4F), |
| + _INIT_DCS_CMD(0xB7, 0x73), |
| + _INIT_DCS_CMD(0xB8, 0x99), |
| + _INIT_DCS_CMD(0xB9, 0xE0), |
| + _INIT_DCS_CMD(0xBA, 0x26), |
| + _INIT_DCS_CMD(0xBB, 0xAD), |
| + _INIT_DCS_CMD(0xBC, 0x36), |
| + _INIT_DCS_CMD(0xBD, 0x3A), |
| + _INIT_DCS_CMD(0xBE, 0xAE), |
| + _INIT_DCS_CMD(0xBF, 0x2A), |
| + _INIT_DCS_CMD(0xC0, 0x66), |
| + _INIT_DCS_CMD(0xC1, 0x9E), |
| + _INIT_DCS_CMD(0xC2, 0xB8), |
| + _INIT_DCS_CMD(0xC3, 0xD1), |
| + _INIT_DCS_CMD(0xC4, 0xDD), |
| + _INIT_DCS_CMD(0xC5, 0xE9), |
| + _INIT_DCS_CMD(0xC6, 0xF6), |
| + _INIT_DCS_CMD(0xC7, 0xFA), |
| + _INIT_DCS_CMD(0xC8, 0xFC), |
| + _INIT_DCS_CMD(0xC9, 0x00), |
| + _INIT_DCS_CMD(0xCA, 0x00), |
| + _INIT_DCS_CMD(0xCB, 0x16), |
| + _INIT_DCS_CMD(0xCC, 0xAF), |
| + _INIT_DCS_CMD(0xCD, 0xFF), |
| + _INIT_DCS_CMD(0xCE, 0xFF), |
| + |
| + _INIT_DCS_CMD(0xB0, 0x00), |
| + _INIT_DCS_CMD(0xB3, 0x08), |
| + _INIT_DCS_CMD(0xB0, 0x04), |
| + _INIT_DCS_CMD(0xB8, 0x68), |
| + _INIT_DELAY_CMD(10), |
| + _INIT_DCS_CMD(0x11), |
| + _INIT_DELAY_CMD(120), |
| + _INIT_DCS_CMD(0x29), |
| + _INIT_DELAY_CMD(20), |
| + {}, |
| +}; |
| + |
| +static inline struct boe_hx_panel *to_boe_hx_panel(struct drm_panel *panel) |
| +{ |
| + return container_of(panel, struct boe_hx_panel, base); |
| +} |
| + |
| +static int boe_hx_panel_init(struct boe_hx_panel *boe_hx) |
| +{ |
| + struct mipi_dsi_device *dsi = boe_hx->dsi; |
| + struct drm_panel *panel = &boe_hx->base; |
| + int err, i; |
| + |
| + for (i = 0; boe_hx_init_cmd[i].len != 0; i++) { |
| + const struct panel_init_cmd *cmd = &boe_hx_init_cmd[i]; |
| + |
| + switch (cmd->type) { |
| + case INIT_DCS_CMD: |
| + err = mipi_dsi_dcs_write(dsi, cmd->data[0], |
| + (cmd->len <= 1) ? NULL : |
| + &cmd->data[1], cmd->len - 1); |
| + break; |
| + |
| + case DELAY_CMD: |
| + msleep(cmd->data[0]); |
| + err = 0; |
| + break; |
| + |
| + case INIT_GENENIC_CMD: |
| + default: |
| + err = mipi_dsi_generic_write(dsi, cmd->data, cmd->len); |
| + break; |
| + } |
| + |
| + if (err < 0) { |
| + dev_err(panel->dev, |
| + "failed to write command %u\n", i); |
| + return err; |
| + } |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +static int boe_hx_panel_off(struct boe_hx_panel *boe_hx) |
| +{ |
| + struct mipi_dsi_device *dsi = boe_hx->dsi; |
| + int ret; |
| + |
| + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; |
| + |
| + ret = mipi_dsi_dcs_set_display_off(dsi); |
| + if (ret < 0) |
| + return ret; |
| + |
| + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
| + if (ret < 0) |
| + return ret; |
| + |
| + return 0; |
| +} |
| + |
| +static int boe_hx_panel_disable(struct drm_panel *panel) |
| +{ |
| + struct boe_hx_panel *boe_hx = to_boe_hx_panel(panel); |
| + |
| + if (!boe_hx->enabled) |
| + return 0; |
| + |
| + backlight_disable(boe_hx->backlight); |
| + |
| + boe_hx->enabled = false; |
| + |
| + return 0; |
| +} |
| + |
| +static int boe_hx_panel_unprepare(struct drm_panel *panel) |
| +{ |
| + struct boe_hx_panel *boe_hx = to_boe_hx_panel(panel); |
| + int ret; |
| + |
| + if (!boe_hx->prepared) |
| + return 0; |
| + |
| + ret = boe_hx_panel_off(boe_hx); |
| + if (ret < 0) { |
| + dev_err(panel->dev, "failed to set panel off: %d\n", ret); |
| + return ret; |
| + } |
| + |
| + msleep(150); |
| + regulator_disable(boe_hx->avee); |
| + regulator_disable(boe_hx->avdd); |
| + usleep_range(5000, 7000); |
| + regulator_disable(boe_hx->pp1800); |
| + if (boe_hx->enable_gpio) |
| + gpiod_set_value(boe_hx->enable_gpio, 0); |
| + |
| + boe_hx->prepared = false; |
| + |
| + return 0; |
| +} |
| + |
| +static int boe_hx_panel_prepare(struct drm_panel *panel) |
| +{ |
| + struct boe_hx_panel *boe_hx = to_boe_hx_panel(panel); |
| + int ret; |
| + |
| + if (boe_hx->prepared) |
| + return 0; |
| + |
| + if (boe_hx->enable_gpio) { |
| + gpiod_set_value(boe_hx->enable_gpio, 0); |
| + usleep_range(1000, 1500); |
| + } |
| + |
| + ret = regulator_enable(boe_hx->pp1800); |
| + if (ret < 0) |
| + return ret; |
| + |
| + usleep_range(3000, 5000); |
| + |
| + ret = regulator_enable(boe_hx->avdd); |
| + if (ret < 0) |
| + goto poweroff1v8; |
| + ret = regulator_enable(boe_hx->avee); |
| + if (ret < 0) |
| + goto poweroffavdd; |
| + |
| + msleep(100); |
| + |
| + if (boe_hx->enable_gpio) { |
| + gpiod_set_value(boe_hx->enable_gpio, 1); |
| + usleep_range(10000, 12000); |
| + } |
| + |
| + ret = boe_hx_panel_init(boe_hx); |
| + if (ret < 0) { |
| + dev_err(panel->dev, "failed to init panel: %d\n", ret); |
| + goto poweroff; |
| + } |
| + |
| + boe_hx->prepared = true; |
| + |
| + return 0; |
| + |
| +poweroff: |
| + regulator_disable(boe_hx->avee); |
| +poweroffavdd: |
| + regulator_disable(boe_hx->avdd); |
| +poweroff1v8: |
| + usleep_range(5000, 7000); |
| + regulator_disable(boe_hx->pp1800); |
| + if (boe_hx->enable_gpio) |
| + gpiod_set_value(boe_hx->enable_gpio, 0); |
| + return ret; |
| +} |
| + |
| +static int boe_hx_panel_enable(struct drm_panel *panel) |
| +{ |
| + struct boe_hx_panel *boe_hx = to_boe_hx_panel(panel); |
| + int ret; |
| + |
| + if (boe_hx->enabled) |
| + return 0; |
| + |
| + ret = backlight_enable(boe_hx->backlight); |
| + if (ret) { |
| + DRM_DEV_ERROR(panel->drm->dev, |
| + "Failed to enable backlight %d\n", ret); |
| + return ret; |
| + } |
| + |
| + boe_hx->enabled = true; |
| + |
| + return 0; |
| +} |
| + |
| +static const struct drm_display_mode default_mode = { |
| + .clock = 159425, |
| + .hdisplay = 1200, |
| + .hsync_start = 1200 + 100, |
| + .hsync_end = 1200 + 100 + 40, |
| + .htotal = 1200 + 100 + 40 + 24, |
| + .vdisplay = 1920, |
| + .vsync_start = 1920 + 10, |
| + .vsync_end = 1920 + 10 + 14, |
| + .vtotal = 1920 + 10 + 14 + 4, |
| + .vrefresh = 60, |
| +}; |
| + |
| +static int boe_hx_panel_get_modes(struct drm_panel *panel) |
| +{ |
| + struct drm_display_mode *mode; |
| + |
| + mode = drm_mode_duplicate(panel->drm, &default_mode); |
| + if (!mode) { |
| + dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n", |
| + default_mode.hdisplay, default_mode.vdisplay, |
| + default_mode.vrefresh); |
| + return -ENOMEM; |
| + } |
| + |
| + drm_mode_set_name(mode); |
| + |
| + drm_mode_probed_add(panel->connector, mode); |
| + |
| + panel->connector->display_info.width_mm = 135; |
| + panel->connector->display_info.height_mm = 216; |
| + panel->connector->display_info.bpc = 8; |
| + |
| + return 1; |
| +} |
| + |
| +static const struct drm_panel_funcs boe_hx_panel_funcs = { |
| + .disable = boe_hx_panel_disable, |
| + .unprepare = boe_hx_panel_unprepare, |
| + .prepare = boe_hx_panel_prepare, |
| + .enable = boe_hx_panel_enable, |
| + .get_modes = boe_hx_panel_get_modes, |
| +}; |
| + |
| +static int boe_hx_panel_add(struct boe_hx_panel *boe_hx) |
| +{ |
| + struct device *dev = &boe_hx->dsi->dev; |
| + |
| + boe_hx->avdd = devm_regulator_get(dev, "avdd"); |
| + if (IS_ERR(boe_hx->avdd)) |
| + return PTR_ERR(boe_hx->avdd); |
| + |
| + boe_hx->avee = devm_regulator_get(dev, "avee"); |
| + if (IS_ERR(boe_hx->avee)) |
| + return PTR_ERR(boe_hx->avee); |
| + |
| + boe_hx->pp1800 = devm_regulator_get(dev, "pp1800"); |
| + if (IS_ERR(boe_hx->pp1800)) |
| + return PTR_ERR(boe_hx->pp1800); |
| + |
| + boe_hx->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); |
| + if (IS_ERR(boe_hx->enable_gpio)) { |
| + dev_err(dev, "cannot get reset-gpios %ld\n", |
| + PTR_ERR(boe_hx->enable_gpio)); |
| + boe_hx->enable_gpio = NULL; |
| + } else { |
| + gpiod_set_value(boe_hx->enable_gpio, 0); |
| + } |
| + |
| + boe_hx->backlight = devm_of_find_backlight(dev); |
| + if (IS_ERR(boe_hx->backlight)) |
| + return PTR_ERR(boe_hx->backlight); |
| + |
| + drm_panel_init(&boe_hx->base); |
| + boe_hx->base.funcs = &boe_hx_panel_funcs; |
| + boe_hx->base.dev = &boe_hx->dsi->dev; |
| + |
| + return drm_panel_add(&boe_hx->base); |
| +} |
| + |
| +static void boe_hx_panel_del(struct boe_hx_panel *boe_hx) |
| +{ |
| + if (boe_hx->base.dev) |
| + drm_panel_remove(&boe_hx->base); |
| +} |
| + |
| +static int boe_hx_panel_probe(struct mipi_dsi_device *dsi) |
| +{ |
| + struct boe_hx_panel *boe_hx; |
| + int ret; |
| + |
| + dsi->lanes = 4; |
| + dsi->format = MIPI_DSI_FMT_RGB888; |
| + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | |
| + MIPI_DSI_MODE_LPM; |
| + |
| + boe_hx = devm_kzalloc(&dsi->dev, sizeof(*boe_hx), GFP_KERNEL); |
| + if (!boe_hx) |
| + return -ENOMEM; |
| + |
| + mipi_dsi_set_drvdata(dsi, boe_hx); |
| + |
| + boe_hx->dsi = dsi; |
| + |
| + ret = boe_hx_panel_add(boe_hx); |
| + if (ret < 0) |
| + return ret; |
| + |
| + return mipi_dsi_attach(dsi); |
| +} |
| + |
| +static int boe_hx_panel_remove(struct mipi_dsi_device *dsi) |
| +{ |
| + struct boe_hx_panel *boe_hx = mipi_dsi_get_drvdata(dsi); |
| + int ret; |
| + |
| + ret = boe_hx_panel_disable(&boe_hx->base); |
| + if (ret < 0) |
| + dev_err(&dsi->dev, "failed to disable panel: %d\n", ret); |
| + |
| + ret = mipi_dsi_detach(dsi); |
| + if (ret < 0) |
| + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); |
| + |
| + boe_hx_panel_del(boe_hx); |
| + |
| + return 0; |
| +} |
| + |
| +static void boe_hx_panel_shutdown(struct mipi_dsi_device *dsi) |
| +{ |
| + struct boe_hx_panel *boe_hx = mipi_dsi_get_drvdata(dsi); |
| + |
| + boe_hx_panel_disable(&boe_hx->base); |
| +} |
| + |
| +static const struct of_device_id boe_hx_of_match[] = { |
| + { .compatible = "boe,tv101wum", }, |
| + { } |
| +}; |
| +MODULE_DEVICE_TABLE(of, boe_hx_of_match); |
| + |
| +static struct mipi_dsi_driver boe_hx_panel_driver = { |
| + .driver = { |
| + .name = "panel-boe-tv101wum", |
| + .of_match_table = boe_hx_of_match, |
| + }, |
| + .probe = boe_hx_panel_probe, |
| + .remove = boe_hx_panel_remove, |
| + .shutdown = boe_hx_panel_shutdown, |
| +}; |
| +module_mipi_dsi_driver(boe_hx_panel_driver); |
| + |
| +MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>"); |
| +MODULE_DESCRIPTION("BOE tv101wum FT8201-based wuxga (1200x1920) video mode panel driver"); |
| +MODULE_LICENSE("GPL v2"); |
| diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c |
| index 88c7d035ace6..f52c892323c3 100644 |
| --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c |
| +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c |
| @@ -56,7 +56,7 @@ struct innolux_panel { |
| struct backlight_device *backlight; |
| struct regulator_bulk_data *supplies; |
| unsigned int num_supplies; |
| - struct gpio_desc *enable_gpio; |
| + struct gpio_desc *enable_gpio[2]; |
| |
| bool prepared; |
| bool enabled; |
| @@ -84,7 +84,7 @@ static int innolux_panel_disable(struct drm_panel *panel) |
| static int innolux_panel_unprepare(struct drm_panel *panel) |
| { |
| struct innolux_panel *innolux = to_innolux_panel(panel); |
| - int err; |
| + int err, i; |
| |
| if (!innolux->prepared) |
| return 0; |
| @@ -104,7 +104,8 @@ static int innolux_panel_unprepare(struct drm_panel *panel) |
| if (innolux->desc->sleep_mode_delay) |
| msleep(innolux->desc->sleep_mode_delay); |
| |
| - gpiod_set_value_cansleep(innolux->enable_gpio, 0); |
| + for (i = 0; i < ARRAY_SIZE(innolux->enable_gpio); i++) |
| + gpiod_set_value_cansleep(innolux->enable_gpio[i], 0); |
| |
| if (innolux->desc->power_down_delay) |
| msleep(innolux->desc->power_down_delay); |
| @@ -122,22 +123,28 @@ static int innolux_panel_unprepare(struct drm_panel *panel) |
| static int innolux_panel_prepare(struct drm_panel *panel) |
| { |
| struct innolux_panel *innolux = to_innolux_panel(panel); |
| - int err; |
| + int err, i; |
| |
| if (innolux->prepared) |
| return 0; |
| |
| - gpiod_set_value_cansleep(innolux->enable_gpio, 0); |
| + for (i = 0; i < ARRAY_SIZE(innolux->enable_gpio); i++) |
| + gpiod_set_value_cansleep(innolux->enable_gpio[i], 0); |
| |
| err = regulator_bulk_enable(innolux->desc->num_supplies, |
| innolux->supplies); |
| if (err < 0) |
| return err; |
| |
| - /* p079zca: t2 (20ms), p097pfg: t4 (15ms) */ |
| - usleep_range(20000, 21000); |
| + for (i = 0; i < ARRAY_SIZE(innolux->enable_gpio); i++) { |
| + if (!innolux->enable_gpio[i]) |
| + break; |
| |
| - gpiod_set_value_cansleep(innolux->enable_gpio, 1); |
| + /* p079zca: t2 (20ms), p097pfg: t4 (15ms); ssd2858: 20ms */ |
| + usleep_range(20000, 21000); |
| + |
| + gpiod_set_value_cansleep(innolux->enable_gpio[i], 1); |
| + } |
| |
| /* p079zca: t4, p097pfg: t5 */ |
| usleep_range(20000, 21000); |
| @@ -158,6 +165,18 @@ static int innolux_panel_prepare(struct drm_panel *panel) |
| goto poweroff; |
| } |
| |
| + /* |
| + * If the command list contains exit sleep mode or set |
| + * display on, wait the appropriate time (needed for |
| + * displays behind a bridge). |
| + */ |
| + /* T6: 120ms - 1000ms*/ |
| + if (cmd->data[0] == MIPI_DCS_EXIT_SLEEP_MODE) |
| + msleep(120); |
| + /* T7: 5ms */ |
| + if (cmd->data[0] == MIPI_DCS_SET_DISPLAY_ON) |
| + usleep_range(5000, 6000); |
| + |
| /* |
| * Included by random guessing, because without this |
| * (or at least, some delay), the panel sometimes |
| @@ -197,7 +216,8 @@ static int innolux_panel_prepare(struct drm_panel *panel) |
| return 0; |
| |
| poweroff: |
| - gpiod_set_value_cansleep(innolux->enable_gpio, 0); |
| + for (i = 0; i < ARRAY_SIZE(innolux->enable_gpio); i++) |
| + gpiod_set_value_cansleep(innolux->enable_gpio[i], 0); |
| regulator_bulk_disable(innolux->desc->num_supplies, innolux->supplies); |
| |
| return err; |
| @@ -405,6 +425,90 @@ static const struct panel_desc innolux_p097pfg_panel_desc = { |
| .sleep_mode_delay = 100, /* T15 */ |
| }; |
| |
| +static const char * const innolux_p097pfg_ssd2858_supply_names[] = { |
| + "avdd", |
| + "avee", |
| + "pp1800", |
| + "pp3300", |
| + "pp1200-bridge", |
| + "vddio-bridge", |
| +}; |
| + |
| +static const struct drm_display_mode innolux_p097pfg_ssd2858_mode = { |
| + .clock = 211660, |
| + .hdisplay = 1536, |
| + .hsync_start = 1536 + 140, |
| + .hsync_end = 1536 + 140 + 10, |
| + .htotal = 1536 + 140 + 10 + 10, |
| + .vdisplay = 2048, |
| + .vsync_start = 2048 + 20, |
| + .vsync_end = 2048 + 20 + 2, |
| + .vtotal = 2048 + 20 + 2 + 10, |
| + .vrefresh = 60, |
| +}; |
| + |
| +static const struct panel_init_cmd innolux_p097pfg_ssd2858_init_cmds[] = { |
| + /* SSD2858 config */ |
| + _INIT_CMD(0xff, 0x00), |
| + /* LOCKCNT=0x1f4, MRX=0, POSTDIV=1 (/2), MULT=0x49 |
| + * 27 Mhz => 985.5 Mhz */ |
| + _INIT_CMD(0x00, 0x08, 0x01, 0xf4, 0x01, 0x49), |
| + /* MTXDIV=1, SYSDIV=3 (=> 4) */ |
| + _INIT_CMD(0x00, 0x0c, 0x00, 0x00, 0x00, 0x03), |
| + /* MTXVPF=24bpp, MRXLS=4 lanes, MRXVB=bypass, MRXECC=1, MRXEOT=1 |
| + * MRXEE=1 */ |
| + _INIT_CMD(0x00, 0x14, 0x0c, 0x3d, 0x80, 0x0f), |
| + _INIT_CMD(0x00, 0x20, 0x15, 0x92, 0x56, 0x7d), |
| + _INIT_CMD(0x00, 0x24, 0x00, 0x00, 0x30, 0x00), |
| + |
| + _INIT_CMD(0x10, 0x08, 0x01, 0x20, 0x08, 0x45), |
| + _INIT_CMD(0x10, 0x1c, 0x00, 0x00, 0x00, 0x00), |
| + _INIT_CMD(0x20, 0x0c, 0x00, 0x00, 0x00, 0x04), |
| + /* Pixel clock 985.5 Mhz * 0x49/0x4b = 959 Mhz */ |
| + _INIT_CMD(0x20, 0x10, 0x00, 0x4b, 0x00, 0x49), |
| + _INIT_CMD(0x20, 0xa0, 0x00, 0x00, 0x00, 0x00), |
| + /* EOT=1, LPE = 0, LSOUT=4 lanes, LPD=25 */ |
| + _INIT_CMD(0x60, 0x08, 0x00, 0xd9, 0x00, 0x08), |
| + _INIT_CMD(0x60, 0x14, 0x01, 0x00, 0x01, 0x06), |
| + /* DSI0 enable (default: probably not needed) */ |
| + _INIT_CMD(0x60, 0x80, 0x00, 0x00, 0x00, 0x0f), |
| + /* DSI1 enable */ |
| + _INIT_CMD(0x60, 0xa0, 0x00, 0x00, 0x00, 0x0f), |
| + |
| + /* HSA=0x18, VSA=0x02, HBP=0x50, VBP=0x0c */ |
| + _INIT_CMD(0x60, 0x0c, 0x0c, 0x50, 0x02, 0x18), |
| + /* VACT= 0x800 (2048), VFP= 0x14, HFP=0x50 */ |
| + _INIT_CMD(0x60, 0x10, 0x08, 0x00, 0x14, 0x50), |
| + /* HACT=0x300 (768) */ |
| + _INIT_CMD(0x60, 0x84, 0x00, 0x00, 0x03, 0x00), |
| + _INIT_CMD(0x60, 0xa4, 0x00, 0x00, 0x03, 0x00), |
| + |
| + /* Take panel out of sleep. */ |
| + _INIT_CMD(0xff, 0x01), |
| + _INIT_CMD(0x11), |
| + _INIT_CMD(0x29), |
| + _INIT_CMD(0xff, 0x00), |
| + |
| + {}, |
| +}; |
| + |
| +static const struct panel_desc innolux_p097pfg_ssd2858_panel_desc = { |
| + .mode = &innolux_p097pfg_ssd2858_mode, |
| + .bpc = 8, |
| + .size = { |
| + .width = 147, |
| + .height = 196, |
| + }, |
| + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | |
| + MIPI_DSI_MODE_LPM, |
| + .format = MIPI_DSI_FMT_RGB888, |
| + .init_cmds = innolux_p097pfg_ssd2858_init_cmds, |
| + .lanes = 4, |
| + .supply_names = innolux_p097pfg_ssd2858_supply_names, |
| + .num_supplies = ARRAY_SIZE(innolux_p097pfg_ssd2858_supply_names), |
| + .sleep_mode_delay = 100, /* T15 */ |
| +}; |
| + |
| static int innolux_panel_get_modes(struct drm_panel *panel) |
| { |
| struct innolux_panel *innolux = to_innolux_panel(panel); |
| @@ -446,6 +550,9 @@ static const struct of_device_id innolux_of_match[] = { |
| { .compatible = "innolux,p097pfg", |
| .data = &innolux_p097pfg_panel_desc |
| }, |
| + { .compatible = "innolux,p097pfg_ssd2858", |
| + .data = &innolux_p097pfg_ssd2858_panel_desc |
| + }, |
| { } |
| }; |
| MODULE_DEVICE_TABLE(of, innolux_of_match); |
| @@ -477,12 +584,14 @@ static int innolux_panel_add(struct mipi_dsi_device *dsi, |
| if (err < 0) |
| return err; |
| |
| - innolux->enable_gpio = devm_gpiod_get_optional(dev, "enable", |
| - GPIOD_OUT_HIGH); |
| - if (IS_ERR(innolux->enable_gpio)) { |
| - err = PTR_ERR(innolux->enable_gpio); |
| - dev_dbg(dev, "failed to get enable gpio: %d\n", err); |
| - innolux->enable_gpio = NULL; |
| + for (i = 0; i < ARRAY_SIZE(innolux->enable_gpio); i++) { |
| + innolux->enable_gpio[i] = devm_gpiod_get_index_optional(dev, |
| + "enable", i, GPIOD_OUT_HIGH); |
| + if (IS_ERR(innolux->enable_gpio[i])) { |
| + err = PTR_ERR(innolux->enable_gpio[i]); |
| + dev_err(dev, "failed to get enable gpio: %d\n", err); |
| + innolux->enable_gpio[i] = NULL; |
| + } |
| } |
| |
| innolux->backlight = devm_of_find_backlight(dev); |
| diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c |
| index 803084c86124..43e420cdab6e 100644 |
| --- a/drivers/iommu/mtk_iommu.c |
| +++ b/drivers/iommu/mtk_iommu.c |
| @@ -262,6 +262,7 @@ static void mtk_iommu_config(struct mtk_iommu_data *data, |
| struct mtk_smi_larb_iommu *larb_mmu; |
| unsigned int larbid, portid; |
| struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); |
| + struct device_link *link; |
| int i; |
| |
| for (i = 0; i < fwspec->num_ids; ++i) { |
| @@ -272,10 +273,20 @@ static void mtk_iommu_config(struct mtk_iommu_data *data, |
| dev_dbg(dev, "%s iommu port: %d\n", |
| enable ? "enable" : "disable", portid); |
| |
| - if (enable) |
| + if (enable) { |
| larb_mmu->mmu |= MTK_SMI_MMU_EN(portid); |
| - else |
| + /* Link the consumer with the larb device(supplier) */ |
| + link = device_link_add(dev, larb_mmu->dev, |
| + DL_FLAG_PM_RUNTIME | |
| + DL_FLAG_AUTOREMOVE_CONSUMER); |
| + if (!link) { |
| + dev_err(dev, "Unable to link %s\n", |
| + dev_name(larb_mmu->dev)); |
| + return; |
| + } |
| + } else { |
| larb_mmu->mmu &= ~MTK_SMI_MMU_EN(portid); |
| + } |
| } |
| } |
| |
| @@ -662,7 +673,7 @@ static int mtk_iommu_probe(struct platform_device *pdev) |
| id = i; |
| |
| plarbdev = of_find_device_by_node(larbnode); |
| - if (!plarbdev) |
| + if (!plarbdev || !plarbdev->dev.driver) |
| return -EPROBE_DEFER; |
| data->smi_imu.larb_imu[id].dev = &plarbdev->dev; |
| |
| @@ -696,7 +707,7 @@ static int mtk_iommu_probe(struct platform_device *pdev) |
| return component_master_add_with_match(dev, &mtk_iommu_com_ops, match); |
| } |
| |
| -static int mtk_iommu_remove(struct platform_device *pdev) |
| +static void mtk_iommu_shutdown(struct platform_device *pdev) |
| { |
| struct mtk_iommu_data *data = platform_get_drvdata(pdev); |
| |
| @@ -709,12 +720,6 @@ static int mtk_iommu_remove(struct platform_device *pdev) |
| clk_disable_unprepare(data->bclk); |
| devm_free_irq(&pdev->dev, data->irq, data); |
| component_master_del(&pdev->dev, &mtk_iommu_com_ops); |
| - return 0; |
| -} |
| - |
| -static void mtk_iommu_shutdown(struct platform_device *pdev) |
| -{ |
| - mtk_iommu_remove(pdev); |
| } |
| |
| static int __maybe_unused mtk_iommu_suspend(struct device *dev) |
| @@ -797,7 +802,6 @@ static const struct of_device_id mtk_iommu_of_ids[] = { |
| |
| static struct platform_driver mtk_iommu_driver = { |
| .probe = mtk_iommu_probe, |
| - .remove = mtk_iommu_remove, |
| .shutdown = mtk_iommu_shutdown, |
| .driver = { |
| .name = "mtk-iommu", |
| @@ -805,16 +809,4 @@ static struct platform_driver mtk_iommu_driver = { |
| .pm = &mtk_iommu_pm_ops, |
| } |
| }; |
| - |
| -static int __init mtk_iommu_init(void) |
| -{ |
| - int ret; |
| - |
| - ret = platform_driver_register(&mtk_iommu_driver); |
| - if (ret != 0) |
| - pr_err("Failed to register MTK IOMMU driver\n"); |
| - |
| - return ret; |
| -} |
| - |
| -subsys_initcall(mtk_iommu_init) |
| +builtin_platform_driver(mtk_iommu_driver); |
| diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c |
| index d70bdf64ab71..832ea99f7a16 100644 |
| --- a/drivers/iommu/mtk_iommu_v1.c |
| +++ b/drivers/iommu/mtk_iommu_v1.c |
| @@ -201,6 +201,7 @@ static void mtk_iommu_config(struct mtk_iommu_data *data, |
| struct mtk_smi_larb_iommu *larb_mmu; |
| unsigned int larbid, portid; |
| struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); |
| + struct device_link *link; |
| int i; |
| |
| for (i = 0; i < fwspec->num_ids; ++i) { |
| @@ -211,10 +212,19 @@ static void mtk_iommu_config(struct mtk_iommu_data *data, |
| dev_dbg(dev, "%s iommu port: %d\n", |
| enable ? "enable" : "disable", portid); |
| |
| - if (enable) |
| + if (enable) { |
| larb_mmu->mmu |= MTK_SMI_MMU_EN(portid); |
| - else |
| + link = device_link_add(dev, larb_mmu->dev, |
| + DL_FLAG_PM_RUNTIME | |
| + DL_FLAG_AUTOREMOVE_CONSUMER); |
| + if (!link) { |
| + dev_err(dev, "Unable to link %s\n", |
| + dev_name(larb_mmu->dev)); |
| + return; |
| + } |
| + } else { |
| larb_mmu->mmu &= ~MTK_SMI_MMU_EN(portid); |
| + } |
| } |
| } |
| |
| @@ -601,7 +611,7 @@ static int mtk_iommu_probe(struct platform_device *pdev) |
| plarbdev = of_platform_device_create( |
| larb_spec.np, NULL, |
| platform_bus_type.dev_root); |
| - if (!plarbdev) { |
| + if (!plarbdev || !plarbdev->dev.driver) { |
| of_node_put(larb_spec.np); |
| return -EPROBE_DEFER; |
| } |
| @@ -636,7 +646,7 @@ static int mtk_iommu_probe(struct platform_device *pdev) |
| return component_master_add_with_match(dev, &mtk_iommu_com_ops, match); |
| } |
| |
| -static int mtk_iommu_remove(struct platform_device *pdev) |
| +static void mtk_iommu_shutdown(struct platform_device *pdev) |
| { |
| struct mtk_iommu_data *data = platform_get_drvdata(pdev); |
| |
| @@ -649,12 +659,6 @@ static int mtk_iommu_remove(struct platform_device *pdev) |
| clk_disable_unprepare(data->bclk); |
| devm_free_irq(&pdev->dev, data->irq, data); |
| component_master_del(&pdev->dev, &mtk_iommu_com_ops); |
| - return 0; |
| -} |
| - |
| -static void mtk_iommu_shutdown(struct platform_device *pdev) |
| -{ |
| - mtk_iommu_remove(pdev); |
| } |
| |
| static int __maybe_unused mtk_iommu_suspend(struct device *dev) |
| @@ -693,7 +697,6 @@ static const struct dev_pm_ops mtk_iommu_pm_ops = { |
| |
| static struct platform_driver mtk_iommu_driver = { |
| .probe = mtk_iommu_probe, |
| - .remove = mtk_iommu_remove, |
| .shutdown = mtk_iommu_shutdown, |
| .driver = { |
| .name = "mtk-iommu-v1", |
| @@ -701,9 +704,4 @@ static struct platform_driver mtk_iommu_driver = { |
| .pm = &mtk_iommu_pm_ops, |
| } |
| }; |
| - |
| -static int __init m4u_init(void) |
| -{ |
| - return platform_driver_register(&mtk_iommu_driver); |
| -} |
| -subsys_initcall(m4u_init); |
| +builtin_platform_driver(mtk_iommu_driver); |
| diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig |
| index 841c005d8ebb..31dc4c5e37e1 100644 |
| --- a/drivers/mailbox/Kconfig |
| +++ b/drivers/mailbox/Kconfig |
| @@ -205,4 +205,22 @@ config MTK_CMDQ_MBOX |
| mailbox driver. The CMDQ is used to help read/write registers with |
| critical time limitation, such as updating display configuration |
| during the vblank. |
| + |
| +config MTK_CMDQ_DEBUG |
| + tristate "MediaTek CMDQ Mailbox Debug" |
| + depends on MTK_CMDQ_MBOX |
| + help |
| + Say yes here to add support for debugging CMDQ driver when timeout |
| + or irq status error happens. It will print some useful information |
| + for location problem, such as thread id, PC value and instructions |
| + of command queue buffer. |
| + |
| +config MTK_CMDQ_DEBUG_SOC |
| + int "MediaTek CMDQ Mailbox Debug SOC" |
| + depends on MTK_CMDQ_DEBUG |
| + help |
| + Enter the SOC id that you want to debug CMDQ driver when timeout |
| + or irq status error happens. |
| + The SOC id is a decimal integer, e.g. 8173 for MT8173 SOC. |
| + You must enter the id. |
| endif |
| diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile |
| index c818b5d011ae..b356e36d8f2a 100644 |
| --- a/drivers/mailbox/Makefile |
| +++ b/drivers/mailbox/Makefile |
| @@ -44,3 +44,4 @@ obj-$(CONFIG_TEGRA_HSP_MBOX) += tegra-hsp.o |
| obj-$(CONFIG_STM32_IPCC) += stm32-ipcc.o |
| |
| obj-$(CONFIG_MTK_CMDQ_MBOX) += mtk-cmdq-mailbox.o |
| +obj-$(CONFIG_MTK_CMDQ_DEBUG) += mtk-cmdq-debug.o |
| diff --git a/drivers/mailbox/mtk-cmdq-debug.c b/drivers/mailbox/mtk-cmdq-debug.c |
| new file mode 100644 |
| index 000000000000..61985342d564 |
| --- /dev/null |
| +++ b/drivers/mailbox/mtk-cmdq-debug.c |
| @@ -0,0 +1,582 @@ |
| +// SPDX-License-Identifier: GPL-2.0 |
| +// |
| +// Copyright (c) 2018 MediaTek Inc. |
| + |
| +#include <linux/kernel.h> |
| +#include <linux/module.h> |
| +#include <linux/mailbox/mtk-cmdq-mailbox.h> |
| +#include <linux/workqueue.h> |
| +#include "mtk-cmdq-debug.h" |
| +#if CONFIG_MTK_CMDQ_DEBUG_SOC == 8173 |
| +#include <dt-bindings/gce/mt8173-gce.h> |
| +#elif CONFIG_MTK_CMDQ_DEBUG_SOC == 8183 |
| +#include <dt-bindings/gce/mt8183-gce.h> |
| +#else |
| +static int __error__[-1]; /* Complle error if SOC is not set. */ |
| +#endif |
| + |
| +#define CMDQ_OP_CODE_MASK (0xff << CMDQ_OP_CODE_SHIFT) |
| +#define CMDQ_NUM_CMD(t) (t->cmd_buf_size / CMDQ_INST_SIZE) |
| +#define CMDQ_GET_32B_VALUE(arg_b, arg_c) ((u32)((arg_b) << 16) | (arg_c)) |
| +#define CMDQ_REG_IDX_PREFIX(type) ((type) ? "" : "Reg Index ") |
| + |
| +struct cmdq_instruction { |
| + s16 arg_c:16; |
| + s16 arg_b:16; |
| + s16 arg_a:16; |
| + u8 s_op:5; |
| + u8 arg_c_type:1; |
| + u8 arg_b_type:1; |
| + u8 arg_a_type:1; |
| + u8 op:8; |
| +}; |
| + |
| +void cmdq_buf_print_write(struct device *dev, u32 offset, |
| + struct cmdq_instruction *cmdq_inst) |
| +{ |
| + u32 addr = ((u32)(cmdq_inst->arg_a | |
| + (cmdq_inst->s_op << CMDQ_SUBSYS_SHIFT))); |
| + |
| + dev_err(dev, "0x%08x [Write | Store] %s0x%08x = %s0x%08x\n", |
| + offset, cmdq_inst->arg_a_type ? "*Reg Index " : "SubSys Reg ", |
| + addr, CMDQ_REG_IDX_PREFIX(!cmdq_inst->arg_b_type), |
| + cmdq_inst->arg_b_type ? cmdq_inst->arg_b : |
| + CMDQ_GET_32B_VALUE(cmdq_inst->arg_b, cmdq_inst->arg_c)); |
| +} |
| + |
| +static void cmdq_buf_print_wfe(struct device *dev, u32 offset, |
| + struct cmdq_instruction *cmdq_inst) |
| +{ |
| + const char *event_str; |
| + u32 cmd = CMDQ_GET_32B_VALUE(cmdq_inst->arg_b, cmdq_inst->arg_c); |
| + |
| + switch (cmdq_inst->arg_a) { |
| +#if CONFIG_MTK_CMDQ_DEBUG_SOC == 8173 |
| + case CMDQ_EVENT_DISP_OVL0_SOF: |
| + event_str = "CMDQ_EVENT_DISP_OVL0_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_OVL1_SOF: |
| + event_str = "CMDQ_EVENT_DISP_OVL1_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_RDMA0_SOF: |
| + event_str = "CMDQ_EVENT_DISP_RDMA0_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_RDMA1_SOF: |
| + event_str = "CMDQ_EVENT_DISP_RDMA1_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_RDMA2_SOF: |
| + event_str = "CMDQ_EVENT_DISP_RDMA2_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_WDMA0_SOF: |
| + event_str = "CMDQ_EVENT_DISP_WDMA0_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_WDMA1_SOF: |
| + event_str = "CMDQ_EVENT_DISP_WDMA1_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_OVL0_EOF: |
| + event_str = "CMDQ_EVENT_DISP_OVL0_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_OVL1_EOF: |
| + event_str = "CMDQ_EVENT_DISP_OVL1_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_RDMA0_EOF: |
| + event_str = "CMDQ_EVENT_DISP_RDMA0_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_RDMA1_EOF: |
| + event_str = "CMDQ_EVENT_DISP_RDMA1_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_RDMA2_EOF: |
| + event_str = "CMDQ_EVENT_DISP_RDMA2_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_WDMA0_EOF: |
| + event_str = "CMDQ_EVENT_DISP_WDMA0_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_WDMA1_EOF: |
| + event_str = "CMDQ_EVENT_DISP_WDMA1_EOF"; |
| + break; |
| + case CMDQ_EVENT_MUTEX0_STREAM_EOF: |
| + event_str = "CMDQ_EVENT_MUTEX0_STREAM_EOF"; |
| + break; |
| + case CMDQ_EVENT_MUTEX1_STREAM_EOF: |
| + event_str = "CMDQ_EVENT_MUTEX1_STREAM_EOF"; |
| + break; |
| + case CMDQ_EVENT_MUTEX2_STREAM_EOF: |
| + event_str = "CMDQ_EVENT_MUTEX2_STREAM_EOF"; |
| + break; |
| + case CMDQ_EVENT_MUTEX3_STREAM_EOF: |
| + event_str = "CMDQ_EVENT_MUTEX3_STREAM_EOF"; |
| + break; |
| + case CMDQ_EVENT_MUTEX4_STREAM_EOF: |
| + event_str = "CMDQ_EVENT_MUTEX4_STREAM_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_RDMA0_UNDERRUN: |
| + event_str = "CMDQ_EVENT_DISP_RDMA0_UNDERRUN"; |
| + break; |
| + case CMDQ_EVENT_DISP_RDMA1_UNDERRUN: |
| + event_str = "CMDQ_EVENT_DISP_RDMA1_UNDERRUN"; |
| + break; |
| + case CMDQ_EVENT_DISP_RDMA2_UNDERRUN: |
| + event_str = "CMDQ_EVENT_DISP_RDMA2_UNDERRUN"; |
| + break; |
| +#elif CONFIG_MTK_CMDQ_DEBUG_SOC == 8183 |
| + case CMDQ_EVENT_DISP_RDMA0_SOF: |
| + event_str = "CMDQ_EVENT_DISP_RDMA0_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_RDMA1_SOF: |
| + event_str = "CMDQ_EVENT_DISP_RDMA1_SOF"; |
| + break; |
| + case CMDQ_EVENT_MDP_RDMA0_SOF: |
| + event_str = "CMDQ_EVENT_MDP_RDMA0_SOF"; |
| + break; |
| + case CMDQ_EVENT_MDP_RSZ0_SOF: |
| + event_str = "CMDQ_EVENT_MDP_RSZ0_SOF"; |
| + break; |
| + case CMDQ_EVENT_MDP_RSZ1_SOF: |
| + event_str = "CMDQ_EVENT_MDP_RSZ1_SOF"; |
| + break; |
| + case CMDQ_EVENT_MDP_TDSHP_SOF: |
| + event_str = "CMDQ_EVENT_MDP_TDSHP_SOF"; |
| + break; |
| + case CMDQ_EVENT_MDP_WROT0_SOF: |
| + event_str = "CMDQ_EVENT_MDP_WROT0_SOF"; |
| + break; |
| + case CMDQ_EVENT_MDP_WDMA0_SOF: |
| + event_str = "CMDQ_EVENT_MDP_WDMA0_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_OVL0_SOF: |
| + event_str = "CMDQ_EVENT_DISP_OVL0_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_OVL0_2L_SOF: |
| + event_str = "CMDQ_EVENT_DISP_OVL0_2L_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_OVL1_2L_SOF: |
| + event_str = "CMDQ_EVENT_DISP_OVL1_2L_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_WDMA0_SOF: |
| + event_str = "CMDQ_EVENT_DISP_WDMA0_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_COLOR0_SOF: |
| + event_str = "CMDQ_EVENT_DISP_COLOR0_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_CCORR0_SOF: |
| + event_str = "CMDQ_EVENT_DISP_CCORR0_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_AAL0_SOF: |
| + event_str = "CMDQ_EVENT_DISP_AAL0_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_GAMMA0_SOF: |
| + event_str = "CMDQ_EVENT_DISP_GAMMA0_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_DITHER0_SOF: |
| + event_str = "CMDQ_EVENT_DISP_DITHER0_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_PWM0_SOF: |
| + event_str = "CMDQ_EVENT_DISP_PWM0_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_DSI0_SOF: |
| + event_str = "CMDQ_EVENT_DISP_DSI0_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_DPI0_SOF: |
| + event_str = "CMDQ_EVENT_DISP_DPI0_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_RSZ_SOF: |
| + event_str = "CMDQ_EVENT_DISP_RSZ_SOF"; |
| + break; |
| + case CMDQ_EVENT_MDP_AAL_SOF: |
| + event_str = "CMDQ_EVENT_MDP_AAL_SOF"; |
| + break; |
| + case CMDQ_EVENT_MDP_CCORR_SOF: |
| + event_str = "CMDQ_EVENT_MDP_CCORR_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_DBI_SOF: |
| + event_str = "CMDQ_EVENT_DISP_DBI_SOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_RDMA0_EOF: |
| + event_str = "CMDQ_EVENT_DISP_RDMA0_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_RDMA1_EOF: |
| + event_str = "CMDQ_EVENT_DISP_RDMA1_EOF"; |
| + break; |
| + case CMDQ_EVENT_MDP_RDMA0_EOF: |
| + event_str = "CMDQ_EVENT_MDP_RDMA0_EOF"; |
| + break; |
| + case CMDQ_EVENT_MDP_RSZ0_EOF: |
| + event_str = "CMDQ_EVENT_MDP_RSZ0_EOF"; |
| + break; |
| + case CMDQ_EVENT_MDP_RSZ1_EOF: |
| + event_str = "CMDQ_EVENT_MDP_RSZ1_EOF"; |
| + break; |
| + case CMDQ_EVENT_MDP_TDSHP_EOF: |
| + event_str = "CMDQ_EVENT_MDP_TDSHP_EOF"; |
| + break; |
| + case CMDQ_EVENT_MDP_WROT0_EOF: |
| + event_str = "CMDQ_EVENT_MDP_WROT0_EOF"; |
| + break; |
| + case CMDQ_EVENT_MDP_WDMA0_EOF: |
| + event_str = "CMDQ_EVENT_MDP_WDMA0_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_OVL0_EOF: |
| + event_str = "CMDQ_EVENT_DISP_OVL0_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_OVL0_2L_EOF: |
| + event_str = "CMDQ_EVENT_DISP_OVL0_2L_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_OVL1_2L_EOF: |
| + event_str = "CMDQ_EVENT_DISP_OVL1_2L_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_WDMA0_EOF: |
| + event_str = "CMDQ_EVENT_DISP_WDMA0_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_COLOR0_EOF: |
| + event_str = "CMDQ_EVENT_DISP_COLOR0_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_CCORR0_EOF: |
| + event_str = "CMDQ_EVENT_DISP_CCORR0_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_AAL0_EOF: |
| + event_str = "CMDQ_EVENT_DISP_AAL0_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_GAMMA0_EOF: |
| + event_str = "CMDQ_EVENT_DISP_GAMMA0_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_DITHER0_EOF: |
| + event_str = "CMDQ_EVENT_DISP_DITHER0_EOF"; |
| + break; |
| + case CMDQ_EVENT_DSI0_EOF: |
| + event_str = "CMDQ_EVENT_DSI0_EOF"; |
| + break; |
| + case CMDQ_EVENT_DPI0_EOF: |
| + event_str = "CMDQ_EVENT_DPI0_EOF"; |
| + break; |
| + case CMDQ_EVENT_DISP_RSZ_EOF: |
| + event_str = "CMDQ_EVENT_DISP_RSZ_EOF"; |
| + break; |
| + case CMDQ_EVENT_MDP_AAL_EOF: |
| + event_str = "CMDQ_EVENT_MDP_AAL_EOF"; |
| + break; |
| + case CMDQ_EVENT_MDP_CCORR_EOF: |
| + event_str = "CMDQ_EVENT_MDP_CCORR_EOF"; |
| + break; |
| + case CMDQ_EVENT_DBI_EOF: |
| + event_str = "CMDQ_EVENT_DBI_EOF"; |
| + break; |
| + case CMDQ_EVENT_MUTEX_STREAM_DONE0: |
| + event_str = "CMDQ_EVENT_MUTEX_STREAM_DONE0"; |
| + break; |
| + case CMDQ_EVENT_MUTEX_STREAM_DONE1: |
| + event_str = "CMDQ_EVENT_MUTEX_STREAM_DONE1"; |
| + break; |
| + case CMDQ_EVENT_MUTEX_STREAM_DONE2: |
| + event_str = "CMDQ_EVENT_MUTEX_STREAM_DONE2"; |
| + break; |
| + case CMDQ_EVENT_MUTEX_STREAM_DONE3: |
| + event_str = "CMDQ_EVENT_MUTEX_STREAM_DONE3"; |
| + break; |
| + case CMDQ_EVENT_MUTEX_STREAM_DONE4: |
| + event_str = "CMDQ_EVENT_MUTEX_STREAM_DONE4"; |
| + break; |
| + case CMDQ_EVENT_MUTEX_STREAM_DONE5: |
| + event_str = "CMDQ_EVENT_MUTEX_STREAM_DONE5"; |
| + break; |
| + case CMDQ_EVENT_MUTEX_STREAM_DONE6: |
| + event_str = "CMDQ_EVENT_MUTEX_STREAM_DONE6"; |
| + break; |
| + case CMDQ_EVENT_MUTEX_STREAM_DONE7: |
| + event_str = "CMDQ_EVENT_MUTEX_STREAM_DONE7"; |
| + break; |
| + case CMDQ_EVENT_MUTEX_STREAM_DONE8: |
| + event_str = "CMDQ_EVENT_MUTEX_STREAM_DONE8"; |
| + break; |
| + case CMDQ_EVENT_MUTEX_STREAM_DONE9: |
| + event_str = "CMDQ_EVENT_MUTEX_STREAM_DONE9"; |
| + break; |
| + case CMDQ_EVENT_MUTEX_STREAM_DONE10: |
| + event_str = "CMDQ_EVENT_MUTEX_STREAM_DONE10"; |
| + break; |
| + case CMDQ_EVENT_MUTEX_STREAM_DONE11: |
| + event_str = "CMDQ_EVENT_MUTEX_STREAM_DONE11"; |
| + break; |
| + case CMDQ_EVENT_DISP_RDMA0_BUF_UNDERRUN_EVEN: |
| + event_str = "CMDQ_EVENT_DISP_RDMA0_BUF_UNDERRUN_EVEN"; |
| + break; |
| + case CMDQ_EVENT_DISP_RDMA1_BUF_UNDERRUN_EVEN: |
| + event_str = "CMDQ_EVENT_DISP_RDMA1_BUF_UNDERRUN_EVEN"; |
| + break; |
| + case CMDQ_EVENT_DSI0_TE_EVENT: |
| + event_str = "CMDQ_EVENT_DSI0_TE_EVENT"; |
| + break; |
| + case CMDQ_EVENT_DSI0_IRQ_EVENT: |
| + event_str = "CMDQ_EVENT_DSI0_IRQ_EVENT"; |
| + break; |
| + case CMDQ_EVENT_DSI0_DONE_EVENT: |
| + event_str = "CMDQ_EVENT_DSI0_DONE_EVENT"; |
| + break; |
| + case CMDQ_EVENT_DISP_WDMA0_SW_RST_DONE: |
| + event_str = "CMDQ_EVENT_DISP_WDMA0_SW_RST_DONE"; |
| + break; |
| + case CMDQ_EVENT_MDP_WDMA_SW_RST_DONE: |
| + event_str = "CMDQ_EVENT_MDP_WDMA_SW_RST_DONE"; |
| + break; |
| + case CMDQ_EVENT_MDP_WROT0_SW_RST_DONE: |
| + event_str = "CMDQ_EVENT_MDP_WROT0_SW_RST_DONE"; |
| + break; |
| + case CMDQ_EVENT_MDP_RDMA0_SW_RST_DONE: |
| + event_str = "CMDQ_EVENT_MDP_RDMA0_SW_RST_DONE"; |
| + break; |
| + case CMDQ_EVENT_DISP_OVL0_FRAME_RST_DONE_PULE: |
| + event_str = "CMDQ_EVENT_DISP_OVL0_FRAME_RST_DONE_PULE"; |
| + break; |
| + case CMDQ_EVENT_DISP_OVL0_2L_FRAME_RST_DONE_ULSE: |
| + event_str = "CMDQ_EVENT_DISP_OVL0_2L_FRAME_RST_DONE_ULSE"; |
| + break; |
| + case CMDQ_EVENT_DISP_OVL1_2L_FRAME_RST_DONE_ULSE: |
| + event_str = "CMDQ_EVENT_DISP_OVL1_2L_FRAME_RST_DONE_ULSE"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_0: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_0"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_1: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_1"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_2: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_2"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_3: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_3"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_4: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_4"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_5: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_5"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_6: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_6"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_7: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_7"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_8: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_8"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_9: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_9"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_10: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_10"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_11: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_11"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_12: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_12"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_13: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_13"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_14: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_14"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_15: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_15"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_16: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_16"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_17: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_17"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_P2_18: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_P2_18"; |
| + break; |
| + case CMDQ_EVENT_AMD_FRAME_DONE: |
| + event_str = "CMDQ_EVENT_AMD_FRAME_DONE"; |
| + break; |
| + case CMDQ_EVENT_DVE_DONE: |
| + event_str = "CMDQ_EVENT_DVE_DONE"; |
| + break; |
| + case CMDQ_EVENT_WMFE_DONE: |
| + event_str = "CMDQ_EVENT_WMFE_DONE"; |
| + break; |
| + case CMDQ_EVENT_RSC_DONE: |
| + event_str = "CMDQ_EVENT_RSC_DONE"; |
| + break; |
| + case CMDQ_EVENT_MFB_DONE: |
| + event_str = "CMDQ_EVENT_MFB_DONE"; |
| + break; |
| + case CMDQ_EVENT_WPE_A_DONE: |
| + event_str = "CMDQ_EVENT_WPE_A_DONE"; |
| + break; |
| + case CMDQ_EVENT_SPE_B_DONE: |
| + event_str = "CMDQ_EVENT_SPE_B_DONE"; |
| + break; |
| + case CMDQ_EVENT_OCC_DONE: |
| + event_str = "CMDQ_EVENT_OCC_DONE"; |
| + break; |
| + case CMDQ_EVENT_VENC_CMDQ_FRAME_DONE: |
| + event_str = "CMDQ_EVENT_VENC_CMDQ_FRAME_DONE"; |
| + break; |
| + case CMDQ_EVENT_JPG_ENC_CMDQ_DONE: |
| + event_str = "CMDQ_EVENT_JPG_ENC_CMDQ_DONE"; |
| + break; |
| + case CMDQ_EVENT_JPG_DEC_CMDQ_DONE: |
| + event_str = "CMDQ_EVENT_JPG_DEC_CMDQ_DONE"; |
| + break; |
| + case CMDQ_EVENT_VENC_CMDQ_MB_DONE: |
| + event_str = "CMDQ_EVENT_VENC_CMDQ_MB_DONE"; |
| + break; |
| + case CMDQ_EVENT_VENC_CMDQ_128BYTE_DONE: |
| + event_str = "CMDQ_EVENT_VENC_CMDQ_128BYTE_DONE"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_A: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_A"; |
| + break; |
| + case CMDQ_EVENT_ISP_FRAME_DONE_B: |
| + event_str = "CMDQ_EVENT_ISP_FRAME_DONE_B"; |
| + break; |
| + case CMDQ_EVENT_CAMSV0_PASS1_DONE: |
| + event_str = "CMDQ_EVENT_CAMSV0_PASS1_DONE"; |
| + break; |
| + case CMDQ_EVENT_CAMSV1_PASS1_DONE: |
| + event_str = "CMDQ_EVENT_CAMSV1_PASS1_DONE"; |
| + break; |
| + case CMDQ_EVENT_CAMSV2_PASS1_DONE: |
| + event_str = "CMDQ_EVENT_CAMSV2_PASS1_DONE"; |
| + break; |
| + case CMDQ_EVENT_TSF_DONE: |
| + event_str = "CMDQ_EVENT_TSF_DONE"; |
| + break; |
| + case CMDQ_EVENT_SENINF_CAM0_FIFO_FULL: |
| + event_str = "CMDQ_EVENT_SENINF_CAM0_FIFO_FULL"; |
| + break; |
| + case CMDQ_EVENT_SENINF_CAM1_FIFO_FULL: |
| + event_str = "CMDQ_EVENT_SENINF_CAM1_FIFO_FULL"; |
| + break; |
| + case CMDQ_EVENT_SENINF_CAM2_FIFO_FULL: |
| + event_str = "CMDQ_EVENT_SENINF_CAM2_FIFO_FULL"; |
| + break; |
| + case CMDQ_EVENT_SENINF_CAM3_FIFO_FULL: |
| + event_str = "CMDQ_EVENT_SENINF_CAM3_FIFO_FULL"; |
| + break; |
| + case CMDQ_EVENT_SENINF_CAM4_FIFO_FULL: |
| + event_str = "CMDQ_EVENT_SENINF_CAM4_FIFO_FULL"; |
| + break; |
| + case CMDQ_EVENT_SENINF_CAM5_FIFO_FULL: |
| + event_str = "CMDQ_EVENT_SENINF_CAM5_FIFO_FULL"; |
| + break; |
| + case CMDQ_EVENT_SENINF_CAM6_FIFO_FULL: |
| + event_str = "CMDQ_EVENT_SENINF_CAM6_FIFO_FULL"; |
| + break; |
| + case CMDQ_EVENT_SENINF_CAM7_FIFO_FULL: |
| + event_str = "CMDQ_EVENT_SENINF_CAM7_FIFO_FULL"; |
| + break; |
| + case CMDQ_EVENT_IPU_CORE0_DONE0: |
| + event_str = "CMDQ_EVENT_IPU_CORE0_DONE0"; |
| + break; |
| + case CMDQ_EVENT_IPU_CORE0_DONE1: |
| + event_str = "CMDQ_EVENT_IPU_CORE0_DONE1"; |
| + break; |
| + case CMDQ_EVENT_IPU_CORE0_DONE2: |
| + event_str = "CMDQ_EVENT_IPU_CORE0_DONE2"; |
| + break; |
| + case CMDQ_EVENT_IPU_CORE0_DONE3: |
| + event_str = "CMDQ_EVENT_IPU_CORE0_DONE3"; |
| + break; |
| + case CMDQ_EVENT_IPU_CORE1_DONE0: |
| + event_str = "CMDQ_EVENT_IPU_CORE1_DONE0"; |
| + break; |
| + case CMDQ_EVENT_IPU_CORE1_DONE1: |
| + event_str = "CMDQ_EVENT_IPU_CORE1_DONE1"; |
| + break; |
| + case CMDQ_EVENT_IPU_CORE1_DONE2: |
| + event_str = "CMDQ_EVENT_IPU_CORE1_DONE2"; |
| + break; |
| + case CMDQ_EVENT_IPU_CORE1_DONE3: |
| + event_str = "CMDQ_EVENT_IPU_CORE1_DONE3"; |
| + break; |
| +#endif |
| + |
| + default: |
| + event_str = "UNKNOWN"; |
| + break; |
| + } |
| + |
| + dev_err(dev, "0x%08x %s event %u\n", offset, |
| + (cmd && CMDQ_WFE_OPTION) ? "wait for" : "clear", |
| + cmdq_inst->arg_a); |
| +} |
| + |
| +void cmdq_buf_print_mask(struct device *dev, u32 offset, |
| + struct cmdq_instruction *cmdq_inst) |
| +{ |
| + u32 mask = CMDQ_GET_32B_VALUE(cmdq_inst->arg_b, cmdq_inst->arg_c); |
| + |
| + dev_err(dev, "0x%08x mask 0x%08x\n", offset, ~mask); |
| +} |
| + |
| +void cmdq_buf_print_misc(struct device *dev, u32 offset, |
| + struct cmdq_instruction *cmdq_inst) |
| +{ |
| + char *cmd_str; |
| + |
| + switch (cmdq_inst->op) { |
| + case CMDQ_CODE_JUMP: |
| + cmd_str = "jump"; |
| + break; |
| + case CMDQ_CODE_EOC: |
| + cmd_str = "eoc"; |
| + break; |
| + case CMDQ_CODE_POLL: |
| + cmd_str = "polling"; |
| + break; |
| + default: |
| + cmd_str = "unknown"; |
| + break; |
| + } |
| + |
| + dev_err(dev, "0x%08x %s\n", offset, cmd_str); |
| +} |
| + |
| +void cmdq_debug_buf_dump_work(struct work_struct *work_item) |
| +{ |
| + struct cmdq_buf_dump *buf_dump = container_of(work_item, |
| + struct cmdq_buf_dump, dump_work); |
| + struct device *dev = buf_dump->dev; |
| + struct cmdq_instruction *cmdq_inst = |
| + (struct cmdq_instruction *)buf_dump->cmd_buf; |
| + u32 i, offset = 0; |
| + |
| + dev_err(dev, "dump %s task start ----------\n", |
| + buf_dump->timeout ? "timeout" : "error"); |
| + for (i = 0; i < CMDQ_NUM_CMD(buf_dump); i++) { |
| + if (offset == buf_dump->pa_offset) |
| + dev_err(dev, |
| + "\e[1;31;40m==========ERROR==========\e[0m\n"); |
| + switch (cmdq_inst[i].op) { |
| + case CMDQ_CODE_WRITE: |
| + cmdq_buf_print_write(dev, offset, &cmdq_inst[i]); |
| + break; |
| + case CMDQ_CODE_WFE: |
| + cmdq_buf_print_wfe(dev, offset, &cmdq_inst[i]); |
| + break; |
| + case CMDQ_CODE_MASK: |
| + cmdq_buf_print_mask(dev, offset, &cmdq_inst[i]); |
| + break; |
| + default: |
| + cmdq_buf_print_misc(dev, offset, &cmdq_inst[i]); |
| + break; |
| + } |
| + if (offset == buf_dump->pa_offset) |
| + dev_err(dev, |
| + "\e[1;31;40m==========ERROR==========\e[0m\n"); |
| + offset += CMDQ_INST_SIZE; |
| + } |
| + dev_err(dev, "dump %s task end ----------\n", |
| + buf_dump->timeout ? "timeout" : "error"); |
| + |
| + kfree(buf_dump->cmd_buf); |
| + kfree(buf_dump); |
| +} |
| +EXPORT_SYMBOL(cmdq_debug_buf_dump_work); |
| + |
| +MODULE_LICENSE("GPL v2"); |
| diff --git a/drivers/mailbox/mtk-cmdq-debug.h b/drivers/mailbox/mtk-cmdq-debug.h |
| new file mode 100644 |
| index 000000000000..5392b00c9394 |
| --- /dev/null |
| +++ b/drivers/mailbox/mtk-cmdq-debug.h |
| @@ -0,0 +1,21 @@ |
| +/* SPDX-License-Identifier: GPL-2.0 */ |
| +/* |
| + * Copyright (c) 2018 MediaTek Inc. |
| + * |
| + */ |
| + |
| +#ifndef MTK_CMDQ_DEBUG_H |
| +#define MTK_CMDQ_DEBUG_H |
| + |
| +struct cmdq_buf_dump { |
| + struct device *dev; /* device of cmdq controller */ |
| + struct work_struct dump_work; |
| + bool timeout; /* 0: error, 1: timeout */ |
| + void *cmd_buf; |
| + size_t cmd_buf_size; |
| + u32 pa_offset; /* pa_curr - pa_base */ |
| +}; |
| + |
| +void cmdq_debug_buf_dump_work(struct work_struct *work_item); |
| + |
| +#endif /* MTK_CMDQ_DEBUG_H */ |
| diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c |
| index aec46d5d3506..2c53ece47abd 100644 |
| --- a/drivers/mailbox/mtk-cmdq-mailbox.c |
| +++ b/drivers/mailbox/mtk-cmdq-mailbox.c |
| @@ -15,9 +15,11 @@ |
| #include <linux/mailbox_controller.h> |
| #include <linux/mailbox/mtk-cmdq-mailbox.h> |
| #include <linux/of_device.h> |
| +#ifdef CONFIG_MTK_CMDQ_DEBUG |
| +#include "mtk-cmdq-debug.h" |
| +#endif |
| |
| #define CMDQ_OP_CODE_MASK (0xff << CMDQ_OP_CODE_SHIFT) |
| -#define CMDQ_IRQ_MASK 0xffff |
| #define CMDQ_NUM_CMD(t) (t->cmd_buf_size / CMDQ_INST_SIZE) |
| |
| #define CMDQ_CURR_IRQ_STATUS 0x10 |
| @@ -34,6 +36,7 @@ |
| #define CMDQ_THR_END_ADDR 0x24 |
| #define CMDQ_THR_WAIT_TOKEN 0x30 |
| #define CMDQ_THR_PRIORITY 0x40 |
| +#define CMDQ_SYNC_TOKEN_UPDATE 0x68 |
| |
| #define CMDQ_THR_ACTIVE_SLOT_CYCLES 0x3200 |
| #define CMDQ_THR_ENABLED 0x1 |
| @@ -71,11 +74,38 @@ struct cmdq { |
| void __iomem *base; |
| u32 irq; |
| u32 thread_nr; |
| + u32 irq_mask; |
| struct cmdq_thread *thread; |
| struct clk *clock; |
| bool suspended; |
| +#ifdef CONFIG_MTK_CMDQ_DEBUG |
| + struct workqueue_struct *buf_dump_wq; |
| +#endif |
| }; |
| |
| +#ifdef CONFIG_MTK_CMDQ_DEBUG |
| +static void cmdq_buf_dump_schedule(struct cmdq_task *task, bool timeout, |
| + u32 pa_curr) |
| +{ |
| + struct device *dev = task->cmdq->mbox.dev; |
| + struct cmdq_buf_dump *buf_dump; |
| + |
| + buf_dump = kmalloc(sizeof(*buf_dump), GFP_ATOMIC); |
| + buf_dump->dev = dev; |
| + buf_dump->timeout = timeout; |
| + buf_dump->cmd_buf = kmalloc(task->pkt->cmd_buf_size, GFP_ATOMIC); |
| + buf_dump->cmd_buf_size = task->pkt->cmd_buf_size; |
| + buf_dump->pa_offset = pa_curr - task->pa_base; |
| + dma_sync_single_for_cpu(dev, task->pa_base, |
| + task->pkt->cmd_buf_size, DMA_TO_DEVICE); |
| + memcpy(buf_dump->cmd_buf, task->pkt->va_base, task->pkt->cmd_buf_size); |
| + dma_sync_single_for_device(dev, task->pa_base, |
| + task->pkt->cmd_buf_size, DMA_TO_DEVICE); |
| + INIT_WORK(&buf_dump->dump_work, cmdq_debug_buf_dump_work); |
| + queue_work(task->cmdq->buf_dump_wq, &buf_dump->dump_work); |
| +} |
| +#endif |
| + |
| static int cmdq_thread_suspend(struct cmdq *cmdq, struct cmdq_thread *thread) |
| { |
| u32 status; |
| @@ -103,8 +133,12 @@ static void cmdq_thread_resume(struct cmdq_thread *thread) |
| |
| static void cmdq_init(struct cmdq *cmdq) |
| { |
| + int i; |
| + |
| WARN_ON(clk_enable(cmdq->clock) < 0); |
| writel(CMDQ_THR_ACTIVE_SLOT_CYCLES, cmdq->base + CMDQ_THR_SLOT_CYCLES); |
| + for (i = 0; i <= CMDQ_MAX_EVENT; i++) |
| + writel(i, cmdq->base + CMDQ_SYNC_TOKEN_UPDATE); |
| clk_disable(cmdq->clock); |
| } |
| |
| @@ -211,12 +245,19 @@ static void cmdq_task_exec_done(struct cmdq_task *task, enum cmdq_cb_status sta) |
| list_del(&task->list_entry); |
| } |
| |
| +#ifdef CONFIG_MTK_CMDQ_DEBUG |
| +static void cmdq_task_handle_error(struct cmdq_task *task, u32 pa_curr) |
| +#else |
| static void cmdq_task_handle_error(struct cmdq_task *task) |
| +#endif |
| { |
| struct cmdq_thread *thread = task->thread; |
| struct cmdq_task *next_task; |
| |
| dev_err(task->cmdq->mbox.dev, "task 0x%p error\n", task); |
| +#ifdef CONFIG_MTK_CMDQ_DEBUG |
| + cmdq_buf_dump_schedule(task, false, pa_curr); |
| +#endif |
| WARN_ON(cmdq_thread_suspend(task->cmdq, thread) < 0); |
| next_task = list_first_entry_or_null(&thread->task_busy_list, |
| struct cmdq_task, list_entry); |
| @@ -264,7 +305,11 @@ static void cmdq_thread_irq_handler(struct cmdq *cmdq, |
| kfree(task); |
| } else if (err) { |
| cmdq_task_exec_done(task, CMDQ_CB_ERROR); |
| +#ifdef CONFIG_MTK_CMDQ_DEBUG |
| + cmdq_task_handle_error(curr_task, curr_pa); |
| +#else |
| cmdq_task_handle_error(curr_task); |
| +#endif |
| kfree(task); |
| } |
| |
| @@ -284,11 +329,11 @@ static irqreturn_t cmdq_irq_handler(int irq, void *dev) |
| unsigned long irq_status, flags = 0L; |
| int bit; |
| |
| - irq_status = readl(cmdq->base + CMDQ_CURR_IRQ_STATUS) & CMDQ_IRQ_MASK; |
| - if (!(irq_status ^ CMDQ_IRQ_MASK)) |
| + irq_status = readl(cmdq->base + CMDQ_CURR_IRQ_STATUS) & cmdq->irq_mask; |
| + if (!(irq_status ^ cmdq->irq_mask)) |
| return IRQ_NONE; |
| |
| - for_each_clear_bit(bit, &irq_status, fls(CMDQ_IRQ_MASK)) { |
| + for_each_clear_bit(bit, &irq_status, cmdq->thread_nr) { |
| struct cmdq_thread *thread = &cmdq->thread[bit]; |
| |
| spin_lock_irqsave(&thread->chan->lock, flags); |
| @@ -337,6 +382,9 @@ static int cmdq_remove(struct platform_device *pdev) |
| { |
| struct cmdq *cmdq = platform_get_drvdata(pdev); |
| |
| +#ifdef CONFIG_MTK_CMDQ_DEBUG |
| + destroy_workqueue(cmdq->buf_dump_wq); |
| +#endif |
| mbox_controller_unregister(&cmdq->mbox); |
| clk_unprepare(cmdq->clock); |
| |
| @@ -430,6 +478,36 @@ static int cmdq_mbox_startup(struct mbox_chan *chan) |
| |
| static void cmdq_mbox_shutdown(struct mbox_chan *chan) |
| { |
| +#ifdef CONFIG_MTK_CMDQ_DEBUG |
| + struct cmdq_thread *thread = (struct cmdq_thread *)chan->con_priv; |
| + struct cmdq *cmdq = dev_get_drvdata(chan->mbox->dev); |
| + struct cmdq_task *task, *tmp; |
| + unsigned long flags; |
| + bool first_task = true; |
| + |
| + spin_lock_irqsave(&thread->chan->lock, flags); |
| + |
| + if (list_empty(&thread->task_busy_list)) { |
| + spin_unlock_irqrestore(&thread->chan->lock, flags); |
| + return; |
| + } |
| + |
| + dev_err(cmdq->mbox.dev, "cmdq timeout\n"); |
| + list_for_each_entry_safe(task, tmp, &thread->task_busy_list, |
| + list_entry) { |
| + if (first_task) { |
| + cmdq_buf_dump_schedule(task, true, readl( |
| + thread->base + CMDQ_THR_CURR_ADDR)); |
| + first_task = false; |
| + } |
| + cmdq_task_exec_done(task, CMDQ_CB_ERROR); |
| + kfree(task); |
| + } |
| + |
| + cmdq_thread_disable(cmdq, thread); |
| + clk_disable(cmdq->clock); |
| + spin_unlock_irqrestore(&thread->chan->lock, flags); |
| +#endif |
| } |
| |
| static const struct mbox_chan_ops cmdq_mbox_chan_ops = { |
| @@ -478,6 +556,9 @@ static int cmdq_probe(struct platform_device *pdev) |
| dev_err(dev, "failed to get irq\n"); |
| return -EINVAL; |
| } |
| + |
| + cmdq->thread_nr = (u32)(unsigned long)of_device_get_match_data(dev); |
| + cmdq->irq_mask = GENMASK(cmdq->thread_nr - 1, 0); |
| err = devm_request_irq(dev, cmdq->irq, cmdq_irq_handler, IRQF_SHARED, |
| "mtk_cmdq", cmdq); |
| if (err < 0) { |
| @@ -494,7 +575,6 @@ static int cmdq_probe(struct platform_device *pdev) |
| return PTR_ERR(cmdq->clock); |
| } |
| |
| - cmdq->thread_nr = (u32)(unsigned long)of_device_get_match_data(dev); |
| cmdq->mbox.dev = dev; |
| cmdq->mbox.chans = devm_kcalloc(dev, cmdq->thread_nr, |
| sizeof(*cmdq->mbox.chans), GFP_KERNEL); |
| @@ -532,6 +612,14 @@ static int cmdq_probe(struct platform_device *pdev) |
| |
| cmdq_init(cmdq); |
| |
| +#ifdef CONFIG_MTK_CMDQ_DEBUG |
| + cmdq->buf_dump_wq = alloc_ordered_workqueue( |
| + "%s", WQ_MEM_RECLAIM | WQ_HIGHPRI, |
| + "cmdq_buf_dump"); |
| +#endif |
| + for (i = 0; i <= CMDQ_MAX_EVENT; i++) |
| + writel(i, cmdq->base + CMDQ_SYNC_TOKEN_UPDATE); |
| + |
| return 0; |
| } |
| |
| @@ -542,6 +630,7 @@ static const struct dev_pm_ops cmdq_pm_ops = { |
| |
| static const struct of_device_id cmdq_of_ids[] = { |
| {.compatible = "mediatek,mt8173-gce", .data = (void *)16}, |
| + {.compatible = "mediatek,mt8183-gce", .data = (void *)24}, |
| {} |
| }; |
| |
| diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c |
| index f761e4d8bf2a..2f375386e376 100644 |
| --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c |
| +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c |
| @@ -29,7 +29,6 @@ |
| #include <media/v4l2-ioctl.h> |
| #include <media/videobuf2-core.h> |
| #include <media/videobuf2-dma-contig.h> |
| -#include <soc/mediatek/smi.h> |
| |
| #include "mtk_jpeg_hw.h" |
| #include "mtk_jpeg_core.h" |
| @@ -901,11 +900,6 @@ static int mtk_jpeg_queue_init(void *priv, struct vb2_queue *src_vq, |
| |
| static void mtk_jpeg_clk_on(struct mtk_jpeg_dev *jpeg) |
| { |
| - int ret; |
| - |
| - ret = mtk_smi_larb_get(jpeg->larb); |
| - if (ret) |
| - dev_err(jpeg->dev, "mtk_smi_larb_get larbvdec fail %d\n", ret); |
| clk_prepare_enable(jpeg->clk_jdec_smi); |
| clk_prepare_enable(jpeg->clk_jdec); |
| } |
| @@ -914,7 +908,6 @@ static void mtk_jpeg_clk_off(struct mtk_jpeg_dev *jpeg) |
| { |
| clk_disable_unprepare(jpeg->clk_jdec); |
| clk_disable_unprepare(jpeg->clk_jdec_smi); |
| - mtk_smi_larb_put(jpeg->larb); |
| } |
| |
| static irqreturn_t mtk_jpeg_dec_irq(int irq, void *priv) |
| @@ -1059,21 +1052,6 @@ static const struct v4l2_file_operations mtk_jpeg_fops = { |
| |
| static int mtk_jpeg_clk_init(struct mtk_jpeg_dev *jpeg) |
| { |
| - struct device_node *node; |
| - struct platform_device *pdev; |
| - |
| - node = of_parse_phandle(jpeg->dev->of_node, "mediatek,larb", 0); |
| - if (!node) |
| - return -EINVAL; |
| - pdev = of_find_device_by_node(node); |
| - if (WARN_ON(!pdev)) { |
| - of_node_put(node); |
| - return -EINVAL; |
| - } |
| - of_node_put(node); |
| - |
| - jpeg->larb = &pdev->dev; |
| - |
| jpeg->clk_jdec = devm_clk_get(jpeg->dev, "jpgdec"); |
| if (IS_ERR(jpeg->clk_jdec)) |
| return PTR_ERR(jpeg->clk_jdec); |
| diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h |
| index 1a6cdfd4ea70..e35fb79b4c74 100644 |
| --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h |
| +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h |
| @@ -55,7 +55,6 @@ enum mtk_jpeg_ctx_state { |
| * @dec_reg_base: JPEG registers mapping |
| * @clk_jdec: JPEG hw working clock |
| * @clk_jdec_smi: JPEG SMI bus clock |
| - * @larb: SMI device |
| */ |
| struct mtk_jpeg_dev { |
| struct mutex lock; |
| @@ -69,7 +68,6 @@ struct mtk_jpeg_dev { |
| void __iomem *dec_reg_base; |
| struct clk *clk_jdec; |
| struct clk *clk_jdec_smi; |
| - struct device *larb; |
| }; |
| |
| /** |
| diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c |
| index 03aba03a24c8..4f7cbc4577de 100644 |
| --- a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c |
| +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c |
| @@ -17,7 +17,6 @@ |
| #include <linux/of.h> |
| #include <linux/of_address.h> |
| #include <linux/of_platform.h> |
| -#include <soc/mediatek/smi.h> |
| |
| #include "mtk_mdp_comp.h" |
| |
| @@ -66,14 +65,6 @@ void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp) |
| { |
| int i, err; |
| |
| - if (comp->larb_dev) { |
| - err = mtk_smi_larb_get(comp->larb_dev); |
| - if (err) |
| - dev_err(dev, |
| - "failed to get larb, err %d. type:%d id:%d\n", |
| - err, comp->type, comp->id); |
| - } |
| - |
| for (i = 0; i < ARRAY_SIZE(comp->clk); i++) { |
| if (IS_ERR(comp->clk[i])) |
| continue; |
| @@ -94,16 +85,11 @@ void mtk_mdp_comp_clock_off(struct device *dev, struct mtk_mdp_comp *comp) |
| continue; |
| clk_disable_unprepare(comp->clk[i]); |
| } |
| - |
| - if (comp->larb_dev) |
| - mtk_smi_larb_put(comp->larb_dev); |
| } |
| |
| int mtk_mdp_comp_init(struct device *dev, struct device_node *node, |
| struct mtk_mdp_comp *comp, enum mtk_mdp_comp_id comp_id) |
| { |
| - struct device_node *larb_node; |
| - struct platform_device *larb_pdev; |
| int i; |
| |
| if (comp_id < 0 || comp_id >= MTK_MDP_COMP_ID_MAX) { |
| @@ -124,30 +110,6 @@ int mtk_mdp_comp_init(struct device *dev, struct device_node *node, |
| break; |
| } |
| |
| - /* Only DMA capable components need the LARB property */ |
| - comp->larb_dev = NULL; |
| - if (comp->type != MTK_MDP_RDMA && |
| - comp->type != MTK_MDP_WDMA && |
| - comp->type != MTK_MDP_WROT) |
| - return 0; |
| - |
| - larb_node = of_parse_phandle(node, "mediatek,larb", 0); |
| - if (!larb_node) { |
| - dev_err(dev, |
| - "Missing mediadek,larb phandle in %pOF node\n", node); |
| - return -EINVAL; |
| - } |
| - |
| - larb_pdev = of_find_device_by_node(larb_node); |
| - if (!larb_pdev) { |
| - dev_warn(dev, "Waiting for larb device %pOF\n", larb_node); |
| - of_node_put(larb_node); |
| - return -EPROBE_DEFER; |
| - } |
| - of_node_put(larb_node); |
| - |
| - comp->larb_dev = &larb_pdev->dev; |
| - |
| return 0; |
| } |
| |
| diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h |
| index 63b3983ef1a4..602d577f5dc2 100644 |
| --- a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h |
| +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h |
| @@ -47,7 +47,6 @@ enum mtk_mdp_comp_id { |
| * @dev_node: component device node |
| * @clk: clocks required for component |
| * @regs: Mapped address of component registers. |
| - * @larb_dev: SMI device required for component |
| * @type: component type |
| * @id: component ID |
| */ |
| @@ -55,7 +54,6 @@ struct mtk_mdp_comp { |
| struct device_node *dev_node; |
| struct clk *clk[2]; |
| void __iomem *regs; |
| - struct device *larb_dev; |
| enum mtk_mdp_comp_type type; |
| enum mtk_mdp_comp_id id; |
| }; |
| diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c |
| index bbb24fb95b95..adb098d761a7 100644 |
| --- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c |
| +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c |
| @@ -25,7 +25,6 @@ |
| #include <linux/platform_device.h> |
| #include <linux/pm_runtime.h> |
| #include <linux/workqueue.h> |
| -#include <soc/mediatek/smi.h> |
| |
| #include "mtk_mdp_core.h" |
| #include "mtk_mdp_m2m.h" |
| diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c |
| index 7884465afcd2..f5177901ba6e 100644 |
| --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c |
| +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c |
| @@ -16,7 +16,6 @@ |
| #include <linux/of_address.h> |
| #include <linux/of_platform.h> |
| #include <linux/pm_runtime.h> |
| -#include <soc/mediatek/smi.h> |
| |
| #include "mtk_vcodec_dec_pm.h" |
| #include "mtk_vcodec_util.h" |
| @@ -24,7 +23,6 @@ |
| |
| int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev) |
| { |
| - struct device_node *node; |
| struct platform_device *pdev; |
| struct mtk_vcodec_pm *pm; |
| struct mtk_vcodec_clk *dec_clk; |
| @@ -35,18 +33,7 @@ int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev) |
| pm = &mtkdev->pm; |
| pm->mtkdev = mtkdev; |
| dec_clk = &pm->vdec_clk; |
| - node = of_parse_phandle(pdev->dev.of_node, "mediatek,larb", 0); |
| - if (!node) { |
| - mtk_v4l2_err("of_parse_phandle mediatek,larb fail!"); |
| - return -1; |
| - } |
| |
| - pdev = of_find_device_by_node(node); |
| - if (WARN_ON(!pdev)) { |
| - of_node_put(node); |
| - return -1; |
| - } |
| - pm->larbvdec = &pdev->dev; |
| pdev = mtkdev->plat_dev; |
| pm->dev = &pdev->dev; |
| |
| @@ -122,11 +109,6 @@ void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm) |
| } |
| } |
| |
| - ret = mtk_smi_larb_get(pm->larbvdec); |
| - if (ret) { |
| - mtk_v4l2_err("mtk_smi_larb_get larbvdec fail %d", ret); |
| - goto error; |
| - } |
| return; |
| |
| error: |
| @@ -139,7 +121,6 @@ void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm) |
| struct mtk_vcodec_clk *dec_clk = &pm->vdec_clk; |
| int i = 0; |
| |
| - mtk_smi_larb_put(pm->larbvdec); |
| for (i = dec_clk->clk_num - 1; i >= 0; i--) |
| clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); |
| } |
| diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h |
| index 662a84b822af..cf56b07c4828 100644 |
| --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h |
| +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h |
| @@ -196,11 +196,8 @@ struct mtk_vcodec_clk { |
| */ |
| struct mtk_vcodec_pm { |
| struct mtk_vcodec_clk vdec_clk; |
| - struct device *larbvdec; |
| |
| struct mtk_vcodec_clk venc_clk; |
| - struct device *larbvenc; |
| - struct device *larbvenclt; |
| struct device *dev; |
| struct mtk_vcodec_dev *mtkdev; |
| }; |
| diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c |
| index 50351adafc47..80d1c4ef8247 100644 |
| --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c |
| +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c |
| @@ -16,7 +16,6 @@ |
| #include <media/v4l2-event.h> |
| #include <media/v4l2-mem2mem.h> |
| #include <media/videobuf2-dma-contig.h> |
| -#include <soc/mediatek/smi.h> |
| |
| #include "mtk_vcodec_drv.h" |
| #include "mtk_vcodec_enc.h" |
| diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c |
| index 39375b8ea27c..c3a1871d4739 100644 |
| --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c |
| +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c |
| @@ -16,7 +16,6 @@ |
| #include <linux/of_address.h> |
| #include <linux/of_platform.h> |
| #include <linux/pm_runtime.h> |
| -#include <soc/mediatek/smi.h> |
| |
| #include "mtk_vcodec_enc_pm.h" |
| #include "mtk_vcodec_util.h" |
| @@ -25,7 +24,6 @@ |
| |
| int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev) |
| { |
| - struct device_node *node; |
| struct platform_device *pdev; |
| struct mtk_vcodec_pm *pm; |
| struct mtk_vcodec_clk *enc_clk; |
| @@ -41,33 +39,6 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev) |
| dev = &pdev->dev; |
| enc_clk = &pm->venc_clk; |
| |
| - node = of_parse_phandle(dev->of_node, "mediatek,larb", 0); |
| - if (!node) { |
| - mtk_v4l2_err("no mediatek,larb found"); |
| - return -ENODEV; |
| - } |
| - pdev = of_find_device_by_node(node); |
| - of_node_put(node); |
| - if (!pdev) { |
| - mtk_v4l2_err("no mediatek,larb device found"); |
| - return -ENODEV; |
| - } |
| - pm->larbvenc = &pdev->dev; |
| - |
| - node = of_parse_phandle(dev->of_node, "mediatek,larb", 1); |
| - if (!node) { |
| - mtk_v4l2_err("no mediatek,larb found"); |
| - return -ENODEV; |
| - } |
| - |
| - pdev = of_find_device_by_node(node); |
| - of_node_put(node); |
| - if (!pdev) { |
| - mtk_v4l2_err("no mediatek,larb device found"); |
| - return -ENODEV; |
| - } |
| - |
| - pm->larbvenclt = &pdev->dev; |
| pdev = mtkdev->plat_dev; |
| pm->dev = &pdev->dev; |
| |
| @@ -123,21 +94,8 @@ void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm) |
| } |
| } |
| |
| - ret = mtk_smi_larb_get(pm->larbvenc); |
| - if (ret) { |
| - mtk_v4l2_err("mtk_smi_larb_get larb3 fail %d", ret); |
| - goto larbvencerr; |
| - } |
| - ret = mtk_smi_larb_get(pm->larbvenclt); |
| - if (ret) { |
| - mtk_v4l2_err("mtk_smi_larb_get larb4 fail %d", ret); |
| - goto larbvenclterr; |
| - } |
| return; |
| |
| -larbvenclterr: |
| - mtk_smi_larb_put(pm->larbvenc); |
| -larbvencerr: |
| clkerr: |
| for (i -= 1; i >= 0; i--) |
| clk_disable_unprepare(enc_clk->clk_info[i].vcodec_clk); |
| @@ -148,8 +106,6 @@ void mtk_vcodec_enc_clock_off(struct mtk_vcodec_pm *pm) |
| struct mtk_vcodec_clk *enc_clk = &pm->venc_clk; |
| int i = 0; |
| |
| - mtk_smi_larb_put(pm->larbvenc); |
| - mtk_smi_larb_put(pm->larbvenclt); |
| for (i = enc_clk->clk_num - 1; i >= 0; i--) |
| clk_disable_unprepare(enc_clk->clk_info[i].vcodec_clk); |
| } |
| diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c |
| index f8d35e3ac1dc..01cab05e7b81 100644 |
| --- a/drivers/media/platform/mtk-vpu/mtk_vpu.c |
| +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c |
| @@ -49,25 +49,63 @@ |
| #define VPU_P_FW_SIZE (VPU_PTCM_SIZE + VPU_EXT_P_SIZE) |
| #define VPU_D_FW_SIZE (VPU_DTCM_SIZE + VPU_EXT_D_SIZE) |
| /* the size of share buffer between Host and VPU */ |
| -#define SHARE_BUF_SIZE 48 |
| |
| /* binary firmware name */ |
| #define VPU_P_FW "vpu_p.bin" |
| #define VPU_D_FW "vpu_d.bin" |
| |
| -#define VPU_RESET 0x0 |
| -#define VPU_TCM_CFG 0x0008 |
| -#define VPU_PMEM_EXT0_ADDR 0x000C |
| -#define VPU_PMEM_EXT1_ADDR 0x0010 |
| -#define VPU_TO_HOST 0x001C |
| -#define VPU_DMEM_EXT0_ADDR 0x0014 |
| -#define VPU_DMEM_EXT1_ADDR 0x0018 |
| -#define HOST_TO_VPU 0x0024 |
| -#define VPU_PC_REG 0x0060 |
| -#define VPU_WDT_REG 0x0084 |
| +enum vpu_regs_idx { |
| + VPU_RESET, |
| + VPU_TCM_CFG, |
| + VPU_TO_HOST, |
| + HOST_TO_VPU, |
| + VPU_PC_REG, |
| + VPU_WDT_REG, |
| + |
| + /* MT8173 only regs */ |
| + VPU_PMEM_EXT0_ADDR, |
| + VPU_PMEM_EXT1_ADDR, |
| + VPU_DMEM_EXT0_ADDR, |
| + VPU_DMEM_EXT1_ADDR, |
| +}; |
| + |
| +enum vpu_type { |
| + VPU_MT8173, |
| + VPU_MT8183, |
| +}; |
| |
| -/* vpu inter-processor communication interrupt */ |
| -#define VPU_IPC_INT BIT(8) |
| +/** |
| + * struct hw_type - VPU hardware type |
| + * |
| + * @regs: the register index for VPU configuration |
| + * @dtcm_offset: the offset to get data tcm address |
| + * @share_obj_sz: share object size, including id, len, share_buf |
| + * @ptcm_sz: maximum program TCM (Tightly-Coupled Memory) size |
| + * @dtcm_sz: maximum data TCM (Tightly-Coupled Memory) size |
| + * @ext_p_sz: daynamic allocated maximum extended program memory size |
| + * @ext_d_sz: daynamic allocated maximum extended data memory size |
| + * @type: the soc where VPU embedded |
| + * @ext_mem_support: extended memory support |
| + * @fw_p: program firmware name |
| + * @fw_d: data firmware name |
| + * @ipc_int: inter-processor communication interrupt bit |
| + * @wdt_int: vpu watch dog timer interrupt bit |
| + */ |
| +struct hw_type { |
| + int *regs; |
| + unsigned long dtcm_offset; |
| + size_t share_obj_sz; |
| + size_t ptcm_sz; |
| + size_t dtcm_sz; |
| + size_t ext_p_sz; |
| + size_t ext_d_sz; |
| + u32 type; |
| + bool ext_mem_support; |
| + char *fw_p; |
| + char *fw_d; |
| + u32 ipc_int; |
| + u32 wdt_int; |
| +}; |
| |
| /** |
| * enum vpu_fw_type - VPU firmware type |
| @@ -173,7 +211,8 @@ struct vpu_ipi_desc { |
| struct share_obj { |
| s32 id; |
| u32 len; |
| - unsigned char share_buf[SHARE_BUF_SIZE]; |
| + /* "share_buf" must be in the last member of this data structure */ |
| + unsigned char *share_buf; |
| }; |
| |
| /** |
| @@ -188,6 +227,7 @@ struct share_obj { |
| * @send_buf: VPU DTCM share buffer for sending |
| * @dev: VPU struct device |
| * @clk: VPU clock on/off |
| + * @hw: the different VPU hardware embedded into mtk SoCs |
| * @fw_loaded: indicate VPU firmware loaded |
| * @enable_4GB: VPU 4GB mode on/off |
| * @vpu_mutex: protect mtk_vpu (except recv_buf) and ensure only |
| @@ -195,7 +235,7 @@ struct share_obj { |
| * suppose a client is using VPU to decode VP8. |
| * If the other client wants to encode VP8, |
| * it has to wait until VP8 decode completes. |
| - * @wdt_refcnt: WDT reference count to make sure the watchdog can be |
| + * @wdt_refcnt: WDT reference count to make sure the watchdog can be |
| * disabled if no other client is using VPU service |
| * @ack_wq: The wait queue for each codec and mdp. When sleeping |
| * processes wake up, they will check the condition |
| @@ -215,6 +255,7 @@ struct mtk_vpu { |
| struct share_obj *send_buf; |
| struct device *dev; |
| struct clk *clk; |
| + const struct hw_type *hw; |
| bool fw_loaded; |
| bool enable_4GB; |
| struct mutex vpu_mutex; /* for protecting vpu data data structure */ |
| @@ -223,14 +264,64 @@ struct mtk_vpu { |
| bool ipi_id_ack[IPI_MAX]; |
| }; |
| |
| +static int mt8173_regs[] = { |
| + [VPU_RESET] = 0x0, |
| + [VPU_TCM_CFG] = 0x8, |
| + [VPU_TO_HOST] = 0x1C, |
| + [HOST_TO_VPU] = 0x24, |
| + [VPU_PC_REG] = 0x60, |
| + [VPU_WDT_REG] = 0x84, |
| + [VPU_PMEM_EXT0_ADDR] = 0x0C, |
| + [VPU_PMEM_EXT1_ADDR] = 0x10, |
| + [VPU_DMEM_EXT0_ADDR] = 0x14, |
| + [VPU_DMEM_EXT1_ADDR] = 0x18, |
| +}; |
| + |
| +static int mt8183_regs[] = { |
| + [VPU_RESET] = 0x0, |
| + [VPU_TO_HOST] = 0x1C, |
| + [HOST_TO_VPU] = 0x28, |
| + [VPU_PC_REG] = 0xB4, |
| + [VPU_WDT_REG] = 0x1C, |
| +}; |
| + |
| +static const struct hw_type vpu_mt8173 = { |
| + .regs = mt8173_regs, |
| + .dtcm_offset = 0x18000, |
| + .share_obj_sz = (8+48), |
| + .ptcm_sz = (96 * SZ_1K), |
| + .dtcm_sz = (32 * SZ_1K), |
| + .ext_p_sz = SZ_1M, |
| + .ext_d_sz = SZ_4M, |
| + .type = VPU_MT8173, |
| + .ext_mem_support = true, |
| + .fw_p = "vpu_p.bin", |
| + .fw_d = "vpu_d.bin", |
| + .ipc_int = BIT(8), |
| +}; |
| + |
| +static const struct hw_type vpu_mt8183 = { |
| + .regs = mt8183_regs, |
| + .dtcm_offset = 0, |
| + .share_obj_sz = (8+288), |
| + .ptcm_sz = (512 * SZ_1K), |
| + .dtcm_sz = (512 * SZ_1K), |
| + .ext_p_sz = 0, |
| + .ext_d_sz = 0, |
| + .type = VPU_MT8183, |
| + .ext_mem_support = false, |
| + .ipc_int = BIT(0), |
| + .wdt_int = BIT(8), |
| +}; |
| + |
| static inline void vpu_cfg_writel(struct mtk_vpu *vpu, u32 val, u32 offset) |
| { |
| - writel(val, vpu->reg.cfg + offset); |
| + writel(val, vpu->reg.cfg + vpu->hw->regs[offset]); |
| } |
| |
| static inline u32 vpu_cfg_readl(struct mtk_vpu *vpu, u32 offset) |
| { |
| - return readl(vpu->reg.cfg + offset); |
| + return readl(vpu->reg.cfg + vpu->hw->regs[offset]); |
| } |
| |
| static inline bool vpu_running(struct mtk_vpu *vpu) |
| @@ -295,9 +386,10 @@ int vpu_ipi_register(struct platform_device *pdev, |
| } |
| EXPORT_SYMBOL_GPL(vpu_ipi_register); |
| |
| -int vpu_ipi_send(struct platform_device *pdev, |
| +int vpu_ipi_send_sync_async(struct platform_device *pdev, |
| enum ipi_id id, void *buf, |
| - unsigned int len) |
| + unsigned int len, |
| + unsigned int wait) |
| { |
| struct mtk_vpu *vpu = platform_get_drvdata(pdev); |
| struct share_obj *send_obj = vpu->send_buf; |
| @@ -305,7 +397,7 @@ int vpu_ipi_send(struct platform_device *pdev, |
| int ret = 0; |
| |
| if (id <= IPI_VPU_INIT || id >= IPI_MAX || |
| - len > sizeof(send_obj->share_buf) || !buf) { |
| + len > (vpu->hw->share_obj_sz - 8) || !buf) { |
| dev_err(vpu->dev, "failed to send ipi message\n"); |
| return -EINVAL; |
| } |
| @@ -333,24 +425,27 @@ int vpu_ipi_send(struct platform_device *pdev, |
| } |
| } while (vpu_cfg_readl(vpu, HOST_TO_VPU)); |
| |
| - memcpy((void *)send_obj->share_buf, buf, len); |
| + memcpy((void *)&send_obj->share_buf, buf, len); |
| send_obj->len = len; |
| send_obj->id = id; |
| |
| vpu->ipi_id_ack[id] = false; |
| + mb(); |
| /* send the command to VPU */ |
| vpu_cfg_writel(vpu, 0x1, HOST_TO_VPU); |
| |
| mutex_unlock(&vpu->vpu_mutex); |
| |
| - /* wait for VPU's ACK */ |
| - timeout = msecs_to_jiffies(IPI_TIMEOUT_MS); |
| - ret = wait_event_timeout(vpu->ack_wq, vpu->ipi_id_ack[id], timeout); |
| - vpu->ipi_id_ack[id] = false; |
| - if (ret == 0) { |
| - dev_err(vpu->dev, "vpu ipi %d ack time out !", id); |
| - ret = -EIO; |
| - goto clock_disable; |
| + if (wait) { |
| + /* wait for VPU's ACK */ |
| + timeout = msecs_to_jiffies(IPI_TIMEOUT_MS); |
| + ret = wait_event_timeout(vpu->ack_wq, vpu->ipi_id_ack[id], timeout); |
| + vpu->ipi_id_ack[id] = false; |
| + if (ret == 0) { |
| + dev_err(vpu->dev, "vpu ipi %d ack time out !", id); |
| + ret = -EIO; |
| + goto clock_disable; |
| + } |
| } |
| vpu_clock_disable(vpu); |
| |
| @@ -363,6 +458,15 @@ int vpu_ipi_send(struct platform_device *pdev, |
| |
| return ret; |
| } |
| +EXPORT_SYMBOL_GPL(vpu_ipi_send_sync_async); |
| + |
| +int vpu_ipi_send(struct platform_device *pdev, |
| + enum ipi_id id, void *buf, |
| + unsigned int len) |
| +{ |
| + return vpu_ipi_send_sync_async(pdev, id, buf, len, 1); |
| + |
| +} |
| EXPORT_SYMBOL_GPL(vpu_ipi_send); |
| |
| static void vpu_wdt_reset_func(struct work_struct *ws) |
| @@ -442,16 +546,16 @@ void *vpu_mapping_dm_addr(struct platform_device *pdev, |
| struct mtk_vpu *vpu = platform_get_drvdata(pdev); |
| |
| if (!dtcm_dmem_addr || |
| - (dtcm_dmem_addr > (VPU_DTCM_SIZE + VPU_EXT_D_SIZE))) { |
| + (dtcm_dmem_addr > (vpu->hw->dtcm_sz + vpu->hw->ext_d_sz))) { |
| dev_err(vpu->dev, "invalid virtual data memory address\n"); |
| return ERR_PTR(-EINVAL); |
| } |
| |
| - if (dtcm_dmem_addr < VPU_DTCM_SIZE) |
| + if (dtcm_dmem_addr < vpu->hw->dtcm_sz) |
| return (__force void *)(dtcm_dmem_addr + vpu->reg.tcm + |
| - VPU_DTCM_OFFSET); |
| + vpu->hw->dtcm_offset); |
| |
| - return vpu->extmem[D_FW].va + (dtcm_dmem_addr - VPU_DTCM_SIZE); |
| + return vpu->extmem[D_FW].va + (dtcm_dmem_addr - vpu->hw->dtcm_sz); |
| } |
| EXPORT_SYMBOL_GPL(vpu_mapping_dm_addr); |
| |
| @@ -478,14 +582,138 @@ struct platform_device *vpu_get_plat_device(struct platform_device *pdev) |
| } |
| EXPORT_SYMBOL_GPL(vpu_get_plat_device); |
| |
| +#if VPU_RESERVED_MEM |
| +phys_addr_t vpu_mem_base_phys; |
| +phys_addr_t vpu_mem_base_virt; |
| +phys_addr_t vpu_mem_size; |
| + |
| +#ifdef CONFIG_OF_RESERVED_MEM |
| +#define VPU_MEM_RESERVED_KEY "mediatek,reserve-memory-vpu_share" |
| + |
| +static struct vpu_reserve_mblock vpu_reserve_mblock[] = { |
| + { |
| + .num = ISP_MEM_ID, |
| + .start_phys = 0x0, |
| + .start_virt = 0x0, |
| + .size = 0x1400000, /*20MB*/ |
| + }, |
| +}; |
| + |
| +int vpu_reserve_mem_of_init(struct reserved_mem *rmem) |
| +{ |
| + enum vpu_reserve_mem_id_t id; |
| + phys_addr_t accumlate_memory_size = 0; |
| + |
| + vpu_mem_base_phys = (phys_addr_t) rmem->base; |
| + vpu_mem_size = (phys_addr_t) rmem->size; |
| + if ((vpu_mem_base_phys >= (0x90000000ULL)) || (vpu_mem_base_phys <= 0x0)) { |
| + /*The vpu remap region is fixed, only |
| + * 0x4000_0000ULL~0x9FFF_FFFFULL |
| + * can be accessible |
| + */ |
| + pr_err("[VPU] The allocated memory(0x%llx) is larger than expected\n", vpu_mem_base_phys); |
| + /*should not call WARN_ON() here or there is no log, return -1 |
| + * instead. |
| + */ |
| + return -1; |
| + } |
| + |
| + pr_debug("[VPU] phys:0x%llx - 0x%llx (0x%llx)\n", (phys_addr_t)rmem->base, |
| + (phys_addr_t)rmem->base + (phys_addr_t)rmem->size, (phys_addr_t)rmem->size); |
| + accumlate_memory_size = 0; |
| + for (id = 0; id < NUMS_MEM_ID; id++) { |
| + vpu_reserve_mblock[id].start_phys = vpu_mem_base_phys + accumlate_memory_size; |
| + accumlate_memory_size += vpu_reserve_mblock[id].size; |
| + pr_debug("[VPU][reserve_mem:%d]: phys:0x%llx - 0x%llx (0x%llx)\n", id, |
| + vpu_reserve_mblock[id].start_phys, |
| + vpu_reserve_mblock[id].start_phys+vpu_reserve_mblock[id].size, |
| + vpu_reserve_mblock[id].size); |
| + } |
| + return 0; |
| +} |
| + |
| +RESERVEDMEM_OF_DECLARE(vpu_reserve_mem_init, VPU_MEM_RESERVED_KEY, vpu_reserve_mem_of_init); |
| +#endif |
| + |
| +static int vpu_reserve_memory_ioremap(void) |
| +{ |
| + enum vpu_reserve_mem_id_t id; |
| + phys_addr_t accumlate_memory_size; |
| + |
| + |
| + if ((vpu_mem_base_phys >= (0x90000000ULL)) || (vpu_mem_base_phys <= 0x0)) { |
| + /*The vpu remap region is fixed, only |
| + * 0x4000_0000ULL~0x8FFF_FFFFULL |
| + * can be accessible |
| + */ |
| + pr_err("[VPU] The allocated memory(0x%llx) is larger than expected\n", vpu_mem_base_phys); |
| + /*call WARN_ON() here to assert the unexpected memory allocation |
| + */ |
| + WARN_ON(1); |
| + return -1; |
| + } |
| + accumlate_memory_size = 0; |
| + vpu_mem_base_virt = (phys_addr_t)(size_t)ioremap_wc(vpu_mem_base_phys, vpu_mem_size); |
| + pr_debug("[VPU]reserve mem: virt:0x%llx - 0x%llx (0x%llx)\n", (phys_addr_t)vpu_mem_base_virt, |
| + (phys_addr_t)vpu_mem_base_virt + (phys_addr_t)vpu_mem_size, vpu_mem_size); |
| + for (id = 0; id < NUMS_MEM_ID; id++) { |
| + vpu_reserve_mblock[id].start_virt = vpu_mem_base_virt + accumlate_memory_size; |
| + accumlate_memory_size += vpu_reserve_mblock[id].size; |
| + } |
| + /* the reserved memory should be larger then expected memory |
| + * or vpu_reserve_mblock does not match dts |
| + */ |
| + WARN_ON(accumlate_memory_size > vpu_mem_size); |
| +#ifdef DEBUG |
| + for (id = 0; id < NUMS_MEM_ID; id++) { |
| + pr_info("[VPU][mem_reserve-%d] phys:0x%llx,virt:0x%llx,size:0x%llx\n", |
| + id, vpu_get_reserve_mem_phys(id), vpu_get_reserve_mem_virt(id), vpu_get_reserve_mem_size(id)); |
| + } |
| +#endif |
| + return 0; |
| +} |
| + |
| +phys_addr_t vpu_get_reserve_mem_phys(enum vpu_reserve_mem_id_t id) |
| +{ |
| + if (id >= NUMS_MEM_ID) { |
| + pr_err("[VPU] no reserve memory for %d", id); |
| + return 0; |
| + } else |
| + return vpu_reserve_mblock[id].start_phys; |
| +} |
| +EXPORT_SYMBOL_GPL(vpu_get_reserve_mem_phys); |
| + |
| +phys_addr_t vpu_get_reserve_mem_virt(enum vpu_reserve_mem_id_t id) |
| +{ |
| + if (id >= NUMS_MEM_ID) { |
| + pr_err("[VPU] no reserve memory for %d", id); |
| + return 0; |
| + } else |
| + return vpu_reserve_mblock[id].start_virt; |
| +} |
| +EXPORT_SYMBOL_GPL(vpu_get_reserve_mem_virt); |
| + |
| +phys_addr_t vpu_get_reserve_mem_size(enum vpu_reserve_mem_id_t id) |
| +{ |
| + if (id >= NUMS_MEM_ID) { |
| + pr_err("[VPU] no reserve memory for %d", id); |
| + return 0; |
| + } else |
| + return vpu_reserve_mblock[id].size; |
| +} |
| +EXPORT_SYMBOL_GPL(vpu_get_reserve_mem_size); |
| +#endif |
| + |
| /* load vpu program/data memory */ |
| static int load_requested_vpu(struct mtk_vpu *vpu, |
| const struct firmware *vpu_fw, |
| u8 fw_type) |
| { |
| - size_t tcm_size = fw_type ? VPU_DTCM_SIZE : VPU_PTCM_SIZE; |
| - size_t fw_size = fw_type ? VPU_D_FW_SIZE : VPU_P_FW_SIZE; |
| - char *fw_name = fw_type ? VPU_D_FW : VPU_P_FW; |
| + size_t tcm_size = fw_type ? vpu->hw->dtcm_sz : vpu->hw->ptcm_sz; |
| + size_t fw_size = fw_type |
| + ? vpu->hw->dtcm_sz + vpu->hw->ext_d_sz |
| + : vpu->hw->ptcm_sz + vpu->hw->ext_p_sz; |
| + char *fw_name = fw_type ? vpu->hw->fw_d : vpu->hw->fw_p; |
| size_t dl_size = 0; |
| size_t extra_fw_size = 0; |
| void *dest; |
| @@ -519,7 +747,7 @@ static int load_requested_vpu(struct mtk_vpu *vpu, |
| } |
| dest = (__force void *)vpu->reg.tcm; |
| if (fw_type == D_FW) |
| - dest += VPU_DTCM_OFFSET; |
| + dest += vpu->hw->dtcm_offset; |
| memcpy(dest, vpu_fw->data, dl_size); |
| /* download to extended memory if need */ |
| if (extra_fw_size > 0) { |
| @@ -567,21 +795,33 @@ int vpu_load_firmware(struct platform_device *pdev) |
| |
| run->signaled = false; |
| dev_dbg(vpu->dev, "firmware request\n"); |
| - /* Downloading program firmware to device*/ |
| - ret = load_requested_vpu(vpu, vpu_fw, P_FW); |
| - if (ret < 0) { |
| - dev_err(dev, "Failed to request %s, %d\n", VPU_P_FW, ret); |
| - goto OUT_LOAD_FW; |
| + if (vpu->hw->type == VPU_MT8173) { |
| + /* Downloading program firmware to device*/ |
| + ret = load_requested_vpu(vpu, vpu_fw, P_FW); |
| + if (ret < 0) { |
| + dev_err(dev, "Failed to request %s, %d\n", |
| + vpu->hw->fw_p, ret); |
| + goto OUT_LOAD_FW; |
| + } |
| + |
| + /* Downloading data firmware to device */ |
| + ret = load_requested_vpu(vpu, vpu_fw, D_FW); |
| + if (ret < 0) { |
| + dev_err(dev, "Failed to request %s, %d\n", |
| + vpu->hw->fw_d, ret); |
| + goto OUT_LOAD_FW; |
| + } |
| } |
| + vpu->fw_loaded = true; |
| |
| - /* Downloading data firmware to device */ |
| - ret = load_requested_vpu(vpu, vpu_fw, D_FW); |
| - if (ret < 0) { |
| - dev_err(dev, "Failed to request %s, %d\n", VPU_D_FW, ret); |
| +#if VPU_RESERVED_MEM |
| + ret = vpu_reserve_memory_ioremap(); |
| + if (ret) { |
| + dev_err(dev, "vpu_reserve_memory_ioremap failed\n"); |
| goto OUT_LOAD_FW; |
| } |
| +#endif |
| |
| - vpu->fw_loaded = true; |
| /* boot up vpu */ |
| vpu_cfg_writel(vpu, 0x1, VPU_RESET); |
| |
| @@ -631,12 +871,14 @@ static ssize_t vpu_debug_read(struct file *file, char __user *user_buf, |
| int ret; |
| struct device *dev = file->private_data; |
| struct mtk_vpu *vpu = dev_get_drvdata(dev); |
| + struct platform_device *pdev = to_platform_device(dev); |
| |
| ret = vpu_clock_enable(vpu); |
| if (ret) { |
| dev_err(vpu->dev, "[VPU] enable clock failed %d\n", ret); |
| return 0; |
| } |
| + vpu_load_firmware(pdev); |
| |
| /* vpu register status */ |
| running = vpu_running(vpu); |
| @@ -671,7 +913,10 @@ static const struct file_operations vpu_debug_fops = { |
| static void vpu_free_ext_mem(struct mtk_vpu *vpu, u8 fw_type) |
| { |
| struct device *dev = vpu->dev; |
| - size_t fw_ext_size = fw_type ? VPU_EXT_D_SIZE : VPU_EXT_P_SIZE; |
| + size_t fw_ext_size = fw_type ? vpu->hw->ext_d_sz : vpu->hw->ext_p_sz; |
| + |
| + if (!vpu->hw->ext_mem_support) |
| + return; |
| |
| dma_free_coherent(dev, fw_ext_size, vpu->extmem[fw_type].va, |
| vpu->extmem[fw_type].pa); |
| @@ -680,11 +925,14 @@ static void vpu_free_ext_mem(struct mtk_vpu *vpu, u8 fw_type) |
| static int vpu_alloc_ext_mem(struct mtk_vpu *vpu, u32 fw_type) |
| { |
| struct device *dev = vpu->dev; |
| - size_t fw_ext_size = fw_type ? VPU_EXT_D_SIZE : VPU_EXT_P_SIZE; |
| + size_t fw_ext_size = fw_type ? vpu->hw->ext_d_sz : vpu->hw->ext_p_sz; |
| u32 vpu_ext_mem0 = fw_type ? VPU_DMEM_EXT0_ADDR : VPU_PMEM_EXT0_ADDR; |
| u32 vpu_ext_mem1 = fw_type ? VPU_DMEM_EXT1_ADDR : VPU_PMEM_EXT1_ADDR; |
| u32 offset_4gb = vpu->enable_4GB ? 0x40000000 : 0; |
| |
| + if (!vpu->hw->ext_mem_support) |
| + return 0; |
| + |
| vpu->extmem[fw_type].va = dma_alloc_coherent(dev, |
| fw_ext_size, |
| &vpu->extmem[fw_type].pa, |
| @@ -711,9 +959,11 @@ static void vpu_ipi_handler(struct mtk_vpu *vpu) |
| { |
| struct share_obj *rcv_obj = vpu->recv_buf; |
| struct vpu_ipi_desc *ipi_desc = vpu->ipi_desc; |
| + char tmp_data[288]; |
| |
| if (rcv_obj->id < IPI_MAX && ipi_desc[rcv_obj->id].handler) { |
| - ipi_desc[rcv_obj->id].handler(rcv_obj->share_buf, |
| + memcpy_fromio(tmp_data, &rcv_obj->share_buf, rcv_obj->len); |
| + ipi_desc[rcv_obj->id].handler(&tmp_data[0], |
| rcv_obj->len, |
| ipi_desc[rcv_obj->id].priv); |
| if (rcv_obj->id > IPI_VPU_INIT) { |
| @@ -727,15 +977,31 @@ static void vpu_ipi_handler(struct mtk_vpu *vpu) |
| |
| static int vpu_ipi_init(struct mtk_vpu *vpu) |
| { |
| - /* Disable VPU to host interrupt */ |
| - vpu_cfg_writel(vpu, 0x0, VPU_TO_HOST); |
| + if (vpu->hw->type == VPU_MT8173) { |
| + /* clear VPU to host interrupt */ |
| + vpu_cfg_writel(vpu, 0x0, VPU_TO_HOST); |
| + /* get shared buffer */ |
| + vpu->recv_buf = (__force struct share_obj *)(vpu->reg.tcm + |
| + vpu->hw->dtcm_offset); |
| + vpu->send_buf = (__force struct share_obj *)(vpu->reg.tcm + |
| + vpu->hw->dtcm_offset + |
| + vpu->hw->share_obj_sz); |
| + } else if (vpu->hw->type == VPU_MT8183) { |
| + /* clear VPU to host interrupt */ |
| + vpu_cfg_writel(vpu, vpu->hw->ipc_int, VPU_TO_HOST); |
| + /* get shared buffer */ |
| + vpu->send_buf = (__force struct share_obj *) (vpu->reg.tcm + |
| + 0x800 - |
| + vpu->hw->share_obj_sz); |
| + |
| + vpu->recv_buf = (__force struct share_obj *)(vpu->reg.tcm + |
| + 0x800 - |
| + vpu->hw->share_obj_sz - |
| + vpu->hw->share_obj_sz); |
| + } |
| |
| - /* shared buffer initialization */ |
| - vpu->recv_buf = (__force struct share_obj *)(vpu->reg.tcm + |
| - VPU_DTCM_OFFSET); |
| - vpu->send_buf = vpu->recv_buf + 1; |
| - memset(vpu->recv_buf, 0, sizeof(struct share_obj)); |
| - memset(vpu->send_buf, 0, sizeof(struct share_obj)); |
| + memset_io(vpu->recv_buf, 0, vpu->hw->share_obj_sz); |
| + memset_io(vpu->send_buf, 0, vpu->hw->share_obj_sz); |
| |
| return 0; |
| } |
| @@ -757,20 +1023,41 @@ static irqreturn_t vpu_irq_handler(int irq, void *priv) |
| return IRQ_NONE; |
| } |
| vpu_to_host = vpu_cfg_readl(vpu, VPU_TO_HOST); |
| - if (vpu_to_host & VPU_IPC_INT) { |
| + if (vpu_to_host & vpu->hw->ipc_int) { |
| vpu_ipi_handler(vpu); |
| } else { |
| dev_err(vpu->dev, "vpu watchdog timeout! 0x%x", vpu_to_host); |
| queue_work(vpu->wdt.wq, &vpu->wdt.ws); |
| } |
| |
| - /* VPU won't send another interrupt until we set VPU_TO_HOST to 0. */ |
| - vpu_cfg_writel(vpu, 0x0, VPU_TO_HOST); |
| + mb(); |
| + /* |
| + * VPU won't send another interrupt until |
| + * we clear the corresponding bits. |
| + */ |
| + if (vpu->hw->type == VPU_MT8173) |
| + vpu_cfg_writel(vpu, 0x0, VPU_TO_HOST); |
| + else if (vpu->hw->type == VPU_MT8183) |
| + vpu_cfg_writel(vpu, vpu->hw->ipc_int | vpu->hw->wdt_int, |
| + VPU_TO_HOST); |
| clk_disable(vpu->clk); |
| |
| return IRQ_HANDLED; |
| } |
| |
| +static const struct of_device_id mtk_vpu_match[] = { |
| + { |
| + .compatible = "mediatek,mt8173-vpu", |
| + .data = &vpu_mt8173, |
| + }, |
| + { |
| + .compatible = "mediatek,mt8183-vpu", |
| + .data = &vpu_mt8183, |
| + }, |
| + {}, |
| +}; |
| +MODULE_DEVICE_TABLE(of, mtk_vpu_match); |
| + |
| #ifdef CONFIG_DEBUG_FS |
| static struct dentry *vpu_debugfs; |
| #endif |
| @@ -780,6 +1067,8 @@ static int mtk_vpu_probe(struct platform_device *pdev) |
| struct device *dev; |
| struct resource *res; |
| int ret = 0; |
| + const struct of_device_id *of_id = |
| + of_match_device(mtk_vpu_match, &pdev->dev); |
| |
| dev_dbg(&pdev->dev, "initialization\n"); |
| |
| @@ -789,6 +1078,7 @@ static int mtk_vpu_probe(struct platform_device *pdev) |
| return -ENOMEM; |
| |
| vpu->dev = &pdev->dev; |
| + vpu->hw = of_id->data; |
| res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tcm"); |
| vpu->reg.tcm = devm_ioremap_resource(dev, res); |
| if (IS_ERR((__force void *)vpu->reg.tcm)) |
| @@ -854,7 +1144,8 @@ static int mtk_vpu_probe(struct platform_device *pdev) |
| #endif |
| |
| /* Set PTCM to 96K and DTCM to 32K */ |
| - vpu_cfg_writel(vpu, 0x2, VPU_TCM_CFG); |
| + if (vpu->hw->type == VPU_MT8173) |
| + vpu_cfg_writel(vpu, 0x2, VPU_TCM_CFG); |
| |
| vpu->enable_4GB = !!(totalram_pages > (SZ_2G >> PAGE_SHIFT)); |
| dev_info(dev, "4GB mode %u\n", vpu->enable_4GB); |
| @@ -921,14 +1212,6 @@ static int mtk_vpu_probe(struct platform_device *pdev) |
| return ret; |
| } |
| |
| -static const struct of_device_id mtk_vpu_match[] = { |
| - { |
| - .compatible = "mediatek,mt8173-vpu", |
| - }, |
| - {}, |
| -}; |
| -MODULE_DEVICE_TABLE(of, mtk_vpu_match); |
| - |
| static int mtk_vpu_remove(struct platform_device *pdev) |
| { |
| struct mtk_vpu *vpu = platform_get_drvdata(pdev); |
| @@ -953,7 +1236,7 @@ static struct platform_driver mtk_vpu_driver = { |
| .remove = mtk_vpu_remove, |
| .driver = { |
| .name = "mtk_vpu", |
| - .of_match_table = mtk_vpu_match, |
| + .of_match_table = of_match_ptr(mtk_vpu_match), |
| }, |
| }; |
| |
| diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.h b/drivers/media/platform/mtk-vpu/mtk_vpu.h |
| index aec0268be3d0..ca09de70ceda 100644 |
| --- a/drivers/media/platform/mtk-vpu/mtk_vpu.h |
| +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.h |
| @@ -100,6 +100,10 @@ enum rst_id { |
| int vpu_ipi_register(struct platform_device *pdev, enum ipi_id id, |
| ipi_handler_t handler, const char *name, void *priv); |
| |
| +int vpu_ipi_send_sync_async(struct platform_device *pdev, |
| + enum ipi_id id, void *buf, |
| + unsigned int len, unsigned int wait); |
| + |
| /** |
| * vpu_ipi_send - send data from AP to vpu. |
| * |
| @@ -191,4 +195,25 @@ int vpu_load_firmware(struct platform_device *pdev); |
| **/ |
| void *vpu_mapping_dm_addr(struct platform_device *pdev, |
| u32 dtcm_dmem_addr); |
| + |
| +#define VPU_RESERVED_MEM (1) |
| +#if VPU_RESERVED_MEM |
| +/* vpu reserve memory ID definition*/ |
| +enum vpu_reserve_mem_id_t { |
| + ISP_MEM_ID, |
| + NUMS_MEM_ID, |
| +}; |
| + |
| +struct vpu_reserve_mblock { |
| + enum vpu_reserve_mem_id_t num; |
| + u64 start_phys; |
| + u64 start_virt; |
| + u64 size; |
| +}; |
| + |
| +extern phys_addr_t vpu_get_reserve_mem_phys(enum vpu_reserve_mem_id_t id); |
| +extern phys_addr_t vpu_get_reserve_mem_virt(enum vpu_reserve_mem_id_t id); |
| +extern phys_addr_t vpu_get_reserve_mem_size(enum vpu_reserve_mem_id_t id); |
| +#endif |
| + |
| #endif /* _MTK_VPU_H */ |
| diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig |
| index 63389f075f1d..4a291dabf2cc 100644 |
| --- a/drivers/memory/Kconfig |
| +++ b/drivers/memory/Kconfig |
| @@ -129,6 +129,15 @@ config JZ4780_NEMC |
| the Ingenic JZ4780. This controller is used to handle external |
| memory devices such as NAND and SRAM. |
| |
| +config MTK_EMI_MBW |
| + bool "Mediatek EMI bandwidth driver" |
| + depends on ARCH_MEDIATEK || COMPILE_TEST |
| + help |
| + This driver is for MTK EMI control. |
| + If unsure, use N. |
| + This is the first time emi upstream. |
| + Only support emi bw statistics. |
| + |
| config MTK_SMI |
| bool |
| depends on ARCH_MEDIATEK || COMPILE_TEST |
| diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile |
| index a01ab3e22f94..82e3d862c24d 100644 |
| --- a/drivers/memory/Makefile |
| +++ b/drivers/memory/Makefile |
| @@ -17,6 +17,7 @@ obj-$(CONFIG_FSL_CORENET_CF) += fsl-corenet-cf.o |
| obj-$(CONFIG_FSL_IFC) += fsl_ifc.o |
| obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o |
| obj-$(CONFIG_JZ4780_NEMC) += jz4780-nemc.o |
| ++obj-$(CONFIG_MTK_EMI_MBW) += mtk-emi.o |
| obj-$(CONFIG_MTK_SMI) += mtk-smi.o |
| obj-$(CONFIG_DA8XX_DDRCTL) += da8xx-ddrctl.o |
| |
| diff --git a/drivers/memory/mtk-emi.c b/drivers/memory/mtk-emi.c |
| new file mode 100644 |
| index 000000000000..5d00c05a8717 |
| --- /dev/null |
| +++ b/drivers/memory/mtk-emi.c |
| @@ -0,0 +1,412 @@ |
| +// SPDX-License-Identifier: GPL-2.0 |
| +/* |
| + * Copyright (c) 2015-2016 MediaTek Inc. |
| + * Author: Xi Chen <xixi.chen@mediatek.com> |
| + */ |
| + |
| +#include <linux/cdev.h> |
| +#include <linux/clk.h> |
| +#include <linux/component.h> |
| +#include <linux/device.h> |
| +#include <linux/err.h> |
| +#include <linux/fs.h> |
| +#include <linux/io.h> |
| +#include <linux/module.h> |
| +#include <linux/of.h> |
| +#include <linux/of_platform.h> |
| +#include <linux/platform_device.h> |
| +#include <linux/pm_runtime.h> |
| +#include <linux/time.h> |
| +#include <linux/timer.h> |
| +#include <soc/mediatek/emi.h> |
| + |
| +/* 67ms emi bw */ |
| +#define EMI_BW_ARRAY_SIZE 67 |
| + |
| +#define MT8173_SMI_LARB_NR 6 |
| +#define MT8167_SMI_LARB_NR 3 |
| +#define MTK_SMI_LARB_NR_MAX 8 |
| +#define MT8173_MMU_EN 0xf00 |
| +#define MT8167_MMU_EN 0xfc0 |
| +#define MT8167_LARB0_OFF 0 |
| +#define MT8167_LARB1_OFF 8 |
| +#define MT8167_LARB2_OFF 21 |
| + |
| +/***************************************************************************** |
| + * Type Definitions |
| + *****************************************************************************/ |
| +enum DDRTYPE { |
| + TYPE_LPDDR3 = 1, |
| + TYPE_LPDDR4, |
| + TYPE_LPDDR4X |
| +}; |
| + |
| +enum { |
| + EMI_BASE_IDX_EMI = 0, |
| + EMI_BASE_IDX_EMI_CH0, |
| + EMI_BASE_IDX_EMI_CH1, |
| + |
| + NR_EMI_BASE_IDX, |
| +}; |
| + |
| +struct emi_base_addr { |
| + unsigned int phy_addr; |
| + unsigned int remap_addr; |
| +}; |
| + |
| +struct mtk_emi { |
| + void __iomem *cen_emi_base; |
| + void __iomem *chn_emi_base[MAX_CH]; |
| + void __iomem *emi_mpu_base; |
| + |
| + struct emi_info_t emi_info; |
| + |
| + struct timer_list emi_bw_timer; |
| + struct timeval old_tv; |
| + |
| + unsigned long long emi_bw_array[EMI_BW_ARRAY_SIZE]; |
| + int emi_bw_cur_idx; |
| + int emi_bw_max_idx; |
| +}; |
| + |
| +/* because timer can't pass argument, so add the global |
| + * static struct device * for timer callback usage |
| + */ |
| +static struct device *emi_dev; |
| + |
| +unsigned long long emi_get_max_bw_in_last_array(struct device *dev, |
| + unsigned long long arr[], unsigned int size) |
| +{ |
| + unsigned int i = 0; |
| + unsigned long long max = arr[0]; |
| + |
| + while (i < size) { |
| + if (arr[i] > max) |
| + max = arr[i]; |
| + ++i; |
| + } |
| + return max; |
| +} |
| + |
| +unsigned long long mtk_emi_get_max_bw(void) |
| +{ |
| + struct mtk_emi *emi; |
| + |
| + if (!emi_dev) |
| + return 0; |
| + |
| + emi = dev_get_drvdata(emi_dev); |
| + return emi_get_max_bw_in_last_array(emi_dev, |
| + emi->emi_bw_array, ARRAY_SIZE(emi->emi_bw_array)); |
| +} |
| +EXPORT_SYMBOL(mtk_emi_get_max_bw); |
| + |
| +void emi_update_bw_array(struct device *dev, unsigned int val) |
| +{ |
| + struct mtk_emi *emi = dev_get_drvdata(emi_dev); |
| + |
| + if (emi->emi_bw_cur_idx == emi->emi_bw_max_idx) { |
| + /* remove the first array element */ |
| + memmove(emi->emi_bw_array, emi->emi_bw_array + 1, |
| + sizeof(unsigned long long) * (emi->emi_bw_max_idx - 1)); |
| + emi->emi_bw_array[emi->emi_bw_max_idx - 1] = val; |
| + } else |
| + emi->emi_bw_array[emi->emi_bw_cur_idx++] = val; |
| +} |
| + |
| +static void emi_dump_bw_array(struct device *dev) |
| +{ |
| + int i = 0; |
| + const int unit = 10; |
| + struct mtk_emi *emi = dev_get_drvdata(emi_dev); |
| + |
| + while (i < emi->emi_bw_max_idx) { |
| + if (i != 0 && i % unit == 0) |
| + pr_info("\n"); |
| + pr_info("0x%x ", emi->emi_bw_array[i]); |
| + |
| + ++i; |
| + } |
| + |
| + pr_info("\n"); |
| +} |
| + |
| +static void emi_counter_reset(struct device *dev) |
| +{ |
| + struct mtk_emi *emi = dev_get_drvdata(dev); |
| + |
| + writel(EMI_BMEN_DEFAULT_VALUE, EMI_BMEN); |
| + writel(EMI_MSEL_DEFAULT_VALUE, EMI_MSEL); |
| + writel(EMI_MSEL2_DEFAULT_VALUE, EMI_MSEL2); |
| + writel(EMI_BMEN2_DEFAULT_VALUE, EMI_BMEN2); |
| + writel(EMI_BMRW0_DEFAULT_VALUE, EMI_BMRW0); |
| +} |
| + |
| +static void emi_counter_pause(struct device *dev) |
| +{ |
| + struct mtk_emi *emi = dev_get_drvdata(dev); |
| + const unsigned int value = readl(EMI_BMEN); |
| + |
| + /* BW monitor */ |
| + writel(value | BUS_MON_PAUSE, EMI_BMEN); |
| +} |
| + |
| +static void emi_counter_continue(struct device *dev) |
| +{ |
| + struct mtk_emi *emi = dev_get_drvdata(dev); |
| + const unsigned int value = readl(EMI_BMEN); |
| + |
| + /* BW monitor */ |
| + writel(value & (~BUS_MON_PAUSE), EMI_BMEN); |
| +} |
| + |
| +static void emi_counter_enable(struct device *dev, const unsigned int enable) |
| +{ |
| + unsigned int value, value_set; |
| + struct mtk_emi *emi = dev_get_drvdata(dev); |
| + |
| + value = readl(EMI_BMEN); |
| + if (enable == 0) { /* disable monitor circuit */ |
| + /* bit3 =1 bit0 = 0-> clear */ |
| + value_set = (value) | (BUS_MON_IDLE); |
| + writel(value_set, EMI_BMEN); |
| + |
| + value_set = ((value) | (BUS_MON_IDLE)) & ~(BUS_MON_EN); |
| + writel(value_set, EMI_BMEN); |
| + |
| + value_set = ((value) & ~(BUS_MON_IDLE)) & ~(BUS_MON_EN); |
| + writel(value_set, EMI_BMEN); |
| + } else { /* enable monitor circuit */ |
| + /* bit3 =0 & bit0=1 */ |
| + value_set = (value & ~(BUS_MON_IDLE)); |
| + writel(value_set, EMI_BMEN); |
| + |
| + value_set = (value & ~(BUS_MON_IDLE)) | (BUS_MON_EN); |
| + writel(value_set, EMI_BMEN); |
| + } |
| +} |
| + |
| +/***************************************************************************** |
| + * APIs |
| + *****************************************************************************/ |
| +static void mtk_emi_mon_start(struct device *dev) |
| +{ |
| + emi_counter_enable(dev, 0); |
| + emi_counter_reset(dev); |
| + emi_counter_enable(dev, 1); |
| +} |
| + |
| +static void mtk_emi_mon_restart(struct device *dev) |
| +{ |
| + emi_counter_continue(dev); |
| + emi_counter_enable(dev, 0); |
| + emi_counter_reset(dev); |
| + emi_counter_enable(dev, 1); |
| +} |
| + |
| +static void mtk_emi_mon_stop(struct device *dev) |
| +{ |
| + emi_counter_pause(dev); |
| +} |
| + |
| +static ssize_t emi_show_max_bw(struct device *dev, |
| + struct device_attribute *attr, char *buf) |
| +{ |
| + unsigned long long var, bw_cpu; |
| + unsigned int bw_gpu; |
| + struct mtk_emi *emi = dev_get_drvdata(dev); |
| + |
| + if (!dev) { |
| + pr_warn("dev is null!!\n"); |
| + return 0; |
| + } |
| + |
| + var = mtk_emi_get_max_bw(); |
| + bw_gpu = readl(EMI_BWVL_4TH) & 0x7f; |
| + bw_cpu = readl(EMI_WSCT3); |
| + |
| + return scnprintf(buf, PAGE_SIZE, |
| + "gpu_max_bw:%llu(0x%x) EMI_BWVL_4TH:0x%x, cpu:%llu(0x%x)\n", |
| + var, var, bw_gpu, bw_cpu, bw_cpu); |
| +} |
| + |
| +DEVICE_ATTR(bw, 0440, emi_show_max_bw, NULL); |
| + |
| +static ssize_t emi_dump_bw(struct device *dev, struct device_attribute *attr, |
| + char *buf) |
| +{ |
| + unsigned long long var; |
| + |
| + if (!dev) { |
| + pr_warn("dev is null!!\n"); |
| + return 0; |
| + } |
| + |
| + emi_dump_bw_array(dev); |
| + var = mtk_emi_get_max_bw(); |
| + |
| + return scnprintf(buf, PAGE_SIZE, |
| + "\temi_max_bw:%llu(0x%x)\n", var, var); |
| +} |
| + |
| +DEVICE_ATTR(dump_bw, 0440, emi_dump_bw, NULL); |
| + |
| +static int emi_bw_ms = 1; |
| +module_param_named(bw_ms, emi_bw_ms, int, 0664); |
| + |
| +static void emi_bw_timer_callback(struct timer_list *tm) |
| +{ |
| + struct timeval tv; |
| + unsigned long long val, cur_max; |
| + struct mtk_emi *emi = dev_get_drvdata(emi_dev); |
| + |
| + do_gettimeofday(&tv); |
| + |
| + /* pasue emi monitor for get WACT value*/ |
| + mtk_emi_mon_stop(emi_dev); |
| + |
| + val = readl(EMI_WSCT4); /* GPU BW */ |
| + val *= 8; |
| + |
| + cur_max = mtk_emi_get_max_bw(); |
| + emi_update_bw_array(emi_dev, val); |
| + |
| + /* set mew timer expires and restart emi monitor */ |
| + emi->old_tv = tv; |
| + emi->emi_bw_timer.expires = jiffies + msecs_to_jiffies(emi_bw_ms); |
| + |
| + add_timer(&(emi->emi_bw_timer)); |
| + mtk_emi_mon_restart(emi_dev); |
| +} |
| + |
| +static int emi_probe(struct platform_device *pdev) |
| +{ |
| + struct mtk_emi *emi; |
| + struct resource *res; |
| + struct device *dev = &pdev->dev; |
| + int i, ret; |
| + |
| + emi = devm_kzalloc(dev, sizeof(*emi), GFP_KERNEL); |
| + if (!emi) |
| + return -ENOMEM; |
| + |
| + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| + emi->cen_emi_base = devm_ioremap_resource(dev, res); |
| + if (IS_ERR(emi->cen_emi_base)) { |
| + pr_err("[EMI] unable to map cen_emi_base\n"); |
| + devm_kfree(dev, emi); |
| + return -EINVAL; |
| + } |
| + |
| + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
| + emi->emi_mpu_base = devm_ioremap_resource(dev, res); |
| + if (IS_ERR(emi->emi_mpu_base)) { |
| + pr_err("[EMI] unable to map emi_mpu_base\n"); |
| + devm_kfree(dev, emi); |
| + return -EINVAL; |
| + } |
| + |
| + for (i = 0; i < MAX_CH; i++) { |
| + res = platform_get_resource(pdev, IORESOURCE_MEM, 2 + i); |
| + emi->chn_emi_base[i] = devm_ioremap_resource(dev, res); |
| + if (IS_ERR(emi->chn_emi_base[i])) { |
| + pr_err("[EMI] unable to map ch%d_emi_base\n", i); |
| + devm_kfree(dev, emi); |
| + return -EINVAL; |
| + } |
| + } |
| + |
| + platform_set_drvdata(pdev, emi); |
| + |
| + emi_dev = dev; |
| + /* start emi bw monitor */ |
| + mtk_emi_mon_start(dev); |
| + |
| + emi->emi_bw_max_idx = ARRAY_SIZE(emi->emi_bw_array); |
| + /* setup timer */ |
| + timer_setup(&(emi->emi_bw_timer), NULL, 0); |
| + do_gettimeofday(&(emi->old_tv)); |
| + |
| + emi->emi_bw_timer.function = emi_bw_timer_callback; |
| + emi->emi_bw_timer.expires = jiffies + msecs_to_jiffies(1); |
| + add_timer(&(emi->emi_bw_timer)); |
| + |
| + /* debug node */ |
| + ret = device_create_file(dev, &dev_attr_bw); |
| + if (ret) { |
| + dev_err(dev, "create bw file failed!\n"); |
| + goto err_create_attr_bw; |
| + } |
| + ret = device_create_file(dev, &dev_attr_dump_bw); |
| + if (ret) { |
| + dev_err(dev, "create dump_bw file failed!\n"); |
| + goto err_create_attr_dump_bw; |
| + } |
| + |
| + return 0; |
| + |
| +err_create_attr_dump_bw: |
| + del_timer(&(emi->emi_bw_timer)); |
| + device_remove_file(dev, &dev_attr_bw); |
| +err_create_attr_bw: |
| + devm_kfree(dev, emi); |
| + return -ENOMEM; |
| +} |
| + |
| +static int emi_remove(struct platform_device *pdev) |
| +{ |
| + struct device *dev = &pdev->dev; |
| + struct mtk_emi *emi = dev_get_drvdata(dev); |
| + |
| + del_timer(&(emi->emi_bw_timer)); |
| + device_remove_file(dev, &dev_attr_dump_bw); |
| + device_remove_file(dev, &dev_attr_bw); |
| + |
| + devm_kfree(dev, emi); |
| + return 0; |
| +} |
| + |
| + |
| +#ifdef CONFIG_OF |
| +static const struct of_device_id emi_of_ids[] = { |
| + {.compatible = "mediatek,mt8183-emi",}, |
| + {} |
| +}; |
| +#endif |
| + |
| +static struct platform_driver emi_bw_driver = { |
| + .probe = emi_probe, |
| + .remove = emi_remove, |
| + .driver = { |
| + .name = "emi_bw", |
| + .owner = THIS_MODULE, |
| + .pm = NULL, |
| +#ifdef CONFIG_OF |
| + .of_match_table = emi_of_ids, |
| +#endif |
| + }, |
| +}; |
| + |
| + |
| +static int __init emi_bw_init(void) |
| +{ |
| + int ret; |
| + |
| + /* register EMI ctrl interface */ |
| + ret = platform_driver_register(&emi_bw_driver); |
| + if (ret) { |
| + pr_err("[EMI/BWL] fail to register emi_bw_driver\n"); |
| + return -ENODEV; |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +static void __exit emi_bw_exit(void) |
| +{ |
| + platform_driver_unregister(&emi_bw_driver); |
| +} |
| + |
| +postcore_initcall(emi_bw_init); |
| +module_exit(emi_bw_exit); |
| + |
| diff --git a/drivers/memory/mtk-smi.c b/drivers/memory/mtk-smi.c |
| index 96883411cd29..a1dc34ba7332 100644 |
| --- a/drivers/memory/mtk-smi.c |
| +++ b/drivers/memory/mtk-smi.c |
| @@ -123,20 +123,6 @@ static void mtk_smi_clk_disable(const struct mtk_smi *smi) |
| clk_disable_unprepare(smi->clk_apb); |
| } |
| |
| -int mtk_smi_larb_get(struct device *larbdev) |
| -{ |
| - int ret = pm_runtime_get_sync(larbdev); |
| - |
| - return (ret < 0) ? ret : 0; |
| -} |
| -EXPORT_SYMBOL_GPL(mtk_smi_larb_get); |
| - |
| -void mtk_smi_larb_put(struct device *larbdev) |
| -{ |
| - pm_runtime_put_sync(larbdev); |
| -} |
| -EXPORT_SYMBOL_GPL(mtk_smi_larb_put); |
| - |
| static int |
| mtk_smi_larb_bind(struct device *dev, struct device *master, void *data) |
| { |
| @@ -271,6 +257,7 @@ static int mtk_smi_larb_probe(struct platform_device *pdev) |
| struct device *dev = &pdev->dev; |
| struct device_node *smi_node; |
| struct platform_device *smi_pdev; |
| + struct device_link *link; |
| |
| larb = devm_kzalloc(dev, sizeof(*larb), GFP_KERNEL); |
| if (!larb) |
| @@ -310,6 +297,12 @@ static int mtk_smi_larb_probe(struct platform_device *pdev) |
| if (!platform_get_drvdata(smi_pdev)) |
| return -EPROBE_DEFER; |
| larb->smi_common_dev = &smi_pdev->dev; |
| + link = device_link_add(dev, larb->smi_common_dev, |
| + DL_FLAG_PM_RUNTIME); |
| + if (!link) { |
| + dev_err(dev, "Unable to link smi-common dev\n"); |
| + return -ENODEV; |
| + } |
| } else { |
| dev_err(dev, "Failed to get the smi_common device\n"); |
| return -EINVAL; |
| @@ -333,17 +326,9 @@ static int __maybe_unused mtk_smi_larb_resume(struct device *dev) |
| const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen; |
| int ret; |
| |
| - /* Power on smi-common. */ |
| - ret = pm_runtime_get_sync(larb->smi_common_dev); |
| - if (ret < 0) { |
| - dev_err(dev, "Failed to pm get for smi-common(%d).\n", ret); |
| - return ret; |
| - } |
| - |
| ret = mtk_smi_clk_enable(&larb->smi); |
| if (ret < 0) { |
| dev_err(dev, "Failed to enable clock(%d).\n", ret); |
| - pm_runtime_put_sync(larb->smi_common_dev); |
| return ret; |
| } |
| |
| @@ -358,7 +343,6 @@ static int __maybe_unused mtk_smi_larb_suspend(struct device *dev) |
| struct mtk_smi_larb *larb = dev_get_drvdata(dev); |
| |
| mtk_smi_clk_disable(&larb->smi); |
| - pm_runtime_put_sync(larb->smi_common_dev); |
| return 0; |
| } |
| |
| diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile |
| index ce8398e6f2c0..c8f3fe701ea7 100644 |
| --- a/drivers/mmc/host/Makefile |
| +++ b/drivers/mmc/host/Makefile |
| @@ -23,7 +23,7 @@ obj-$(CONFIG_MMC_SDHCI_F_SDH30) += sdhci_f_sdh30.o |
| obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o |
| obj-$(CONFIG_MMC_WBSD) += wbsd.o |
| obj-$(CONFIG_MMC_AU1X) += au1xmmc.o |
| -obj-$(CONFIG_MMC_MTK) += mtk-sd.o |
| +obj-$(CONFIG_MMC_MTK) += mtk-sd.o mtk-sdio-proc.o |
| obj-$(CONFIG_MMC_OMAP) += omap.o |
| obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o |
| obj-$(CONFIG_MMC_ATMELMCI) += atmel-mci.o |
| diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c |
| index 0de3749c9311..8aaa5d405987 100644 |
| --- a/drivers/mmc/host/mtk-sd.c |
| +++ b/drivers/mmc/host/mtk-sd.c |
| @@ -39,6 +39,8 @@ |
| #include <linux/mmc/sdio.h> |
| #include <linux/mmc/slot-gpio.h> |
| |
| +#include "mtk-sdio-proc.h" |
| + |
| #define MAX_BD_NUM 1024 |
| |
| /*--------------------------------------------------------------------------*/ |
| @@ -2234,6 +2236,9 @@ static int msdc_drv_probe(struct platform_device *pdev) |
| if (ret) |
| goto end; |
| |
| + if (host->mmc->caps & MMC_CAP_SDIO_IRQ) |
| + sdio_proc_init(host->mmc); |
| + |
| return 0; |
| end: |
| pm_runtime_disable(host->dev); |
| diff --git a/drivers/mmc/host/mtk-sdio-proc.c b/drivers/mmc/host/mtk-sdio-proc.c |
| new file mode 100644 |
| index 000000000000..6f4c3cd96d42 |
| --- /dev/null |
| +++ b/drivers/mmc/host/mtk-sdio-proc.c |
| @@ -0,0 +1,342 @@ |
| +/* |
| + * Copyright (c) 2014-2015 MediaTek Inc. |
| + * Author: Chaotian.Jing <chaotian.jing@mediatek.com> |
| + * |
| + * This program is free software; you can redistribute it and/or modify |
| + * it under the terms of the GNU General Public License version 2 as |
| + * published by the Free Software Foundation. |
| + * |
| + * This program is distributed in the hope that it will be useful, |
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + * GNU General Public License for more details. |
| + */ |
| + |
| +#include "mtk-sdio-proc.h" |
| + |
| +static struct mmc_host *host; |
| + |
| +/** |
| + * sdio_proc_show dispaly the common cccr and cis. |
| + */ |
| +static int sdio_proc_show(struct seq_file *m, void *v) |
| +{ |
| + struct mmc_card *card; |
| + struct sdio_cccr cccr; |
| + |
| + WARN_ON(!host); |
| + card = host->card; |
| + cccr = card->cccr; |
| + |
| + seq_puts(m, "\n=========================================\n"); |
| + seq_puts(m, "common cccr:\n"); |
| + seq_printf(m, "sdio_vsn:%x, sd_vsn:%x, multi_block%x.\n" |
| + "low_speed:%x, wide_bus:%x, hight_power:%x.\n" |
| + "high_speed:%x, disable_cd:%x.\n", |
| + cccr.sdio_vsn, cccr.sd_vsn, cccr.multi_block, |
| + cccr.low_speed, cccr.wide_bus, cccr.high_power, |
| + cccr.high_speed, cccr.disable_cd); |
| + |
| + seq_puts(m, "common cis:\n"); |
| + seq_printf(m, "vendor: %x, device:%x, blksize:%x, max_dtr:%x\n", |
| + card->cis.vendor, card->cis.device, |
| + card->cis.blksize, card->cis.max_dtr); |
| + |
| + seq_puts(m, "read cmd format:\n"); |
| + seq_puts(m, "echo 0 0xReg 0xfunction> /proc/sdio\n"); |
| + seq_puts(m, "write cmd format:\n"); |
| + seq_puts(m, "echo 1 0xReg 0xfunction 0xValue> /proc/sdio\n"); |
| + seq_puts(m, "setspeed cmd format:\n"); |
| + seq_puts(m, "echo 2 0xclkfrequency > /proc/sdio\n"); |
| + seq_puts(m, "tune cmd format:\n"); |
| + seq_puts(m, "echo 3 0xloop_cycles > /proc/sdio\n"); |
| + seq_puts(m, "multi read cmd format:\n"); |
| + seq_puts(m, "echo 4 0x13 0x0 > /proc/sdio\n"); |
| + seq_puts(m, "multi write cmd format:\n"); |
| + seq_puts(m, "echo 5 0x13 0x0 0xvalue > /proc/sdio\n"); |
| + seq_puts(m, "Notice:value is the read result!\n"); |
| + seq_puts(m, "=========================================\n"); |
| + |
| + return 0; |
| +} |
| + |
| +static int sdio_tuning(void) |
| +{ |
| + int err = 0; |
| + |
| + err = mmc_send_tuning(host, MMC_SEND_TUNING_BLOCK, NULL); |
| + if (err) |
| + pr_err("tuning result is %d.\n", err); |
| + return err; |
| +} |
| + |
| +/** |
| + * sdio_proc_write - read/write sdio function register. |
| + */ |
| +static ssize_t sdio_proc_write(struct file *file, const char *buf, |
| + size_t count, loff_t *f_pos) |
| +{ |
| + struct mmc_card *card; |
| + struct sdio_func *func; |
| + struct mmc_ios *ios; |
| + char *cmd_buf; |
| + unsigned int cmd, addr, fn, value, hqa_result; |
| + unsigned char result; |
| + int i = 0, ret; |
| + unsigned long long count_r = 0, count_w = 0, total = 0; |
| + |
| + WARN_ON(!host); |
| + card = host->card; |
| + ios = &host->ios; |
| + |
| + cmd_buf = kzalloc((count + 1), GFP_KERNEL); |
| + if (!cmd_buf) |
| + return -ENOMEM; |
| + |
| + func = kzalloc(sizeof(struct sdio_func), GFP_KERNEL); |
| + if (!func) |
| + return -ENOMEM; |
| + |
| + ret = copy_from_user(cmd_buf, buf, count); |
| + if (ret < 0) { |
| + kfree(cmd_buf); |
| + kfree(func); |
| + return -EFAULT; |
| + } |
| + |
| + *(cmd_buf + count) = '\0'; |
| + ret = sscanf(cmd_buf, "%x %x %x %x", |
| + &cmd, &addr, &fn, &value); |
| + if (ret == 0) { |
| + pr_err("please enter cmd.\n"); |
| + return ret; |
| + } |
| + |
| + if ((cmd == tune) || (cmd == speed)) |
| + fn = 0; |
| + |
| + /* Judge whether request fn is over the max functions. */ |
| + if (fn > card->sdio_funcs) { |
| + pr_err("the fn is over the max sdio funcs.\n"); |
| + return -EFAULT; |
| + } |
| + |
| + if (fn) { |
| + /** |
| + * The test read/write api don't need more func |
| + * information. So we just use the card & func->num |
| + * to the new struct func. |
| + */ |
| + if (card->sdio_func[fn - 1]) { |
| + func->card = card; |
| + func->num = card->sdio_func[fn - 1]->num; |
| + func->tuples = card->sdio_func[fn - 1]->tuples; |
| + func->tmpbuf = card->sdio_func[fn - 1]->tmpbuf; |
| + func->max_blksize = card->sdio_func[fn - 1]->max_blksize; |
| + if ((cmd == hqa_read) || (cmd == hqa_write) || (cmd == burn)) |
| + func->cur_blksize = 8; |
| + else |
| + func->cur_blksize = 1; |
| + func = card->sdio_func[fn - 1]; |
| + } else |
| + pr_err("func %d is null,.\n", fn); |
| + } else { |
| + /** |
| + * function 0 should not need struct func. |
| + * but the api need the parameter, so we create |
| + * the a new func for function 0. |
| + */ |
| + func->card = card; |
| + func->tuples = card->tuples; |
| + func->num = 0; |
| + func->max_blksize = 16; |
| + if ((cmd == hqa_read) || (cmd == hqa_write) || (cmd == burn)) |
| + func->cur_blksize = 16; |
| + else |
| + func->cur_blksize = 1; |
| + |
| + func->tmpbuf = kmalloc(func->cur_blksize, GFP_KERNEL); |
| + if (!func->tmpbuf) { |
| + kfree(func); |
| + return -ENOMEM; |
| + } |
| + memset(func->tmpbuf, 0, func->cur_blksize); |
| + } |
| + |
| + sdio_claim_host(func); |
| + pr_err("===========================================\n"); |
| + |
| + switch (cmd) { |
| + case read: |
| + pr_err("read addr:%x, fn:%d.\n", addr, fn); |
| + ret = 0; |
| + if (fn == 0) |
| + result = sdio_f0_readb(func, addr, &ret); |
| + else |
| + result = sdio_readb(func, addr, &ret); |
| + |
| + if (ret) |
| + pr_err("Read f%d reg(%x) fail(%d).\n", |
| + func->num, addr, ret); |
| + else |
| + pr_err("f%d reg(%x) is 0x%02x.\n", |
| + func->num, addr, result); |
| + break; |
| + case write: |
| + pr_err("write addr:%x, value:%x, fn %d.\n", |
| + addr, (u8)value, fn); |
| + ret = 0; |
| + if (fn == 0) |
| + /* (0xF0 - 0xFF) are permiited for func0 */ |
| + sdio_f0_writeb(func, (u8)value, addr, &ret); |
| + else |
| + sdio_writeb(func, (u8)value, addr, &ret); |
| + |
| + if (ret) |
| + pr_err("write f%d reg(%x) fail(%d).\n", |
| + func->num, addr, ret); |
| + else |
| + pr_err("write f%d reg(%x) success(%d).\n", |
| + func->num, addr, ret); |
| + |
| + break; |
| + case speed: |
| + pr_err("set frequence:%x.\n", addr); |
| + |
| + if (addr > 200000000) |
| + addr = 200000000; |
| + ios->clock = addr; |
| + pr_err("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u width %u timing %u\n", |
| + mmc_hostname(host), ios->clock, ios->bus_mode, |
| + ios->power_mode, ios->chip_select, ios->vdd, |
| + ios->bus_width, ios->timing); |
| + |
| + host->ops->set_ios(host, ios); |
| + break; |
| + case tune: |
| + value = 0; |
| + pr_err("read loop / 0x200:%x.\n", addr); |
| + |
| + do { |
| + result = sdio_tuning(); |
| + if (result) |
| + value = value + 1; |
| + |
| + i = i + 1; |
| + } while (i < addr); |
| + |
| + pr_err("send tuning cmd is result (%d).\n", value); |
| + break; |
| + case hqa_read: |
| + pr_err("hqa_r addr:%x, fn %d\n", addr, fn); |
| + i = 0; |
| + hqa_result = 0; |
| + do { |
| + ret = 0; |
| + hqa_result = sdio_readl(func, addr, &ret); |
| + if (ret) |
| + pr_err("Read f%d reg(%x) fail(%d).\n", |
| + func->num, addr, ret); |
| + |
| + i = i + 1; |
| + } while (i < 0x10000); |
| + pr_err("Read %d cycles success:f%d reg(%x) is 0x%02x.\n", |
| + i, func->num, addr, hqa_result); |
| + break; |
| + case hqa_write: |
| + pr_err("hqa_w addr:%x, value:%x, fn %d\n", |
| + addr, value, fn); |
| + i = 0; |
| + hqa_result = 0; |
| + do { |
| + ret = 0; |
| + sdio_writel(func, value, addr, &ret); |
| + if (ret) |
| + pr_err("write f%d reg(%x) fail(%d).\n", |
| + func->num, addr, ret); |
| + |
| + i = i + 1; |
| + } while (i < 0x10000); |
| + pr_err("write f%d reg(%x) success(%d).\n", |
| + func->num, addr, ret); |
| + break; |
| + case burn: |
| + do { |
| + ret = 0; |
| + addr = 0x13; |
| + value = sdio_readl(func, addr, &ret); |
| + if (ret) |
| + pr_err("Read f%d reg(%x) fail(%d).\n", |
| + func->num, addr, ret); |
| + else { |
| + pr_err("********read success********\n"); |
| + count_r = count_r + 1; |
| + } |
| + msleep(20); |
| + |
| + ret = 0; |
| + addr = 0x13; |
| + func->cur_blksize = 4; |
| + sdio_writel(func, value, addr, &ret); |
| + if (ret) |
| + pr_err("write f%d reg(%x) fail(%d).\n", |
| + func->num, addr, ret); |
| + else { |
| + pr_err("********write success*******\n"); |
| + count_w = count_w + 1; |
| + } |
| + total = total + 1; |
| + msleep(20); |
| + pr_err("success read:%llx, write:%llx, total:%llx.\n", |
| + count_r, count_w, total); |
| + } while (1); |
| + break; |
| + default: |
| + pr_err("cmd is not valid.\n"); |
| + break; |
| + } |
| + |
| + pr_err("\n===========================================\n"); |
| + sdio_release_host(func); |
| + |
| + kfree(cmd_buf); |
| + kfree(func); |
| + |
| + return count; |
| +} |
| + |
| +/** |
| + * open function show some stable information. |
| + */ |
| +static int sdio_proc_open(struct inode *inode, struct file *file) |
| +{ |
| + return single_open(file, sdio_proc_show, inode->i_private); |
| +} |
| + |
| +/** |
| + * sdio pre is our own function. |
| + * seq or single pre is the kernel function. |
| + */ |
| +static const struct file_operations sdio_proc_fops = { |
| + .owner = THIS_MODULE, |
| + .open = sdio_proc_open, |
| + .release = single_release, |
| + .write = sdio_proc_write, |
| + .read = seq_read, |
| + .llseek = seq_lseek, |
| +}; |
| + |
| +int sdio_proc_init(struct mmc_host *host_init) |
| +{ |
| + struct proc_dir_entry *prEntry; |
| + |
| + host = host_init; |
| + |
| + prEntry = proc_create("sdio", 0660, NULL, &sdio_proc_fops); |
| + if (prEntry) |
| + pr_err("[%s]/proc/sdio_proc is created.\n", __func__); |
| + else |
| + pr_err("[%s]Create /proc/sdio_proc failed.\n", __func__); |
| + |
| + return 0; |
| +} |
| diff --git a/drivers/mmc/host/mtk-sdio-proc.h b/drivers/mmc/host/mtk-sdio-proc.h |
| new file mode 100644 |
| index 000000000000..33659ba69be3 |
| --- /dev/null |
| +++ b/drivers/mmc/host/mtk-sdio-proc.h |
| @@ -0,0 +1,48 @@ |
| +/* |
| + * Copyright (c) 2014-2015 MediaTek Inc. |
| + * Author: Chaotian.Jing <chaotian.jing@mediatek.com> |
| + * |
| + * This program is free software; you can redistribute it and/or modify |
| + * it under the terms of the GNU General Public License version 2 as |
| + * published by the Free Software Foundation. |
| + * |
| + * This program is distributed in the hope that it will be useful, |
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + * GNU General Public License for more details. |
| + */ |
| + |
| +#include <linux/version.h> |
| +#include <linux/kernel.h> |
| +#include <linux/sched.h> |
| +#include <linux/kthread.h> |
| +#include <linux/delay.h> |
| +#include <linux/module.h> |
| +#include <linux/init.h> |
| +#include <linux/proc_fs.h> |
| +#include <linux/string.h> |
| +#include <linux/uaccess.h> |
| +#include <linux/mmc/host.h> |
| +#include <linux/vmalloc.h> |
| +#include <linux/fs.h> |
| +#include <linux/seq_file.h> |
| +#include <linux/slab.h> |
| +#include <linux/mmc/card.h> |
| +#include <linux/mmc/core.h> |
| +#include <linux/mmc/host.h> |
| +#include <linux/mmc/mmc.h> |
| +#include <linux/mmc/sd.h> |
| +#include <linux/mmc/sdio.h> |
| +#include <linux/mmc/sdio_func.h> |
| + |
| +int sdio_proc_init(struct mmc_host *host); |
| + |
| +enum { |
| + read = 0, |
| + write, |
| + speed, |
| + tune, |
| + hqa_read, |
| + hqa_write, |
| + burn |
| +}; |
| diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c |
| index 9eed1cb17fda..2a14606ac91f 100644 |
| --- a/drivers/net/wireless/ath/ath10k/htt_rx.c |
| +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c |
| @@ -1952,6 +1952,7 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt, |
| int num_mpdu_ranges; |
| size_t tot_hdr_len; |
| struct ieee80211_channel *ch; |
| + bool pn_invalid; |
| |
| peer_id = __le16_to_cpu(rx->hdr.peer_id); |
| |
| @@ -1959,7 +1960,7 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt, |
| peer = ath10k_peer_find_by_id(ar, peer_id); |
| spin_unlock_bh(&ar->data_lock); |
| if (!peer) |
| - ath10k_warn(ar, "Got RX ind from invalid peer: %u\n", peer_id); |
| + ath10k_dbg(ar, ATH10K_DBG_HTT, "Got RX ind from invalid peer: %u\n", peer_id); |
| |
| num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1), |
| HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES); |
| @@ -1977,15 +1978,21 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt, |
| num_mpdu_ranges); |
| |
| if (mpdu_ranges->mpdu_range_status != |
| - HTT_RX_IND_MPDU_STATUS_OK) { |
| - ath10k_warn(ar, "MPDU range status: %d\n", |
| + HTT_RX_IND_MPDU_STATUS_OK && |
| + mpdu_ranges->mpdu_range_status != |
| + HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR) { |
| + ath10k_dbg(ar, ATH10K_DBG_HTT, "MPDU range status: %d\n", |
| mpdu_ranges->mpdu_range_status); |
| goto err; |
| } |
| |
| - if (check_pn_type == HTT_RX_PN_CHECK && |
| - ath10k_htt_rx_pn_check_replay_hl(ar, peer, rx)) |
| - goto err; |
| + if (check_pn_type == HTT_RX_PN_CHECK) { |
| + spin_lock_bh(&ar->data_lock); |
| + pn_invalid = ath10k_htt_rx_pn_check_replay_hl(ar, peer, rx); |
| + spin_unlock_bh(&ar->data_lock); |
| + if (pn_invalid) |
| + goto err; |
| + } |
| |
| /* Strip off all headers before the MAC header before delivery to |
| * mac80211 |
| @@ -2047,6 +2054,9 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt, |
| rx_status->flag &= ~RX_FLAG_IV_STRIPPED & |
| ~RX_FLAG_MMIC_STRIPPED; |
| |
| + if (mpdu_ranges->mpdu_range_status == HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR) |
| + rx_status->flag |= RX_FLAG_MMIC_ERROR; |
| + |
| ieee80211_rx_ni(ar->hw, skb); |
| |
| /* We have delivered the skb to the upper layers (mac80211) so we |
| diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h |
| index 5c256d41cc82..23fdbc3941b2 100644 |
| --- a/drivers/net/wireless/ath/ath10k/hw.h |
| +++ b/drivers/net/wireless/ath/ath10k/hw.h |
| @@ -162,6 +162,8 @@ enum qca9377_chip_id_rev { |
| #define ATH10K_FW_UTF_FILE "utf.bin" |
| #define ATH10K_FW_UTF_API2_FILE "utf-2.bin" |
| |
| +#define ATH10K_FW_UTF_FILE_BASE "utf" |
| + |
| /* includes also the null byte */ |
| #define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K" |
| #define ATH10K_BOARD_MAGIC "QCA-ATH10K-BOARD" |
| @@ -1076,6 +1078,7 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw, |
| #define MBOX_CPU_INT_STATUS_ENABLE_ADDRESS 0x00000819 |
| #define MBOX_CPU_INT_STATUS_ENABLE_BIT_LSB 0 |
| #define MBOX_CPU_INT_STATUS_ENABLE_BIT_MASK 0x000000ff |
| +#define MBOX_CPU_STATUS_ENABLE_ASSERT_MASK 0x00000001 |
| #define MBOX_ERROR_STATUS_ENABLE_ADDRESS 0x0000081a |
| #define MBOX_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB 1 |
| #define MBOX_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK 0x00000002 |
| diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c |
| index 2ebe657be089..7beac869bf58 100644 |
| --- a/drivers/net/wireless/ath/ath10k/sdio.c |
| +++ b/drivers/net/wireless/ath/ath10k/sdio.c |
| @@ -618,6 +618,10 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar, |
| full_len, |
| last_in_bundle, |
| last_in_bundle); |
| + if (ret) { |
| + ath10k_warn(ar, "alloc_rx_pkt error %d\n", ret); |
| + goto err; |
| + } |
| } |
| |
| ar_sdio->n_rx_pkts = i; |
| @@ -866,6 +870,10 @@ static int ath10k_sdio_mbox_proc_cpu_intr(struct ath10k *ar) |
| |
| out: |
| mutex_unlock(&irq_data->mtx); |
| + if (cpu_int_status & MBOX_CPU_STATUS_ENABLE_ASSERT_MASK) { |
| + ath10k_err(ar, "firmware crashed!\n"); |
| + queue_work(ar->workqueue, &ar->restart_work); |
| + } |
| return ret; |
| } |
| |
| @@ -1448,10 +1456,6 @@ static void ath10k_sdio_hif_power_down(struct ath10k *ar) |
| return; |
| } |
| |
| - ret = mmc_hw_reset(ar_sdio->func->card->host); |
| - if (ret) |
| - ath10k_warn(ar, "unable to reset sdio: %d\n", ret); |
| - |
| sdio_release_host(ar_sdio->func); |
| |
| ar_sdio->is_disabled = true; |
| @@ -1510,8 +1514,10 @@ static int ath10k_sdio_hif_enable_intrs(struct ath10k *ar) |
| regs->int_status_en |= |
| FIELD_PREP(MBOX_INT_STATUS_ENABLE_MBOX_DATA_MASK, 1); |
| |
| - /* Set up the CPU Interrupt status Register */ |
| - regs->cpu_int_status_en = 0; |
| + /* Set up the CPU Interrupt Status Register, enable CPU sourced interrupt #0 |
| + * #0 is used for report assertion from target |
| + */ |
| + regs->cpu_int_status_en = FIELD_PREP(MBOX_CPU_STATUS_ENABLE_ASSERT_MASK, 1); |
| |
| /* Set up the Error Interrupt status Register */ |
| regs->err_int_status_en = |
| diff --git a/drivers/net/wireless/ath/ath10k/testmode.c b/drivers/net/wireless/ath/ath10k/testmode.c |
| index c24ee616833c..348d98be2c70 100644 |
| --- a/drivers/net/wireless/ath/ath10k/testmode.c |
| +++ b/drivers/net/wireless/ath/ath10k/testmode.c |
| @@ -185,8 +185,23 @@ static int ath10k_tm_fetch_firmware(struct ath10k *ar) |
| { |
| struct ath10k_fw_components *utf_mode_fw; |
| int ret; |
| + char fw_name[100]; |
| + int fw_api2 = 2; |
| + |
| + switch (ar->hif.bus) { |
| + case ATH10K_BUS_SDIO: |
| + case ATH10K_BUS_USB: |
| + scnprintf(fw_name, sizeof(fw_name), "%s-%s-%d.bin", |
| + ATH10K_FW_UTF_FILE_BASE, ath10k_bus_str(ar->hif.bus), |
| + fw_api2); |
| + break; |
| + default: |
| + scnprintf(fw_name, sizeof(fw_name), "%s-%d.bin", |
| + ATH10K_FW_UTF_FILE_BASE, fw_api2); |
| + break; |
| + } |
| |
| - ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_UTF_API2_FILE, |
| + ret = ath10k_core_fetch_firmware_api_n(ar, fw_name, |
| &ar->testmode.utf_mode_fw.fw_file); |
| if (ret == 0) { |
| ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using fw utf api 2"); |
| diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c |
| index a613e546717a..564cfaee129d 100644 |
| --- a/drivers/pinctrl/mediatek/mtk-eint.c |
| +++ b/drivers/pinctrl/mediatek/mtk-eint.c |
| @@ -113,6 +113,8 @@ static void mtk_eint_mask(struct irq_data *d) |
| void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq, |
| eint->regs->mask_set); |
| |
| + eint->cur_mask[d->hwirq >> 5] &= ~mask; |
| + |
| writel(mask, reg); |
| } |
| |
| @@ -123,6 +125,8 @@ static void mtk_eint_unmask(struct irq_data *d) |
| void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq, |
| eint->regs->mask_clr); |
| |
| + eint->cur_mask[d->hwirq >> 5] |= mask; |
| + |
| writel(mask, reg); |
| |
| if (eint->dual_edge[d->hwirq]) |
| @@ -217,19 +221,6 @@ static void mtk_eint_chip_write_mask(const struct mtk_eint *eint, |
| } |
| } |
| |
| -static void mtk_eint_chip_read_mask(const struct mtk_eint *eint, |
| - void __iomem *base, u32 *buf) |
| -{ |
| - int port; |
| - void __iomem *reg; |
| - |
| - for (port = 0; port < eint->hw->ports; port++) { |
| - reg = base + eint->regs->mask + (port << 2); |
| - buf[port] = ~readl_relaxed(reg); |
| - /* Mask is 0 when irq is enabled, and 1 when disabled. */ |
| - } |
| -} |
| - |
| static int mtk_eint_irq_request_resources(struct irq_data *d) |
| { |
| struct mtk_eint *eint = irq_data_get_irq_chip_data(d); |
| @@ -318,7 +309,7 @@ static void mtk_eint_irq_handler(struct irq_desc *desc) |
| struct irq_chip *chip = irq_desc_get_chip(desc); |
| struct mtk_eint *eint = irq_desc_get_handler_data(desc); |
| unsigned int status, eint_num; |
| - int offset, index, virq; |
| + int offset, mask_offset, index, virq; |
| void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat); |
| int dual_edge, start_level, curr_level; |
| |
| @@ -328,10 +319,24 @@ static void mtk_eint_irq_handler(struct irq_desc *desc) |
| status = readl(reg); |
| while (status) { |
| offset = __ffs(status); |
| + mask_offset = eint_num >> 5; |
| index = eint_num + offset; |
| virq = irq_find_mapping(eint->domain, index); |
| status &= ~BIT(offset); |
| |
| + /* |
| + * If we get an interrupt on pin that was only required |
| + * for wake (but no real interrupt requested), mask the |
| + * interrupt (as would mtk_eint_resume do anyway later |
| + * in the resume sequence). |
| + */ |
| + if (eint->wake_mask[mask_offset] & BIT(offset) && |
| + !(eint->cur_mask[mask_offset] & BIT(offset))) { |
| + writel_relaxed(BIT(offset), reg - |
| + eint->regs->stat + |
| + eint->regs->mask_set); |
| + } |
| + |
| dual_edge = eint->dual_edge[index]; |
| if (dual_edge) { |
| /* |
| @@ -370,7 +375,6 @@ static void mtk_eint_irq_handler(struct irq_desc *desc) |
| |
| int mtk_eint_do_suspend(struct mtk_eint *eint) |
| { |
| - mtk_eint_chip_read_mask(eint, eint->base, eint->cur_mask); |
| mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask); |
| |
| return 0; |
| diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c |
| index ff9fef5a032b..317ec441ad60 100644 |
| --- a/drivers/soc/mediatek/mtk-cmdq-helper.c |
| +++ b/drivers/soc/mediatek/mtk-cmdq-helper.c |
| @@ -9,17 +9,109 @@ |
| #include <linux/mailbox_controller.h> |
| #include <linux/soc/mediatek/mtk-cmdq.h> |
| |
| -#define CMDQ_ARG_A_WRITE_MASK 0xffff |
| +#define CMDQ_GET_ARG_B(arg) (((arg) & GENMASK(31, 16)) >> 16) |
| +#define CMDQ_GET_ARG_C(arg) ((arg) & GENMASK(15, 0)) |
| #define CMDQ_WRITE_ENABLE_MASK BIT(0) |
| #define CMDQ_EOC_IRQ_EN BIT(0) |
| #define CMDQ_EOC_CMD ((u64)((CMDQ_CODE_EOC << CMDQ_OP_CODE_SHIFT)) \ |
| << 32 | CMDQ_EOC_IRQ_EN) |
| +#define CMDQ_IMMEDIATE_VALUE 0 |
| +#define CMDQ_REG_TYPE 1 |
| + |
| +struct cmdq_instruction { |
| + s16 arg_c:16; |
| + s16 arg_b:16; |
| + s16 arg_a:16; |
| + u8 s_op:5; |
| + u8 arg_c_type:1; |
| + u8 arg_b_type:1; |
| + u8 arg_a_type:1; |
| + u8 op:8; |
| +}; |
| + |
| +static void cmdq_pkt_instr_encoder(struct cmdq_pkt *pkt, s16 arg_c, s16 arg_b, |
| + s16 arg_a, u8 s_op, u8 arg_c_type, |
| + u8 arg_b_type, u8 arg_a_type, u8 op) |
| +{ |
| + struct cmdq_instruction *cmdq_inst; |
| + |
| + cmdq_inst = pkt->va_base + pkt->cmd_buf_size; |
| + cmdq_inst->op = op; |
| + cmdq_inst->arg_a_type = arg_a_type; |
| + cmdq_inst->arg_b_type = arg_b_type; |
| + cmdq_inst->arg_c_type = arg_c_type; |
| + cmdq_inst->s_op = s_op; |
| + cmdq_inst->arg_a = arg_a; |
| + cmdq_inst->arg_b = arg_b; |
| + cmdq_inst->arg_c = arg_c; |
| + pkt->cmd_buf_size += CMDQ_INST_SIZE; |
| +} |
| + |
| +struct cmdq_subsys *cmdq_dev_get_subsys(struct device *dev, int idx) |
| +{ |
| + struct cmdq_subsys *subsys; |
| + struct of_phandle_args spec; |
| + |
| + subsys = devm_kzalloc(dev, sizeof(*subsys), GFP_KERNEL); |
| + if (!subsys) |
| + return NULL; |
| + |
| + if (of_parse_phandle_with_args(dev->of_node, "mediatek,gce-client-reg", |
| + "#subsys-cells", idx, &spec)) { |
| + dev_err(dev, "can't parse gce-client-reg property"); |
| + |
| + return(struct cmdq_subsys *)-ENODEV; |
| + } |
| + |
| + subsys->id = spec.args[0]; |
| + subsys->offset = spec.args[1]; |
| + subsys->size = spec.args[2]; |
| + of_node_put(spec.np); |
| + |
| + return subsys; |
| +} |
| +EXPORT_SYMBOL(cmdq_dev_get_subsys); |
| + |
| +s32 cmdq_dev_get_event(struct device *dev, const char *name) |
| +{ |
| + s32 index = 0; |
| + struct of_phandle_args spec; |
| + s32 result; |
| + |
| + if (!dev) |
| + return -EINVAL; |
| + |
| + index = of_property_match_string(dev->of_node, |
| + "mediatek,gce-event-names", name); |
| + if (index < 0) { |
| + dev_err(dev, "no gce-event-names property or no such event:%s", |
| + name); |
| + |
| + return index; |
| + } |
| + |
| + if (of_parse_phandle_with_args(dev->of_node, "mediatek,gce-events", |
| + "#event-cells", index, &spec)) { |
| + dev_err(dev, "can't parse gce-events property"); |
| + |
| + return -ENODEV; |
| + } |
| + |
| + result = spec.args[0]; |
| + of_node_put(spec.np); |
| + |
| + return result; |
| +} |
| +EXPORT_SYMBOL(cmdq_dev_get_event); |
| |
| static void cmdq_client_timeout(struct timer_list *t) |
| { |
| struct cmdq_client *client = from_timer(client, t, timer); |
| |
| dev_err(client->client.dev, "cmdq timeout!\n"); |
| +#ifdef CONFIG_MTK_CMDQ_DEBUG |
| + mbox_free_channel(client->chan); |
| +#endif |
| } |
| |
| struct cmdq_client *cmdq_mbox_create(struct device *dev, int index, u32 timeout) |
| @@ -110,10 +202,11 @@ void cmdq_pkt_destroy(struct cmdq_pkt *pkt) |
| } |
| EXPORT_SYMBOL(cmdq_pkt_destroy); |
| |
| -static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, enum cmdq_code code, |
| - u32 arg_a, u32 arg_b) |
| +static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, s16 arg_c, s16 arg_b, |
| + s16 arg_a, u8 s_op, u8 arg_c_type, |
| + u8 arg_b_type, u8 arg_a_type, |
| + enum cmdq_code code) |
| { |
| - u64 *cmd_ptr; |
| |
| if (unlikely(pkt->cmd_buf_size + CMDQ_INST_SIZE > pkt->buf_size)) { |
| /* |
| @@ -129,77 +222,129 @@ static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, enum cmdq_code code, |
| __func__, (u32)pkt->buf_size); |
| return -ENOMEM; |
| } |
| - cmd_ptr = pkt->va_base + pkt->cmd_buf_size; |
| - (*cmd_ptr) = (u64)((code << CMDQ_OP_CODE_SHIFT) | arg_a) << 32 | arg_b; |
| - pkt->cmd_buf_size += CMDQ_INST_SIZE; |
| + cmdq_pkt_instr_encoder(pkt, arg_c, arg_b, arg_a, s_op, arg_c_type, |
| + arg_b_type, arg_a_type, code); |
| |
| return 0; |
| } |
| |
| -int cmdq_pkt_write(struct cmdq_pkt *pkt, u32 value, u32 subsys, u32 offset) |
| +int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value) |
| { |
| - u32 arg_a = (offset & CMDQ_ARG_A_WRITE_MASK) | |
| - (subsys << CMDQ_SUBSYS_SHIFT); |
| - |
| - return cmdq_pkt_append_command(pkt, CMDQ_CODE_WRITE, arg_a, value); |
| + return cmdq_pkt_append_command(pkt, CMDQ_GET_ARG_C(value), |
| + CMDQ_GET_ARG_B(value), offset, subsys, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, CMDQ_CODE_WRITE); |
| } |
| EXPORT_SYMBOL(cmdq_pkt_write); |
| |
| -int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u32 value, |
| - u32 subsys, u32 offset, u32 mask) |
| +int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys, u16 offset, |
| + u32 value, u32 mask) |
| { |
| u32 offset_mask = offset; |
| int err = 0; |
| |
| if (mask != 0xffffffff) { |
| - err = cmdq_pkt_append_command(pkt, CMDQ_CODE_MASK, 0, ~mask); |
| + err = cmdq_pkt_append_command(pkt, CMDQ_GET_ARG_C(~mask), |
| + CMDQ_GET_ARG_B(~mask), |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_CODE_MASK); |
| offset_mask |= CMDQ_WRITE_ENABLE_MASK; |
| } |
| - err |= cmdq_pkt_write(pkt, value, subsys, offset_mask); |
| + err |= cmdq_pkt_write(pkt, subsys, offset_mask, value); |
| |
| return err; |
| } |
| EXPORT_SYMBOL(cmdq_pkt_write_mask); |
| |
| -int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u32 event) |
| +int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event) |
| { |
| - u32 arg_b; |
| - |
| if (event >= CMDQ_MAX_EVENT) |
| return -EINVAL; |
| |
| - /* |
| - * WFE arg_b |
| - * bit 0-11: wait value |
| - * bit 15: 1 - wait, 0 - no wait |
| - * bit 16-27: update value |
| - * bit 31: 1 - update, 0 - no update |
| - */ |
| - arg_b = CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | CMDQ_WFE_WAIT_VALUE; |
| - |
| - return cmdq_pkt_append_command(pkt, CMDQ_CODE_WFE, event, arg_b); |
| + return cmdq_pkt_append_command(pkt, CMDQ_GET_ARG_C(CMDQ_WFE_OPTION), |
| + CMDQ_GET_ARG_B(CMDQ_WFE_OPTION), event, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_CODE_WFE); |
| } |
| EXPORT_SYMBOL(cmdq_pkt_wfe); |
| |
| -int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u32 event) |
| +int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event) |
| { |
| if (event >= CMDQ_MAX_EVENT) |
| return -EINVAL; |
| |
| - return cmdq_pkt_append_command(pkt, CMDQ_CODE_WFE, event, |
| - CMDQ_WFE_UPDATE); |
| + return cmdq_pkt_append_command(pkt, CMDQ_GET_ARG_C(CMDQ_WFE_UPDATE), |
| + CMDQ_GET_ARG_B(CMDQ_WFE_UPDATE), event, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_CODE_WFE); |
| } |
| EXPORT_SYMBOL(cmdq_pkt_clear_event); |
| |
| +int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys, |
| + u16 offset, u32 value, u32 mask) |
| +{ |
| + int err; |
| + |
| + if (mask != 0xffffffff) { |
| + err = cmdq_pkt_append_command(pkt, CMDQ_GET_ARG_C(~mask), |
| + CMDQ_GET_ARG_B(~mask), |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_CODE_MASK); |
| + |
| + if (err != 0) |
| + return err; |
| + } |
| + offset = offset | 0x1; |
| + |
| + return cmdq_pkt_append_command(pkt, CMDQ_GET_ARG_C(value), |
| + CMDQ_GET_ARG_B(value), |
| + offset, subsys, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_CODE_POLL); |
| +} |
| +EXPORT_SYMBOL(cmdq_pkt_poll); |
| + |
| static int cmdq_pkt_finalize(struct cmdq_pkt *pkt) |
| { |
| int err; |
| |
| /* insert EOC and generate IRQ for each command iteration */ |
| - err = cmdq_pkt_append_command(pkt, CMDQ_CODE_EOC, 0, CMDQ_EOC_IRQ_EN); |
| - |
| + err = cmdq_pkt_append_command(pkt, CMDQ_GET_ARG_C(CMDQ_EOC_IRQ_EN), |
| + CMDQ_GET_ARG_B(CMDQ_EOC_IRQ_EN), |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_CODE_EOC); |
| + if (err < 0) |
| + return err; |
| /* JUMP to end */ |
| - err |= cmdq_pkt_append_command(pkt, CMDQ_CODE_JUMP, 0, CMDQ_JUMP_PASS); |
| + err = cmdq_pkt_append_command(pkt, CMDQ_GET_ARG_C(CMDQ_JUMP_PASS), |
| + CMDQ_GET_ARG_B(CMDQ_JUMP_PASS), |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_IMMEDIATE_VALUE, |
| + CMDQ_CODE_JUMP); |
| |
| return err; |
| } |
| diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c |
| index ad0406bed698..3eaa37cefb90 100644 |
| --- a/drivers/thermal/mtk_thermal.c |
| +++ b/drivers/thermal/mtk_thermal.c |
| @@ -46,6 +46,7 @@ |
| #define TEMP_MONIDET0 0x014 |
| #define TEMP_MONIDET1 0x018 |
| #define TEMP_MSRCTL0 0x038 |
| +#define TEMP_MSRCTL1 0x03c |
| #define TEMP_AHBPOLL 0x040 |
| #define TEMP_AHBTO 0x044 |
| #define TEMP_ADCPNP0 0x048 |
| @@ -95,6 +96,9 @@ |
| #define TEMP_ADCVALIDMASK_VALID_HIGH BIT(5) |
| #define TEMP_ADCVALIDMASK_VALID_POS(bit) (bit) |
| |
| +#define TEMP_BUS_STA (BIT(1) | BIT(8)) |
| +#define TEMP_SENSING_POINTS_PAUSE 0x10E |
| + |
| /* MT8173 thermal sensors */ |
| #define MT8173_TS1 0 |
| #define MT8173_TS2 1 |
| @@ -266,6 +270,10 @@ struct mtk_thermal_data { |
| struct mtk_thermal { |
| struct device *dev; |
| void __iomem *thermal_base; |
| + void __iomem *apmixed_base; |
| + void __iomem *auxadc_base; |
| + u64 apmixed_phys_base; |
| + u64 auxadc_phys_base; |
| |
| struct clk *clk_peri_therm; |
| struct clk *clk_auxadc; |
| @@ -795,6 +803,52 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num, |
| mtk_thermal_put_bank(bank); |
| } |
| |
| +static int mtk_thermal_disable_sensing(struct mtk_thermal *mt, int num) |
| +{ |
| + struct mtk_thermal_bank *bank = &mt->banks[num]; |
| + u32 val; |
| + unsigned long timeout; |
| + bool expired; |
| + int ret = 0; |
| + |
| + bank->id = num; |
| + bank->mt = mt; |
| + |
| + mtk_thermal_get_bank(bank); |
| + |
| + /* wait until temperature measurement bus idle */ |
| + timeout = jiffies + HZ; |
| + expired = false; |
| + while (1) { |
| + val = readl(mt->thermal_base + TEMP_MSRCTL1); |
| + if ((val & TEMP_BUS_STA) == 0x0 || |
| + (val & TEMP_BUS_STA) == TEMP_BUS_STA) |
| + break; |
| + |
| + if (expired) { |
| + ret = -ETIMEDOUT; |
| + goto out; |
| + } |
| + |
| + cpu_relax(); |
| + |
| + if (time_after(jiffies, timeout)) |
| + expired = true; |
| + } |
| + |
| + /* pause periodic temperature measurement for sensing points */ |
| + writel(val | TEMP_SENSING_POINTS_PAUSE, |
| + mt->thermal_base + TEMP_MSRCTL1); |
| + |
| + /* disable periodic temperature meausrement on sensing points */ |
| + writel(0x0, mt->thermal_base + TEMP_MONCTL0); |
| + |
| +out: |
| + mtk_thermal_put_bank(bank); |
| + |
| + return ret; |
| +} |
| + |
| static u64 of_get_phys_base(struct device_node *np) |
| { |
| u64 size64; |
| @@ -917,7 +971,6 @@ static int mtk_thermal_probe(struct platform_device *pdev) |
| struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node; |
| struct mtk_thermal *mt; |
| struct resource *res; |
| - u64 auxadc_phys_base, apmixed_phys_base; |
| struct thermal_zone_device *tzdev; |
| struct mtk_thermal_zone *tz; |
| |
| @@ -954,11 +1007,12 @@ static int mtk_thermal_probe(struct platform_device *pdev) |
| return -ENODEV; |
| } |
| |
| - auxadc_phys_base = of_get_phys_base(auxadc); |
| + mt->auxadc_phys_base = of_get_phys_base(auxadc); |
| + mt->auxadc_base = of_iomap(auxadc, 0); |
| |
| of_node_put(auxadc); |
| |
| - if (auxadc_phys_base == OF_BAD_ADDR) { |
| + if (mt->auxadc_phys_base == OF_BAD_ADDR) { |
| dev_err(&pdev->dev, "Can't get auxadc phys address\n"); |
| return -EINVAL; |
| } |
| @@ -969,11 +1023,12 @@ static int mtk_thermal_probe(struct platform_device *pdev) |
| return -ENODEV; |
| } |
| |
| - apmixed_phys_base = of_get_phys_base(apmixedsys); |
| + mt->apmixed_phys_base = of_get_phys_base(apmixedsys); |
| + mt->apmixed_base = of_iomap(apmixedsys, 0); |
| |
| of_node_put(apmixedsys); |
| |
| - if (apmixed_phys_base == OF_BAD_ADDR) { |
| + if (mt->apmixed_phys_base == OF_BAD_ADDR) { |
| dev_err(&pdev->dev, "Can't get auxadc phys address\n"); |
| return -EINVAL; |
| } |
| @@ -985,19 +1040,19 @@ static int mtk_thermal_probe(struct platform_device *pdev) |
| ret = clk_prepare_enable(mt->clk_auxadc); |
| if (ret) { |
| dev_err(&pdev->dev, "Can't enable auxadc clk: %d\n", ret); |
| - return ret; |
| + goto err_disable_clk_auxadc; |
| } |
| |
| ret = clk_prepare_enable(mt->clk_peri_therm); |
| if (ret) { |
| dev_err(&pdev->dev, "Can't enable peri clk: %d\n", ret); |
| - goto err_disable_clk_auxadc; |
| + goto err_disable_clk_peri_therm; |
| } |
| |
| for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++) |
| for (i = 0; i < mt->conf->num_banks; i++) |
| - mtk_thermal_init_bank(mt, i, apmixed_phys_base, |
| - auxadc_phys_base, ctrl_id); |
| + mtk_thermal_init_bank(mt, i, mt->apmixed_phys_base, |
| + mt->auxadc_phys_base, ctrl_id); |
| |
| platform_set_drvdata(pdev, mt); |
| |
| @@ -1041,11 +1096,78 @@ static int mtk_thermal_remove(struct platform_device *pdev) |
| return 0; |
| } |
| |
| +static int __maybe_unused mtk_thermal_suspend(struct device *dev) |
| +{ |
| + struct platform_device *pdev = to_platform_device(dev); |
| + struct mtk_thermal *mt = platform_get_drvdata(pdev); |
| + int i, ret; |
| + |
| + for (i = 0; i < mt->conf->num_banks; i++) { |
| + ret = mtk_thermal_disable_sensing(mt, i); |
| + if (ret) |
| + goto out; |
| + } |
| + |
| + /* disable buffer */ |
| + writel(readl(mt->apmixed_base + APMIXED_SYS_TS_CON1) | 0x30, |
| + mt->apmixed_base + APMIXED_SYS_TS_CON1); |
| + |
| + clk_disable_unprepare(mt->clk_peri_therm); |
| + clk_disable_unprepare(mt->clk_auxadc); |
| + |
| + return 0; |
| + |
| +out: |
| + dev_err(&pdev->dev, "Failed to wait until bus idle\n"); |
| + |
| + return ret; |
| +} |
| + |
| +static int __maybe_unused mtk_thermal_resume(struct device *dev) |
| +{ |
| + struct platform_device *pdev = to_platform_device(dev); |
| + struct mtk_thermal *mt = platform_get_drvdata(pdev); |
| + int i, ret, ctrl_id; |
| + |
| + ret = device_reset(&pdev->dev); |
| + if (ret) |
| + return ret; |
| + |
| + ret = clk_prepare_enable(mt->clk_auxadc); |
| + if (ret) { |
| + dev_err(&pdev->dev, "Can't enable auxadc clk: %d\n", ret); |
| + goto err_disable_clk_auxadc; |
| + } |
| + |
| + ret = clk_prepare_enable(mt->clk_peri_therm); |
| + if (ret) { |
| + dev_err(&pdev->dev, "Can't enable peri clk: %d\n", ret); |
| + goto err_disable_clk_peri_therm; |
| + } |
| + |
| + for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++) |
| + for (i = 0; i < mt->conf->num_banks; i++) |
| + mtk_thermal_init_bank(mt, i, mt->apmixed_phys_base, |
| + mt->auxadc_phys_base, ctrl_id); |
| + return 0; |
| + |
| +err_disable_clk_peri_therm: |
| + clk_disable_unprepare(mt->clk_peri_therm); |
| +err_disable_clk_auxadc: |
| + clk_disable_unprepare(mt->clk_auxadc); |
| + |
| + return ret; |
| +} |
| + |
| +static SIMPLE_DEV_PM_OPS(mtk_thermal_pm_ops, |
| + mtk_thermal_suspend, mtk_thermal_resume); |
| + |
| static struct platform_driver mtk_thermal_driver = { |
| .probe = mtk_thermal_probe, |
| .remove = mtk_thermal_remove, |
| .driver = { |
| .name = "mtk-thermal", |
| + .pm = &mtk_thermal_pm_ops, |
| .of_match_table = mtk_thermal_of_match, |
| }, |
| }; |
| diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c |
| old mode 100644 |
| new mode 100755 |
| index 417c7c810df9..c201646f61b9 |
| --- a/drivers/tty/serial/8250/8250_mtk.c |
| +++ b/drivers/tty/serial/8250/8250_mtk.c |
| @@ -31,6 +31,7 @@ |
| #define MTK_UART_RXTRI_AD 0x14 /* RX Trigger address */ |
| #define MTK_UART_FRACDIV_L 0x15 /* Fractional divider LSB address */ |
| #define MTK_UART_FRACDIV_M 0x16 /* Fractional divider MSB address */ |
| +#define MTK_UART_DEBUG0 0x18 |
| #define MTK_UART_IER_XOFFI 0x20 /* Enable XOFF character interrupt */ |
| #define MTK_UART_IER_RTSI 0x40 /* Enable RTS Modem status interrupt */ |
| #define MTK_UART_IER_CTSI 0x80 /* Enable CTS Modem status interrupt */ |
| @@ -395,9 +396,18 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, |
| static int __maybe_unused mtk8250_runtime_suspend(struct device *dev) |
| { |
| struct mtk8250_data *data = dev_get_drvdata(dev); |
| + struct uart_8250_port *up = serial8250_get_port(data->line); |
| |
| - clk_disable_unprepare(data->uart_clk); |
| - clk_disable_unprepare(data->bus_clk); |
| + /*wait until UART in idle status*/ |
| + while |
| + (serial_in(up, MTK_UART_DEBUG0)); |
| + |
| + if (data->clk_count == 0U) |
| + dev_dbg(dev, "%s clock count is 0\n", __func__); |
| + else { |
| + clk_disable_unprepare(data->bus_clk); |
| + data->clk_count--; |
| + } |
| |
| return 0; |
| } |
| @@ -407,16 +417,16 @@ static int __maybe_unused mtk8250_runtime_resume(struct device *dev) |
| struct mtk8250_data *data = dev_get_drvdata(dev); |
| int err; |
| |
| - err = clk_prepare_enable(data->uart_clk); |
| - if (err) { |
| - dev_warn(dev, "Can't enable clock\n"); |
| - return err; |
| - } |
| - |
| - err = clk_prepare_enable(data->bus_clk); |
| - if (err) { |
| - dev_warn(dev, "Can't enable bus clock\n"); |
| - return err; |
| + if (data->clk_count > 0U) |
| + dev_dbg(dev, "%s clock count is %d\n", __func__, |
| + data->clk_count); |
| + else { |
| + err = clk_prepare_enable(data->bus_clk); |
| + if (err) { |
| + dev_warn(dev, "Can't enable bus clock\n"); |
| + return err; |
| + } |
| + data->clk_count++; |
| } |
| |
| return 0; |
| @@ -426,12 +436,14 @@ static void |
| mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) |
| { |
| if (!state) |
| - pm_runtime_get_sync(port->dev); |
| + if (!mtk8250_runtime_resume(port->dev)) |
| + pm_runtime_get_sync(port->dev); |
| |
| serial8250_do_pm(port, state, old); |
| |
| if (state) |
| - pm_runtime_put_sync_suspend(port->dev); |
| + if (!pm_runtime_put_sync_suspend(port->dev)) |
| + mtk8250_runtime_suspend(port->dev); |
| } |
| |
| #ifdef CONFIG_SERIAL_8250_DMA |
| @@ -508,6 +520,8 @@ static int mtk8250_probe(struct platform_device *pdev) |
| if (!data) |
| return -ENOMEM; |
| |
| + data->clk_count = 0; |
| + |
| if (pdev->dev.of_node) { |
| err = mtk8250_probe_of(pdev, &uart.port, data); |
| if (err) |
| @@ -540,6 +554,7 @@ static int mtk8250_probe(struct platform_device *pdev) |
| |
| platform_set_drvdata(pdev, data); |
| |
| + pm_runtime_enable(&pdev->dev); |
| err = mtk8250_runtime_resume(&pdev->dev); |
| if (err) |
| return err; |
| @@ -548,9 +563,6 @@ static int mtk8250_probe(struct platform_device *pdev) |
| if (data->line < 0) |
| return data->line; |
| |
| - pm_runtime_set_active(&pdev->dev); |
| - pm_runtime_enable(&pdev->dev); |
| - |
| return 0; |
| } |
| |
| @@ -561,11 +573,13 @@ static int mtk8250_remove(struct platform_device *pdev) |
| pm_runtime_get_sync(&pdev->dev); |
| |
| serial8250_unregister_port(data->line); |
| - mtk8250_runtime_suspend(&pdev->dev); |
| |
| pm_runtime_disable(&pdev->dev); |
| pm_runtime_put_noidle(&pdev->dev); |
| |
| + if (!pm_runtime_status_suspended(&pdev->dev)) |
| + mtk8250_runtime_suspend(&pdev->dev); |
| + |
| return 0; |
| } |
| |
| diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c |
| index 48d10a61e271..542b67a6b5a6 100644 |
| --- a/drivers/usb/mtu3/mtu3_core.c |
| +++ b/drivers/usb/mtu3/mtu3_core.c |
| @@ -94,6 +94,7 @@ static int mtu3_device_enable(struct mtu3 *mtu) |
| { |
| void __iomem *ibase = mtu->ippc_base; |
| u32 check_clk = 0; |
| + struct ssusb_mtk *ssusb = mtu->ssusb; |
| |
| mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); |
| |
| @@ -107,7 +108,7 @@ static int mtu3_device_enable(struct mtu3 *mtu) |
| (SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN | |
| SSUSB_U2_PORT_HOST_SEL)); |
| |
| - if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG) { |
| + if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG && !ssusb->otg_switch.manual_drd_enabled) { |
| mtu3_setbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL); |
| if (mtu->is_u3_ip) |
| mtu3_setbits(ibase, SSUSB_U3_CTRL(0), |
| @@ -120,6 +121,7 @@ static int mtu3_device_enable(struct mtu3 *mtu) |
| static void mtu3_device_disable(struct mtu3 *mtu) |
| { |
| void __iomem *ibase = mtu->ippc_base; |
| + struct ssusb_mtk *ssusb = mtu->ssusb; |
| |
| if (mtu->is_u3_ip) |
| mtu3_setbits(ibase, SSUSB_U3_CTRL(0), |
| @@ -128,7 +130,7 @@ static void mtu3_device_disable(struct mtu3 *mtu) |
| mtu3_setbits(ibase, SSUSB_U2_CTRL(0), |
| SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN); |
| |
| - if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG) |
| + if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG && !ssusb->otg_switch.manual_drd_enabled) |
| mtu3_clrbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL); |
| |
| mtu3_setbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); |
| @@ -183,6 +185,9 @@ static void mtu3_intr_enable(struct mtu3 *mtu) |
| value = SUSPEND_INTR | RESUME_INTR | RESET_INTR | LPM_RESUME_INTR; |
| mtu3_writel(mbase, U3D_COMMON_USB_INTR_ENABLE, value); |
| |
| + mtu3_clrbits(mbase, U3D_DEVICE_CONTROL, DC_SESSION); |
| + mtu3_setbits(mbase, U3D_MISC_CTRL, VBUS_FRC_EN | VBUS_ON); |
| + |
| if (mtu->is_u3_ip) { |
| /* Enable U3 LTSSM interrupts */ |
| value = HOT_RST_INTR | WARM_RST_INTR | VBUS_RISE_INTR | |
| @@ -759,7 +764,10 @@ static int mtu3_hw_init(struct mtu3 *mtu) |
| mtu->hw_version = mtu3_readl(mtu->ippc_base, U3D_SSUSB_HW_ID); |
| |
| cap_dev = mtu3_readl(mtu->ippc_base, U3D_SSUSB_IP_DEV_CAP); |
| - mtu->is_u3_ip = !!SSUSB_IP_DEV_U3_PORT_NUM(cap_dev); |
| + if (mtu->max_speed <= USB_SPEED_HIGH) |
| + mtu->is_u3_ip = 0; |
| + else |
| + mtu->is_u3_ip = !!SSUSB_IP_DEV_U3_PORT_NUM(cap_dev); |
| |
| dev_info(mtu->dev, "IP version 0x%x(%s IP)\n", mtu->hw_version, |
| mtu->is_u3_ip ? "U3" : "U2"); |
| diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c |
| index ac60e9c8564e..7660d107e5bc 100644 |
| --- a/drivers/usb/mtu3/mtu3_dr.c |
| +++ b/drivers/usb/mtu3/mtu3_dr.c |
| @@ -401,7 +401,7 @@ void ssusb_set_force_mode(struct ssusb_mtk *ssusb, |
| break; |
| case MTU3_DR_FORCE_HOST: |
| value |= SSUSB_U2_PORT_FORCE_IDDIG; |
| - value &= ~SSUSB_U2_PORT_RG_IDDIG; |
| + value &= ~(SSUSB_U2_PORT_RG_IDDIG | SSUSB_U2_PORT_OTG_SEL); |
| break; |
| case MTU3_DR_FORCE_NONE: |
| value &= ~(SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG); |
| diff --git a/include/dt-bindings/gce/mt8183-gce.h b/include/dt-bindings/gce/mt8183-gce.h |
| new file mode 100644 |
| index 000000000000..aeb95154fac2 |
| --- /dev/null |
| +++ b/include/dt-bindings/gce/mt8183-gce.h |
| @@ -0,0 +1,177 @@ |
| +/* SPDX-License-Identifier: GPL-2.0 */ |
| +/* |
| + * Copyright (c) 2019 MediaTek Inc. |
| + * Author: Bibby Hsieh <bibby.hsieh@mediatek.com> |
| + * |
| + */ |
| + |
| +#ifndef _DT_BINDINGS_GCE_MT8183_H |
| +#define _DT_BINDINGS_GCE_MT8183_H |
| + |
| +#define CMDQ_NO_TIMEOUT 0xffffffff |
| + |
| +#define CMDQ_THR_MAX_COUNT 24 |
| + |
| +/* GCE HW thread priority */ |
| +#define CMDQ_THR_PRIO_LOWEST 0 |
| +#define CMDQ_THR_PRIO_HIGHEST 1 |
| + |
| +/* GCE SUBSYS */ |
| +#define SUBSYS_1300XXXX 0 |
| +#define SUBSYS_1400XXXX 1 |
| +#define SUBSYS_1401XXXX 2 |
| +#define SUBSYS_1402XXXX 3 |
| +#define SUBSYS_1502XXXX 4 |
| +#define SUBSYS_1880XXXX 5 |
| +#define SUBSYS_1881XXXX 6 |
| +#define SUBSYS_1882XXXX 7 |
| +#define SUBSYS_1883XXXX 8 |
| +#define SUBSYS_1884XXXX 9 |
| +#define SUBSYS_1000XXXX 10 |
| +#define SUBSYS_1001XXXX 11 |
| +#define SUBSYS_1002XXXX 12 |
| +#define SUBSYS_1003XXXX 13 |
| +#define SUBSYS_1004XXXX 14 |
| +#define SUBSYS_1005XXXX 15 |
| +#define SUBSYS_1020XXXX 16 |
| +#define SUBSYS_1028XXXX 17 |
| +#define SUBSYS_1700XXXX 18 |
| +#define SUBSYS_1701XXXX 19 |
| +#define SUBSYS_1702XXXX 20 |
| +#define SUBSYS_1703XXXX 21 |
| +#define SUBSYS_1800XXXX 22 |
| +#define SUBSYS_1801XXXX 23 |
| +#define SUBSYS_1802XXXX 24 |
| +#define SUBSYS_1804XXXX 25 |
| +#define SUBSYS_1805XXXX 26 |
| +#define SUBSYS_1808XXXX 27 |
| +#define SUBSYS_180aXXXX 28 |
| +#define SUBSYS_180bXXXX 29 |
| + |
| +#define CMDQ_EVENT_DISP_RDMA0_SOF 0 |
| +#define CMDQ_EVENT_DISP_RDMA1_SOF 1 |
| +#define CMDQ_EVENT_MDP_RDMA0_SOF 2 |
| +#define CMDQ_EVENT_MDP_RSZ0_SOF 4 |
| +#define CMDQ_EVENT_MDP_RSZ1_SOF 5 |
| +#define CMDQ_EVENT_MDP_TDSHP_SOF 6 |
| +#define CMDQ_EVENT_MDP_WROT0_SOF 7 |
| +#define CMDQ_EVENT_MDP_WDMA0_SOF 8 |
| +#define CMDQ_EVENT_DISP_OVL0_SOF 9 |
| +#define CMDQ_EVENT_DISP_OVL0_2L_SOF 10 |
| +#define CMDQ_EVENT_DISP_OVL1_2L_SOF 11 |
| +#define CMDQ_EVENT_DISP_WDMA0_SOF 12 |
| +#define CMDQ_EVENT_DISP_COLOR0_SOF 13 |
| +#define CMDQ_EVENT_DISP_CCORR0_SOF 14 |
| +#define CMDQ_EVENT_DISP_AAL0_SOF 15 |
| +#define CMDQ_EVENT_DISP_GAMMA0_SOF 16 |
| +#define CMDQ_EVENT_DISP_DITHER0_SOF 17 |
| +#define CMDQ_EVENT_DISP_PWM0_SOF 18 |
| +#define CMDQ_EVENT_DISP_DSI0_SOF 19 |
| +#define CMDQ_EVENT_DISP_DPI0_SOF 20 |
| +#define CMDQ_EVENT_DISP_RSZ_SOF 22 |
| +#define CMDQ_EVENT_MDP_AAL_SOF 23 |
| +#define CMDQ_EVENT_MDP_CCORR_SOF 24 |
| +#define CMDQ_EVENT_DISP_DBI_SOF 25 |
| +#define CMDQ_EVENT_DISP_RDMA0_EOF 26 |
| +#define CMDQ_EVENT_DISP_RDMA1_EOF 27 |
| +#define CMDQ_EVENT_MDP_RDMA0_EOF 28 |
| +#define CMDQ_EVENT_MDP_RSZ0_EOF 30 |
| +#define CMDQ_EVENT_MDP_RSZ1_EOF 31 |
| +#define CMDQ_EVENT_MDP_TDSHP_EOF 32 |
| +#define CMDQ_EVENT_MDP_WROT0_EOF 33 |
| +#define CMDQ_EVENT_MDP_WDMA0_EOF 34 |
| +#define CMDQ_EVENT_DISP_OVL0_EOF 35 |
| +#define CMDQ_EVENT_DISP_OVL0_2L_EOF 36 |
| +#define CMDQ_EVENT_DISP_OVL1_2L_EOF 37 |
| +#define CMDQ_EVENT_DISP_WDMA0_EOF 38 |
| +#define CMDQ_EVENT_DISP_COLOR0_EOF 39 |
| +#define CMDQ_EVENT_DISP_CCORR0_EOF 40 |
| +#define CMDQ_EVENT_DISP_AAL0_EOF 41 |
| +#define CMDQ_EVENT_DISP_GAMMA0_EOF 42 |
| +#define CMDQ_EVENT_DISP_DITHER0_EOF 43 |
| +#define CMDQ_EVENT_DSI0_EOF 44 |
| +#define CMDQ_EVENT_DPI0_EOF 45 |
| +#define CMDQ_EVENT_DISP_RSZ_EOF 47 |
| +#define CMDQ_EVENT_MDP_AAL_EOF 48 |
| +#define CMDQ_EVENT_MDP_CCORR_EOF 49 |
| +#define CMDQ_EVENT_DBI_EOF 50 |
| +#define CMDQ_EVENT_MUTEX_STREAM_DONE0 130 |
| +#define CMDQ_EVENT_MUTEX_STREAM_DONE1 131 |
| +#define CMDQ_EVENT_MUTEX_STREAM_DONE2 132 |
| +#define CMDQ_EVENT_MUTEX_STREAM_DONE3 133 |
| +#define CMDQ_EVENT_MUTEX_STREAM_DONE4 134 |
| +#define CMDQ_EVENT_MUTEX_STREAM_DONE5 135 |
| +#define CMDQ_EVENT_MUTEX_STREAM_DONE6 136 |
| +#define CMDQ_EVENT_MUTEX_STREAM_DONE7 137 |
| +#define CMDQ_EVENT_MUTEX_STREAM_DONE8 138 |
| +#define CMDQ_EVENT_MUTEX_STREAM_DONE9 139 |
| +#define CMDQ_EVENT_MUTEX_STREAM_DONE10 140 |
| +#define CMDQ_EVENT_MUTEX_STREAM_DONE11 141 |
| +#define CMDQ_EVENT_DISP_RDMA0_BUF_UNDERRUN_EVEN 142 |
| +#define CMDQ_EVENT_DISP_RDMA1_BUF_UNDERRUN_EVEN 143 |
| +#define CMDQ_EVENT_DSI0_TE_EVENT 144 |
| +#define CMDQ_EVENT_DSI0_IRQ_EVENT 145 |
| +#define CMDQ_EVENT_DSI0_DONE_EVENT 146 |
| +#define CMDQ_EVENT_DISP_WDMA0_SW_RST_DONE 150 |
| +#define CMDQ_EVENT_MDP_WDMA_SW_RST_DONE 151 |
| +#define CMDQ_EVENT_MDP_WROT0_SW_RST_DONE 152 |
| +#define CMDQ_EVENT_MDP_RDMA0_SW_RST_DONE 154 |
| +#define CMDQ_EVENT_DISP_OVL0_FRAME_RST_DONE_PULE 155 |
| +#define CMDQ_EVENT_DISP_OVL0_2L_FRAME_RST_DONE_ULSE 156 |
| +#define CMDQ_EVENT_DISP_OVL1_2L_FRAME_RST_DONE_ULSE 157 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_0 257 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_1 258 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_2 259 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_3 260 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_4 261 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_5 262 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_6 263 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_7 264 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_8 265 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_9 266 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_10 267 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_11 268 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_12 269 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_13 270 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_14 271 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_15 272 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_16 273 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_17 274 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_P2_18 275 |
| +#define CMDQ_EVENT_AMD_FRAME_DONE 276 |
| +#define CMDQ_EVENT_DVE_DONE 277 |
| +#define CMDQ_EVENT_WMFE_DONE 278 |
| +#define CMDQ_EVENT_RSC_DONE 279 |
| +#define CMDQ_EVENT_MFB_DONE 280 |
| +#define CMDQ_EVENT_WPE_A_DONE 281 |
| +#define CMDQ_EVENT_SPE_B_DONE 282 |
| +#define CMDQ_EVENT_OCC_DONE 283 |
| +#define CMDQ_EVENT_VENC_CMDQ_FRAME_DONE 289 |
| +#define CMDQ_EVENT_JPG_ENC_CMDQ_DONE 290 |
| +#define CMDQ_EVENT_JPG_DEC_CMDQ_DONE 291 |
| +#define CMDQ_EVENT_VENC_CMDQ_MB_DONE 292 |
| +#define CMDQ_EVENT_VENC_CMDQ_128BYTE_DONE 293 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_A 321 |
| +#define CMDQ_EVENT_ISP_FRAME_DONE_B 322 |
| +#define CMDQ_EVENT_CAMSV0_PASS1_DONE 323 |
| +#define CMDQ_EVENT_CAMSV1_PASS1_DONE 324 |
| +#define CMDQ_EVENT_CAMSV2_PASS1_DONE 325 |
| +#define CMDQ_EVENT_TSF_DONE 326 |
| +#define CMDQ_EVENT_SENINF_CAM0_FIFO_FULL 327 |
| +#define CMDQ_EVENT_SENINF_CAM1_FIFO_FULL 328 |
| +#define CMDQ_EVENT_SENINF_CAM2_FIFO_FULL 329 |
| +#define CMDQ_EVENT_SENINF_CAM3_FIFO_FULL 330 |
| +#define CMDQ_EVENT_SENINF_CAM4_FIFO_FULL 331 |
| +#define CMDQ_EVENT_SENINF_CAM5_FIFO_FULL 332 |
| +#define CMDQ_EVENT_SENINF_CAM6_FIFO_FULL 333 |
| +#define CMDQ_EVENT_SENINF_CAM7_FIFO_FULL 334 |
| +#define CMDQ_EVENT_IPU_CORE0_DONE0 353 |
| +#define CMDQ_EVENT_IPU_CORE0_DONE1 354 |
| +#define CMDQ_EVENT_IPU_CORE0_DONE2 355 |
| +#define CMDQ_EVENT_IPU_CORE0_DONE3 356 |
| +#define CMDQ_EVENT_IPU_CORE1_DONE0 385 |
| +#define CMDQ_EVENT_IPU_CORE1_DONE1 386 |
| +#define CMDQ_EVENT_IPU_CORE1_DONE2 387 |
| +#define CMDQ_EVENT_IPU_CORE1_DONE3 388 |
| + |
| +#endif |
| diff --git a/include/linux/mailbox/mtk-cmdq-mailbox.h b/include/linux/mailbox/mtk-cmdq-mailbox.h |
| index ccb73422c2fa..1dfd5ed5c8c5 100644 |
| --- a/include/linux/mailbox/mtk-cmdq-mailbox.h |
| +++ b/include/linux/mailbox/mtk-cmdq-mailbox.h |
| @@ -19,6 +19,10 @@ |
| #define CMDQ_WFE_UPDATE BIT(31) |
| #define CMDQ_WFE_WAIT BIT(15) |
| #define CMDQ_WFE_WAIT_VALUE 0x1 |
| +#define CMDQ_WFE_OPTION (CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | \ |
| + CMDQ_WFE_WAIT_VALUE) |
| +/** cmdq event maximum */ |
| +#define CMDQ_MAX_EVENT 0x3ff |
| |
| /* |
| * CMDQ_CODE_MASK: |
| @@ -42,6 +46,7 @@ |
| enum cmdq_code { |
| CMDQ_CODE_MASK = 0x02, |
| CMDQ_CODE_WRITE = 0x04, |
| + CMDQ_CODE_POLL = 0x08, |
| CMDQ_CODE_JUMP = 0x10, |
| CMDQ_CODE_WFE = 0x20, |
| CMDQ_CODE_EOC = 0x40, |
| diff --git a/include/linux/soc/mediatek/mtk-cmdq.h b/include/linux/soc/mediatek/mtk-cmdq.h |
| index 54ade13a9b15..15884354af20 100644 |
| --- a/include/linux/soc/mediatek/mtk-cmdq.h |
| +++ b/include/linux/soc/mediatek/mtk-cmdq.h |
| @@ -13,11 +13,14 @@ |
| |
| #define CMDQ_NO_TIMEOUT 0xffffffffu |
| |
| -/** cmdq event maximum */ |
| -#define CMDQ_MAX_EVENT 0x3ff |
| - |
| struct cmdq_pkt; |
| |
| +struct cmdq_subsys { |
| + u8 id; |
| + u16 offset; |
| + u16 size; |
| +}; |
| + |
| struct cmdq_client { |
| spinlock_t lock; |
| u32 pkt_cnt; |
| @@ -63,26 +66,26 @@ void cmdq_pkt_destroy(struct cmdq_pkt *pkt); |
| /** |
| * cmdq_pkt_write() - append write command to the CMDQ packet |
| * @pkt: the CMDQ packet |
| - * @value: the specified target register value |
| * @subsys: the CMDQ sub system code |
| * @offset: register offset from CMDQ sub system |
| + * @value: the specified target register value |
| * |
| * Return: 0 for success; else the error code is returned |
| */ |
| -int cmdq_pkt_write(struct cmdq_pkt *pkt, u32 value, u32 subsys, u32 offset); |
| +int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value); |
| |
| /** |
| * cmdq_pkt_write_mask() - append write command with mask to the CMDQ packet |
| * @pkt: the CMDQ packet |
| - * @value: the specified target register value |
| * @subsys: the CMDQ sub system code |
| * @offset: register offset from CMDQ sub system |
| + * @value: the specified target register value |
| * @mask: the specified target register mask |
| * |
| * Return: 0 for success; else the error code is returned |
| */ |
| -int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u32 value, |
| - u32 subsys, u32 offset, u32 mask); |
| +int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys, u16 offset, |
| + u32 value, u32 mask); |
| |
| /** |
| * cmdq_pkt_wfe() - append wait for event command to the CMDQ packet |
| @@ -91,7 +94,7 @@ int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u32 value, |
| * |
| * Return: 0 for success; else the error code is returned |
| */ |
| -int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u32 event); |
| +int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event); |
| |
| /** |
| * cmdq_pkt_clear_event() - append clear event command to the CMDQ packet |
| @@ -100,8 +103,23 @@ int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u32 event); |
| * |
| * Return: 0 for success; else the error code is returned |
| */ |
| -int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u32 event); |
| +int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event); |
| |
| +/** |
| + * cmdq_pkt_poll() - Append polling command to the CMDQ packet, ask GCE to |
| + * execute an instruction that wait for a specified hardware |
| + * register to check for the value. All GCE hardware |
| + * threads will be blocked by this instruction. |
| + * @pkt: the CMDQ packet |
| + * @subsys: the CMDQ sub system code |
| + * @offset: register offset from CMDQ sub system |
| + * @value: the specified target register value |
| + * @mask: the specified target register mask |
| + * |
| + * Return: 0 for success; else the error code is returned |
| + */ |
| +int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys, |
| + u16 offset, u32 value, u32 mask); |
| /** |
| * cmdq_pkt_flush_async() - trigger CMDQ to asynchronously execute the CMDQ |
| * packet and call back at the end of done packet |
| @@ -130,4 +148,28 @@ int cmdq_pkt_flush_async(struct cmdq_pkt *pkt, cmdq_async_flush_cb cb, |
| */ |
| int cmdq_pkt_flush(struct cmdq_pkt *pkt); |
| |
| +/** |
| + * cmdq_dev_get_subsys() - parse sub system from the device node of CMDQ client |
| + * @dev: device of CMDQ mailbox client |
| + * @idx: the index of desired subsys |
| + * |
| + * Return: CMDQ subsys pointer |
| + * |
| + * Help CMDQ client pasing the sub system number |
| + * from the device node of CMDQ client. |
| + */ |
| +struct cmdq_subsys *cmdq_dev_get_subsys(struct device *dev, int idx); |
| + |
| +/** |
| + * cmdq_dev_get_event() - parse event from the device node of CMDQ client |
| + * @dev: device of CMDQ mailbox client |
| + * @name: the name of desired event |
| + * |
| + * Return: CMDQ event number |
| + * |
| + * Help CMDQ client pasing the event number |
| + * from the device node of CMDQ client. |
| + */ |
| +s32 cmdq_dev_get_event(struct device *dev, const char *name); |
| + |
| #endif /* __MTK_CMDQ_H__ */ |
| diff --git a/include/soc/mediatek/emi.h b/include/soc/mediatek/emi.h |
| new file mode 100644 |
| index 000000000000..83bdaeb6840b |
| --- /dev/null |
| +++ b/include/soc/mediatek/emi.h |
| @@ -0,0 +1,116 @@ |
| +/* SPDX-License-Identifier: GPL-2.0 */ |
| +/* |
| + * Copyright (c) 2015-2016 MediaTek Inc. |
| + * Author: Xi Chen <xixi.chen@mediatek.com> |
| + */ |
| + |
| +#ifndef _MTK_EMI_H_ |
| +#define _MTK_EMI_H_ |
| + |
| +#define MAX_CH 2 |
| +#define MAX_RK 2 |
| + |
| +struct emi_info_t { |
| + unsigned int dram_type; |
| + unsigned int ch_num; |
| + unsigned int rk_num; |
| + unsigned int rank_size[MAX_RK]; |
| +}; |
| + |
| +/***************************************************************************** |
| + * Macro Definiations |
| + *****************************************************************************/ |
| +#define EMI_REG_BASE (0x10219000) |
| +#define EMI_REG_BASE_MAPPED (emi->cen_emi_base) |
| + |
| +#define EMI_MDCT (EMI_REG_BASE_MAPPED + 0x078) |
| +#define EMI_MDCT_2ND (EMI_REG_BASE_MAPPED + 0x07C) |
| + |
| +#define EMI_ARBA (EMI_REG_BASE_MAPPED + 0x100) |
| +#define EMI_ARBB (EMI_REG_BASE_MAPPED + 0x108) |
| +#define EMI_ARBC (EMI_REG_BASE_MAPPED + 0x110) |
| +#define EMI_ARBD (EMI_REG_BASE_MAPPED + 0x118) |
| +#define EMI_ARBE (EMI_REG_BASE_MAPPED + 0x120) |
| +#define EMI_ARBF (EMI_REG_BASE_MAPPED + 0x128) |
| +#define EMI_ARBG (EMI_REG_BASE_MAPPED + 0x130) |
| +#define EMI_ARBH (EMI_REG_BASE_MAPPED + 0x138) |
| + |
| +#define EMI_BMEN (EMI_REG_BASE_MAPPED + 0x400) |
| +#define EMI_BCNT (EMI_REG_BASE_MAPPED + 0x408) |
| +#define EMI_TACT (EMI_REG_BASE_MAPPED + 0x410) |
| +#define EMI_TSCT (EMI_REG_BASE_MAPPED + 0x418) |
| +#define EMI_WACT (EMI_REG_BASE_MAPPED + 0x420) |
| +#define EMI_WSCT (EMI_REG_BASE_MAPPED + 0x428) |
| +#define EMI_BACT (EMI_REG_BASE_MAPPED + 0x430) |
| +#define EMI_BSCT (EMI_REG_BASE_MAPPED + 0x438) |
| +#define EMI_MSEL (EMI_REG_BASE_MAPPED + 0x440) |
| +#define EMI_TSCT2 (EMI_REG_BASE_MAPPED + 0x448) |
| +#define EMI_TSCT3 (EMI_REG_BASE_MAPPED + 0x450) |
| +#define EMI_WSCT2 (EMI_REG_BASE_MAPPED + 0x458) |
| +#define EMI_WSCT3 (EMI_REG_BASE_MAPPED + 0x460) |
| +#define EMI_WSCT4 (EMI_REG_BASE_MAPPED + 0x464) |
| +#define EMI_MSEL2 (EMI_REG_BASE_MAPPED + 0x468) |
| + |
| +#define EMI_BMEN2 (EMI_REG_BASE_MAPPED + 0x4E8) |
| + |
| +#define EMI_BMRW0 (EMI_REG_BASE_MAPPED + 0x4F8) |
| + |
| +#define EMI_TTYPE1 (EMI_REG_BASE_MAPPED + 0x500) |
| +#define EMI_TTYPE17 (EMI_REG_BASE_MAPPED + 0x580) |
| + |
| +#define EMI_BWVL (EMI_REG_BASE_MAPPED + 0x7D0) |
| +#define EMI_BWVL_2ND (EMI_REG_BASE_MAPPED + 0x7D4) |
| +#define EMI_BWVL_3RD (EMI_REG_BASE_MAPPED + 0x7D8) |
| +#define EMI_BWVL_4TH (EMI_REG_BASE_MAPPED + 0x7DC) |
| +#define EMI_BWVL_5TH (EMI_REG_BASE_MAPPED + 0x7E0) |
| + |
| +#define EMI_CH0_REG_BASE (0x1022D000) |
| +#define EMI_CH0_REG_BASE_MAPPED (emi->chn_emi_base[0]) |
| +#define EMI_CH0_DRS_ST2 (EMI_CH0_REG_BASE_MAPPED + 0x17C) |
| +#define EMI_CH0_DRS_ST3 (EMI_CH0_REG_BASE_MAPPED + 0x180) |
| +#define EMI_CH0_DRS_ST4 (EMI_CH0_REG_BASE_MAPPED + 0x184) |
| + |
| +#define EMI_CH1_REG_BASE (0x10235000) |
| +#define EMI_CH1_REG_BASE_MAPPED (emi->chn_emi_base[1]) |
| +#define EMI_CH1_DRS_ST2 (EMI_CH1_REG_BASE_MAPPED + 0x17C) |
| +#define EMI_CH1_DRS_ST3 (EMI_CH1_REG_BASE_MAPPED + 0x180) |
| +#define EMI_CH1_DRS_ST4 (EMI_CH1_REG_BASE_MAPPED + 0x184) |
| + |
| +/* |
| + * DEFAULT_VALUE |
| + */ |
| +#define EMI_BMEN_DEFAULT_VALUE (0x00FF0000) |
| +#define EMI_BMEN2_DEFAULT_VALUE (0x02000000) |
| +#define EMI_BMRW0_DEFAULT_VALUE (0xFFFFFFFF) |
| +#define EMI_MSEL_DEFAULT_VALUE (0x00030024) |
| +#define EMI_MSEL2_DEFAULT_VALUE (0x000000C0) |
| +#define BC_OVERRUN (0x00000100) |
| + |
| +/* EMI_BMEN */ |
| +#define BUS_MON_EN BIT(0) |
| +#define BUS_MON_PAUSE BIT(1) |
| +#define BUS_MON_IDLE BIT(3) |
| + |
| +#define MAX_DRAM_CH_NUM (2) |
| +#define DRAM_RANK_NUM (2) |
| +#define DRAM_PDIR_NUM (8) |
| +#define EMI_TTYPE_NUM (21) |
| +#define EMI_TSCT_NUM (3) |
| +#define EMI_MDCT_NUM (2) |
| +#define EMI_DRS_ST_NUM (3) |
| +#define EMI_BW_LIMIT_NUM (8) |
| + |
| +#define DRAMC_CG_SHIFT (9) |
| + |
| +#define EMI_IDX_SIZE (1024) |
| + |
| +#define EMI_BWVL_UNIT (271) |
| + |
| +#define MBW_BUF_LEN (0x800000) |
| +#define DATA_CNT_PER_BLK (35) |
| +#define BLK_CNT_PER_BUF (0x800) |
| + |
| +/* public apis */ |
| +unsigned long long emi_get_max_bw(void); |
| + |
| +#endif |
| diff --git a/include/soc/mediatek/smi.h b/include/soc/mediatek/smi.h |
| index 7a8d87051ee8..609397d69602 100644 |
| --- a/include/soc/mediatek/smi.h |
| +++ b/include/soc/mediatek/smi.h |
| @@ -24,26 +24,6 @@ struct mtk_smi_iommu { |
| struct mtk_smi_larb_iommu larb_imu[MTK_LARB_NR_MAX]; |
| }; |
| |
| -/* |
| - * mtk_smi_larb_get: Enable the power domain and clocks for this local arbiter. |
| - * It also initialize some basic setting(like iommu). |
| - * mtk_smi_larb_put: Disable the power domain and clocks for this local arbiter. |
| - * Both should be called in non-atomic context. |
| - * |
| - * Returns 0 if successful, negative on failure. |
| - */ |
| -int mtk_smi_larb_get(struct device *larbdev); |
| -void mtk_smi_larb_put(struct device *larbdev); |
| - |
| -#else |
| - |
| -static inline int mtk_smi_larb_get(struct device *larbdev) |
| -{ |
| - return 0; |
| -} |
| - |
| -static inline void mtk_smi_larb_put(struct device *larbdev) { } |
| - |
| #endif |
| |
| #endif |
| -- |
| 2.20.1 |
| |