blob: 8e41f61fde8543bdaf914e5e86aea8745520286e [file] [log] [blame]
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(&reg, 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(&reg, &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(&reg, &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(&reg, &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