Compare commits

...
15 Commits
Author SHA1 Message Date
Peter De Schrijver 2f81bc20ef clk: tegra: dfll: fix use of tune values
There was some confusion on the use of the tune values. They were
defined in 2 different structs, but only initialzed in one of them.
Remove most of the references in struct tegra_dfll_soc_data and adjust
the code accordingly. Only tune_high_min_millivolts is left, because
this can be adjusted using debugfs. Hence copy the initial value from
the cvb table at boot.
2026-08-25 18:13:19 -05:00
Peter De Schrijver 0807237da1 clk: tegra: apply regulator align to Vmin
Apply regulator alignment when using Vmin to determine the lowest possible
rate generated by the DFLL.

Change-Id: I169528614871733e4a7568f3ec740079b0e9d097
Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1584439
GVS: Gerrit_Virtual_Submit
Reviewed-by: Aleksandr Frid <afrid@nvidia.com>
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
2026-08-24 21:32:13 -05:00
tmakin 411a23e997 soc/tegra: fuse: print speedo IDs on info 2026-08-24 18:59:17 -05:00
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
27 changed files with 455 additions and 4632 deletions

No files matched your search

-969
View File
@@ -1,969 +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>;
};
pcie@1003000 {
status = "okay";
avdd-pll-uerefe-supply = <&max77620_ldo1>;
hvddio-pex-supply = <&max77620_sd3>;
dvddio-pex-supply = <&max77620_ldo1>;
dvdd-pex-pll-supply = <&max77620_ldo1>;
hvdd-pex-pll-e-supply = <&max77620_sd3>;
vddio-pex-ctl-supply = <&max77620_sd3>;
pci@1,0 {
phys = <&{/padctl@7009f000/pads/pcie/lanes/pcie-3}>, /* Referred to plat config */
<&{/padctl@7009f000/pads/pcie/lanes/pcie-2}>;
phy-names = "pcie-0", "pcie-1";
nvidia,num-lanes = <2>;
status = "disabled";
};
pci@2,0 {
phys = <&{/padctl@7009f000/pads/pcie/lanes/pcie-0}>;
phy-names = "pcie-0";
status = "okay";
};
};
host1x@50000000 {
dsia: dsi@54300000 {
status = "okay";
panel@0 {
compatible = "nintendo,panel-nx-dsi";
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
@@ -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";
};
File diff suppressed because it is too large. Load diff
@@ -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";
};
@@ -48,6 +48,8 @@
};
pinmux@700008d4 {
compatible = "nvidia,tegra210b01-pinmux";
pinmux-sdmmc1-1v8-drv {
sdmmc1 {
nvidia,pull-down-strength = <0x8>;
+326 -15
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;
@@ -1647,7 +1948,7 @@ static int dfll_build_pwm_lut(struct tegra_dfll *td, unsigned long v_max)
int i;
unsigned long rate, reg_volt;
u8 lut_bottom = MAX_DFLL_VOLTAGES;
int v_min = td->soc->cvb->min_millivolts * 1000;
int v_min = td->soc->min_millivolts * 1000;
for (i = 0; i < MAX_DFLL_VOLTAGES; i++) {
reg_volt = td->lut_uv[i];
@@ -1667,7 +1968,7 @@ static int dfll_build_pwm_lut(struct tegra_dfll *td, unsigned long v_max)
if ((lut_bottom == MAX_DFLL_VOLTAGES) ||
(lut_bottom + 1 >= td->lut_size)) {
dev_err(td->dev, "no voltage above DFLL minimum %d mV\n",
td->soc->cvb->min_millivolts);
td->soc->min_millivolts);
return -EINVAL;
}
td->lut_bottom = lut_bottom;
@@ -1676,7 +1977,7 @@ static int dfll_build_pwm_lut(struct tegra_dfll *td, unsigned long v_max)
rate = get_dvco_rate_below(td, td->lut_bottom);
if (!rate) {
dev_err(td->dev, "no opp below DFLL minimum voltage %d mV\n",
td->soc->cvb->min_millivolts);
td->soc->min_millivolts);
return -EINVAL;
}
td->dvco_rate_min = rate;
@@ -1699,17 +2000,20 @@ static int dfll_build_pwm_lut(struct tegra_dfll *td, unsigned long v_max)
*/
static int dfll_build_i2c_lut(struct tegra_dfll *td, unsigned long v_max)
{
unsigned long rate, v, v_opp;
unsigned long rate, v, v_opp, v_min_align;
int ret = -EINVAL;
int j, selector, lut;
v = td->soc->cvb->min_millivolts * 1000;
v = td->soc->min_millivolts * 1000;
lut = find_vdd_map_entry_exact(td, v);
if (lut < 0)
goto out;
td->lut[0] = lut;
td->lut_bottom = 0;
v_min_align = DIV_ROUND_UP(td->soc->min_millivolts * 1000,
td->soc->alignment.step_uv) * td->soc->alignment.step_uv;
for (j = 1, rate = 0; ; rate++) {
struct dev_pm_opp *opp;
@@ -1718,7 +2022,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td, unsigned long v_max)
break;
v_opp = dev_pm_opp_get_voltage(opp);
if (v_opp <= td->soc->cvb->min_millivolts * 1000)
if (v_opp <= v_min_align)
td->dvco_rate_min = dev_pm_opp_get_freq(opp);
dev_pm_opp_put(opp);
@@ -1749,7 +2053,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td, unsigned long v_max)
if (!td->dvco_rate_min)
dev_err(td->dev, "no opp above DFLL minimum voltage %d mV\n",
td->soc->cvb->min_millivolts);
td->soc->min_millivolts);
else {
ret = 0;
for (j = 0; j < td->lut_size; j++)
@@ -2057,12 +2361,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);
+42 -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)) {
@@ -854,6 +864,9 @@ static int tegra124_dfll_fcpu_probe(struct platform_device *pdev)
return PTR_ERR(soc->cvb);
}
soc->tune_high_min_millivolts =
soc->cvb->cpu_dfll_data.tune_high_min_millivolts;
err = tegra_dfll_register(pdev, soc);
if (err < 0) {
tegra_cvb_remove_opp_table(soc->dev, soc->cvb, soc->max_freq);
+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)
+1 -1
View File
@@ -1088,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;
+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 = {
+3 -2
View File
@@ -122,8 +122,9 @@ static void tegra_fuse_print_sku_info(struct tegra_sku_info *tegra_sku_info)
tegra_revision_name[tegra_sku_info->revision],
tegra_sku_info->sku_id, tegra_sku_info->cpu_process_id,
tegra_sku_info->soc_process_id);
pr_debug("Tegra CPU Speedo ID %d, SoC Speedo ID %d\n",
tegra_sku_info->cpu_speedo_id, tegra_sku_info->soc_speedo_id);
pr_info("Tegra CPU Speedo ID %d, SoC Speedo ID %d, GPU Speedo ID %d\n",
tegra_sku_info->cpu_speedo_id, tegra_sku_info->soc_speedo_id,
tegra_sku_info->gpu_speedo_id);
}
static int tegra_fuse_add_lookups(struct tegra_fuse *fuse)