Compare commits

122 Commits
Author SHA1 Message Date
Aaron Kling 81536e184f Bluetooth: btbcm: Add entry for BCM4356A3 UART bluetooth
This patch adds the device ID for the bluetooth chip used in the
Nvidia specific Broadcom BCM4356 PCI-E WiFi / UART BT chip.

Startup log:

  Bluetooth: hci0: BCM: chip id 122
  Bluetooth: hci0: BCM: features 0x0f
  Bluetooth: hci0: BCM4356A3
  Bluetooth: hci0: BCM4356A3 (001.004.009) build 0000
  Bluetooth: hci0: BCM4356A3 'brcm/BCM4356A3.nvidia,p2894-2551-b00.hcd' Patch
  Bluetooth: hci0: BCM: features 0x0f
  Bluetooth: hci0: BCM4356A3 37.4MHz Class 1.5 Nvidia mDarcy-0108
  Bluetooth: hci0: BCM4356A3 (001.004.009) build 0109

Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 18:06:46 -05:00
SylveonDeko 9695c7dbec iio: light: add a driver for the ROHM BH1730 ambient light sensor
- The BH1730FVC on the Erista and OLED boards reports visible and
  infrared light over I2C
- Expose an illuminance channel in lux plus raw visible and infrared
  counts, adjusting the gain automatically, so Android can drive auto
  brightness from it
2026-10-16 18:03:38 -05:00
SylveonDeko 9200398a8e drm/panel: nx-dsi: add DCS backlight and clean up command lists
- Control brightness over DCS (11-bit) through a backlight device on
  panels without a PWM backlight, such as the OLED
- Send display off when the panel is disabled and in the OLED suspend
  list, and display on at the end of its init list, so it no longer
  flashes gray when the screen turns off
- Read the power mode after setting the initial brightness, which waits
  for the panel to take the command before video starts; without it the
  boot animation stayed dark
- Read the 3 byte display ID properly, and treat machines compatible with
  nintendo,aula as the OLED panel
- Use named DCS opcodes and end every command list with a terminator
- Log the display ID once instead of on every screen on
2026-10-16 18:03:38 -05:00
SylveonDeko edb1a77268 drm/panel: nx-dsi: fix the vertical sync width
- The panels use a 1 line vsync with a 10 line front porch and 9 line back
  porch
- vsync_end used a 2 line pulse while vtotal assumed 1, which shrank the
  back porch to 8 lines
2026-10-16 18:03:38 -05:00
SylveonDeko 2e86a8e7d7 drm/tegra: dsi: send panel commands while video is running
- When the video stream is active, queue DCS packets as video-mode command
  packets sent during blanking instead of using host mode, which would
  stall the display
- Wait two frame ends before restoring the registers, so the panel has
  received and applied the command
- Lets the OLED panel change brightness and switch off without stopping
  the display first
2026-10-16 18:03:38 -05:00
SylveonDeko be77b6992d drm/tegra: dsi: reset the host FIFO before every transfer
- Always flush the host FIFO before sending a packet instead of only after
  the status register reports an underflow or overflow
- With the reset limited to error cases the OLED flashed gray when the
  screen turned off; resetting before every transfer stops it
2026-10-16 18:03:38 -05:00
SylveonDeko 7943c58d69 firmware: tegra: bpmp: tell the Tegra210 BPMP to enter SC7 on suspend
- Register a syscore suspend hook on Tegra210 that sends the BPMP its
  enable-suspend request (MRQ 17) as the last step before deep sleep
- Split the atomic transfer into an inner helper so the hook can send the
  request from syscore context, where interrupts are already off
- Without the request the BPMP never arms SC7, so deep sleep cannot work
2026-10-16 18:03:38 -05:00
SylveonDeko 53d6115483 phy: tegra: xusb: add the Tegra210B01 USB3 lane tuning
- Write the Tegra210B01 per-lane UPHY settings into UPHY_MISC_PAD_PX_CTL8
  for every lane used as USB3
- Skip the Tegra210 PLL calibration and DCO values on B01, which has its
  own PLL table and was having it overwritten
- USB3 device mode now links at SuperSpeed on Mariko units instead of
  falling back to USB2
2026-10-16 18:03:38 -05:00
SylveonDeko a649219eac phy: tegra: xusb: track whether the USB2 VBUS supply is enabled
- Remember if this port turned its VBUS regulator on
- Switching to host mode twice no longer enables it a second time, and
  switching to none no longer disables a regulator it never enabled
- Fixes the unbalanced regulator warnings on USB-C role changes
2026-10-16 18:03:37 -05:00
SylveonDeko 566df49d42 usb: typec: bm92txx: fix the debugfs command parsers
- kstrtouint() returns 0 on success, but the cmd and usbhub_dp_sleep
  writers treated anything other than 1 as a syntax error
- Every valid command was rejected, so the debugfs controls never worked
2026-10-16 18:03:37 -05:00
SylveonDeko facb57bae3 usb: typec: bm92txx: keep the alert IRQ masked until its work is done
- The handler masks the IRQ and queues the event work, and the work unmasks
  it only once the controller status has been read
- Without this, a fast USB-C replug re-entered the state machine while it
  was still processing the previous event, so hotplug got stuck
- Unmask right away if the work was already queued, so no alert is lost
2026-10-16 18:03:37 -05:00
tmakin 5cc184ae32 [wip] testing orientation in tegra-dsi 2026-10-16 10:05:20 -05:00
CTCaer 7c63b83f01 soc: tegra: introduce reboot2payload
Some Tegra124 and Tegra21x boards have open-source
bootloaders injected via RCM rather than onboard. These
boards need special reboot handling, which we call
`Reboot2Payload`.

Co-developed-by: Thomas Makin <halorocker89@gmail.com>
Co-developed-by: Ezekiel Bethel <zek@9net.org>
2026-10-16 10:05:20 -05:00
tmakin baccdc9e58 soc: tegra: add support for brom cmds
Tegra bootrom can signal PMIC and other onboard devices to handle
early-boot configuration. Downstream L4T kernel has long supported
this functionality, where commands are specified via device-tree and
can be hooked for power/reset events.

Based on:
- https://gitlab.com/nvidia/nv-tegra/linux-3.10/-/commit/4ac6f24c8988ef8f6d8100f9dceede5a3ff4a2d3
- https://gitlab.com/nvidia/nv-tegra/linux-4.4/-/commit/5ba61fa064fdd66c8e84592e721a5ac0fa78ed6e
- https://github.com/CTCaer/switch-l4t-kernel-4.9/commit/b4f03b6ab671597971bd9fc41482c0b52eb64bfd

Co-developed-by: Laxman Dewangan <ldewangan@nvidia.com>
Co-developed-by: CTCaer <ctcaer@gmail.com>
2026-10-16 10:05:19 -05:00
tmakin 33b21c2d6c soc: tegra: add t21x panic handler
Some t21x bootloaders like cboot read PMC_SCRATCH37 to check if a
reboot was due to a kernel panic. Support this functionality with
a panic notifier. Original implementation relied on single bit 24
but a specific magic was chosen in later improvement to prevent
false positive from random data in scratch register during reboot.

Based on:
- https://gitlab.com/nvidia/nv-tegra/linux-4.9/-/commit/31b412a5fc80ed0fe33f3ad4e7cc779ce66446a2
- https://github.com/CTCaer/switch-l4t-kernel-4.9/commit/b74fee3edf8053b0b954643d3bd065596cee8aca

Co-developed-by: Nat Pettipaw <npettipaw@nvidia.com>
Co-developed-by: CTCaer <ctcaer@gmail.com>
2026-10-16 10:05:18 -05:00
tmakin 4d226a839b stmfts: update touch handling 2026-10-16 10:05:18 -05:00
tmakin 388bf6d873 panel-nx: add drm orientation 2026-10-16 10:05:18 -05:00
Billy Laws edc8773c3a [SQUASH] input: misc: Add support for max77620's onoff block
input: misc: Max77620 ON/OFF Block change to button press to key_sleep for linux.

input: misc: max77620-onoff: Ignore button release interrupt if the accompanying press was reported to userspace

Caused some userspaces to shutdown after wakeup from lp0 sleep if the
button was pressed during sleep and not released till after waking.

max77620-onoff: Refactor driver

- Add `maxim,onoff-keycode` under `onoff` child node to select custom ON/OFF button key code.
- Fix button stack at resume.

max77620-onoff: Correct regmap

max77620-onoff: correct irq priority and names

max77620-onoff: clear pending irq on probe

Change-Id: I033bd7a26a4e59b2508e90b4d9e42d2d52e5c17e
2026-10-16 10:05:17 -05:00
tmakin a52522ec20 stmfts: support FTM4 chips
Some FingerTipS chips use FTM4 variants like Ftm4cd60d

Based loosely on
https://github.com/android-linux-stable/bluecross/blob/android-msm-bluecross-4.9/drivers/input/touchscreen/stm/ftm4_ts.c
and
https://github.com/CTCaer/switch-l4t-kernel-4.9/blob/linux-dev/drivers/input/touchscreen/stm/ftm4_ts.c

Assisted-by: Grok:grok-4.6
2026-10-16 10:05:17 -05:00
Petr Hodina 55d66b816f arm64: dts: qcom: sdm845-google: Add STM FTS touchscreen support
Basic touchscreen connected to second i2c bus.

Signed-off-by: Petr Hodina <petr.hodina@protonmail.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
Co-developed-by: David Heidelberg <david@ixit.cz>
Signed-off-by: David Heidelberg <david@ixit.cz>
2026-10-16 10:05:16 -05:00
David Heidelberg 1c0fce1fc9 Input: stmfts - support FTS5
The FTS support SLPI and AP mode, introduce mode-switch GPIO to switch
between those two. Currently we can handle only full power AP mode, so we
just keep the AP on.

Useful for devices like Pixel 3 (blueline), Pixel 4a (sunfish),
Xiaomi Mi 8 (dipper), and many others.

Based on work of Petr Hodina <petr.hodina@protonmail.com>

Signed-off-by: David Heidelberg <david@ixit.cz>
2026-10-16 10:05:16 -05:00
David Heidelberg 366206868d dt-bindings: input: touchscreen: st,stmfts: Introduce STM FTS5
Introduce more recent STM FTS5 touchscreen support.

Signed-off-by: David Heidelberg <david@ixit.cz>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
2026-10-16 10:05:15 -05:00
David Heidelberg 78f0d0ee79 dt-bindings: input: touchscreen: st,stmfts: Improve example
The touchscreen-size-{x,y} is exact number, the -1 deduction is done on
driver side.

Example now use interrupts-extended and size obviously not deducted by
one.

Signed-off-by: David Heidelberg <david@ixit.cz>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
2026-10-16 10:05:14 -05:00
David Heidelberg 357adbb4b6 Input: stmfts - wait for controller ready after reset
After releasing the reset line stmfts_reset() sleeps a fixed 50 ms and
stmfts_power_on() another 50 ms before the first I2C access.  That is
enough for a warm reset, but when both supplies were really cut during
system suspend the controller boots from cold and can need longer.  If
it does, the first read fails, stmfts_resume() returns an error and the
touchscreen is left powered off with its interrupt disabled.

The controller posts a controller ready event once it has booted, and
the event parser already completes cmd_done on it.  Enable the interrupt
right after releasing reset and wait for that event instead of sleeping,
giving the controller 300 ms, the total budget the vendor driver allows.
Boards without a reset line keep the old timing.

Usually phones such as Pixel 4a and Xiaomi Mi 8 needs longer delay, so
without this change touchscreen stops working.

Fixes: 8a1f9de80e45 ("Input: stmfts - add optional reset GPIO support")
Cc: stable@vger.kernel.org
Co-developed-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: David Heidelberg <david@ixit.cz>
2026-10-16 10:05:14 -05:00
Uwe Kleine-König (The Capable Hub) e79e702f4b Input: Use named initializers for arrays of i2c_device_data
While being less compact, using named initializers allows to more easily
see which members of the structs are assigned which value without having
to lookup the declaration of the struct. And it's also more robust
against changes to the struct definition.

The mentioned robustness is relevant for a planned change to struct
i2c_device_id that replaces .driver_data by an anonymous union.

This patch doesn't modify the compiled arrays, only their representation
in source form benefits. The former was confirmed with x86 and arm64
builds.

Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
Link: https://patch.msgid.link/20260515164848.497608-2-u.kleine-koenig@baylibre.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-16 10:05:13 -05:00
Dmitry Torokhov 385cc5b46a Input: stmfts - fix formatting issues
Fix a few formatting issues reported by checkpatch.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-16 10:05:12 -05:00
Petr Hodina bb56abf25c Input: stmfts - add optional reset GPIO support
Add support for an optional "reset-gpios" property. If present, the
driver drives the reset line high at probe time and releases it during
power-on, after the regulators have been enabled.

Signed-off-by: Petr Hodina <petr.hodina@protonmail.com>
Co-developed-by: David Heidelberg <david@ixit.cz>
Signed-off-by: David Heidelberg <david@ixit.cz>
Link: https://patch.msgid.link/20260409-stmfts5-v4-8-64fe62027db5@ixit.cz
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-16 10:05:12 -05:00
Petr Hodina 374ecd3b9c Input: stmfts - use client to make future code cleaner
Make code cleaner, compiler will optimize it away anyway.

Preparation for FTM5 support, where more steps are needed.

Signed-off-by: Petr Hodina <petr.hodina@protonmail.com>
Signed-off-by: David Heidelberg <david@ixit.cz>
Link: https://patch.msgid.link/20260409-stmfts5-v4-6-64fe62027db5@ixit.cz
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-16 10:05:11 -05:00
David Heidelberg f0054c977e Input: stmfts - disable regulators and disable irq when power on fails
We must power off regulators and ensure that IRQ is disabled when
failing at power on phase. Create stmfts_configure function to limit
use of goto.

Signed-off-by: David Heidelberg <david@ixit.cz>
Link: https://patch.msgid.link/20260409-stmfts5-v4-5-64fe62027db5@ixit.cz
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-16 10:05:11 -05:00
David Heidelberg c9b03f2a90 Input: stmfts - abstract reading information from the firmware
Improves readability and makes splitting power on function in following
commit easier.

Signed-off-by: David Heidelberg <david@ixit.cz>
Link: https://patch.msgid.link/20260409-stmfts5-v4-4-64fe62027db5@ixit.cz
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-16 10:05:10 -05:00
David Heidelberg 5ddd9aea8e Input: stmfts - switch to devm_regulator_bulk_get_const
Switch to devm_regulator_bulk_get_const() to stop setting the supplies
list in probe(), and move the regulator_bulk_data struct in static const.

Signed-off-by: David Heidelberg <david@ixit.cz>
Link: https://patch.msgid.link/20260409-stmfts5-v4-3-64fe62027db5@ixit.cz
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-16 10:05:10 -05:00
David Heidelberg ea452c97f1 Input: stmfts - use dev struct directly
Makes the code better readable and noticably shorter.

Signed-off-by: David Heidelberg <david@ixit.cz>
Link: https://patch.msgid.link/20260409-stmfts5-v4-2-64fe62027db5@ixit.cz
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-16 10:05:10 -05:00
David Heidelberg 7d9c4bbb67 Input: stmfts - fix the MODULE_LICENSE() string
Replace the bogus "GPL v2" with "GPL" as MODULE_LICNSE() string. The
value does not declare the module's exact license, but only lets the
module loader test whether the module is Free Software or not.

See commit bf7fbeeae6 ("module: Cure the MODULE_LICENSE "GPL" vs.
"GPL v2" bogosity") in the details of the issue. The fix is to use
"GPL" for all modules under any variant of the GPL.

Signed-off-by: David Heidelberg <david@ixit.cz>
Link: https://patch.msgid.link/20260409-stmfts5-v4-1-64fe62027db5@ixit.cz
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-16 10:05:09 -05:00
tmakin 33311c67da bm92t: gork assisted minor rework 2026-10-16 10:05:08 -05:00
tmakin 0aaad09bd8 xudc: hax for testing 2026-10-16 10:05:08 -05:00
tmakin 416d5d3002 [UPSTREAM] usb: gadget: tegra-xudc: Fix CNT65 configuration
https://lore.kernel.org/linux-tegra/20260921-tegra-usb-v1-5-74a925a35d82@nvidia.com/
2026-10-16 10:05:07 -05:00
tmakin 0184fed5fc xusb: t210: support utmi pad biasing
Based on t186 driver and downstream:
https://gitlab.com/nvidia/nv-tegra/linux-4.9/-/commit/8d05313ac9fd54a2fc373a0e789390dfa0607726
2026-10-16 10:05:07 -05:00
tmakin 671b02a011 gki hax 2026-10-16 10:05:06 -05:00
Bibhay Ranjan f6e6b92330 pinctrl: t210b01: Add SDMMC2 pinmux support
Add sdmmc2 pinmux support inorder to use
SDMMC2 controller on t210b01 platforms.

Bug 200360711

Change-Id: Ie2d3a20d10325d42dc5dbf601c9da747ff0caa66
Signed-off-by: Bibhay Ranjan <bibhayr@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1593367
Reviewed-on: https://git-master.nvidia.com/r/1648549
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-by: Pavan Kunapuli <pkunapuli@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Ashutosh Jha <ajha@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
2026-10-16 10:05:06 -05:00
tmakin 45accfc973 xusb: tegra210: add needed reg for b01 2026-10-16 10:05:06 -05:00
Peter De Schrijver 0165c547a5 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-10-16 10:05:05 -05:00
Peter De Schrijver 8c790c74be 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-10-16 10:05:04 -05:00
tmakin e750db52c2 soc/tegra: fuse: print speedo IDs on info 2026-10-16 10:05:04 -05:00
tmakin c0a3c258da 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-10-16 10:05:03 -05:00
Alex Frid 507c11e883 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-10-16 10:05:03 -05:00
Alex Frid 8b9573fe47 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-10-16 10:05:03 -05:00
Alex Frid b4d9e4018c 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-10-16 10:05:02 -05:00
tmakin 05d4959aea clk: tegra: add locking support to DFLL
Based on part of https://gitlab.com/nvidia/nv-tegra/linux-4.9/-/commit/4f0b1e6e76f7b0ff8d028c66d34da9f37ca39233
2026-10-16 10:05:01 -05:00
Alex Frid a0a10e68be 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-10-16 10:05:01 -05:00
Vince Hsu 8d9e37d949 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-10-16 10:05:00 -05:00
tmakin 5977d303bf gpio: tegra: deprecate static allocation 2026-10-16 10:05:00 -05:00
tmakin 2970cfd003 tegra210b01: use tegra210b01 pinctrl 2026-10-16 10:04:59 -05:00
Laxman Dewangan 33f0d99b25 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-10-16 10:04:59 -05:00
Maulik Shah 8a32e68a20 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-10-16 10:04:58 -05:00
Runyu Xiao c4170e390f 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-10-16 10:04:58 -05:00
tmakin 8bb394a05c bm92t: convert to typec fwk
note: ai
2026-10-16 10:04:58 -05:00
tmakin 60167df1b5 bm92t fix 2026-10-16 10:04:57 -05:00
tmakin ba4dac12be bm92t: err change 2026-10-16 10:04:57 -05:00
tmakin 3ae6806be3 power: bq24190: add get_current_limit 2026-10-16 10:04:57 -05:00
tmakin d20bb062dd pci: tegra: update lanes if dt incorrect 2026-10-16 10:04:56 -05:00
tmakin 2d503e0fb1 sor: allow selection of alt sor1 tuning 2026-10-16 10:04:56 -05:00
Alexandre Hamamdjian 8d227a6fbb 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-10-16 10:04:56 -05:00
CTCaer dc3314220d 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-10-16 10:04:55 -05:00
azkali 111b681101 regulator: fan52555: add support for fan53528 fan 2026-10-16 10:04:55 -05:00
tmakin 9a5413e9fa t210: assign better mmc clocks 2026-10-16 10:04:55 -05:00
tmakin 1ac0412403 clk changes, test later 2026-10-16 10:04:54 -05:00
Laxman Dewangan b82ce7b0d8 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-10-16 10:04:54 -05:00
tmakin 42bdbbe5fc clk: tegra210: update pll_c4 parameters 2026-10-16 10:04:54 -05:00
tmakin f90a6cfcfc ftm4: compile fixes 2026-10-16 10:04:53 -05:00
Alvin Park f9e0107d8c 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-10-16 10:04:52 -05:00
azkali ff6546fecc touchscreen: stm: forward port ftm4 touchscreen driver from L4T 2026-10-16 10:04:52 -05:00
tmakin 69ea5d3e76 dts: misc updates 2026-10-16 10:04:51 -05:00
tmakin 3a4823d9a4 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-10-16 10:04:51 -05:00
Vidya Sagar e139717fa0 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-10-16 10:04:51 -05:00
Manikanta Maddireddy b3464e207b 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-10-16 10:04:51 -05:00
Manikanta Maddireddy d4e173764d 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-10-16 10:04:50 -05:00
Manikanta Maddireddy a580b0b407 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-10-16 10:04:50 -05:00
Manikanta Maddireddy 048038800f 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-10-16 10:04:50 -05:00
Vidya Sagar 6237faf30d 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-10-16 10:04:50 -05:00
Vidya Sagar 1b54bcb738 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-10-16 10:04:49 -05:00
Manikanta Maddireddy f6569aea67 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-10-16 10:04:49 -05:00
Vidya Sagar 7e02b98660 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-10-16 10:04:49 -05:00
Manikanta Maddireddy cece5d6901 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-10-16 10:04:49 -05:00
Manikanta Maddireddy 56976e04c8 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-10-16 10:04:48 -05:00
tmakin d9df5126de [WAR] core: don't loop 2026-10-16 10:04:48 -05:00
tmakin 1396d339da 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-10-16 10:04:48 -05:00
tmakin 3195473247 tegra210b01: do not enable venc
Signed-off-by: Thomas Makin <halorocker89@gmail.com>
2026-10-16 10:04:48 -05:00
tmakin 04296c2cff tegra-drm: add t210b01 dsi support
Signed-off-by: Thomas Makin <halorocker89@gmail.com>
2026-10-16 10:04:48 -05:00
tmakin fafe37755a enable max77812
Signed-off-by: Thomas Makin <halorocker89@gmail.com>
2026-10-16 10:04:47 -05:00
tmakin 3f5f6163a4 panel-nx: match jdi panel driver style
squash later
2026-10-16 10:04:47 -05:00
azkali 009888ec9b 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-10-16 10:04:47 -05:00
Laxman Dewangan b71d035063 regulator: core: add API to get min/max voltage for rails
Add API to get min/max rail voltage configured from platform for
given rails. This will help to set the pad voltage based on platform
specific power tree.

bug 200083043

Change-Id: I054734ca2a25b5c830525e27ab22e43534f67351
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-on: http://git-master/r/712001
(cherry picked from commit c0d1de0da091132d037e1bb32f2ee09b5c00369b)
Reviewed-on: http://git-master/r/1119836
Signed-off-by: Thomas Makin <halorocker89@gmail.com>
2026-10-16 10:04:47 -05:00
Alex Frid 723687b1e0 clk: Add parent change notifications
Added parent change notifications to be used when drivers behavior
depends on physical nature of the parent, not just clock rate it
supplies (e.g., selection of Tegra DFLL as CPU clock source changes
mechanism of voltage control even if the clock rate stays the same
as on PLL).

Bug 200269751

Change-Id: I617c94927ef437caf240efd91497b49ad6f5c39d
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1573111
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: svccoveritychecker <svccoveritychecker@nvidia.com>
Reviewed-by: Peter De Schrijver <pdeschrijver@nvidia.com>
Tested-by: Peter De Schrijver <pdeschrijver@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
Reviewed-by: Timo Alho <talho@nvidia.com>
Signed-off-by: Thomas Makin <halorocker89@gmail.com>
2026-10-16 10:04:47 -05:00
Alex Frid d2796f7568 clk: tegra: Add subtree change notifications
Added PRE_SUBTREE_CHANGE and POST_SUBTREE_CHANGE that called before
and after rate change is propagated down the sub-tree rooted in clk.
This would allow children to be aware that next set rate operation
is triggered by downward rate propagation, rather than direct set rate
on a child clock.

Bug 200267979

Change-Id: I6f2acbeca7cead0ecd385dcb2e58ced32448e998
Signed-off-by: Alex Frid <afrid@nvidia.com>
Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
(cherry picked from commit 62f0d763fcb6c9d5bd9a373d22d802503ab0fdc5)
Reviewed-on: https://git-master.nvidia.com/r/1558143
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Timo Alho <talho@nvidia.com>
Signed-off-by: Thomas Makin <halorocker89@gmail.com>
2026-10-16 10:04:46 -05:00
tmakin f273a9844a arm64: t210b01: enable max77812
Signed-off-by: Thomas Makin <halorocker89@gmail.com>
2026-10-16 10:04:46 -05:00
tmakin 40623ab505 arm64: t210b01: add max77620 support
Signed-off-by: Thomas Makin <halorocker89@gmail.com>
2026-10-16 10:04:46 -05:00
tmakin d6cfe43b69 arm64: t210: add initial support for nx
The Nintendo Switch is a video game console based on the
Tegra X1 (T210) and X1+ (T210B01).

Signed-off-by: Thomas Makin <halorocker89@gmail.com>
2026-10-16 10:04:46 -05:00
Aaron Kling 1b168e5b8c ANDROID: GKI: Export Nvidia dts'
Change-Id: I6e882d22300339288fa4f40d07faf0d4e9f413b0
2026-10-16 10:04:46 -05:00
Keir Fraser 973d5536d3 Revert "Revert "ANDROID: Support CONFIG_CMDLINE_EXTEND""
This reverts commit 68cf9989a1 and
reinstates long-standing Android command-line parsing behaviour with
CONFIG_CMDLINE_EXTEND.

Bug: 357781595
Bug: 120440972
Bug: 278749606
Signed-off-by: Keir Fraser <keirf@google.com>
Change-Id: Iac374066a980d38a1dadf1fa13fff16f48bd44c5
2026-10-16 10:04:45 -05:00
Aaron Kling 2753300b4e arm64: tegra: Add support for NVIDIA Shield TV 2019
Add initial device-tree support for NVIDIA Shield TV 2019 (a.k.a Sif)
based on the Tegra210B01 SoC with 2 GiB of LPDDR4 RAM.

Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:45 -05:00
Aaron Kling ba2c386d76 arm64: tegra: Enable HDA controller on P2894
The HDA controller can be used for audio playback over HDMI.

Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:45 -05:00
Aaron Kling 5af98305bc arm64: tegra: Enable HDMI on P2894
Add regulators and enable the host1x nodes necessary to attain video
output via hdmi.

Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:45 -05:00
Aaron Kling 47176bb1fa arm64: tegra: Enable DFLL clock on P2894
Add pinmux for PWM-based DFLL support.

Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:45 -05:00
Aaron Kling 0e1c162428 arm64: tegra: Enable PWM fan on P2894
This is based on 6f78a94, which enabled added the fan and thermal zones
for the Jetson Nano Devkit. The fan and thermal characteristics of the
two devices are similar, so using the same configuration.

Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:45 -05:00
Aaron Kling bc4ef68f74 arm64: tegra: Add Wifi node for Tegra210B01 P2894
The Tegra210B01 p2894 product has a BCM4356 module with wifi on pcie.
Enable the pcie port it is plugged into add a node for the wifi card,
and add a gpio-hog to enable power to the card. Attempts to tie the gpio
to power sequencing has not worked.

Change-Id: I7236fa1a3eabeb7fbb5b94af05f951b922955a38
Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:45 -05:00
Aaron Kling 918c526413 arm64: tegra: Add Wifi node for Tegra210 P2894
The Tegra210 p2894 product has a BCM4354 module with wifi on sdio.

Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:44 -05:00
Aaron Kling c508b718dd arm64: tegra: Wire up Bluetooth for P2894
The p2894 product contains a BCM4354 module with bluetooth on uart.

Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:44 -05:00
Aaron Kling 42d74b5aba arm64: tegra: Enable PCIe Ethernet on P2894
The P2894 product has a Realtek r6168 PCIe ethernet adapter. Enable the
pcie port the adapter is attached to.

Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:44 -05:00
Aaron Kling f00ff820f7 arm64: tegra: Enable XUSB controller on P2894
Enable the XUSB controller on P2894. One of the USB 3.0 lanes goes to a
switchable USB-A port, while the second USB 3.0 lane supports the normal
USB-A port.

The padctl layout is different between the Tegra210 and Tegra210B01
variants. The latter is overridden in the device specific dts.

Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:44 -05:00
Aaron Kling 4055e1cac3 arm64: tegra: Enable gpu on P2894
This adds the gpu regulator and enables the gpu node.

Change-Id: I7d9580967edf9af4c31d500608f880eeb9d1e0b5
Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:44 -05:00
Aaron Kling c3d883fb2a arm64: tegra: Add support for NVIDIA Shield TV Pro 2019
Add initial device-tree support for NVIDIA Shield TV Pro 2019 (a.k.a
MDarcy) based up the Tegra210B01 SoC with 3 GiB of LPDDR4 RAM.

This device is very similar to the Tegra210 p2894 device, so this shares
the p2894 dtsi with a few overrides to the pinmux and power tree.

Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:43 -05:00
Aaron Kling 733af3c200 arm64: tegra: tegra210-p2894: Move arch dtsi include
In preparation for support of the Tegra210B01 p2894 variant, move the
arch dtsi include to the Tegra210 revision specific dts. This will allow
the p2894 dtsi to be shared across archs, as the variants share a
majority of the hardware design.

Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:43 -05:00
Aaron Kling 492f318ca8 arm64: tegra: Add Tegra210B01 support
Also known as Tegra X1+, the Tegra210B01 has higher CPU and GPU clocks
than the original Tegra210.

Add a SoC-level device tree file that describes most of the hardware
available on the SoC. This is derived from the Tegra210 dtsi, as they
share a lot.

Co-developed-by: Thomas Makin <halorocker89@gmail.com>
Signed-off-by: Thomas Makin <halorocker89@gmail.com>
Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:43 -05:00
Aaron Kling a241deda10 arm64: tegra: Add BPMP node for Tegra210
The Tegra210 soc supports bpmp offload for power management among other
things. This was considered insecure partway through the soc's lifecycle
and support was removed in the bootloader. However, Tegra210B01 returned
to using the bpmp. Plus old bootloaders on the original Tegra210 still
work with the existing driver. So add the node to the common Tegra210
soc dtsi, but disabled by default.

Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:43 -05:00
tmakin 2a5099fdb3 mmc: sdhci-tegra: add support for Tegra210B01
Tegra210B01 is basically the same as Tegra210 but uses different tap
delays.

Signed-off-by: Thomas Makin <halorocker89@gmail.com>
Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:43 -05:00
tmakin 7b3ff6397c pci: tegra: add t210b01 support
This commit also fixes configuration checks

Signed-off-by: Thomas Makin <halorocker89@gmail.com>
Co-developed-by: Aaron Kling <webgeek1234@gmail.com>
Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:43 -05:00
Aaron Kling 67057dade8 usb: gadget: tegra-xudc: Add Tegra210B01 Support
It doesn't need some of the workarounds that the original Tegra210 does.

Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:43 -05:00
Aaron Kling 58e4c5446f usb: xhci: tegra: Add Tegra210B01 support
This uses a different firmware, but is otherwise compatible with
Tegra210.

Co-developed-by: Thomas Makin <halorocker89@gmail.com>
Signed-off-by: Thomas Makin <halorocker89@gmail.com>
Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:43 -05:00
Aaron Kling 8cf303ed56 phy: tegra: xusb: Add Tegra201B01 Support
This covers a few differences:
* Lanes compared to the original Tegra210
* The soc has a different clock driver and thus callbacks
* The soc has an extra clock for uphy management

Co-developed-by: Thomas Makin <halorocker89@gmail.com>
Change-Id: I455358267b3a700461caa8f9f9963d33596dd189
Signed-off-by: Thomas Makin <halorocker89@gmail.com>
Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:42 -05:00
tmakin 72d27b6240 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-10-16 10:04:42 -05:00
Alexandre Hamamdjian 123ae32e8b soc/tegra: pmc: Add Tegra210B01 support
The PMC in Tegra210B01 is very similar to the one in the original
Tegra210, but has a few powergate differences. Specifically sata and ve2
are removed.

Signed-off-by: Alexandre Hamamdjian <azkali.limited@gmail.com>
Co-developed-by: Thomas Makin <halorocker89@gmail.com>
Signed-off-by: Thomas Makin <halorocker89@gmail.com>
Co-developed-by: Aaron Kling <webgeek1234@gmail.com>
Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
2026-10-16 10:04:42 -05:00
Thomas Makin 3bbfabafa3 drm/nouveau: add gm20b variant for t210b01
Support a revision of the GM20B chipset used in the Tegra X1+
(t210b01) chip.

Changes:
- Support GM20B variant ID 0x12e
- Support GPCPLL revision C1
- Differentiate DVFS parameters between B1 (t210) and C1 (t210b01)
- Add pstates for t210b01 (start with NA table for now)

Verified on NVIDIA Shield Pro 2019.

Co-developed-by: Aaron Kling <webgeek1234@gmail.com>
Signed-off-by: Thomas Makin <tmakin@nvidia.com>
2026-10-16 10:04:37 -05:00
174 changed files with 14041 additions and 683 deletions

No files matched your search

+11
View File
@@ -1706,6 +1706,17 @@ devicetree_library(
deps = ["//common:dtc_includes_aarch64"],
)
devicetree_library(
name = "all_nvidia_dts",
hdrs = glob([
"arch/arm64/boot/dts/nvidia/*.dtsi",
"arch/arm64/boot/dts/nvidia/*.dts",
]),
includes = ["arch/arm64/boot/dts/nvidia"],
visibility = ["//vendor:__subpackages__"],
deps = [":dtc_includes_aarch64"],
)
_KSELFTEST_DIR = "testcases/selftests"
_KSELFTEST_COPTS = [
@@ -14,12 +14,11 @@ description:
functionality. Along with it the user can enable the touchkey which can work
as a basic HOME and BACK key for phones.
allOf:
- $ref: touchscreen.yaml#
properties:
compatible:
const: st,stmfts
enum:
- st,stmfts
- st,stmfts5
reg:
maxItems: 1
@@ -40,6 +39,14 @@ properties:
vdd-supply:
description: Power supply
mode-switch-gpios:
description: Optional switch between touchscreen SLPI and AP mode.
maxItems: 1
reset-gpios:
description: Reset GPIO (active-low)
maxItems: 1
required:
- compatible
- reg
@@ -47,6 +54,17 @@ required:
- interrupts
- vdd-supply
allOf:
- $ref: touchscreen.yaml#
- if:
not:
properties:
compatible:
const: st,stmfts5
then:
properties:
mode-switch-gpios: false
unevaluatedProperties: false
examples:
@@ -60,10 +78,9 @@ examples:
touchscreen@49 {
compatible = "st,stmfts";
reg = <0x49>;
interrupt-parent = <&gpa1>;
interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
touchscreen-size-x = <1599>;
touchscreen-size-y = <2559>;
interrupts-extended = <&gpa1 1 IRQ_TYPE_LEVEL_LOW>;
touchscreen-size-x = <1600>;
touchscreen-size-y = <2560>;
touch-key-connected;
avdd-supply = <&ldo30_reg>;
vdd-supply = <&ldo31_reg>;
@@ -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
@@ -23335,6 +23335,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
+6
View File
@@ -2453,6 +2453,12 @@ config CMDLINE_FROM_BOOTLOADER
the boot loader doesn't provide any, the default kernel command
string provided in CMDLINE will be used.
config CMDLINE_EXTEND
bool "Extend bootloader kernel arguments"
help
The command-line arguments provided by the boot loader will be
appended to the default kernel command string.
config CMDLINE_FORCE
bool "Always use the default kernel command string"
help
+7
View File
@@ -30,6 +30,13 @@ dtb-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210-p3450-0000.dtb
dtb-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210-p3541-0000.dtb
dtb-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210-smaug.dtb
dtb-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210-p2894-0050-a08.dtb
dtb-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210b01-p2894-2551-b00.dtb
dtb-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210b01-p3425-0050-a04.dtb
dtb-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210-odin.dtb
dtb-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210b01-p2894-0050-a08.dtb
dtb-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210b01-odin.dtb
dtb-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210b01-vali.dtb
dtb-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210b01-fric.dtb
dtb-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186-p2771-0000.dtb
dtb-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186-p3509-0000+p3636-0001.dtb
dtb-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra194-p2972-0000.dtb
@@ -1,9 +1,29 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
#include "tegra210.dtsi"
#include "tegra210-p2894.dtsi"
/ {
model = "NVIDIA Shield TV";
compatible = "nvidia,p2894-0050-a08", "nvidia,darcy", "nvidia,tegra210";
mmc@700b0200 {
status = "okay";
bus-width = <4>;
non-removable;
power-gpios = <&gpio TEGRA_GPIO(H, 0) GPIO_ACTIVE_HIGH>;
vqmmc-supply = <&max77620_sd3>;
vmmc-supply = <&vdd_3v3>;
#address-cells = <1>;
#size-cells = <0>;
wifi@1 {
compatible = "brcm,bcm4354-fmac", "brcm,bcm4329-fmac";
reg = <1>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(H, 2) IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "host-wake";
};
};
};
+296 -1
View File
@@ -4,11 +4,11 @@
#include <dt-bindings/input/gpio-keys.h>
#include <dt-bindings/mfd/max77620.h>
#include <dt-bindings/pinctrl/pinctrl-tegra.h>
#include "tegra210.dtsi"
/ {
aliases {
serial0 = &uarta;
serial3 = &uartd;
};
chosen {
@@ -21,6 +21,43 @@
reg = <0x0 0x80000000 0x0 0xc0000000>;
};
pcie@1003000 {
status = "okay";
hvddio-pex-supply = <&max77620_sd3>;
dvddio-pex-supply = <&max77620_ldo1>;
vddio-pex-ctl-supply = <&max77620_sd3>;
pci@2,0 {
phys = <&{/padctl@7009f000/pads/pcie/lanes/pcie-0}>;
phy-names = "pcie-0";
status = "okay";
};
};
host1x@50000000 {
dpaux@54040000 {
status = "okay";
};
sor@54580000 {
status = "okay";
avdd-io-hdmi-dp-supply = <&max77620_ldo8>;
vdd-hdmi-dp-pll-supply = <&max77620_sd3>;
hdmi-supply = <&vdd_hdmi>;
nvidia,ddc-i2c-bus = <&hdmi_ddc>;
nvidia,hpd-gpio = <&gpio TEGRA_GPIO(CC, 1)
GPIO_ACTIVE_LOW>;
};
};
gpu@57000000 {
vdd-supply = <&vdd_gpu>;
status = "okay";
};
pinmux: pinmux@700008d4 {
status = "okay";
pinctrl-names = "boot";
@@ -1318,6 +1355,20 @@
nvidia,open-drain = <TEGRA_PIN_DISABLE>;
};
};
dvfs_pwm_active_state: pinmux-dvfs-pwm-active {
dvfs_pwm_pbb1 {
nvidia,pins = "dvfs_pwm_pbb1";
nvidia,tristate = <TEGRA_PIN_DISABLE>;
};
};
dvfs_pwm_inactive_state: pinmux-dvfs-pwm-inactive {
dvfs_pwm_pbb1 {
nvidia,pins = "dvfs_pwm_pbb1";
nvidia,tristate = <TEGRA_PIN_ENABLE>;
};
};
};
serial@70006000 {
@@ -1326,6 +1377,26 @@
status = "okay";
};
pwm@7000a000 {
status = "okay";
};
serial@70006300 {
/delete-property/ reg-shift;
status = "okay";
compatible = "nvidia,tegra30-hsuart";
reset-names = "serial";
bluetooth {
compatible = "brcm,bcm43540-bt";
device-wakeup-gpios = <&gpio TEGRA_GPIO(H, 3) GPIO_ACTIVE_HIGH>;
shutdown-gpios = <&gpio TEGRA_GPIO(H, 4) GPIO_ACTIVE_HIGH>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(H, 5) IRQ_TYPE_LEVEL_LOW>;
interrupt-names = "host-wakeup";
};
};
i2c@7000d000 {
status = "okay";
clock-frequency = <400000>;
@@ -1570,6 +1641,12 @@
};
};
/* HDMI DDC */
hdmi_ddc: i2c@7000c700 {
status = "okay";
clock-frequency = <100000>;
};
pmc@7000e400 {
nvidia,invert-interrupt;
nvidia,suspend-mode = <0>;
@@ -1582,12 +1659,154 @@
status = "okay";
};
hda@70030000 {
status = "okay";
nvidia,model = "NVIDIA SHIELD TV HDA";
};
usb@70090000 {
phys = <&{/padctl@7009f000/pads/usb2/lanes/usb2-0}>,
<&{/padctl@7009f000/pads/usb2/lanes/usb2-2}>,
<&{/padctl@7009f000/pads/pcie/lanes/pcie-6}>,
<&{/padctl@7009f000/pads/pcie/lanes/pcie-5}>;
phy-names = "usb2-0", "usb2-2", "usb3-0", "usb3-1";
dvddio-pex-supply = <&max77620_ldo1>;
hvddio-pex-supply = <&max77620_sd3>;
avdd-usb-supply = <&vdd_3v3>;
status = "okay";
};
padctl@7009f000 {
status = "okay";
avdd-pll-utmip-supply = <&max77620_sd3>;
avdd-pll-uerefe-supply = <&max77620_ldo7>;
dvdd-pex-pll-supply = <&max77620_ldo1>;
hvdd-pex-pll-e-supply = <&max77620_sd3>;
pads {
usb2 {
status = "okay";
lanes {
usb2-0 {
nvidia,function = "xusb";
status = "okay";
};
usb2-2 {
nvidia,function = "xusb";
status = "okay";
};
};
};
pcie {
status = "okay";
lanes {
pcie-0 {
nvidia,function = "pcie-x1";
status = "okay";
};
pcie-1 {
nvidia,function = "pcie-x4";
status = "okay";
};
pcie-2 {
nvidia,function = "pcie-x4";
status = "okay";
};
pcie-3 {
nvidia,function = "pcie-x4";
status = "okay";
};
pcie-4 {
nvidia,function = "pcie-x4";
status = "okay";
};
pcie-5 {
nvidia,function = "usb3-ss";
status = "okay";
};
pcie-6 {
nvidia,function = "usb3-ss";
status = "okay";
};
};
};
};
ports {
usb2-0 {
status = "okay";
vbus-supply = <&usb_vbus1>;
usb-role-switch;
role-switch-default-mode = "peripheral";
mode = "otg";
};
usb2-2 {
status = "okay";
vbus-supply = <&usb_vbus2>;
mode = "host";
};
usb3-0 {
nvidia,usb2-companion = <0>;
status = "okay";
};
usb3-1 {
nvidia,usb2-companion = <2>;
status = "okay";
};
};
};
mmc@700b0600 {
bus-width = <8>;
non-removable;
status = "okay";
};
usb@700d0000 {
status = "okay";
phys = <&{/padctl@7009f000/pads/usb2/lanes/usb2-0}>,
<&{/padctl@7009f000/pads/pcie/lanes/pcie-6}>;
phy-names = "usb2-0", "usb3-0";
avddio-usb-supply = <&max77620_ldo1>;
hvdd-usb-supply = <&vdd_3v3>;
};
clock@70110000 {
status = "okay";
nvidia,cf = <6>;
nvidia,ci = <0>;
nvidia,cg = <2>;
nvidia,droop-ctrl = <0x00000f00>;
nvidia,force-mode = <1>;
nvidia,sample-rate = <25000>;
nvidia,pwm-min-microvolts = <708000>;
nvidia,pwm-period-nanoseconds = <2500>; /* 2.5us */
nvidia,pwm-to-pmic;
nvidia,pwm-tristate-microvolts = <1000000>;
nvidia,pwm-voltage-step-microvolts = <19200>;
pinctrl-names = "dvfs_pwm_enable", "dvfs_pwm_disable";
pinctrl-0 = <&dvfs_pwm_active_state>;
pinctrl-1 = <&dvfs_pwm_inactive_state>;
};
clk32k_in: clock-32k {
compatible = "fixed-clock";
clock-frequency = <32768>;
@@ -1637,6 +1856,18 @@
method = "smc";
};
fan: pwm-fan {
compatible = "pwm-fan";
pwms = <&pwm 3 65536>;
fan-supply = <&vdd_fan>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(G, 0) IRQ_TYPE_EDGE_RISING>;
/* cooling level (0, 1, 2, 3) - pwm inverted */
cooling-levels = <255 128 64 0>;
#cooling-cells = <2>;
};
battery_reg: regulator-vdd-ac-bat {
compatible = "regulator-fixed";
regulator-name = "vdd-ac-bat";
@@ -1831,4 +2062,68 @@
enable-active-high;
gpio-open-drain;
};
vdd_gpu: regulator-vdd-gpu {
compatible = "pwm-regulator";
pwms = <&pwm 1 8000>;
regulator-name = "VDD_GPU";
regulator-min-microvolt = <710000>;
regulator-max-microvolt = <1320000>;
enable-gpios = <&pmic 6 GPIO_ACTIVE_HIGH>;
regulator-ramp-delay = <80>;
regulator-enable-ramp-delay = <2000>;
regulator-settling-time-us = <160>;
};
thermal-zones {
cpu-thermal {
trips {
cpu_trip_critical: critical {
temperature = <96500>;
hysteresis = <0>;
type = "critical";
};
cpu_trip_hot: hot {
temperature = <70000>;
hysteresis = <2000>;
type = "hot";
};
cpu_trip_active: active {
temperature = <50000>;
hysteresis = <2000>;
type = "active";
};
cpu_trip_passive: passive {
temperature = <30000>;
hysteresis = <2000>;
type = "passive";
};
};
cooling-maps {
map0 {
cooling-device = <&fan 3 3>;
trip = <&cpu_trip_critical>;
};
map1 {
cooling-device = <&fan 2 2>;
trip = <&cpu_trip_hot>;
};
map2 {
cooling-device = <&fan 1 1>;
trip = <&cpu_trip_active>;
};
map3 {
cooling-device = <&fan 0 0>;
trip = <&cpu_trip_passive>;
};
};
};
};
};
+20 -7
View File
@@ -1018,6 +1018,21 @@
status = "disabled";
};
bpmp: bpmp@70016000 {
compatible = "nvidia,tegra210-bpmp";
reg = <0x0 0x70016000 0x0 0x2000
0x0 0x60001000 0x0 0x1000>;
status = "disabled";
interrupts = <GIC_SPI 6 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 4 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "tx", "rx";
iommus = <&mc TEGRA_SWGROUP_AVPC>;
#clock-cells = <1>;
};
mc: memory-controller@70019000 {
compatible = "nvidia,tegra210-mc";
reg = <0x0 0x70019000 0x0 0x1000>;
@@ -1295,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";
};
@@ -1362,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";
@@ -0,0 +1,108 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
#include "tegra210b01.dtsi"
#include "tegra210-p2894.dtsi"
/ {
model = "NVIDIA Shield TV Pro 2019";
compatible = "nvidia,p2894-2551-b00", "nvidia,darcy", "nvidia,tegra210b01",
"nvidia,tegra210";
pcie@1003000 {
pci@1,0 {
phys = <&{/padctl@7009f000/pads/pcie/lanes/pcie-3}>,
<&{/padctl@7009f000/pads/pcie/lanes/pcie-2}>;
phy-names = "pcie-0", "pcie-1";
status = "okay";
wifi@0,0 {
compatible = "brcm,bcm4356-fmac", "brcm,bcm4329-fmac";
};
};
};
gpio@6000d000 {
wlreg-hog {
gpio-hog;
gpios = <TEGRA_GPIO(H, 0) GPIO_ACTIVE_HIGH>;
output-high;
line-name = "wlreg_on";
};
};
pinmux@700008d4 {
pinmux {
pex_l0_rst_n_pa0 {
nvidia,function = "pe0";
nvidia,pull = <TEGRA_PIN_PULL_UP>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
};
pex_l0_clkreq_n_pa1 {
nvidia,pull = <TEGRA_PIN_PULL_UP>;
nvidia,io-hv = <TEGRA_PIN_DISABLE>;
};
pex_wake_n_pa2 {
nvidia,pull = <TEGRA_PIN_PULL_UP>;
nvidia,tristate = <TEGRA_PIN_ENABLE>;
nvidia,io-hv = <TEGRA_PIN_DISABLE>;
};
wifi_wake_ap_ph2 {
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
};
pz1 {
nvidia,pull = <TEGRA_PIN_PULL_UP>;
};
};
};
i2c@7000d000 {
pmic@3c {
regulators {
sd2 {
regulator-min-microvolt = <1350000>;
regulator-max-microvolt = <1350000>;
};
};
};
};
usb@70090000 {
phys = <&{/padctl@7009f000/pads/usb2/lanes/usb2-0}>,
<&{/padctl@7009f000/pads/usb2/lanes/usb2-2}>,
<&{/padctl@7009f000/pads/pcie/lanes/pcie-5}>,
<&{/padctl@7009f000/pads/pcie/lanes/pcie-4}>;
phy-names = "usb2-0", "usb2-2", "usb3-0", "usb3-1";
dvddio-pex-supply = <&max77620_ldo1>;
hvddio-pex-supply = <&max77620_sd3>;
avdd-usb-supply = <&vdd_3v3>;
status = "okay";
};
padctl@7009f000 {
pads {
pcie {
lanes {
pcie-1 {
nvidia,function = "usb3-ss";
};
pcie-4 {
nvidia,function = "usb3-ss";
};
pcie-6 {
/delete-property/ nvidia,function;
status = "disabled";
};
};
};
};
};
usb@700d0000 {
phys = <&{/padctl@7009f000/pads/usb2/lanes/usb2-0}>,
<&{/padctl@7009f000/pads/pcie/lanes/pcie-5}>;
};
};
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,142 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
#include "tegra210b01-nx.dtsi"
/ {
model = "Nintendo Switch Lite";
compatible = "nvidia,vali", "nintendo,hoag", "nintendo,nx", "nvidia,tegra210b01", "nvidia,tegra210";
/* Joycon/Fan power (usb) */
v_vdd50_b: v-vdd50-b {
status = "disabled"; /* Only enabled on Odin/Modin */
};
en_vdd_jcl_chgr: left-joycon-charger {
status = "disabled"; /* Only enabled on Odin/Modin/Fric */
};
en_vdd_jcr_chgr: right-joycon-charger {
status = "disabled"; /* Only enabled on Odin/Modin/Fric */
};
spi@7000da00 {
status = "disabled"; /* Disabled for Vali since Sio uses it */
};
/* Right Joycon */
serial@70006040 {
status = "disabled";
joyconr {
status = "disabled";
};
};
/* Left Joycon / Sio */
serial@70006200 {
status = "okay";
/delete-property/ nvidia,invert-txd;
/delete-property/ nvidia,invert-rts;
joyconl {
status = "disabled";
};
sio {
status = "okay";
};
};
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 {
/* Vali: Powers LDO 2V8 for Sio VDD
* Powers LDO 1V8 for I2C1 VDDQ and ALC5639.
*/
ldo8 {
regulator-name = "vdd-i2c1";
regulator-max-microvolt = <2800000>;
regulator-always-on;
regulator-boot-on;
};
};
};
};
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>;
};
};
+184
View File
@@ -0,0 +1,184 @@
// SPDX-License-Identifier: GPL-2.0
#include "tegra210.dtsi"
/delete-node/ &emc;
/delete-node/ &{/sata@70020000};
/ {
compatible = "nvidia,tegra210b01", "nvidia,tegra210";
pcie@1003000 {
compatible = "nvidia,tegra210b01-pcie";
/delete-property/ pinctrl-names;
/delete-property/ pinctrl-0;
/delete-property/ pinctrl-1;
};
host1x@50000000 {
/delete-node/ sor@54540000;
/delete-node/ dpaux@545c0000;
/delete-node/ vi@54080000;
/delete-node/ i2c@546c0000;
dc@54200000 {
nvidia,outputs = <&dsia &dsib &sor1>;
};
dc@54240000 {
nvidia,outputs = <&dsia &dsib &sor1>;
};
dsi@54300000 {
compatible = "nvidia,tegra210b01-dsi";
};
dsi@54400000 {
compatible = "nvidia,tegra210b01-dsi";
};
};
clock@60006000 {
compatible = "nvidia,tegra210b01-car";
};
actmon@6000c800 {
clocks = <&tegra_car TEGRA210_CLK_ACTMON>,
<&bpmp 0>;
};
pinmux@700008d4 {
compatible = "nvidia,tegra210b01-pinmux";
pinmux-sdmmc1-1v8-drv {
sdmmc1 {
nvidia,pull-down-strength = <0x8>;
nvidia,pull-up-strength = <0x8>;
};
};
pinmux-sdmmc3-1v8-drv {
sdmmc3 {
nvidia,pull-down-strength = <0x8>;
nvidia,pull-up-strength = <0x8>;
};
};
};
i2c@7000d100 {
/delete-property/ pinctrl-0;
/delete-property/ pinctrl-1;
/delete-property/ pinctrl-names;
};
memory-controller@70019000 {
#address-cells = <2>;
#size-cells = <2>;
emc: external-memory-controller@7001b000 {
compatible = "nvidia,tegra186-emc";
reg = <0x0 0x7001b000 0x0 0x1000>;
clocks = <&bpmp 0>;
clock-names = "emc";
interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
#cooling-cells = <2>;
#interconnect-cells = <0>;
nvidia,bpmp = <&bpmp>;
};
};
mmc@700b0000 {
compatible = "nvidia,tegra210b01-sdhci";
nvidia,pad-autocal-pull-up-offset-3v3 = <0x06>;
nvidia,pad-autocal-pull-down-offset-3v3 = <0x06>;
nvidia,pad-autocal-pull-up-offset-1v8 = <0x06>;
nvidia,pad-autocal-pull-down-offset-1v8 = <0x06>;
nvidia,default-tap = <0xb>;
nvidia,default-trim = <0xe>;
assigned-clocks = <&tegra_car TEGRA210_CLK_SDMMC1>,
<&tegra_car TEGRA210_CLK_PLL_C4_OUT2>;
assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_C4_OUT2>;
};
mmc@700b0200 {
compatible = "nvidia,tegra210b01-sdhci";
nvidia,pad-autocal-pull-up-offset-1v8 = <0x06>;
nvidia,pad-autocal-pull-down-offset-1v8 = <0x06>;
nvidia,default-tap = <0x8>;
nvidia,default-trim = <0xd>;
};
mmc@700b0400 {
compatible = "nvidia,tegra210b01-sdhci";
nvidia,pad-autocal-pull-up-offset-3v3 = <0x06>;
nvidia,pad-autocal-pull-down-offset-3v3 = <0x06>;
nvidia,pad-autocal-pull-up-offset-1v8 = <0x06>;
nvidia,pad-autocal-pull-down-offset-1v8 = <0x06>;
nvidia,default-tap = <0xb>;
nvidia,default-trim = <0x12>;
};
mmc@700b0600 {
compatible = "nvidia,tegra210b01-sdhci";
nvidia,pad-autocal-pull-up-offset-1v8 = <0x06>;
nvidia,pad-autocal-pull-down-offset-1v8 = <0x06>;
nvidia,default-tap = <0x9>;
nvidia,default-trim = <0xd>;
assigned-clocks = <&tegra_car TEGRA210_CLK_SDMMC4>,
<&tegra_car TEGRA210_CLK_PLL_C4_OUT2>;
assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_C4_OUT2>;
assigned-clock-rates = <199680000>, <199680000>;
};
/* Tegra210B01 has MBIST patched and is missing VI unit */
pmc@7000e400 {
compatible = "nvidia,tegra210b01-pmc";
powergates {
/delete-node/ venc;
};
};
bpmp@70016000 {
status = "okay";
};
usb@70090000 {
compatible = "nvidia,tegra210b01-xusb";
};
padctl@7009f000 {
compatible = "nvidia,tegra210b01-xusb-padctl";
pads {
pcie {
clocks = <&tegra_car TEGRA210_CLK_PLL_E>,
<&tegra_car TEGRA210_CLK_PLL_P_UPHY_OUT>;
clock-names = "pll", "uphy_mgmt";
};
};
};
usb@700d0000 {
compatible = "nvidia,tegra210b01-xudc";
};
thermal-sensor@700e2000 {
compatible = "nvidia,tegra210b01-soctherm";
throttle-cfgs {
heavy {
nvidia,cpu-throt-percent = <0>;
nvidia,gpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_NONE>;
};
};
};
clock@70110000 {
compatible = "nvidia,tegra210b01-dfll";
};
};
@@ -26,7 +26,24 @@
status = "okay";
/* ST,FTS @ 49 */
touchscreen@49 {
compatible = "st,stmfts5";
reg = <0x49>;
pinctrl-0 = <&touchscreen_irq_n>, <&touchscreen_reset>;
pinctrl-names = "default";
interrupts-extended = <&tlmm 125 IRQ_TYPE_LEVEL_LOW>;
mode-switch-gpios = <&tlmm 136 GPIO_ACTIVE_HIGH>;
reset-gpios = <&tlmm 99 GPIO_ACTIVE_LOW>;
avdd-supply = <&vreg_l19a_3p3>;
vdd-supply = <&vreg_l14a_1p8>;
touchscreen-size-x = <1080>;
touchscreen-size-y = <2160>;
};
};
&mdss_dsi0 {
@@ -466,7 +466,7 @@
bias-pull-up;
};
touchscreen_pins: ts-pins-gpio-state {
touchscreen_irq_n: ts-irq-n-gpio-state {
pins = "gpio125";
function = "gpio";
drive-strength = <2>;
+1
View File
@@ -874,6 +874,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
+2 -6
View File
@@ -1,5 +1,6 @@
CONFIG_LOCALVERSION="-4k"
CONFIG_AUDIT=y
CONFIG_GENERIC_IRQ_DEBUGFS=y
CONFIG_TIME_KUNIT_TEST=m
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
@@ -9,7 +10,6 @@ CONFIG_BPF_JIT_ALWAYS_ON=y
# CONFIG_BPF_UNPRIV_DEFAULT_OFF is not set
CONFIG_BPF_LSM=y
CONFIG_PREEMPT=y
CONFIG_SCHED_CLASS_EXT=y
CONFIG_IRQ_TIME_ACCOUNTING=y
CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
@@ -50,7 +50,6 @@ CONFIG_EXPERT=y
# CONFIG_FHANDLE is not set
# CONFIG_RSEQ is not set
CONFIG_PROFILING=y
CONFIG_RUST=y
CONFIG_ARCH_SUNXI=y
CONFIG_ARCH_HISI=y
CONFIG_ARCH_QCOM=y
@@ -70,6 +69,7 @@ CONFIG_RANDOMIZE_BASE=y
# CONFIG_RANDOMIZE_MODULE_REGION_FULL is not set
CONFIG_UNWIND_PATCH_PAC_INTO_SCS=y
CONFIG_CMDLINE="console=ttynull stack_depot_disable=on cgroup_disable=pressure kasan.stacktrace=off kvm-arm.mode=protected bootconfig ioremap_guard"
CONFIG_CMDLINE_EXTEND=y
# CONFIG_DMI is not set
CONFIG_HIBERNATION=y
CONFIG_PM_USERSPACE_AUTOSLEEP=y
@@ -441,7 +441,6 @@ CONFIG_HW_RANDOM=y
# CONFIG_HW_RANDOM_HISI is not set
# CONFIG_HW_RANDOM_HISTB is not set
CONFIG_HW_RANDOM_CCTRNG=m
# CONFIG_DEVMEM is not set
# CONFIG_DEVPORT is not set
# CONFIG_I2C_HELPER_AUTO is not set
# CONFIG_I2C_TEGRA_BPMP is not set
@@ -607,7 +606,6 @@ CONFIG_VIRTIO_BALLOON=m
CONFIG_VHOST_VSOCK=y
CONFIG_STAGING=y
CONFIG_ASHMEM=y
CONFIG_ASHMEM_RUST=y
CONFIG_COMMON_CLK_SCPI=y
# CONFIG_SUNXI_CCU is not set
CONFIG_CLK_KUNIT_TEST=m
@@ -766,8 +764,6 @@ CONFIG_STACKTRACE_BUILD_ID=y
CONFIG_DYNAMIC_DEBUG_CORE=y
CONFIG_DEBUG_INFO_DWARF5=y
CONFIG_DEBUG_INFO_COMPRESSED_ZSTD=y
CONFIG_DEBUG_INFO_BTF=y
CONFIG_MODULE_ALLOW_BTF_MISMATCH=y
CONFIG_HEADERS_INSTALL=y
# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
CONFIG_MAGIC_SYSRQ=y
+4 -1
View File
@@ -385,8 +385,11 @@ static __init void parse_cmdline(const void *fdt, int chosen)
static char const cmdline[] __initconst = CONFIG_CMDLINE;
const u8 *prop = get_bootargs_cmdline(fdt, chosen);
if (IS_ENABLED(CONFIG_CMDLINE_FORCE) || !prop)
if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) ||
IS_ENABLED(CONFIG_CMDLINE_FORCE) ||
!prop) {
__parse_cmdline(cmdline, true);
}
if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && prop)
__parse_cmdline(prop, true);
+48
View File
@@ -0,0 +1,48 @@
<6>[ 0.505994] bm92t 0-0018: bm92t_probe
<6>[ 0.506468] bm92t 0-0018: DP handling disabled
<6>[ 0.508019] bm92t 0-0018: fw_type: 0x603, fw_rev: 0xD7C
<7>[ 0.508615] bm92t 0-0018: write reg cmd = 0x06 len = 3
<6>[ 0.509242] bm92t 0-0018: bm92t_debug_init
<6>[ 0.519206] bm92t 0-0018: init done
<7>[ 0.621689] bm92t 0-0018: Disabling VBUS
<3>[ 0.623565] bm92t 0-0018: Unknown cmd rejected!
<4>[ 0.623586] bm92t 0-0018: Invalid state, initiating SYS Reset!
<7>[ 0.623626] bm92t 0-0018: write reg cmd = 0x05 len = 3
<7>[ 0.624129] bm92t 0-0018: Sent cmd 0x0D 0x0D return value 0
<7>[ 0.727667] bm92t 0-0018: write reg cmd = 0x06 len = 3
<7>[ 0.728199] bm92t 0-0018: write reg cmd = 0x19 len = 3
<6>[ 0.728696] bm92t 0-0018: extcon cable is set to init state
<6>[ 0.840258] bm92t 0-0018: Alert= 0x0008 Status1= 0x1A80 Status2= 0x2000 DP= 0x4000 State= INIT_STATE
<7>[ 0.840297] bm92t 0-0018: Enabling VBUS
<6>[ 1.069745] bm92t 0-0018: extcon cable (02: USB HOST) attached
<6>[ 1.072449] bm92t 0-0018: Alert= 0x0008 Status1= 0x0D80 Status2= 0x0000 DP= 0x4000 State= INIT_STATE
<6>[ 1.095097] bm92t 0-0018: Alert= 0x4000 Status1= 0x0D80 Status2= 0x0000 DP= 0x4000 State= INIT_STATE
<6>[ 1.137871] bm92t 0-0018: Alert= 0x1000 Status1= 0x4D80 Status2= 0x0000 DP= 0x4000 State= INIT_STATE
<6>[ 1.141067] bm92t 0-0018: Supported PDOs:
<6>[ 1.141089] bm92t 0-0018: PDO 1: 1500mA 5000mV DRD
<6>[ 1.141104] bm92t 0-0018: Device in powered mode
<6>[ 1.141120] bm92t 0-0018: Requesting 1: min 900mA, max 1500mA, 5000mV
<7>[ 1.141138] bm92t 0-0018: write reg cmd = 0x30 len = 6
<7>[ 1.141930] bm92t 0-0018: write reg cmd = 0x05 len = 3
<7>[ 1.142422] bm92t 0-0018: Sent cmd 0x07 0x07 return value 0
<7>[ 1.142438] bm92t 0-0018: state = NEW_PDO
<6>[ 1.166166] bm92t 0-0018: Alert= 0x0004 Status1= 0x4D80 Status2= 0x0000 DP= 0x4000 State= NEW_PDO
<7>[ 1.166200] bm92t 0-0018: cmd done in NEW_PDO state
<6>[ 1.189414] bm92t 0-0018: Alert= 0x1000 Status1= 0x4D80 Status2= 0x0000 DP= 0x4000 State= NEW_PDO
<6>[ 1.191193] bm92t 0-0018: New PD Contract:
<6>[ 1.191212] bm92t 0-0018: PDO: 1: 1500mA, 5000mV
<6>[ 1.191224] bm92t 0-0018: RDO: op 900mA, 1500mA max
<7>[ 1.191240] bm92t 0-0018: write reg cmd = 0x05 len = 3
<7>[ 1.191734] bm92t 0-0018: Sent cmd 0x05 0x05 return value 0
<7>[ 1.191750] bm92t 0-0018: state = PS_RDY_SENT
<6>[ 1.194256] bm92t 0-0018: Alert= 0x0004 Status1= 0x4D80 Status2= 0x0000 DP= 0x4000 State= PS_RDY_SENT
<7>[ 1.194287] bm92t 0-0018: write reg cmd = 0x05 len = 3
<7>[ 1.194804] bm92t 0-0018: Sent cmd 0x18 0x18 return value 0
<7>[ 1.194818] bm92t 0-0018: state = DR_SWAP_SENT
<6>[ 1.203046] bm92t 0-0018: Alert= 0x0004 Status1= 0x4DE0 Status2= 0x0000 DP= 0x4000 State= DR_SWAP_SENT
<3>[ 1.203075] bm92t 0-0018: DR_SWAP_CMD rejected!
<6>[ 1.203093] bm92t 0-0018: extcon cable (02: USB HOST) detached
<6>[ 1.203168] bm92t 0-0018: extcon cable (01: USB) attached
<7>[ 1.203195] bm92t 0-0018: state = INIT_STATE
<6>[ 2.131526] bm92t 0-0018: Alert= 0x0800 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
<6>[ 3.216479] bm92t 0-0018: Set Charging Current Limit 900ma
+72
View File
@@ -0,0 +1,72 @@
[ 0.513067][ T1] /i2c@7000c000/bm92t@18: Fixed dependency cycle(s) with /padctl@7009f000
[ 0.513632][ T1] /padctl@7009f000: Fixed dependency cycle(s) with /i2c@7000c000/bm92t@18
[ 3.774932][ T1] /padctl@7009f000: Fixed dependency cycle(s) with /i2c@7000c000/bm92t@18
[ 3.781706][ T1] /i2c@7000c000/bm92t@18: Fixed dependency cycle(s) with /padctl@7009f000
[ 4.999891][ T1] bm92t 0-0018: DP handling disabled
[ 5.005789][ T1] bm92t 0-0018: fw_type: 0x603, fw_rev: 0xD7C
[ 5.010151][ T1] bm92t 0-0018: write reg cmd = 0x06 len = 3
[ 5.029128][ T1] bm92t 0-0018: init done
[ 5.133260][ T76] bm92t 0-0018: Disabling VBUS
[ 5.139599][ T76] bm92t 0-0018: Unknown cmd rejected!
[ 5.150059][ T76] bm92t 0-0018: Invalid state, initiating SYS Reset!
[ 5.163413][ T76] bm92t 0-0018: write reg cmd = 0x05 len = 3
[ 5.174663][ T76] bm92t 0-0018: Sent cmd 0x0D 0x0D return value 0
[ 5.284905][ T76] bm92t 0-0018: write reg cmd = 0x06 len = 3
[ 5.289002][ T76] bm92t 0-0018: write reg cmd = 0x19 len = 3
[ 5.294828][ T76] bm92t 0-0018: extcon cable is set to init state
[ 5.409602][ T14] bm92t 0-0018: Alert= 0x0000 Status1= 0x0000 Status2= 0x0000 DP= 0x0000 State= INIT_STATE
[ 5.419830][ T14] bm92t 0-0018: Alert= 0x0000 Status1= 0x0000 Status2= 0x0000 DP= 0x0000 State= INIT_STATE
[ 5.430023][ T14] bm92t 0-0018: Alert= 0x0000 Status1= 0x0000 Status2= 0x0000 DP= 0x0000 State= INIT_STATE
[ 5.440217][ T14] bm92t 0-0018: Alert= 0x0000 Status1= 0x0000 Status2= 0x0000 DP= 0x0000 State= INIT_STATE
[ 5.450404][ T14] bm92t 0-0018: Alert= 0x0000 Status1= 0x0000 Status2= 0x0000 DP= 0x0000 State= INIT_STATE
[ 5.460599][ T14] bm92t 0-0018: Alert= 0x0000 Status1= 0x0000 Status2= 0x0000 DP= 0x0000 State= INIT_STATE
[ 5.470791][ T14] bm92t 0-0018: Alert= 0x0000 Status1= 0x0000 Status2= 0x0000 DP= 0x0000 State= INIT_STATE
[ 5.480977][ T14] bm92t 0-0018: Alert= 0x0000 Status1= 0x0000 Status2= 0x0000 DP= 0x0000 State= INIT_STATE
[ 5.491180][ T14] bm92t 0-0018: Alert= 0x0000 Status1= 0x0000 Status2= 0x0000 DP= 0x0000 State= INIT_STATE
[ 5.501370][ T14] bm92t 0-0018: Alert= 0x0000 Status1= 0x0D80 Status2= 0x0000 DP= 0x4000 State= INIT_STATE
[ 5.601170][ T12] bm92t 0-0018: Supported PDOs:
[ 5.603621][ T12] bm92t 0-0018: PDO 1: 1500mA 5000mV DRD
[ 5.609164][ T12] bm92t 0-0018: Device in powered mode
[ 5.614444][ T12] bm92t 0-0018: Requesting 1: min 900mA, max 1500mA, 5000mV
[ 5.621646][ T12] bm92t 0-0018: write reg cmd = 0x30 len = 6
[ 5.628227][ T12] bm92t 0-0018: write reg cmd = 0x05 len = 3
[ 5.633748][ T12] bm92t 0-0018: Sent cmd 0x07 0x07 return value 0
[ 5.639500][ T12] bm92t 0-0018: state = NEW_PDO
[ 5.669385][ T12] bm92t 0-0018: cmd done in NEW_PDO state
[ 5.682390][ T14] bm92t 0-0018: New PD Contract:
[ 5.684930][ T14] bm92t 0-0018: PDO: 1: 1500mA, 5000mV
[ 5.690203][ T14] bm92t 0-0018: RDO: op 900mA, 1500mA max
[ 5.695750][ T14] bm92t 0-0018: write reg cmd = 0x05 len = 3
[ 5.702053][ T14] bm92t 0-0018: Sent cmd 0x05 0x05 return value 0
[ 5.707809][ T14] bm92t 0-0018: state = PS_RDY_SENT
[ 5.715462][ T14] bm92t 0-0018: extcon cable (02: USB HOST) attached
[ 5.719728][ T14] bm92t 0-0018: write reg cmd = 0x05 len = 3
[ 5.726030][ T14] bm92t 0-0018: Sent cmd 0x18 0x18 return value 0
[ 5.731775][ T14] bm92t 0-0018: state = DR_SWAP_SENT
[ 5.739509][ T14] bm92t 0-0018: DR_SWAP_CMD rejected!
[ 5.742450][ T14] bm92t 0-0018: extcon cable (02: USB HOST) detached
[ 5.749002][ T14] bm92t 0-0018: extcon cable (01: USB) attached
[ 5.755045][ T14] bm92t 0-0018: state = INIT_STATE
[ 7.750906][ T76] bm92t 0-0018: Set Charging Current Limit 900ma
[ 10.413696][ T12] bm92t_event_handler: 1554 callbacks suppressed
[ 10.413707][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 10.430124][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 10.440606][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 10.450832][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 10.461080][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 10.471307][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 10.481507][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 10.491702][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 10.501887][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 10.512081][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 15.415942][ T55] bm92t_event_handler: 1865 callbacks suppressed
[ 15.415949][ T55] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 15.432305][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 15.442506][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 15.452721][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 15.462926][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 15.473114][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 15.483314][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 15.493520][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 15.503715][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
[ 15.513916][ T12] bm92t 0-0018: Alert= 0x0000 Status1= 0x4DE0 Status2= 0x0001 DP= 0x4000 State= INIT_STATE
+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);
+1
View File
@@ -506,6 +506,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = {
{ 0x6606, "BCM4345C5" }, /* 003.006.006 */
{ 0x230f, "BCM4356A2" }, /* 001.003.015 */
{ 0x2310, "BCM4343A2" }, /* 001.003.016 */
{ 0x2409, "BCM4356A3" }, /* 001.004.009 */
{ 0x220e, "BCM20702A1" }, /* 001.002.014 */
{ 0x420d, "BCM4349B1" }, /* 002.002.013 */
{ 0x420e, "BCM4349B1" }, /* 002.002.014 */
+23 -2
View File
@@ -2464,6 +2464,13 @@ static void clk_change_rate(struct clk_core *core)
if (core->ops->post_rate_change)
core->ops->post_rate_change(core->hw, old_rate, core->rate);
/*
* Allow children to be aware that next set rate operation is triggered
* by downward rate propagation, rather than direct set rate on itself.
*/
if (core->notifier_count)
__clk_notify(core, PRE_SUBTREE_CHANGE, old_rate, core->rate);
/*
* Use safe iteration, as change_rate can actually swap parents
* for certain clock types.
@@ -2479,6 +2486,9 @@ static void clk_change_rate(struct clk_core *core)
if (core->new_child)
clk_change_rate(core->new_child);
if (core->notifier_count)
__clk_notify(core, POST_SUBTREE_CHANGE, old_rate, core->rate);
clk_pm_runtime_put(core);
}
@@ -2858,6 +2868,7 @@ static int clk_core_set_parent_nolock(struct clk_core *core,
int ret = 0;
int p_index = 0;
unsigned long p_rate = 0;
unsigned long old_p_rate = 0;
lockdep_assert_held(&prepare_lock);
@@ -2900,13 +2911,23 @@ static int clk_core_set_parent_nolock(struct clk_core *core,
if (ret & NOTIFY_STOP_MASK)
goto runtime_put;
/* do the re-parent */
ret = __clk_set_parent(core, parent, p_index);
/* propagate PRE_PARENT_CHANGE notifications */
if (core->parent)
old_p_rate = core->parent->rate;
ret = __clk_notify(core, PRE_PARENT_CHANGE, old_p_rate, p_rate);
/* do the re-parent if no objections */
if (!(ret & NOTIFY_STOP_MASK))
ret = __clk_set_parent(core, parent, p_index);
/* propagate rate an accuracy recalculation accordingly */
if (ret) {
__clk_notify(core, ABORT_PARENT_CHANGE, old_p_rate, p_rate);
__clk_recalc_rates(core, true, ABORT_RATE_CHANGE);
} else {
__clk_notify(core, POST_PARENT_CHANGE, old_p_rate, p_rate);
__clk_recalc_rates(core, true, POST_RATE_CHANGE);
__clk_recalc_accuracies(core);
}
+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);
+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);
+60 -19
View File
@@ -13,6 +13,7 @@
#include <linux/pm.h>
#include <linux/semaphore.h>
#include <linux/sched/clock.h>
#include <linux/syscore_ops.h>
#include <soc/tegra/bpmp.h>
#include <soc/tegra/bpmp-abi.h>
@@ -343,28 +344,12 @@ static ssize_t tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel,
static int __maybe_unused tegra_bpmp_resume(struct device *dev);
int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp,
struct tegra_bpmp_message *msg)
static int __tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp,
struct tegra_bpmp_message *msg)
{
struct tegra_bpmp_channel *channel;
struct tegra_bpmp_channel *channel = bpmp->tx_channel;
int err;
if (WARN_ON(!irqs_disabled()))
return -EPERM;
if (!tegra_bpmp_message_valid(msg))
return -EINVAL;
if (bpmp->suspended) {
/* Reset BPMP IPC channels during resume based on flags passed */
if (msg->flags & TEGRA_BPMP_MESSAGE_RESET)
tegra_bpmp_resume(bpmp->dev);
else
return -EAGAIN;
}
channel = bpmp->tx_channel;
spin_lock(&bpmp->atomic_tx_lock);
err = tegra_bpmp_channel_write(channel, msg->mrq, MSG_ACK,
@@ -387,6 +372,26 @@ int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp,
return __tegra_bpmp_channel_read(channel, msg->rx.data, msg->rx.size,
&msg->rx.ret);
}
int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp,
struct tegra_bpmp_message *msg)
{
if (WARN_ON(!irqs_disabled()))
return -EPERM;
if (!tegra_bpmp_message_valid(msg))
return -EINVAL;
if (bpmp->suspended) {
/* Reset BPMP IPC channels during resume based on flags passed */
if (msg->flags & TEGRA_BPMP_MESSAGE_RESET)
tegra_bpmp_resume(bpmp->dev);
else
return -EAGAIN;
}
return __tegra_bpmp_transfer_atomic(bpmp, msg);
}
EXPORT_SYMBOL_GPL(tegra_bpmp_transfer_atomic);
int tegra_bpmp_transfer(struct tegra_bpmp *bpmp,
@@ -733,6 +738,37 @@ void tegra_bpmp_handle_rx(struct tegra_bpmp *bpmp)
spin_unlock(&bpmp->lock);
}
#define MRQ_T210_ENABLE_SUSPEND 17
#define TEGRA210_BPMP_PM_SC7 23
static int tegra210_bpmp_syscore_suspend(void *data)
{
struct tegra_bpmp *bpmp = data;
__le32 req[2] = { cpu_to_le32(TEGRA210_BPMP_PM_SC7), 0 };
struct tegra_bpmp_message msg = {
.mrq = MRQ_T210_ENABLE_SUSPEND,
.tx = {
.data = req,
.size = sizeof(req),
},
};
int err;
err = __tegra_bpmp_transfer_atomic(bpmp, &msg);
if (err < 0)
dev_err(bpmp->dev, "failed to enable SC7: %d\n", err);
return 0;
}
static const struct syscore_ops tegra210_bpmp_syscore_ops = {
.suspend = tegra210_bpmp_syscore_suspend,
};
static struct syscore tegra210_bpmp_syscore = {
.ops = &tegra210_bpmp_syscore_ops,
};
static int tegra_bpmp_probe(struct platform_device *pdev)
{
struct tegra_bpmp *bpmp;
@@ -831,6 +867,11 @@ static int tegra_bpmp_probe(struct platform_device *pdev)
if (err < 0)
dev_err(&pdev->dev, "debugfs initialization failed: %d\n", err);
if (of_device_is_compatible(pdev->dev.of_node, "nvidia,tegra210-bpmp")) {
tegra210_bpmp_syscore.data = bpmp;
register_syscore(&tegra210_bpmp_syscore);
}
return 0;
free_mrq:
+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
@@ -192,7 +192,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
@@ -148,7 +148,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)
@@ -134,5 +134,6 @@ int gf100_clk_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct
int gk104_clk_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_clk **);
int gk20a_clk_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_clk **);
int gm20b_clk_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_clk **);
int gm20b_b01_clk_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_clk **);
int gp10b_clk_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_clk **);
#endif
@@ -42,4 +42,5 @@ int gf117_volt_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct
int gk104_volt_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_volt **);
int gk20a_volt_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_volt **);
int gm20b_volt_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_volt **);
int gm20b_b01_volt_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_volt **);
#endif
@@ -2072,6 +2072,31 @@ nv12b_chipset = {
.sw = { 0x00000001, gf100_sw_new },
};
static const struct nvkm_device_chip
nv12e_chipset = {
.name = "GM20B",
.acr = { 0x00000001, gm20b_acr_new },
.bar = { 0x00000001, gm20b_bar_new },
.bus = { 0x00000001, gf100_bus_new },
.clk = { 0x00000001, gm20b_b01_clk_new },
.fb = { 0x00000001, gm20b_fb_new },
.fuse = { 0x00000001, gm107_fuse_new },
.imem = { 0x00000001, gk20a_instmem_new },
.ltc = { 0x00000001, gm200_ltc_new },
.mc = { 0x00000001, gk20a_mc_new },
.mmu = { 0x00000001, gm20b_mmu_new },
.pmu = { 0x00000001, gm20b_pmu_new },
.privring = { 0x00000001, gk20a_privring_new },
.timer = { 0x00000001, gk20a_timer_new },
.top = { 0x00000001, gk104_top_new },
.volt = { 0x00000001, gm20b_b01_volt_new },
.ce = { 0x00000004, gm200_ce_new },
.dma = { 0x00000001, gf119_dma_new },
.fifo = { 0x00000001, gm200_fifo_new },
.gr = { 0x00000001, gm20b_gr_new },
.sw = { 0x00000001, gf100_sw_new },
};
static const struct nvkm_device_chip
nv130_chipset = {
.name = "GP100",
@@ -3328,6 +3353,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
case 0x124: device->chip = &nv124_chipset; break;
case 0x126: device->chip = &nv126_chipset; break;
case 0x12b: device->chip = &nv12b_chipset; break;
case 0x12e: device->chip = &nv12e_chipset; break;
case 0x130: device->chip = &nv130_chipset; break;
case 0x132: device->chip = &nv132_chipset; break;
case 0x134: device->chip = &nv134_chipset; break;
+351 -8
View File
@@ -96,12 +96,18 @@ struct gm20b_clk_dvfs_params {
u32 vco_ctrl;
};
static const struct gm20b_clk_dvfs_params gm20b_dvfs_params = {
static const struct gm20b_clk_dvfs_params gm20b_b1_dvfs_params = {
.coeff_slope = -165230,
.coeff_offs = 214007,
.vco_ctrl = 0x7 << 3,
};
static const struct gm20b_clk_dvfs_params gm20b_c1_dvfs_params = {
.coeff_slope = 0,
.coeff_offs = 0,
.vco_ctrl = 0x7 << 3,
};
/*
* base.n is now the *integer* part of the N factor.
* sdm_din contains n's decimal part.
@@ -358,7 +364,7 @@ gm20b_pllg_disable(struct gm20b_clk *clk)
}
static int
gm20b_pllg_program_mnp(struct gm20b_clk *clk, const struct gk20a_pll *pll)
gm20b_pllg_program_mnp(struct gm20b_clk *clk, const struct gk20a_pll *pll, bool pll_c1)
{
struct nvkm_subdev *subdev = &clk->base.base.subdev;
struct nvkm_device *device = subdev->device;
@@ -396,7 +402,7 @@ gm20b_pllg_program_mnp(struct gm20b_clk *clk, const struct gk20a_pll *pll)
* the case, calculate and program an interim PL that will allow
* us to respect that rule.
*/
if ((old & new) == 0) {
if ((old & new) == 0 && !pll_c1) {
cur_pll.base.pl = min(old | BIT(ffs(new) - 1),
new | BIT(ffs(old) - 1));
gk20a_pllg_write_mnp(&clk->base, &cur_pll.base);
@@ -431,7 +437,7 @@ gm20b_pllg_program_mnp(struct gm20b_clk *clk, const struct gk20a_pll *pll)
}
static int
gm20b_pllg_program_mnp_slide(struct gm20b_clk *clk, const struct gk20a_pll *pll)
gm20b_pllg_program_mnp_slide(struct gm20b_clk *clk, const struct gk20a_pll *pll, bool pll_c1)
{
struct gk20a_pll cur_pll;
int ret;
@@ -453,7 +459,7 @@ gm20b_pllg_program_mnp_slide(struct gm20b_clk *clk, const struct gk20a_pll *pll)
/* program MNP with the new clock parameters and new NDIV_LO */
cur_pll = *pll;
cur_pll.n = gk20a_pllg_n_lo(&clk->base, &cur_pll);
ret = gm20b_pllg_program_mnp(clk, &cur_pll);
ret = gm20b_pllg_program_mnp(clk, &cur_pll, pll_c1);
if (ret)
return ret;
@@ -611,7 +617,7 @@ gm20b_clk_prog(struct nvkm_clk *base)
pll_safe = clk->new_pll;
gm20b_dvfs_calc_safe_pll(clk, &pll_safe);
ret = gm20b_pllg_program_mnp_slide(clk, &pll_safe);
ret = gm20b_pllg_program_mnp_slide(clk, &pll_safe, false);
if (ret)
return ret;
}
@@ -632,7 +638,73 @@ prog:
clk->dvfs = clk->new_dvfs;
clk->base.pll = clk->new_pll;
return gm20b_pllg_program_mnp_slide(clk, &clk->base.pll);
return gm20b_pllg_program_mnp_slide(clk, &clk->base.pll, false);
}
static int
gm20b_b01_clk_prog(struct nvkm_clk *base)
{
struct gm20b_clk *clk = gm20b_clk(base);
u32 cur_freq;
int ret;
/* No change in DVFS settings? */
if (clk->uv == clk->new_uv)
goto prog;
/*
* Interim step for changing DVFS detection settings: low enough
* frequency to be safe at DVFS coeff = 0.
*
* 1. If voltage is increasing:
* - safe frequency target matches the lowest - old - frequency
* - DVFS settings are still old
* - Voltage already increased to new level by volt, but maximum
* detection limit assures PLL output remains under F/V curve
*
* 2. If voltage is decreasing:
* - safe frequency target matches the lowest - new - frequency
* - DVFS settings are still old
* - Voltage is also old, it will be lowered by volt afterwards
*
* Interim step can be skipped if old frequency is below safe minimum,
* i.e., it is low enough to be safe at any voltage in operating range
* with zero DVFS coefficient.
*/
cur_freq = nvkm_clk_read(&clk->base.base, nv_clk_src_gpc);
if (cur_freq > clk->safe_fmax_vmin) {
struct gk20a_pll pll_safe;
if (clk->uv < clk->new_uv)
/* voltage will raise: safe frequency is current one */
pll_safe = clk->base.pll;
else
/* voltage will drop: safe frequency is new one */
pll_safe = clk->new_pll;
gm20b_dvfs_calc_safe_pll(clk, &pll_safe);
ret = gm20b_pllg_program_mnp_slide(clk, &pll_safe, true);
if (ret)
return ret;
}
/*
* DVFS detection settings transition:
* - Set DVFS coefficient zero
* - Set calibration level to new voltage
* - Set DVFS coefficient to match new voltage
*/
gm20b_dvfs_program_coeff(clk, 0);
gm20b_dvfs_program_ext_cal(clk, clk->new_dvfs.dfs_ext_cal);
gm20b_dvfs_program_coeff(clk, clk->new_dvfs.dfs_coeff);
gm20b_dvfs_program_dfs_detection(clk, &clk->new_dvfs);
prog:
clk->uv = clk->new_uv;
clk->dvfs = clk->new_dvfs;
clk->base.pll = clk->new_pll;
return gm20b_pllg_program_mnp_slide(clk, &clk->base.pll, true);
}
static struct nvkm_pstate
@@ -717,6 +789,112 @@ gm20b_pstates[] = {
},
};
static struct nvkm_pstate
gm20b_b01_pstates[] = {
{
.base = {
.domain[nv_clk_src_gpc] = 76800,
.voltage = 0,
},
},
{
.base = {
.domain[nv_clk_src_gpc] = 153600,
.voltage = 1,
},
},
{
.base = {
.domain[nv_clk_src_gpc] = 230400,
.voltage = 2,
},
},
{
.base = {
.domain[nv_clk_src_gpc] = 307200,
.voltage = 3,
},
},
{
.base = {
.domain[nv_clk_src_gpc] = 384000,
.voltage = 4,
},
},
{
.base = {
.domain[nv_clk_src_gpc] = 460800,
.voltage = 5,
},
},
{
.base = {
.domain[nv_clk_src_gpc] = 537600,
.voltage = 6,
},
},
{
.base = {
.domain[nv_clk_src_gpc] = 614400,
.voltage = 7,
},
},
{
.base = {
.domain[nv_clk_src_gpc] = 691200,
.voltage = 8,
},
},
{
.base = {
.domain[nv_clk_src_gpc] = 768000,
.voltage = 9,
},
},
{
.base = {
.domain[nv_clk_src_gpc] = 844800,
.voltage = 10,
},
},
{
.base = {
.domain[nv_clk_src_gpc] = 921600,
.voltage = 11,
},
},
{
.base = {
.domain[nv_clk_src_gpc] = 998400,
.voltage = 12,
},
},
{
.base = {
.domain[nv_clk_src_gpc] = 1075200,
.voltage = 13,
},
},
{
.base = {
.domain[nv_clk_src_gpc] = 1152000,
.voltage = 14,
},
},
{
.base = {
.domain[nv_clk_src_gpc] = 1228800,
.voltage = 15,
},
},
{
.base = {
.domain[nv_clk_src_gpc] = 1267200,
.voltage = 16,
},
},
};
static void
gm20b_clk_fini(struct nvkm_clk *base)
{
@@ -805,8 +983,85 @@ calibrated:
return 0;
}
static int
gm20b_b01_clk_init_dvfs(struct gm20b_clk *clk)
{
struct nvkm_subdev *subdev = &clk->base.base.subdev;
struct nvkm_device *device = subdev->device;
bool fused = clk->uvdet_offs && clk->uvdet_slope;
static const s32 ADC_SLOPE_UV = 10000; /* default ADC detection slope */
u32 data;
int ret;
/* Enable NA DVFS */
nvkm_mask(device, GPCPLL_DVFS1, GPCPLL_DVFS1_EN_DFS_BIT,
GPCPLL_DVFS1_EN_DFS_BIT);
/* Set VCO_CTRL */
if (clk->dvfs_params->vco_ctrl)
nvkm_mask(device, GPCPLL_CFG3, GPCPLL_CFG3_VCO_CTRL_MASK,
clk->dvfs_params->vco_ctrl << GPCPLL_CFG3_VCO_CTRL_SHIFT);
if (fused) {
/* Start internal calibration, but ignore results */
nvkm_mask(device, GPCPLL_DVFS1, GPCPLL_DVFS1_EN_DFS_CAL_BIT,
GPCPLL_DVFS1_EN_DFS_CAL_BIT);
/* got uvdev parameters from fuse, skip calibration */
goto calibrated;
}
/*
* If calibration parameters are not fused, start internal calibration,
* wait for completion, and use results along with default slope to
* calculate ADC offset during boot.
*/
nvkm_mask(device, GPCPLL_DVFS1, GPCPLL_DVFS1_EN_DFS_CAL_BIT,
GPCPLL_DVFS1_EN_DFS_CAL_BIT);
/*
* C1 PLL revision must be enabled to read internal calibration results.
*/
nvkm_mask(device, GPCPLL_CFG, GPCPLL_CFG_ENABLE, 1);
/* Wait for internal calibration done (spec < 2us). */
ret = nvkm_wait_usec(device, 10, GPCPLL_DVFS1,
GPCPLL_DVFS1_DFS_CAL_DONE_BIT,
GPCPLL_DVFS1_DFS_CAL_DONE_BIT);
if (ret < 0) {
nvkm_error(subdev, "GPCPLL calibration timeout\n");
return -ETIMEDOUT;
}
data = nvkm_rd32(device, GPCPLL_CFG3) >>
GPCPLL_CFG3_PLL_DFS_TESTOUT_SHIFT;
data &= MASK(GPCPLL_CFG3_PLL_DFS_TESTOUT_WIDTH);
/*
* Disable C1 PLL revision after reading calibration results.
*/
nvkm_mask(device, GPCPLL_CFG, GPCPLL_CFG_ENABLE, 0);
clk->uvdet_slope = ADC_SLOPE_UV;
clk->uvdet_offs = ((s32)clk->uv) - data * ADC_SLOPE_UV;
nvkm_debug(subdev, "calibrated DVFS parameters: offs %d, slope %d\n",
clk->uvdet_offs, clk->uvdet_slope);
calibrated:
/* Compute and apply initial DVFS parameters */
gm20b_dvfs_calc_det_coeff(clk, clk->uv, &clk->dvfs);
gm20b_dvfs_program_coeff(clk, 0);
gm20b_dvfs_program_ext_cal(clk, clk->dvfs.dfs_ext_cal);
gm20b_dvfs_program_coeff(clk, clk->dvfs.dfs_coeff);
gm20b_dvfs_program_dfs_detection(clk, &clk->new_dvfs);
return 0;
}
/* Forward declaration to detect speedo >=1 in gm20b_clk_init() */
static const struct nvkm_clk_func gm20b_clk;
static const struct nvkm_clk_func gm20b_b01_clk;
static int
gm20b_clk_init(struct nvkm_clk *base)
@@ -860,6 +1115,17 @@ gm20b_clk_init(struct nvkm_clk *base)
ret = gm20b_clk_init_dvfs(_clk);
if (ret)
return ret;
} else if (clk->base.func == &gm20b_b01_clk) {
struct gm20b_clk *_clk = gm20b_clk(base);
struct nvkm_volt *volt = device->volt;
/* Get current voltage */
_clk->uv = nvkm_volt_get(volt);
/* Initialize DVFS */
ret = gm20b_b01_clk_init_dvfs(_clk);
if (ret)
return ret;
}
/* Start with lowest frequency */
@@ -912,6 +1178,23 @@ gm20b_clk = {
},
};
static const struct nvkm_clk_func
gm20b_b01_clk = {
.init = gm20b_clk_init,
.fini = gm20b_clk_fini,
.read = gk20a_clk_read,
.calc = gm20b_clk_calc,
.prog = gm20b_b01_clk_prog,
.tidy = gk20a_clk_tidy,
.pstates = gm20b_b01_pstates,
.nr_pstates = ARRAY_SIZE(gm20b_b01_pstates),
.domains = {
{ nv_clk_src_crystal, 0xff },
{ nv_clk_src_gpc, 0xff, 0, "core", GK20A_CLK_GPC_MDIV },
{ nv_clk_src_max },
},
};
static int
gm20b_clk_new_speedo0(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_clk **pclk)
@@ -1058,7 +1341,67 @@ gm20b_clk_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
clk->base.pl_to_div = pl_to_div;
clk->base.div_to_pl = div_to_pl;
clk->dvfs_params = &gm20b_dvfs_params;
clk->dvfs_params = &gm20b_b1_dvfs_params;
ret = gm20b_clk_init_fused_params(clk);
/*
* we will calibrate during init - should never happen on
* prod parts
*/
if (ret)
nvkm_warn(subdev, "no fused calibration parameters\n");
ret = gm20b_clk_init_safe_fmax(clk);
if (ret)
return ret;
return 0;
}
int
gm20b_b01_clk_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_clk **pclk)
{
struct nvkm_device_tegra *tdev = device->func->tegra(device);
struct gm20b_clk *clk;
struct nvkm_subdev *subdev;
struct gk20a_clk_pllg_params *clk_params;
int ret;
/* Speedo 0 GPUs cannot use noise-aware PLL */
if (tdev->gpu_speedo_id == 0)
return -EINVAL;
/* Speedo >= 1, use NAPLL */
clk = kzalloc(sizeof(*clk) + sizeof(*clk_params), GFP_KERNEL);
if (!clk)
return -ENOMEM;
*pclk = &clk->base.base;
subdev = &clk->base.base.subdev;
/* duplicate the clock parameters since we will patch them below */
clk_params = (void *) (clk + 1);
*clk_params = gm20b_pllg_params;
ret = gk20a_clk_ctor(device, type, inst, &gm20b_b01_clk, clk_params, &clk->base);
if (ret)
return ret;
/*
* NAPLL can only work with max_u, clamp the m range so
* gk20a_pllg_calc_mnp always uses it
*/
clk_params->max_m = clk_params->min_m = DIV_ROUND_UP(clk_params->max_u,
(clk->base.parent_rate / KHZ));
if (clk_params->max_m == 0) {
nvkm_error(subdev, "cannot use NAPLL, and legacy clock unavailable...\n");
kfree(clk);
return -EINVAL;
}
clk->base.pl_to_div = pl_to_div;
clk->base.div_to_pl = div_to_pl;
clk->dvfs_params = &gm20b_c1_dvfs_params;
ret = gm20b_clk_init_fused_params(clk);
/*
@@ -91,3 +91,54 @@ gm20b_volt_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
return gk20a_volt_ctor(device, type, inst, gm20b_cvb_coef,
ARRAY_SIZE(gm20b_cvb_coef), vmin, volt);
}
static const struct cvb_coef gm20b_b01_na_cvb_coef[] = {
/* KHz, c0, c1, c2, c3, c4, c5 */
/* 76800 */ { 610000, 0, 0, 0, 0, 0 },
/* 153600 */ { 610000, 0, 0, 0, 0, 0 },
/* 230400 */ { 610000, 0, 0, 0, 0, 0 },
/* 307200 */ { 610000, 0, 0, 0, 0, 0 },
/* 384000 */ { 610000, 0, 0, 0, 0, 0 },
/* 460800 */ { 610000, 0, 0, 0, 0, 0 },
/* 537600 */ { 801688, -10900, -163, 298, -10599, 162 },
/* 614400 */ { 824214, -5743, -452, 238, -6325, 81 },
/* 691200 */ { 848830, -3903, -552, 119, -4030, -2 },
/* 768000 */ { 891575, -4409, -584, 0, -2849, 39 },
/* 844800 */ { 940071, -5367, -602, -60, -63, -93 },
/* 921600 */ { 986765, -6637, -614, -179, 1905, -13 },
/* 998400 */ { 1098475, -13529, -497, -179, 3626, 9 },
/* 1075200 */ { 1163644, -12688, -648, 0, 1077, 40 },
/* 1152000 */ { 1204812, -9908, -830, 0, 1469, 110 },
/* 1228800 */ { 1277303, -11675, -859, 0, 3722, 313 },
/* 1267200 */ { 1335531, -12567, -867, 0, 3681, 559 },
};
int
gm20b_b01_volt_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_volt **pvolt)
{
struct nvkm_device_tegra *tdev = device->func->tegra(device);
struct gk20a_volt *volt;
u32 vmin;
if (tdev->gpu_speedo_id >= ARRAY_SIZE(speedo_to_vmin)) {
nvdev_error(device, "unsupported speedo %d\n",
tdev->gpu_speedo_id);
return -EINVAL;
}
volt = kzalloc(sizeof(*volt), GFP_KERNEL);
if (!volt)
return -ENOMEM;
*pvolt = &volt->base;
vmin = speedo_to_vmin[tdev->gpu_speedo_id];
switch (tdev->gpu_speedo_id) {
case 1:
return gk20a_volt_ctor(device, type, inst, gm20b_b01_na_cvb_coef,
ARRAY_SIZE(gm20b_b01_na_cvb_coef), vmin, volt);
default:
return -EINVAL;
}
}
+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
+877
View File
@@ -0,0 +1,877 @@
/*
* Copyright (C) 2018 SwtcR <swtcr0@gmail.com>
* Copyright (C) 2023-2026 Azkali <a.ffcc7@gmail.com>
* Copyright (C) 2026 Thomas Makin <halorocker89@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_of.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))
#define DCS_SM_BRIGHTNESS_MAX 2047
#define DCS_SM_DUTY_MAX 255
#define DCS_SM_DUTY_DEFAULT 150
/* 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;
bool dcs_backlight;
const struct drm_display_mode *mode;
enum drm_panel_orientation orientation;
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,
},
{ MIPI_DCS_NOP, -1, { 0x00 } },
};
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, 0, { 0x00 } },
{
0xFF,
180,
},
// Set color mode to basic (natural). Stock is Saturated (0x00). (Reset value is 0x20).
{ MIPI_DCS_PRIV_SM_SET_COLOR_MODE, 1, { DCS_SM_COLOR_MODE_BASIC } },
// Enable backlight and smooth PWM.
{ MIPI_DCS_WRITE_CONTROL_DISPLAY, 1, { DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL | DCS_CONTROL_DISPLAY_DIMMING_CTRL } },
// Unlock Level 2 registers.
{ MIPI_DCS_PRIV_SM_SET_REGS_LOCK, 4, { 0x5A, 0x5A, 0x5A, 0x5A } },
// Set registers offset and set PWM transition to 6 frames (100ms).
{ MIPI_DCS_PRIV_SM_SET_REG_OFFSET, 1, { 0x07 } },
{ MIPI_DCS_PRIV_SM_SET_ELVSS, 1, { 0x06 } },
// Relock Level 2 registers.
{ MIPI_DCS_PRIV_SM_SET_REGS_LOCK, 4, { 0x5A, 0x5A, 0xA5, 0xA5 } },
// MIPI_DCS_SET_BRIGHTNESS 0000: 0%. 07FF: 100%.
{ MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 2, { 0x00, 0x00 } },
{
0xFF,
5,
},
{ MIPI_DCS_SET_DISPLAY_ON, 0, { 0x00 } },
{
0xFF,
20,
},
{ MIPI_DCS_NOP, -1, { 0x00 } },
};
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 } },
{ MIPI_DCS_NOP, -1, { 0x00 } },
};
struct init_cmd suspend_cmds_PANEL_AUO_A062TAN01[] = {
{
0xFF,
100,
},
{
0xFF,
5,
},
{ MIPI_DCS_ENTER_SLEEP_MODE, 2, { 0x00, 0x0 } },
{
0xFF,
50,
},
{ MIPI_DCS_NOP, -1, { 0x00 } },
};
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,
},
{ MIPI_DCS_NOP, -1, { 0x00 } },
};
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 } },
{ MIPI_DCS_NOP, -1, { 0x00 } },
};
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,
},
{ MIPI_DCS_NOP, -1, { 0x00 } },
};
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,
},
{ MIPI_DCS_NOP, -1, { 0x00 } },
};
struct init_cmd suspend_cmds_PANEL_SAM_AMS699VC01[] = {
{ MIPI_DCS_SET_DISPLAY_OFF, 0, { 0x00 } },
{
0xFF,
100,
},
{ MIPI_DCS_ENTER_SLEEP_MODE, 0, { 0x00 } },
{
0xFF,
120,
},
{ MIPI_DCS_NOP, -1, { 0x00 } },
};
static inline struct nx_panel *to_nx_panel(struct drm_panel *panel)
{
return container_of(panel, struct nx_panel, base);
}
static u16 nx_dcs_brightness(struct backlight_device *bl)
{
if (backlight_is_blank(bl))
return 0;
if (bl->props.brightness >= DCS_SM_DUTY_MAX)
return DCS_SM_BRIGHTNESS_MAX;
return max(bl->props.brightness, 1) *
(DCS_SM_BRIGHTNESS_MAX / DCS_SM_DUTY_MAX);
}
static void nx_panel_detect(struct nx_panel *nx)
{
u8 id[3] = { 0 };
int ret;
nx->init_cmds = NULL;
nx->suspend_cmds = NULL;
nx->display_id = 0;
ret = mipi_dsi_dcs_read(nx->dsi, MIPI_DCS_GET_DISPLAY_ID,
id, sizeof(id));
if (ret < 0) {
dev_err(&nx->dsi->dev, "failed to read panel ID: %d\n", ret);
} else {
nx->display_id = (id[2] << 8) | id[0];
dev_info_once(&nx->dsi->dev, "display ID[%d]: %02x %02x %02x\n",
ret, id[0], id[1], id[2]);
}
if ((nx->display_id & 0xFF) == PANEL_JDI_XXX062M)
nx->display_id = PANEL_JDI_XXX062M;
if (of_machine_is_compatible("nintendo,aula"))
nx->display_id = PANEL_SAM_AMS699VC01;
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;
}
if (nx->dcs_backlight) {
u8 mode;
ret = mipi_dsi_dcs_set_display_brightness_large(dsi,
nx_dcs_brightness(nx->backlight));
if (ret < 0) {
dev_err(dev, "failed to set brightness: %d\n", ret);
return ret;
}
ret = mipi_dsi_dcs_get_power_mode(dsi, &mode);
if (ret < 0)
dev_warn(dev, "failed to read power mode: %d\n", 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);
if (nx->dcs_backlight)
mipi_dsi_dcs_set_display_off(nx->dsi);
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 + 1,
.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 enum drm_panel_orientation nx_panel_get_orientation(struct drm_panel *panel)
{
struct nx_panel *nx = to_nx_panel(panel);
return nx->orientation;
}
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,
.get_orientation = nx_panel_get_orientation,
};
static int nx_dcs_backlight_update_status(struct backlight_device *bl)
{
struct nx_panel *nx = bl_get_data(bl);
if (!nx->prepared)
return 0;
return mipi_dsi_dcs_set_display_brightness_large(nx->dsi,
nx_dcs_brightness(bl));
}
static const struct backlight_ops nx_dcs_backlight_ops = {
.update_status = nx_dcs_backlight_update_status,
};
static int nx_panel_add(struct nx_panel *nx)
{
struct device *dev = &nx->dsi->dev;
struct device_node *np;
int ret;
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;
} else {
struct backlight_properties props = {
.type = BACKLIGHT_RAW,
.brightness = DCS_SM_DUTY_DEFAULT,
.max_brightness = DCS_SM_DUTY_MAX,
};
nx->backlight = devm_backlight_device_register(dev, "backlight", dev, nx,
&nx_dcs_backlight_ops,
&props);
if (IS_ERR(nx->backlight))
return PTR_ERR(nx->backlight);
nx->dcs_backlight = true;
}
ret = of_drm_get_panel_orientation(dev->of_node, &nx->orientation);
if (ret < 0) {
dev_err(dev, "Failed to get orientation %d\n", ret);
return ret;
}
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 && !nx->dcs_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", },
+184 -44
View File
@@ -25,6 +25,7 @@
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_simple_kms_helper.h>
#include <drm/drm_vblank.h>
#include "dc.h"
#include "drm.h"
@@ -54,6 +55,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 +99,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 +142,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 +201,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 +219,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 +460,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 +668,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 +686,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 +694,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)
@@ -1055,6 +1075,9 @@ static int tegra_dsi_init(struct host1x_client *client)
&tegra_dsi_connector_helper_funcs);
dsi->output.connector.dpms = DRM_MODE_DPMS_OFF;
drm_connector_set_orientation_from_panel(
&dsi->output.connector, dsi->output.panel);
drm_simple_encoder_init(drm, &dsi->output.encoder,
DRM_MODE_ENCODER_DSI);
drm_encoder_helper_add(&dsi->output.encoder,
@@ -1069,7 +1092,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;
@@ -1323,6 +1346,39 @@ static void tegra_dsi_writesl(struct tegra_dsi *dsi, unsigned long offset,
}
}
static ssize_t tegra_dsi_video_transfer(struct tegra_dsi *dsi,
const struct mipi_dsi_packet *packet)
{
const u8 *header = packet->header;
u32 host_control, value;
host_control = tegra_dsi_readl(dsi, DSI_HOST_CONTROL);
value = DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_TX_TRIG_SOL |
DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC;
tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
value = DSI_VIDEO_MODE_CMD_PKT_ENABLE | DSI_VIDEO_MODE_LINE_TYPE(4);
tegra_dsi_writel(dsi, value, DSI_VIDEO_MODE_CONTROL);
value = header[2] << 16 | header[1] << 8 | header[0];
tegra_dsi_writel(dsi, value, DSI_WR_DATA);
if (packet->payload_length > 0)
tegra_dsi_writesl(dsi, DSI_WR_DATA, packet->payload,
packet->payload_length);
if (dsi->output.encoder.crtc) {
drm_crtc_wait_one_vblank(dsi->output.encoder.crtc);
drm_crtc_wait_one_vblank(dsi->output.encoder.crtc);
}
tegra_dsi_writel(dsi, 0, DSI_VIDEO_MODE_CONTROL);
tegra_dsi_writel(dsi, host_control, DSI_HOST_CONTROL);
return packet->size;
}
static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host,
const struct mipi_dsi_msg *msg)
{
@@ -1343,14 +1399,16 @@ static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host,
if (packet.size > dsi->video_fifo_depth * 4)
return -ENOSPC;
/* reset underflow/overflow flags */
value = tegra_dsi_readl(dsi, DSI_STATUS);
if (value & (DSI_STATUS_UNDERFLOW | DSI_STATUS_OVERFLOW)) {
value = DSI_HOST_CONTROL_FIFO_RESET;
tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
usleep_range(10, 20);
if (tegra_dsi_readl(dsi, DSI_CONTROL) & DSI_CONTROL_VIDEO_ENABLE) {
if (msg->rx_buf && msg->rx_len > 0)
return -EBUSY;
return tegra_dsi_video_transfer(dsi, &packet);
}
tegra_dsi_writel(dsi, DSI_HOST_CONTROL_FIFO_RESET, DSI_HOST_CONTROL);
usleep_range(10, 20);
value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
value |= DSI_POWER_CONTROL_ENABLE;
tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
@@ -1633,6 +1691,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 +1752,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);
+20
View File
@@ -102,6 +102,8 @@
#define DSI_PAD_CONTROL_CD 0x4c
#define DSI_PAD_CD_STATUS 0x4d
#define DSI_VIDEO_MODE_CONTROL 0x4e
#define DSI_VIDEO_MODE_CMD_PKT_ENABLE (1 << 0)
#define DSI_VIDEO_MODE_LINE_TYPE(x) (((x) & 0x7) << 1)
#define DSI_PAD_CONTROL_1 0x4f
#define DSI_PAD_CONTROL_2 0x50
#define DSI_PAD_OUT_CLK(x) (((x) & 0x7) << 0)
@@ -130,6 +132,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 },
+10
View File
@@ -135,6 +135,16 @@ config AS73211
This driver can also be built as a module. If so, the module
will be called as73211.
config BH1730
tristate "ROHM BH1730 ambient light sensor"
depends on I2C
help
Say Y here to build support for the ROHM BH1730FVC ambient light
sensor.
To compile this driver as a module, choose M here: the module will
be called bh1730.
config BH1745
tristate "ROHM BH1745 colour sensor"
depends on I2C
+1
View File
@@ -15,6 +15,7 @@ obj-$(CONFIG_APDS9300) += apds9300.o
obj-$(CONFIG_APDS9306) += apds9306.o
obj-$(CONFIG_APDS9960) += apds9960.o
obj-$(CONFIG_AS73211) += as73211.o
obj-$(CONFIG_BH1730) += bh1730.o
obj-$(CONFIG_BH1745) += bh1745.o
obj-$(CONFIG_BH1750) += bh1750.o
obj-$(CONFIG_BH1780) += bh1780.o
+575
View File
@@ -0,0 +1,575 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ROHM BH1730 ambient light sensor driver
*
* Copyright (c) 2021 CTCaer <ctcaer@gmail.com>
*
* Based on previous iio BH1730FVC drivers from:
* Copyright (c) 2018 Google, Inc.
* Author: Pierre Bourdon <delroth@google.com>
*
* Copyright (C) 2012 Samsung Electronics. All rights reserved.
* Author: Won Huh <won.huh@samsung.com>
*
* Data sheets:
* http://www.rohm.com/web/global/datasheet/BH1730FVC/bh1730fvc-e
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pm.h>
#include <linux/regulator/consumer.h>
#define BH1730_NAME "bh1730fvc"
#define BH1730_CMD_BIT BIT(7)
#define BH1730_REG_CONTROL 0x00
#define BH1730_REG_TIMING 0x01
#define BH1730_REG_GAIN 0x07
#define BH1730_REG_DATA0LOW 0x14
#define BH1730_REG_DATA1LOW 0x16
#define BH1730_CONTROL_POWER BIT(0)
#define BH1730_CONTROL_ADC_EN BIT(1)
#define BH1730_ADC_CALC_DELAY_US 2000 /* BH1730_INTERNAL_CLOCK_MS * 714 */
#define BH1730_ITIME_TO_US 2700 /* BH1730_INTERNAL_CLOCK_MS * 964 */
#define BH1730_DEFAULT_INTEG_CYCLE 38
#define BH1730_DEFAULT_ITIME_MS 100
#define BH1730_POWER_ON_DELAY_US 10000
#define BH1730_MAX_MEASURED_LUX 100000
enum bh1730_gain {
BH1730_GAIN_1X = 0,
BH1730_GAIN_2X,
BH1730_GAIN_64X,
BH1730_GAIN_128X,
};
struct gain_coeff_t {
u32 cl;
u32 fl;
};
struct opt_win_coeff_t {
u32 rc;
u32 cv;
u32 ci;
};
struct lux_cal_data_t {
const struct gain_coeff_t *gain_coeff;
const struct opt_win_coeff_t *opt_win_coeff;
u32 opt_win_coeff_count;
u32 itime_cycle;
u32 mul;
};
/*
* No optical window or optical window that has flat transmittance
* from visible light to infrared light.
*/
static const struct opt_win_coeff_t def_lux_coeff[] = {
{ 260, 1290, 2733 },
{ 550, 795, 859 },
{ 1090, 510, 345 },
{ 2130, 276, 130 }
};
static const struct gain_coeff_t def_gain_coeff[] = {
{ 3000, -1 }, /* 1x */
{ 2000, 9800 }, /* 2x */
{ 15, 60000 }, /* 64x */
{ 0, 1300 } /* 128x */
};
static const struct lux_cal_data_t def_lux_data = {
.gain_coeff = def_gain_coeff,
.opt_win_coeff = def_lux_coeff,
.opt_win_coeff_count = ARRAY_SIZE(def_lux_coeff),
.itime_cycle = BH1730_DEFAULT_INTEG_CYCLE,
.mul = 1000
};
struct bh1730_data {
struct i2c_client *client;
struct lux_cal_data_t cal;
struct regulator *reg_vdd;
struct regulator *reg_vid;
enum bh1730_gain gain;
bool powered;
u32 itime_us;
u32 tmt_us;
};
static int bh1730_read_word(struct bh1730_data *bh1730, u8 reg)
{
int ret = i2c_smbus_read_word_data(bh1730->client,
BH1730_CMD_BIT | reg);
if (ret < 0)
dev_err(&bh1730->client->dev,
"i2c read failed error %d, register %01x\n",
ret, reg);
return ret;
}
static int bh1730_write(struct bh1730_data *bh1730, u8 reg, u8 val)
{
int ret = i2c_smbus_write_byte_data(bh1730->client,
BH1730_CMD_BIT | reg,
val);
if (ret < 0)
dev_err(&bh1730->client->dev,
"i2c write failed error %d, register %01x\n",
ret, reg);
return ret;
}
static int bh1730_gain_multiplier(struct bh1730_data *bh1730)
{
switch (bh1730->gain) {
case BH1730_GAIN_1X:
return 1;
case BH1730_GAIN_2X:
return 2;
case BH1730_GAIN_64X:
return 64;
case BH1730_GAIN_128X:
return 128;
}
dev_warn(&bh1730->client->dev,
"invalid gain multiplier settings: %d\n", bh1730->gain);
bh1730->gain = BH1730_GAIN_1X;
return 1;
}
static int bh1730_set_gain(struct bh1730_data *bh1730, enum bh1730_gain gain)
{
int ret = bh1730_write(bh1730, BH1730_REG_GAIN, gain);
if (ret < 0)
return ret;
bh1730->gain = gain;
return 0;
}
static int bh1730_set_integration_time_cycle(struct bh1730_data *bh1730,
u32 cycle)
{
int ret, itime;
itime = 256 - cycle;
/* ITIME == 0 is reserved for manual integration mode. */
if (itime <= 0 || itime > 255) {
dev_warn(&bh1730->client->dev,
"integration time out of range: %d cycles\n", cycle);
return -ERANGE;
}
ret = bh1730_write(bh1730, BH1730_REG_TIMING, itime);
if (ret < 0)
return ret;
bh1730->itime_us = BH1730_ITIME_TO_US * cycle;
bh1730->tmt_us = bh1730->itime_us + BH1730_ADC_CALC_DELAY_US;
return 0;
}
static int bh1730_adjust_gain(struct bh1730_data *bh1730)
{
int visible, ir, highest, gain, ret;
visible = bh1730_read_word(bh1730, BH1730_REG_DATA0LOW);
if (visible < 0)
return visible;
ir = bh1730_read_word(bh1730, BH1730_REG_DATA1LOW);
if (ir < 0)
return ir;
highest = max(visible, ir);
/* Adjust gain based on sensitivity calibration */
gain = bh1730->gain;
if (highest > bh1730->cal.gain_coeff[gain].fl &&
gain != BH1730_GAIN_1X) {
gain--; /* Decrease sensitivity */
} else if (highest < bh1730->cal.gain_coeff[gain].cl &&
gain != BH1730_GAIN_128X) {
gain++; /* Increase sensitivity */
}
if (gain != bh1730->gain) {
ret = bh1730_set_gain(bh1730, gain);
if (ret < 0)
return ret;
fsleep(bh1730->tmt_us);
}
return 0;
}
static int bh1730_get_lux(struct bh1730_data *bh1730)
{
const struct opt_win_coeff_t *opt_win_coeff;
int i, visible, ir;
u64 lux = 0;
visible = bh1730_read_word(bh1730, BH1730_REG_DATA0LOW);
/* If visible is 0, skip calculations */
if (visible <= 0)
return visible;
ir = bh1730_read_word(bh1730, BH1730_REG_DATA1LOW);
if (ir < 0)
return ir;
/* Calibrate based on optical window */
for (i = 0; i < bh1730->cal.opt_win_coeff_count; i++) {
opt_win_coeff = &bh1730->cal.opt_win_coeff[i];
if (1000 * ir / visible < opt_win_coeff->rc) {
lux = ((u64)opt_win_coeff->cv * visible) -
(opt_win_coeff->ci * ir);
break;
}
}
/* Calculate lux */
lux *= BH1730_DEFAULT_ITIME_MS;
lux = div_u64(lux, bh1730_gain_multiplier(bh1730) * bh1730->itime_us);
lux = div_u64(lux * bh1730->cal.mul, 1000);
if (lux > BH1730_MAX_MEASURED_LUX)
lux = BH1730_MAX_MEASURED_LUX;
return (int)lux;
}
static int bh1730_power_ctrl(struct bh1730_data *bh1730, bool enable)
{
struct device *dev = &bh1730->client->dev;
int ret;
if (bh1730->powered == enable)
return 0;
if (enable) {
ret = regulator_enable(bh1730->reg_vdd);
if (ret) {
dev_err(dev, "failed to enable vdd: %d\n", ret);
return ret;
}
ret = regulator_enable(bh1730->reg_vid);
if (ret) {
dev_err(dev, "failed to enable vid: %d\n", ret);
regulator_disable(bh1730->reg_vdd);
return ret;
}
fsleep(BH1730_POWER_ON_DELAY_US);
} else {
regulator_disable(bh1730->reg_vid);
regulator_disable(bh1730->reg_vdd);
}
bh1730->powered = enable;
return 0;
}
static int bh1730_power_on(struct bh1730_data *bh1730)
{
int ret = bh1730_power_ctrl(bh1730, true);
if (ret < 0)
return ret;
return bh1730_write(bh1730, BH1730_REG_CONTROL,
BH1730_CONTROL_POWER | BH1730_CONTROL_ADC_EN);
}
static int bh1730_init_config(struct bh1730_data *bh1730)
{
int ret;
ret = bh1730_set_gain(bh1730, BH1730_GAIN_64X);
if (ret < 0)
return ret;
return bh1730_set_integration_time_cycle(bh1730,
bh1730->cal.itime_cycle);
}
static int bh1730_power_off(struct bh1730_data *bh1730)
{
int ret = bh1730_write(bh1730, BH1730_REG_CONTROL, 0);
if (ret < 0)
return ret;
return bh1730_power_ctrl(bh1730, false);
}
static int bh1730_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct bh1730_data *bh1730 = iio_priv(indio_dev);
int data_reg, ret;
ret = bh1730_adjust_gain(bh1730);
if (ret < 0)
return ret;
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
ret = bh1730_get_lux(bh1730);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_RAW:
switch (chan->channel2) {
case IIO_MOD_LIGHT_CLEAR:
data_reg = BH1730_REG_DATA0LOW;
break;
case IIO_MOD_LIGHT_IR:
data_reg = BH1730_REG_DATA1LOW;
break;
default:
return -EINVAL;
}
ret = bh1730_read_word(bh1730, data_reg);
if (ret < 0)
return ret;
ret = ret * 1000 / bh1730_gain_multiplier(bh1730);
*val = ret / 1000;
*val2 = (ret % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_INT_TIME:
*val = 0;
*val2 = bh1730->itime_us;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static int bh1730_parse_dt(struct bh1730_data *bh1730)
{
struct device *dev = &bh1730->client->dev;
struct device_node *dn = dev->of_node;
u32 *opt_win_coeff = NULL;
u32 *gain_coeff = NULL;
int opt_win_coeff_count, gain_coeff_count;
u32 cycle = 0, mul = 0;
bh1730->cal = def_lux_data;
bh1730->reg_vdd = devm_regulator_get(dev, "als-vdd");
if (IS_ERR(bh1730->reg_vdd))
return dev_err_probe(dev, PTR_ERR(bh1730->reg_vdd),
"failed to get als-vdd\n");
bh1730->reg_vid = devm_regulator_get(dev, "als-vid");
if (IS_ERR(bh1730->reg_vid))
return dev_err_probe(dev, PTR_ERR(bh1730->reg_vid),
"failed to get als-vid\n");
if (!dn)
goto out;
/* Get calibration */
if (of_property_read_u32(dn, "rohm,integration-cycle", &cycle) ||
of_property_read_u32(dn, "rohm,lux-multiplier", &mul) ||
!cycle || !mul)
goto out;
/* Get optical window coefficients */
opt_win_coeff_count = of_property_count_u32_elems(dn, "rohm,opt-win-coeff");
if (opt_win_coeff_count > 0 &&
!(opt_win_coeff_count % (sizeof(struct opt_win_coeff_t) / sizeof(u32)))) {
opt_win_coeff = devm_kcalloc(dev, opt_win_coeff_count,
sizeof(u32), GFP_KERNEL);
if (!opt_win_coeff)
return -ENOMEM;
if (of_property_read_u32_array(dn, "rohm,opt-win-coeff",
opt_win_coeff, opt_win_coeff_count))
goto out;
}
/* Get gain sensitivity coefficients, 2 for each gain supported */
gain_coeff_count = of_property_count_u32_elems(dn, "rohm,gain-coeff");
if (gain_coeff_count == 8) {
gain_coeff = devm_kcalloc(dev, gain_coeff_count,
sizeof(u32), GFP_KERNEL);
if (!gain_coeff)
return -ENOMEM;
if (of_property_read_u32_array(dn, "rohm,gain-coeff",
gain_coeff, gain_coeff_count))
goto out;
}
if (opt_win_coeff) {
bh1730->cal.opt_win_coeff =
(const struct opt_win_coeff_t *)opt_win_coeff;
bh1730->cal.opt_win_coeff_count = opt_win_coeff_count /
(sizeof(struct opt_win_coeff_t) / sizeof(u32));
}
if (gain_coeff)
bh1730->cal.gain_coeff = (const struct gain_coeff_t *)gain_coeff;
bh1730->cal.itime_cycle = cycle;
bh1730->cal.mul = mul;
return 0;
out:
dev_info(dev, "using default calibration\n");
return 0;
}
static const struct iio_info bh1730_info = {
.read_raw = bh1730_read_raw,
};
static const struct iio_chan_spec bh1730_channels[] = {
{
.type = IIO_LIGHT,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_INT_TIME),
},
{
.type = IIO_INTENSITY,
.modified = 1,
.channel2 = IIO_MOD_LIGHT_CLEAR,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
},
{
.type = IIO_INTENSITY,
.modified = 1,
.channel2 = IIO_MOD_LIGHT_IR,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
},
};
static void bh1730_power_off_action(void *data)
{
bh1730_power_off(data);
}
static int bh1730_probe(struct i2c_client *client)
{
struct bh1730_data *bh1730;
struct iio_dev *indio_dev;
int ret;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA))
return -EOPNOTSUPP;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*bh1730));
if (!indio_dev)
return -ENOMEM;
bh1730 = iio_priv(indio_dev);
bh1730->client = client;
i2c_set_clientdata(client, indio_dev);
ret = bh1730_parse_dt(bh1730);
if (ret < 0)
return ret;
ret = bh1730_power_on(bh1730);
if (ret < 0)
return ret;
ret = devm_add_action_or_reset(&client->dev, bh1730_power_off_action,
bh1730);
if (ret)
return ret;
ret = bh1730_init_config(bh1730);
if (ret < 0)
return ret;
indio_dev->info = &bh1730_info;
indio_dev->name = "bh1730";
indio_dev->channels = bh1730_channels;
indio_dev->num_channels = ARRAY_SIZE(bh1730_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
return devm_iio_device_register(&client->dev, indio_dev);
}
static int bh1730_suspend(struct device *dev)
{
struct bh1730_data *bh1730 = iio_priv(dev_get_drvdata(dev));
return bh1730_power_off(bh1730);
}
static int bh1730_resume(struct device *dev)
{
struct bh1730_data *bh1730 = iio_priv(dev_get_drvdata(dev));
int ret;
ret = bh1730_power_on(bh1730);
if (ret < 0)
return ret;
return bh1730_init_config(bh1730);
}
static DEFINE_SIMPLE_DEV_PM_OPS(bh1730_pm_ops, bh1730_suspend, bh1730_resume);
static const struct i2c_device_id bh1730_i2c_device_id[] = {
{ BH1730_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, bh1730_i2c_device_id);
static const struct of_device_id of_bh1730_match[] = {
{ .compatible = "rohm,bh1730fvc" },
{ }
};
MODULE_DEVICE_TABLE(of, of_bh1730_match);
static struct i2c_driver bh1730_driver = {
.probe = bh1730_probe,
.driver = {
.name = BH1730_NAME,
.of_match_table = of_bh1730_match,
.pm = pm_sleep_ptr(&bh1730_pm_ops),
},
.id_table = bh1730_i2c_device_id,
};
module_i2c_driver(bh1730_driver);
MODULE_AUTHOR("CTCaer <ctcaer@gmail.com>");
MODULE_DESCRIPTION("ROHM BH1730FVC driver");
MODULE_LICENSE("GPL");
+1 -1
View File
@@ -304,7 +304,7 @@ static int seesaw_probe(struct i2c_client *client)
}
static const struct i2c_device_id seesaw_id_table[] = {
{ SEESAW_DEVICE_NAME },
{ .name = SEESAW_DEVICE_NAME },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, seesaw_id_table);
+1 -1
View File
@@ -337,7 +337,7 @@ static void as5011_remove(struct i2c_client *client)
}
static const struct i2c_device_id as5011_id[] = {
{ MODULE_DEVICE_ALIAS },
{ .name = MODULE_DEVICE_ALIAS },
{ }
};
MODULE_DEVICE_TABLE(i2c, as5011_id);
+1 -1
View File
@@ -126,7 +126,7 @@ MODULE_DEVICE_TABLE(of, of_qwiic_match);
#endif /* CONFIG_OF */
static const struct i2c_device_id qwiic_id_table[] = {
{ KBUILD_MODNAME },
{ .name = KBUILD_MODNAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, qwiic_id_table);
+2 -2
View File
@@ -842,8 +842,8 @@ static int adp5588_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(adp5588_dev_pm_ops, adp5588_suspend, adp5588_resume);
static const struct i2c_device_id adp5588_id[] = {
{ "adp5588-keys" },
{ "adp5587-keys" },
{ .name = "adp5588-keys" },
{ .name = "adp5587-keys" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adp5588_id);
+7 -7
View File
@@ -651,13 +651,13 @@ static const struct of_device_id cap11xx_dt_ids[] = {
MODULE_DEVICE_TABLE(of, cap11xx_dt_ids);
static const struct i2c_device_id cap11xx_i2c_ids[] = {
{ "cap1106", (kernel_ulong_t)&cap1106_model },
{ "cap1126", (kernel_ulong_t)&cap1126_model },
{ "cap1188", (kernel_ulong_t)&cap1188_model },
{ "cap1203", (kernel_ulong_t)&cap1203_model },
{ "cap1206", (kernel_ulong_t)&cap1206_model },
{ "cap1293", (kernel_ulong_t)&cap1293_model },
{ "cap1298", (kernel_ulong_t)&cap1298_model },
{ .name = "cap1106", .driver_data = (kernel_ulong_t)&cap1106_model },
{ .name = "cap1126", .driver_data = (kernel_ulong_t)&cap1126_model },
{ .name = "cap1188", .driver_data = (kernel_ulong_t)&cap1188_model },
{ .name = "cap1203", .driver_data = (kernel_ulong_t)&cap1203_model },
{ .name = "cap1206", .driver_data = (kernel_ulong_t)&cap1206_model },
{ .name = "cap1293", .driver_data = (kernel_ulong_t)&cap1293_model },
{ .name = "cap1298", .driver_data = (kernel_ulong_t)&cap1298_model },
{ }
};
MODULE_DEVICE_TABLE(i2c, cap11xx_i2c_ids);
+1 -1
View File
@@ -209,7 +209,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cypress_sf_pm_ops,
cypress_sf_suspend, cypress_sf_resume);
static const struct i2c_device_id cypress_sf_id_table[] = {
{ CYPRESS_SF_DEV_NAME },
{ .name = CYPRESS_SF_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, cypress_sf_id_table);
@@ -128,7 +128,7 @@ static int dir685_tk_probe(struct i2c_client *client)
}
static const struct i2c_device_id dir685_tk_id[] = {
{ "dir685tk" },
{ .name = "dir685tk" },
{ }
};
MODULE_DEVICE_TABLE(i2c, dir685_tk_id);
+1 -1
View File
@@ -788,7 +788,7 @@ static int lm8323_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(lm8323_pm_ops, lm8323_suspend, lm8323_resume);
static const struct i2c_device_id lm8323_id[] = {
{ "lm8323" },
{ .name = "lm8323" },
{ }
};
+1 -1
View File
@@ -194,7 +194,7 @@ static int lm8333_probe(struct i2c_client *client)
}
static const struct i2c_device_id lm8333_id[] = {
{ "lm8333" },
{ .name = "lm8333" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm8333_id);
+1 -1
View File
@@ -270,7 +270,7 @@ static int max7359_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(max7359_pm, max7359_suspend, max7359_resume);
static const struct i2c_device_id max7359_ids[] = {
{ "max7359" },
{ .name = "max7359" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max7359_ids);
+1 -1
View File
@@ -322,7 +322,7 @@ static int mpr_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(mpr121_touchkey_pm_ops, mpr_suspend, mpr_resume);
static const struct i2c_device_id mpr121_id[] = {
{ "mpr121_touchkey" },
{ .name = "mpr121_touchkey" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mpr121_id);
+1 -1
View File
@@ -233,7 +233,7 @@ static int qt1070_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(qt1070_pm_ops, qt1070_suspend, qt1070_resume);
static const struct i2c_device_id qt1070_id[] = {
{ "qt1070" },
{ .name = "qt1070" },
{ }
};
MODULE_DEVICE_TABLE(i2c, qt1070_id);
+1 -1
View File
@@ -393,7 +393,7 @@ static int qt2160_probe(struct i2c_client *client)
}
static const struct i2c_device_id qt2160_idtable[] = {
{ "qt2160" },
{ .name = "qt2160" },
{ }
};
+1 -1
View File
@@ -354,7 +354,7 @@ static int tca8418_keypad_probe(struct i2c_client *client)
}
static const struct i2c_device_id tca8418_id[] = {
{ "tca8418", 8418, },
{ .name = "tca8418", .driver_data = 8418 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tca8418_id);
+1 -1
View File
@@ -326,7 +326,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tm2_touchkey_pm_ops,
tm2_touchkey_suspend, tm2_touchkey_resume);
static const struct i2c_device_id tm2_touchkey_id_table[] = {
{ TM2_TOUCHKEY_DEV_NAME },
{ .name = TM2_TOUCHKEY_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, tm2_touchkey_id_table);
+7
View File
@@ -282,6 +282,13 @@ config INPUT_MAX77693_HAPTIC
To compile this driver as module, choose M here: the
module will be called max77693-haptic.
config INPUT_MAX77620_ONOFF
tristate "MAX77620 ONOFF support"
depends on MFD_MAX77620
help
Support the ONOFF block of MAX77620 PMICs as an input device
reporting power button status.
config INPUT_MAX8925_ONKEY
tristate "MAX8925 ONKEY support"
depends on MFD_MAX8925
+1
View File
@@ -55,6 +55,7 @@ obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
obj-$(CONFIG_INPUT_MAX7360_ROTARY) += max7360-rotary.o
obj-$(CONFIG_INPUT_MAX77650_ONKEY) += max77650-onkey.o
obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o
obj-$(CONFIG_INPUT_MAX77620_ONOFF) += max77620-onoff.o
obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o
obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o
obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o
+5 -5
View File
@@ -72,11 +72,11 @@ static int ad714x_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id ad714x_id[] = {
{ "ad7142_captouch" },
{ "ad7143_captouch" },
{ "ad7147_captouch" },
{ "ad7147a_captouch" },
{ "ad7148_captouch" },
{ .name = "ad7142_captouch" },
{ .name = "ad7143_captouch" },
{ .name = "ad7147_captouch" },
{ .name = "ad7147a_captouch" },
{ .name = "ad7148_captouch" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad714x_id);
+1 -1
View File
@@ -96,7 +96,7 @@ static int adxl34x_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id adxl34x_id[] = {
{ "adxl34x" },
{ .name = "adxl34x" },
{ }
};
+1 -1
View File
@@ -192,7 +192,7 @@ static void apanel_shutdown(struct i2c_client *client)
}
static const struct i2c_device_id apanel_id[] = {
{ "fujitsu_apanel" },
{ .name = "fujitsu_apanel" },
{ }
};
MODULE_DEVICE_TABLE(i2c, apanel_id);
+1 -1
View File
@@ -257,7 +257,7 @@ static const struct of_device_id atmel_captouch_of_id[] = {
MODULE_DEVICE_TABLE(of, atmel_captouch_of_id);
static const struct i2c_device_id atmel_captouch_id[] = {
{ "atmel_captouch" },
{ .name = "atmel_captouch" },
{ }
};
MODULE_DEVICE_TABLE(i2c, atmel_captouch_id);
+3 -3
View File
@@ -536,9 +536,9 @@ static int __maybe_unused bma150_resume(struct device *dev)
static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL);
static const struct i2c_device_id bma150_id[] = {
{ "bma150" },
{ "smb380" },
{ "bma023" },
{ .name = "bma150" },
{ .name = "smb380" },
{ .name = "bma023" },
{ }
};
+1 -1
View File
@@ -90,7 +90,7 @@ static const struct dev_pm_ops cma3000_i2c_pm_ops = {
};
static const struct i2c_device_id cma3000_i2c_id[] = {
{ "cma3000_d01" },
{ .name = "cma3000_d01" },
{ }
};
+1 -1
View File
@@ -1305,7 +1305,7 @@ MODULE_DEVICE_TABLE(of, da7280_of_match);
#endif
static const struct i2c_device_id da7280_i2c_id[] = {
{ "da7280", },
{ .name = "da7280" },
{ }
};
MODULE_DEVICE_TABLE(i2c, da7280_i2c_id);
+4 -4
View File
@@ -630,10 +630,10 @@ static int drv260x_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(drv260x_pm_ops, drv260x_suspend, drv260x_resume);
static const struct i2c_device_id drv260x_id[] = {
{ "drv2604" },
{ "drv2604l" },
{ "drv2605" },
{ "drv2605l" },
{ .name = "drv2604" },
{ .name = "drv2604l" },
{ .name = "drv2605" },
{ .name = "drv2605l" },
{ }
};
MODULE_DEVICE_TABLE(i2c, drv260x_id);
+1 -1
View File
@@ -281,7 +281,7 @@ static int drv2665_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(drv2665_pm_ops, drv2665_suspend, drv2665_resume);
static const struct i2c_device_id drv2665_id[] = {
{ "drv2665" },
{ .name = "drv2665" },
{ }
};
MODULE_DEVICE_TABLE(i2c, drv2665_id);
+1 -1
View File
@@ -458,7 +458,7 @@ static int drv2667_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(drv2667_pm_ops, drv2667_suspend, drv2667_resume);
static const struct i2c_device_id drv2667_id[] = {
{ "drv2667" },
{ .name = "drv2667" },
{ }
};
MODULE_DEVICE_TABLE(i2c, drv2667_id);
+1 -1
View File
@@ -525,7 +525,7 @@ static int kxtj9_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume);
static const struct i2c_device_id kxtj9_id[] = {
{ NAME },
{ .name = NAME },
{ }
};
+235
View File
@@ -0,0 +1,235 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2018 Billy Laws
* Copyright (C) 2020-2022 CTCaer
*
* Author:
* Billy Laws <blaws05@gmail.com>
* CTCaer <ctcaer@gmail.com>
*
* Description:
* ONOFF driver for MAXIM 77620 charger/power-supply.
*/
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/mfd/max77620.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#define ONOFF_IRQF 2
#define ONOFF_IRQR 3
/* MAX77620 IRQ ONOFF interrupts */
#define MAX77620_IRQ_ONOFF_MRWRN 0
#define MAX77620_IRQ_ONOFF_EN0_1SEC 1
#define MAX77620_IRQ_ONOFF_EN0_F 2
#define MAX77620_IRQ_ONOFF_EN0_R 3
#define MAX77620_IRQ_ONOFF_LID_F 4
#define MAX77620_IRQ_ONOFF_LID_R 5
#define MAX77620_IRQ_ONOFF_ACOK_F 6
#define MAX77620_IRQ_ONOFF_ACOK_R 7
struct max77620_onoff {
struct regmap *rmap;
struct input_dev *input;
int irq_f, irq_r;
unsigned int code;
bool suspended;
};
static const struct regmap_irq max77620_onoff_irqs[] = {
REGMAP_IRQ_REG(MAX77620_IRQ_ONOFF_MRWRN, 0, MAX77620_IRQ_ONOFF_MRWRN_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_ONOFF_EN0_1SEC, 0, MAX77620_IRQ_ONOFF_EN0_1SEC_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_ONOFF_EN0_F, 0, MAX77620_IRQ_ONOFF_EN0_F_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_ONOFF_EN0_R, 0, MAX77620_IRQ_ONOFF_EN0_R_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_ONOFF_LID_F, 0, MAX77620_IRQ_ONOFF_LID_F_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_ONOFF_LID_R, 0, MAX77620_IRQ_ONOFF_LID_R_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_ONOFF_ACOK_F, 0, MAX77620_IRQ_ONOFF_ACOK_F_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_ONOFF_ACOK_R, 0, MAX77620_IRQ_ONOFF_ACOK_R_MASK),
};
static struct regmap_irq_chip max77620_onoff_irq_chip = {
.name = "max77620-onoff",
.irqs = max77620_onoff_irqs,
.num_irqs = ARRAY_SIZE(max77620_onoff_irqs),
.num_regs = 1,
.irq_reg_stride = 1,
.status_base = MAX77620_REG_ONOFFIRQ,
.mask_base = MAX77620_REG_ONOFFIRQM,
};
static irqreturn_t max77620_onoff_handler(int irq, void *data)
{
struct max77620_onoff *onoff = data;
bool pressed = irq == onoff->irq_r;
/* Skip release report in suspended state */
if (onoff->suspended && !pressed)
return IRQ_HANDLED;
input_report_key(onoff->input, onoff->code, pressed);
input_sync(onoff->input);
return IRQ_HANDLED;
}
static int max77620_onoff_probe(struct platform_device *pdev)
{
struct max77620_onoff *onoff;
struct device *dev, *parent;
struct max77620_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct device_node *np;
unsigned int code;
int irq, ret;
dev = &pdev->dev;
parent = dev->parent;
onoff = devm_kzalloc(dev, sizeof(*onoff), GFP_KERNEL);
if (!onoff)
return -ENOMEM;
onoff->rmap = chip->rmap;
ret = regmap_read(onoff->rmap, MAX77620_REG_ONOFFIRQ, &code);
if (ret < 0)
dev_err(dev, "Failed to clear onoff irq: %d\n", ret);
np = of_get_child_by_name(pdev->dev.parent->of_node, "onoff");
if (np && !of_device_is_available(np))
np = NULL;
if (np)
ret = of_property_read_u32(np, "maxim,onoff-keycode",
&code);
if (!np || ret < 0)
onoff->code = KEY_POWER;
else
onoff->code = code;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
onoff->input = devm_input_allocate_device(dev);
if (!onoff->input)
return -ENOMEM;
onoff->input->name = "max77620_onoff";
onoff->input->phys = "max77620_onoff/input0";
onoff->input->id.bustype = BUS_I2C;
input_set_capability(onoff->input, EV_KEY, onoff->code);
ret = devm_regmap_add_irq_chip(&pdev->dev, onoff->rmap, irq,
IRQF_ONESHOT, -1,
&max77620_onoff_irq_chip,
&chip->onoff_irq_data);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to add onoff irq_chip %d\n", ret);
goto fail;
}
onoff->irq_r = regmap_irq_get_virq(chip->onoff_irq_data,
MAX77620_IRQ_ONOFF_EN0_R);
onoff->irq_f = regmap_irq_get_virq(chip->onoff_irq_data,
MAX77620_IRQ_ONOFF_EN0_F);
ret = devm_request_any_context_irq(dev, onoff->irq_r,
max77620_onoff_handler,
IRQF_ONESHOT, "en0-down", onoff);
if (ret < 0)
goto fail;
ret = devm_request_any_context_irq(dev, onoff->irq_f,
max77620_onoff_handler,
IRQF_ONESHOT, "en0-up", onoff);
if (ret < 0)
goto fail;
platform_set_drvdata(pdev, onoff);
input_set_drvdata(onoff->input, onoff);
device_init_wakeup(dev, 1);
ret = input_register_device(onoff->input);
fail:
return ret;
}
#ifdef CONFIG_PM_SLEEP
static int max77620_onoff_suspend(struct device *dev)
{
struct max77620_onoff *onoff = dev_get_drvdata(dev);
onoff->suspended = true;
if (device_may_wakeup(dev))
return enable_irq_wake(onoff->irq_f);
return 0;
}
static int max77620_onoff_resume(struct device *dev)
{
struct max77620_onoff *onoff = dev_get_drvdata(dev);
unsigned int val, ret;
/* Clear ON/OFF interrupts */
ret = regmap_read(onoff->rmap, MAX77620_REG_ONOFFIRQ, &val);
if (ret < 0)
dev_err(dev, "Failed to clear onoff irq: %d\n", ret);
onoff->suspended = false;
/* If ON/OFF was pressed, report it */
if (val & MAX77620_IRQ_ONOFF_EN0_R_MASK) {
input_report_key(onoff->input, onoff->code, 1);
input_sync(onoff->input);
}
/* Unconditionally release after resume */
input_report_key(onoff->input, onoff->code, 0);
input_sync(onoff->input);
if (device_may_wakeup(dev))
return disable_irq_wake(onoff->irq_f);
return 0;
}
static const struct dev_pm_ops max77620_onoff_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(max77620_onoff_suspend,
max77620_onoff_resume)
};
#endif /* CONFIG_PM_SLEEP */
static struct platform_driver max77620_onoff_driver = {
.driver = {
.name = "max77620-onoff",
#ifdef CONFIG_PM_SLEEP
.pm = &max77620_onoff_pm_ops,
#endif
},
.probe = max77620_onoff_probe,
};
static int __init max77620_onoff_init(void)
{
return platform_driver_register(&max77620_onoff_driver);
}
subsys_initcall(max77620_onoff_init);
static void __exit max77620_onoff_exit(void)
{
platform_driver_unregister(&max77620_onoff_driver);
}
module_exit(max77620_onoff_exit);
MODULE_DESCRIPTION("MAXIM 77620 ONOFF driver");
MODULE_AUTHOR("Billy Laws <blaws05@gmail.com>");
MODULE_LICENSE("GPL v2");
+1 -1
View File
@@ -200,7 +200,7 @@ static int mma8450_probe(struct i2c_client *c)
}
static const struct i2c_device_id mma8450_id[] = {
{ MMA8450_DRV_NAME },
{ .name = MMA8450_DRV_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, mma8450_id);
+1 -1
View File
@@ -189,7 +189,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(pcf8574_kp_pm_ops,
pcf8574_kp_suspend, pcf8574_kp_resume);
static const struct i2c_device_id pcf8574_kp_id[] = {
{ DRV_NAME },
{ .name = DRV_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id);
+1 -1
View File
@@ -1456,7 +1456,7 @@ static const struct dev_pm_ops cyapa_pm_ops = {
};
static const struct i2c_device_id cyapa_id_table[] = {
{ "cyapa" },
{ .name = "cyapa" },
{ }
};
MODULE_DEVICE_TABLE(i2c, cyapa_id_table);
+1 -1
View File
@@ -1407,7 +1407,7 @@ err:
static DEFINE_SIMPLE_DEV_PM_OPS(elan_pm_ops, elan_suspend, elan_resume);
static const struct i2c_device_id elan_id[] = {
{ DRIVER_NAME },
{ .name = DRIVER_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, elan_id);
+1 -1
View File
@@ -607,7 +607,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(synaptics_i2c_pm, synaptics_i2c_suspend,
synaptics_i2c_resume);
static const struct i2c_device_id synaptics_i2c_id_table[] = {
{ "synaptics_i2c" },
{ .name = "synaptics_i2c" },
{ }
};
MODULE_DEVICE_TABLE(i2c, synaptics_i2c_id_table);
+1 -1
View File
@@ -365,7 +365,7 @@ static const struct dev_pm_ops rmi_i2c_pm = {
};
static const struct i2c_device_id rmi_id[] = {
{ "rmi4_i2c" },
{ .name = "rmi4_i2c" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rmi_id);
+1 -1
View File
@@ -413,7 +413,7 @@ static const struct dev_pm_ops rmi_smb_pm = {
};
static const struct i2c_device_id rmi_id[] = {
{ "rmi4_smbus" },
{ .name = "rmi4_smbus" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rmi_id);
+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/
+2 -2
View File
@@ -42,8 +42,8 @@ static int ad7879_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id ad7879_id[] = {
{ "ad7879" },
{ "ad7889" },
{ .name = "ad7879" },
{ .name = "ad7889" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad7879_id);
+1 -1
View File
@@ -164,7 +164,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(ar1021_i2c_pm,
ar1021_i2c_suspend, ar1021_i2c_resume);
static const struct i2c_device_id ar1021_i2c_id[] = {
{ "ar1021" },
{ .name = "ar1021" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ar1021_i2c_id);
+5 -5
View File
@@ -3420,11 +3420,11 @@ MODULE_DEVICE_TABLE(acpi, mxt_acpi_id);
#endif
static const struct i2c_device_id mxt_id[] = {
{ "qt602240_ts" },
{ "atmel_mxt_ts" },
{ "atmel_mxt_tp" },
{ "maxtouch" },
{ "mXT224" },
{ .name = "qt602240_ts" },
{ .name = "atmel_mxt_ts" },
{ .name = "atmel_mxt_tp" },
{ .name = "maxtouch" },
{ .name = "mXT224" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mxt_id);
Loaded 100 of 174 files, more files were not shown because too many files have changed in this diff. Show more