Compare commits

...
51 Commits
Author SHA1 Message Date
tmakin bd7511b3e8 drm/tegra: dsi: detect possible_crtcs
Other platforms allow dsi across multiple heads, but some have
one or more heads disabled. This results in a mismatch between
possible_crtcs and the real crtc mask. Apply the same
`tegra_output_find_possible_crtcs` function to DSI to properly
detect.
2026-08-24 18:39:46 -05:00
Alex Frid 6f93d204b3 soc: tegra: Add support for DFLL Vmin CVB
Added Vmin coefficients to CPU DFLL CVB table, and updated Vmin
calculations during OPP table build accordingly. Changed build function
signature to return final Vmin.

Bug 1906940

Change-Id: I6e19266f865e9a3dda21c9e0f7178feece055ddf
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1565468
Reviewed-by: Peter De Schrijver <pdeschrijver@nvidia.com>
Tested-by: Peter De Schrijver <pdeschrijver@nvidia.com>
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: Timo Alho <talho@nvidia.com>
2026-08-24 18:39:46 -05:00
Alex Frid 7a7ebd4523 clk: soc: tegra: Add DFLL tune high margin voltage
Added DFLL tune high margin voltage entry in CVB table. This allows to
replace current fixed margin defined as number of DFLL voltage steps
with per-table/per-chip margin in millivolts, and convert it to steps
during DFLL initialization.

Bug 1967884

Change-Id: I56268ae2faf9cc633b9f988cacbfd0ea3ba77ff3
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1576307
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
2026-08-24 18:39:45 -05:00
Alex Frid ff35a431be clk: soc: tegra: Add DFLL tune1_high parameter
Added support for DFLL tune1_high parameter

Bug 1967884

Change-Id: I0140724a22c43a3b05d39735b7a7faebd4be2908
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1577129
Reviewed-by: Peter De Schrijver <pdeschrijver@nvidia.com>
Tested-by: Peter De Schrijver <pdeschrijver@nvidia.com>
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
2026-08-24 18:39:45 -05:00
tmakin 8f2bbc2e1c clk: tegra: add locking support to DFLL
Based on part of https://gitlab.com/nvidia/nv-tegra/linux-4.9/-/commit/4f0b1e6e76f7b0ff8d028c66d34da9f37ca39233
2026-08-24 18:39:45 -05:00
Alex Frid 44d55b9a98 clk: soc: tegra: Rename DFLL tune1 to tune1_low
Renamed DFLL tune1 to tune1_low to be consistent with
tune0_low/tune0_high naming convention.

Bug 1967884

Change-Id: If23170305143b05c2918e04691c73fe13b777272
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1576306
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
2026-08-24 18:39:45 -05:00
Vince Hsu 2960dca2ed clk: tegra: add DFLL dynamic tuning support
This patch is heavily based on the DFLL driver which is
written by Paul Walmsley and used by Tegra124 Chrome
projects currently.

The DFLL output can be fine tuned by the tuning parameters
depending on the voltage threshold. Both of the tuning
parameters and voltage threshold are specified by the
chip characterization. This patch introduces a tuning
timer which controls/monitors the tuning status. When
the DFLL is in open loop, only the tune low parameter
can be used. Once the DFLL enters the close loop, we
can switch to the tune high state if the output voltage
goes higher than the predefined threshold.

Added support for PWM regulator based DFLL.

Bug 200262988

Change-Id: I5ed51fbbf4b18cbd8cced5ab27848817201d8b39
Signed-off-by: Vince Hsu <vinceh@nvidia.com>
Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1565464
Reviewed-by: Aleksandr Frid <afrid@nvidia.com>
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: Timo Alho <talho@nvidia.com>
2026-08-24 18:39:45 -05:00
tmakin 3096ddec71 gpio: tegra: deprecate static allocation 2026-08-24 18:39:45 -05:00
tmakin d896aa5b70 tegra210b01: use tegra210b01 pinctrl 2026-08-24 18:39:45 -05:00
Laxman Dewangan 14e2972237 pinctrl: tegra210: Add support for LPDR bit
Tegra SOC Tegra210b01 have the support for LPDR configuration
via DT property "nvidia,lpdr".

Add support for configuring this property.

bug 200302268

Change-Id: I314af7f5094de6097f3c5944b28ad91ca61b1fdd
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-on: http://git-master/r/1469552
Reviewed-on: https://git-master.nvidia.com/r/1557094
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: Pavan Kunapuli <pkunapuli@nvidia.com>
GVS: Gerrit_Virtual_Submit
2026-08-24 18:39:44 -05:00
Maulik Shah 9c4ef8cb70 gpio: Use IRQ trigger mask helpers
Use IRQ_TYPE_LEVEL_MASK and IRQ_TYPE_EDGE_BOTH instead of open-coded
trigger type combinations in irqchip callbacks.

No functional change intended.

Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Maulik Shah <maulik.shah@oss.qualcomm.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Link: https://patch.msgid.link/20260802-b4b4-irq-trigger-mask-gpio-v1-1-948973636c84@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-08-24 18:39:44 -05:00
Runyu Xiao 5df1c69e32 gpio: tegra: do not call pinctrl for GPIO direction
tegra_gpio_direction_input() and tegra_gpio_direction_output() already
program the GPIO controller direction registers directly. The additional
pinctrl_gpio_direction_input/output() calls do not add a Tegra pinctrl
operation, because the Tegra pinmux ops provide GPIO request/free
handling but no gpio_set_direction hook.

The extra call still enters the pinctrl core and takes pctldev->mutex.
Shared GPIO users can call the direction path while holding their
per-line spinlock, so this otherwise redundant pinctrl direction call can
sleep in an atomic context.

This was found by our static analysis tool and then confirmed by manual
review of tegra_gpio_probe(), the Tegra GPIO direction callbacks and the
Tegra pinctrl ops. The reviewed path has a default non-sleeping
struct gpio_chip while the direction callback still enters the pinctrl
mutex path.

A directed runtime validation kept the same non-sleeping chip registration
and drove:

  gpio_shared_proxy_direction_output()
  gpiod_direction_output_raw_commit()
  tegra_gpio_direction_output()
  pinctrl_gpio_direction_output()

Lockdep reported a sleep-in-atomic warning with the shared GPIO spinlock
held and pinctrl_get_device_gpio_range() plus tegra_gpio_direction_output()
on the stack.

Do not mark the whole chip as can_sleep to paper over this: can_sleep
describes whether get()/set() may sleep, and Tegra value access is MMIO.
Remove the redundant pinctrl direction calls and keep pinctrl involvement
in the existing request/free path.

Fixes: 11da905412 ("gpio: tegra: Fix offset of pinctrl calls")
Cc: stable@vger.kernel.org
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
Link: https://patch.msgid.link/20260619152439.1239561-1-runyu.xiao@seu.edu.cn
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-08-24 18:39:44 -05:00
tmakin ee65e16217 bm92t: convert to typec fwk
note: ai
2026-08-24 18:39:43 -05:00
tmakin 84af317cf3 bm92t fix 2026-08-24 18:39:43 -05:00
tmakin a64e4bf1c1 bm92t: err change 2026-08-24 18:39:43 -05:00
tmakin a75c8520d0 power: bq24190: add get_current_limit 2026-08-24 18:39:43 -05:00
tmakin bbf04e9a89 emc: t186: fix mutex 2026-08-24 18:39:43 -05:00
tmakin c66af1b766 pci: tegra: update lanes if dt incorrect 2026-08-24 18:39:43 -05:00
tmakin 2458ea9a04 Revert "mmc: sdhci: pedantic clock rate debug logging"
This reverts commit 17bfd541f2b904f4ba87f0fcb3e2d3b4332d1802.
2026-08-24 18:39:43 -05:00
tmakin 14f6277465 sor: allow selection of alt sor1 tuning 2026-08-24 18:39:42 -05:00
tmakin d786880067 mmc: sdhci: pedantic clock rate debug logging
Add pr_info-level logging across the SDHCI subsystem and the Tegra
SDMMC clock providers so clock rate calculation, rounding, assigned
clocks and parents are visible in dmesg without needing dynamic_debug.

  - sdhci-tegra: log curr_clk_rate/max_clk/clock on set_clock entry and
    after clk_get_rate(), the requested host_clk, the rounded
    get_max_clock value, and dump regs before hw tuning.
  - sdhci: promote the DBG() macro from pr_debug to pr_info and log
    host->clock/max_clk/clock plus the computed divider/actual clock
    in sdhci_calc_clk() and sdhci_set_clock().
  - clk-sdmmc-mux / clk-divider / clk-utils: log div, mul, parent_rate,
    rounded rate and recalc_rate results in round_rate/recalc_rate/
    set_rate/div_frac_get so the full rate decision path is traceable.
  - mmc core: log the requested speed in mmc_set_clock() and the
    tuning entry/host-exec points in mmc_execute_tuning().

Change-Id: I4d569a01da8355db3319e82de942f1401dfac911
2026-08-24 18:39:42 -05:00
Alexandre Hamamdjian e3d103cf3e dt-bindings: usb: add Rohm BM92TXX Type-C controller
Add the device-tree binding documentation for the Rohm BM92TXX family
of USB Type-C and Power Delivery controllers. The device is controlled
over I2C and signals state changes through a dedicated interrupt line.

Document the rohm,* properties consumed by the driver: the optional
VCONN-enable GPIO, the DisplayPort alternate-mode toggles
(rohm,dp-disable, rohm,dp-alerts-enable, rohm,dp-signal-toggle-on-resume,
rohm,dp-lanes), the suspend/dock tunables (rohm,led-static-on-suspend,
rohm,dock-power-limit-disable) and the four
rohm,pd-{5,9,12,15}v-current-limit-ma per-PDO charging current limits.
A graph port is required to link the controller to a USB role switch
consumer.

Signed-off-by: Alexandre Hamamdjian <azkali.limited@gmail.com>
2026-08-24 18:39:42 -05:00
CTCaer c7a50eb91f usb: typec: bm92txx: add Rohm BM92TXX support
Add a driver for the Rohm Semiconductor BM92TXX family of USB Type-C
and Power Delivery controllers. The IC integrates an MCU that runs the
PD state machine; the host configures it and observes status over I2C
and reacts to a level-triggered ALERT interrupt.

The driver exposes the controller through extcon and a USB role switch,
manages the VBUS sink, optional VBUS source and battery-charger
regulators along with the VCONN-enable GPIO, and applies per-PDO
charging current limits (5 V, 9 V, 12 V, 15 V) sourced from device
tree. DisplayPort alternate-mode handling and dock LED behaviour are
configurable through rohm,* properties so the same driver can serve
boards that wire the part up differently. A debugfs interface under
bm92txx/ is provided for register dumps and low-level command access
when CONFIG_DEBUG_FS is enabled.

Signed-off-by: CTCaer <ctcaer@gmail.com>
Signed-off-by: Alexandre Hamamdjian <azkali.limited@gmail.com>
2026-08-24 18:39:42 -05:00
azkali 84d6d81d7e regulator: fan52555: add support for fan53528 fan 2026-08-24 18:39:42 -05:00
tmakin 18b308e7ed t210: assign better mmc clocks 2026-08-24 18:39:42 -05:00
tmakin fe8a0116e4 clk changes, test later 2026-08-24 18:39:42 -05:00
Laxman Dewangan ea82274201 NVIDIA: SAUCE: platform: tegra: Add tegra prod as built-in driver
BugLink: https://bugs.launchpad.net/bugs/2080908

This is an integration squash change of below commits.

 - [INTG: NV INTERNAL] platform: tegra: Add tegra prod as built-in
 - [INTG: NV INTERNAL] platform: tegra: Add tegra prod framework
 - [INTG: NV INTERNAL] platform: tegra: Add support for mask with 1s
 - [INTG: NV INTERNAL] platform: tegra_prod: Use kmemleak_not_leak for allocated memory
 - [INTG: NV INTERNAL] platform: tegra_prod: Fix prod setting parsing for package/board
 - [INTG: NV INTERNAL] platform: tegra_prod: Use proper variable name
 - [INTG: NV INTERNAL] platform: tegra_prod: Use for_each_available_child_of_node()
 - [INTG: NV INTERNAL] platform: tegra: move struct tegra_prod_list to private
 - [INTG: NV INTERNAL] platform: tegra_prod: Add APIs to managed allocation of prod_list
 - [INTG: NV INTERNAL] platform: tegra_prod: Remove unused APIs from public header
 - [INTG: NV INTERNAL] platform: tegra_prod: Get rid of tegra_prod_release()
 - [INTG: NV INTERNAL] platform: tegra_prod: Add support for nested prod nodes
 - [INTG: NV INTERNAL] platform: tegra_prod: Add devm_tegra_prod_get_from_node()
 - [INTG: NV INTERNAL] platform: tegra_prod: use devm_ for allocation
 - [INTG: NV INTERNAL] platform: tegra_prod: Do not use kmemleak_not_leak()
 - [INTG: NV INTERNAL] platform: tegra: Add support to find prod setting
 - [INTG: NV INTERNAL] platform: tegra: APIs to set prod based on name/index/offset/mask
 - [INTG: NV INTERNAL] prod: Add support for masked write in partially prod config
 - [INTG: NV INTERNAL] platform: tegra_prod: Use strcasecmp() for prod name
 - [INTG: NV INTERNAL] prod: set prod-settings mask to 1-style default
 - [INTG: NV INTERNAL] platform: tegra_prod: add support to avoid multiple configruation
 - soc: tegra: Add prod configuration parser
 - prod: remove package and board specific prod node
 - platform: tegra: Add config for next generation tegra prod
 - tegra-prod: Add legacy and next gen prod based on config
 - tegra-prod: Fix missing last entry
 - tegra-prod: Fix null pointer error
 - tegra-prod: Fix null pointer error
 - tegra: prod: remove new prod settings support

http://nvbugs/4165866
http://nvbugs/200416207
http://nvbugs/1758682
http://nvbugs/1745386
http://nvbugs/1768583
http://nvbugs/200217343
http://nvbugs/200215286
http://nvbugs/1807581
http://nvbugs/1865456
http://nvbugs/4097475
http://nvbugs/3389584
http://nvbugs/4638219
http://nvbugs/4283554
http://nvbugs/4765671
http://nvbugs/4754882

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Signed-off-by: Petlozu Pravareshwar <petlozup@nvidia.com>
Acked-by: Noah Wager <noah.wager@canonical.com>
Acked-by: Jacob Martin <jacob.martin@canonical.com>
Signed-off-by: Noah Wager <noah.wager@canonical.com>
2026-08-24 18:39:41 -05:00
tmakin 9fcb37425f clk: tegra210: update pll_c4 parameters 2026-08-24 18:39:41 -05:00
tmakin 10d17dbcce ftm4: compile fixes 2026-08-24 18:39:41 -05:00
Alvin Park bc5942c904 serial: tegra: clear tx_in_progress in flush func
Cleared tx_in_progress when tegra_uart_flush_buffer is called.
If tegra_uart_flush_buffer is called before complete to transmit
through DMA, next transmit could not be started because
tx_in_progress is not cleared.

Bug 3098159

Change-Id: I4b6b001314479313d7854d04a10d8394357a37cf
Signed-off-by: Alvin Park <apark@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-4.9/+/2405363
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: automaticguardword <automaticguardword@nvidia.com>
Reviewed-by: Hardik T Shah <hardikts@nvidia.com>
Reviewed-by: Phoenix Jung <pjung@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Signed-off-by: CTCaer <ctcaer@gmail.com>
2026-08-24 18:39:41 -05:00
azkali b54985fe3d touchscreen: stm: forward port ftm4 touchscreen driver from L4T 2026-08-24 18:39:41 -05:00
tmakin 3091c05197 dts: misc updates 2026-08-24 18:39:41 -05:00
tmakin f11ecb413d memory: tegra: populate dt subnodes
Tegra210b01 uses tegra186-emc driver as emc clock is controlled by BPMP.
However, this driver expects emc as subnode of mc. Adjust Tegra30 mc
probe routine to populate subnodes.
2026-08-24 18:39:41 -05:00
Vidya Sagar 74ff5e5f6d PCI: tegra: add PCI_REASSIGN_ALL_BUS flag
adds PCI_REASSIGN_ALL_BUS pci flag so as to enable
re-assigning bus numbers (if there is any bridge device added
recently) during rescan.

Bug 200192107

Change-Id: Iffc02827a75dcb82f5e02b69e96e65b38a0b7cd6
Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
Reviewed-on: http://git-master/r/1144609
(cherry picked from commit 26464cda2eff345548e3271f26b00ddcd79d9264)
Reviewed-on: http://git-master/r/1176833
(cherry picked from commit bf21f6959bbecc70b4dce07329e0deea32b41b67)
Reviewed-on: http://git-master/r/1141937
(cherry picked from commit 284d2e97ce311771808d8dbd75c861a95c16d031)
Reviewed-on: http://git-master/r/1210983
(cherry picked from commit ef83e7563eb0ce4dad493abba2c92d20a67f41ac)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-4.14/+/2371135
(cherry picked from commit a43acb68398f7fd6208988684698b49962b3c6f9)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-5.9/+/2407883
Reviewed-by: automaticguardword <automaticguardword@nvidia.com>
Reviewed-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
2026-08-24 18:39:41 -05:00
Manikanta Maddireddy 31811f31cc PCI: tegra: Add DT support to disable CLKREQ# control on PLLE
Sometimes CLKREQ# pin connection might be missing on a platform. Add DT
support to disable CLKREQ# control on PLLE in driver. Platform device tree
can use this DT property to disable CLKREQ# control on PLLE. In kernel-5.9,
upstream device tree property "supports-clkreq" is used in place of
kernel-4.14 custom device tree property "nvidia,disable-clock-request".

bug 200420606

Change-Id: I6ac44bd99d090e158fa10e5e9b62d63e52563c8c
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1786551
(cherry picked from commit 6870a94b48a4bbbe9df607802c7f7c1f61806b7b)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-5.9/+/2407880
Reviewed-by: automaticguardword <automaticguardword@nvidia.com>
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
2026-08-24 18:39:40 -05:00
Manikanta Maddireddy a5329b2b64 PCI: tegra: aspm DT support
Squashed below k414 commits into single change.

PCI: tegra: Add DT support to disable per state aspm

Kernel config option provides choice to disable L0s & L1 or L1 substates
combinedly. Add DT support to disable each aspm state individually.

bug 200420606

Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1786548
(cherry picked from commit f3c5bcdc3ab8cadd3d24ea4d1a8e0aba7beea751)

PCI: tegra: Fix ASPM DT property parsing code

DT property "nvidia,disable-aspm-states" is part of PCIe port node.
Use correct of_node pointer to parse this property.

bug 200434876

Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-4.14/+/2383766
(cherry picked from commit 8dd957e9ecf29da4ba94471e3d74b2aef98a0643)

Change-Id: Iee1f573a103c0045d4f8f6606db13b47575b8cb9
Reviewed-on: https://git-master.nvidia.com/r/c/linux-5.9/+/2408709
Reviewed-by: automaticguardword <automaticguardword@nvidia.com>
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: Bitan Biswas <bbiswas@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
2026-08-24 18:39:40 -05:00
Manikanta Maddireddy b9088d4a23 PCI: tegra: Bypass CLKREQ# control over PLLE
When PCIe link is L2 CLKREQ# will be floating and this might interfere
with PLL power down. Bypass CLKREQ# control over PLLE when link is in L2.

bug 1356695
bug 200420606

Change-Id: I361db03df5f9a1a8d38bd9fb816d17fc4c64a9fc
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1786565
(cherry picked from commit 69e79f42f65df70b0c76e62200aca40ed3972e3b)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-5.9/+/2407877
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
2026-08-24 18:39:40 -05:00
Manikanta Maddireddy fddd6304c2 PCI: tegra: Fix incorrect CLKREQ and PLLE programming
CLKREQ_EN bit should be cleared to control REFCLK through CLKREQ# pin.
Enable PCIE2PLLE bit to control PLLE through clock clamp signal.
Program PADS2PLLE and PCIE2PLLE bits only if Tegra PCIe supports L1SS.

bug 200420606

Change-Id: I04cacf64fce8eed0f17bb632457ffcc9f052819d
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1786550
(cherry picked from commit e71a64e47225b848c9b8a1d33e8c80a7bdb9d3cc)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-5.9/+/2407876
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
2026-08-24 18:39:40 -05:00
Vidya Sagar 5150f5d841 PCI: tegra: Fixups to avoid unnecessary wakeup from ASPM-L1.2
sets CLKREQ asserted delay to a higher value to avoid
unnecessary wake up from L1.2.ENTRY state for Tegra210

bug 200420606

Change-Id: Iec2564bfd434897f0e50cd3f0ad6bc76aacc12e8
Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1786545
(cherry picked from commit d7785c1e6c98e33a85ba9487d3be6ab7e518a285)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-5.9/+/2407875
Reviewed-by: automaticguardword <automaticguardword@nvidia.com>
Reviewed-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
2026-08-24 18:39:40 -05:00
Vidya Sagar 322c8e45b5 PCI: tegra: Apply sw fixups to support ASPM-L1 Sub-States
Programs Port Common_Mode_Restore_Time and Port T_POWER_ON values
(from the L1 PM Substates Capabilities Register, PCIe 4.0r0.9, sec 7.8.3.2)
to get them reflected in ASPM-L1 Sub-States capability registers.
Also adjusts internal counter values according to 19.2 MHz clk_m value.

bug 200420606

Change-Id: Ie139255e522e4476fdfbe64aa6250d0293b7ae89
Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1786544
(cherry picked from commit 9ac6211e1a99583618945c86748214ccc33de463)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-5.9/+/2407874
Reviewed-by: automaticguardword <automaticguardword@nvidia.com>
Reviewed-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
2026-08-24 18:39:40 -05:00
Manikanta Maddireddy 7b4c276857 PCI: tegra: Configure L1 power save parameters
Programmed bits of register RP_VEND_XP_PAD_PWRDN are defined as follows,

L1(bit[0]):
 This bit, when set, causes the analog pads to power down when we're in L1.
 When clear, the LTSSM still enters L1 as required, but the analog pads
 are left at full power.
DYNAMIC(bit[1]):
 This bit, when set, causes unused analog pads to power down after
 "Dynamic Link Width Re-negotiation" takes place.  When clear, all analog
 pads remain powered up, even those that are no longer being used after
 "Dynamic Link Width Re-negotiation" down-sizes the link.
DISABLED(bit[2]):
 This bit, when set, causes the analog pads to power down when we're in the
 DISABLED_DOWN state. When clear, the LTSSM still enters DISBLED_DOWN as
 required, but the analog pads are left at full power.
L1_CLKREQ(bit[15]):
 This bit, when set, causes the analog pads to power down to
 SLEEP_MODE_L1_REQ when clkreq signal is deasserted in L1.
 (NV_PROJ__PCIE2_RP_VEND_XP_PAD_PWRDN_L1 needs to be set in order to power
 down pad in L1.)  Also, when clkreq is asserted in L1, ltssm will exit L1
 immediately. When clear, the clkreq signal doesn't affect the power
 management.
SLEEP_MODE_L1(bits[4:3]):
 It defines the 2-bit sleep-mode coding in the pad when LTSSM is in the L1
 state or DISABLED state.
SLEEP_MODE_DYNAMIC(bits[6:5]):
 It defines the 2-bit sleep-mode coding in the pad when the lane shut down
 due to dynamic link downsizing.
SLEEP_MODE_L1_CLKREQ(bits[17:16]):
 It defines the 2-bit sleep-mode coding when clkreq is deasserted in L1.
The 2-bit sleep-mode encoding is defined as:
 - L0 (0x0): Normal power-up mode
 - L1 (0x1): L1 power-down mode; Tx common mode on, Rx e-idle detect on
 - L1P (0x2): L1 power-down mode; Tx common mode off, Rx e-idle detect on
 - L1PP (0x3): L1 power-down mode; Tx common mode off, Rx e-idle detect off

bug 200420606

Change-Id: I74aa9c1460d882084b1ecccb9c0168dd667c9d84
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1786547
(cherry picked from commit d7899c186f89ecf503812003b743adbae07c4cbe)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-5.9/+/2407873
Reviewed-by: automaticguardword <automaticguardword@nvidia.com>
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
2026-08-24 18:39:40 -05:00
Vidya Sagar 820e88911d PCI: tegra: Advertise ASPM L1 PM support
Enables advertisement of ASPM-L1 support in capability
registers of applicable Tegra chips

bug 200420606

Change-Id: Ie5dbb3a262ca1c0c9cc59c91a8710bf6bd6a6900
Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1786543
(cherry picked from commit 7eedf2a02489b529374bc1ca95234be1f02b9119)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-5.9/+/2407872
Reviewed-by: automaticguardword <automaticguardword@nvidia.com>
Reviewed-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
2026-08-24 18:39:40 -05:00
Manikanta Maddireddy e9d731ffb6 PCI: tegra: Convert WRAP transactions to increment burst
AFI module doesn't support WRAP transactions in Tegra. WRAP instructions
from CPU targeting PCIe BAR memory can cause data corruption. This can
happen if PCIe memory is marked as normal cacheable or GRE device.
Program mselect register to convert WRAP transactions to increment burst
for slave PCIe.

bug 200353330
bug 200420606

Change-Id: I867da85eb63332708bc294238e30ad99a71f345d
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1786561
(cherry picked from commit b345cfae7b7633a3a52e0f2a659baf44feee1466)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-5.9/+/2407869
Reviewed-by: automaticguardword <automaticguardword@nvidia.com>
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
2026-08-24 18:39:40 -05:00
Manikanta Maddireddy 3f763023a0 PCI: tegra: Access endpoint config only if PCIe link is up
Few endpoints like Wi-Fi supports power on/off and to leverage that
root port must support hot-plug and hot-unplug. Tegra PCIe doesn't
support hot-plug and hot-unplug, however it supports endpoint power
on/off feature as follows,
 - Power off sequence:
   - Transition of PCIe link to L2
   - Power off endpoint
   - Leave root port in power up state with the link in L2
 - Power on sequence:
   - Power on endpoint
   - Apply hot reset to get PCIe link up

PCIe client driver stops accessing PCIe endpoint config and BAR registers
after endpoint is powered off. However, software applications like x11
server or lspci can access endpoint config registers in which case
host controller raises "response decoding" errors. To avoid this scenario,
add PCIe link up check in config read and write callback functions before
accessing endpoint config registers.

Change-Id: I47653cb0b580c2b764cb0ad9c42deeb9c8823c58
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-4.14/+/2371131
(cherry picked from commit be664bfdd901138222a8ea8bb17160a2fa9de04a)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-5.9/+/2407866
Reviewed-by: automaticguardword <automaticguardword@nvidia.com>
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
2026-08-24 18:39:39 -05:00
tmakin 96595f6b1b [WAR] core: don't loop 2026-08-24 18:39:39 -05:00
tmakin 28a7b211f7 memory: tegra186-emc: support t210b01
Tegra210b01 uses Tegra186 style emc management, as in it is
offloaded to BPMP. This driver already implements this, so no
reason to shoehorn in elsewhere.

Signed-off-by: Thomas Makin <halorocker89@gmail.com>
2026-08-24 18:39:39 -05:00
tmakin a00de5720b tegra210b01: do not enable venc
Signed-off-by: Thomas Makin <halorocker89@gmail.com>
2026-08-24 18:39:39 -05:00
tmakin 176ffad43c tegra-drm: add t210b01 dsi support
Signed-off-by: Thomas Makin <halorocker89@gmail.com>
2026-08-24 18:39:39 -05:00
tmakin 4c56a02679 enable max77812
Signed-off-by: Thomas Makin <halorocker89@gmail.com>
2026-08-24 18:39:39 -05:00
tmakin 9856c0e55d panel-nx: match jdi panel driver style
squash later
2026-08-24 18:39:39 -05:00
azkali cb59995ea8 panel: dsi-nx: Add dsi-nx panel driver
dsi-nx is a new blanket driver for panels on the Nintendo Switch.
The Switch boots Linux via the "hekate" custom bootloader, which
performs panel initialization and passes panel info to kernel.

This driver is based on panel-jdi-lpm062m326a by SwitchR.

Signed-off-by: Thomas Makin <halorocker89@gmail.com>
2026-08-24 18:38:09 -05:00
60 changed files with 7519 additions and 3880 deletions

No files matched your search

@@ -0,0 +1,128 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/usb/rohm,bm92t.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Rohm BM92TXX USB Type-C and Power Delivery controller
maintainers:
- CTCaer <ctcaer@gmail.com>
- Alexandre Hamamdjian <azkali.limited@gmail.com>
description:
The Rohm BM92TXX is a family of USB Type-C and Power Delivery
controllers with an integrated MCU. The host communicates with the
device over I2C and is notified of state changes through a dedicated
interrupt line.
properties:
compatible:
const: rohm,bm92t
reg:
maxItems: 1
interrupts:
maxItems: 1
vbus-supply:
description: VBUS sink regulator.
vbus-source-supply:
description: VBUS source (provider) regulator.
pd_bat_chg-supply:
description: Battery charger regulator gated by Power Delivery state.
rohm,vconn-en-gpio:
maxItems: 1
description: GPIO controlling the external VCONN switch.
rohm,dp-disable:
type: boolean
description: Disable DisplayPort alternate-mode handling.
rohm,dp-alerts-enable:
type: boolean
description: Enable DisplayPort status alerts.
rohm,dp-signal-toggle-on-resume:
type: boolean
description:
Toggle the DisplayPort signal on resume to work around sinks that
do not re-train after system resume.
rohm,dp-lanes:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [2, 4]
default: 2
description: Number of DisplayPort lanes to negotiate.
rohm,led-static-on-suspend:
type: boolean
description:
Keep the charge LED in a static state during system suspend
instead of letting the controller animate it.
rohm,dock-power-limit-disable:
type: boolean
description:
Disable the lower power limit applied when a dock is detected.
rohm,pd-5v-current-limit-ma:
description: Charging current limit in mA when 5V PD contract is active.
rohm,pd-9v-current-limit-ma:
description: Charging current limit in mA when 9V PD contract is active.
rohm,pd-12v-current-limit-ma:
description: Charging current limit in mA when 12V PD contract is active.
rohm,pd-15v-current-limit-ma:
description: Charging current limit in mA when 15V PD contract is active.
port:
$ref: /schemas/graph.yaml#/properties/port
description:
Output port linking to a USB role switch consumer endpoint.
required:
- compatible
- reg
- interrupts
- port
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
typec@18 {
compatible = "rohm,bm92t";
reg = <0x18>;
interrupt-parent = <&gpio>;
interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
vbus-supply = <&vbus_reg>;
vbus-source-supply = <&vbus_src_reg>;
pd_bat_chg-supply = <&pd_bat_chg_reg>;
rohm,dp-lanes = <4>;
rohm,pd-5v-current-limit-ma = <2000>;
rohm,pd-9v-current-limit-ma = <2000>;
rohm,pd-12v-current-limit-ma = <1500>;
rohm,pd-15v-current-limit-ma = <1200>;
port {
bm92t_ep: endpoint {
remote-endpoint = <&usb_role_sw>;
};
};
};
};
+8
View File
@@ -23259,6 +23259,14 @@ L: linux-iio@vger.kernel.org
S: Supported
F: drivers/iio/pressure/rohm-bm1390.c
ROHM BM92TXX USB TYPE-C CONTROLLER DRIVER
M: CTCaer <ctcaer@gmail.com>
M: Alexandre Hamamdjian <azkali.limited@gmail.com>
L: linux-usb@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/usb/rohm,bm92t.yaml
F: drivers/usb/typec/bm92txx.c
ROHM BU270xx LIGHT SENSOR DRIVERs
M: Matti Vaittinen <mazziesaccount@gmail.com>
L: linux-iio@vger.kernel.org
-944
View File
@@ -1,944 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
#include <dt-bindings/mfd/max77620.h>
#include <dt-bindings/gpio/tegra-gpio.h>
#include <dt-bindings/thermal/thermal.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/soc/tegra-pmc.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/pwm/pwm.h>
#include <dt-bindings/pinctrl/pinctrl-tegra.h>
#include "tegra210.dtsi"
/ {
aliases {
i2c1 = "/i2c@7000c000";
i2c2 = "/i2c@7000c400";
i2c3 = "/i2c@7000c500";
i2c5 = "/i2c@7000d000";
rtc0 = "/i2c@7000d000/max77620@3c";
rtc1 = "/rtc@7000e000";
serial0 = &uarta;
serial1 = &uartb;
serial2 = &uartc;
serial3 = &uartd;
};
chosen {
bootargs = "root=/dev/mmcblk0p2 rw rootwait fbcon=rotate:3 printk.synchronous=1 loglevel=4 console=fb0 console=ttyGS0 earlycon";
stdout-path = "serial1:115200n8";
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
vdd-cpu-supply = <&cpu_max_reg>;
};
idle-states {
cpu-sleep {
status = "okay";
};
};
};
gpu@57000000 {
status = "okay";
vdd-supply = <&gpu_max_reg>;
};
host1x@50000000 {
dsia: dsi@54300000 {
status = "okay";
panel@0 {
compatible = "jdi,lpm062m326a";
reset-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>;
backlight = <&backlight>;
vdd1-supply = <&v_pavdd_5v0>;
vdd2-supply = <&v_navdd_5v0>;
};
};
/* tegradc.0: DSI */
dc@54200000 {
status = "okay";
pavdd_lcd-supply = <&v_pavdd_5v0>;
navdd_lcd-supply = <&v_navdd_5v0>;
dvdd_lcd-supply = <&max77620_sd3>;
vdd_lcd_bl_en-supply = <&lcd_bl_en>;
nvidia,outputs = <&dsia>;
};
/* tegradc.1: DP */
dc@54240000 {
status = "okay";
avdd_hdmi-supply = <&max77620_ldo8>; /* 1V05 */
avdd_hdmi_pll-supply = <&max77620_sd3>; /* 1V8 */
// vdd_hdmi_5v0-supply = <&vdd_hdmi>; /* 5V0 GPIO_PCC7 fixed reg */
vdd-dp-pwr-supply = <&vdd_3v3>;
avdd-dp-pll-supply = <&max77620_sd3>;
vdd-dp-pad-supply = <&max77620_ldo8>;
extcon-cables = <&bm92t 3>;
extcon-cable-names = "typec1";
nvidia,outputs = <&sor1>;
};
dpaux1: dpaux@54040000 {
status = "okay";
vdd-supply = <&v_pavdd_5v0>;
};
sor1: sor@54580000 {
status = "okay";
nvidia,dpaux = <&dpaux1>;
avdd-io-hdmi-dp-supply = <&max77620_ldo8>;
vdd-hdmi-dp-pll-supply = <&max77620_sd3>;
nvidia,hpd-gpio = <&gpio TEGRA_GPIO(CC, 1) GPIO_ACTIVE_LOW>;
};
vi: i2c@546c0000 {
status = "okay";
};
};
clock@70110000 {
status = "okay";
nvidia,cf = <6>;
nvidia,ci = <0>;
nvidia,cg = <2>;
nvidia,droop-ctrl = <0x00000f00>;
nvidia,force-mode = <1>;
nvidia,i2c-fs-rate = <400000>;
nvidia,sample-rate = <12500>;
vdd-cpu-supply = <&cpu_max_reg>;
};
memory {
device_type = "memory";
reg = <0x0 0x80000000 0x0 0x80000000>;
};
reserved-memory {
/delete-node/ vpr-carveout;
/delete-node/ iram-carveout;
};
r2p {
compatible = "tegra-r2p";
status = "okay";
};
/* debug port */
serial@70006000 {
status = "disabled";
};
/* joycon ports:
invert TXD and RTS via IRDA_CSR
start @ 1000000 baud, switch to 3000000
when they are >= 3000000 baud, use 2 stop bits
use flow control
Note: hsuart driver is required for flow control
*/
/* right joycon */
serial@70006040 {
status = "okay";
compatible = "nvidia,tegra124-hsuart", "nvidia,tegra30-hsuart";
nvidia,invert-txd;
nvidia,invert-rts;
reset-names = "serial";
joyconr {
status = "okay";
compatible = "nintendo,joycon-serdev";
charger-supply = <&en_vdd_jcr_chgr>;
detect-en-gpios = <&gpio TEGRA_GPIO(G, 0) GPIO_ACTIVE_HIGH>;
detect-gpios = <&gpio TEGRA_GPIO(H, 6) GPIO_ACTIVE_LOW>;
};
};
/* left joycon */
serial@70006200 {
status = "okay";
compatible = "nvidia,tegra124-hsuart", "nvidia,tegra30-hsuart";
nvidia,invert-txd;
nvidia,invert-rts;
reset-names = "serial";
joyconl {
status = "okay";
compatible = "nintendo,joycon-serdev";
charger-supply = <&en_vdd_jcl_chgr>;
detect-en-gpios = <&gpio TEGRA_GPIO(D, 1) GPIO_ACTIVE_HIGH>;
detect-gpios = <&gpio TEGRA_GPIO(E, 6) GPIO_ACTIVE_LOW>;
};
};
/* bluetooth */
serial@70006300 {
dma-names = "tx";
status = "okay";
compatible = "nvidia,tegra124-hsuart", "nvidia,tegra30-hsuart";
reset-names = "serial";
bluetooth {
compatible = "brcm,bcm43438-bt";
vbat-supply = <&battery_reg>;
vddio-supply = <&battery_reg>;
shutdown-gpios = <&gpio TEGRA_GPIO(H, 4) GPIO_ACTIVE_HIGH>;
device-wakeup-gpios = <&gpio TEGRA_GPIO(H, 3) GPIO_ACTIVE_LOW>;
max-speed = <3000000>; /* Max supported 4 MBaud */
sco-routing = <1>; /* Over HCI */
};
};
clk32k_in: clock-32k {
compatible = "fixed-clock";
clock-frequency = <32768>;
#clock-cells = <0>;
};
backlight: backlight {
compatible = "pwm-backlight";
pwms = <&pwm 0 33898>;
pwm-names = "backlight";
brightness-levels = <
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40 41 42 43 44
45 46 47 48 49 50 51 52 53 54 55 56 57 58
59 60 61 62 63 64 65 66 67 68 69 70 71 72
73 74 75 76 77 78 79 80 81 82 83 84 85 86
87 88 89 90 91 92 93 94 95 96 97 98 99 100
>;
default-brightness-level = <50>;
enable-gpios = <&gpio TEGRA_GPIO(V, 1) GPIO_ACTIVE_HIGH>;
power-supply = <&max77620_sd3>;
};
/* Fixed regulators */
battery_reg: vdd-ac-bat {
compatible = "regulator-fixed";
status = "okay";
regulator-name = "vdd-ac-bat";
regulator-min-microvolt = <4800000>;
regulator-max-microvolt = <4800000>;
regulator-always-on;
regulator-boot-on;
};
vdd_3v3: vdd-3v3 {
compatible = "regulator-fixed";
regulator-name = "vdd-3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
gpio = <&max77620 3 0>;
enable-active-high;
regulator-enable-ramp-delay = <160>;
regulator-disable-ramp-delay = <10000>;
};
max77620_gpio7: avdd-dsi-csi-1v2 {
compatible = "regulator-fixed";
regulator-name = "max77620-gpio7";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-boot-on; /* Must be set for seamless display */
gpio = <&max77620 7 0>;
enable-active-high;
regulator-enable-ramp-delay = <240>;
regulator-disable-ramp-delay = <11340>;
vin-supply = <&max77620_ldo0>;
};
lcd_bl_en: lcd-bl-en {
compatible = "regulator-fixed";
regulator-name = "lcd-bl-en";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
gpio = <&gpio TEGRA_GPIO(V, 1) 0>;
regulator-boot-on; /* Must be set for seamless display */
enable-active-high;
regulator-always-on;
regulator-state-mem {
regulator-off-in-suspend;
};
};
en_vdd_sd: en-vdd-sd {
compatible = "regulator-fixed";
regulator-name = "en-vdd-sd";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio TEGRA_GPIO(E, 4) 0>;
enable-active-high;
regulator-enable-ramp-delay = <472>;
regulator-disable-ramp-delay = <4880>;
vin-supply = <&vdd_3v3>;
};
/* LCD Power Enable +5V. Rohm BD8316GWL. */
v_pavdd_5v0: v-pavdd-5v0 {
compatible = "regulator-fixed";
regulator-name = "v_pavdd_5v0";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
gpio = <&gpio TEGRA_GPIO(I, 0) 0>;
enable-active-high;
regulator-boot-on; /* Must be set for seamless display */
regulator-enable-ramp-delay = <232>;
};
/* LCD Power Enable -5V. Rohm BD8316GWL. */
v_navdd_5v0: v-navdd-5v0 {
compatible = "regulator-fixed";
regulator-name = "v_navdd_5v0";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
gpio = <&gpio TEGRA_GPIO(I, 1) 0>;
enable-active-high;
regulator-boot-on; /* Must be set for seamless display */
regulator-enable-ramp-delay = <232>;
};
/* Joycon/Fan power (battery). Maxim MAX8969EWL53+. */
v_vdd50_a: v-vdd50-a {
compatible = "regulator-fixed";
regulator-name = "v_vdd50_a";
regulator-min-microvolt = <5300000>;
regulator-max-microvolt = <5300000>;
gpio = <&gpio TEGRA_GPIO(A, 5) 0>;
enable-active-high;
};
/* Joycon/Fan power (usb). DC0 on Odin. Maxim MAX8969EWL53+ on Modin. */
v_vdd50_b: v-vdd50-b {
compatible = "regulator-fixed";
regulator-name = "v_vdd50_b";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
gpio = <&gpio TEGRA_GPIO(CC, 4) 0>;
enable-active-high;
};
v_vdd5v3: v-vdd5v3 {
compatible = "regulator-fixed";
status = "okay"; /* Only enabled on Modin/Vali/Fric */
regulator-name = "v_vdd5v3";
regulator-min-microvolt = <5300000>;
regulator-max-microvolt = <5300000>;
gpio = <&gpio TEGRA_GPIO(X, 3) 0>;
enable-active-high;
regulator-enable-ramp-delay = <10000>;
};
vdd3v3_gc: vdd3v3-gc {
compatible = "regulator-fixed";
regulator-name = "vdd3v3_gc";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio TEGRA_GPIO(E, 5) 0>;
enable-active-high;
regulator-enable-ramp-delay = <472>;
regulator-disable-ramp-delay = <4880>;
vin-supply = <&vdd_3v3>;
};
/* TI TCR2EE48 4.8V */
en_vdd_jcl_chgr: left-joycon-charger {
compatible = "regulator-fixed";
status = "okay";
regulator-name = "left-joycon-charger";
regulator-min-microvolt = <4800000>;
regulator-max-microvolt = <4800000>;
gpio = <&gpio TEGRA_GPIO(CC, 3) GPIO_ACTIVE_HIGH>;
enable-active-high;
vin-supply = <&v_vdd50_a>;
regulator-state-mem {
regulator-off-in-suspend;
};
};
/* TI TCR2EE48 4.8V */
en_vdd_jcr_chgr: right-joycon-charger {
compatible = "regulator-fixed";
status = "okay";
regulator-name = "right-joycon-charger";
regulator-min-microvolt = <4800000>;
regulator-max-microvolt = <4800000>;
gpio = <&gpio TEGRA_GPIO(K, 3) GPIO_ACTIVE_HIGH>;
enable-active-high;
vin-supply = <&v_vdd50_a>;
regulator-state-mem {
regulator-off-in-suspend;
};
};
/* SDMMC4 for EMMC */
mmc@700b0600 {
status = "disabled";
bus-width = <8>;
max-frequency = <200000000>;
cap-mmc-highspeed;
mmc-ddr-1_8v;
mmc-hs200-1_8v;
mmc-hs400-1_8v;
non-removable;
vqmmc-supply = <&max77620_sd3>;
vmmc-supply = <&vdd_3v3>;
};
/* SDMMC3 Not Used */
mmc@700b0400 {
status = "disabled";
vqmmc-supply = <&max77620_sd3>;
vmmc-supply = <&vdd_3v3>;
};
/* SDMMC2 for Gamecard */
mmc@700b0200 {
status = "disabled";
bus-width = <8>;
max-frequency = <200000000>;
mmc-ddr-1_8v;
mmc-hs400-1_8v;
mmc-hs200-1_8v;
cap-mmc-highspeed;
cap-sd-highspeed;
non-removable;
vqmmc-supply = <&max77620_sd3>;
vmmc-supply = <&vdd_3v3>;
};
/* SDMMC1 for SD Card */
mmc@700b0000 {
status = "okay";
bus-width = <4>;
max-frequency = <200000000>;
cap-sd-highspeed;
sd-uhs-sdr12;
sd-uhs-sdr50;
sd-uhs-sdr104;
cd-gpios = <&gpio TEGRA_GPIO(Z, 1) GPIO_ACTIVE_LOW>;
vmmc-supply = <&en_vdd_sd>;
vqmmc-supply = <&max77620_ldo2>;
};
hda@70030000 {
status = "okay";
};
/* i2c1 @ 100000hz
1c: realtek 5639
18: rohm usb-pd
4c: ti temperature sensor
6b: ti charger
36: maxim fuel gauge
*/
i2c@7000c000 {
status = "okay";
clock-frequency = <100000>;
bq24193@6b {
compatible = "ti,bq24193";
reg = <0x6b>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(Z, 0) IRQ_TYPE_LEVEL_LOW>;
monitored-battery = <&fuel_gauge>;
#extcon-cells = <1>;
omit-battery-class;
battery_charger: charger {
regulator-name = "batt_regulator";
regulator-max-microamp = <4500000>;
};
usb0_vbus: usb-otg-vbus {
regulator-name = "vbus_regulator";
};
};
fuel_gauge: fuel-gauge@36 {
compatible = "maxim,max17050";
status = "okay";
reg = <0x36>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(Y, 0) IRQ_TYPE_NONE>;
/* Actual is 5000 but driver does not account for CGAIN */
/* And does not take into account Rsense and CGAIN for capacity */
maxim,rsns-microohm = <10000>;
maxim,over-heat-temp = <600>;
maxim,dead-volt = <3000>;
maxim,over-volt = <4208>; /* Actual: 4258 mV */
#thermal-sensor-cells = <0>;
};
rt5639: audio-codec@1c {
status = "okay";
compatible = "realtek,rt5639";
reg = <0x1c>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(BB, 4) IRQ_TYPE_EDGE_RISING>;
realtek,ldo1-en-gpios = <&gpio TEGRA_GPIO(Z, 4) GPIO_ACTIVE_HIGH>;
realtek,over-current-threshold-microamp = <600>;
realtek,over-current-scale-factor = <2>;
realtek,jack-detect-is-jd1;
};
/* PD Chip */
bm92t: bm92t@18 {
compatible = "rohm,bm92t";
reg = <0x18>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(K, 4) IRQ_TYPE_EDGE_RISING>;
#extcon-cells = <1>;
pd_bat_chg-supply = <&battery_charger>;
vbus-source-supply = <&v_vdd5v3>;
vbus-supply = <&usb0_vbus>;
rohm,dp-lanes = <2>;
rohm,dp-signal-toggle-on-resume;
/* Absolute max is 2.4A, constrained by BQ24193 ILIM */
rohm,pd-5v-current-limit-ma = <2000>;
rohm,pd-9v-current-limit-ma = <2000>;
rohm,pd-12v-current-limit-ma = <1500>;
rohm,pd-15v-current-limit-ma = <1200>;
port {
usb_con_ep: endpoint {
remote-endpoint = <&usb_port_0>;
};
};
};
tmp451: temperature-sensor@4c {
compatible = "ti,tmp451";
status = "okay";
reg = <0x4c>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(X, 4) IRQ_TYPE_EDGE_FALLING>;
vcc-supply = <&battery_reg>;
#thermal-sensor-cells = <1>;
};
};
/* i2c3 @ 400000hz
49: stm touchscreen controller
*/
i2c@7000c500 {
status = "okay";
clock-frequency = <400000>;
touchscreen@49 {
compatible = "stm,ftm4_fts";
status = "okay";
reg = <0x49>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(X, 1) IRQ_TYPE_LEVEL_LOW>;
vdd-tp-2v9-supply = <&max77620_ldo6>;
stm,vio-gpio = <&gpio TEGRA_GPIO(J, 7) GPIO_ACTIVE_HIGH>;
stm,irq_type = <0x2000>; /* IRQF_ONESHOT */
stm,regulator_avdd = "vdd-tp-2v9";
stm,max_coords = <1280 720>;
stm,max-real-coords = <1264 704>;
stm,edge-offset = <15 15>;
stm,delayed-open;
stm,delayed-open-time = <0>;
};
};
/* i2c2 @ 400000hz
29: rohm ambient light sensor
*/
i2c@7000c400 {
status = "okay";
clock-frequency = <400000>;
bh1730fvc: bh1730fvc@29 {
status = "disabled";
compatible = "rohm,bh1730fvc";
reg = <0x29>;
als-vid-supply = <&max77620_ldo6>;
als-vdd-supply = <&vdd_3v3>;
rohm,integration-cycle = <38>;
rohm,lux-multiplier = <3600>;
rohm,opt-win-coeff = < 500 5002 7502
754 2250 2000
1029 1999 1667
1373 884 583
1879 309 165>;
rohm,gain-coeff = < 2500 0
1600 7800
10 50000
0 1000>;
};
};
spi@7000da00 {
status = "disabled"; /* Disabled for Vali */
num-cs = <1>;
#address-cells = <1>;
#size-cells = <0>;
// spi-cs-setup-delay-ns = <2>;
// spi-cs-hold-delay-ns = <2>;
// spi-cs-inactive-delay-ns = <2>;
/*
* Model WHOAMI:
* LSM6DS3H 0x69, LSM6DSE 0x6A, LSM6DSO 0x6C, ICM40607 0x38.
*/
gyroscope: imu@0 {
reg = <0>;
status = "disabled";
compatible = "st,lsm6ds3h";
#address-cells = <1>;
#size-cells = <0>;
spi-max-frequency = <8000000>;
/* SPI Mode-3 */
spi-cpha;
spi-cpol;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(X, 2) IRQ_TYPE_LEVEL_HIGH>;
vdd-supply = <&battery_reg>;
vddio-supply = <&battery_reg>;
st,drdy-int-pin = <2>;
nvidia,rx-clk-tap-delay = <0x1f>;
nvidia,tx-clk-tap-delay = <0x0>;
mount-matrix =
"1", "0", "0", /* X: x */
"0", "1", "0", /* Y: y */
"0", "0", "1"; /* Z: z */
};
};
gpio-keys {
compatible = "gpio-keys";
key-volume-down {
label = "Volume Down";
gpios = <&gpio TEGRA_GPIO(X, 7) GPIO_ACTIVE_LOW>;
linux,input-type = <EV_KEY>;
linux,code = <KEY_VOLUMEDOWN>;
debounce-interval = <10>;
};
key-volume-up {
label = "Volume Up";
gpios = <&gpio TEGRA_GPIO(X, 6) GPIO_ACTIVE_LOW>;
linux,input-type = <EV_KEY>;
linux,code = <KEY_VOLUMEUP>;
debounce-interval = <10>;
};
};
gpio@6000d000 {
boot-default-output-high {
gpio-hog;
output-high;
gpios = <TEGRA_GPIO(H, 1) GPIO_ACTIVE_HIGH>; /* Wi-Fi Reset. Powered on by default. */
line-name = "boot-default-output-high";
};
};
pwm@7000a000 {
status = "okay";
#pwm-cells = <2>;
};
fan: pwm-fan {
compatible = "pwm-fan";
cooling-min-state = <0>;
cooling-max-state = <5>;
#cooling-cells = <2>;
pwms = <&pwm 1 33333>;
fan-supply = <&v_vdd50_a>;
enable-gpios = <&gpio TEGRA_GPIO(A, 5) GPIO_ACTIVE_HIGH>;
/* cooling level (0, 1, 2, 3, 4, 5) - pwm inverted */
cooling-levels = <255 204 153 102 51 0>;
};
sound {
status = "okay";
compatible = "nvidia,tegra-audio-rt5640-tx1",
"nvidia,tegra-audio-rt5640";
nvidia,model = "Nintendo Switch";
nvidia,audio-codec = <&rt5639>;
nvidia,i2s-controller = <&tegra_i2s1>;
// nvidia,hp-det-gpios = <&gpio 143 0>;
clocks = <&tegra_car TEGRA210_CLK_PLL_A>,
<&tegra_car TEGRA210_CLK_PLL_A_OUT0>,
<&tegra_car TEGRA210_CLK_CLK_M>;
clock-names = "pll_a", "plla_out0", "mclk";
assigned-clocks = <&tegra_car TEGRA210_CLK_PLL_A>,
<&tegra_car TEGRA210_CLK_PLL_A_OUT0>,
<&tegra_car TEGRA210_CLK_D_AUDIO>,
<&tegra_car TEGRA210_CLK_EXTERN1>;
assigned-clock-rates = <368640000>, <36864000>,
<36864000>, <12288000>;
nvidia,audio-routing =
"Headphones", "HPOL",
"Headphones", "HPOR",
"Speakers", "SPORP",
"Speakers", "SPORN",
"Speakers", "SPOLP",
"Speakers", "SPOLN",
"IN1P", "Mic Jack",
"IN1P", "Mic Jack";
};
thermal-zones {
cpu {
polling-delay-passive = <250>;
polling-delay = <500>;
status = "okay";
/* Based on Console profile SoC: 95% (100% at Handheld) */
coefficients = <95 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
thermal-sensors = <&tmp451 1>;
trips {
cpu_critical: cpu-critical {
temperature = <102500>;
hysteresis = <0>;
type = "critical";
};
cpu_heavy: cpu-heavy {
temperature = <98500>;
hysteresis = <1000>;
type = "hot";
};
cpu_throttle: cpu-throttle {
temperature = <89000>;
hysteresis = <2000>;
type = "passive";
};
cpu_cap_trip1: cpu-cap-trip1 {
temperature = <58000>;
hysteresis = <2000>;
type = "active";
};
cpu_floor_trip1: cpu-floor-trip1 {
temperature = <53000>;
hysteresis = <2000>;
type = "active";
};
cpu_cap_trip0: cpu-cap-trip0 {
temperature = <48000>;
hysteresis = <2000>;
type = "active";
};
cpu_floor_trip0: cpu-floor-trip0 {
temperature = <43000>;
hysteresis = <2000>;
type = "active";
};
};
cooling-maps {
map0 {
cooling-device = <&fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
trip = <&cpu_critical>;
};
map1 {
cooling-device = <&fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
trip = <&cpu_heavy>;
};
map2 {
cooling-device = <&fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
trip = <&cpu_throttle>;
};
map3 {
cooling-device = <&fan 1 1>;
trip = <&cpu_cap_trip1>;
};
map4 {
cooling-device = <&fan 2 2>;
trip = <&cpu_floor_trip1>;
};
map5 {
cooling-device = <&fan 3 3>;
trip = <&cpu_cap_trip0>;
};
map6 {
cooling-device = <&fan 4 4>;
trip = <&cpu_floor_trip0>;
};
};
};
gpu {
polling-delay-passive = <250>;
polling-delay = <500>;
status = "okay";
thermal-sensors = <&tmp451 1>;
trips {
gpu_critical: gpu-critical {
temperature = <103000>;
hysteresis = <0>;
type = "critical";
};
gpu_heavy: gpu-heavy {
temperature = <100000>;
hysteresis = <1000>;
type = "hot";
};
gpu_throttle: gpu-throttle {
temperature = <90500>;
hysteresis = <0>;
type = "passive";
};
};
cooling-maps {
map0 {
trip = <&gpu_critical>;
cooling-device = <&fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
};
map1 {
trip = <&gpu_heavy>;
cooling-device = <&fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
};
map2 {
trip = <&gpu_throttle>;
cooling-device = <&fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
};
};
};
pmic {
status = "okay";
polling-delay-passive = <250>;
polling-delay = <500>;
thermal-sensors = <&max77620>;
trips {
pmic_die_warn_temp_thresh: hot-die {
temperature = <120000>;
type = "hot";
hysteresis = <0>;
};
pmic_die_cirt_temp_thresh: critical-die {
temperature = <140000>;
type = "critical";
hysteresis = <0>;
};
};
cooling-maps {
map0 {
trip = <&pmic_die_warn_temp_thresh>;
cooling-device = <&throttle_heavy 1 1>;
contribution = <100>;
};
};
};
cpu_vreg {
status = "okay";
polling-delay-passive = <250>;
polling-delay = <500>;
thermal-sensors = <&cpu_max_reg>;
trips {
cpu_vreg_die_warn_temp_thresh: hot-die {
temperature = <120000>;
type = "hot";
hysteresis = <0>;
};
};
cooling-maps {
map0 {
trip = <&cpu_vreg_die_warn_temp_thresh>;
cooling-device = <&throttle_heavy 1 1>;
contribution = <100>;
};
};
};
gpu_vreg {
status = "okay";
polling-delay-passive = <250>;
polling-delay = <500>;
thermal-sensors = <&gpu_max_reg>;
trips {
gpu_vreg_die_warn_temp_thresh: hot-die {
temperature = <120000>;
type = "hot";
hysteresis = <0>;
};
};
cooling-maps {
/*
* There are currently no cooling maps,
* because there are no cooling devices.
*/
};
};
};
};
File diff suppressed because it is too large. Load diff
+5 -7
View File
@@ -1310,11 +1310,9 @@
nvidia,pad-autocal-pull-down-offset-sdr104 = <0x0>;
nvidia,default-tap = <0x2>;
nvidia,default-trim = <0x4>;
assigned-clocks = <&tegra_car TEGRA210_CLK_SDMMC4>,
<&tegra_car TEGRA210_CLK_PLL_C4_OUT0>,
<&tegra_car TEGRA210_CLK_PLL_C4>;
assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_C4_OUT0>;
assigned-clock-rates = <200000000>, <1000000000>, <1000000000>;
assigned-clocks = <&tegra_car TEGRA210_CLK_SDMMC1>,
<&tegra_car TEGRA210_CLK_PLL_C4_OUT2>;
assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_C4_OUT2>;
status = "disabled";
};
@@ -1377,8 +1375,8 @@
nvidia,default-tap = <0x8>;
nvidia,default-trim = <0x0>;
assigned-clocks = <&tegra_car TEGRA210_CLK_SDMMC4>,
<&tegra_car TEGRA210_CLK_PLL_C4_OUT0>;
assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_C4_OUT0>;
<&tegra_car TEGRA210_CLK_PLL_C4_OUT2>;
assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_C4_OUT2>;
nvidia,dqs-trim = <40>;
mmc-hs400-1_8v;
status = "disabled";
@@ -1,9 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
#include "tegra210b01-nx.dtsi"
/ {
model = "Nintendo Switch (OLED model)";
compatible = "nvidia,fric", "nintendo,aula", "nintendo,nx", "nvidia,tegra210b01";
};
@@ -1,432 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <dt-bindings/mfd/max77620.h>
#include "tegra210b01.dtsi"
/ {
aliases {
serial0 = &uarta;
};
chosen {
stdout-path = "serial0:115200n8";
};
memory@80000000 {
device_type = "memory";
reg = <0x0 0x80000000 0x0 0xc0000000>;
};
serial@70006000 {
/delete-property/ dmas;
/delete-property/ dma-names;
status = "okay";
};
pmc@7000e400 {
nvidia,invert-interrupt;
nvidia,suspend-mode = <0>;
nvidia,cpu-pwr-good-time = <0>;
nvidia,cpu-pwr-off-time = <0>;
nvidia,core-pwr-good-time = <13100 7800>;
nvidia,core-pwr-off-time = <44160>;
nvidia,core-power-req-active-high;
nvidia,sys-clock-req-active-high;
status = "okay";
};
mmc@700b0600 {
bus-width = <8>;
non-removable;
status = "okay";
};
clk32k_in: clock-32k {
compatible = "fixed-clock";
clock-frequency = <32768>;
#clock-cells = <0>;
};
cpus {
cpu@0 {
enable-method = "psci";
};
cpu@1 {
enable-method = "psci";
};
cpu@2 {
enable-method = "psci";
};
cpu@3 {
enable-method = "psci";
};
};
psci {
compatible = "arm,psci-1.0";
method = "smc";
};
i2c@7000d000 {
status = "okay";
clock-frequency = <400000>;
pmic_a: pmic@33 {
compatible = "maxim,max77812-regulator";
reg = <0x33>;
maxim,soft-start-slew-rate = <5000>;
maxim,shutdown-slew-rate = <5000>;
maxim,ramp-up-slew-rate = <5000>;
maxim,ramp-down-slew-rate = <5000>;
status = "okay";
/* interrupt-parent = <&gpio>; */
/* interrupts = <TEGRA_GPIO(K, 6) IRQ_TYPE_NONE>; */
regulators {
gpu_max_reg: m1vout {
regulator-name = "vdd-gpu";
regulator-min-microvolt = <250000>;
regulator-max-microvolt = <1525000>;
/* regulator-max-microamp = <10000000>; */ /* 0x33 cfg */
/* regulator-max-microamp = <15000000>; */ /* 0x31 cfg */
regulator-init-microvolt = <800000>;
regulator-ramp-delay = <5000>;
regulator-enable-ramp-delay = <5000>;
regulator-disable-ramp-delay = <5000>;
maxim,peak-current-limit-ua = <7200000>;
};
m2vout {
regulator-name = "vdd-mvout2";
regulator-min-microvolt = <250000>;
regulator-max-microvolt = <1525000>;
regulator-ramp-delay = <5000>;
regulator-enable-ramp-delay = <5000>;
regulator-disable-ramp-delay = <5000>;
maxim,peak-current-limit-ua = <7200000>;
};
ram_max_reg: m3vout {
status = "okay";
regulator-name = "vddio-ddr";
regulator-min-microvolt = <550000>; /* Set min lpddr4x normally allowed */
regulator-max-microvolt = <650000>; /* Set max lpddr4x normally allowed */
/* regulator-max-microamp = <5000000>; */
regulator-always-on;
regulator-boot-on;
/* regulator-init-microvolt = <600000>; */ /* Controlled by bootloader */
regulator-ramp-delay = <5000>;
regulator-enable-ramp-delay = <5000>;
regulator-disable-ramp-delay = <5000>;
maxim,peak-current-limit-ua = <7200000>;
};
cpu_max_reg: m4vout {
regulator-name = "vdd-cpu";
regulator-min-microvolt = <250000>;
regulator-max-microvolt = <1525000>;
/* regulator-max-microamp = <5000000>; */
regulator-always-on;
regulator-boot-on;
regulator-init-microvolt = <1000000>;
regulator-ramp-delay = <5000>;
regulator-enable-ramp-delay = <5000>;
regulator-disable-ramp-delay = <5000>;
maxim,peak-current-limit-ua = <7200000>;
};
};
};
pmic_b: pmic@3c {
compatible = "maxim,max77620";
reg = <0x3c>;
interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
#interrupt-cells = <2>;
interrupt-controller;
gpio-controller;
#gpio-cells = <2>;
pinctrl-names = "default";
pinctrl-0 = <&max77620_default>;
fps {
#address-cells = <1>;
#size-cells = <0>;
fps0 {
reg = <0>;
maxim,shutdown-fps-time-period-us = <5120>;
maxim,fps-event-source = <MAX77620_FPS_EVENT_SRC_EN0>;
};
fps1 {
reg = <1>;
maxim,shutdown-fps-time-period-us = <5120>;
maxim,fps-event-source = <MAX77620_FPS_EVENT_SRC_EN1>;
maxim,device-state-on-disabled-event = <MAX77620_FPS_INACTIVE_STATE_SLEEP>;
};
fps2 {
reg = <2>;
maxim,shutdown-fps-time-period-us = <5120>;
maxim,fps-event-source = <MAX77620_FPS_EVENT_SRC_EN0>;
};
};
// hog-0 {
// gpio-hog;
// output-high;
// gpios = <2 GPIO_ACTIVE_HIGH>,
// <7 GPIO_ACTIVE_HIGH>;
// };
max77620_default: pinmux {
gpio0 {
pins = "gpio0";
function = "gpio";
};
gpio1 {
pins = "gpio1";
function = "fps-out";
drive-open-drain = <1>;
maxim,active-fps-source = <MAX77620_FPS_SRC_0>;
maxim,active-fps-power-up-slot = <5>;
maxim,active-fps-power-down-slot = <0>;
};
gpio2 {
pins = "gpio2";
function = "fps-out";
drive-open-drain = <1>;
maxim,active-fps-source = <MAX77620_FPS_SRC_0>;
maxim,active-fps-power-up-slot = <6>;
maxim,active-fps-power-down-slot = <0>;
};
gpio3 {
pins = "gpio3";
function = "fps-out";
drive-open-drain = <1>;
maxim,active-fps-source = <MAX77620_FPS_SRC_0>;
maxim,active-fps-power-up-slot = <3>;
maxim,active-fps-power-down-slot = <0>;
};
gpio4 {
pins = "gpio4";
function = "32k-out1";
};
gpio5_6_7 {
pins = "gpio5", "gpio6", "gpio7";
function = "gpio";
drive-open-drain = <1>;
};
};
regulators {
in-ldo0-1-supply = <&max77620_sd2>;
in-ldo7-8-supply = <&max77620_sd2>;
max77620_sd0: sd0 {
regulator-name = "vdd-core";
regulator-min-microvolt = <625000>;
regulator-max-microvolt = <1400000>;
regulator-boot-on;
regulator-always-on;
maxim,active-fps-source = <MAX77620_FPS_SRC_1>;
maxim,active-fps-power-up-slot = <1>;
maxim,active-fps-power-down-slot = <7>;
// regulator-initial-mode = <REGULATOR_MODE_NORMAL>;
regulator-enable-ramp-delay = <50>;
regulator-disable-ramp-delay = <4080>;
maxim,ramp-rate-setting = <27500>;
regulator-ramp-delay = <27500>;
};
max77620_sd1: sd1 {
regulator-name = "vdd-ddr";
regulator-min-microvolt = <1050000>;
regulator-max-microvolt = <1175000>;
regulator-always-on;
regulator-boot-on;
/* regulator-init-microvolt = <1100000>; */ /* Controlled by bootloader */
// regulator-initial-mode = <REGULATOR_MODE_NORMAL>;
maxim,active-fps-source = <MAX77620_FPS_SRC_0>;
maxim,active-fps-power-up-slot = <5>;
maxim,active-fps-power-down-slot = <2>;
regulator-enable-ramp-delay = <60>;
regulator-disable-ramp-delay = <145800>;
maxim,ramp-rate-setting = <27500>;
regulator-ramp-delay = <27500>;
};
max77620_sd2: sd2 {
regulator-name = "vdd-pre-reg";
regulator-min-microvolt = <1325000>;
regulator-max-microvolt = <1325000>;
regulator-always-on;
regulator-boot-on;
maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
maxim,active-fps-power-up-slot = <0>;
maxim,active-fps-power-down-slot = <0>;
regulator-enable-ramp-delay = <40>;
regulator-disable-ramp-delay = <20000>;
maxim,ramp-rate-setting = <27500>;
regulator-ramp-delay = <27500>;
};
max77620_sd3: sd3 {
regulator-name = "vdd-1v8";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
regulator-boot-on;
maxim,active-fps-source = <MAX77620_FPS_SRC_0>;
maxim,active-fps-power-up-slot = <2>;
maxim,active-fps-power-down-slot = <4>;
// regulator-initial-mode = <REGULATOR_MODE_NORMAL>;
regulator-enable-ramp-delay = <50>;
regulator-disable-ramp-delay = <118000>;
maxim,ramp-rate-setting = <27500>;
regulator-ramp-delay = <27500>;
};
max77620_ldo0: ldo0 {
regulator-name = "avdd-sys";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-boot-on; /* Must be set for seamless display */
maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
maxim,active-fps-power-up-slot = <0>;
maxim,active-fps-power-down-slot = <0>;
regulator-enable-ramp-delay = <50>;
regulator-disable-ramp-delay = <4000>;
maxim,ramp-rate-setting = <50000>;
regulator-ramp-delay = <50000>;
};
max77620_ldo1: ldo1 {
regulator-name = "vdd-pex";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
maxim,active-fps-power-up-slot = <0>;
maxim,active-fps-power-down-slot = <0>;
regulator-enable-ramp-delay = <50>;
regulator-disable-ramp-delay = <7000>;
maxim,ramp-rate-setting = <50000>;
regulator-ramp-delay = <50000>;
};
max77620_ldo2: ldo2 {
regulator-name = "vddio-sdmmc1";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
maxim,active-fps-power-up-slot = <0>;
maxim,active-fps-power-down-slot = <0>;
regulator-enable-ramp-delay = <100>;
regulator-disable-ramp-delay = <6000>;
maxim,ramp-rate-setting = <50000>;
regulator-ramp-delay = <50000>;
};
max77620_ldo3: ldo3 {
regulator-name = "vdd-gc-3v1";
regulator-min-microvolt = <3100000>;
regulator-max-microvolt = <3100000>;
maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
maxim,active-fps-power-up-slot = <0>;
maxim,active-fps-power-down-slot = <0>;
regulator-enable-ramp-delay = <100>;
regulator-disable-ramp-delay = <3000>;
maxim,ramp-rate-setting = <50000>;
regulator-ramp-delay = <50000>;
};
max77620_ldo4: ldo4 {
regulator-name = "vdd-rtc";
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <800000>;
regulator-always-on;
regulator-boot-on;
maxim,active-fps-power-up-slot = <0>;
maxim,active-fps-power-down-slot = <7>;
maxim,active-fps-source = <MAX77620_FPS_SRC_0>;
regulator-enable-ramp-delay = <50>;
regulator-disable-ramp-delay = <610>;
maxim,ramp-rate-setting = <50000>;
regulator-ramp-delay = <50000>;
};
/* GC Card Vddio */
max77620_ldo5: ldo5 {
regulator-name = "vdd-gc-1v8";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
maxim,active-fps-power-up-slot = <0>;
maxim,active-fps-power-down-slot = <0>;
regulator-enable-ramp-delay = <70>;
regulator-disable-ramp-delay = <3000>;
maxim,ramp-rate-setting = <50000>;
regulator-ramp-delay = <50000>;
};
/* Touch Panel, ALS. Powers LDO 1V8. */
max77620_ldo6: ldo6 {
regulator-name = "vdd-tp-2v9";
regulator-min-microvolt = <2900000>;
regulator-max-microvolt = <2900000>;
regulator-boot-on; /* Decrease por time for Touch Panel. */
maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
maxim,active-fps-power-up-slot = <0>;
maxim,active-fps-power-down-slot = <0>;
regulator-enable-ramp-delay = <100>;
regulator-disable-ramp-delay = <3000>;
maxim,ramp-rate-setting = <50000>;
regulator-ramp-delay = <50000>;
};
/* Not used on T210B01 */
max77620_ldo7: ldo7 {
regulator-name = "vdd-gen-pll-edp";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>; /* 3100000 */
maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
maxim,active-fps-power-up-slot = <0>;
maxim,active-fps-power-down-slot = <0>;
regulator-enable-ramp-delay = <50>;
regulator-disable-ramp-delay = <2768>;
maxim,ramp-rate-setting = <50000>;
regulator-ramp-delay = <50000>;
};
/* Odin/Modin/Fric: DP. */
/* Vali: Powers LDO 2V8 for Sio VDD
* Powers LDO 1V8 for I2C1 VDDQ and ALC5639.
*/
max77620_ldo8: ldo8 {
regulator-name = "vdd-hdmi-dp";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
maxim,active-fps-source = <MAX77620_FPS_SRC_NONE>;
maxim,active-fps-power-up-slot = <0>;
maxim,active-fps-power-down-slot = <0>;
regulator-enable-ramp-delay = <50>;
regulator-disable-ramp-delay = <4000>;
maxim,ramp-rate-setting = <50000>;
regulator-ramp-delay = <50000>;
};
};
};
};
};
@@ -1,10 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
#include "tegra210b01-nx.dtsi"
/ {
model = "Nintendo Switch (2019)";
compatible = "nvidia,modin", "nvidia,odin", "nintendo,iowa", "nintendo,nx", "nvidia,tegra210b01";
};
@@ -5,7 +5,7 @@
/ {
model = "Nintendo Switch Lite";
compatible = "nvidia,vali", "nintendo,hoag", "nintendo,nx", "nvidia,tegra210b01";
compatible = "nvidia,vali", "nintendo,hoag", "nintendo,nx", "nvidia,tegra210b01", "nvidia,tegra210";
/* Joycon/Fan power (usb) */
v_vdd50_b: v-vdd50-b {
@@ -48,6 +48,33 @@
};
};
i2c@7000c000 {
bm92t: bm92t@18 {
status = "disabled";
/delete-property/ rohm,dp-signal-toggle-on-resume;
rohm,dp-disable;
rohm,pd-5v-current-limit-ma = <2000>;
rohm,pd-9v-current-limit-ma = <1500>;
rohm,pd-12v-current-limit-ma = <1200>;
rohm,pd-15v-current-limit-ma = <900>;
};
bq2419x: bq24193@6b {
battery_charger: charger {
ti,charge-voltage-limit-millivolt = <4320>; /* Adjusted by cell age */
ti,fast-charge-current-limit-milliamp = <1664>;
ti,temp-range = <0 18 47 58>;
ti,charge-thermal-voltage-limit = <4320 4320 4320 4080>; /* Adjusted by cell age */
ti,charge-current-limit = <512 640 1664 1664>;
};
};
fuel_gauge: fuel-gauge@36 {
maxim,over-volt = <4320>; /* Actual: 4370 mV */
maxim,kernel-maximum-soc = <100>; /* Adjusted by cell age */
};
};
i2c@7000d000 {
pmic_b: pmic@3c {
regulators {
@@ -64,4 +91,52 @@
};
};
i2c@546c0000 {
bus-pullup-supply = <&battery_reg>;
};
host1x@50000000 {
/* tegradc.1: DP */
dc@54240000 {
status = "disabled";
};
};
xusb: usb@70090000 {
status = "okay";
phys = <&{/padctl@7009f000/pads/usb2/lanes/usb2-0}>,
<&{/padctl@7009f000/pads/pcie/lanes/pcie-5}>;
phy-names = "usb2-0", "usb3-0";
extcon = <&bm92t 0>;
extcon-cable-names = "vbus";
avdd-usb-supply = <&vdd_3v3>;
dvddio-pex-supply = <&max77620_ldo1>;
hvddio-pex-supply = <&max77620_sd3>;
};
xudc: usb@700d0000 {
status = "okay";
phys = <&{/padctl@7009f000/pads/usb2/lanes/usb2-0}>,
<&{/padctl@7009f000/pads/pcie/lanes/pcie-5}>;
phy-names = "usb2-0", "usb3-0";
extcon = <&bm92t 1>;
extcon-cable-names = "id";
hvdd-usb-supply = <&vdd_3v3>;
avddio-usb-supply = <&max77620_ldo1>;
};
padctl@7009f000 {
status = "okay";
avdd-pll-utmip-supply = <&max77620_sd3>;
avdd-pll-uerefe-supply = <&max77620_ldo1>;
dvdd-pex-pll-supply = <&max77620_ldo1>;
hvdd-pex-pll-e-supply = <&max77620_sd3>;
};
};
@@ -48,6 +48,8 @@
};
pinmux@700008d4 {
compatible = "nvidia,tegra210b01-pinmux";
pinmux-sdmmc1-1v8-drv {
sdmmc1 {
nvidia,pull-down-strength = <0x8>;
@@ -132,6 +134,7 @@
assigned-clock-rates = <199680000>, <199680000>;
};
/* Tegra210B01 has MBIST patched and is missing VI unit */
pmc@7000e400 {
compatible = "nvidia,tegra210b01-pmc";
+1
View File
@@ -872,6 +872,7 @@ CONFIG_REGULATOR_HI6421V530=y
CONFIG_REGULATOR_HI655X=y
CONFIG_REGULATOR_LP873X=m
CONFIG_REGULATOR_MAX77620=y
CONFIG_REGULATOR_MAX77812=y
CONFIG_REGULATOR_MAX8973=y
CONFIG_REGULATOR_MAX20411=m
CONFIG_REGULATOR_MP8859=y
+9
View File
@@ -2236,6 +2236,15 @@ static int fw_devlink_create_devlink(struct device *con,
goto out;
}
/*
* SYNC_STATE_ONLY links are useless once a consumer device has probed.
* So, only create it if the consumer hasn't probed yet.
*/
if (flags & DL_FLAG_SYNC_STATE_ONLY &&
con->links.status != DL_DEV_NO_DRIVER &&
con->links.status != DL_DEV_PROBING)
goto out;
if (con != sup_dev && !device_link_add(con, sup_dev, flags)) {
dev_err(con, "Failed to create device link (0x%x) with supplier %s for %pfwf\n",
flags, dev_name(sup_dev), link->consumer);
+316 -8
View File
@@ -31,6 +31,7 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/i2c.h>
@@ -193,6 +194,37 @@
*/
#define REF_CLK_CYC_PER_DVCO_SAMPLE 4
/*
* DFLL_OUTPUT_RAMP_DELAY: after the DFLL's I2C PMIC output starts
* requesting the minimum TUNE_HIGH voltage, the minimum number of
* microseconds to wait for the PMIC's voltage output to finish
* slewing
*/
#define DFLL_OUTPUT_RAMP_DELAY 100
/*
* DFLL_TUNE_HIGH_DELAY: number of microseconds to wait between tests
* to see if the high voltage has been reached yet, during a
* transition from the low-voltage range to the high-voltage range
*/
#define DFLL_TUNE_HIGH_DELAY 2000
/*
* DFLL_TUNE_HIGH_MARGIN_STEPS: attempt to initially program the DFLL
* voltage target to a (DFLL_TUNE_HIGH_MARGIN_STEPS * 10 millivolt)
* margin above the high voltage floor, in closed-loop mode in the
* high-voltage range
*/
#define DFLL_TUNE_HIGH_MARGIN_STEPS 2
/*
* I2C_OUTPUT_ACTIVE_TEST_US: mandatory minimum interval (in
* microseconds) between testing whether the I2C controller is
* currently sending a voltage-set command. Some comments list this
* as being a worst-case margin for "disable propagation."
*/
#define I2C_OUTPUT_ACTIVE_TEST_US 2
/*
* REF_CLOCK_RATE: the DFLL reference clock rate currently supported by this
* driver, in Hz
@@ -224,6 +256,9 @@ enum dfll_ctrl_mode {
* enum dfll_tune_range - voltage range that the driver believes it's in
* @DFLL_TUNE_UNINITIALIZED: DFLL tuning not yet programmed
* @DFLL_TUNE_LOW: DFLL in the low-voltage range (or open-loop mode)
* @DFLL_TUNE_WAIT_DFLL: waiting for DFLL voltage output to reach high
* @DFLL_TUNE_WAIT_PMIC: waiting for PMIC to react to DFLL output
* @DFLL_TUNE_HIGH: DFLL in the high-voltage range
*
* Some DFLL tuning parameters may need to change depending on the
* DVCO's voltage; these states represent the ranges that the driver
@@ -232,7 +267,10 @@ enum dfll_ctrl_mode {
*/
enum dfll_tune_range {
DFLL_TUNE_UNINITIALIZED = 0,
DFLL_TUNE_LOW = 1,
DFLL_TUNE_LOW,
DFLL_TUNE_WAIT_DFLL,
DFLL_TUNE_WAIT_PMIC,
DFLL_TUNE_HIGH,
};
@@ -285,6 +323,10 @@ struct tegra_dfll {
struct dfll_rate_req last_req;
unsigned long last_unrounded_rate;
struct hrtimer tune_timer;
ktime_t tune_delay;
ktime_t tune_ramp_delay;
/* Parameters from DT */
u32 droop_ctrl;
u32 sample_rate;
@@ -305,6 +347,11 @@ struct tegra_dfll {
int lut_size;
u8 lut_bottom, lut_min, lut_max, lut_safe;
/* tuning parameters */
u8 tune_high_out_start;
u8 tune_high_out_min;
u8 tune_out_last;
/* PWM interface */
enum tegra_dfll_pmu_if pmu_if;
unsigned long pwm_rate;
@@ -312,6 +359,9 @@ struct tegra_dfll {
struct pinctrl_state *pwm_enable_state;
struct pinctrl_state *pwm_disable_state;
u32 reg_init_uV;
/* spinlock protecting register accesses */
spinlock_t lock;
};
#define clk_hw_to_dfll(_hw) container_of(_hw, struct tegra_dfll, dfll_clk_hw)
@@ -324,6 +374,8 @@ static const char * const mode_name[] = {
[DFLL_CLOSED_LOOP] = "closed_loop",
};
static void dfll_load_i2c_lut(struct tegra_dfll *td);
/*
* Register accessors
*/
@@ -361,6 +413,36 @@ static inline void dfll_i2c_wmb(struct tegra_dfll *td)
dfll_i2c_readl(td, DFLL_I2C_CFG);
}
/**
* is_output_i2c_req_pending - is an I2C voltage-set command in progress?
* @pdev: DFLL instance
*
* Returns 1 if an I2C request is in progress, or 0 if not. The DFLL
* IP block requires two back-to-back reads of the I2C_REQ_PENDING
* field to return 0 before the software can be sure that no I2C
* request is currently pending. Also, a minimum time interval
* between DFLL_I2C_STS reads is required by the IP block.
*/
static int is_output_i2c_req_pending(struct tegra_dfll *td)
{
u32 sts;
if (td->pmu_if == TEGRA_DFLL_PMU_PWM)
return 0;
sts = dfll_i2c_readl(td, DFLL_I2C_STS);
if (sts & DFLL_I2C_STS_I2C_REQ_PENDING)
return 1;
udelay(I2C_OUTPUT_ACTIVE_TEST_US);
sts = dfll_i2c_readl(td, DFLL_I2C_STS);
if (sts & DFLL_I2C_STS_I2C_REQ_PENDING)
return 1;
return 0;
}
/**
* dfll_is_running - is the DFLL currently generating a clock?
* @td: DFLL instance
@@ -452,13 +534,139 @@ static void dfll_tune_low(struct tegra_dfll *td)
td->tune_range = DFLL_TUNE_LOW;
dfll_writel(td, td->soc->cvb->cpu_dfll_data.tune0_low, DFLL_TUNE0);
dfll_writel(td, td->soc->cvb->cpu_dfll_data.tune1, DFLL_TUNE1);
dfll_writel(td, td->soc->cvb->cpu_dfll_data.tune1_low, DFLL_TUNE1);
dfll_wmb(td);
if (td->soc->set_clock_trimmers_low)
td->soc->set_clock_trimmers_low();
}
/**
* dfll_tune_high - tune DFLL and CPU clock shaper for high voltages
* @td: DFLL instance
*
* Tune the DFLL oscillator parameters and the CPU clock shaper
* for the high-voltage range. The bottom end of the high-voltage
* range is represented by the index td->soc->tune_high_min_millivolts.
* Used in closed-loop mode. No return value.
*/
static void dfll_tune_high(struct tegra_dfll *td)
{
u32 tune0_high;
u32 tune1_high;
td->tune_range = DFLL_TUNE_HIGH;
tune0_high = td->soc->cvb->cpu_dfll_data.tune0_high;
if (!tune0_high)
tune0_high = td->soc->cvb->cpu_dfll_data.tune0_low;
dfll_writel(td, tune0_high, DFLL_TUNE0);
tune1_high = td->soc->cvb->cpu_dfll_data.tune1_high;
if (!tune1_high)
tune1_high = td->soc->cvb->cpu_dfll_data.tune1_low;
dfll_writel(td, tune1_high, DFLL_TUNE1);
dfll_wmb(td);
if (td->soc->set_clock_trimmers_high)
td->soc->set_clock_trimmers_high();
}
/**
* dfll_set_close_loop_config - prepare to switch to closed-loop mode
* @pdev: DFLL instance
* @req: requested output rate
*
* Prepare to switch the DFLL to closed-loop mode. This involves
* switching the DFLL's tuning voltage regime (if necessary), and
* rewriting the LUT to restrict the minimum and maximum voltages. No
* return value.
*/
static void dfll_set_close_loop_config(struct tegra_dfll *td,
struct dfll_rate_req *req)
{
bool sample_tune_out_last = false;
switch (td->tune_range) {
case DFLL_TUNE_LOW:
if (req->lut_index > td->tune_high_out_start) {
hrtimer_start(&td->tune_timer, td->tune_delay,
HRTIMER_MODE_REL);
}
sample_tune_out_last = true;
break;
case DFLL_TUNE_HIGH:
case DFLL_TUNE_WAIT_DFLL:
case DFLL_TUNE_WAIT_PMIC:
if (req->lut_index <= td->tune_high_out_start)
dfll_tune_low(td);
break;
default:
BUG();
}
td->lut_min = td->tune_range == DFLL_TUNE_LOW ?
0 : td->tune_high_out_min;
if (sample_tune_out_last && td->pmu_if == TEGRA_DFLL_PMU_I2C) {
u32 val;
val = dfll_i2c_readl(td, DFLL_I2C_STS);
td->tune_out_last = val >> DFLL_I2C_STS_I2C_LAST_SHIFT;
td->tune_out_last &= OUT_MASK;
}
}
/**
* dfll_tune_timer_cb - timer callback while tuning low to high
* @data: struct platform_device * of the DFLL instance
*
* Timer callback, used when switching from TUNE_LOW to TUNE_HIGH in
* closed-loop mode. Waits for DFLL I2C voltage command output to
* reach tune_high_out_min, then waits for the PMIC to react to the
* command. No return value.
*/
static enum hrtimer_restart dfll_tune_timer_cb(struct hrtimer *timer)
{
struct tegra_dfll *td;
u32 val, out_min, out_last;
bool use_ramp_delay;
td = container_of(timer, struct tegra_dfll, tune_timer);
if (td->tune_range == DFLL_TUNE_WAIT_DFLL) {
out_min = td->lut_min;
if (td->pmu_if == TEGRA_DFLL_PMU_I2C) {
val = dfll_i2c_readl(td, DFLL_I2C_STS);
out_last = val >> DFLL_I2C_STS_I2C_LAST_SHIFT;
out_last &= OUT_MASK;
} else {
out_last = out_min;
}
use_ramp_delay = !is_output_i2c_req_pending(td);
use_ramp_delay |= td->tune_out_last != out_last;
if (use_ramp_delay &&
(out_last >= td->tune_high_out_min) &&
(out_min >= td->tune_high_out_min)) {
td->tune_range = DFLL_TUNE_WAIT_PMIC;
hrtimer_start(&td->tune_timer, td->tune_ramp_delay,
HRTIMER_MODE_REL);
} else {
hrtimer_start(&td->tune_timer, td->tune_delay,
HRTIMER_MODE_REL);
}
} else if (td->tune_range == DFLL_TUNE_WAIT_PMIC) {
dfll_tune_high(td);
}
return HRTIMER_NORESTART;
}
/*
* Output clock scaler helpers
*/
@@ -554,7 +762,6 @@ static int dfll_i2c_set_output_enabled(struct tegra_dfll *td, bool enable)
return 0;
}
/*
* DFLL-to-PWM controller interface
*/
@@ -679,10 +886,10 @@ static void dfll_load_i2c_lut(struct tegra_dfll *td)
u32 val;
for (i = 0; i < MAX_DFLL_VOLTAGES; i++) {
if (i < td->lut_min)
lut_index = td->lut_min;
else if (i > td->lut_max)
lut_index = td->lut_max;
if (i < td->lut_bottom)
lut_index = td->lut_bottom;
else if (i > td->lut_size - 1)
lut_index = td->lut_size - 1;
else
lut_index = i;
@@ -813,6 +1020,28 @@ static int find_lut_index_for_rate(struct tegra_dfll *td, unsigned long rate)
return -ENOENT;
}
/**
* find_mv_out_cap - find the out_map index with voltage >= @mv
* @td: DFLL instance
* @mv: millivolts
*
* Find the lut index with voltage greater than or equal to @mv,
* and return it. If all of the voltages in out_map are less than
* @mv, then return the lut index * corresponding to the highest
* possible voltage, even though it's less than @mv.
*/
static u8 find_mv_out_cap(struct tegra_dfll *td, int mv)
{
u8 i;
for (i = td->lut_bottom; i < td->lut_size; i++) {
if (td->lut_uv[i] >= mv * 1000)
return i;
}
return i - 1; /* maximum possible output */
}
/**
* dfll_calculate_rate_request - calculate DFLL parameters for a given rate
* @td: DFLL instance
@@ -913,6 +1142,7 @@ static int dfll_request_rate(struct tegra_dfll *td, unsigned long rate)
{
int ret;
struct dfll_rate_req req;
unsigned long flags;
if (td->mode == DFLL_UNINITIALIZED) {
dev_err(td->dev, "%s: Cannot set DFLL rate in %s mode\n",
@@ -927,8 +1157,12 @@ static int dfll_request_rate(struct tegra_dfll *td, unsigned long rate)
td->last_unrounded_rate = rate;
td->last_req = req;
if (td->mode == DFLL_CLOSED_LOOP)
if (td->mode == DFLL_CLOSED_LOOP) {
spin_lock_irqsave(&td->lock, flags);
dfll_set_close_loop_config(td, &td->last_req);
dfll_set_frequency_request(td, &td->last_req);
spin_unlock_irqrestore(&td->lock, flags);
}
return 0;
}
@@ -946,13 +1180,18 @@ static int dfll_request_rate(struct tegra_dfll *td, unsigned long rate)
*/
static int dfll_disable(struct tegra_dfll *td)
{
unsigned long flags;
if (td->mode != DFLL_OPEN_LOOP) {
dev_err(td->dev, "cannot disable DFLL in %s mode\n",
mode_name[td->mode]);
return -EINVAL;
}
spin_lock_irqsave(&td->lock, flags);
dfll_set_mode(td, DFLL_DISABLED);
spin_unlock_irqrestore(&td->lock, flags);
pm_runtime_put_sync(td->dev);
return 0;
@@ -1016,6 +1255,7 @@ static void dfll_set_open_loop_config(struct tegra_dfll *td)
static int dfll_lock(struct tegra_dfll *td)
{
struct dfll_rate_req *req = &td->last_req;
unsigned long flags;
switch (td->mode) {
case DFLL_CLOSED_LOOP:
@@ -1033,9 +1273,12 @@ static int dfll_lock(struct tegra_dfll *td)
else
dfll_i2c_set_output_enabled(td, true);
spin_lock_irqsave(&td->lock, flags);
dfll_set_mode(td, DFLL_CLOSED_LOOP);
dfll_set_close_loop_config(td, req);
dfll_set_frequency_request(td, req);
dfll_set_force_output_enabled(td, false);
spin_unlock_irqrestore(&td->lock, flags);
return 0;
default:
@@ -1055,14 +1298,19 @@ static int dfll_lock(struct tegra_dfll *td)
*/
static int dfll_unlock(struct tegra_dfll *td)
{
unsigned long flags;
switch (td->mode) {
case DFLL_CLOSED_LOOP:
spin_lock_irqsave(&td->lock, flags);
dfll_set_open_loop_config(td);
dfll_set_mode(td, DFLL_OPEN_LOOP);
if (td->pmu_if == TEGRA_DFLL_PMU_PWM)
dfll_pwm_set_output_enabled(td, false);
else
dfll_i2c_set_output_enabled(td, false);
spin_unlock_irqrestore(&td->lock, flags);
return 0;
case DFLL_OPEN_LOOP:
@@ -1325,8 +1573,10 @@ static int attr_registers_show(struct seq_file *s, void *data)
{
u32 val, offs;
struct tegra_dfll *td = s->private;
unsigned long flags;
seq_puts(s, "CONTROL REGISTERS:\n");
spin_lock_irqsave(&td->lock, flags);
for (offs = 0; offs <= DFLL_MONITOR_DATA; offs += 4) {
if (offs == DFLL_OUTPUT_CFG)
val = dfll_i2c_readl(td, offs);
@@ -1355,6 +1605,8 @@ static int attr_registers_show(struct seq_file *s, void *data)
__raw_readl(td->lut_base + offs));
}
spin_unlock_irqrestore(&td->lock, flags);
return 0;
}
@@ -1445,6 +1697,53 @@ static int dfll_init_clks(struct tegra_dfll *td)
return 0;
}
/**
* dfll_init_tuning_thresholds - set up the high voltage range, if possible
* @td: DFLL instance
*
* Determine whether the DFLL tuning parameters need to be
* reprogrammed when the DFLL voltage reaches a certain minimum
* threshold. No return value.
*/
static void dfll_init_tuning_thresholds(struct tegra_dfll *td)
{
u8 out_min, out_start, max_voltage_index;
max_voltage_index = td->lut_size - 1;
/*
* Convert high tuning voltage threshold into output LUT
* index, and add necessary margin. If voltage threshold is
* outside operating range set it at maximum output level to
* effectively disable tuning parameters adjustment.
*/
td->tune_high_out_min = max_voltage_index;
td->tune_high_out_start = max_voltage_index;
if (td->soc->tune_high_min_millivolts < td->soc->min_millivolts)
return; /* no difference between low & high voltage range */
out_min = find_mv_out_cap(td, td->soc->tune_high_min_millivolts);
if ((out_min + 2) > max_voltage_index)
return;
if (td->soc->cvb->cpu_dfll_data.tune_high_margin_millivolts) {
unsigned int mv;
mv = td->soc->tune_high_min_millivolts +
td->soc->cvb->cpu_dfll_data.tune_high_margin_millivolts;
if (mv * 1000 > td->lut_uv[max_voltage_index])
return;
out_start = max((u8)(out_min + 1), find_mv_out_cap(td, mv));
} else {
out_start = out_min + DFLL_TUNE_HIGH_MARGIN_STEPS;
}
if (out_start > max_voltage_index)
return;
td->tune_high_out_min = out_min;
td->tune_high_out_start = out_start;
}
/**
* dfll_init - Prepare the DFLL IP block for use
* @td: DFLL instance
@@ -1501,6 +1800,8 @@ static int dfll_init(struct tegra_dfll *td)
dfll_init_out_if(td);
dfll_init_tuning_thresholds(td);
pm_runtime_put_sync(td->dev);
return 0;
@@ -2057,12 +2358,19 @@ int tegra_dfll_register(struct platform_device *pdev,
if (ret)
return ret;
spin_lock_init(&td->lock);
ret = dfll_register_clk(td);
if (ret) {
dev_err(&pdev->dev, "DFLL clk registration failed\n");
return ret;
}
/* Initialize tuning timer */
hrtimer_setup(&td->tune_timer, dfll_tune_timer_cb, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
td->tune_delay = ktime_set(0, DFLL_TUNE_HIGH_DELAY * 1000);
td->tune_ramp_delay = ktime_set(0, DFLL_OUTPUT_RAMP_DELAY * 1000);
dfll_debug_init(td);
return 0;
+2
View File
@@ -31,6 +31,8 @@ struct tegra_dfll_soc_data {
unsigned long max_freq;
const struct cvb_table *cvb;
struct rail_alignment alignment;
unsigned int min_millivolts;
unsigned int tune_high_min_millivolts;
void (*init_clock_trimmers)(void);
void (*set_clock_trimmers_high)(void);
+39 -29
View File
@@ -64,7 +64,7 @@ static const unsigned long tegra114_cpu_max_freq_table[] = {
.cpu_dfll_data = { \
.tune0_low = 0x00b0039d, \
.tune0_high = 0x00b0009d, \
.tune1 = 0x0000001f, \
.tune1_low = 0x0000001f, \
.tune_high_min_millivolts = 1050, \
}
@@ -100,7 +100,7 @@ static const struct cvb_table tegra114_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0x00b0019d,
.tune0_high = 0x00b0019d,
.tune1 = 0x0000001f,
.tune1_low = 0x0000001f,
.tune_high_min_millivolts = 1000,
}
},
@@ -167,7 +167,7 @@ static const struct cvb_table tegra124_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0x005020ff,
.tune0_high = 0x005040ff,
.tune1 = 0x00000060,
.tune1_low = 0x00000060,
}
},
};
@@ -335,7 +335,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune0_high = 0xffead0ff,
.tune1 = 0x20091d9,
.tune1_low = 0x20091d9,
.tune_high_min_millivolts = 864,
}
},
@@ -348,7 +348,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune0_high = 0xffead0ff,
.tune1 = 0x20091d9,
.tune1_low = 0x20091d9,
.tune_high_min_millivolts = 864,
}
},
@@ -361,7 +361,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune0_high = 0xffead0ff,
.tune1 = 0x20091d9,
.tune1_low = 0x20091d9,
}
},
{
@@ -373,7 +373,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune0_high = 0xffead0ff,
.tune1 = 0x20091d9,
.tune1_low = 0x20091d9,
}
},
{
@@ -385,7 +385,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune0_high = 0xffead0ff,
.tune1 = 0x20091d9,
.tune1_low = 0x20091d9,
}
},
{
@@ -397,7 +397,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune0_high = 0xffead0ff,
.tune1 = 0x20091d9,
.tune1_low = 0x20091d9,
}
},
{
@@ -409,7 +409,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune0_high = 0xffead0ff,
.tune1 = 0x20091d9,
.tune1_low = 0x20091d9,
.tune_high_min_millivolts = 864,
}
},
@@ -422,7 +422,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune0_high = 0xffead0ff,
.tune1 = 0x20091d9,
.tune1_low = 0x20091d9,
.tune_high_min_millivolts = 864,
}
},
@@ -434,7 +434,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
TEGRA210_CPU_CVB_TABLE,
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune1 = 0x20091d9,
.tune1_low = 0x20091d9,
}
},
{
@@ -445,7 +445,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
TEGRA210_CPU_CVB_TABLE,
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune1 = 0x25501d0,
.tune1_low = 0x25501d0,
}
},
{
@@ -457,7 +457,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune0_high = 0xffead0ff,
.tune1 = 0x20091d9,
.tune1_low = 0x20091d9,
.tune_high_min_millivolts = 864,
}
},
@@ -470,7 +470,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune0_high = 0xffead0ff,
.tune1 = 0x25501d0,
.tune1_low = 0x25501d0,
.tune_high_min_millivolts = 864,
}
},
@@ -482,7 +482,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
TEGRA210_CPU_CVB_TABLE_XA,
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune1 = 0x17711BD,
.tune1_low = 0x17711BD,
}
},
{
@@ -494,7 +494,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune0_high = 0xffead0ff,
.tune1 = 0x20091d9,
.tune1_low = 0x20091d9,
.tune_high_min_millivolts = 864,
}
},
@@ -507,7 +507,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune0_high = 0xffead0ff,
.tune1 = 0x25501d0,
.tune1_low = 0x25501d0,
.tune_high_min_millivolts = 864,
}
},
@@ -519,7 +519,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
TEGRA210_CPU_CVB_TABLE,
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune1 = 0x20091d9,
.tune1_low = 0x20091d9,
}
},
{
@@ -530,7 +530,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
TEGRA210_CPU_CVB_TABLE,
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune1 = 0x25501d0,
.tune1_low = 0x25501d0,
}
},
{
@@ -542,7 +542,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune0_high = 0xffead0ff,
.tune1 = 0x20091d9,
.tune1_low = 0x20091d9,
.tune_high_min_millivolts = 864,
}
},
@@ -555,7 +555,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune0_high = 0xffead0ff,
.tune1 = 0x25501d0,
.tune1_low = 0x25501d0,
.tune_high_min_millivolts = 864,
}
},
@@ -568,7 +568,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune0_high = 0xffead0ff,
.tune1 = 0x20091d9,
.tune1_low = 0x20091d9,
.tune_high_min_millivolts = 864,
}
},
@@ -581,7 +581,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
.cpu_dfll_data = {
.tune0_low = 0xffead0ff,
.tune0_high = 0xffead0ff,
.tune1 = 0x25501d0,
.tune1_low = 0x25501d0,
.tune_high_min_millivolts = 864,
}
},
@@ -680,10 +680,13 @@ static struct cvb_table tegra210b01_cpu_cvb_tables[] = {
.process_id = -1,
.max_millivolts = 1120,
CPUB01_CVB_TABLE,
.vmin_coefficients = { 620000, 0, 0 },
.cpu_dfll_data = {
.tune0_low = 0x0000ffcf,
.tune1 = 0x012207ff,
.tune1_low = 0x012207ff,
.tune1_high = 0x03FFF7FF,
.tune_high_min_millivolts = 850,
.tune_high_margin_millivolts = 38,
}
},
{
@@ -691,11 +694,13 @@ static struct cvb_table tegra210b01_cpu_cvb_tables[] = {
.process_id = 1,
.max_millivolts = 1120,
CPUB01_CVB_TABLE_SLT_B1,
.vmin_coefficients = { 600000, 0, 0 },
.cpu_dfll_data = {
.tune0_low = 0x0000ffa0,
.tune0_high = 0x0000ffff,
.tune1 = 0x021107ff,
.tune1_low = 0x021107ff,
.tune_high_min_millivolts = 850,
.tune_high_margin_millivolts = 38,
}
},
{
@@ -703,11 +708,13 @@ static struct cvb_table tegra210b01_cpu_cvb_tables[] = {
.process_id = 0,
.max_millivolts = 1120,
CPUB01_CVB_TABLE_SLT_B0,
.vmin_coefficients = { 600000, 0, 0 },
.cpu_dfll_data = {
.tune0_low = 0x0000ff90,
.tune0_high = 0x0000ffff,
.tune1 = 0x021107ff,
.tune1_low = 0x021107ff,
.tune_high_min_millivolts = 850,
.tune_high_margin_millivolts = 38,
}
},
{
@@ -715,10 +722,12 @@ static struct cvb_table tegra210b01_cpu_cvb_tables[] = {
.process_id = -1,
.max_millivolts = 1120,
CPUB01_CVB_TABLE,
.vmin_coefficients = { 620000, 0, 0 },
.cpu_dfll_data = {
.tune0_low = 0x0000ffcf,
.tune1 = 0x012207ff,
.tune1_low = 0x012207ff,
.tune_high_min_millivolts = 850,
.tune_high_margin_millivolts = 38,
}
},
};
@@ -845,7 +854,8 @@ static int tegra124_dfll_fcpu_probe(struct platform_device *pdev)
soc->cvb = tegra_cvb_add_opp_table(soc->dev, fcpu_data->cpu_cvb_tables,
fcpu_data->cpu_cvb_tables_size,
&align, process_id, speedo_id,
speedo_value, soc->max_freq);
speedo_value, soc->max_freq,
&soc->min_millivolts);
soc->alignment = align;
if (IS_ERR(soc->cvb)) {
+10 -8
View File
@@ -1812,7 +1812,7 @@ static struct div_nmp pllss_nmp = {
static struct tegra_clk_pll_freq_table pll_c4_vco_freq_table[] = {
{ 12000000, 600000000, 50, 1, 1, 0 },
{ 13000000, 600000000, 46, 1, 1, 0 }, /* actual: 598.0 MHz */
{ 38400000, 600000000, 62, 4, 1, 0 }, /* actual: 595.2 MHz */
{ 38400000, 998400000, 78, 3, 1, 0 },
{ 0, 0, 0, 0, 0, 0 },
};
@@ -1824,14 +1824,16 @@ static const struct clk_div_table pll_vco_post_div_table[] = {
{ .val = 4, .div = 5 },
{ .val = 5, .div = 6 },
{ .val = 6, .div = 8 },
{ .val = 7, .div = 10 },
{ .val = 8, .div = 12 },
{ .val = 9, .div = 16 },
{ .val = 10, .div = 12 },
{ .val = 7, .div = 9 },
{ .val = 8, .div = 10 },
{ .val = 9, .div = 12 },
{ .val = 10, .div = 15 },
{ .val = 11, .div = 16 },
{ .val = 12, .div = 20 },
{ .val = 13, .div = 24 },
{ .val = 14, .div = 32 },
{ .val = 12, .div = 18 },
{ .val = 13, .div = 20 },
{ .val = 14, .div = 24 },
{ .val = 15, .div = 30 },
{ .val = 16, .div = 32 },
{ .val = 0, .div = 0 },
};
+77 -73
View File
@@ -1705,7 +1705,6 @@ static struct div_nmp pllss_nmp = {
static struct tegra_clk_pll_freq_table pll_c4_vco_freq_table[] = {
{ 38400000, 998400000, 52, 2, 1, 0 },
{ 38400000, 787200000, 41, 2, 1, 0 },
{ 0, 0, 0, 0, 0, 0 },
};
@@ -2177,9 +2176,9 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = {
[tegra_clk_i2s0] = { .dt_id = TEGRA210_CLK_I2S0, .present = true },
[tegra_clk_apbdma] = { .dt_id = TEGRA210_CLK_APBDMA, .present = true },
[tegra_clk_kfuse] = { .dt_id = TEGRA210_CLK_KFUSE, .present = true },
[tegra_clk_sbc1_9] = { .dt_id = TEGRA210_CLK_SBC1, .present = true },
[tegra_clk_sbc2_9] = { .dt_id = TEGRA210_CLK_SBC2, .present = true },
[tegra_clk_sbc3_9] = { .dt_id = TEGRA210_CLK_SBC3, .present = true },
[tegra_clk_sbc1_9] = { .dt_id = TEGRA210_CLK_SBC1, .use_integer_div = true, .present = true },
[tegra_clk_sbc2_9] = { .dt_id = TEGRA210_CLK_SBC2, .use_integer_div = true, .present = true },
[tegra_clk_sbc3_9] = { .dt_id = TEGRA210_CLK_SBC3, .use_integer_div = true, .present = true },
[tegra_clk_i2c5] = { .dt_id = TEGRA210_CLK_I2C5, .present = true },
[tegra_clk_csi] = { .dt_id = TEGRA210_CLK_CSI, .present = true },
[tegra_clk_i2c2] = { .dt_id = TEGRA210_CLK_I2C2, .present = true },
@@ -2189,20 +2188,20 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = {
[tegra_clk_bsev] = { .dt_id = TEGRA210_CLK_BSEV, .present = true },
[tegra_clk_uartd_8] = { .dt_id = TEGRA210_CLK_UARTD, .present = true },
[tegra_clk_i2c3] = { .dt_id = TEGRA210_CLK_I2C3, .present = true },
[tegra_clk_sbc4_9] = { .dt_id = TEGRA210_CLK_SBC4, .present = true },
[tegra_clk_sbc4_9] = { .dt_id = TEGRA210_CLK_SBC4, .use_integer_div = true, .present = true },
[tegra_clk_sdmmc3_9] = { .dt_id = TEGRA210_CLK_SDMMC3, .present = true },
[tegra_clk_pcie] = { .dt_id = TEGRA210_CLK_PCIE, .present = true },
[tegra_clk_owr_8] = { .dt_id = TEGRA210_CLK_OWR, .present = true },
[tegra_clk_afi] = { .dt_id = TEGRA210_CLK_AFI, .present = true },
[tegra_clk_csite_8] = { .dt_id = TEGRA210_CLK_CSITE, .present = true },
[tegra_clk_soc_therm_8] = { .dt_id = TEGRA210_CLK_SOC_THERM, .present = true },
[tegra_clk_soc_therm_8] = { .dt_id = TEGRA210_CLK_SOC_THERM, .use_integer_div = true, .present = true },
[tegra_clk_dtv] = { .dt_id = TEGRA210_CLK_DTV, .present = true },
[tegra_clk_i2cslow] = { .dt_id = TEGRA210_CLK_I2CSLOW, .present = true },
[tegra_clk_i2cslow] = { .dt_id = TEGRA210_CLK_I2CSLOW, .use_integer_div = true, .present = true },
[tegra_clk_tsec_8] = { .dt_id = TEGRA210_CLK_TSEC, .present = true },
[tegra_clk_xusb_host] = { .dt_id = TEGRA210_CLK_XUSB_HOST, .present = true },
[tegra_clk_csus] = { .dt_id = TEGRA210_CLK_CSUS, .present = true },
[tegra_clk_mselect] = { .dt_id = TEGRA210_CLK_MSELECT, .present = true },
[tegra_clk_tsensor] = { .dt_id = TEGRA210_CLK_TSENSOR, .present = true },
[tegra_clk_tsensor] = { .dt_id = TEGRA210_CLK_TSENSOR, .use_integer_div = true, .present = true },
[tegra_clk_i2s3] = { .dt_id = TEGRA210_CLK_I2S3, .present = true },
[tegra_clk_i2s4] = { .dt_id = TEGRA210_CLK_I2S4, .present = true },
[tegra_clk_i2c4] = { .dt_id = TEGRA210_CLK_I2C4, .present = true },
@@ -2217,8 +2216,8 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = {
[tegra_clk_sata_8] = { .dt_id = TEGRA210_CLK_SATA, .present = true },
[tegra_clk_hda_8] = { .dt_id = TEGRA210_CLK_HDA, .present = true },
[tegra_clk_hda2hdmi] = { .dt_id = TEGRA210_CLK_HDA2HDMI, .present = true },
[tegra_clk_cilab] = { .dt_id = TEGRA210_CLK_CILAB, .present = true },
[tegra_clk_cilcd] = { .dt_id = TEGRA210_CLK_CILCD, .present = true },
[tegra_clk_cilab] = { .dt_id = TEGRA210_CLK_CILAB, .use_integer_div = true, .present = true },
[tegra_clk_cilcd] = { .dt_id = TEGRA210_CLK_CILCD, .use_integer_div = true, .present = true },
[tegra_clk_cile] = { .dt_id = TEGRA210_CLK_CILE, .present = true },
[tegra_clk_dsialp] = { .dt_id = TEGRA210_CLK_DSIALP, .present = true },
[tegra_clk_dsiblp] = { .dt_id = TEGRA210_CLK_DSIBLP, .present = true },
@@ -2238,7 +2237,7 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = {
[tegra_clk_pll_g_ref] = { .dt_id = TEGRA210_CLK_PLL_G_REF, .present = true, },
[tegra_clk_uartb_8] = { .dt_id = TEGRA210_CLK_UARTB, .present = true },
[tegra_clk_spdif_in_8] = { .dt_id = TEGRA210_CLK_SPDIF_IN, .present = true },
[tegra_clk_spdif_out] = { .dt_id = TEGRA210_CLK_SPDIF_OUT, .present = true },
[tegra_clk_spdif_out] = { .dt_id = TEGRA210_CLK_SPDIF_OUT, .use_integer_div = true, .present = true },
[tegra_clk_vi_10] = { .dt_id = TEGRA210_CLK_VI, .present = true },
[tegra_clk_vi_sensor_8] = { .dt_id = TEGRA210_CLK_VI_SENSOR, .present = true },
[tegra_clk_fuse] = { .dt_id = TEGRA210_CLK_FUSE, .present = true },
@@ -2276,7 +2275,6 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = {
[tegra_clk_pll_u_60m] = { .dt_id = TEGRA210_CLK_PLL_U_60M, .present = true },
[tegra_clk_pll_u_48m] = { .dt_id = TEGRA210_CLK_PLL_U_48M, .present = true },
[tegra_clk_pll_x] = { .dt_id = TEGRA210_CLK_PLL_X, .present = true },
[tegra_clk_pll_x_out0] = { .dt_id = TEGRA210_CLK_PLL_X_OUT0, .present = true },
[tegra_clk_pll_re_vco] = { .dt_id = TEGRA210_CLK_PLL_RE_VCO, .present = true },
[tegra_clk_pll_re_out] = { .dt_id = TEGRA210_CLK_PLL_RE_OUT, .present = true },
[tegra_clk_spdif_in_sync] = { .dt_id = TEGRA210_CLK_SPDIF_IN_SYNC, .present = true },
@@ -2310,7 +2308,6 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = {
[tegra_clk_hclk] = { .dt_id = TEGRA210_CLK_HCLK, .present = true },
[tegra_clk_pclk] = { .dt_id = TEGRA210_CLK_PCLK, .present = true },
[tegra_clk_cclk_g] = { .dt_id = TEGRA210_CLK_CCLK_G, .present = true },
[tegra_clk_cclk_lp] = { .dt_id = TEGRA210_CLK_CCLK_LP, .present = true },
[tegra_clk_dfll_ref] = { .dt_id = TEGRA210_CLK_DFLL_REF, .present = true },
[tegra_clk_dfll_soc] = { .dt_id = TEGRA210_CLK_DFLL_SOC, .present = true },
[tegra_clk_vi_sensor2_8] = { .dt_id = TEGRA210_CLK_VI_SENSOR2, .present = true },
@@ -2325,8 +2322,8 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = {
[tegra_clk_spdif_mux] = { .dt_id = TEGRA210_CLK_SPDIF_MUX, .present = true },
[tegra_clk_maud] = { .dt_id = TEGRA210_CLK_MAUD, .present = true },
[tegra_clk_mipibif] = { .dt_id = TEGRA210_CLK_MIPIBIF, .present = true },
[tegra_clk_qspi] = { .dt_id = TEGRA210_CLK_QSPI, .present = true },
[tegra_clk_sdmmc_legacy] = { .dt_id = TEGRA210_CLK_SDMMC_LEGACY, .present = true },
[tegra_clk_qspi] = { .dt_id = TEGRA210_CLK_QSPI, .use_integer_div = true, .present = true },
[tegra_clk_sdmmc_legacy] = { .dt_id = TEGRA210_CLK_SDMMC_LEGACY, .use_integer_div = true, .present = true },
[tegra_clk_tsecb] = { .dt_id = TEGRA210_CLK_TSECB, .present = true },
[tegra_clk_uartape] = { .dt_id = TEGRA210_CLK_UARTAPE, .present = true },
[tegra_clk_vi_i2c] = { .dt_id = TEGRA210_CLK_VI_I2C, .present = true },
@@ -2535,7 +2532,7 @@ static void tegra210_utmi_hw_sequencer_enable(void)
udelay(1);
}
static int tegra210_enable_utmipll(void)
static int tegra210b01_enable_utmipll(void)
{
u32 reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
bool hw_on = reg & UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE;
@@ -2618,7 +2615,7 @@ static int tegra210_enable_pllu(void)
return 0;
}
static int tegra210_init_pllu(void)
static int tegra210b01_init_pllu(void)
{
u32 reg;
int err;
@@ -2676,7 +2673,7 @@ static int tegra210_init_pllu(void)
}
/* enable UTMIPLL hw control if not yet done by the bootloader */
return tegra210_enable_utmipll();
return tegra210b01_enable_utmipll();
}
/*
@@ -2876,7 +2873,7 @@ static __init void tegra210_periph_clk_init(struct device_node *np,
tegra210_clk_register_mc("mc", "emc");
}
static void __init tegra210_pll_init(void __iomem *clk_base,
static void __init tegra210b01_pll_init(void __iomem *clk_base,
void __iomem *pmc)
{
struct clk *clk;
@@ -2921,7 +2918,7 @@ static void __init tegra210_pll_init(void __iomem *clk_base,
clks[TEGRA210_CLK_PLL_C3] = clk;
/* PLLU_VCO */
if (!tegra210_init_pllu()) {
if (!tegra210b01_init_pllu()) {
clk = clk_register_fixed_rate(NULL, "pll_u_vco", "pll_ref", 0,
480*1000*1000);
clk_register_clkdev(clk, "pll_u_vco", NULL);
@@ -3030,8 +3027,8 @@ static void __init tegra210_pll_init(void __iomem *clk_base,
clks[TEGRA210_CLK_PLL_E] = clk;
/* PLLC4 */
clk = tegra_clk_register_pllre_tegra210("pll_c4_vco", "pll_ref",
clk_base, pmc, 0, &pll_c4_vco_params, NULL, pll_ref_freq);
clk = tegra_clk_register_pllre("pll_c4_vco", "pll_ref", clk_base, pmc,
0, &pll_c4_vco_params, NULL, pll_ref_freq);
clk_register_clkdev(clk, "pll_c4_vco", NULL);
clks[TEGRA210_CLK_PLL_C4] = clk;
@@ -3098,6 +3095,55 @@ static void __init tegra210_pll_init(void __iomem *clk_base,
clks[TEGRA210_CLK_PLL_P_UPHY_OUT] = clk;
}
static char *tegra210b01_determine_pllc4_rate(void)
{
struct device_node *node;
u32 val;
int out0_ratio, i;
unsigned long sdmmc_max_rate = 0;
struct clk *clk;
char *sclk_high_clk;
for_each_compatible_node(node, NULL, "nvidia,tegra210-sdhci") {
if (!of_device_is_available(node))
continue;
if (!of_property_read_u32(node, "max-frequency", &val)
&& val > sdmmc_max_rate)
sdmmc_max_rate = val;
}
switch (sdmmc_max_rate) {
case 266000000:
sclk_high_clk = "pll_c4_out1";
pll_c4_vco_params.fixed_rate = 798000000;
out0_ratio = 4;
break;
default:
sclk_high_clk = "pll_c4_out3";
pll_c4_vco_params.fixed_rate = 1000000000;
out0_ratio = 1;
break;
}
pll_c4_vco_params.fixed_rate /= pll_ref_freq/pll_c4_vco_params.mdiv_default;
pll_c4_vco_params.fixed_rate *= pll_ref_freq/pll_c4_vco_params.mdiv_default;
val = readl(clk_base + PLLC4_BASE);
for (i = 0; pll_vco_post_div_table[i].div; i++)
if (pll_vco_post_div_table[i].div >= out0_ratio)
break;
val &= ~GENMASK(23, 19);
val |= pll_vco_post_div_table[i].val << pll_c4_vco_params.div_nmp->divp_shift;
writel(val, clk_base + PLLC4_BASE);
clk = clk_register_fixed_factor(NULL, "pll_c4_out0", "pll_c4_vco", 0,
1, pll_vco_post_div_table[i].div);
clks[TEGRA210_CLK_PLL_C4_OUT0] = clk;
return sclk_high_clk;
}
/* Tegra210 CPU clock and reset control functions */
static void tegra210_wait_cpu_in_reset(u32 cpu)
{
@@ -3179,7 +3225,7 @@ static void tegra210_clk_resume(void *data)
fence_udelay(2, clk_base);
/* restore PLLs and all peripheral clock rates */
tegra210_init_pllu();
tegra210b01_init_pllu();
clk_restore_context();
/* restore saved context of peripheral clocks and reset state */
@@ -3227,12 +3273,9 @@ static const struct of_device_id pmc_match[] __initconst = {
};
static struct tegra_clk_init_table t210b01_init_table[] __initdata = {
{ TEGRA210_CLK_PLL_A, TEGRA210_CLK_CLK_MAX, 564480000, 1,
TEGRA_TABLE_RATE_CHANGE_OVERCLOCK },
{ TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 0, 1,
TEGRA_TABLE_RATE_CHANGE_OVERCLOCK },
{ TEGRA210_CLK_PLL_DP, TEGRA210_CLK_CLK_MAX, 270000000, 0,
TEGRA_TABLE_RATE_CHANGE_OVERCLOCK },
{ TEGRA210_CLK_PLL_A, TEGRA210_CLK_CLK_MAX, 564480000, 1, TEGRA_TABLE_RATE_CHANGE_OVERCLOCK },
//{ TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 0, 1, TEGRA_TABLE_RATE_CHANGE_OVERCLOCK },
{ TEGRA210_CLK_PLL_DP, TEGRA210_CLK_CLK_MAX, 270000000, 0, TEGRA_TABLE_RATE_CHANGE_OVERCLOCK },
{ TEGRA210_CLK_PLL_P_UPHY_OUT, TEGRA210_CLK_CLK_MAX, 102000000, 1 },
{ TEGRA210_CLK_SDMMC_LEGACY, TEGRA210_CLK_PLL_P, 12000000, 0 },
{ TEGRA210_CLK_I2CSLOW, TEGRA210_CLK_CLK_32K, 32000, 0 },
@@ -3403,48 +3446,6 @@ static int tegra210b01_reset_deassert(unsigned long id)
return 0;
}
static enum clk_id tegra210b01_integer_div_id[] = {
tegra_clk_cilab,
tegra_clk_cilcd,
tegra_clk_spdif_out,
tegra_clk_sbc1_9,
tegra_clk_sbc2_9,
tegra_clk_sbc3_9,
tegra_clk_sbc4_9,
tegra_clk_sdmmc_legacy,
tegra_clk_i2cslow,
tegra_clk_qspi,
tegra_clk_soc_therm_8,
tegra_clk_tsensor,
};
static void tegra210b01_adjust_clks(struct tegra_clk *tegra_clks)
{
int i;
/* Remove CPU_LP claster clocks */
tegra_clks[tegra_clk_cclk_lp].present = false;
tegra_clks[tegra_clk_pll_x_out0].present = false;
/* Prevent 1:1.5 fractional divider setting */
div1_5_not_allowed = true;
/* Prevent any fractional setting */
for (i = 0; i < ARRAY_SIZE(tegra210b01_integer_div_id); i++) {
enum clk_id cid = tegra210b01_integer_div_id[i];
if (cid >= tegra_clk_max || !tegra_clks[cid].present) {
pr_warn("%s: clk %d is not present\n", __func__, cid);
continue;
}
tegra_clks[cid].use_integer_div = true;
}
}
/**
* tegra210b01_clock_init - Tegra210-specific clock initialization
* @np: struct device_node * of the DT node for the SoC CAR IP block
@@ -3457,6 +3458,7 @@ static void tegra210b01_adjust_clks(struct tegra_clk *tegra_clks)
static void __init tegra210b01_clock_init(struct device_node *np)
{
struct device_node *node;
char *sclk_high_clk;
u32 value, clk_m_div;
clk_base = of_iomap(np, 0);
@@ -3485,7 +3487,8 @@ static void __init tegra210b01_clock_init(struct device_node *np)
if (!clks)
return;
tegra210b01_adjust_clks(tegra210_clks);
/* Prevent 1:1.5 fractional divider setting */
div1_5_not_allowed = true;
value = readl(clk_base + SPARE_REG0) >> CLK_M_DIVISOR_SHIFT;
clk_m_div = (value & CLK_M_DIVISOR_MASK) + 1;
@@ -3496,7 +3499,8 @@ static void __init tegra210b01_clock_init(struct device_node *np)
return;
tegra_fixed_clk_init(tegra210_clks);
tegra210_pll_init(clk_base, pmc_base);
sclk_high_clk = tegra210b01_determine_pllc4_rate();
tegra210b01_pll_init(clk_base, pmc_base);
tegra210_periph_clk_init(np, clk_base, pmc_base);
tegra_audio_clk_init(clk_base, pmc_base, tegra210_clks,
tegra210_audio_plls,
+13 -4
View File
@@ -54,13 +54,18 @@ static int round_voltage(int mv, const struct rail_alignment *align, int up)
static int build_opp_table(struct device *dev, const struct cvb_table *table,
struct rail_alignment *align,
int speedo_value, unsigned long max_freq)
int speedo_value, unsigned long max_freq, int *vmin)
{
int i, ret, dfll_mv, min_mv, max_mv;
min_mv = round_voltage(table->min_millivolts, align, UP);
max_mv = round_voltage(table->max_millivolts, align, DOWN);
dfll_mv = get_cvb_voltage(
speedo_value, table->speedo_scale, &table->vmin_coefficients);
dfll_mv = round_cvb_voltage(dfll_mv, table->voltage_scale, align);
min_mv = max(min_mv, dfll_mv);
for (i = 0; i < MAX_DVFS_FREQS; i++) {
const struct cvb_table_freq_entry *entry = &table->entries[i];
@@ -78,6 +83,9 @@ static int build_opp_table(struct device *dev, const struct cvb_table *table,
return ret;
}
if (vmin)
*vmin = min_mv;
return 0;
}
@@ -90,7 +98,8 @@ static int build_opp_table(struct device *dev, const struct cvb_table *table,
* @process_id: process id of the HW module
* @speedo_id: speedo id of the HW module
* @speedo_value: speedo value of the HW module
* @max_freq: highest safe clock rate
* @max_rate: highest safe clock rate
* @vmin: final minimum voltage returned to the caller
*
* On Tegra, a CVB table encodes the relationship between operating voltage
* and safe maximal frequency for a given module (e.g. GPU or CPU). This
@@ -103,7 +112,7 @@ const struct cvb_table *
tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *tables,
size_t count, struct rail_alignment *align,
int process_id, int speedo_id, int speedo_value,
unsigned long max_freq)
unsigned long max_freq, int *vmin)
{
size_t i;
int ret;
@@ -118,7 +127,7 @@ tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *tables,
continue;
ret = build_opp_table(dev, table, align, speedo_value,
max_freq);
max_freq, vmin);
return ret ? ERR_PTR(ret) : table;
}
+5 -2
View File
@@ -31,8 +31,10 @@ struct cvb_table_freq_entry {
struct cvb_cpu_dfll_data {
u32 tune0_low;
u32 tune0_high;
u32 tune1;
u32 tune1_low;
u32 tune1_high;
unsigned int tune_high_min_millivolts;
unsigned int tune_high_margin_millivolts;
};
struct cvb_table {
@@ -46,13 +48,14 @@ struct cvb_table {
int voltage_scale;
struct cvb_table_freq_entry entries[MAX_DVFS_FREQS];
struct cvb_cpu_dfll_data cpu_dfll_data;
struct cvb_coefficients vmin_coefficients;
};
const struct cvb_table *
tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *cvb_tables,
size_t count, struct rail_alignment *align,
int process_id, int speedo_id, int speedo_value,
unsigned long max_freq);
unsigned long max_freq, int *vmin);
void tegra_cvb_remove_opp_table(struct device *dev,
const struct cvb_table *table,
unsigned long max_freq);
+4 -4
View File
@@ -285,9 +285,9 @@ static void gpio_irq_unmask(struct irq_data *d)
gpiochip_enable_irq(&chips->chip, hwirq);
status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
status &= IRQ_TYPE_EDGE_BOTH;
if (!status)
status = IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
status = IRQ_TYPE_EDGE_BOTH;
if (status & IRQ_TYPE_EDGE_FALLING)
writel_relaxed(mask, &g->set_falling);
@@ -297,7 +297,7 @@ static void gpio_irq_unmask(struct irq_data *d)
static int gpio_irq_type(struct irq_data *d, unsigned trigger)
{
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
if (trigger & ~IRQ_TYPE_EDGE_BOTH)
return -EINVAL;
return 0;
@@ -400,7 +400,7 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger)
mask = __gpio_mask(i);
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
if (trigger & ~IRQ_TYPE_EDGE_BOTH)
return -EINVAL;
writel_relaxed(mask, (trigger & IRQ_TYPE_EDGE_FALLING)
+1 -1
View File
@@ -160,7 +160,7 @@ mediatek_gpio_irq_type(struct irq_data *d, unsigned int type)
rg->hlevel | rg->llevel) & mask)
return 0;
type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
type = IRQ_TYPE_EDGE_BOTH;
}
rg->rising &= ~mask;
+2 -2
View File
@@ -1263,14 +1263,14 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
gc = irq_get_domain_generic_chip(mvchip->domain, 0);
gc->private = mvchip;
ct = &gc->chip_types[0];
ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
ct->type = IRQ_TYPE_LEVEL_MASK;
ct->chip.irq_mask = mvebu_gpio_level_irq_mask;
ct->chip.irq_unmask = mvebu_gpio_level_irq_unmask;
ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
ct->chip.name = mvchip->chip.label;
ct = &gc->chip_types[1];
ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
ct->type = IRQ_TYPE_EDGE_BOTH;
ct->chip.irq_ack = mvebu_gpio_irq_ack;
ct->chip.irq_mask = mvebu_gpio_edge_irq_mask;
ct->chip.irq_unmask = mvebu_gpio_edge_irq_unmask;
+2 -2
View File
@@ -198,7 +198,7 @@ static int mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
gc->private = port;
ct = &gc->chip_types[0];
ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
ct->type = IRQ_TYPE_LEVEL_MASK;
ct->chip.irq_ack = irq_gc_ack_set_bit;
ct->chip.irq_mask = irq_gc_mask_disable_reg;
ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
@@ -210,7 +210,7 @@ static int mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
ct->regs.disable = PINCTRL_PIN2IRQ(port) + MXS_CLR;
ct = &gc->chip_types[1];
ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
ct->type = IRQ_TYPE_EDGE_BOTH;
ct->chip.irq_ack = irq_gc_ack_set_bit;
ct->chip.irq_mask = irq_gc_mask_disable_reg;
ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
+4 -5
View File
@@ -432,8 +432,7 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
if (type & ~IRQ_TYPE_SENSE_MASK)
return -EINVAL;
if (!bank->regs->leveldetect0 &&
(type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
if (!bank->regs->leveldetect0 && (type & IRQ_TYPE_LEVEL_MASK))
return -EINVAL;
raw_spin_lock_irqsave(&bank->lock, flags);
@@ -450,9 +449,9 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
}
raw_spin_unlock_irqrestore(&bank->lock, flags);
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
if (type & IRQ_TYPE_LEVEL_MASK)
irq_set_handler_locked(d, handle_level_irq);
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
else if (type & IRQ_TYPE_EDGE_BOTH)
/*
* Edge IRQs are already cleared/acked in irq_handler and
* not need to be masked, as result handle_edge_irq()
@@ -702,7 +701,7 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
* after enabing the interrupt to clear the wakeup status.
*/
if (bank->regs->leveldetect0 && bank->regs->wkup_en &&
trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
trigger & IRQ_TYPE_LEVEL_MASK)
omap_clear_gpio_irqstatus(bank, offset);
if (trigger)
+2 -3
View File
@@ -132,8 +132,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
if (offset < 0 || offset >= PL061_GPIO_NR)
return -EINVAL;
if ((trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) &&
(trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)))
if ((trigger & IRQ_TYPE_LEVEL_MASK) && (trigger & IRQ_TYPE_EDGE_BOTH))
{
dev_err(gc->parent,
"trying to configure line %d for both level and edge "
@@ -149,7 +148,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
gpiois = readb(pl061->base + GPIOIS);
gpioibe = readb(pl061->base + GPIOIBE);
if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
if (trigger & IRQ_TYPE_LEVEL_MASK) {
bool polarity = trigger & IRQ_TYPE_LEVEL_HIGH;
/* Disable edge detection */
+1 -1
View File
@@ -406,7 +406,7 @@ static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type)
if (__gpio_is_occupied(pchip, gpio))
return 0;
type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
type = IRQ_TYPE_EDGE_BOTH;
}
gpdr = readl_relaxed(c->regbase + GPDR_OFFSET);
+2 -2
View File
@@ -169,9 +169,9 @@ static int rda_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
if (ret)
return ret;
if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
if (flow_type & IRQ_TYPE_LEVEL_MASK)
irq_set_handler_locked(data, handle_level_irq);
else if (flow_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
else if (flow_type & IRQ_TYPE_EDGE_BOTH)
irq_set_handler_locked(data, handle_edge_irq);
return 0;
+1 -1
View File
@@ -134,7 +134,7 @@ static int sa1100_gpio_type(struct irq_data *d, unsigned int type)
if (type == IRQ_TYPE_PROBE) {
if ((sgc->irqrising | sgc->irqfalling) & mask)
return 0;
type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
type = IRQ_TYPE_EDGE_BOTH;
}
if (type & IRQ_TYPE_EDGE_RISING)
+1 -1
View File
@@ -158,7 +158,7 @@ static int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd,
sd->gc->private = sd;
ct = sd->gc->chip_types;
ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
ct->type = IRQ_TYPE_LEVEL_MASK;
ct->regs.eoi = GPSTR;
ct->regs.mask = GPIO_INT;
ct->chip.irq_mask = irq_gc_mask_clr_bit;
+1 -1
View File
@@ -149,7 +149,7 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
int regoffset = offset / 8;
int mask = BIT(offset % 8);
if (type & IRQ_TYPE_LEVEL_LOW || type & IRQ_TYPE_LEVEL_HIGH)
if (type & IRQ_TYPE_LEVEL_MASK)
return -EINVAL;
/* STMPE801 and STMPE 1600 don't have RE and FE registers */
+4 -19
View File
@@ -172,18 +172,11 @@ static int tegra_gpio_direction_input(struct gpio_chip *chip,
unsigned int offset)
{
struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
int ret;
tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, offset), offset, 0);
tegra_gpio_enable(tgi, offset);
ret = pinctrl_gpio_direction_input(chip, offset);
if (ret < 0)
dev_err(tgi->dev,
"Failed to set pinctrl input direction of GPIO %d: %d",
chip->base + offset, ret);
return ret;
return 0;
}
static int tegra_gpio_direction_output(struct gpio_chip *chip,
@@ -191,19 +184,12 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip,
int value)
{
struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
int ret;
tegra_gpio_set(chip, offset, value);
tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, offset), offset, 1);
tegra_gpio_enable(tgi, offset);
ret = pinctrl_gpio_direction_output(chip, offset);
if (ret < 0)
dev_err(tgi->dev,
"Failed to set pinctrl output direction of GPIO %d: %d",
chip->base + offset, ret);
return ret;
return 0;
}
static int tegra_gpio_get_direction(struct gpio_chip *chip,
@@ -356,9 +342,9 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
return ret;
}
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
if (type & IRQ_TYPE_LEVEL_MASK)
irq_set_handler_locked(d, handle_level_irq);
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
else if (type & IRQ_TYPE_EDGE_BOTH)
irq_set_handler_locked(d, handle_edge_irq);
if (d->parent_data)
@@ -722,7 +708,6 @@ static int tegra_gpio_probe(struct platform_device *pdev)
tgi->gc.direction_output = tegra_gpio_direction_output;
tgi->gc.set = tegra_gpio_set;
tgi->gc.get_direction = tegra_gpio_get_direction;
tgi->gc.base = 0;
tgi->gc.ngpio = tgi->bank_count * 32;
tgi->gc.parent = &pdev->dev;
+1 -1
View File
@@ -149,7 +149,7 @@ static int timbgpio_irq_type(struct irq_data *d, unsigned trigger)
if (ver > 2)
bflr = ioread32(tgpio->membase + TGPIO_BFLR);
if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
if (trigger & IRQ_TYPE_LEVEL_MASK) {
bflr &= ~(1 << offset);
flr &= ~(1 << offset);
if (trigger & IRQ_TYPE_LEVEL_HIGH)
+9
View File
@@ -354,6 +354,15 @@ config DRM_PANEL_JDI_LPM102A188A
The panel has a 2560×1800 resolution. It provides a MIPI DSI interface
to the host.
config DRM_PANEL_NX_DSI
tristate "Nintendo Switch 720x1280 DSI 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 the DSI panels
used in the Nintendo Switch.
config DRM_PANEL_JDI_LT070ME05000
tristate "JDI LT070ME05000 WUXGA DSI panel"
depends on OF
+1
View File
@@ -62,6 +62,7 @@ obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672E) += panel-novatek-nt36672e.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT37700F) += panel-novatek-nt37700f.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT37801) += panel-novatek-nt37801.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o
obj-$(CONFIG_DRM_PANEL_NX_DSI) += panel-nx-dsi.o
obj-$(CONFIG_DRM_PANEL_MANTIX_MLAF057WE51) += panel-mantix-mlaf057we51.o
obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o
obj-$(CONFIG_DRM_PANEL_ORISETECH_OTA5601A) += panel-orisetech-ota5601a.o
+772
View File
@@ -0,0 +1,772 @@
/*
* Copyright (C) 2018 SwtcR <swtcr0@gmail.com>
* Copyright (C) 2023-2024 Azkali <a.ffcc7@gmail.com>
*
* Based on Sharp ls043t1le01 panel driver by Werner Johansson <werner.johansson@sonymobile.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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <video/mipi_display.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_crtc.h>
#include <drm/drm_panel.h>
#include <drm/drm_modes.h>
/*! MIPI DCS Panel Private CMDs. */
#define MIPI_DCS_PRIV_SM_SET_COLOR_MODE ((u8)0xA0)
#define MIPI_DCS_PRIV_SM_SET_REG_OFFSET ((u8)0xB0)
#define MIPI_DCS_PRIV_SM_SET_ELVSS ((u8)0xB1) /* OLED backlight tuning. Byte7: PWM transition time in frames. */
#define MIPI_DCS_PRIV_SET_POWER_CONTROL ((u8)0xB1)
#define MIPI_DCS_PRIV_SET_EXTC ((u8)0xB9) /* Enable extended commands. */
#define MIPI_DCS_PRIV_UNK_BD ((u8)0xBD)
#define MIPI_DCS_PRIV_UNK_D5 ((u8)0xD5)
#define MIPI_DCS_PRIV_UNK_D6 ((u8)0xD6)
#define MIPI_DCS_PRIV_UNK_D8 ((u8)0xD8)
#define MIPI_DCS_PRIV_UNK_D9 ((u8)0xD9)
#define MIPI_DCS_PRIV_SM_SET_REGS_LOCK ((u8)0xE2)
/* BL Control */
#define DCS_CONTROL_DISPLAY_SM_FLASHLIGHT ((u8)BIT(2))
#define DCS_CONTROL_DISPLAY_BACKLIGHT_CTRL ((u8)BIT(2))
#define DCS_CONTROL_DISPLAY_DIMMING_CTRL ((u8)BIT(3))
#define DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL ((u8)BIT(5))
/* OLED Panels color mode */
#define DCS_SM_COLOR_MODE_SATURATED ((u8)0x00) /* Disabled. Similar to vivid but over-saturated. Wide gamut? */
#define DCS_SM_COLOR_MODE_WASHED ((u8)0x45)
#define DCS_SM_COLOR_MODE_BASIC ((u8)0x03)
#define DCS_SM_COLOR_MODE_POR_RESET ((u8)0x20) /* Reset value on power on. */
#define DCS_SM_COLOR_MODE_NATURAL ((u8)0x23) /* Not actually natural.. */
#define DCS_SM_COLOR_MODE_VIVID ((u8)0x65)
#define DCS_SM_COLOR_MODE_NIGHT0 ((u8)0x43) /* Based on washed out. */
#define DCS_SM_COLOR_MODE_NIGHT1 ((u8)0x15) /* Based on basic. */
#define DCS_SM_COLOR_MODE_NIGHT2 ((u8)0x35) /* Based on natural. */
#define DCS_SM_COLOR_MODE_NIGHT3 ((u8)0x75) /* Based on vivid. */
#define DCS_SM_COLOR_MODE_ENABLE ((u8)BIT(0))
enum
{
PANEL_JDI_XXX062M = 0x10,
PANEL_JDI_LAM062M109A = 0x0910,
PANEL_JDI_LPM062M326A = 0x2610,
PANEL_INL_P062CCA_AZ1 = 0x0F20,
PANEL_AUO_A062TAN01 = 0x0F30,
PANEL_INL_2J055IA_27A = 0x1020,
PANEL_AUO_A055TAN01 = 0x1030,
PANEL_SHP_LQ055T1SW10 = 0x1040,
PANEL_SAM_AMS699VC01 = 0x2050,
PANEL_RR_SUPER5_OLED_V1 = 0x10E0,
PANEL_RR_SUPER5_OLED_HD_V1 = 0x10E1,
PANEL_RR_SUPER7_IPS_V1 = 0x0FE0,
PANEL_RR_SUPER7_IPS_HD_V1 = 0x0FE1,
PANEL_RR_SUPER7_OLED_7_V1 = 0x20E0,
PANEL_RR_SUPER7_OLED_HD_7_V1 = 0x20E1,
// Found on 6/2" clones. Unknown markings. Quality seems JDI like. Has bad low backlight scaling. ID: [83] 94 [0F].
PANEL_OEM_CLONE_6_2 = 0x0F83,
// Found on 5.5" clones with AUO A055TAN02 (59.05A30.001) fake markings.
PANEL_OEM_CLONE_5_5 = 0x00B3,
// Found on 5.5" clones with AUO A055TAN02 (59.05A30.001) fake markings.
PANEL_OEM_CLONE = 0x0000
};
struct init_cmd {
u8 cmd;
int length;
u8 data[64];
};
struct nx_panel {
struct drm_panel base;
struct mipi_dsi_device *dsi;
struct backlight_device *backlight;
struct regulator *supply1;
struct regulator *supply2;
struct gpio_desc *reset_gpio;
bool prepared;
bool enabled;
const struct drm_display_mode *mode;
struct init_cmd *init_cmds;
struct init_cmd *suspend_cmds;
u16 display_id;
};
struct init_cmd init_cmds_default[] = {
{ MIPI_DCS_EXIT_SLEEP_MODE, 2, { 0x00, 0x0 } },
{
0xFF,
120,
},
{ MIPI_DCS_SET_DISPLAY_ON, 2, { 0x00, 0x0 } },
{
0xFF,
20,
},
};
struct init_cmd init_cmds_PANEL_JDI_XXX062M[] = {
{ MIPI_DCS_PRIV_SET_EXTC, 3, { 0xFF, 0x83, 0x94 } },
{ MIPI_DCS_PRIV_UNK_BD, 2, { 0x00, 0x0 } },
{ MIPI_DCS_PRIV_UNK_D8, 24, { 0xAA, 0xAA, 0xAA, 0xEB, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xEB, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xEB, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xEB, 0xAA, 0xAA } },
{ MIPI_DCS_PRIV_UNK_BD, 2, { 0x01, 0x0 } },
{ MIPI_DCS_PRIV_UNK_D8,
38,
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } },
{ MIPI_DCS_PRIV_UNK_BD, 2, { 0x02, 0x0 } },
{ MIPI_DCS_PRIV_UNK_D8,
14,
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF } },
{ MIPI_DCS_PRIV_UNK_BD, 2, { 0x00, 0x00 } },
{ MIPI_DCS_PRIV_UNK_D9, 2, { 0x06, 0x0 } },
{ MIPI_DCS_PRIV_SET_EXTC, 3, { 0x00, 0x00, 0x00 } },
{ MIPI_DCS_EXIT_SLEEP_MODE, 2, { 0x00, 0x0 } },
{
0xFF,
180,
},
{ MIPI_DCS_SET_DISPLAY_ON, 2, { 0x00, 0x0 } },
{
0xFF,
20,
},
{ MIPI_DCS_NOP, -1, { 0x00 } },
};
struct init_cmd suspend_cmds_PANEL_JDI_XXX062M[] = {
{ MIPI_DCS_SET_DISPLAY_OFF, 2, { 0x00, 0x0 } },
{
0xFF,
50,
},
{ MIPI_DCS_PRIV_SET_EXTC, 3, { 0xFF, 0x83, 0x94 } },
{ MIPI_DCS_PRIV_UNK_D5,
32,
{ 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 } },
{ MIPI_DCS_PRIV_SET_POWER_CONTROL,
10,
{ 0x41, 0x0F, 0x4F, 0x33, 0xA4, 0x79, 0xF1, 0x81, 0x2D, 0x00 } },
{ MIPI_DCS_PRIV_SET_EXTC, 3, { 0x00, 0x00, 0x00 } },
{ MIPI_DCS_ENTER_SLEEP_MODE, 2, { 0x00, 0x0 } },
{
0xFF,
50,
},
{ MIPI_DCS_NOP, -1, { 0x00 } },
};
struct init_cmd init_cmds_PANEL_SAM_AMS699VC01[] = {
{ MIPI_DCS_EXIT_SLEEP_MODE, 2, { 0x00, 0x0 } },
{
0xFF,
180,
},
// Set color mode to basic (natural). Stock is Saturated (0x00). (Reset value is 0x20).
{ MIPI_DCS_PRIV_SM_SET_COLOR_MODE, 2, { 0x23, 0x0 } },
// Enable backlight and smooth PWM.
{ MIPI_DCS_WRITE_CONTROL_DISPLAY, 2, { 0x28, 0x0 } },
// Unlock Level 2 registers.
{ 0x05, 9, { 0x0, 0x0, 0xE2, 0x5A, 0x5A, 0x5A, 0x5A, 0x0, 0x0 } },
// Set registers offset and set PWM transition to 6 frames (100ms).
{ MIPI_DCS_PRIV_SM_SET_REG_OFFSET, 2, { 0x07, 0x0 } },
{ MIPI_DCS_PRIV_SM_SET_ELVSS, 2, { 0x06, 0x0 } },
// Relock Level 2 registers.
{ 0x05, 9, { 0x0, 0x0, 0xE2, 0x5A, 0x5A, 0xA5, 0xA5, 0x0, 0x0 } },
// MIPI_DCS_SET_BRIGHTNESS 0000: 0%. FF07: 100%.
{ 0x03, 7, { 0x00, 0x00, 0x51, 0x0, 0x0, 0x0, 0x0 } },
{
0xFF,
5,
},
};
struct init_cmd init_cmds_PANEL_AUO_A062TAN01[] = {
{ MIPI_DCS_EXIT_SLEEP_MODE, 2, { 0x00, 0x0 } },
{
0xFF,
180,
},
{ MIPI_DCS_PRIV_SET_EXTC, 3, { 0xFF, 0x83, 0x94 } },
{
0xFF,
5,
},
{ MIPI_DCS_PRIV_SET_POWER_CONTROL, 6, { 0x48, 0x11, 0x71, 0x09, 0x32, 0x14 } },
};
struct init_cmd suspend_cmds_PANEL_AUO_A062TAN01[] = {
{
0xFF,
100,
},
{
0xFF,
5,
},
{ MIPI_DCS_ENTER_SLEEP_MODE, 2, { 0x00, 0x0 } },
{
0xFF,
50,
},
};
struct init_cmd suspend_cmds_PANEL_AUO_A055TAN01[] = {
{
0xFF,
100,
},
{ MIPI_DCS_PRIV_SET_EXTC, 3, { 0xFF, 0x83, 0x94 } },
{
0xFF,
5,
},
{ MIPI_DCS_PRIV_SET_POWER_CONTROL, 10, { 0x48, 0x11, 0x71, 0x09, 0x32, 0x14, 0x71, 0x31, 0x4D, 0x11 } },
{
0xFF,
5,
},
{ MIPI_DCS_ENTER_SLEEP_MODE, 2, { 0x00, 0x0 } },
{
0xFF,
50,
},
};
struct init_cmd init_cmds_PANEL_INL_P062CCA_AZ1[] = {
{ MIPI_DCS_EXIT_SLEEP_MODE, 2, { 0x00, 0x0 } },
{
0xFF,
180,
},
{ MIPI_DCS_PRIV_SET_EXTC, 3, { 0xFF, 0x83, 0x94 } },
{
0xFF,
5,
},
{ MIPI_DCS_PRIV_SET_POWER_CONTROL, 6, { 0x48, 0x15, 0x75, 0x09, 0x32, 0x14 } },
};
struct init_cmd suspend_cmds_PANEL_INL_2J055IA_27A[] = {
{
0xFF,
100,
},
{ MIPI_DCS_PRIV_SET_EXTC, 3, { 0xFF, 0x83, 0x94 } },
{
0xFF,
5,
},
{ MIPI_DCS_PRIV_SET_POWER_CONTROL, 10, { 0x48, 0x15, 0x75, 0x09, 0x32, 0x14, 0x71, 0x31, 0x4D, 0x11 } },
{
0xFF,
5,
},
{ MIPI_DCS_ENTER_SLEEP_MODE, 2, { 0x00, 0x0 } },
{
0xFF,
50,
},
};
struct init_cmd suspend_cmds_PANEL_SHP_LQ055T1SW10[] = {
{
0xFF,
100,
},
{ MIPI_DCS_PRIV_SET_EXTC, 3, { 0xFF, 0x83, 0x94 } },
{
0xFF,
5,
},
{ MIPI_DCS_PRIV_SET_POWER_CONTROL, 10, { 0x48, 0x13, 0x73, 0x09, 0x32, 0x24, 0x71, 0x31, 0x4C, 0x00 } },
{
0xFF,
5,
},
{ MIPI_DCS_ENTER_SLEEP_MODE, 2, { 0x00, 0x0 } },
{
0xFF,
50,
},
};
struct init_cmd suspend_cmds_PANEL_SAM_AMS699VC01[] = {
{
0xFF,
100,
},
{ MIPI_DCS_ENTER_SLEEP_MODE, 2, { 0x00, 0x0 } },
{
0xFF,
120,
},
};
static inline struct nx_panel *to_nx_panel(struct drm_panel *panel)
{
return container_of(panel, struct nx_panel, base);
}
static void nx_panel_detect(struct nx_panel *nx)
{
int ret;
nx->init_cmds = NULL;
nx->suspend_cmds = NULL;
memset(&(nx->display_id), 0, sizeof(nx->display_id));
ret = mipi_dsi_dcs_read(nx->dsi, MIPI_DCS_GET_DISPLAY_ID,
&(nx->display_id), sizeof(nx->display_id));
if (ret < 0) {
dev_err(&nx->dsi->dev, "failed to read panel ID: %d\n", ret);
} else {
dev_info(&nx->dsi->dev, "display ID[%d]: %04x\n",
ret, nx->display_id);
}
dev_info(&nx->dsi->dev,
"setting init sequence for ID %04x\n", nx->display_id);
switch (nx->display_id) {
case PANEL_JDI_XXX062M:
nx->init_cmds = init_cmds_PANEL_JDI_XXX062M;
break;
case PANEL_SAM_AMS699VC01:
nx->init_cmds = init_cmds_PANEL_SAM_AMS699VC01;
break;
case PANEL_INL_P062CCA_AZ1:
nx->init_cmds = init_cmds_PANEL_INL_P062CCA_AZ1;
break;
case PANEL_AUO_A062TAN01:
nx->init_cmds = init_cmds_PANEL_AUO_A062TAN01;
break;
case PANEL_INL_2J055IA_27A:
case PANEL_AUO_A055TAN01:
case PANEL_SHP_LQ055T1SW10:
default:
dev_info(&nx->dsi->dev, "using default init sequence\n");
nx->init_cmds = init_cmds_default;
break;
}
dev_info(&nx->dsi->dev,
"setting suspend sequence for ID %04x\n", nx->display_id);
switch (nx->display_id) {
case PANEL_JDI_XXX062M:
nx->suspend_cmds = suspend_cmds_PANEL_JDI_XXX062M;
break;
case PANEL_AUO_A062TAN01:
nx->suspend_cmds = suspend_cmds_PANEL_AUO_A062TAN01;
break;
case PANEL_INL_2J055IA_27A:
nx->suspend_cmds = suspend_cmds_PANEL_INL_2J055IA_27A;
break;
case PANEL_AUO_A055TAN01:
nx->suspend_cmds = suspend_cmds_PANEL_AUO_A055TAN01;
break;
case PANEL_SHP_LQ055T1SW10:
nx->suspend_cmds = suspend_cmds_PANEL_SHP_LQ055T1SW10;
break;
case PANEL_SAM_AMS699VC01:
nx->suspend_cmds = suspend_cmds_PANEL_SAM_AMS699VC01;
break;
case PANEL_INL_P062CCA_AZ1:
default:
dev_info(&nx->dsi->dev, "using default suspend sequence\n");
break;
}
msleep(20);
}
static int nx_mipi_dsi_dcs_cmds(struct init_cmd *cmds, struct nx_panel *nx)
{
int ret = 0;
while (cmds && cmds->length != -1) {
if (cmds->cmd == 0xFF)
msleep(cmds->length);
else {
ret = mipi_dsi_dcs_write(nx->dsi, cmds->cmd,
cmds->data, cmds->length);
if (ret < 0) {
dev_err(&nx->dsi->dev,
"failed to write dsi_cmd: %d error: %d\n",
cmds->cmd, ret);
return ret;
}
}
cmds++;
}
return ret;
}
static int nx_panel_init(struct nx_panel *nx)
{
struct mipi_dsi_device *dsi = nx->dsi;
struct device *dev = &nx->dsi->dev;
int ret;
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
ret = mipi_dsi_set_maximum_return_packet_size(dsi, 3);
if (ret < 0) {
dev_err(dev, "failed to set maximum return packet size: %d\n",
ret);
return ret;
}
nx_panel_detect(nx);
ret = nx_mipi_dsi_dcs_cmds(nx->init_cmds, nx);
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_set_column_address(dsi, 0, nx->mode->hdisplay - 1);
if (ret < 0) {
dev_err(dev, "failed to set page address: %d\n", ret);
return ret;
}
ret = mipi_dsi_dcs_set_page_address(dsi, 0, nx->mode->vdisplay - 1);
if (ret < 0) {
dev_err(dev, "failed to set column address: %d\n", ret);
return ret;
}
ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
if (ret < 0) {
dev_err(dev, "failed to set vblank tear on: %d\n", ret);
return ret;
}
ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT);
if (ret < 0) {
dev_err(dev, "failed to set pixel format: %d\n", ret);
return ret;
}
return 0;
}
static int nx_panel_enable(struct drm_panel *panel)
{
struct nx_panel *nx = to_nx_panel(panel);
if (nx->enabled)
return 0;
backlight_enable(nx->backlight);
nx->enabled = true;
return 0;
}
static int nx_panel_disable(struct drm_panel *panel)
{
struct nx_panel *nx = to_nx_panel(panel);
if (!nx->enabled)
return 0;
backlight_disable(nx->backlight);
nx->enabled = false;
return 0;
}
static int nx_panel_unprepare(struct drm_panel *panel)
{
struct nx_panel *nx = to_nx_panel(panel);
int ret;
if (!nx->prepared)
return 0;
nx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
ret = nx_mipi_dsi_dcs_cmds(nx->suspend_cmds, nx);
if (ret < 0)
dev_err(&nx->dsi->dev, "failed to write suspend cmds: %d\n",
ret);
if (nx->reset_gpio)
gpiod_set_value(nx->reset_gpio, 0);
msleep(10);
regulator_disable(nx->supply2);
msleep(10);
regulator_disable(nx->supply1);
nx->prepared = false;
return 0;
}
static int nx_panel_prepare(struct drm_panel *panel)
{
struct nx_panel *nx = to_nx_panel(panel);
struct device *dev = &nx->dsi->dev;
int ret;
if (nx->prepared)
return 0;
ret = regulator_enable(nx->supply1);
if (ret < 0)
return ret;
msleep(10);
ret = regulator_enable(nx->supply2);
if (ret < 0)
goto poweroff;
msleep(10);
if (nx->reset_gpio) {
gpiod_set_value(nx->reset_gpio, 0);
msleep(10);
gpiod_set_value(nx->reset_gpio, 1);
msleep(60);
}
nx->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
ret = nx_panel_init(nx);
if (ret < 0) {
dev_err(dev, "failed to init panel: %d\n", ret);
goto reset;
}
nx->prepared = true;
return 0;
reset:
if (nx->reset_gpio)
gpiod_set_value(nx->reset_gpio, 0);
regulator_disable(nx->supply2);
poweroff:
regulator_disable(nx->supply1);
return ret;
}
static const struct drm_display_mode default_mode = {
.clock = 78000,
.hdisplay = 720,
.hsync_start = 720 + 136,
.hsync_end = 720 + 136 + 72,
.htotal = 720 + 136 + 72 + 72,
.vdisplay = 1280,
.vsync_start = 1280 + 10,
.vsync_end = 1280 + 10 + 2,
.vtotal = 1280 + 10 + 1 + 9,
.flags = 0,
};
static int nx_panel_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
struct drm_display_mode *mode;
struct nx_panel *nx = to_nx_panel(panel);
struct device *dev = &nx->dsi->dev;
mode = drm_mode_duplicate(connector->dev, &default_mode);
if (!mode) {
dev_err(dev, "failed to add mode %ux%ux@%u\n",
default_mode.hdisplay, default_mode.vdisplay,
drm_mode_vrefresh(&default_mode));
return -ENOMEM;
}
drm_mode_set_name(mode);
drm_mode_probed_add(connector, mode);
connector->display_info.width_mm = 77;
connector->display_info.height_mm = 137;
connector->display_info.bpc = 8;
return 1;
}
static const struct drm_panel_funcs nx_panel_funcs = {
.prepare = nx_panel_prepare,
.unprepare = nx_panel_unprepare,
.enable = nx_panel_enable,
.disable = nx_panel_disable,
.get_modes = nx_panel_get_modes,
};
static int nx_panel_add(struct nx_panel *nx)
{
struct device *dev = &nx->dsi->dev;
struct device_node *np;
nx->mode = &default_mode;
nx->supply1 = devm_regulator_get(dev, "vdd1");
if (IS_ERR(nx->supply1))
return PTR_ERR(nx->supply1);
nx->supply2 = devm_regulator_get(dev, "vdd2");
if (IS_ERR(nx->supply2))
return PTR_ERR(nx->supply2);
nx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(nx->reset_gpio)) {
dev_err(dev, "cannot get reset-gpios %ld\n",
PTR_ERR(nx->reset_gpio));
nx->reset_gpio = NULL;
} else {
gpiod_set_value(nx->reset_gpio, 0);
}
usleep_range(2000, 4000);
np = of_parse_phandle(dev->of_node, "backlight", 0);
if (np) {
nx->backlight = of_find_backlight_by_node(np);
of_node_put(np);
if (!nx->backlight)
return -EPROBE_DEFER;
}
drm_panel_init(&nx->base, &nx->dsi->dev, &nx_panel_funcs,
DRM_MODE_CONNECTOR_DSI);
drm_panel_add(&nx->base);
return 0;
}
static void nx_panel_del(struct nx_panel *nx)
{
if (nx->base.dev)
drm_panel_remove(&nx->base);
if (nx->backlight)
put_device(&nx->backlight->dev);
}
static int nx_panel_probe(struct mipi_dsi_device *dsi)
{
struct nx_panel *nx;
int ret;
dsi->lanes = 4;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
MIPI_DSI_CLOCK_NON_CONTINUOUS |
MIPI_DSI_MODE_NO_EOT_PACKET;
nx = devm_kzalloc(&dsi->dev, sizeof(*nx), GFP_KERNEL);
if (!nx)
return -ENOMEM;
mipi_dsi_set_drvdata(dsi, nx);
nx->dsi = dsi;
ret = nx_panel_add(nx);
if (ret < 0)
return ret;
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
nx_panel_del(nx);
return ret;
}
return 0;
}
static void nx_panel_remove(struct mipi_dsi_device *dsi)
{
struct nx_panel *nx = mipi_dsi_get_drvdata(dsi);
int ret;
ret = nx_panel_disable(&nx->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);
nx_panel_del(nx);
}
static void nx_panel_shutdown(struct mipi_dsi_device *dsi)
{
struct nx_panel *nx = mipi_dsi_get_drvdata(dsi);
nx_panel_disable(&nx->base);
}
static const struct of_device_id nx_panel_of_match[] = {
{
.compatible = "nintendo,nx-dsi",
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, nx_panel_of_match);
static struct mipi_dsi_driver nx_panel_driver = {
.driver = {
.name = "panel-nx-dsi",
.of_match_table = nx_panel_of_match,
},
.probe = nx_panel_probe,
.remove = nx_panel_remove,
.shutdown = nx_panel_shutdown,
};
module_mipi_dsi_driver(nx_panel_driver);
MODULE_AUTHOR("SwtcR <swtcr0@gmail.com>");
MODULE_DESCRIPTION("Nintendo Switch DSI (720x1280) panel driver");
MODULE_LICENSE("GPL v2");
+1
View File
@@ -1378,6 +1378,7 @@ static const struct of_device_id host1x_drm_subdevs[] = {
{ .compatible = "nvidia,tegra132-dsi", },
{ .compatible = "nvidia,tegra210-dc", },
{ .compatible = "nvidia,tegra210-dsi", },
{ .compatible = "nvidia,tegra210b01-dsi", },
{ .compatible = "nvidia,tegra210-sor", },
{ .compatible = "nvidia,tegra210-sor1", },
{ .compatible = "nvidia,tegra210-vic", },
+139 -38
View File
@@ -54,6 +54,21 @@ to_dsi_state(struct drm_connector_state *state)
return container_of(state, struct tegra_dsi_state, base);
}
/*
* remap of registers revised in Tegra210B01
*/
struct dsi_regmap {
int init_seq_data_15;
int slew_impedance[4];
int preemphasis;
int bias;
int ganged_mode_control;
int ganged_mode_start;
int ganged_mode_size;
int dbg_regs_cnt;
struct debugfs_reg32 dbg_regs_ext[16];
};
struct tegra_dsi {
struct host1x_client client;
struct tegra_output output;
@@ -83,6 +98,8 @@ struct tegra_dsi {
/* for ganged-mode support */
struct tegra_dsi *master;
struct tegra_dsi *slave;
const struct dsi_regmap *regmap;
};
static inline struct tegra_dsi *
@@ -124,7 +141,7 @@ static inline void tegra_dsi_writel(struct tegra_dsi *dsi, u32 value,
#define DEBUGFS_REG32(_name) { .name = #_name, .offset = _name }
static const struct debugfs_reg32 tegra_dsi_regs[] = {
static const struct debugfs_reg32 tegra_dsi_regs_common[] = {
DEBUGFS_REG32(DSI_INCR_SYNCPT),
DEBUGFS_REG32(DSI_INCR_SYNCPT_CONTROL),
DEBUGFS_REG32(DSI_INCR_SYNCPT_ERROR),
@@ -183,19 +200,6 @@ static const struct debugfs_reg32 tegra_dsi_regs[] = {
DEBUGFS_REG32(DSI_PAD_CONTROL_2),
DEBUGFS_REG32(DSI_PAD_CONTROL_3),
DEBUGFS_REG32(DSI_PAD_CONTROL_4),
DEBUGFS_REG32(DSI_GANGED_MODE_CONTROL),
DEBUGFS_REG32(DSI_GANGED_MODE_START),
DEBUGFS_REG32(DSI_GANGED_MODE_SIZE),
DEBUGFS_REG32(DSI_RAW_DATA_BYTE_COUNT),
DEBUGFS_REG32(DSI_ULTRA_LOW_POWER_CONTROL),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_8),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_9),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_10),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_11),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_12),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_13),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_14),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_15),
};
static int tegra_dsi_show_regs(struct seq_file *s, void *data)
@@ -214,10 +218,17 @@ static int tegra_dsi_show_regs(struct seq_file *s, void *data)
goto unlock;
}
for (i = 0; i < ARRAY_SIZE(tegra_dsi_regs); i++) {
unsigned int offset = tegra_dsi_regs[i].offset;
for (i = 0; i < ARRAY_SIZE(tegra_dsi_regs_common); i++) {
unsigned int offset = tegra_dsi_regs_common[i].offset;
seq_printf(s, "%-32s %#05x %08x\n", tegra_dsi_regs[i].name,
seq_printf(s, "%-32s %#05x %08x\n", tegra_dsi_regs_common[i].name,
offset, tegra_dsi_readl(dsi, offset));
}
for (i = 0; i < dsi->regmap->dbg_regs_cnt; i++) {
unsigned int offset = dsi->regmap->dbg_regs_ext[i].offset;
seq_printf(s, "%-32s %#05x %08x\n", dsi->regmap->dbg_regs_ext[i].name,
offset, tegra_dsi_readl(dsi, offset));
}
@@ -448,11 +459,11 @@ static void tegra_dsi_ganged_enable(struct tegra_dsi *dsi, unsigned int start,
{
u32 value;
tegra_dsi_writel(dsi, start, DSI_GANGED_MODE_START);
tegra_dsi_writel(dsi, size << 16 | size, DSI_GANGED_MODE_SIZE);
tegra_dsi_writel(dsi, start, dsi->regmap->ganged_mode_start);
tegra_dsi_writel(dsi, size << 16 | size, dsi->regmap->ganged_mode_size);
value = DSI_GANGED_MODE_CONTROL_ENABLE;
tegra_dsi_writel(dsi, value, DSI_GANGED_MODE_CONTROL);
tegra_dsi_writel(dsi, value, dsi->regmap->ganged_mode_control);
}
static void tegra_dsi_enable(struct tegra_dsi *dsi)
@@ -656,9 +667,9 @@ static void tegra_dsi_video_disable(struct tegra_dsi *dsi)
static void tegra_dsi_ganged_disable(struct tegra_dsi *dsi)
{
tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_START);
tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_SIZE);
tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL);
tegra_dsi_writel(dsi, 0, dsi->regmap->ganged_mode_start);
tegra_dsi_writel(dsi, 0, dsi->regmap->ganged_mode_size);
tegra_dsi_writel(dsi, 0, dsi->regmap->ganged_mode_control);
}
static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
@@ -674,7 +685,7 @@ static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
{
u32 value;
int err;
int err, i;
/*
* XXX Is this still needed? The module reset is deasserted right
@@ -682,21 +693,29 @@ static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
*/
tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
for (i = 0; i < ARRAY_SIZE(dsi->regmap->slew_impedance); i++) {
if (dsi->regmap->slew_impedance[i])
tegra_dsi_writel(dsi, 0, dsi->regmap->slew_impedance[i]);
}
/* start calibration */
tegra_dsi_pad_enable(dsi);
value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
DSI_PAD_OUT_CLK(0x0);
tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
/* do not set padctl 2 slew by default */
if (of_property_read_bool(dsi->dev->of_node, "nvidia,slew-enable")) {
value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
DSI_PAD_OUT_CLK(0x0);
tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
}
value = DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) |
value = tegra_dsi_readl(dsi, dsi->regmap->preemphasis);
value |= DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) |
DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3);
tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3);
tegra_dsi_writel(dsi, value, dsi->regmap->preemphasis);
tegra_dsi_writel(dsi, 0, dsi->regmap->bias);
err = tegra_mipi_start_calibration(dsi->mipi);
if (err < 0)
@@ -1069,7 +1088,7 @@ static int tegra_dsi_init(struct host1x_client *client)
dev_err(dsi->dev, "failed to initialize output: %d\n",
err);
dsi->output.encoder.possible_crtcs = 0x3;
tegra_output_find_possible_crtcs(&dsi->output, drm);
}
return 0;
@@ -1633,6 +1652,12 @@ static int tegra_dsi_probe(struct platform_device *pdev)
goto remove;
}
dsi->regmap = of_device_get_match_data(&pdev->dev);
if (IS_ERR(dsi->regmap)) {
err = PTR_ERR(dsi->regmap);
goto remove;
}
dsi->mipi = tegra_mipi_request(&pdev->dev, pdev->dev.of_node);
if (IS_ERR(dsi->mipi)) {
err = PTR_ERR(dsi->mipi);
@@ -1688,11 +1713,87 @@ static void tegra_dsi_remove(struct platform_device *pdev)
tegra_mipi_free(dsi->mipi);
}
static const struct dsi_regmap tegra_dsi_regmap = {
.init_seq_data_15 = DSI_INIT_SEQ_DATA_15,
.slew_impedance = { DSI_PAD_CONTROL_2 },
.preemphasis = DSI_PAD_CONTROL_3,
.bias = DSI_PAD_CONTROL_4,
.ganged_mode_control = DSI_GANGED_MODE_CONTROL,
.ganged_mode_start = DSI_GANGED_MODE_START,
.ganged_mode_size = DSI_GANGED_MODE_SIZE,
.dbg_regs_cnt = 13,
.dbg_regs_ext = {
DEBUGFS_REG32(DSI_GANGED_MODE_CONTROL),
DEBUGFS_REG32(DSI_GANGED_MODE_START),
DEBUGFS_REG32(DSI_GANGED_MODE_SIZE),
DEBUGFS_REG32(DSI_RAW_DATA_BYTE_COUNT),
DEBUGFS_REG32(DSI_ULTRA_LOW_POWER_CONTROL),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_8),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_9),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_10),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_11),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_12),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_13),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_14),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_15),
},
};
static const struct dsi_regmap tegra_dsi_regmap_b01 = {
.init_seq_data_15 = DSI_INIT_SEQ_DATA_15_B01,
.slew_impedance = {
DSI_PAD_CONTROL_2,
DSI_PAD_CONTROL_3,
DSI_PAD_CONTROL_4,
DSI_PAD_CONTROL_5_B01,
},
.preemphasis = DSI_PAD_CONTROL_6_B01,
.bias = DSI_PAD_CONTROL_7_B01,
.ganged_mode_control = DSI_GANGED_MODE_CONTROL_B01,
.ganged_mode_start = DSI_GANGED_MODE_START_B01,
.ganged_mode_size = DSI_GANGED_MODE_SIZE_B01,
.dbg_regs_cnt = 16,
.dbg_regs_ext = {
DEBUGFS_REG32(DSI_PAD_CONTROL_5_B01),
DEBUGFS_REG32(DSI_PAD_CONTROL_6_B01),
DEBUGFS_REG32(DSI_PAD_CONTROL_7_B01),
DEBUGFS_REG32(DSI_GANGED_MODE_CONTROL_B01),
DEBUGFS_REG32(DSI_GANGED_MODE_START_B01),
DEBUGFS_REG32(DSI_GANGED_MODE_SIZE_B01),
DEBUGFS_REG32(DSI_RAW_DATA_BYTE_COUNT_B01),
DEBUGFS_REG32(DSI_ULTRA_LOW_POWER_CONTROL_B01),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_8_B01),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_9_B01),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_10_B01),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_11_B01),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_12_B01),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_13_B01),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_14_B01),
DEBUGFS_REG32(DSI_INIT_SEQ_DATA_15_B01),
},
};
static const struct of_device_id tegra_dsi_of_match[] = {
{ .compatible = "nvidia,tegra210-dsi", },
{ .compatible = "nvidia,tegra132-dsi", },
{ .compatible = "nvidia,tegra124-dsi", },
{ .compatible = "nvidia,tegra114-dsi", },
{
.compatible = "nvidia,tegra210b01-dsi",
.data = &tegra_dsi_regmap_b01
},
{
.compatible = "nvidia,tegra210-dsi",
.data = &tegra_dsi_regmap
},
{
.compatible = "nvidia,tegra132-dsi",
.data = &tegra_dsi_regmap
},
{
.compatible = "nvidia,tegra124-dsi",
.data = &tegra_dsi_regmap
},
{
.compatible = "nvidia,tegra114-dsi",
.data = &tegra_dsi_regmap
},
{ },
};
MODULE_DEVICE_TABLE(of, tegra_dsi_of_match);
+18
View File
@@ -130,6 +130,24 @@
#define DSI_INIT_SEQ_DATA_14 0x5e
#define DSI_INIT_SEQ_DATA_15 0x5f
// Tegra210B01 has a revised set of regs
#define DSI_PAD_CONTROL_5_B01 0x53
#define DSI_PAD_CONTROL_6_B01 0x54
#define DSI_PAD_CONTROL_7_B01 0x55
#define DSI_GANGED_MODE_CONTROL_B01 0x56
#define DSI_GANGED_MODE_START_B01 0x57
#define DSI_GANGED_MODE_SIZE_B01 0x58
#define DSI_RAW_DATA_BYTE_COUNT_B01 0x59
#define DSI_ULTRA_LOW_POWER_CONTROL_B01 0x5a
#define DSI_INIT_SEQ_DATA_8_B01 0x5b
#define DSI_INIT_SEQ_DATA_9_B01 0x5c
#define DSI_INIT_SEQ_DATA_10_B01 0x5d
#define DSI_INIT_SEQ_DATA_11_B01 0x5e
#define DSI_INIT_SEQ_DATA_12_B01 0x5f
#define DSI_INIT_SEQ_DATA_13_B01 0x60
#define DSI_INIT_SEQ_DATA_14_B01 0x61
#define DSI_INIT_SEQ_DATA_15_B01 0x62
/*
* pixel format as used in the DSI_CONTROL_FORMAT field
*/
+23 -4
View File
@@ -55,7 +55,6 @@ struct tegra_sor_hdmi_settings {
u8 preemphasis[4];
};
#if 1
static const struct tegra_sor_hdmi_settings tegra210_sor_hdmi_defaults[] = {
{
.frequency = 54000000,
@@ -134,8 +133,8 @@ static const struct tegra_sor_hdmi_settings tegra210_sor_hdmi_defaults[] = {
.preemphasis = { 0x00, 0x00, 0x00, 0x00 },
},
};
#else
static const struct tegra_sor_hdmi_settings tegra210_sor_hdmi_defaults[] = {
static const struct tegra_sor_hdmi_settings tegra210_sor_hdmi_odin[] = {
{
.frequency = 75000000,
.vcocap = 0x3,
@@ -198,7 +197,6 @@ static const struct tegra_sor_hdmi_settings tegra210_sor_hdmi_defaults[] = {
.preemphasis = { 0x02, 0x3f, 0x3f, 0x3f },
},
};
#endif
static const struct tegra_sor_hdmi_settings tegra186_sor_hdmi_defaults[] = {
{
@@ -3533,6 +3531,26 @@ static const struct tegra_sor_soc tegra210_sor1 = {
.tx_pu = tegra124_sor_tx_pu,
};
static const struct tegra_sor_soc tegra210_sor1_odin = {
.supports_lvds = false,
.supports_hdmi = true,
.supports_dp = true,
.supports_audio = true,
.supports_hdcp = true,
.regs = &tegra210_sor_regs,
.has_nvdisplay = false,
.num_settings = ARRAY_SIZE(tegra210_sor_hdmi_odin),
.settings = tegra210_sor_hdmi_odin,
.xbar_cfg = tegra210_sor_xbar_cfg,
.lane_map = tegra210_sor_lane_map,
.voltage_swing = tegra124_sor_voltage_swing,
.pre_emphasis = tegra124_sor_pre_emphasis,
.post_cursor = tegra124_sor_post_cursor,
.tx_pu = tegra124_sor_tx_pu,
};
static const struct tegra_sor_regs tegra186_sor_regs = {
.head_state0 = 0x151,
.head_state1 = 0x154,
@@ -3656,6 +3674,7 @@ static const struct of_device_id tegra_sor_of_match[] = {
{ .compatible = "nvidia,tegra194-sor", .data = &tegra194_sor },
{ .compatible = "nvidia,tegra186-sor", .data = &tegra186_sor },
{ .compatible = "nvidia,tegra210-sor1", .data = &tegra210_sor1 },
{ .compatible = "nvidia,tegra210-sor1-odin", .data = &tegra210_sor1_odin },
{ .compatible = "nvidia,tegra210-sor", .data = &tegra210_sor },
{ .compatible = "nvidia,tegra132-sor", .data = &tegra132_sor },
{ .compatible = "nvidia,tegra124-sor", .data = &tegra124_sor },
+1
View File
@@ -11,6 +11,7 @@ menuconfig INPUT_TOUCHSCREEN
If unsure, say Y.
if INPUT_TOUCHSCREEN
source "drivers/input/touchscreen/stm/Kconfig"
config TOUCHSCREEN_88PM860X
tristate "Marvell 88PM860x touchscreen"
+1
View File
@@ -119,3 +119,4 @@ obj-$(CONFIG_TOUCHSCREEN_IQS5XX) += iqs5xx.o
obj-$(CONFIG_TOUCHSCREEN_IQS7211) += iqs7211.o
obj-$(CONFIG_TOUCHSCREEN_ZINITIX) += zinitix.o
obj-$(CONFIG_TOUCHSCREEN_HIMAX_HX83112B) += himax_hx83112b.o
obj-$(CONFIG_TOUCHSCREEN_FTM4) += stm/
+19
View File
@@ -0,0 +1,19 @@
#
# STMicroelectronics TOUCH driver configuration
#
config TOUCHSCREEN_FTM4
tristate "STMicroelectronics i2c multitouch touchscreen - FTM4 with FingerTipS"
depends on I2C
help
Say Y here to enable STMicroelectronics touchscreen support.
If unsure, say N.
To compile this driver as a module, choose M here: the module
will be called fts_touch.
config TOUCHSCREEN_FTM4_SHOW_EVENTS
bool "Enable debug of FTM4 events"
depends on TOUCHSCREEN_FTM4
help
Say Y here to enable dumping of touch driver events. This should
only be enabled for debugging and not for shipping code.
+3
View File
@@ -0,0 +1,3 @@
# FTM4 driver
obj-$(CONFIG_TOUCHSCREEN_FTM4) += ftm4.o
ftm4-objs += ftm4_ts.o
File diff suppressed because it is too large. Load diff
+374
View File
@@ -0,0 +1,374 @@
/******************************** FingerTipS 4CD60D ****************************
*
* File Name : fts.c
* Authors : Copyright (c) 2012 STMicroelectronics, Analog Mems Sensor Team
* Copyright (c) 2019-2020 Billy Laws <blaws05@gmail.com>
* Copyright (c) 2019-2021 Kostas Missos <ctcaer@gmail.com>
* Description : FTS Capacitive touch screen controller (FingerTipS)
*
********************************************************************************
*
* 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.
*
* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE
* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS.
*******************************************************************************/
#ifndef _LINUX_FTM4_TS_H_
#define _LINUX_FTM4_TS_H_
#include <linux/device.h>
#include <linux/atomic.h>
#include <linux/printk.h>
#define tsp_debug_dbg(dev, fmt, ...) dev_dbg(dev, fmt, ## __VA_ARGS__)
#define tsp_debug_info(dev, fmt, ...) dev_info(dev, fmt, ## __VA_ARGS__)
#define tsp_debug_err(dev, fmt, ...) dev_err(dev, fmt, ## __VA_ARGS__)
#ifdef CONFIG_TOUCHSCREEN_FTM4_SHOW_EVENTS
#define tsp_debug_event(dev, fmt, ...) dev_dbg(dev, fmt, ## __VA_ARGS__)
#else
#define tsp_debug_event(dev, fmt, ...)
#endif
#define FTS_INPUT_OPEN_DWORK_TIME 10
#define FTS_TS_DRV_NAME "fts_touch"
#define FTS_TS_DRV_VERSION "4CD60D"
#define STM_DEVICE_NAME "STM"
#define FTS_ID0 0x36
#define FTS_ID1 0x70
#define FTS_DIGITAL_REV_1 0x01
#define FTS_DIGITAL_REV_2 0x02
#define FTS_FIFO_MAX 32
#define FTS_EVENT_SIZE 8
#define FTS_FW_UPDATE_RETRY 3
#define FTS_LOCKDOWNCODE_SIZE 13
#define PRESSURE_MIN 0
#define PRESSURE_MAX 500
#define FINGER_MAX 10
#define EVENTID_NO_EVENT 0x00
#define EVENTID_ENTER_POINTER 0x03
#define EVENTID_LEAVE_POINTER 0x04
#define EVENTID_HOS_EVENT 0x04
#define EVENTID_MOTION_POINTER 0x05
#define EVENTID_HOVER_ENTER_POINTER 0x07
#define EVENTID_HOVER_LEAVE_POINTER 0x08
#define EVENTID_MOTION_POINTER 0x05
#define EVENTID_HOVER_MOTION_POINTER 0x09
#define EVENTID_PROXIMITY_IN 0x0B
#define EVENTID_PROXIMITY_OUT 0x0C
#define EVENTID_MSKEY 0x0E
#define EVENTID_ERROR 0x0F
#define EVENTID_CONTROLLER_READY 0x10
#define EVENTID_SLEEPOUT_CONTROLLER_READY 0x11
#define EVENTID_RESULT_READ_REGISTER 0x12
#define EVENTID_STATUS_REQUEST_COMP 0x13
#define EVENTID_STATUS_EVENT 0x16
#define EVENTID_INTERNAL_RELEASE_INFO 0x14
#define EVENTID_EXTERNAL_RELEASE_INFO 0x15
#define EVENTID_FROM_STRING 0x80
#define EVENTID_GESTURE 0x20
#define EVENTID_SIDE_SCROLL 0x40
/* side touch event-id for debug, remove after f/w fixed */
#define EVENTID_SIDE_TOUCH_DEBUG 0xDB
#define EVENTID_SIDE_TOUCH 0x0B
#define EVENTID_ERROR_FLASH_CORRUPTION 0x03
/* define flash corruption type */
#define EVENTID_ERROR_CONFIG_FLASH_CORRUPTION_1 0x01
#define EVENTID_ERROR_CONFIG_FLASH_CORRUPTION_2 0x02
#define EVENTID_ERROR_CX_FLASH_CORRUPTION 0x03
#define EVENTID_LOCKDOWN_CODE 0x1E
#define EVENTID_ERROR_LOCKDOWN 0x0B
#define STATUS_EVENT_MS_CX_TUNING_DONE 0x01
#define STATUS_EVENT_SS_CX_TUNING_DONE 0x02
#define STATUS_EVENT_FLASH_WRITE_CONFIG 0x03
#define STATUS_EVENT_FLASH_WRITE_CXTUNE_VALUE 0x04
#define STATUS_EVENT_FORCE_CAL_MUTUAL_SELF 0x05
#define STATUS_EVENT_FORCE_CAL_DONE 0x06
#define STATUS_EVENT_FORCE_CAL_MUTUAL 0x15
#define STATUS_EVENT_FORCE_CAL_SELF 0x06
#define STATUS_EVENT_PARAM1_FCAL_MS_SS_DONE 0x23
#define STATUS_EVENT_WATERMODE_ON 0x07
#define STATUS_EVENT_WATERMODE_OFF 0x08
#define STATUS_EVENT_RTUNE_MUTUAL 0x09
#define STATUS_EVENT_RTUNE_SELF 0x0A
#define STATUS_EVENT_PANEL_TEST_RESULT 0x0B
#define STATUS_EVENT_GLOVE_MODE 0x0C
#define STATUS_EVENT_RAW_DATA_READY 0x0D
#define STATUS_EVENT_MUTUAL_CAL_FRAME_CHECK 0xC1
#define STATUS_EVENT_SELF_CAL_FRAME_CHECK 0xC2
#define STATUS_EVENT_CHARGER_CONNECTED 0xCC
#define STATUS_EVENT_CHARGER_DISCONNECTED 0xCD
#define STATUS_EVENT_PURE_AUTOTUNE_FLAG_WRITE_FINISH 0x10
#define STATUS_EVENT_PURE_AUTOTUNE_FLAG_CLEAR_FINISH 0x11
#define INT_ENABLE 0x48
#define INT_DISABLE 0x08
#define FTS_READ_STATUS 0x84
#define FTS_READ_ONE_EVENT 0x85
#define FTS_READ_ALL_EVENT 0x86
#define FTS_CMD_SENSEOFF 0x92
#define FTS_CMD_SENSEON 0x93
#define FTS_CMD_HOVER_OFF 0x94
#define FTS_CMD_HOVER_ON 0x95
#define FTS_CMD_MSKEY_AUTOTUNE 0x96
#define FTS_CMD_TRIM_LOW_POWER_OSCILLATOR 0x97
#define FTS_CMD_KEY_SENSE_OFF 0x9A
#define FTS_CMD_KEY_SENSE_ON 0x9B
#define FTS_CMD_SET_FAST_GLOVE_MODE 0x9D
#define FTS_CMD_MSHOVER_OFF 0x9E
#define FTS_CMD_MSHOVER_ON 0x9F
#define FTS_CMD_SET_NOR_GLOVE_MODE 0x9F
#define FTS_CMD_FLUSHBUFFER 0xA1
#define FTS_CMD_FORCECALIBRATION 0xA2
#define FTS_CMD_MS_CX_TUNING 0xA3
#define FTS_CMD_SS_CX_TUNING 0xA4
#define FTS_CMD_ITO_CHECK 0xA7
#define FTS_CMD_CHARGER_PLUGGED 0xA8
#define FTS_CMD_CHARGER_UNPLUGGED 0xAB
#define FTS_CMD_RELEASEINFO 0xAA
#define FTS_CMD_STYLUS_OFF 0xAB
#define FTS_CMD_STYLUS_ON 0xAC
#define FTS_CMD_LOWPOWER_MODE 0xAD
#define FTS_CMD_WRITE_REG 0xB6
#define FTS_CMS_ENABLE_FEATURE 0xC1
#define FTS_CMS_DISABLE_FEATURE 0xC2
#define FTS_CMD_SWITCH_SENSE_MODE 0xC3
#define FTS_CMD_LOCKDOWN_READ 0xC4
#define FTS_CMD_WRITE_PRAM 0xF0
#define FTS_CMD_BURN_PROG_FLASH 0xF2
#define FTS_CMD_ERASE_PROG_FLASH 0xF3
#define FTS_CMD_READ_FLASH_STAT 0xF4
#define FTS_CMD_UNLOCK_FLASH 0xF7
#define FTS_CMD_SAVE_FWCONFIG 0xFB
#define FTS_CMD_SAVE_CX_TUNING 0xFC
#define FTS_CMD_FAST_SCAN 0x01
#define FTS_CMD_SLOW_SCAN 0x02
#define FTS_CMD_USLOW_SCAN 0x03
#define FTS_STYLUS_MODE 0x00
#define FTS_FINGER_MODE 0x01
#define FTS_HOVER_MODE 0x02
#define FTS_REPORT_RATE_90HZ 0
#define FTS_REPORT_RATE_60HZ 1
#define FTS_REPORT_RATE_30HZ 2
#define FTS_CMD_STRING_ACCESS 0xEC00
#define FTS_CMD_NOTIFY 0xC0
#define FTS_RETRY_COUNT 10
/* QUICK SHOT : Quick Camera Launching */
#define FTS_STRING_EVENT_REAR_CAM (1 << 0)
#define FTS_STRING_EVENT_FRONT_CAM (1 << 1)
/* SCRUB : Display Watch, Event Status / Fast Access Event */
#define FTS_STRING_EVENT_WATCH_STATUS (1 << 2)
#define FTS_STRING_EVENT_FAST_ACCESS (1 << 3)
#define FTS_STRING_EVENT_DIRECT_INDICATOR ((1 << 3) | (1 << 2))
#define FTS_STRING_EVENT_SPAY (1 << 4)
#define FTS_STRING_EVENT_SPAY1 (1 << 5)
#define FTS_STRING_EVENT_SPAY2 ((1 << 4) | (1 << 5))
#define FTS_SIDEGESTURE_EVENT_SINGLE_STROKE 0xE0
#define FTS_SIDEGESTURE_EVENT_DOUBLE_STROKE 0xE1
#define FTS_SIDEGESTURE_EVENT_INNER_STROKE 0xE3
#define FTS_SIDETOUCH_EVENT_LONG_PRESS 0xBB
#define FTS_SIDETOUCH_EVENT_REBOOT_BY_ESD 0xED
#define FTS_ENABLE 1
#define FTS_DISABLE 0
#define FTS_MODE_QUICK_SHOT (1 << 0)
#define FTS_MODE_SCRUB (1 << 1)
#define FTS_MODE_SPAY (1 << 1)
#define FTS_MODE_QUICK_APP_ACCESS (1 << 2)
#define FTS_MODE_DIRECT_INDICATOR (1 << 3)
#define TSP_BUF_SIZE 2048
#define CMD_STR_LEN 32
#define CMD_RESULT_STR_LEN 2048
#define CMD_PARAM_NUM 8
#define FTS_LOWP_FLAG_QUICK_CAM (1 << 0)
#define FTS_LOWP_FLAG_2ND_SCREEN (1 << 1)
#define FTS_LOWP_FLAG_BLACK_UI (1 << 2)
#define FTS_LOWP_FLAG_QUICK_APP_ACCESS (1 << 3)
#define FTS_LOWP_FLAG_DIRECT_INDICATOR (1 << 4)
#define FTS_LOWP_FLAG_SPAY (1 << 5)
#define FTS_LOWP_FLAG_TEMP_CMD (1 << 6)
enum fts_error_return {
FTS_NOT_ERROR = 0,
FTS_ERROR_INVALID_CHIP_ID,
FTS_ERROR_INVALID_CHIP_VERSION_ID,
FTS_ERROR_INVALID_SW_VERSION,
FTS_ERROR_EVENT_ID,
FTS_ERROR_TIMEOUT,
FTS_ERROR_FW_UPDATE_FAIL,
};
#define RAW_MAX 3750
/**
* struct fts_finger - Represents fingers.
* @ state: finger status (Event ID).
* @ mcount: moving counter for debug.
*/
struct fts_finger {
unsigned char state;
int lx;
int ly;
};
enum tsp_power_mode {
FTS_POWER_STATE_ACTIVE = 0,
FTS_POWER_STATE_POWERDOWN,
};
enum fts_customer_feature {
FTS_FEATURE_ORIENTATION_GESTURE = 1,
FTS_FEATURE_STYLUS,
FTS_FEATURE_QUICK_SHORT_CAMERA_ACCESS,
FTS_FEATURE_SIDE_GUSTURE,
FTS_FEATURE_COVER_GLASS,
FTS_FEATURE_COVER_WALLET,
FTS_FEATURE_COVER_LED,
FTS_FEATURE_COVER_CLEAR_FLIP,
FTS_FEATURE_DUAL_SIDE_GUSTURE,
FTS_FEATURE_CUSTOM_COVER_GLASS_ON,
};
struct fts_flash_corruption_info {
bool fw_broken;
bool cfg_broken;
bool cx_broken;
};
struct fts_i2c_platform_data {
bool disable_tuning;
bool delayed_open;
unsigned int delayed_open_time;
int max_x;
int max_y;
struct regulator *regulator_dvdd;
struct regulator *regulator_avdd;
int (*power)(void *data, bool on);
unsigned gpio;
int vdd_gpio;
int vio_gpio;
int irq_type;
int coord_factor;
int x_axis_real_max;
int y_axis_real_max;
int x_axis_edge_offset;
int y_axis_edge_offset;
};
struct fts_ts_info {
struct device *dev;
struct i2c_client *client;
struct input_dev *input_dev;
struct work_struct work;
int irq;
int irq_type;
atomic_t irq_enabled;
struct fts_i2c_platform_data *board;
bool run_autotune;
int power_state;
int touch_count;
struct fts_finger finger[FINGER_MAX];
bool palm_pressed;
int palm_touch_id;
int touch_mode;
struct delayed_work open_work;
struct mutex i2c_mutex;
struct mutex device_mutex;
spinlock_t lock;
unsigned char data[FTS_EVENT_SIZE * FTS_FIFO_MAX];
struct fts_flash_corruption_info flash_corruption_info;
};
#define WRITE_CHUNK_SIZE 32
#define FLASH_CHUNK (64 * 1024)
#define DMA_CHUNK 32
#define FW_HEADER_SIZE 64
#define FW_HEADER_FTB_SIGNATURE 0xAA55AA55
#define FW_FTB_VER 0x00000001
#define FW_BYTES_ALLIGN 4
#define FW_BIN_VER_OFFSET 16
#define FW_BIN_CONFIG_VER_OFFSET 20
/* Command for flash */
#define FLASH_CMD_UNLOCK 0xF7
#define FLASH_CMD_WRITE_64K 0xF8
#define FLASH_CMD_READ_REGISTER 0xF9
#define FLASH_CMD_WRITE_REGISTER 0xFA
/* Parameters for commands */
#define ADDR_WARM_BOOT 0x001E
#define WARM_BOOT_VALUE 0x38
#define FLASH_ADDR_CODE 0x00000000
#define FLASH_ADDR_CONFIG 0x0000FC00
#define FLASH_UNLOCK_CODE0 0x74
#define FLASH_UNLOCK_CODE1 0x45
#define FLASH_ERASE_UNLOCK_CODE0 0x72
#define FLASH_ERASE_UNLOCK_CODE1 0x03
#define FLASH_ERASE_UNLOCK_CODE2 0x02
#define FLASH_ERASE_CODE0 0x02
#define FLASH_ERASE_CODE1 0xC0
#define FLASH_DMA_CODE0 0x05
#define FLASH_DMA_CODE1 0xC0
#define FLASH_DMA_CONFIG 0x06
#endif /* _LINUX_FTM4_TS_H_ */
+4
View File
@@ -545,6 +545,10 @@ int tegra30_mc_probe(struct tegra_mc *mc)
if (err < 0)
return err;
err = of_platform_populate(mc->dev->of_node, NULL, NULL, mc->dev);
if (err < 0)
return err;
return 0;
}
+5
View File
@@ -443,6 +443,8 @@ static int tegra186_emc_probe(struct platform_device *pdev)
if (!emc)
return -ENOMEM;
mutex_init(&emc->rate_lock);
emc->bpmp = tegra_bpmp_get(&pdev->dev);
if (IS_ERR(emc->bpmp))
return dev_err_probe(&pdev->dev, PTR_ERR(emc->bpmp),
@@ -521,6 +523,9 @@ static const struct of_device_id tegra186_emc_of_match[] = {
#if defined(CONFIG_ARCH_TEGRA_186_SOC)
{ .compatible = "nvidia,tegra186-emc" },
#endif
#if defined(CONFIG_ARCH_TEGRA_210_SOC)
{ .compatible = "nvidia,tegra210b01-emc" },
#endif
#if defined(CONFIG_ARCH_TEGRA_194_SOC)
{ .compatible = "nvidia,tegra194-emc" },
#endif
+363 -5
View File
@@ -6,7 +6,7 @@
* Author: Mike Rapoport <mike@compulab.co.il>
*
* Based on NVIDIA PCIe driver
* Copyright (c) 2008-2009, NVIDIA Corporation.
* Copyright (c) 2008-2020, NVIDIA Corporation.
*
* Bits taken from arch/arm/mach-dove/pcie.c
*
@@ -165,10 +165,61 @@
#define AFI_PLLE_CONTROL 0x160
#define AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL (1 << 9)
#define AFI_PLLE_CONTROL_BYPASS_PCIE2PLLE_CONTROL (1 << 8)
#define AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN (1 << 1)
#define AFI_PLLE_CONTROL_PCIE2PLLE_CONTROL_EN (1 << 0)
#define AFI_PEXBIAS_CTRL_0 0x168
#define RP_PRIV_XP_DL 0x00000494
#define RP_PRIV_XP_DL_GEN2_UPD_FC_TSHOLD (0x1ff << 1)
#define RP_L1_PM_SUBSTATES_CTL 0xc00
#define RP_L1_PM_SUBSTATES_CTL_PCI_PM_L1_2 (0x1 << 0)
#define RP_L1_PM_SUBSTATES_CTL_PCI_PM_L1_1 (0x1 << 1)
#define RP_L1_PM_SUBSTATES_CTL_ASPM_L1_2 (0x1 << 2)
#define RP_L1_PM_SUBSTATES_CTL_ASPM_L1_1 (0x1 << 3)
#define RP_L1_PM_SUBSTATES_CTL_CM_RTIME_MASK (0xff << 8)
#define RP_L1_PM_SUBSTATES_CTL_CM_RTIME_SHIFT 8
#define RP_L1_PM_SUBSTATES_CTL_T_PWRN_SCL_MASK (0x3 << 16)
#define RP_L1_PM_SUBSTATES_CTL_T_PWRN_SCL_SHIFT 16
#define RP_L1_PM_SUBSTATES_CTL_T_PWRN_VAL_MASK (0x1f << 19)
#define RP_L1_PM_SUBSTATES_CTL_T_PWRN_VAL_SHIFT 19
#define RP_L1_PM_SUBSTATES_CTL_HIDE_CAP (0x1 << 24)
#define RP_L1_PM_SUBSTATES_1_CTL 0xc04
#define RP_L1_PM_SUBSTATES_1_CTL_PWR_OFF_DLY_MASK 0x1fff
#define RP_L1_PM_SUBSTATES_1_CTL_PWR_OFF_DLY 0x26
#define RP_L1SS_1_CTL_CLKREQ_ASSERTED_DLY_MASK (0x1ff << 13)
#define RP_L1SS_1_CTL_CLKREQ_ASSERTED_DLY (0x27 << 13)
#define RP_L1_PM_SUBSTATES_2_CTL 0xc08
#define RP_L1_PM_SUBSTATES_2_CTL_T_L1_2_DLY_MASK 0x1fff
#define RP_L1_PM_SUBSTATES_2_CTL_T_L1_2_DLY 0x4d
#define RP_L1_PM_SUBSTATES_2_CTL_MICROSECOND_MASK (0xff << 13)
#define RP_L1_PM_SUBSTATES_2_CTL_MICROSECOND (0x13 << 13)
#define RP_L1_PM_SUBSTATES_2_CTL_MICROSECOND_COMP_MASK (0xf << 21)
#define RP_L1_PM_SUBSTATES_2_CTL_MICROSECOND_COMP (0x2 << 21)
#define RP_RX_HDR_LIMIT 0x00000e00
#define RP_RX_HDR_LIMIT_PW_MASK (0xff << 8)
#define RP_RX_HDR_LIMIT_PW (0x0e << 8)
#define RP_TIMEOUT0 0xe24
#define RP_TIMEOUT0_PAD_PWRUP_MASK 0xff
#define RP_TIMEOUT0_PAD_PWRUP 0xa
#define RP_TIMEOUT0_PAD_PWRUP_CM_MASK 0xffff00
#define RP_TIMEOUT0_PAD_PWRUP_CM (0x180 << 8)
#define RP_TIMEOUT0_PAD_SPDCHNG_GEN2_MASK (0xff << 24)
#define RP_TIMEOUT0_PAD_SPDCHNG_GEN2 (0xa << 24)
#define RP_TIMEOUT1 0xe28
#define RP_TIMEOUT1_RCVRY_SPD_SUCCESS_EIDLE_MASK (0xff << 16)
#define RP_TIMEOUT1_RCVRY_SPD_SUCCESS_EIDLE (0x10 << 16)
#define RP_TIMEOUT1_RCVRY_SPD_UNSUCCESS_EIDLE_MASK (0xff << 24)
#define RP_TIMEOUT1_RCVRY_SPD_UNSUCCESS_EIDLE (0x74 << 24)
#define RP_ECTL_1_R1 0x00000e80
#define RP_ECTL_1_R1_TX_DRV_AMP_1C_MASK 0x3f
@@ -207,6 +258,19 @@
#define RP_VEND_XP_OPPORTUNISTIC_UPDATEFC (1 << 28)
#define RP_VEND_XP_UPDATE_FC_THRESHOLD_MASK (0xff << 18)
#define RP_VEND_XP1 0xf04
#define RP_VEND_XP1_LINK_PVT_CTL_IGNORE_L0S (1 << 23)
#define RP_VEND_XP1_LINK_PVT_CTL_L1_ASPM_SUPPORT (1 << 21)
#define RP_XP_REF 0xf30
#define RP_XP_REF_MICROSECOND_LIMIT_MASK 0xff
#define RP_XP_REF_MICROSECOND_LIMIT 0x14
#define RP_XP_REF_MICROSECOND_ENABLE (1 << 8)
#define RP_XP_REF_CPL_TO_OVERRIDE (1 << 13)
#define RP_XP_REF_CPL_TO_CUSTOM_VALUE_MASK (0x1ffff << 14)
#define RP_XP_REF_CPL_TO_CUSTOM_VALUE (0x1770 << 14)
#define RP_VEND_CTL0 0x00000f44
#define RP_VEND_CTL0_DSK_RST_PULSE_WIDTH_MASK (0xf << 12)
#define RP_VEND_CTL0_DSK_RST_PULSE_WIDTH (0x9 << 12)
@@ -230,12 +294,23 @@
#define RP_PRIV_MISC_TMS_CLK_CLAMP_THRESHOLD (0xf << 24)
#define RP_PRIV_MISC_TMS_CLK_CLAMP_ENABLE (1 << 31)
#define RP_VEND_XP_PAD_PWRDN 0x00000f50
#define RP_VEND_XP_PAD_PWRDN_L1_EN (1 << 0)
#define RP_VEND_XP_PAD_PWRDN_DYNAMIC_EN (1 << 1)
#define RP_VEND_XP_PAD_PWRDN_DISABLED_EN (1 << 2)
#define RP_VEND_XP_PAD_PWRDN_L1_CLKREQ_EN (1 << 15)
#define RP_VEND_XP_PAD_PWRDN_SLEEP_MODE_DYNAMIC_L1PP (3 << 5)
#define RP_VEND_XP_PAD_PWRDN_SLEEP_MODE_L1_L1PP (3 << 3)
#define RP_VEND_XP_PAD_PWRDN_SLEEP_MODE_L1_CLKREQ_L1PP (3 << 16)
#define RP_LINK_CONTROL_STATUS 0x00000090
#define RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000
#define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000
#define RP_LINK_CONTROL_STATUS_2 0x000000b0
#define RP_L1_PM_SUBSTATES_CAP 0x144
#define PADS_CTL_SEL 0x0000009c
#define PADS_CTL 0x000000a0
@@ -312,6 +387,10 @@ struct tegra_pcie_soc {
bool program_deskew_time;
bool update_fc_timer;
bool has_cache_bars;
bool enable_wrap;
bool has_aspm_l1;
bool has_aspm_l1ss;
bool l1ss_rp_wake_fixup;
struct {
struct {
u32 rp_ectl_1_r1;
@@ -376,6 +455,8 @@ struct tegra_pcie_port {
void __iomem *base;
unsigned int index;
unsigned int lanes;
unsigned int aspm_state;
bool supports_clkreq;
struct phy **phys;
@@ -404,6 +485,14 @@ static inline u32 pads_readl(struct tegra_pcie *pcie, unsigned long offset)
return readl(pcie->pads + offset);
}
static bool tegra_pcie_link_up(struct tegra_pcie_port *port)
{
u32 value;
value = readl(port->base + RP_LINK_CONTROL_STATUS);
return !!(value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE);
}
/*
* The configuration space mapping on Tegra is somewhat similar to the ECAM
* defined by PCIe. However it deviates a bit in how the 4 bits for extended
@@ -469,20 +558,50 @@ static void __iomem *tegra_pcie_map_bus(struct pci_bus *bus,
static int tegra_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 *value)
{
struct tegra_pcie *pcie = bus->sysdata;
struct pci_dev *bridge;
struct tegra_pcie_port *port;
if (bus->number == 0)
return pci_generic_config_read32(bus, devfn, where, size,
value);
bridge = pcie_find_root_port(bus->self);
list_for_each_entry(port, &pcie->ports, list)
if (port->index + 1 == PCI_SLOT(bridge->devfn))
break;
/* If there is no link, then there is no device */
if (!tegra_pcie_link_up(port)) {
*value = 0xffffffff;
return PCIBIOS_DEVICE_NOT_FOUND;
}
return pci_generic_config_read(bus, devfn, where, size, value);
}
static int tegra_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 value)
{
struct tegra_pcie *pcie = bus->sysdata;
struct tegra_pcie_port *port;
struct pci_dev *bridge;
if (bus->number == 0)
return pci_generic_config_write32(bus, devfn, where, size,
value);
bridge = pcie_find_root_port(bus->self);
list_for_each_entry(port, &pcie->ports, list)
if (port->index + 1 == PCI_SLOT(bridge->devfn))
break;
/* If there is no link, then there is no device */
if (!tegra_pcie_link_up(port))
return PCIBIOS_DEVICE_NOT_FOUND;
return pci_generic_config_write(bus, devfn, where, size, value);
}
@@ -539,6 +658,44 @@ static void tegra_pcie_port_reset(struct tegra_pcie_port *port)
}
}
static void disable_aspm_l0s(struct tegra_pcie_port *port)
{
u32 val = 0;
val = readl(port->base + RP_VEND_XP1);
val |= RP_VEND_XP1_LINK_PVT_CTL_IGNORE_L0S;
writel(val, port->base + RP_VEND_XP1);
}
static void disable_aspm_l10(struct tegra_pcie_port *port)
{
u32 val = 0;
val = readl(port->base + RP_VEND_XP1);
val &= ~RP_VEND_XP1_LINK_PVT_CTL_L1_ASPM_SUPPORT;
writel(val, port->base + RP_VEND_XP1);
}
static void disable_aspm_l11(struct tegra_pcie_port *port)
{
u32 val = 0;
val = readl(port->base + RP_L1_PM_SUBSTATES_CTL);
val &= ~RP_L1_PM_SUBSTATES_CTL_PCI_PM_L1_1;
val &= ~RP_L1_PM_SUBSTATES_CTL_ASPM_L1_1;
writel(val, port->base + RP_L1_PM_SUBSTATES_CTL);
}
static void disable_aspm_l12(struct tegra_pcie_port *port)
{
u32 val = 0;
val = readl(port->base + RP_L1_PM_SUBSTATES_CTL);
val &= ~RP_L1_PM_SUBSTATES_CTL_PCI_PM_L1_2;
val &= ~RP_L1_PM_SUBSTATES_CTL_ASPM_L1_2;
writel(val, port->base + RP_L1_PM_SUBSTATES_CTL);
}
static void tegra_pcie_enable_rp_features(struct tegra_pcie_port *port)
{
const struct tegra_pcie_soc *soc = port->pcie->soc;
@@ -575,6 +732,47 @@ static void tegra_pcie_enable_rp_features(struct tegra_pcie_port *port)
}
writel(value, port->base + RP_PRIV_MISC);
if (soc->has_aspm_l1) {
/* Advertise ASPM-L1 state capability*/
value = readl(port->base + RP_VEND_XP1);
value |= RP_VEND_XP1_LINK_PVT_CTL_L1_ASPM_SUPPORT;
writel(value, port->base + RP_VEND_XP1);
/* Power saving configuration for L1 sleep/idle */
value = readl(port->base + RP_VEND_XP_PAD_PWRDN);
value |= RP_VEND_XP_PAD_PWRDN_DISABLED_EN;
value |= RP_VEND_XP_PAD_PWRDN_DYNAMIC_EN;
value |= RP_VEND_XP_PAD_PWRDN_L1_EN;
value |= RP_VEND_XP_PAD_PWRDN_L1_CLKREQ_EN;
value |= RP_VEND_XP_PAD_PWRDN_SLEEP_MODE_DYNAMIC_L1PP;
value |= RP_VEND_XP_PAD_PWRDN_SLEEP_MODE_L1_L1PP;
value |= RP_VEND_XP_PAD_PWRDN_SLEEP_MODE_L1_CLKREQ_L1PP;
writel(value, port->base + RP_VEND_XP_PAD_PWRDN);
if (port->aspm_state & 0x1)
disable_aspm_l0s(port);
if (port->aspm_state & 0x2)
disable_aspm_l10(port);
}
if (soc->has_aspm_l1ss) {
if (port->aspm_state & 0x2) {
disable_aspm_l11(port);
disable_aspm_l12(port);
}
if (port->aspm_state & 0x4)
disable_aspm_l11(port);
if (port->aspm_state & 0x8)
disable_aspm_l12(port);
/* Disable L1SS capability if CLKREQ# is not present */
if (!port->supports_clkreq) {
value = readl(port->base + RP_L1_PM_SUBSTATES_CTL);
value |= RP_L1_PM_SUBSTATES_CTL_HIDE_CAP;
writel(value, port->base + RP_L1_PM_SUBSTATES_CTL);
}
}
}
static void tegra_pcie_program_ectl_settings(struct tegra_pcie_port *port)
@@ -635,6 +833,26 @@ static void tegra_pcie_program_ectl_settings(struct tegra_pcie_port *port)
writel(value, port->base + RP_ECTL_6_R2);
}
static void tegra_pcie_enable_wrap(void)
{
u32 val;
void __iomem *msel_base;
#define MSELECT_CONFIG_BASE 0x50060000
#define MSELECT_CONFIG_WRAP_TO_INCR_SLAVE1 BIT(28)
#define MSELECT_CONFIG_ERR_RESP_EN_SLAVE1 BIT(24)
/* Config MSELECT to support wrap trans for normal NC & GRE mapping */
msel_base = ioremap(MSELECT_CONFIG_BASE, 4);
val = readl(msel_base);
/* Enable WRAP_TO_INCR_SLAVE1 */
val |= MSELECT_CONFIG_WRAP_TO_INCR_SLAVE1;
/* Disable ERR_RESP_EN_SLAVE1 */
val &= ~MSELECT_CONFIG_ERR_RESP_EN_SLAVE1;
writel(val, msel_base);
iounmap(msel_base);
}
static void tegra_pcie_apply_sw_fixup(struct tegra_pcie_port *port)
{
const struct tegra_pcie_soc *soc = port->pcie->soc;
@@ -669,6 +887,76 @@ static void tegra_pcie_apply_sw_fixup(struct tegra_pcie_port *port)
value &= ~PCI_EXP_LNKSTA_CLS;
value |= PCI_EXP_LNKSTA_CLS_2_5GB;
writel(value, port->base + RP_LINK_CONTROL_STATUS_2);
if (soc->enable_wrap)
tegra_pcie_enable_wrap();
if (soc->has_aspm_l1ss) {
/* Set port Common_Mode_Restore_Time to 30us */
value = readl(port->base + RP_L1_PM_SUBSTATES_CTL);
value &= ~RP_L1_PM_SUBSTATES_CTL_CM_RTIME_MASK;
value |= (0x1E << RP_L1_PM_SUBSTATES_CTL_CM_RTIME_SHIFT);
writel(value, port->base + RP_L1_PM_SUBSTATES_CTL);
/* set port T_POWER_ON to 70us */
value = readl(port->base + RP_L1_PM_SUBSTATES_CTL);
value &= ~(RP_L1_PM_SUBSTATES_CTL_T_PWRN_SCL_MASK |
RP_L1_PM_SUBSTATES_CTL_T_PWRN_VAL_MASK);
value |= (1 << RP_L1_PM_SUBSTATES_CTL_T_PWRN_SCL_SHIFT) |
(7 << RP_L1_PM_SUBSTATES_CTL_T_PWRN_VAL_SHIFT);
writel(value, port->base + RP_L1_PM_SUBSTATES_CTL);
/* Following is based on clk_m being 19.2 MHz */
value = readl(port->base + RP_TIMEOUT0);
value &= ~RP_TIMEOUT0_PAD_PWRUP_MASK;
value |= RP_TIMEOUT0_PAD_PWRUP;
value &= ~RP_TIMEOUT0_PAD_PWRUP_CM_MASK;
value |= RP_TIMEOUT0_PAD_PWRUP_CM;
value &= ~RP_TIMEOUT0_PAD_SPDCHNG_GEN2_MASK;
value |= RP_TIMEOUT0_PAD_SPDCHNG_GEN2;
writel(value, port->base + RP_TIMEOUT0);
value = readl(port->base + RP_TIMEOUT1);
value &= ~RP_TIMEOUT1_RCVRY_SPD_SUCCESS_EIDLE_MASK;
value |= RP_TIMEOUT1_RCVRY_SPD_SUCCESS_EIDLE;
value &= ~RP_TIMEOUT1_RCVRY_SPD_UNSUCCESS_EIDLE_MASK;
value |= RP_TIMEOUT1_RCVRY_SPD_UNSUCCESS_EIDLE;
writel(value, port->base + RP_TIMEOUT1);
value = readl(port->base + RP_XP_REF);
value &= ~RP_XP_REF_MICROSECOND_LIMIT_MASK;
value |= RP_XP_REF_MICROSECOND_LIMIT;
value |= RP_XP_REF_MICROSECOND_ENABLE;
value |= RP_XP_REF_CPL_TO_OVERRIDE;
value &= ~RP_XP_REF_CPL_TO_CUSTOM_VALUE_MASK;
value |= RP_XP_REF_CPL_TO_CUSTOM_VALUE;
writel(value, port->base + RP_XP_REF);
value = readl(port->base + RP_L1_PM_SUBSTATES_1_CTL);
value &= ~RP_L1_PM_SUBSTATES_1_CTL_PWR_OFF_DLY_MASK;
value |= RP_L1_PM_SUBSTATES_1_CTL_PWR_OFF_DLY;
writel(value, port->base + RP_L1_PM_SUBSTATES_1_CTL);
value = readl(port->base + RP_L1_PM_SUBSTATES_2_CTL);
value &= ~RP_L1_PM_SUBSTATES_2_CTL_T_L1_2_DLY_MASK;
value |= RP_L1_PM_SUBSTATES_2_CTL_T_L1_2_DLY;
value &= ~RP_L1_PM_SUBSTATES_2_CTL_MICROSECOND_MASK;
value |= RP_L1_PM_SUBSTATES_2_CTL_MICROSECOND;
value &= ~RP_L1_PM_SUBSTATES_2_CTL_MICROSECOND_COMP_MASK;
value |= RP_L1_PM_SUBSTATES_2_CTL_MICROSECOND_COMP;
writel(value, port->base + RP_L1_PM_SUBSTATES_2_CTL);
}
if (soc->l1ss_rp_wake_fixup) {
/*
* Set CLKREQ asserted delay greater than Power_Off
* time (2us) to avoid RP wakeup in L1.2.ENTRY
*/
value = readl(port->base + RP_L1_PM_SUBSTATES_1_CTL);
value &= ~RP_L1SS_1_CTL_CLKREQ_ASSERTED_DLY_MASK;
value |= RP_L1SS_1_CTL_CLKREQ_ASSERTED_DLY;
writel(value, port->base + RP_L1_PM_SUBSTATES_1_CTL);
}
}
static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
@@ -681,8 +969,12 @@ static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
value = afi_readl(port->pcie, ctrl);
value |= AFI_PEX_CTRL_REFCLK_EN;
if (soc->has_pex_clkreq_en)
value |= AFI_PEX_CTRL_CLKREQ_EN;
if (soc->has_pex_clkreq_en) {
if (port->supports_clkreq)
value &= ~AFI_PEX_CTRL_CLKREQ_EN;
else
value |= AFI_PEX_CTRL_CLKREQ_EN;
}
value |= AFI_PEX_CTRL_OVERRIDE_EN;
@@ -1112,10 +1404,20 @@ static void tegra_pcie_enable_controller(struct tegra_pcie *pcie)
unsigned long value;
/* enable PLL power down */
if (pcie->phy) {
if (soc->has_aspm_l1ss) {
value = afi_readl(pcie, AFI_PLLE_CONTROL);
value &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL;
value |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN;
list_for_each_entry(port, &pcie->ports, list) {
if (!port->supports_clkreq) {
value &= ~AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN;
break;
}
}
value &= ~AFI_PLLE_CONTROL_BYPASS_PCIE2PLLE_CONTROL;
value |= AFI_PLLE_CONTROL_PCIE2PLLE_CONTROL_EN;
afi_writel(pcie, value, AFI_PLLE_CONTROL);
}
@@ -1547,6 +1849,11 @@ static void tegra_pcie_pme_turnoff(struct tegra_pcie_port *port)
val = afi_readl(pcie, AFI_PCIE_PME);
val &= ~(0x1 << soc->ports[port->index].pme.turnoff_bit);
afi_writel(pcie, val, AFI_PCIE_PME);
/* PCIe link is in L2, bypass CLKREQ# control over PLLE power down */
val = afi_readl(pcie, AFI_PLLE_CONTROL);
val |= AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL;
afi_writel(pcie, val, AFI_PLLE_CONTROL);
}
static void tegra_pcie_msi_irq(struct irq_desc *desc)
@@ -1838,6 +2145,13 @@ static void tegra_pcie_disable_interrupts(struct tegra_pcie *pcie)
afi_writel(pcie, value, AFI_INTR_MASK);
}
static void update_rp_lanes(struct tegra_pcie *pcie, u32 lanes)
{
struct tegra_pcie_port *port = NULL;
list_for_each_entry(port, &pcie->ports, list)
port->lanes = (lanes >> (port->index << 3)) & 0xFF;
}
static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes,
u32 *xbar)
{
@@ -1866,14 +2180,21 @@ static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes,
"switching to default 2x1, 1x1, 1x1 "
"configuration\n");
*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211;
update_rp_lanes(pcie, 0x010102);
return 0;
}
} else if (of_device_is_compatible(np, "nvidia,tegra210b01-pcie")) {
switch (lanes) {
case 0x0104:
dev_info(pcie->dev, "4x1, 1x1 configuration\n");
dev_info(dev, "4x1, 1x1 configuration\n");
*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1;
return 0;
default:
dev_info(dev, "wrong configuration updated in DT, "
"switching to default 4x1, 1x1 configuration\n");
*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1;
update_rp_lanes(pcie, 0x0104);
return 0;
}
} else if (of_device_is_compatible(np, "nvidia,tegra124-pcie") ||
of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
@@ -1887,6 +2208,13 @@ static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes,
dev_info(dev, "2x1, 1x1 configuration\n");
*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1;
return 0;
default:
dev_info(dev, "wrong configuration updated in DT, "
"switching to default 4x1, 1x1 configuration\n");
*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1;
update_rp_lanes(pcie, 0x0104);
return 0;
}
} else if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) {
switch (lanes) {
@@ -2190,6 +2518,14 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
"failed to get reset GPIO\n");
}
err = of_property_read_u32(port, "nvidia,disable-aspm-states",
&rp->aspm_state);
if (err < 0)
rp->aspm_state = 0;
rp->supports_clkreq = of_property_read_bool(port,
"supports-clkreq");
list_add_tail(&rp->list, &pcie->ports);
}
@@ -2378,6 +2714,10 @@ static const struct tegra_pcie_soc tegra20_pcie = {
.program_deskew_time = false,
.update_fc_timer = false,
.has_cache_bars = true,
.enable_wrap = false,
.has_aspm_l1 = false,
.has_aspm_l1ss = false,
.l1ss_rp_wake_fixup = false,
.ectl.enable = false,
};
@@ -2407,6 +2747,10 @@ static const struct tegra_pcie_soc tegra30_pcie = {
.program_deskew_time = false,
.update_fc_timer = false,
.has_cache_bars = false,
.enable_wrap = false,
.has_aspm_l1 = true,
.has_aspm_l1ss = false,
.l1ss_rp_wake_fixup = false,
.ectl.enable = false,
};
@@ -2428,6 +2772,10 @@ static const struct tegra_pcie_soc tegra124_pcie = {
.program_deskew_time = false,
.update_fc_timer = false,
.has_cache_bars = false,
.enable_wrap = false,
.has_aspm_l1 = true,
.has_aspm_l1ss = false,
.l1ss_rp_wake_fixup = false,
.ectl.enable = false,
};
@@ -2451,6 +2799,10 @@ static const struct tegra_pcie_soc tegra210_pcie = {
.program_deskew_time = true,
.update_fc_timer = true,
.has_cache_bars = false,
.enable_wrap = true,
.has_aspm_l1 = true,
.has_aspm_l1ss = true,
.l1ss_rp_wake_fixup = true,
.ectl = {
.regs = {
.rp_ectl_1_r1 = 0x0000001f,
@@ -2530,6 +2882,10 @@ static const struct tegra_pcie_soc tegra186_pcie = {
.program_deskew_time = false,
.update_fc_timer = false,
.has_cache_bars = false,
.enable_wrap = false,
.has_aspm_l1 = true,
.has_aspm_l1ss = true,
.l1ss_rp_wake_fixup = false,
.ectl.enable = false,
};
@@ -2660,6 +3016,8 @@ static int tegra_pcie_probe(struct platform_device *pdev)
goto pm_runtime_put;
}
pci_add_flags(PCI_REASSIGN_ALL_BUS);
host->ops = &tegra_pcie_ops;
host->map_irq = tegra_pcie_map_irq;
+35 -3
View File
@@ -7,12 +7,17 @@
#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include "pinctrl-tegra.h"
struct tegra210_pinctrl_soc {
bool lpdr_support;
};
/*
* Most pins affected by the pinmux can also be GPIOs. Define these first.
* These must match how the GPIO driver names/numbers its pins.
@@ -1349,7 +1354,7 @@ static const char * const tegra210_functions[] = {
.parked_bitmask = prk_mask, \
}
static const struct tegra_pingroup tegra210_groups[] = {
static struct tegra_pingroup tegra210_groups[] = {
/* pg_name, f0, f1, f2, f3, r, hsm, drvtype, e_io_hv, lpdr, rdrv, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w */
PINGROUP(sdmmc1_clk_pm0, SDMMC1, RSVD1, RSVD2, RSVD3, 0x3000, Y, Y, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1),
PINGROUP(sdmmc1_cmd_pm1, SDMMC1, SPI3, RSVD2, RSVD3, 0x3004, Y, Y, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1),
@@ -1558,12 +1563,39 @@ static const struct tegra_pinctrl_soc_data tegra210_pinctrl = {
static int tegra210_pinctrl_probe(struct platform_device *pdev)
{
const struct tegra210_pinctrl_soc *soc;
struct tegra_pingroup *g;
int i;
soc = of_device_get_match_data(&pdev->dev);
if (soc->lpdr_support) {
for (i = 0; i < tegra210_pinctrl.ngroups; ++i) {
g = &tegra210_groups[i];
if (g->mux_reg >= 0)
g->lpdr_bit = 8;
}
}
return tegra_pinctrl_probe(pdev, &tegra210_pinctrl);
}
static const struct tegra210_pinctrl_soc tegra210_pinctrl_soc_data = {
.lpdr_support = false,
};
static const struct tegra210_pinctrl_soc tegra210b01_pinctrl_soc_data = {
.lpdr_support = true,
};
static const struct of_device_id tegra210_pinctrl_of_match[] = {
{ .compatible = "nvidia,tegra210-pinmux", },
{ },
{
.compatible = "nvidia,tegra210-pinmux",
.data = &tegra210_pinctrl_soc_data,
}, {
.compatible = "nvidia,tegra210b01-pinmux",
.data = &tegra210b01_pinctrl_soc_data,
}, {
},
};
static struct platform_driver tegra210_pinctrl_driver = {
+1
View File
@@ -12,6 +12,7 @@ obj-$(CONFIG_GOLDFISH) += goldfish/
obj-$(CONFIG_CHROME_PLATFORMS) += chrome/
obj-$(CONFIG_CZNIC_PLATFORMS) += cznic/
obj-$(CONFIG_SURFACE_PLATFORMS) += surface/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_ARM64_PLATFORM_DEVICES) += arm64/
obj-$(CONFIG_BCM2835_VCHIQ) += raspberrypi/
obj-$(CONFIG_ACPI_WMI) += wmi/
+24
View File
@@ -0,0 +1,24 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Tegra Platform Specific Drivers
#
menuconfig TEGRA_PLATFORM_DEVICES
bool "Tegra Platform Specific Device Drivers"
default y
help
Say Y here to get to see options for device drivers of various
Tegra platforms. This option itself does not add any kernel code.
If you say N, all options in this submenu will be skipped and
disabled.
if TEGRA_PLATFORM_DEVICES
config TEGRA_PROD_LEGACY
def_bool y
help
This config helps client driver to identify whether prod
framework is implemented as legacy method or not.
endif # TEGRA_PLATFORM_DEVICES
+3
View File
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_TEGRA_PROD_LEGACY) += tegra_prod.o
+620
View File
@@ -0,0 +1,620 @@
/*
* Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/io.h>
#include <linux/tegra_prod.h>
#define PROD_TUPLE_NUM (sizeof(struct prod_tuple)/sizeof(u32))
/* tegra_prod: Tegra Prod list for the given submodule
* @n_prod_cells: Number of prod setting cells.
*/
struct tegra_prod {
struct tegra_prod_config *prod_config;
int num; /* number of tegra_prod*/
int n_prod_cells;
};
struct prod_tuple {
u32 index; /* Address base index */
u32 addr; /* offset address*/
u32 mask; /* mask */
u32 val; /* value */
};
struct tegra_prod_config {
const char *name;
struct prod_tuple *prod_tuple;
int count; /* number of prod_tuple*/
bool boot_init;
};
static int tegra_prod_get_child_tupple_count(struct device *dev,
struct device_node *np,
int n_tupple)
{
struct device_node *child;
int count;
int total_tupple = 0;
count = of_property_count_u32_elems(np, "prod");
if (count > 0) {
if ((count < n_tupple) || (count % n_tupple != 0)) {
dev_err(dev, "Node %s has invalid entries\n", np->name);
return -EINVAL;
}
total_tupple = count / n_tupple;
}
for_each_available_child_of_node(np, child) {
count = tegra_prod_get_child_tupple_count(dev, child, n_tupple);
if (count < 0)
return count;
total_tupple += count;
}
return total_tupple;
}
static int tegra_prod_read_prod_data(struct device *dev,
struct device_node *np,
struct prod_tuple *p_tuple,
int n_tupple)
{
u32 pval;
int count;
int t_count;
int cnt;
int index;
int ret;
count = of_property_count_u32_elems(np, "prod");
if (count <= 0) {
dev_dbg(dev, "Node %s: prod prop not found\n", np->name);
return 0;
}
t_count = count / n_tupple;
for (cnt = 0; cnt < t_count; cnt++, p_tuple++) {
index = cnt * n_tupple;
if (n_tupple == 4) {
ret = of_property_read_u32_index(np, "prod", index,
&pval);
if (ret) {
dev_err(dev, "Failed to parse prod of node %s\n",
np->name);
return -EINVAL;
}
p_tuple->index = pval;
index++;
} else {
p_tuple->index = 0;
}
ret = of_property_read_u32_index(np, "prod", index, &pval);
if (ret) {
dev_err(dev, "Failed to parse address of node %s\n",
np->name);
return -EINVAL;
}
p_tuple->addr = pval;
index++;
ret = of_property_read_u32_index(np, "prod", index, &pval);
if (ret) {
dev_err(dev, "Failed to parse mask of node %s\n",
np->name);
return -EINVAL;
}
p_tuple->mask = pval;
index++;
ret = of_property_read_u32_index(np, "prod", index, &pval);
if (ret) {
dev_err(dev, "Failed to parse value of node %s\n",
np->name);
return -EINVAL;
}
p_tuple->val = pval;
}
return t_count;
}
static int tegra_prod_read_node_tupple(struct device *dev,
struct device_node *np,
struct prod_tuple *p_tuple,
int n_tupple)
{
int ret = 0;
int sindex;
struct device_node *child;
ret = tegra_prod_read_prod_data(dev, np, p_tuple, n_tupple);
if (ret < 0)
return -EINVAL;
sindex = ret;
p_tuple += ret;
for_each_available_child_of_node(np, child) {
ret = tegra_prod_read_node_tupple(dev, child,
p_tuple, n_tupple);
if (ret < 0)
return -EINVAL;
sindex += ret;
p_tuple += ret;
}
return sindex;
}
/* Process the tupples and optimise for the register configuration for
* Same location.
*/
static void tegra_prod_optimise_tupple(struct prod_tuple *p_tuple,
int n_tupple)
{
struct prod_tuple *ti, *tj;
u32 mask;
int i, j;
for (i = 0; i < n_tupple; ++i) {
ti = p_tuple + i;
for (j = i + 1; j < n_tupple; ++j) {
tj = p_tuple + j;
if (ti->index != tj->index)
continue;
if (ti->addr != tj->addr)
continue;
mask = ti->mask & tj->mask;
if (!mask)
continue;
ti->val &= ~mask;
ti->mask &= ~mask;
}
}
}
/**
* tegra_prod_parse_dt - Read the prod setting form Device tree.
* @np: device node from which the property value is to be read.
* @np_prod: Prod setting node.
* @tegra_prod: The list of tegra prods.
*
* Read the prod setting form DT according the prod name in tegra prod list.
* prod tuple will be allocated dynamically according to the tuple number of
* each prod in DT.
*
* Returns 0 on success.
*/
static int tegra_prod_parse_dt(struct device *dev,
const struct device_node *np,
const struct device_node *np_prod,
struct tegra_prod *tegra_prod)
{
struct device_node *child;
struct tegra_prod_config *t_prod;
struct prod_tuple *p_tuple;
int n_child;
int n_tupple = 3;
int ret;
int count;
u32 pval;
bool mask_opt;
if (!tegra_prod || !tegra_prod->prod_config) {
dev_err(dev, "Node %s: Invalid tegra prods list.\n", np->name);
return -EINVAL;
};
mask_opt = of_property_read_bool(np_prod, "enable-mask-optimisation");
ret = of_property_read_u32(np_prod, "#prod-cells", &pval);
if (!ret)
n_tupple = pval;
if ((n_tupple != 3) && (n_tupple != 4)) {
dev_err(dev, "Node %s: Prod cells not supported\n", np->name);
return -EINVAL;
}
tegra_prod->n_prod_cells = n_tupple;
n_child = 0;
for_each_available_child_of_node(np_prod, child) {
t_prod = &tegra_prod->prod_config[n_child];
t_prod->name = child->name;
count = tegra_prod_get_child_tupple_count(dev, child, n_tupple);
if (count < 0) {
dev_err(dev, "Node %s: Child has not proper setting\n",
child->name);
return -EINVAL;
}
if (!count) {
dev_err(dev, "Node %s: prod prop not found\n",
child->name);
return -EINVAL;
}
t_prod->count = count;
t_prod->prod_tuple = devm_kcalloc(dev, t_prod->count,
sizeof(*p_tuple), GFP_KERNEL);
if (!t_prod->prod_tuple)
return -ENOMEM;
t_prod->boot_init = of_property_read_bool(child,
"nvidia,prod-boot-init");
ret = tegra_prod_read_node_tupple(dev, child,
t_prod->prod_tuple, n_tupple);
if (ret < 0) {
dev_err(dev, "Node %s: Reading prod setting failed: %d\n",
child->name, ret);
return ret;
}
if (t_prod->count != ret) {
dev_err(dev, "Node %s: prod read failed: exp %d read %d\n",
child->name, t_prod->count, ret);
return -EINVAL;
}
/* Optimise the prod configuration */
if (mask_opt)
tegra_prod_optimise_tupple(t_prod->prod_tuple,
t_prod->count);
n_child++;
}
tegra_prod->num = n_child;
return 0;
}
/**
* tegra_prod_set_tuple - Only set a tuple.
* @base: base address of the register.
* @prod_tuple: the tuple to set.
* @new_mask: Mask override value, 0 means use from tupple.
*
* Returns 0 on success.
*/
static int tegra_prod_set_tuple(void __iomem **base,
struct prod_tuple *prod_tuple,
u32 new_mask)
{
u32 reg;
u32 mask = (new_mask) ? new_mask : prod_tuple->mask;
if (!prod_tuple)
return -EINVAL;
reg = readl(base[prod_tuple->index] + prod_tuple->addr);
reg = ((reg & ~mask) | (prod_tuple->val & mask));
writel(reg, base[prod_tuple->index] + prod_tuple->addr);
return 0;
}
/**
* tegra_prod_set - Set one prod setting.
* @base: base address of the register.
* @tegra_prod: the prod setting to set.
*
* Set all the tuples in one tegra_prod.
* Returns 0 on success.
*/
static int tegra_prod_set(void __iomem **base,
struct tegra_prod_config *tegra_prod)
{
int i;
int ret;
if (!tegra_prod)
return -EINVAL;
for (i = 0; i < tegra_prod->count; i++) {
ret = tegra_prod_set_tuple(base, &tegra_prod->prod_tuple[i], 0);
if (ret)
return ret;
}
return 0;
}
/**
* tegra_prod_set_list - Set all the prod settings of the list in sequence.
* @base: base address of the register.
* @tegra_prod: the list of tegra prods.
*
* Returns 0 on success.
*/
int tegra_prod_set_list(void __iomem **base,
struct tegra_prod *tegra_prod)
{
int i;
int ret;
if (!tegra_prod)
return -EINVAL;
for (i = 0; i < tegra_prod->num; i++) {
ret = tegra_prod_set(base, &tegra_prod->prod_config[i]);
if (ret)
return ret;
}
return 0;
}
EXPORT_SYMBOL(tegra_prod_set_list);
/**
* tegra_prod_set_boot_init - Set all the prod settings of the list in sequence
* Which are needed for boot initialisation.
* @base: base address of the register.
* @tegra_prod: the list of tegra prods.
*
* Returns 0 on success.
*/
int tegra_prod_set_boot_init(void __iomem **base,
struct tegra_prod *tegra_prod)
{
int i;
int ret;
if (!tegra_prod)
return -EINVAL;
for (i = 0; i < tegra_prod->num; i++) {
if (!tegra_prod->prod_config[i].boot_init)
continue;
ret = tegra_prod_set(base, &tegra_prod->prod_config[i]);
if (ret)
return ret;
}
return 0;
}
EXPORT_SYMBOL(tegra_prod_set_boot_init);
/**
* tegra_prod_set_by_name - Set the prod setting according the name.
* @base: base address of the register.
* @name: the name of tegra prod need to set.
* @tegra_prod: the list of tegra prods.
*
* Find the tegra prod in the list according to the name. Then set
* that tegra prod.
*
* Returns 0 on success.
*/
int tegra_prod_set_by_name(void __iomem **base, const char *name,
struct tegra_prod *tegra_prod)
{
int i;
struct tegra_prod_config *t_prod;
if (!tegra_prod)
return -EINVAL;
for (i = 0; i < tegra_prod->num; i++) {
t_prod = &tegra_prod->prod_config[i];
if (!strcasecmp(t_prod->name, name))
return tegra_prod_set(base, t_prod);
}
return -ENODEV;
}
EXPORT_SYMBOL(tegra_prod_set_by_name);
/**
* tegra_prod_set_by_name_partially - Set the prod setting from list partially
* under given prod name. The matching is done
* qith index, offset and mask.
* @base: base address of the register.
* @name: the name of tegra prod need to set.
* @tegra_prod: the list of tegra prods.
* @index: Index of base address.
* @offset: Offset of the register.
* @mask: Mask field on given register.
*
* Find the tegra prod in the list according to the name. Then set
* that tegra prod which has matching of index, offset and mask.
*
* Returns 0 on success.
*/
int tegra_prod_set_by_name_partially(void __iomem **base, const char *name,
struct tegra_prod *tegra_prod, u32 index,
u32 offset, u32 mask)
{
struct tegra_prod_config *t_prod;
int ret;
int i;
bool found = false;
if (!tegra_prod)
return -EINVAL;
for (i = 0; i < tegra_prod->num; i++) {
t_prod = &tegra_prod->prod_config[i];
if (!strcasecmp(t_prod->name, name)) {
found = true;
break;
}
}
if (!found)
return -ENODEV;
for (i = 0; i < t_prod->count; i++) {
struct prod_tuple *ptuple = &t_prod->prod_tuple[i];;
if ((ptuple->index != index) || (ptuple->addr != offset) ||
((ptuple->mask & mask) != mask))
continue;
ret = tegra_prod_set_tuple(base, ptuple, mask);
if (ret < 0)
return ret;
}
return 0;
}
EXPORT_SYMBOL(tegra_prod_set_by_name_partially);
bool tegra_prod_by_name_supported(struct tegra_prod *tegra_prod,
const char *name)
{
int i;
struct tegra_prod_config *t_prod;
if (!tegra_prod)
return false;
for (i = 0; i < tegra_prod->num; i++) {
t_prod = &tegra_prod->prod_config[i];
if (!t_prod)
break;
if (!strcasecmp(t_prod->name, name))
return true;
}
return false;
}
EXPORT_SYMBOL(tegra_prod_by_name_supported);
/**
* tegra_prod_init - Init tegra prod list.
# @dev: Device handle.
* @np: device node from which the property value is to be read.
*
* Query all the prod settings under DT node & Init the tegra prod list
* automatically.
*
* Returns 0 on success, -EINVAL for wrong prod number, -ENOMEM if failed
* to allocate memory for tegra prod list.
*/
static struct tegra_prod *tegra_prod_init(struct device *dev,
const struct device_node *np)
{
struct tegra_prod *tegra_prod;
struct device_node *np_prod;
int prod_num = 0;
int ret;
np_prod = of_get_child_by_name(np, "prod-settings");
if (!np_prod)
return ERR_PTR(-ENODEV);
/* Check whether child is enabled or not */
if (!of_device_is_available(np_prod)) {
dev_err(dev, "Node %s: Node is not enabled\n", np_prod->name);
return ERR_PTR(-ENODEV);
}
prod_num = of_get_child_count(np_prod);
if (prod_num <= 0) {
dev_err(dev, "Node %s: No child node for prod settings\n",
np_prod->name);
return ERR_PTR(-ENODEV);
}
tegra_prod = devm_kzalloc(dev, sizeof(*tegra_prod), GFP_KERNEL);
if (!tegra_prod)
return ERR_PTR(-ENOMEM);
tegra_prod->prod_config = devm_kcalloc(dev, prod_num,
sizeof(*tegra_prod->prod_config),
GFP_KERNEL);
if (!tegra_prod->prod_config)
return ERR_PTR(-ENOMEM);
tegra_prod->num = prod_num;
ret = tegra_prod_parse_dt(dev, np, np_prod, tegra_prod);
if (ret) {
dev_err(dev, "Node %s: Failed to read the Prod Setting.\n",
np->name);
return ERR_PTR(ret);
}
return tegra_prod;
}
static void devm_tegra_prod_release(struct device *dev, void *res)
{
}
struct tegra_prod *devm_tegra_prod_get(struct device *dev)
{
struct tegra_prod **ptr, *prod_list;
ptr = devres_alloc(devm_tegra_prod_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
prod_list = tegra_prod_init(dev, dev->of_node);
if (IS_ERR(prod_list)) {
devres_free(ptr);
return prod_list;
}
*ptr = prod_list;
devres_add(dev, ptr);
return prod_list;
}
EXPORT_SYMBOL(devm_tegra_prod_get);
struct tegra_prod *devm_tegra_prod_get_from_node(struct device *dev,
struct device_node *np)
{
struct tegra_prod **ptr, *prod_list;
ptr = devres_alloc(devm_tegra_prod_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
prod_list = tegra_prod_init(dev, np);
if (IS_ERR(prod_list)) {
devres_free(ptr);
return prod_list;
}
*ptr = prod_list;
devres_add(dev, ptr);
return prod_list;
}
EXPORT_SYMBOL(devm_tegra_prod_get_from_node);
+24
View File
@@ -611,6 +611,29 @@ out:
}
#ifdef CONFIG_REGULATOR
static int bq24190_get_charging_current(struct regulator_dev *dev)
{
struct bq24190_dev_info *bdi = rdev_get_drvdata(dev);
int in_current_limit;
int ret;
dev_info(bdi->dev, "Getting charging current\n");
ret = bq24190_get_field_val(bdi, BQ24190_REG_ISC,
BQ24190_REG_ISC_IINLIM_MASK,
BQ24190_REG_ISC_IINLIM_SHIFT,
bq24190_isc_iinlim_values,
ARRAY_SIZE(bq24190_isc_iinlim_values),
&in_current_limit);
if (ret < 0)
goto error;
return in_current_limit;
error:
dev_err(bdi->dev, "Charger enable failed, err = %d\n", ret);
return ret;
}
static int bq24190_set_charging_current(struct regulator_dev *dev,
int min_uA, int max_uA)
{
@@ -645,6 +668,7 @@ error:
}
static const struct regulator_ops bq24190_chrg_ops = {
.get_current_limit = bq24190_get_charging_current,
.set_current_limit = bq24190_set_charging_current,
};
+49 -5
View File
@@ -56,6 +56,11 @@
#define CTL_MODE_VSEL0_MODE BIT(0)
#define CTL_MODE_VSEL1_MODE BIT(1)
#define FAN53528_CTL_MODE_MASK 0x3
#define FAN53528_CTL_MODE_FPWM (BIT(1) | BIT(0))
#define FAN53528_CTL_MODE_AUTFPWM 0x0
#define FAN53528_VOLTAGE_MASK 0x7F
#define FAN53555_NVOLTAGES 64 /* Numbers of voltages */
#define FAN53526_NVOLTAGES 128
#define RK8602_NVOLTAGES 160
@@ -67,6 +72,7 @@
enum fan53555_vendor {
FAN53526_VENDOR_FAIRCHILD = 0,
FAN53528_VENDOR_FAIRCHILD,
FAN53555_VENDOR_FAIRCHILD,
FAN53555_VENDOR_ROCKCHIP, /* RK8600, RK8601 */
RK8602_VENDOR_ROCKCHIP, /* RK8602, RK8603 */
@@ -161,8 +167,12 @@ static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV)
ret = regulator_map_voltage_linear(rdev, uV, uV);
if (ret < 0)
return ret;
ret = regmap_update_bits(rdev->regmap, di->sleep_reg,
di->desc.vsel_mask, ret);
if (di->vendor == FAN53528_VENDOR_FAIRCHILD)
ret = regmap_update_bits(rdev->regmap, di->sleep_reg,
FAN53528_VOLTAGE_MASK, ret);
else
ret = regmap_update_bits(rdev->regmap, di->sleep_reg,
di->desc.vsel_mask, ret);
if (ret < 0)
return ret;
/* Cache the sleep voltage setting.
@@ -194,11 +204,21 @@ static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode)
switch (mode) {
case REGULATOR_MODE_FAST:
regmap_update_bits(rdev->regmap, di->mode_reg,
di->mode_mask, di->mode_mask);
if (di->vendor == FAN53528_VENDOR_FAIRCHILD)
regmap_update_bits(rdev->regmap, FAN53555_CONTROL,
FAN53528_CTL_MODE_MASK,
FAN53528_CTL_MODE_FPWM);
else
regmap_update_bits(rdev->regmap, di->mode_reg,
di->mode_mask, di->mode_mask);
break;
case REGULATOR_MODE_NORMAL:
regmap_update_bits(rdev->regmap, di->vol_reg, di->mode_mask, 0);
if (di->vendor == FAN53528_VENDOR_FAIRCHILD)
regmap_update_bits(di->regmap, FAN53555_CONTROL,
FAN53528_CTL_MODE_MASK,
FAN53528_CTL_MODE_AUTFPWM);
else
regmap_update_bits(rdev->regmap, di->vol_reg, di->mode_mask, 0);
break;
default:
return -EINVAL;
@@ -212,6 +232,17 @@ static unsigned int fan53555_get_mode(struct regulator_dev *rdev)
unsigned int val;
int ret = 0;
if (di->vendor == FAN53528_VENDOR_FAIRCHILD) {
ret = regmap_read(di->regmap, FAN53555_CONTROL, &val);
if (ret < 0)
return ret;
if ((val & FAN53528_CTL_MODE_MASK) == FAN53528_CTL_MODE_FPWM)
return REGULATOR_MODE_FAST;
else
return REGULATOR_MODE_NORMAL;
return 0;
}
ret = regmap_read(rdev->regmap, di->mode_reg, &val);
if (ret < 0)
return ret;
@@ -610,6 +641,13 @@ static int fan53555_regulator_register(struct fan53555_device_info *di,
rdesc->enable_time = di->enable_time;
rdesc->owner = THIS_MODULE;
if (di->vendor == FAN53528_VENDOR_FAIRCHILD) {
rdesc->name = "fan53528-reg";
rdesc->n_voltages = FAN53526_NVOLTAGES;
rdesc->vsel_mask = FAN53528_VOLTAGE_MASK;
};
rdev = devm_regulator_register(di->dev, &di->desc, config);
return PTR_ERR_OR_ZERO(rdev);
}
@@ -645,6 +683,9 @@ static const struct of_device_id __maybe_unused fan53555_dt_ids[] = {
{
.compatible = "fcs,fan53526",
.data = (void *)FAN53526_VENDOR_FAIRCHILD,
}, {
.compatible = "fcs,fan53528",
.data = (void *)FAN53528_VENDOR_FAIRCHILD,
}, {
.compatible = "fcs,fan53555",
.data = (void *)FAN53555_VENDOR_FAIRCHILD
@@ -752,6 +793,9 @@ static const struct i2c_device_id fan53555_id[] = {
{
.name = "fan53526",
.driver_data = FAN53526_VENDOR_FAIRCHILD
}, {
.name = "fan53528",
.driver_data = FAN53528_VENDOR_FAIRCHILD
}, {
.name = "fan53555",
.driver_data = FAN53555_VENDOR_FAIRCHILD
+4 -2
View File
@@ -4,7 +4,7 @@
*
* High-speed serial driver for NVIDIA Tegra SoCs
*
* Copyright (c) 2012-2019, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2012-2020, NVIDIA CORPORATION. All rights reserved.
*
* Author: Laxman Dewangan <ldewangan@nvidia.com>
*/
@@ -1260,8 +1260,10 @@ static void tegra_uart_flush_buffer(struct uart_port *u)
struct tegra_uart_port *tup = to_tegra_uport(u);
tup->tx_bytes = 0;
if (tup->tx_dma_chan)
if (tup->tx_dma_chan) {
dmaengine_terminate_all(tup->tx_dma_chan);
tup->tx_in_progress = 0;
}
}
static void tegra_uart_shutdown(struct uart_port *u)
+12
View File
@@ -64,6 +64,18 @@ config TYPEC_ANX7411
If you choose to build this driver as a dynamically linked module, the
module will be called anx7411.ko.
config TYPEC_BM92TXX
tristate "Rohm Semiconductor BM92TXX USB Type-C Support"
depends on I2C
depends on USB_ROLE_SWITCH
depends on DRM
help
Say Y or M here if your system has Rohm BM92TXX USB Type-C and
Power Delivery controller.
If you choose to build this driver as a dynamically linked module, the
module will be called bm92txx.ko
config TYPEC_RT1719
tristate "Richtek RT1719 Sink Only Type-C controller driver"
depends on USB_ROLE_SWITCH || !USB_ROLE_SWITCH
+1
View File
@@ -7,6 +7,7 @@ obj-$(CONFIG_TYPEC_TCPM) += tcpm/
obj-$(CONFIG_TYPEC_UCSI) += ucsi/
obj-$(CONFIG_TYPEC_TPS6598X) += tipd/
obj-$(CONFIG_TYPEC_ANX7411) += anx7411.o
obj-$(CONFIG_TYPEC_BM92TXX) += bm92txx.o
obj-$(CONFIG_TYPEC_HD3SS3220) += hd3ss3220.o
obj-$(CONFIG_TYPEC_STUSB160X) += stusb160x.o
obj-$(CONFIG_TYPEC_RT1719) += rt1719.o
File diff suppressed because it is too large. Load diff
+126
View File
@@ -0,0 +1,126 @@
/*
* Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _TEGRA_PRODS_H
#define _TEGRA_PRODS_H
struct tegra_prod;
/**
* tegra_prod_set_list(): Set all prods configurations
* @base: List of IO mapped registers.
* @tegra_prod: tegra_prod handle which is allocated by devm_tegra_prod_get()
* or tegra_prod_get_from_node();
*
* Configure all the prod configuration listed on prod-setting nodes.
*
* Returns 0 on success otherwise negive error number for failed case.
*/
int tegra_prod_set_list(void __iomem **base, struct tegra_prod *tegra_prod);
/**
* tegra_prod_set_boot_init(): Set all prods configurations which has boot init
* flag on the prod setting nodes.
* @base: List of IO mapped registers.
* @tegra_prod: tegra_prod handle which is allocated by devm_tegra_prod_get()
* or tegra_prod_get_from_node();
*
* Configure all the prod configuration listed on prod-setting nodes.
*
* Returns 0 on success otherwise negive error number for failed case.
*/
int tegra_prod_set_boot_init(void __iomem **base,
struct tegra_prod *tegra_prod);
/**
* tegra_prod_set_by_name(): Set prod configuration with specific prod name.
* This is used for conditional prod configurations.
* @base: List of IO mapped registers.
* @name: Name of conditional prod which need to be configure.
* @tegra_prod: tegra_prod handle which is allocated by devm_tegra_prod_get()
* or tegra_prod_get_from_node();
*
* Configure prod configuration with specific prod name for conditional
* prod configurations.
*
* Returns 0 on success otherwise negive error number for failed case.
*/
int tegra_prod_set_by_name(void __iomem **base, const char *name,
struct tegra_prod *tegra_prod);
/**
* tegra_prod_set_by_name_partially - Set the prod setting from list partially
* under given prod name. The matching is done
* qith index, offset and mask.
* @base: base address of the register.
* @name: the name of tegra prod need to set.
* @tegra_prod: the list of tegra prods.
* @index: Index of base address.
* @offset: Offset of the register.
* @mask: Mask field on given register.
*
* Find the tegra prod in the list according to the name. Then set
* that tegra prod which has matching of index, offset and mask.
*
* Returns 0 on success.
*/
int tegra_prod_set_by_name_partially(void __iomem **base, const char *name,
struct tegra_prod *tegra_prod, u32 index,
u32 offset, u32 mask);
/**
* tegra_prod_by_name_supported - Tell whether tegra prod will be supported by
* given name or not.
* @tegra_prod: the list of tegra prods.
* @name: the name of tegra prod need to set.
*
* Find the tegra prod in the list according to the name. If it exist then
* return true else false.
*/
bool tegra_prod_by_name_supported(struct tegra_prod *tegra_prod,
const char *name);
/**
* devm_tegra_prod_get(): Get the prod handle from the device.
* @dev: Device handle on which prod setting nodes are available.
*
* Parse the prod-setting node of the dev->of_node and keep all prod
* setting data in prod handle.
* This handle is used for setting prod configurations.
*
* Returns valid prod_list handle on success or pointer to the error
* when it failed.
*/
struct tegra_prod *devm_tegra_prod_get(struct device *dev);
/**
* devm_tegra_prod_get_from_node(): Get the prod handle from the node.
* @dev: Device handle.
* @np: Node pointer on which prod setting nodes are available.
*
* Parse the prod-setting node of the node pointer "np" and keep all prod
* setting data in prod handle.
* This handle is used for setting prod configurations.
*
* Returns valid prod_list handle on success or pointer to the error
* when it failed.
* The allocated resource is released by driver core framework when device
* is unbinded and so no need to call any release APIs for the tegra_prod
* handle.
*/
struct tegra_prod *devm_tegra_prod_get_from_node(struct device *dev,
struct device_node *np);
#endif