diff --git a/.gitignore b/.gitignore index f6050b88e95b..705e09913dc2 100644 --- a/.gitignore +++ b/.gitignore @@ -65,6 +65,11 @@ modules.builtin # /debian/ +# +# Snap directory (make snap-pkg) +# +/snap/ + # # tar directory (make tar*-pkg) # diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 3bec49c33bbb..7f3a0728ccf2 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -228,8 +228,6 @@ isdn/ - directory with info on the Linux ISDN support, and supported cards. kbuild/ - directory with info about the kernel build process. -kernel-doc-nano-HOWTO.txt - - outdated info about kernel-doc documentation. kdump/ - directory with mini HowTo on getting the crash dump code to work. doc-guide/ @@ -346,8 +344,6 @@ prctl/ - directory with info on the priveledge control subsystem preempt-locking.txt - info on locking under a preemptive kernel. -printk-formats.txt - - how to get printk format specifiers right process/ - how to work with the mainline kernel development process. pps/ diff --git a/Documentation/ABI/stable/sysfs-bus-vmbus b/Documentation/ABI/stable/sysfs-bus-vmbus index d4077cc60d55..e46be65d0e1d 100644 --- a/Documentation/ABI/stable/sysfs-bus-vmbus +++ b/Documentation/ABI/stable/sysfs-bus-vmbus @@ -42,72 +42,93 @@ Contact: K. Y. Srinivasan Description: The 16 bit vendor ID of the device Users: tools/hv/lsvmbus and user level RDMA libraries -What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/cpu +What: /sys/bus/vmbus/devices/vmbus_*/channels/NN +Date: September. 2017 +KernelVersion: 4.14 +Contact: Stephen Hemminger +Description: Directory for per-channel information + NN is the VMBUS relid associtated with the channel. + +What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/cpu Date: September. 2017 KernelVersion: 4.14 Contact: Stephen Hemminger Description: VCPU (sub)channel is affinitized to -Users: tools/hv/lsvmbus and other debuggig tools +Users: tools/hv/lsvmbus and other debugging tools -What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/cpu +What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/cpu Date: September. 2017 KernelVersion: 4.14 Contact: Stephen Hemminger Description: VCPU (sub)channel is affinitized to -Users: tools/hv/lsvmbus and other debuggig tools +Users: tools/hv/lsvmbus and other debugging tools -What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/in_mask +What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/in_mask Date: September. 2017 KernelVersion: 4.14 Contact: Stephen Hemminger -Description: Inbound channel signaling state +Description: Host to guest channel interrupt mask Users: Debugging tools -What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/latency +What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/latency Date: September. 2017 KernelVersion: 4.14 Contact: Stephen Hemminger Description: Channel signaling latency Users: Debugging tools -What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/out_mask +What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/out_mask Date: September. 2017 KernelVersion: 4.14 Contact: Stephen Hemminger -Description: Outbound channel signaling state +Description: Guest to host channel interrupt mask Users: Debugging tools -What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/pending +What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/pending Date: September. 2017 KernelVersion: 4.14 Contact: Stephen Hemminger Description: Channel interrupt pending state Users: Debugging tools -What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/read_avail +What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/read_avail Date: September. 2017 KernelVersion: 4.14 Contact: Stephen Hemminger -Description: Bytes availabble to read +Description: Bytes available to read Users: Debugging tools -What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/write_avail +What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/write_avail Date: September. 2017 KernelVersion: 4.14 Contact: Stephen Hemminger -Description: Bytes availabble to write +Description: Bytes available to write Users: Debugging tools -What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/events +What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/events Date: September. 2017 KernelVersion: 4.14 Contact: Stephen Hemminger Description: Number of times we have signaled the host Users: Debugging tools -What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/interrupts +What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/interrupts Date: September. 2017 KernelVersion: 4.14 Contact: Stephen Hemminger Description: Number of times we have taken an interrupt (incoming) Users: Debugging tools + +What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/subchannel_id +Date: January. 2018 +KernelVersion: 4.16 +Contact: Stephen Hemminger +Description: Subchannel ID associated with VMBUS channel +Users: Debugging tools and userspace drivers + +What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/monitor_id +Date: January. 2018 +KernelVersion: 4.16 +Contact: Stephen Hemminger +Description: Monitor bit associated with channel +Users: Debugging tools and userspace drivers diff --git a/Documentation/ABI/testing/devlink-resource-mlxsw b/Documentation/ABI/testing/devlink-resource-mlxsw new file mode 100644 index 000000000000..259ed2948ec0 --- /dev/null +++ b/Documentation/ABI/testing/devlink-resource-mlxsw @@ -0,0 +1,33 @@ +What: /kvd/ +Date: 08-Jan-2018 +KernelVersion: v4.16 +Contact: mlxsw@mellanox.com +Description: The main database in the Spectrum device is a centralized + KVD database used for many of the tables used to configure + the chip including L2 FDB, L3 LPM, ECMP and more. The KVD + is divided into two sections, the first is hash-based table + and the second is a linear access table. The division + between the linear and hash-based sections is static and + require reload before the changes take effect. + +What: /kvd/linear +Date: 08-Jan-2018 +KernelVersion: v4.16 +Contact: mlxsw@mellanox.com +Description: The linear section of the KVD is managed by software as a + flat memory accessed using an index. + +What: /kvd/hash_single +Date: 08-Jan-2018 +KernelVersion: v4.16 +Contact: mlxsw@mellanox.com +Description: The hash based section of the KVD is managed by the switch + device. Used in case the key size is smaller or equal to + 64bit. + +What: /kvd/hash_double +Date: 08-Jan-2018 +KernelVersion: v4.16 +Contact: mlxsw@mellanox.com +Description: The hash based section of the KVD is managed by the switch + device. Used in case the key is larger than 64 bit. diff --git a/Documentation/ABI/testing/evm b/Documentation/ABI/testing/evm index 9578247e1792..d12cb2eae9ee 100644 --- a/Documentation/ABI/testing/evm +++ b/Documentation/ABI/testing/evm @@ -14,30 +14,46 @@ Description: generated either locally or remotely using an asymmetric key. These keys are loaded onto root's keyring using keyctl, and EVM is then enabled by - echoing a value to /evm: + echoing a value to /evm made up of the + following bits: - 1: enable HMAC validation and creation - 2: enable digital signature validation - 3: enable HMAC and digital signature validation and HMAC - creation + Bit Effect + 0 Enable HMAC validation and creation + 1 Enable digital signature validation + 2 Permit modification of EVM-protected metadata at + runtime. Not supported if HMAC validation and + creation is enabled. + 31 Disable further runtime modification of EVM policy - Further writes will be blocked if HMAC support is enabled or - if bit 32 is set: + For example: - echo 0x80000002 >/evm + echo 1 >/evm - will enable digital signature validation and block - further writes to /evm. + will enable HMAC validation and creation - Until this is done, EVM can not create or validate the - 'security.evm' xattr, but returns INTEGRITY_UNKNOWN. - Loading keys and signaling EVM should be done as early - as possible. Normally this is done in the initramfs, - which has already been measured as part of the trusted - boot. For more information on creating and loading - existing trusted/encrypted keys, refer to: + echo 0x80000003 >/evm - Documentation/security/keys/trusted-encrypted.rst. Both dracut - (via 97masterkey and 98integrity) and systemd (via + will enable HMAC and digital signature validation and + HMAC creation and disable all further modification of policy. + + echo 0x80000006 >/evm + + will enable digital signature validation, permit + modification of EVM-protected metadata and + disable all further modification of policy + + Note that once a key has been loaded, it will no longer be + possible to enable metadata modification. + + Until key loading has been signaled EVM can not create + or validate the 'security.evm' xattr, but returns + INTEGRITY_UNKNOWN. Loading keys and signaling EVM + should be done as early as possible. Normally this is + done in the initramfs, which has already been measured + as part of the trusted boot. For more information on + creating and loading existing trusted/encrypted keys, + refer to: + Documentation/security/keys/trusted-encrypted.rst. Both + dracut (via 97masterkey and 98integrity) and systemd (via core/ima-setup) have support for loading keys at boot time. diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy index e76432b9954d..2028f2d093b2 100644 --- a/Documentation/ABI/testing/ima_policy +++ b/Documentation/ABI/testing/ima_policy @@ -17,7 +17,8 @@ Description: rule format: action [condition ...] - action: measure | dont_measure | appraise | dont_appraise | audit + action: measure | dont_measure | appraise | dont_appraise | + audit | hash | dont_hash condition:= base | lsm [option] base: [[func=] [mask=] [fsmagic=] [fsuuid=] [uid=] [euid=] [fowner=]] diff --git a/Documentation/ABI/testing/rtc-cdev b/Documentation/ABI/testing/rtc-cdev new file mode 100644 index 000000000000..97447283f13b --- /dev/null +++ b/Documentation/ABI/testing/rtc-cdev @@ -0,0 +1,42 @@ +What: /dev/rtcX +Date: April 2005 +KernelVersion: 2.6.12 +Contact: linux-rtc@vger.kernel.org +Description: + The ioctl interface to drivers for real-time clocks (RTCs). + Following actions are supported: + + * RTC_RD_TIME, RTC_SET_TIME: Read or set the RTC time. Time + format is a Gregorian calendar date and 24 hour wall clock + time. + + * RTC_AIE_ON, RTC_AIE_OFF: Enable or disable the alarm interrupt + for RTCs that support alarms + + * RTC_ALM_READ, RTC_ALM_SET: Read or set the alarm time for + RTCs that support alarms. Can be set upto 24 hours in the + future. Requires a separate RTC_AIE_ON call to enable the + alarm interrupt. (Prefer to use RTC_WKALM_*) + + * RTC_WKALM_RD, RTC_WKALM_SET: For RTCs that support a more + powerful interface, which can issue alarms beyond 24 hours and + enable IRQs in the same request. + + * RTC_PIE_ON, RTC_PIE_OFF: Enable or disable the periodic + interrupt for RTCs that support periodic interrupts. + + * RTC_UIE_ON, RTC_UIE_OFF: Enable or disable the update + interrupt for RTCs that support it. + + * RTC_IRQP_READ, RTC_IRQP_SET: Read or set the frequency for + periodic interrupts for RTCs that support periodic interrupts. + Requires a separate RTC_PIE_ON call to enable the periodic + interrupts. + + The ioctl() calls supported by the older /dev/rtc interface are + also supported by the newer RTC class framework. However, + because the chips and systems are not standardized, some PC/AT + functionality might not be provided. And in the same way, some + newer features -- including those enabled by ACPI -- are exposed + by the RTC class framework, but can't be supported by the older + driver. diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 2e3f919485f4..6a5f34b4d5b9 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -32,7 +32,7 @@ Description: Description of the physical chip / device for device X. Typically a part number. -What: /sys/bus/iio/devices/iio:deviceX/timestamp_clock +What: /sys/bus/iio/devices/iio:deviceX/current_timestamp_clock KernelVersion: 4.5 Contact: linux-iio@vger.kernel.org Description: @@ -1290,7 +1290,7 @@ KernelVersion: 3.4 Contact: linux-iio@vger.kernel.org Description: Unit-less light intensity. Modifiers both and ir indicate - that measurements contains visible and infrared light + that measurements contain visible and infrared light components or just infrared light, respectively. Modifier uv indicates that measurements contain ultraviolet light components. @@ -1413,6 +1413,16 @@ Description: the available samples after the timeout expires and thus have a maximum delay guarantee. +What: /sys/bus/iio/devices/iio:deviceX/buffer/data_available +KernelVersion: 4.16 +Contact: linux-iio@vger.kernel.org +Description: + A read-only value indicating the bytes of data available in the + buffer. In the case of an output buffer, this indicates the + amount of empty space available to write data to. In the case of + an input buffer, this indicates the amount of data available for + reading. + What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_enabled KernelVersion: 4.2 Contact: linux-iio@vger.kernel.org diff --git a/Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32 b/Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32 new file mode 100644 index 000000000000..da9822309f07 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32 @@ -0,0 +1,16 @@ +What: /sys/bus/iio/devices/iio:deviceX/in_voltage_spi_clk_freq +KernelVersion: 4.14 +Contact: arnaud.pouliquen@st.com +Description: + For audio purpose only. + Used by audio driver to set/get the spi input frequency. + This is mandatory if DFSDM is slave on SPI bus, to + provide information on the SPI clock frequency during runtime + Notice that the SPI frequency should be a multiple of sample + frequency to ensure the precision. + if DFSDM input is SPI master + Reading SPI clkout frequency, + error on writing + If DFSDM input is SPI Slave: + Reading returns value previously set. + Writing value before starting conversions. \ No newline at end of file diff --git a/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd b/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd new file mode 100644 index 000000000000..0088aba4caa8 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd @@ -0,0 +1,25 @@ +What: /sys/bus/pci/drivers/xhci_hcd/.../dbc +Date: June 2017 +Contact: Lu Baolu +Description: + xHCI compatible USB host controllers (i.e. super-speed + USB3 controllers) are often implemented with the Debug + Capability (DbC). It can present a debug device which + is fully compliant with the USB framework and provides + the equivalent of a very high performance full-duplex + serial link for debug purpose. + + The DbC debug device shares a root port with xHCI host. + When the DbC is enabled, the root port will be assigned + to the Debug Capability. Otherwise, it will be assigned + to xHCI. + + Writing "enable" to this attribute will enable the DbC + functionality and the shared root port will be assigned + to the DbC device. Writing "disable" to this attribute + will disable the DbC functionality and the shared root + port will roll back to the xHCI. + + Reading this attribute gives the state of the DbC. It + can be one of the following states: disabled, enabled, + initialized, connected, configured and stalled. diff --git a/Documentation/ABI/testing/sysfs-bus-siox b/Documentation/ABI/testing/sysfs-bus-siox new file mode 100644 index 000000000000..fed7c3765a4e --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-siox @@ -0,0 +1,87 @@ +What: /sys/bus/siox/devices/siox-X/active +KernelVersion: 4.16 +Contact: Gavin Schenk , Uwe Kleine-König +Description: + On reading represents the current state of the bus. If it + contains a "0" the bus is stopped and connected devices are + expected to not do anything because their watchdog triggered. + When the file contains a "1" the bus is operated and periodically + does a push-pull cycle to write and read data from the + connected devices. + When writing a "0" or "1" the bus moves to the described state. + +What: /sys/bus/siox/devices/siox-X/device_add +KernelVersion: 4.16 +Contact: Gavin Schenk , Uwe Kleine-König +Description: + Write-only file. Write + + + + to add a new device dynamically. is the name that is used to match + to a driver (similar to the platform bus). and define + the length of the input and output shift register in bytes respectively. + defines the 4 bit device type that is check to identify connection + problems. + The new device is added to the end of the existing chain. + +What: /sys/bus/siox/devices/siox-X/device_remove +KernelVersion: 4.16 +Contact: Gavin Schenk , Uwe Kleine-König +Description: + Write-only file. A single write removes the last device in the siox chain. + +What: /sys/bus/siox/devices/siox-X/poll_interval_ns +KernelVersion: 4.16 +Contact: Gavin Schenk , Uwe Kleine-König +Description: + Defines the interval between two poll cycles in nano seconds. + Note this is rounded to jiffies on writing. On reading the current value + is returned. + +What: /sys/bus/siox/devices/siox-X-Y/connected +KernelVersion: 4.16 +Contact: Gavin Schenk , Uwe Kleine-König +Description: + Read-only value. "0" means the Yth device on siox bus X isn't "connected" i.e. + communication with it is not ensured. "1" signals a working connection. + +What: /sys/bus/siox/devices/siox-X-Y/inbytes +KernelVersion: 4.16 +Contact: Gavin Schenk , Uwe Kleine-König +Description: + Read-only value reporting the inbytes value provided to siox-X/device_add + +What: /sys/bus/siox/devices/siox-X-Y/status_errors +KernelVersion: 4.16 +Contact: Gavin Schenk , Uwe Kleine-König +Description: + Counts the number of time intervals when the read status byte doesn't yield the + expected value. + +What: /sys/bus/siox/devices/siox-X-Y/type +KernelVersion: 4.16 +Contact: Gavin Schenk , Uwe Kleine-König +Description: + Read-only value reporting the type value provided to siox-X/device_add. + +What: /sys/bus/siox/devices/siox-X-Y/watchdog +KernelVersion: 4.16 +Contact: Gavin Schenk , Uwe Kleine-König +Description: + Read-only value reporting if the watchdog of the siox device is + active. "0" means the watchdog is not active and the device is expected to + be operational. "1" means the watchdog keeps the device in reset. + +What: /sys/bus/siox/devices/siox-X-Y/watchdog_errors +KernelVersion: 4.16 +Contact: Gavin Schenk , Uwe Kleine-König +Description: + Read-only value reporting the number to time intervals when the + watchdog was active. + +What: /sys/bus/siox/devices/siox-X-Y/outbytes +KernelVersion: 4.16 +Contact: Gavin Schenk , Uwe Kleine-König +Description: + Read-only value reporting the outbytes value provided to siox-X/device_add. diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-netdev b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev new file mode 100644 index 000000000000..451af6d6768c --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev @@ -0,0 +1,45 @@ +What: /sys/class/leds//device_name +Date: Dec 2017 +KernelVersion: 4.16 +Contact: linux-leds@vger.kernel.org +Description: + Specifies the network device name to monitor. + +What: /sys/class/leds//interval +Date: Dec 2017 +KernelVersion: 4.16 +Contact: linux-leds@vger.kernel.org +Description: + Specifies the duration of the LED blink in milliseconds. + Defaults to 50 ms. + +What: /sys/class/leds//link +Date: Dec 2017 +KernelVersion: 4.16 +Contact: linux-leds@vger.kernel.org +Description: + Signal the link state of the named network device. + If set to 0 (default), the LED's normal state is off. + If set to 1, the LED's normal state reflects the link state + of the named network device. + Setting this value also immediately changes the LED state. + +What: /sys/class/leds//tx +Date: Dec 2017 +KernelVersion: 4.16 +Contact: linux-leds@vger.kernel.org +Description: + Signal transmission of data on the named network device. + If set to 0 (default), the LED will not blink on transmission. + If set to 1, the LED will blink for the milliseconds specified + in interval to signal transmission. + +What: /sys/class/leds//rx +Date: Dec 2017 +KernelVersion: 4.16 +Contact: linux-leds@vger.kernel.org +Description: + Signal reception of data on the named network device. + If set to 0 (default), the LED will not blink on reception. + If set to 1, the LED will blink for the milliseconds specified + in interval to signal reception. diff --git a/Documentation/ABI/testing/sysfs-class-net b/Documentation/ABI/testing/sysfs-class-net index 6856da99b6f7..2f1788111cd9 100644 --- a/Documentation/ABI/testing/sysfs-class-net +++ b/Documentation/ABI/testing/sysfs-class-net @@ -259,3 +259,27 @@ Contact: netdev@vger.kernel.org Description: Symbolic link to the PHY device this network device is attached to. + +What: /sys/class/net//carrier_changes +Date: Mar 2014 +KernelVersion: 3.15 +Contact: netdev@vger.kernel.org +Description: + 32-bit unsigned integer counting the number of times the link has + seen a change from UP to DOWN and vice versa + +What: /sys/class/net//carrier_up_count +Date: Jan 2018 +KernelVersion: 4.16 +Contact: netdev@vger.kernel.org +Description: + 32-bit unsigned integer counting the number of times the link has + been up + +What: /sys/class/net//carrier_down_count +Date: Jan 2018 +KernelVersion: 4.16 +Contact: netdev@vger.kernel.org +Description: + 32-bit unsigned integer counting the number of times the link has + been down diff --git a/Documentation/ABI/testing/sysfs-class-ocxl b/Documentation/ABI/testing/sysfs-class-ocxl new file mode 100644 index 000000000000..b5b1fa197592 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-ocxl @@ -0,0 +1,35 @@ +What: /sys/class/ocxl//afu_version +Date: January 2018 +Contact: linuxppc-dev@lists.ozlabs.org +Description: read only + Version of the AFU, in the format : + Reflects what is read in the configuration space of the AFU + +What: /sys/class/ocxl//contexts +Date: January 2018 +Contact: linuxppc-dev@lists.ozlabs.org +Description: read only + Number of contexts for the AFU, in the format / + where: + n: number of currently active contexts, for debug + max: maximum number of contexts supported by the AFU + +What: /sys/class/ocxl//pp_mmio_size +Date: January 2018 +Contact: linuxppc-dev@lists.ozlabs.org +Description: read only + Size of the per-process mmio area, as defined in the + configuration space of the AFU + +What: /sys/class/ocxl//global_mmio_size +Date: January 2018 +Contact: linuxppc-dev@lists.ozlabs.org +Description: read only + Size of the global mmio area, as defined in the + configuration space of the AFU + +What: /sys/class/ocxl//global_mmio_area +Date: January 2018 +Contact: linuxppc-dev@lists.ozlabs.org +Description: read/write + Give access the global mmio area for the AFU diff --git a/Documentation/ABI/testing/sysfs-class-rtc b/Documentation/ABI/testing/sysfs-class-rtc new file mode 100644 index 000000000000..cf60412882f0 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-rtc @@ -0,0 +1,91 @@ +What: /sys/class/rtc/ +Date: March 2006 +KernelVersion: 2.6.17 +Contact: linux-rtc@vger.kernel.org +Description: + The rtc/ class subdirectory belongs to the RTC subsystem. + +What: /sys/class/rtc/rtcX/ +Date: March 2006 +KernelVersion: 2.6.17 +Contact: linux-rtc@vger.kernel.org +Description: + The /sys/class/rtc/rtc{0,1,2,3,...} directories correspond + to each RTC device. + +What: /sys/class/rtc/rtcX/date +Date: March 2006 +KernelVersion: 2.6.17 +Contact: linux-rtc@vger.kernel.org +Description: + (RO) RTC-provided date in YYYY-MM-DD format + +What: /sys/class/rtc/rtcX/hctosys +Date: September 2009 +KernelVersion: 2.6.32 +Contact: linux-rtc@vger.kernel.org +Description: + (RO) 1 if the RTC provided the system time at boot via the + CONFIG_RTC_HCTOSYS kernel option, 0 otherwise + +What: /sys/class/rtc/rtcX/max_user_freq +Date: October 2007 +KernelVersion: 2.6.24 +Contact: linux-rtc@vger.kernel.org +Description: + (RW) The maximum interrupt rate an unprivileged user may request + from this RTC. + +What: /sys/class/rtc/rtcX/name +Date: March 2006 +KernelVersion: 2.6.17 +Contact: linux-rtc@vger.kernel.org +Description: + (RO) The name of the RTC corresponding to this sysfs directory + +What: /sys/class/rtc/rtcX/since_epoch +Date: March 2006 +KernelVersion: 2.6.17 +Contact: linux-rtc@vger.kernel.org +Description: + (RO) RTC-provided time as the number of seconds since the epoch + +What: /sys/class/rtc/rtcX/time +Date: March 2006 +KernelVersion: 2.6.17 +Contact: linux-rtc@vger.kernel.org +Description: + (RO) RTC-provided time in 24-hour notation (hh:mm:ss) + +What: /sys/class/rtc/rtcX/*/nvmem +Date: February 2016 +KernelVersion: 4.6 +Contact: linux-rtc@vger.kernel.org +Description: + (RW) The non volatile storage exported as a raw file, as + described in Documentation/nvmem/nvmem.txt + +What: /sys/class/rtc/rtcX/offset +Date: February 2016 +KernelVersion: 4.6 +Contact: linux-rtc@vger.kernel.org +Description: + (RW) The amount which the rtc clock has been adjusted in + firmware. Visible only if the driver supports clock offset + adjustment. The unit is parts per billion, i.e. The number of + clock ticks which are added to or removed from the rtc's base + clock per billion ticks. A positive value makes a day pass more + slowly, longer, and a negative value makes a day pass more + quickly. + +What: /sys/class/rtc/rtcX/wakealarm +Date: February 2007 +KernelVersion: 2.6.20 +Contact: linux-rtc@vger.kernel.org +Description: + (RW) The time at which the clock will generate a system wakeup + event. This is a one shot wakeup event, so must be reset after + wake if a daily wakeup is required. Format is seconds since the + epoch by default, or if there's a leading +, seconds in the + future, or if there is a leading +=, seconds ahead of the + current alarm. diff --git a/Documentation/ABI/testing/sysfs-devices-coredump b/Documentation/ABI/testing/sysfs-devices-coredump new file mode 100644 index 000000000000..e459368533a4 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-coredump @@ -0,0 +1,10 @@ +What: /sys/devices/.../coredump +Date: December 2017 +Contact: Arend van Spriel +Description: + The /sys/devices/.../coredump attribute is only present when the + device is bound to a driver, which provides the .coredump() + callback. The attribute is write only. Anything written to this + file will trigger the .coredump() callback. + + Available when CONFIG_DEV_COREDUMP is enabled. diff --git a/Documentation/ABI/testing/sysfs-driver-samsung-laptop b/Documentation/ABI/testing/sysfs-driver-samsung-laptop index 63c1ad0212fc..34d3a3359cf4 100644 --- a/Documentation/ABI/testing/sysfs-driver-samsung-laptop +++ b/Documentation/ABI/testing/sysfs-driver-samsung-laptop @@ -3,7 +3,7 @@ Date: January 1, 2010 KernelVersion: 2.6.33 Contact: Greg Kroah-Hartman Description: Some Samsung laptops have different "performance levels" - that are can be modified by a function key, and by this + that can be modified by a function key, and by this sysfs file. These values don't always make a whole lot of sense, but some users like to modify them to keep their fans quiet at all costs. Reading from this file diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index a7799c2fca28..d870b5514d15 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -186,3 +186,9 @@ Date: August 2017 Contact: "Jaegeuk Kim" Description: Controls sleep time of GC urgent mode + +What: /sys/fs/f2fs//readdir_ra +Date: November 2017 +Contact: "Sheng Yong" +Description: + Controls readahead inode block in readdir. diff --git a/Documentation/ABI/testing/sysfs-kernel-livepatch b/Documentation/ABI/testing/sysfs-kernel-livepatch index d5d39748382f..dac7e1e62a8b 100644 --- a/Documentation/ABI/testing/sysfs-kernel-livepatch +++ b/Documentation/ABI/testing/sysfs-kernel-livepatch @@ -33,6 +33,32 @@ Description: An attribute which indicates whether the patch is currently in transition. +What: /sys/kernel/livepatch//signal +Date: Nov 2017 +KernelVersion: 4.15.0 +Contact: live-patching@vger.kernel.org +Description: + A writable attribute that allows administrator to affect the + course of an existing transition. Writing 1 sends a fake + signal to all remaining blocking tasks. The fake signal + means that no proper signal is delivered (there is no data in + signal pending structures). Tasks are interrupted or woken up, + and forced to change their patched state. + +What: /sys/kernel/livepatch//force +Date: Nov 2017 +KernelVersion: 4.15.0 +Contact: live-patching@vger.kernel.org +Description: + A writable attribute that allows administrator to affect the + course of an existing transition. Writing 1 clears + TIF_PATCH_PENDING flag of all tasks and thus forces the tasks to + the patched or unpatched state. Administrator should not + use this feature without a clearance from a patch + distributor. Removal (rmmod) of patch modules is permanently + disabled when the feature is used. See + Documentation/livepatch/livepatch.txt for more information. + What: /sys/kernel/livepatch// Date: Nov 2014 KernelVersion: 3.19.0 diff --git a/Documentation/IRQ-domain.txt b/Documentation/IRQ-domain.txt index 4a1cd7645d85..507775cce753 100644 --- a/Documentation/IRQ-domain.txt +++ b/Documentation/IRQ-domain.txt @@ -265,37 +265,5 @@ support other architectures, such as ARM, ARM64 etc. === Debugging === -If you switch on CONFIG_IRQ_DOMAIN_DEBUG (which depends on -CONFIG_IRQ_DOMAIN and CONFIG_DEBUG_FS), you will find a new file in -your debugfs mount point, called irq_domain_mapping. This file -contains a live snapshot of all the IRQ domains in the system: - - name mapped linear-max direct-max devtree-node - pl061 8 8 0 /smb/gpio@e0080000 - pl061 8 8 0 /smb/gpio@e1050000 - pMSI 0 0 0 /interrupt-controller@e1101000/v2m@e0080000 - MSI 37 0 0 /interrupt-controller@e1101000/v2m@e0080000 - GICv2m 37 0 0 /interrupt-controller@e1101000/v2m@e0080000 - GICv2 448 448 0 /interrupt-controller@e1101000 - -it also iterates over the interrupts to display their mapping in the -domains, and makes the domain stacking visible: - - -irq hwirq chip name chip data active type domain - 1 0x00019 GICv2 0xffff00000916bfd8 * LINEAR GICv2 - 2 0x0001d GICv2 0xffff00000916bfd8 LINEAR GICv2 - 3 0x0001e GICv2 0xffff00000916bfd8 * LINEAR GICv2 - 4 0x0001b GICv2 0xffff00000916bfd8 * LINEAR GICv2 - 5 0x0001a GICv2 0xffff00000916bfd8 LINEAR GICv2 -[...] - 96 0x81808 MSI 0x (null) RADIX MSI - 96+ 0x00063 GICv2m 0xffff8003ee116980 RADIX GICv2m - 96+ 0x00063 GICv2 0xffff00000916bfd8 LINEAR GICv2 - 97 0x08800 MSI 0x (null) * RADIX MSI - 97+ 0x00064 GICv2m 0xffff8003ee116980 * RADIX GICv2m - 97+ 0x00064 GICv2 0xffff00000916bfd8 * LINEAR GICv2 - -Here, interrupts 1-5 are only using a single domain, while 96 and 97 -are build out of a stack of three domain, each level performing a -particular function. +Most of the internals of the IRQ subsystem are exposed in debugfs by +turning CONFIG_GENERIC_IRQ_DEBUGFS on. diff --git a/Documentation/RCU/Design/Data-Structures/Data-Structures.html b/Documentation/RCU/Design/Data-Structures/Data-Structures.html index 38d6d800761f..6c06e10bd04b 100644 --- a/Documentation/RCU/Design/Data-Structures/Data-Structures.html +++ b/Documentation/RCU/Design/Data-Structures/Data-Structures.html @@ -1097,7 +1097,8 @@ will cause the CPU to disregard the values of its counters on its next exit from idle. Finally, the rcu_qs_ctr_snap field is used to detect cases where a given operation has resulted in a quiescent state -for all flavors of RCU, for example, cond_resched_rcu_qs(). +for all flavors of RCU, for example, cond_resched() +when RCU has indicated a need for quiescent states.
RCU Callback Handling
@@ -1182,8 +1183,8 @@ CPU (and from tracing) unless otherwise stated. Its fields are as follows:
-  1   int dynticks_nesting;
-  2   int dynticks_nmi_nesting;
+  1   long dynticks_nesting;
+  2   long dynticks_nmi_nesting;
   3   atomic_t dynticks;
   4   bool rcu_need_heavy_qs;
   5   unsigned long rcu_qs_ctr;
@@ -1191,15 +1192,31 @@ Its fields are as follows:
 

The ->dynticks_nesting field counts the -nesting depth of normal interrupts. -In addition, this counter is incremented when exiting dyntick-idle -mode and decremented when entering it. +nesting depth of process execution, so that in normal circumstances +this counter has value zero or one. +NMIs, irqs, and tracers are counted by the ->dynticks_nmi_nesting +field. +Because NMIs cannot be masked, changes to this variable have to be +undertaken carefully using an algorithm provided by Andy Lutomirski. +The initial transition from idle adds one, and nested transitions +add two, so that a nesting level of five is represented by a +->dynticks_nmi_nesting value of nine. This counter can therefore be thought of as counting the number of reasons why this CPU cannot be permitted to enter dyntick-idle -mode, aside from non-maskable interrupts (NMIs). -NMIs are counted by the ->dynticks_nmi_nesting -field, except that NMIs that interrupt non-dyntick-idle execution -are not counted. +mode, aside from process-level transitions. + +

However, it turns out that when running in non-idle kernel context, +the Linux kernel is fully capable of entering interrupt handlers that +never exit and perhaps also vice versa. +Therefore, whenever the ->dynticks_nesting field is +incremented up from zero, the ->dynticks_nmi_nesting field +is set to a large positive number, and whenever the +->dynticks_nesting field is decremented down to zero, +the the ->dynticks_nmi_nesting field is set to zero. +Assuming that the number of misnested interrupts is not sufficient +to overflow the counter, this approach corrects the +->dynticks_nmi_nesting field every time the corresponding +CPU enters the idle loop from process context.

The ->dynticks field counts the corresponding CPU's transitions to and from dyntick-idle mode, so that this counter @@ -1231,14 +1248,16 @@ in response.   Quick Quiz: - Why not just count all NMIs? - Wouldn't that be simpler and less error prone? + Why not simply combine the ->dynticks_nesting + and ->dynticks_nmi_nesting counters into a + single counter that just counts the number of reasons that + the corresponding CPU is non-idle? Answer: - It seems simpler only until you think hard about how to go about - updating the rcu_dynticks structure's - ->dynticks field. + Because this would fail in the presence of interrupts whose + handlers never return and of handlers that manage to return + from a made-up interrupt.   diff --git a/Documentation/RCU/Design/Requirements/Requirements.html b/Documentation/RCU/Design/Requirements/Requirements.html index 62e847bcdcdd..49690228b1c6 100644 --- a/Documentation/RCU/Design/Requirements/Requirements.html +++ b/Documentation/RCU/Design/Requirements/Requirements.html @@ -581,7 +581,8 @@ This guarantee was only partially premeditated. DYNIX/ptx used an explicit memory barrier for publication, but had nothing resembling rcu_dereference() for subscription, nor did it have anything resembling the smp_read_barrier_depends() -that was later subsumed into rcu_dereference(). +that was later subsumed into rcu_dereference() and later +still into READ_ONCE(). The need for these operations made itself known quite suddenly at a late-1990s meeting with the DEC Alpha architects, back in the days when DEC was still a free-standing company. @@ -2797,7 +2798,7 @@ RCU must avoid degrading real-time response for CPU-bound threads, whether executing in usermode (which is one use case for CONFIG_NO_HZ_FULL=y) or in the kernel. That said, CPU-bound loops in the kernel must execute -cond_resched_rcu_qs() at least once per few tens of milliseconds +cond_resched() at least once per few tens of milliseconds in order to avoid receiving an IPI from RCU.

@@ -3128,7 +3129,7 @@ The solution, in the form of is to have implicit read-side critical sections that are delimited by voluntary context switches, that is, calls to schedule(), -cond_resched_rcu_qs(), and +cond_resched(), and synchronize_rcu_tasks(). In addition, transitions to and from userspace execution also delimit tasks-RCU read-side critical sections. diff --git a/Documentation/RCU/rcu_dereference.txt b/Documentation/RCU/rcu_dereference.txt index 1acb26b09b48..ab96227bad42 100644 --- a/Documentation/RCU/rcu_dereference.txt +++ b/Documentation/RCU/rcu_dereference.txt @@ -122,11 +122,7 @@ o Be very careful about comparing pointers obtained from Note that if checks for being within an RCU read-side critical section are not required and the pointer is never dereferenced, rcu_access_pointer() should be used in place - of rcu_dereference(). The rcu_access_pointer() primitive - does not require an enclosing read-side critical section, - and also omits the smp_read_barrier_depends() included in - rcu_dereference(), which in turn should provide a small - performance gain in some CPUs (e.g., the DEC Alpha). + of rcu_dereference(). o The comparison is against a pointer that references memory that was initialized "a long time ago." The reason diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt index a08f928c8557..4259f95c3261 100644 --- a/Documentation/RCU/stallwarn.txt +++ b/Documentation/RCU/stallwarn.txt @@ -23,12 +23,10 @@ o A CPU looping with preemption disabled. This condition can o A CPU looping with bottom halves disabled. This condition can result in RCU-sched and RCU-bh stalls. -o For !CONFIG_PREEMPT kernels, a CPU looping anywhere in the - kernel without invoking schedule(). Note that cond_resched() - does not necessarily prevent RCU CPU stall warnings. Therefore, - if the looping in the kernel is really expected and desirable - behavior, you might need to replace some of the cond_resched() - calls with calls to cond_resched_rcu_qs(). +o For !CONFIG_PREEMPT kernels, a CPU looping anywhere in the kernel + without invoking schedule(). If the looping in the kernel is + really expected and desirable behavior, you might need to add + some calls to cond_resched(). o Booting Linux using a console connection that is too slow to keep up with the boot-time console-message rate. For example, diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt index df62466da4e0..a27fbfb0efb8 100644 --- a/Documentation/RCU/whatisRCU.txt +++ b/Documentation/RCU/whatisRCU.txt @@ -600,8 +600,7 @@ don't forget about them when submitting patches making use of RCU!] #define rcu_dereference(p) \ ({ \ - typeof(p) _________p1 = p; \ - smp_read_barrier_depends(); \ + typeof(p) _________p1 = READ_ONCE(p); \ (_________p1); \ }) diff --git a/Documentation/accelerators/ocxl.rst b/Documentation/accelerators/ocxl.rst new file mode 100644 index 000000000000..4f7af841d935 --- /dev/null +++ b/Documentation/accelerators/ocxl.rst @@ -0,0 +1,160 @@ +======================================================== +OpenCAPI (Open Coherent Accelerator Processor Interface) +======================================================== + +OpenCAPI is an interface between processors and accelerators. It aims +at being low-latency and high-bandwidth. The specification is +developed by the `OpenCAPI Consortium `_. + +It allows an accelerator (which could be a FPGA, ASICs, ...) to access +the host memory coherently, using virtual addresses. An OpenCAPI +device can also host its own memory, that can be accessed from the +host. + +OpenCAPI is known in linux as 'ocxl', as the open, processor-agnostic +evolution of 'cxl' (the driver for the IBM CAPI interface for +powerpc), which was named that way to avoid confusion with the ISDN +CAPI subsystem. + + +High-level view +=============== + +OpenCAPI defines a Data Link Layer (DL) and Transaction Layer (TL), to +be implemented on top of a physical link. Any processor or device +implementing the DL and TL can start sharing memory. + +:: + + +-----------+ +-------------+ + | | | | + | | | Accelerated | + | Processor | | Function | + | | +--------+ | Unit | +--------+ + | |--| Memory | | (AFU) |--| Memory | + | | +--------+ | | +--------+ + +-----------+ +-------------+ + | | + +-----------+ +-------------+ + | TL | | TLX | + +-----------+ +-------------+ + | | + +-----------+ +-------------+ + | DL | | DLX | + +-----------+ +-------------+ + | | + | PHY | + +---------------------------------------+ + + + +Device discovery +================ + +OpenCAPI relies on a PCI-like configuration space, implemented on the +device. So the host can discover AFUs by querying the config space. + +OpenCAPI devices in Linux are treated like PCI devices (with a few +caveats). The firmware is expected to abstract the hardware as if it +was a PCI link. A lot of the existing PCI infrastructure is reused: +devices are scanned and BARs are assigned during the standard PCI +enumeration. Commands like 'lspci' can therefore be used to see what +devices are available. + +The configuration space defines the AFU(s) that can be found on the +physical adapter, such as its name, how many memory contexts it can +work with, the size of its MMIO areas, ... + + + +MMIO +==== + +OpenCAPI defines two MMIO areas for each AFU: + +* the global MMIO area, with registers pertinent to the whole AFU. +* a per-process MMIO area, which has a fixed size for each context. + + + +AFU interrupts +============== + +OpenCAPI includes the possibility for an AFU to send an interrupt to a +host process. It is done through a 'intrp_req' defined in the +Transaction Layer, specifying a 64-bit object handle which defines the +interrupt. + +The driver allows a process to allocate an interrupt and obtain its +64-bit object handle, that can be passed to the AFU. + + + +char devices +============ + +The driver creates one char device per AFU found on the physical +device. A physical device may have multiple functions and each +function can have multiple AFUs. At the time of this writing though, +it has only been tested with devices exporting only one AFU. + +Char devices can be found in /dev/ocxl/ and are named as: +/dev/ocxl/.. + +where is a max 20-character long name, as found in the +config space of the AFU. + is added by the driver and can help distinguish devices +when a system has more than one instance of the same OpenCAPI device. + is also to help distinguish AFUs in the unlikely case where a +device carries multiple copies of the same AFU. + + + +Sysfs class +=========== + +An ocxl class is added for the devices representing the AFUs. See +/sys/class/ocxl. The layout is described in +Documentation/ABI/testing/sysfs-class-ocxl + + + +User API +======== + +open +---- + +Based on the AFU definition found in the config space, an AFU may +support working with more than one memory context, in which case the +associated char device may be opened multiple times by different +processes. + + +ioctl +----- + +OCXL_IOCTL_ATTACH: + + Attach the memory context of the calling process to the AFU so that + the AFU can access its memory. + +OCXL_IOCTL_IRQ_ALLOC: + + Allocate an AFU interrupt and return an identifier. + +OCXL_IOCTL_IRQ_FREE: + + Free a previously allocated AFU interrupt. + +OCXL_IOCTL_IRQ_SET_FD: + + Associate an event fd to an AFU interrupt so that the user process + can be notified when the AFU sends an interrupt. + + +mmap +---- + +A process can mmap the per-process MMIO area for interactions with the +AFU. diff --git a/Documentation/admin-guide/README.rst b/Documentation/admin-guide/README.rst index 63066db39910..af5a437198d0 100644 --- a/Documentation/admin-guide/README.rst +++ b/Documentation/admin-guide/README.rst @@ -170,11 +170,6 @@ Configuring the kernel your existing ./.config file and asking about new config symbols. - "make silentoldconfig" - Like above, but avoids cluttering the screen - with questions already answered. - Additionally updates the dependencies. - "make olddefconfig" Like above, but sets new symbols to their default values without prompting. diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 46b26bfee27b..1d1d53f85ddd 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -114,7 +114,6 @@ This facility can be used to prevent such uncontrolled GPE floodings. Format: - Support masking of GPEs numbered from 0x00 to 0x7f. acpi_no_auto_serialize [HW,ACPI] Disable auto-serialization of AML methods @@ -223,7 +222,7 @@ acpi_sleep= [HW,ACPI] Sleep options Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, - old_ordering, nonvs, sci_force_enable } + old_ordering, nonvs, sci_force_enable, nobl } See Documentation/power/video.txt for information on s3_bios and s3_mode. s3_beep is for debugging; it makes the PC's speaker beep @@ -239,6 +238,9 @@ sci_force_enable causes the kernel to set SCI_EN directly on resume from S1/S3 (which is against the ACPI spec, but some broken systems don't work without it). + nobl causes the internal blacklist of systems known to + behave incorrectly in some ways with respect to system + suspend and resume to be ignored (use wisely). acpi_use_timer_override [HW,ACPI] Use timer override. For some broken Nvidia NF5 boards @@ -644,6 +646,20 @@ console=brl,ttyS0 For now, only VisioBraille is supported. + console_msg_format= + [KNL] Change console messages format + default + By default we print messages on consoles in + "[time stamp] text\n" format (time stamp may not be + printed, depending on CONFIG_PRINTK_TIME or + `printk_time' param). + syslog + Switch to syslog format: "<%u>[time stamp] text\n" + IOW, each message will have a facility and loglevel + prefix. The format is similar to one used by syslog() + syscall, or to executing "dmesg -S --raw" or to reading + from /proc/kmsg. + consoleblank= [KNL] The console blank (screen saver) timeout in seconds. A value of 0 disables the blank timer. Defaults to 0. @@ -915,9 +931,12 @@ earlycon= [KNL] Output early console device and options. - When used with no options, the early console is - determined by the stdout-path property in device - tree's chosen node. + [ARM64] The early console is determined by the + stdout-path property in device tree's chosen node, + or determined by the ACPI SPCR table. + + [X86] When used with no options the early console is + determined by the ACPI SPCR table. cdns,[,options] Start an early, polled-mode console on a Cadence @@ -2050,9 +2069,6 @@ This tests the locking primitive's ability to transition abruptly to and from idle. - locktorture.torture_runnable= [BOOT] - Start locktorture running at boot time. - locktorture.torture_type= [KNL] Specify the locking implementation to test. @@ -2539,6 +2555,9 @@ This is useful when you use a panic=... timeout and need the box quickly up again. + These settings can be accessed at runtime via + the nmi_watchdog and hardlockup_panic sysctls. + netpoll.carrier_timeout= [NET] Specifies amount of time (in seconds) that netpoll should wait for a carrier. By default netpoll @@ -2742,8 +2761,6 @@ norandmaps Don't use address space randomization. Equivalent to echo 0 > /proc/sys/kernel/randomize_va_space - noreplace-paravirt [X86,IA-64,PV_OPS] Don't patch paravirt_ops - noreplace-smp [X86-32,SMP] Don't replace SMP instructions with UP alternatives @@ -3486,9 +3503,6 @@ the same as for rcuperf.nreaders. N, where N is the number of CPUs - rcuperf.perf_runnable= [BOOT] - Start rcuperf running at boot time. - rcuperf.perf_type= [KNL] Specify the RCU implementation to test. @@ -3622,9 +3636,6 @@ Test RCU's dyntick-idle handling. See also the rcutorture.shuffle_interval parameter. - rcutorture.torture_runnable= [BOOT] - Start rcutorture running at boot time. - rcutorture.torture_type= [KNL] Specify the RCU implementation to test. @@ -3682,7 +3693,8 @@ rdt= [HW,X86,RDT] Turn on/off individual RDT features. List is: - cmt, mbmtotal, mbmlocal, l3cat, l3cdp, l2cat, mba. + cmt, mbmtotal, mbmlocal, l3cat, l3cdp, l2cat, l2cdp, + mba. E.g. to turn on cmt and turn off mba use: rdt=cmt,!mba @@ -3702,7 +3714,11 @@ [KNL, SMP] Set scheduler's default relax_domain_level. See Documentation/cgroup-v1/cpusets.txt. - reserve= [KNL,BUGS] Force the kernel to ignore some iomem area + reserve= [KNL,BUGS] Force kernel to ignore I/O ports or memory + Format: ,[,,,...] + Reserve I/O ports or memory so the kernel won't use + them. If is less than 0x10000, the region + is assumed to be I/O ports; otherwise it is memory. reservetop= [X86-32] Format: nn[KMG] diff --git a/Documentation/admin-guide/mono.rst b/Documentation/admin-guide/mono.rst index cdddc099af64..59e6d59f0ed9 100644 --- a/Documentation/admin-guide/mono.rst +++ b/Documentation/admin-guide/mono.rst @@ -9,14 +9,14 @@ This will allow you to execute Mono-based .NET binaries just like any other program after you have done the following: 1) You MUST FIRST install the Mono CLR support, either by downloading - a binary package, a source tarball or by installing from CVS. Binary + a binary package, a source tarball or by installing from Git. Binary packages for several distributions can be found at: - http://go-mono.com/download.html + http://www.mono-project.com/download/ Instructions for compiling Mono can be found at: - http://www.go-mono.com/compiling.html + http://www.mono-project.com/docs/compiling-mono/linux/ Once the Mono CLR support has been installed, just check that ``/usr/bin/mono`` (which could be located elsewhere, for example diff --git a/Documentation/admin-guide/thunderbolt.rst b/Documentation/admin-guide/thunderbolt.rst index 9b55952039a6..9948ec36a204 100644 --- a/Documentation/admin-guide/thunderbolt.rst +++ b/Documentation/admin-guide/thunderbolt.rst @@ -3,13 +3,13 @@ ============= The interface presented here is not meant for end users. Instead there should be a userspace tool that handles all the low-level details, keeps -database of the authorized devices and prompts user for new connections. +a database of the authorized devices and prompts users for new connections. More details about the sysfs interface for Thunderbolt devices can be found in ``Documentation/ABI/testing/sysfs-bus-thunderbolt``. Those users who just want to connect any device without any sort of -manual work, can add following line to +manual work can add following line to ``/etc/udev/rules.d/99-local.rules``:: ACTION=="add", SUBSYSTEM=="thunderbolt", ATTR{authorized}=="0", ATTR{authorized}="1" @@ -20,7 +20,7 @@ vulnerable to DMA attacks. Security levels and how to use them ----------------------------------- -Starting from Intel Falcon Ridge Thunderbolt controller there are 4 +Starting with Intel Falcon Ridge Thunderbolt controller there are 4 security levels available. The reason for these is the fact that the connected devices can be DMA masters and thus read contents of the host memory without CPU and OS knowing about it. There are ways to prevent @@ -37,14 +37,14 @@ The security levels are as follows: user User is asked whether the device is allowed to be connected. Based on the device identification information available through - ``/sys/bus/thunderbolt/devices``. user then can do the decision. + ``/sys/bus/thunderbolt/devices``, the user then can make the decision. In BIOS settings this is typically called *Unique ID*. secure User is asked whether the device is allowed to be connected. In addition to UUID the device (if it supports secure connect) is sent a challenge that should match the expected one based on a random key - written to ``key`` sysfs attribute. In BIOS settings this is + written to the ``key`` sysfs attribute. In BIOS settings this is typically called *One time saved key*. dponly @@ -78,7 +78,7 @@ When a device is plugged in it will appear in sysfs as follows:: /sys/bus/thunderbolt/devices/0-1/unique_id - e0376f00-0300-0100-ffff-ffffffffffff The ``authorized`` attribute reads 0 which means no PCIe tunnels are -created yet. The user can authorize the device by simply:: +created yet. The user can authorize the device by simply entering:: # echo 1 > /sys/bus/thunderbolt/devices/0-1/authorized @@ -86,7 +86,7 @@ This will create the PCIe tunnels and the device is now connected. If the device supports secure connect, and the domain security level is set to ``secure``, it has an additional attribute ``key`` which can hold -a random 32 byte value used for authorization and challenging the device in +a random 32-byte value used for authorization and challenging the device in future connects:: /sys/bus/thunderbolt/devices/0-3/authorized - 0 @@ -99,12 +99,12 @@ future connects:: Notice the key is empty by default. -If the user does not want to use secure connect it can just ``echo 1`` +If the user does not want to use secure connect they can just ``echo 1`` to the ``authorized`` attribute and the PCIe tunnels will be created in -the same way than in ``user`` security level. +the same way as in the ``user`` security level. If the user wants to use secure connect, the first time the device is -plugged a key needs to be created and send to the device:: +plugged a key needs to be created and sent to the device:: # key=$(openssl rand -hex 32) # echo $key > /sys/bus/thunderbolt/devices/0-3/key @@ -121,27 +121,27 @@ device using the same key:: If the challenge the device returns back matches the one we expect based on the key, the device is connected and the PCIe tunnels are created. -However, if the challenge failed no tunnels are created and error is +However, if the challenge fails no tunnels are created and error is returned to the user. -If the user still wants to connect the device it can either approve -the device without a key or write new key and write 1 to the +If the user still wants to connect the device they can either approve +the device without a key or write a new key and write 1 to the ``authorized`` file to get the new key stored on the device NVM. Upgrading NVM on Thunderbolt device or host ------------------------------------------- -Since most of the functionality is handled in a firmware running on a +Since most of the functionality is handled in firmware running on a host controller or a device, it is important that the firmware can be upgraded to the latest where possible bugs in it have been fixed. Typically OEMs provide this firmware from their support site. -There is also a central site which has links where to download firmwares +There is also a central site which has links where to download firmware for some machines: `Thunderbolt Updates `_ -Before you upgrade firmware on a device or host, please make sure it is -the suitable. Failing to do that may render the device (or host) in a +Before you upgrade firmware on a device or host, please make sure it is a +suitable upgrade. Failing to do that may render the device (or host) in a state where it cannot be used properly anymore without special tools! Host NVM upgrade on Apple Macs is not supported. @@ -151,7 +151,7 @@ Thunderbolt device so that the host controller appears. It does not matter which device is connected (unless you are upgrading NVM on a device - then you need to connect that particular device). -Note OEM-specific method to power the controller up ("force power") may +Note an OEM-specific method to power the controller up ("force power") may be available for your system in which case there is no need to plug in a Thunderbolt device. @@ -171,7 +171,7 @@ it comes back the driver notices it and initiates a full power cycle. After a while the host controller appears again and this time it should be fully functional. -We can verify that the new NVM firmware is active by running following +We can verify that the new NVM firmware is active by running the following commands:: # cat /sys/bus/thunderbolt/devices/0-0/nvm_authenticate @@ -179,38 +179,38 @@ commands:: # cat /sys/bus/thunderbolt/devices/0-0/nvm_version 18.0 -If ``nvm_authenticate`` contains anything else than 0x0 it is the error +If ``nvm_authenticate`` contains anything other than 0x0 it is the error code from the last authentication cycle, which means the authentication of the NVM image failed. Note names of the NVMem devices ``nvm_activeN`` and ``nvm_non_activeN`` -depends on the order they are registered in the NVMem subsystem. N in +depend on the order they are registered in the NVMem subsystem. N in the name is the identifier added by the NVMem subsystem. Upgrading NVM when host controller is in safe mode -------------------------------------------------- If the existing NVM is not properly authenticated (or is missing) the -host controller goes into safe mode which means that only available -functionality is flashing new NVM image. When in this mode the reading +host controller goes into safe mode which means that the only available +functionality is flashing a new NVM image. When in this mode, reading ``nvm_version`` fails with ``ENODATA`` and the device identification information is missing. To recover from this mode, one needs to flash a valid NVM image to the -host host controller in the same way it is done in the previous chapter. +host controller in the same way it is done in the previous chapter. Networking over Thunderbolt cable --------------------------------- -Thunderbolt technology allows software communication across two hosts +Thunderbolt technology allows software communication between two hosts connected by a Thunderbolt cable. -It is possible to tunnel any kind of traffic over Thunderbolt link but +It is possible to tunnel any kind of traffic over a Thunderbolt link but currently we only support Apple ThunderboltIP protocol. -If the other host is running Windows or macOS only thing you need to -do is to connect Thunderbolt cable between the two hosts, the -``thunderbolt-net`` is loaded automatically. If the other host is also -Linux you should load ``thunderbolt-net`` manually on one host (it does -not matter which one):: +If the other host is running Windows or macOS, the only thing you need to +do is to connect a Thunderbolt cable between the two hosts; the +``thunderbolt-net`` driver is loaded automatically. If the other host is +also Linux you should load ``thunderbolt-net`` manually on one host (it +does not matter which one):: # modprobe thunderbolt-net @@ -220,12 +220,12 @@ is built-in to the kernel image, there is no need to do anything. The driver will create one virtual ethernet interface per Thunderbolt port which are named like ``thunderbolt0`` and so on. From this point you can either use standard userspace tools like ``ifconfig`` to -configure the interface or let your GUI to handle it automatically. +configure the interface or let your GUI handle it automatically. Forcing power ------------- Many OEMs include a method that can be used to force the power of a -thunderbolt controller to an "On" state even if nothing is connected. +Thunderbolt controller to an "On" state even if nothing is connected. If supported by your machine this will be exposed by the WMI bus with a sysfs attribute called "force_power". diff --git a/Documentation/arm64/cpu-feature-registers.txt b/Documentation/arm64/cpu-feature-registers.txt index bd9b3faab2c4..a70090b28b07 100644 --- a/Documentation/arm64/cpu-feature-registers.txt +++ b/Documentation/arm64/cpu-feature-registers.txt @@ -110,7 +110,9 @@ infrastructure: x--------------------------------------------------x | Name | bits | visible | |--------------------------------------------------| - | RES0 | [63-48] | n | + | RES0 | [63-52] | n | + |--------------------------------------------------| + | FHM | [51-48] | y | |--------------------------------------------------| | DP | [47-44] | y | |--------------------------------------------------| diff --git a/Documentation/arm64/elf_hwcaps.txt b/Documentation/arm64/elf_hwcaps.txt index 89edba12a9e0..57324ee55ecc 100644 --- a/Documentation/arm64/elf_hwcaps.txt +++ b/Documentation/arm64/elf_hwcaps.txt @@ -158,3 +158,7 @@ HWCAP_SHA512 HWCAP_SVE Functionality implied by ID_AA64PFR0_EL1.SVE == 0b0001. + +HWCAP_ASIMDFHM + + Functionality implied by ID_AA64ISAR0_EL1.FHM == 0b0001. diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt index fc1c884fea10..c1d520de6dfe 100644 --- a/Documentation/arm64/silicon-errata.txt +++ b/Documentation/arm64/silicon-errata.txt @@ -72,7 +72,7 @@ stable kernels. | Hisilicon | Hip0{6,7} | #161010701 | N/A | | Hisilicon | Hip07 | #161600802 | HISILICON_ERRATUM_161600802 | | | | | | -| Qualcomm Tech. | Falkor v1 | E1003 | QCOM_FALKOR_ERRATUM_1003 | +| Qualcomm Tech. | Kryo/Falkor v1 | E1003 | QCOM_FALKOR_ERRATUM_1003 | | Qualcomm Tech. | Falkor v1 | E1009 | QCOM_FALKOR_ERRATUM_1009 | | Qualcomm Tech. | QDF2400 ITS | E0065 | QCOM_QDF2400_ERRATUM_0065 | | Qualcomm Tech. | Falkor v{1,2} | E1041 | QCOM_FALKOR_ERRATUM_1041 | diff --git a/Documentation/bpf/bpf_devel_QA.txt b/Documentation/bpf/bpf_devel_QA.txt new file mode 100644 index 000000000000..84cbb302f2b5 --- /dev/null +++ b/Documentation/bpf/bpf_devel_QA.txt @@ -0,0 +1,550 @@ +This document provides information for the BPF subsystem about various +workflows related to reporting bugs, submitting patches, and queueing +patches for stable kernels. + +For general information about submitting patches, please refer to +Documentation/process/. This document only describes additional specifics +related to BPF. + +Reporting bugs: +--------------- + +Q: How do I report bugs for BPF kernel code? + +A: Since all BPF kernel development as well as bpftool and iproute2 BPF + loader development happens through the netdev kernel mailing list, + please report any found issues around BPF to the following mailing + list: + + netdev@vger.kernel.org + + This may also include issues related to XDP, BPF tracing, etc. + + Given netdev has a high volume of traffic, please also add the BPF + maintainers to Cc (from kernel MAINTAINERS file): + + Alexei Starovoitov + Daniel Borkmann + + In case a buggy commit has already been identified, make sure to keep + the actual commit authors in Cc as well for the report. They can + typically be identified through the kernel's git tree. + + Please do *not* report BPF issues to bugzilla.kernel.org since it + is a guarantee that the reported issue will be overlooked. + +Submitting patches: +------------------- + +Q: To which mailing list do I need to submit my BPF patches? + +A: Please submit your BPF patches to the netdev kernel mailing list: + + netdev@vger.kernel.org + + Historically, BPF came out of networking and has always been maintained + by the kernel networking community. Although these days BPF touches + many other subsystems as well, the patches are still routed mainly + through the networking community. + + In case your patch has changes in various different subsystems (e.g. + tracing, security, etc), make sure to Cc the related kernel mailing + lists and maintainers from there as well, so they are able to review + the changes and provide their Acked-by's to the patches. + +Q: Where can I find patches currently under discussion for BPF subsystem? + +A: All patches that are Cc'ed to netdev are queued for review under netdev + patchwork project: + + http://patchwork.ozlabs.org/project/netdev/list/ + + Those patches which target BPF, are assigned to a 'bpf' delegate for + further processing from BPF maintainers. The current queue with + patches under review can be found at: + + https://patchwork.ozlabs.org/project/netdev/list/?delegate=77147 + + Once the patches have been reviewed by the BPF community as a whole + and approved by the BPF maintainers, their status in patchwork will be + changed to 'Accepted' and the submitter will be notified by mail. This + means that the patches look good from a BPF perspective and have been + applied to one of the two BPF kernel trees. + + In case feedback from the community requires a respin of the patches, + their status in patchwork will be set to 'Changes Requested', and purged + from the current review queue. Likewise for cases where patches would + get rejected or are not applicable to the BPF trees (but assigned to + the 'bpf' delegate). + +Q: How do the changes make their way into Linux? + +A: There are two BPF kernel trees (git repositories). Once patches have + been accepted by the BPF maintainers, they will be applied to one + of the two BPF trees: + + https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git/ + https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/ + + The bpf tree itself is for fixes only, whereas bpf-next for features, + cleanups or other kind of improvements ("next-like" content). This is + analogous to net and net-next trees for networking. Both bpf and + bpf-next will only have a master branch in order to simplify against + which branch patches should get rebased to. + + Accumulated BPF patches in the bpf tree will regularly get pulled + into the net kernel tree. Likewise, accumulated BPF patches accepted + into the bpf-next tree will make their way into net-next tree. net and + net-next are both run by David S. Miller. From there, they will go + into the kernel mainline tree run by Linus Torvalds. To read up on the + process of net and net-next being merged into the mainline tree, see + the netdev FAQ under: + + Documentation/networking/netdev-FAQ.txt + + Occasionally, to prevent merge conflicts, we might send pull requests + to other trees (e.g. tracing) with a small subset of the patches, but + net and net-next are always the main trees targeted for integration. + + The pull requests will contain a high-level summary of the accumulated + patches and can be searched on netdev kernel mailing list through the + following subject lines (yyyy-mm-dd is the date of the pull request): + + pull-request: bpf yyyy-mm-dd + pull-request: bpf-next yyyy-mm-dd + +Q: How do I indicate which tree (bpf vs. bpf-next) my patch should be + applied to? + +A: The process is the very same as described in the netdev FAQ, so + please read up on it. The subject line must indicate whether the + patch is a fix or rather "next-like" content in order to let the + maintainers know whether it is targeted at bpf or bpf-next. + + For fixes eventually landing in bpf -> net tree, the subject must + look like: + + git format-patch --subject-prefix='PATCH bpf' start..finish + + For features/improvements/etc that should eventually land in + bpf-next -> net-next, the subject must look like: + + git format-patch --subject-prefix='PATCH bpf-next' start..finish + + If unsure whether the patch or patch series should go into bpf + or net directly, or bpf-next or net-next directly, it is not a + problem either if the subject line says net or net-next as target. + It is eventually up to the maintainers to do the delegation of + the patches. + + If it is clear that patches should go into bpf or bpf-next tree, + please make sure to rebase the patches against those trees in + order to reduce potential conflicts. + + In case the patch or patch series has to be reworked and sent out + again in a second or later revision, it is also required to add a + version number (v2, v3, ...) into the subject prefix: + + git format-patch --subject-prefix='PATCH net-next v2' start..finish + + When changes have been requested to the patch series, always send the + whole patch series again with the feedback incorporated (never send + individual diffs on top of the old series). + +Q: What does it mean when a patch gets applied to bpf or bpf-next tree? + +A: It means that the patch looks good for mainline inclusion from + a BPF point of view. + + Be aware that this is not a final verdict that the patch will + automatically get accepted into net or net-next trees eventually: + + On the netdev kernel mailing list reviews can come in at any point + in time. If discussions around a patch conclude that they cannot + get included as-is, we will either apply a follow-up fix or drop + them from the trees entirely. Therefore, we also reserve to rebase + the trees when deemed necessary. After all, the purpose of the tree + is to i) accumulate and stage BPF patches for integration into trees + like net and net-next, and ii) run extensive BPF test suite and + workloads on the patches before they make their way any further. + + Once the BPF pull request was accepted by David S. Miller, then + the patches end up in net or net-next tree, respectively, and + make their way from there further into mainline. Again, see the + netdev FAQ for additional information e.g. on how often they are + merged to mainline. + +Q: How long do I need to wait for feedback on my BPF patches? + +A: We try to keep the latency low. The usual time to feedback will + be around 2 or 3 business days. It may vary depending on the + complexity of changes and current patch load. + +Q: How often do you send pull requests to major kernel trees like + net or net-next? + +A: Pull requests will be sent out rather often in order to not + accumulate too many patches in bpf or bpf-next. + + As a rule of thumb, expect pull requests for each tree regularly + at the end of the week. In some cases pull requests could additionally + come also in the middle of the week depending on the current patch + load or urgency. + +Q: Are patches applied to bpf-next when the merge window is open? + +A: For the time when the merge window is open, bpf-next will not be + processed. This is roughly analogous to net-next patch processing, + so feel free to read up on the netdev FAQ about further details. + + During those two weeks of merge window, we might ask you to resend + your patch series once bpf-next is open again. Once Linus released + a v*-rc1 after the merge window, we continue processing of bpf-next. + + For non-subscribers to kernel mailing lists, there is also a status + page run by David S. Miller on net-next that provides guidance: + + http://vger.kernel.org/~davem/net-next.html + +Q: I made a BPF verifier change, do I need to add test cases for + BPF kernel selftests? + +A: If the patch has changes to the behavior of the verifier, then yes, + it is absolutely necessary to add test cases to the BPF kernel + selftests suite. If they are not present and we think they are + needed, then we might ask for them before accepting any changes. + + In particular, test_verifier.c is tracking a high number of BPF test + cases, including a lot of corner cases that LLVM BPF back end may + generate out of the restricted C code. Thus, adding test cases is + absolutely crucial to make sure future changes do not accidentally + affect prior use-cases. Thus, treat those test cases as: verifier + behavior that is not tracked in test_verifier.c could potentially + be subject to change. + +Q: When should I add code to samples/bpf/ and when to BPF kernel + selftests? + +A: In general, we prefer additions to BPF kernel selftests rather than + samples/bpf/. The rationale is very simple: kernel selftests are + regularly run by various bots to test for kernel regressions. + + The more test cases we add to BPF selftests, the better the coverage + and the less likely it is that those could accidentally break. It is + not that BPF kernel selftests cannot demo how a specific feature can + be used. + + That said, samples/bpf/ may be a good place for people to get started, + so it might be advisable that simple demos of features could go into + samples/bpf/, but advanced functional and corner-case testing rather + into kernel selftests. + + If your sample looks like a test case, then go for BPF kernel selftests + instead! + +Q: When should I add code to the bpftool? + +A: The main purpose of bpftool (under tools/bpf/bpftool/) is to provide + a central user space tool for debugging and introspection of BPF programs + and maps that are active in the kernel. If UAPI changes related to BPF + enable for dumping additional information of programs or maps, then + bpftool should be extended as well to support dumping them. + +Q: When should I add code to iproute2's BPF loader? + +A: For UAPI changes related to the XDP or tc layer (e.g. cls_bpf), the + convention is that those control-path related changes are added to + iproute2's BPF loader as well from user space side. This is not only + useful to have UAPI changes properly designed to be usable, but also + to make those changes available to a wider user base of major + downstream distributions. + +Q: Do you accept patches as well for iproute2's BPF loader? + +A: Patches for the iproute2's BPF loader have to be sent to: + + netdev@vger.kernel.org + + While those patches are not processed by the BPF kernel maintainers, + please keep them in Cc as well, so they can be reviewed. + + The official git repository for iproute2 is run by Stephen Hemminger + and can be found at: + + https://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git/ + + The patches need to have a subject prefix of '[PATCH iproute2 master]' + or '[PATCH iproute2 net-next]'. 'master' or 'net-next' describes the + target branch where the patch should be applied to. Meaning, if kernel + changes went into the net-next kernel tree, then the related iproute2 + changes need to go into the iproute2 net-next branch, otherwise they + can be targeted at master branch. The iproute2 net-next branch will get + merged into the master branch after the current iproute2 version from + master has been released. + + Like BPF, the patches end up in patchwork under the netdev project and + are delegated to 'shemminger' for further processing: + + http://patchwork.ozlabs.org/project/netdev/list/?delegate=389 + +Q: What is the minimum requirement before I submit my BPF patches? + +A: When submitting patches, always take the time and properly test your + patches *prior* to submission. Never rush them! If maintainers find + that your patches have not been properly tested, it is a good way to + get them grumpy. Testing patch submissions is a hard requirement! + + Note, fixes that go to bpf tree *must* have a Fixes: tag included. The + same applies to fixes that target bpf-next, where the affected commit + is in net-next (or in some cases bpf-next). The Fixes: tag is crucial + in order to identify follow-up commits and tremendously helps for people + having to do backporting, so it is a must have! + + We also don't accept patches with an empty commit message. Take your + time and properly write up a high quality commit message, it is + essential! + + Think about it this way: other developers looking at your code a month + from now need to understand *why* a certain change has been done that + way, and whether there have been flaws in the analysis or assumptions + that the original author did. Thus providing a proper rationale and + describing the use-case for the changes is a must. + + Patch submissions with >1 patch must have a cover letter which includes + a high level description of the series. This high level summary will + then be placed into the merge commit by the BPF maintainers such that + it is also accessible from the git log for future reference. + +Q: What do I need to consider when adding a new instruction or feature + that would require BPF JIT and/or LLVM integration as well? + +A: We try hard to keep all BPF JITs up to date such that the same user + experience can be guaranteed when running BPF programs on different + architectures without having the program punt to the less efficient + interpreter in case the in-kernel BPF JIT is enabled. + + If you are unable to implement or test the required JIT changes for + certain architectures, please work together with the related BPF JIT + developers in order to get the feature implemented in a timely manner. + Please refer to the git log (arch/*/net/) to locate the necessary + people for helping out. + + Also always make sure to add BPF test cases (e.g. test_bpf.c and + test_verifier.c) for new instructions, so that they can receive + broad test coverage and help run-time testing the various BPF JITs. + + In case of new BPF instructions, once the changes have been accepted + into the Linux kernel, please implement support into LLVM's BPF back + end. See LLVM section below for further information. + +Stable submission: +------------------ + +Q: I need a specific BPF commit in stable kernels. What should I do? + +A: In case you need a specific fix in stable kernels, first check whether + the commit has already been applied in the related linux-*.y branches: + + https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/ + + If not the case, then drop an email to the BPF maintainers with the + netdev kernel mailing list in Cc and ask for the fix to be queued up: + + netdev@vger.kernel.org + + The process in general is the same as on netdev itself, see also the + netdev FAQ document. + +Q: Do you also backport to kernels not currently maintained as stable? + +A: No. If you need a specific BPF commit in kernels that are currently not + maintained by the stable maintainers, then you are on your own. + + The current stable and longterm stable kernels are all listed here: + + https://www.kernel.org/ + +Q: The BPF patch I am about to submit needs to go to stable as well. What + should I do? + +A: The same rules apply as with netdev patch submissions in general, see + netdev FAQ under: + + Documentation/networking/netdev-FAQ.txt + + Never add "Cc: stable@vger.kernel.org" to the patch description, but + ask the BPF maintainers to queue the patches instead. This can be done + with a note, for example, under the "---" part of the patch which does + not go into the git log. Alternatively, this can be done as a simple + request by mail instead. + +Q: Where do I find currently queued BPF patches that will be submitted + to stable? + +A: Once patches that fix critical bugs got applied into the bpf tree, they + are queued up for stable submission under: + + http://patchwork.ozlabs.org/bundle/bpf/stable/?state=* + + They will be on hold there at minimum until the related commit made its + way into the mainline kernel tree. + + After having been under broader exposure, the queued patches will be + submitted by the BPF maintainers to the stable maintainers. + +Testing patches: +---------------- + +Q: Which BPF kernel selftests version should I run my kernel against? + +A: If you run a kernel xyz, then always run the BPF kernel selftests from + that kernel xyz as well. Do not expect that the BPF selftest from the + latest mainline tree will pass all the time. + + In particular, test_bpf.c and test_verifier.c have a large number of + test cases and are constantly updated with new BPF test sequences, or + existing ones are adapted to verifier changes e.g. due to verifier + becoming smarter and being able to better track certain things. + +LLVM: +----- + +Q: Where do I find LLVM with BPF support? + +A: The BPF back end for LLVM is upstream in LLVM since version 3.7.1. + + All major distributions these days ship LLVM with BPF back end enabled, + so for the majority of use-cases it is not required to compile LLVM by + hand anymore, just install the distribution provided package. + + LLVM's static compiler lists the supported targets through 'llc --version', + make sure BPF targets are listed. Example: + + $ llc --version + LLVM (http://llvm.org/): + LLVM version 6.0.0svn + Optimized build. + Default target: x86_64-unknown-linux-gnu + Host CPU: skylake + + Registered Targets: + bpf - BPF (host endian) + bpfeb - BPF (big endian) + bpfel - BPF (little endian) + x86 - 32-bit X86: Pentium-Pro and above + x86-64 - 64-bit X86: EM64T and AMD64 + + For developers in order to utilize the latest features added to LLVM's + BPF back end, it is advisable to run the latest LLVM releases. Support + for new BPF kernel features such as additions to the BPF instruction + set are often developed together. + + All LLVM releases can be found at: http://releases.llvm.org/ + +Q: Got it, so how do I build LLVM manually anyway? + +A: You need cmake and gcc-c++ as build requisites for LLVM. Once you have + that set up, proceed with building the latest LLVM and clang version + from the git repositories: + + $ git clone http://llvm.org/git/llvm.git + $ cd llvm/tools + $ git clone --depth 1 http://llvm.org/git/clang.git + $ cd ..; mkdir build; cd build + $ cmake .. -DLLVM_TARGETS_TO_BUILD="BPF;X86" \ + -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_BUILD_TYPE=Release \ + -DLLVM_BUILD_RUNTIME=OFF + $ make -j $(getconf _NPROCESSORS_ONLN) + + The built binaries can then be found in the build/bin/ directory, where + you can point the PATH variable to. + +Q: Should I notify BPF kernel maintainers about issues in LLVM's BPF code + generation back end or about LLVM generated code that the verifier + refuses to accept? + +A: Yes, please do! LLVM's BPF back end is a key piece of the whole BPF + infrastructure and it ties deeply into verification of programs from the + kernel side. Therefore, any issues on either side need to be investigated + and fixed whenever necessary. + + Therefore, please make sure to bring them up at netdev kernel mailing + list and Cc BPF maintainers for LLVM and kernel bits: + + Yonghong Song + Alexei Starovoitov + Daniel Borkmann + + LLVM also has an issue tracker where BPF related bugs can be found: + + https://bugs.llvm.org/buglist.cgi?quicksearch=bpf + + However, it is better to reach out through mailing lists with having + maintainers in Cc. + +Q: I have added a new BPF instruction to the kernel, how can I integrate + it into LLVM? + +A: LLVM has a -mcpu selector for the BPF back end in order to allow the + selection of BPF instruction set extensions. By default the 'generic' + processor target is used, which is the base instruction set (v1) of BPF. + + LLVM has an option to select -mcpu=probe where it will probe the host + kernel for supported BPF instruction set extensions and selects the + optimal set automatically. + + For cross-compilation, a specific version can be select manually as well. + + $ llc -march bpf -mcpu=help + Available CPUs for this target: + + generic - Select the generic processor. + probe - Select the probe processor. + v1 - Select the v1 processor. + v2 - Select the v2 processor. + [...] + + Newly added BPF instructions to the Linux kernel need to follow the same + scheme, bump the instruction set version and implement probing for the + extensions such that -mcpu=probe users can benefit from the optimization + transparently when upgrading their kernels. + + If you are unable to implement support for the newly added BPF instruction + please reach out to BPF developers for help. + + By the way, the BPF kernel selftests run with -mcpu=probe for better + test coverage. + +Q: In some cases clang flag "-target bpf" is used but in other cases the + default clang target, which matches the underlying architecture, is used. + What is the difference and when I should use which? + +A: Although LLVM IR generation and optimization try to stay architecture + independent, "-target " still has some impact on generated code: + + - BPF program may recursively include header file(s) with file scope + inline assembly codes. The default target can handle this well, + while bpf target may fail if bpf backend assembler does not + understand these assembly codes, which is true in most cases. + + - When compiled without -g, additional elf sections, e.g., + .eh_frame and .rela.eh_frame, may be present in the object file + with default target, but not with bpf target. + + - The default target may turn a C switch statement into a switch table + lookup and jump operation. Since the switch table is placed + in the global readonly section, the bpf program will fail to load. + The bpf target does not support switch table optimization. + The clang option "-fno-jump-tables" can be used to disable + switch table generation. + + You should use default target when: + + - Your program includes a header file, e.g., ptrace.h, which eventually + pulls in some header files containing file scope host assembly codes. + - You can add "-fno-jump-tables" to work around the switch table issue. + + Otherwise, you can use bpf target. + +Happy BPF hacking! diff --git a/Documentation/cgroup-v1/cgroups.txt b/Documentation/cgroup-v1/cgroups.txt index 308e5ff7207a..059f7063eea6 100644 --- a/Documentation/cgroup-v1/cgroups.txt +++ b/Documentation/cgroup-v1/cgroups.txt @@ -523,12 +523,7 @@ Accessing a task's cgroup pointer may be done in the following ways: Each subsystem should: - add an entry in linux/cgroup_subsys.h -- define a cgroup_subsys object called _subsys - -If a subsystem can be compiled as a module, it should also have in its -module initcall a call to cgroup_load_subsys(), and in its exitcall a -call to cgroup_unload_subsys(). It should also set its_subsys.module = -THIS_MODULE in its .c file. +- define a cgroup_subsys object called _cgrp_subsys Each subsystem may export the following methods. The only mandatory methods are css_alloc/free. Any others that are null are presumed to diff --git a/Documentation/cgroup-v1/memory.txt b/Documentation/cgroup-v1/memory.txt index cefb63639070..a4af2e124e24 100644 --- a/Documentation/cgroup-v1/memory.txt +++ b/Documentation/cgroup-v1/memory.txt @@ -524,9 +524,9 @@ Note: Only anonymous and swap cache memory is listed as part of 'rss' stat. This should not be confused with the true 'resident set size' or the amount of physical memory used by the cgroup. - 'rss + file_mapped" will give you resident set size of cgroup. + 'rss + mapped_file" will give you resident set size of cgroup. (Note: file and shmem may be shared among other cgroups. In that case, - file_mapped is accounted only when the memory cgroup is owner of page + mapped_file is accounted only when the memory cgroup is owner of page cache.) 5.3 swappiness diff --git a/Documentation/cgroup-v2.txt b/Documentation/cgroup-v2.txt index 2cddab7efb20..74cdeaed9f7a 100644 --- a/Documentation/cgroup-v2.txt +++ b/Documentation/cgroup-v2.txt @@ -53,10 +53,14 @@ v1 is available under Documentation/cgroup-v1/. 5-3-2. Writeback 5-4. PID 5-4-1. PID Interface Files - 5-5. RDMA - 5-5-1. RDMA Interface Files - 5-6. Misc - 5-6-1. perf_event + 5-5. Device + 5-6. RDMA + 5-6-1. RDMA Interface Files + 5-7. Misc + 5-7-1. perf_event + 5-N. Non-normative information + 5-N-1. CPU controller root cgroup process behaviour + 5-N-2. IO controller root cgroup process behaviour 6. Namespace 6-1. Basics 6-2. The Root and Views @@ -279,7 +283,7 @@ thread mode, the following conditions must be met. exempt from this requirement. Topology-wise, a cgroup can be in an invalid state. Please consider -the following toplogy:: +the following topology:: A (threaded domain) - B (threaded) - C (domain, just created) @@ -420,7 +424,9 @@ The root cgroup is exempt from this restriction. Root contains processes and anonymous resource consumption which can't be associated with any other cgroups and requires special treatment from most controllers. How resource consumption in the root cgroup is governed -is up to each controller. +is up to each controller (for more information on this topic please +refer to the Non-normative information section in the Controllers +chapter). Note that the restriction doesn't get in the way if there is no enabled controller in the cgroup's "cgroup.subtree_control". This is @@ -1063,10 +1069,10 @@ PAGE_SIZE multiple when read back. reached the limit and allocation was about to fail. Depending on context result could be invocation of OOM - killer and retrying allocation or failing alloction. + killer and retrying allocation or failing allocation. Failed allocation in its turn could be returned into - userspace as -ENOMEM or siletly ignored in cases like + userspace as -ENOMEM or silently ignored in cases like disk readahead. For now OOM in memory cgroup kills tasks iff shortage has happened inside page fault. @@ -1191,7 +1197,7 @@ PAGE_SIZE multiple when read back. cgroups. The default is "max". Swap usage hard limit. If a cgroup's swap usage reaches this - limit, anonymous meomry of the cgroup will not be swapped out. + limit, anonymous memory of the cgroup will not be swapped out. Usage Guidelines @@ -1429,6 +1435,30 @@ through fork() or clone(). These will return -EAGAIN if the creation of a new process would cause a cgroup policy to be violated. +Device controller +----------------- + +Device controller manages access to device files. It includes both +creation of new device files (using mknod), and access to the +existing device files. + +Cgroup v2 device controller has no interface files and is implemented +on top of cgroup BPF. To control access to device files, a user may +create bpf programs of the BPF_CGROUP_DEVICE type and attach them +to cgroups. On an attempt to access a device file, corresponding +BPF programs will be executed, and depending on the return value +the attempt will succeed or fail with -EPERM. + +A BPF_CGROUP_DEVICE program takes a pointer to the bpf_cgroup_dev_ctx +structure, which describes the device access attempt: access type +(mknod/read/write) and device (type, major and minor numbers). +If the program returns 0, the attempt fails with -EPERM, otherwise +it succeeds. + +An example of BPF_CGROUP_DEVICE program may be found in the kernel +source tree in the tools/testing/selftests/bpf/dev_cgroup.c file. + + RDMA ---- @@ -1481,6 +1511,35 @@ always be filtered by cgroup v2 path. The controller can still be moved to a legacy hierarchy after v2 hierarchy is populated. +Non-normative information +------------------------- + +This section contains information that isn't considered to be a part of +the stable kernel API and so is subject to change. + + +CPU controller root cgroup process behaviour +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When distributing CPU cycles in the root cgroup each thread in this +cgroup is treated as if it was hosted in a separate child cgroup of the +root cgroup. This child cgroup weight is dependent on its thread nice +level. + +For details of this mapping see sched_prio_to_weight array in +kernel/sched/core.c file (values from this array should be scaled +appropriately so the neutral - nice 0 - value is 100 instead of 1024). + + +IO controller root cgroup process behaviour +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Root cgroup processes are hosted in an implicit leaf child node. +When distributing IO resources this implicit child node is taken into +account as if it was a normal child cgroup of the root cgroup with a +weight value of 200. + + Namespace ========= diff --git a/Documentation/circular-buffers.txt b/Documentation/circular-buffers.txt index d4628174b7c5..53e51caa3347 100644 --- a/Documentation/circular-buffers.txt +++ b/Documentation/circular-buffers.txt @@ -220,8 +220,7 @@ before it writes the new tail pointer, which will erase the item. Note the use of READ_ONCE() and smp_load_acquire() to read the opposition index. This prevents the compiler from discarding and -reloading its cached value - which some compilers will do across -smp_read_barrier_depends(). This isn't strictly needed if you can +reloading its cached value. This isn't strictly needed if you can be sure that the opposition index will _only_ be used the once. The smp_load_acquire() additionally forces the CPU to order against subsequent memory references. Similarly, smp_store_release() is used diff --git a/Documentation/conf.py b/Documentation/conf.py index 63857d33778c..62ac5a9f3a9f 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -88,7 +88,6 @@ finally: if makefile_version and makefile_patchlevel: version = release = makefile_version + '.' + makefile_patchlevel else: - sys.stderr.write('Warning: Could not extract kernel version\n') version = release = "unknown version" # The language for content autogenerated by Sphinx. Refer to documentation diff --git a/Documentation/errseq.rst b/Documentation/core-api/errseq.rst similarity index 92% rename from Documentation/errseq.rst rename to Documentation/core-api/errseq.rst index 4c29bd5afbc5..ff332e272405 100644 --- a/Documentation/errseq.rst +++ b/Documentation/core-api/errseq.rst @@ -1,5 +1,7 @@ +===================== The errseq_t datatype ===================== + An errseq_t is a way of recording errors in one place, and allowing any number of "subscribers" to tell whether it has changed since a previous point where it was sampled. @@ -21,12 +23,13 @@ a flag to tell whether the value has been sampled since a new value was recorded. That allows us to avoid bumping the counter if no one has sampled it since the last time an error was recorded. -Thus we end up with a value that looks something like this:: +Thus we end up with a value that looks something like this: - bit: 31..13 12 11..0 - +-----------------+----+----------------+ - | counter | SF | errno | - +-----------------+----+----------------+ ++--------------------------------------+----+------------------------+ +| 31..13 | 12 | 11..0 | ++--------------------------------------+----+------------------------+ +| counter | SF | errno | ++--------------------------------------+----+------------------------+ The general idea is for "watchers" to sample an errseq_t value and keep it as a running cursor. That value can later be used to tell whether @@ -42,6 +45,7 @@ has ever been an error set since it was first initialized. API usage ========= + Let me tell you a story about a worker drone. Now, he's a good worker overall, but the company is a little...management heavy. He has to report to 77 supervisors today, and tomorrow the "big boss" is coming in @@ -125,6 +129,7 @@ not usable by anyone else. Serializing errseq_t cursor updates =================================== + Note that the errseq_t API does not protect the errseq_t cursor during a check_and_advance_operation. Only the canonical error code is handled atomically. In a situation where more than one task might be using the @@ -147,3 +152,8 @@ errseq_check_and_advance after taking the lock. e.g.:: That avoids the spinlock in the common case where nothing has changed since the last time it was checked. + +Functions +========= + +.. kernel-doc:: lib/errseq.c diff --git a/Documentation/core-api/idr.rst b/Documentation/core-api/idr.rst new file mode 100644 index 000000000000..9078a5c3ac95 --- /dev/null +++ b/Documentation/core-api/idr.rst @@ -0,0 +1,79 @@ +.. SPDX-License-Identifier: CC-BY-SA-4.0 + +============= +ID Allocation +============= + +:Author: Matthew Wilcox + +Overview +======== + +A common problem to solve is allocating identifiers (IDs); generally +small numbers which identify a thing. Examples include file descriptors, +process IDs, packet identifiers in networking protocols, SCSI tags +and device instance numbers. The IDR and the IDA provide a reasonable +solution to the problem to avoid everybody inventing their own. The IDR +provides the ability to map an ID to a pointer, while the IDA provides +only ID allocation, and as a result is much more memory-efficient. + +IDR usage +========= + +Start by initialising an IDR, either with :c:func:`DEFINE_IDR` +for statically allocated IDRs or :c:func:`idr_init` for dynamically +allocated IDRs. + +You can call :c:func:`idr_alloc` to allocate an unused ID. Look up +the pointer you associated with the ID by calling :c:func:`idr_find` +and free the ID by calling :c:func:`idr_remove`. + +If you need to change the pointer associated with an ID, you can call +:c:func:`idr_replace`. One common reason to do this is to reserve an +ID by passing a ``NULL`` pointer to the allocation function; initialise the +object with the reserved ID and finally insert the initialised object +into the IDR. + +Some users need to allocate IDs larger than ``INT_MAX``. So far all of +these users have been content with a ``UINT_MAX`` limit, and they use +:c:func:`idr_alloc_u32`. If you need IDs that will not fit in a u32, +we will work with you to address your needs. + +If you need to allocate IDs sequentially, you can use +:c:func:`idr_alloc_cyclic`. The IDR becomes less efficient when dealing +with larger IDs, so using this function comes at a slight cost. + +To perform an action on all pointers used by the IDR, you can +either use the callback-based :c:func:`idr_for_each` or the +iterator-style :c:func:`idr_for_each_entry`. You may need to use +:c:func:`idr_for_each_entry_continue` to continue an iteration. You can +also use :c:func:`idr_get_next` if the iterator doesn't fit your needs. + +When you have finished using an IDR, you can call :c:func:`idr_destroy` +to release the memory used by the IDR. This will not free the objects +pointed to from the IDR; if you want to do that, use one of the iterators +to do it. + +You can use :c:func:`idr_is_empty` to find out whether there are any +IDs currently allocated. + +If you need to take a lock while allocating a new ID from the IDR, +you may need to pass a restrictive set of GFP flags, which can lead +to the IDR being unable to allocate memory. To work around this, +you can call :c:func:`idr_preload` before taking the lock, and then +:c:func:`idr_preload_end` after the allocation. + +.. kernel-doc:: include/linux/idr.h + :doc: idr sync + +IDA usage +========= + +.. kernel-doc:: lib/idr.c + :doc: IDA description + +Functions and structures +======================== + +.. kernel-doc:: include/linux/idr.h +.. kernel-doc:: lib/idr.c diff --git a/Documentation/core-api/index.rst b/Documentation/core-api/index.rst index d5bbe035316d..c670a8031786 100644 --- a/Documentation/core-api/index.rst +++ b/Documentation/core-api/index.rst @@ -14,13 +14,17 @@ Core utilities kernel-api assoc_array atomic_ops + refcount-vs-atomic cpu_hotplug + idr local_ops workqueue genericirq flexible-arrays librs genalloc + errseq + printk-formats Interfaces for kernel debugging =============================== diff --git a/Documentation/core-api/kernel-api.rst b/Documentation/core-api/kernel-api.rst index 2d9da6c40a4d..ff335f8aeb39 100644 --- a/Documentation/core-api/kernel-api.rst +++ b/Documentation/core-api/kernel-api.rst @@ -103,18 +103,6 @@ CRC Functions .. kernel-doc:: lib/crc-itu-t.c :export: -idr/ida Functions ------------------ - -.. kernel-doc:: include/linux/idr.h - :doc: idr sync - -.. kernel-doc:: lib/idr.c - :doc: IDA description - -.. kernel-doc:: lib/idr.c - :export: - Math Functions in Linux ======================= @@ -139,6 +127,21 @@ Division Functions .. kernel-doc:: lib/gcd.c :export: +Sorting +------- + +.. kernel-doc:: lib/sort.c + :export: + +.. kernel-doc:: lib/list_sort.c + :export: + +UUID/GUID +--------- + +.. kernel-doc:: lib/uuid.c + :export: + Memory Management in Linux ========================== diff --git a/Documentation/printk-formats.txt b/Documentation/core-api/printk-formats.rst similarity index 58% rename from Documentation/printk-formats.txt rename to Documentation/core-api/printk-formats.rst index aa0a776c817a..934559b3c130 100644 --- a/Documentation/printk-formats.txt +++ b/Documentation/core-api/printk-formats.rst @@ -5,6 +5,7 @@ How to get printk format specifiers right :Author: Randy Dunlap :Author: Andrew Murray + Integer types ============= @@ -25,105 +26,101 @@ Integer types s64 %lld or %llx u64 %llu or %llx -If is dependent on a config option for its size (e.g., ``sector_t``, -``blkcnt_t``) or is architecture-dependent for its size (e.g., ``tcflag_t``), -use a format specifier of its largest possible type and explicitly cast to it. + +If is dependent on a config option for its size (e.g., sector_t, +blkcnt_t) or is architecture-dependent for its size (e.g., tcflag_t), use a +format specifier of its largest possible type and explicitly cast to it. Example:: printk("test: sector number/total blocks: %llu/%llu\n", (unsigned long long)sector, (unsigned long long)blockcount); -Reminder: ``sizeof()`` result is of type ``size_t``. +Reminder: sizeof() returns type size_t. -The kernel's printf does not support ``%n``. For obvious reasons, floating -point formats (``%e, %f, %g, %a``) are also not recognized. Use of any +The kernel's printf does not support %n. Floating point formats (%e, %f, +%g, %a) are also not recognized, for obvious reasons. Use of any unsupported specifier or length qualifier results in a WARN and early -return from vsnprintf. +return from vsnprintf(). -Raw pointer value SHOULD be printed with %p. The kernel supports -the following extended format specifiers for pointer types: - -Pointer Types +Pointer types ============= -Pointers printed without a specifier extension (i.e unadorned %p) are -hashed to give a unique identifier without leaking kernel addresses to user -space. On 64 bit machines the first 32 bits are zeroed. If you _really_ -want the address see %px below. +A raw pointer value may be printed with %p which will hash the address +before printing. The kernel also supports extended specifiers for printing +pointers of different types. + +Plain Pointers +-------------- :: %p abcdef12 or 00000000abcdef12 +Pointers printed without a specifier extension (i.e unadorned %p) are +hashed to prevent leaking information about the kernel memory layout. This +has the added benefit of providing a unique identifier. On 64-bit machines +the first 32 bits are zeroed. If you *really* want the address see %px +below. + Symbols/Function Pointers -========================= +------------------------- :: + %pS versatile_init+0x0/0x110 + %ps versatile_init %pF versatile_init+0x0/0x110 %pf versatile_init - %pS versatile_init+0x0/0x110 %pSR versatile_init+0x9/0x110 (with __builtin_extract_return_addr() translation) - %ps versatile_init %pB prev_fn_of_versatile_init+0x88/0x88 -The ``F`` and ``f`` specifiers are for printing function pointers, -for example, f->func, &gettimeofday. They have the same result as -``S`` and ``s`` specifiers. But they do an extra conversion on -ia64, ppc64 and parisc64 architectures where the function pointers -are actually function descriptors. -The ``S`` and ``s`` specifiers can be used for printing symbols -from direct addresses, for example, __builtin_return_address(0), -(void *)regs->ip. They result in the symbol name with (``S``) or -without (``s``) offsets. If KALLSYMS are disabled then the symbol -address is printed instead. +The ``S`` and ``s`` specifiers are used for printing a pointer in symbolic +format. They result in the symbol name with (S) or without (s) +offsets. If KALLSYMS are disabled then the symbol address is printed instead. + +Note, that the ``F`` and ``f`` specifiers are identical to ``S`` (``s``) +and thus deprecated. We have ``F`` and ``f`` because on ia64, ppc64 and +parisc64 function pointers are indirect and, in fact, are function +descriptors, which require additional dereferencing before we can lookup +the symbol. As of now, ``S`` and ``s`` perform dereferencing on those +platforms (when needed), so ``F`` and ``f`` exist for compatibility +reasons only. The ``B`` specifier results in the symbol name with offsets and should be used when printing stack backtraces. The specifier takes into consideration the effect of compiler optimisations which may occur -when tail-call``s are used and marked with the noreturn GCC attribute. - -Examples:: - - printk("Going to call: %pF\n", gettimeofday); - printk("Going to call: %pF\n", p->func); - printk("%s: called from %pS\n", __func__, (void *)_RET_IP_); - printk("%s: called from %pS\n", __func__, - (void *)__builtin_return_address(0)); - printk("Faulted at %pS\n", (void *)regs->ip); - printk(" %s%pB\n", (reliable ? "" : "? "), (void *)*stack); +when tail-calls are used and marked with the noreturn GCC attribute. Kernel Pointers -=============== +--------------- :: %pK 01234567 or 0123456789abcdef For printing kernel pointers which should be hidden from unprivileged -users. The behaviour of ``%pK`` depends on the ``kptr_restrict sysctl`` - see +users. The behaviour of %pK depends on the kptr_restrict sysctl - see Documentation/sysctl/kernel.txt for more details. Unmodified Addresses -==================== +-------------------- :: %px 01234567 or 0123456789abcdef -For printing pointers when you _really_ want to print the address. Please +For printing pointers when you *really* want to print the address. Please consider whether or not you are leaking sensitive information about the -Kernel layout in memory before printing pointers with %px. %px is -functionally equivalent to %lx. %px is preferred to %lx because it is more -uniquely grep'able. If, in the future, we need to modify the way the Kernel -handles printing pointers it will be nice to be able to find the call -sites. +kernel memory layout before printing pointers with %px. %px is functionally +equivalent to %lx (or %lu). %px is preferred because it is more uniquely +grep'able. If in the future we need to modify the way the kernel handles +printing pointers we will be better equipped to find the call sites. Struct Resources -================ +---------------- :: @@ -133,32 +130,37 @@ Struct Resources [mem 0x0000000060000000-0x000000006fffffff pref] For printing struct resources. The ``R`` and ``r`` specifiers result in a -printed resource with (``R``) or without (``r``) a decoded flags member. +printed resource with (R) or without (r) a decoded flags member. + Passed by reference. -Physical addresses types ``phys_addr_t`` -======================================== +Physical address types phys_addr_t +---------------------------------- :: %pa[p] 0x01234567 or 0x0123456789abcdef -For printing a ``phys_addr_t`` type (and its derivatives, such as -``resource_size_t``) which can vary based on build options, regardless of -the width of the CPU data path. Passed by reference. +For printing a phys_addr_t type (and its derivatives, such as +resource_size_t) which can vary based on build options, regardless of the +width of the CPU data path. -DMA addresses types ``dma_addr_t`` -================================== +Passed by reference. + +DMA address types dma_addr_t +---------------------------- :: %pad 0x01234567 or 0x0123456789abcdef -For printing a ``dma_addr_t`` type which can vary based on build options, -regardless of the width of the CPU data path. Passed by reference. +For printing a dma_addr_t type which can vary based on build options, +regardless of the width of the CPU data path. + +Passed by reference. Raw buffer as an escaped string -=============================== +------------------------------- :: @@ -168,8 +170,8 @@ For printing raw buffer as an escaped string. For the following buffer:: 1b 62 20 5c 43 07 22 90 0d 5d -few examples show how the conversion would be done (the result string -without surrounding quotes):: +A few examples show how the conversion would be done (excluding surrounding +quotes):: %*pE "\eb \C\a"\220\r]" %*pEhp "\x1bb \C\x07"\x90\x0d]" @@ -179,23 +181,23 @@ The conversion rules are applied according to an optional combination of flags (see :c:func:`string_escape_mem` kernel documentation for the details): - - ``a`` - ESCAPE_ANY - - ``c`` - ESCAPE_SPECIAL - - ``h`` - ESCAPE_HEX - - ``n`` - ESCAPE_NULL - - ``o`` - ESCAPE_OCTAL - - ``p`` - ESCAPE_NP - - ``s`` - ESCAPE_SPACE + - a - ESCAPE_ANY + - c - ESCAPE_SPECIAL + - h - ESCAPE_HEX + - n - ESCAPE_NULL + - o - ESCAPE_OCTAL + - p - ESCAPE_NP + - s - ESCAPE_SPACE By default ESCAPE_ANY_NP is used. ESCAPE_ANY_NP is the sane choice for many cases, in particularly for printing SSIDs. -If field width is omitted the 1 byte only will be escaped. +If field width is omitted then 1 byte only will be escaped. Raw buffer as a hex string -========================== +-------------------------- :: @@ -204,12 +206,12 @@ Raw buffer as a hex string %*phD 00-01-02- ... -3f %*phN 000102 ... 3f -For printing a small buffers (up to 64 bytes long) as a hex string with -certain separator. For the larger buffers consider to use +For printing small buffers (up to 64 bytes long) as a hex string with a +certain separator. For larger buffers consider using :c:func:`print_hex_dump`. MAC/FDDI addresses -================== +------------------ :: @@ -220,11 +222,11 @@ MAC/FDDI addresses %pmR 050403020100 For printing 6-byte MAC/FDDI addresses in hex notation. The ``M`` and ``m`` -specifiers result in a printed address with (``M``) or without (``m``) byte -separators. The default byte separator is the colon (``:``). +specifiers result in a printed address with (M) or without (m) byte +separators. The default byte separator is the colon (:). Where FDDI addresses are concerned the ``F`` specifier can be used after -the ``M`` specifier to use dash (``-``) separators instead of the default +the ``M`` specifier to use dash (-) separators instead of the default separator. For Bluetooth addresses the ``R`` specifier shall be used after the ``M`` @@ -234,7 +236,7 @@ of Bluetooth addresses which are in the little endian order. Passed by reference. IPv4 addresses -============== +-------------- :: @@ -243,8 +245,8 @@ IPv4 addresses %p[Ii]4[hnbl] For printing IPv4 dot-separated decimal addresses. The ``I4`` and ``i4`` -specifiers result in a printed address with (``i4``) or without (``I4``) -leading zeros. +specifiers result in a printed address with (i4) or without (I4) leading +zeros. The additional ``h``, ``n``, ``b``, and ``l`` specifiers are used to specify host, network, big or little endian order addresses respectively. Where @@ -253,7 +255,7 @@ no specifier is provided the default network/big endian order is used. Passed by reference. IPv6 addresses -============== +-------------- :: @@ -262,7 +264,7 @@ IPv6 addresses %pI6c 1:2:3:4:5:6:7:8 For printing IPv6 network-order 16-bit hex addresses. The ``I6`` and ``i6`` -specifiers result in a printed address with (``I6``) or without (``i6``) +specifiers result in a printed address with (I6) or without (i6) colon-separators. Leading zeros are always used. The additional ``c`` specifier can be used with the ``I`` specifier to @@ -272,7 +274,7 @@ http://tools.ietf.org/html/rfc5952 Passed by reference. IPv4/IPv6 addresses (generic, with port, flowinfo, scope) -========================================================= +--------------------------------------------------------- :: @@ -282,8 +284,8 @@ IPv4/IPv6 addresses (generic, with port, flowinfo, scope) %pISpc 1.2.3.4:12345 or [1:2:3:4:5:6:7:8]:12345 %p[Ii]S[pfschnbl] -For printing an IP address without the need to distinguish whether it``s -of type AF_INET or AF_INET6, a pointer to a valid ``struct sockaddr``, +For printing an IP address without the need to distinguish whether it's of +type AF_INET or AF_INET6. A pointer to a valid struct sockaddr, specified through ``IS`` or ``iS``, can be passed to this format specifier. The additional ``p``, ``f``, and ``s`` specifiers are used to specify port @@ -309,7 +311,7 @@ Further examples:: %pISpfc 1.2.3.4:12345 or [1:2:3:4:5:6:7:8]:12345/123456789 UUID/GUID addresses -=================== +------------------- :: @@ -318,33 +320,33 @@ UUID/GUID addresses %pUl 03020100-0504-0706-0809-0a0b0c0e0e0f %pUL 03020100-0504-0706-0809-0A0B0C0E0E0F -For printing 16-byte UUID/GUIDs addresses. The additional 'l', 'L', -'b' and 'B' specifiers are used to specify a little endian order in -lower ('l') or upper case ('L') hex characters - and big endian order -in lower ('b') or upper case ('B') hex characters. +For printing 16-byte UUID/GUIDs addresses. The additional ``l``, ``L``, +``b`` and ``B`` specifiers are used to specify a little endian order in +lower (l) or upper case (L) hex notation - and big endian order in lower (b) +or upper case (B) hex notation. Where no additional specifiers are used the default big endian -order with lower case hex characters will be printed. +order with lower case hex notation will be printed. Passed by reference. dentry names -============ +------------ :: %pd{,2,3,4} %pD{,2,3,4} -For printing dentry name; if we race with :c:func:`d_move`, the name might be -a mix of old and new ones, but it won't oops. ``%pd`` dentry is a safer -equivalent of ``%s`` ``dentry->d_name.name`` we used to use, ``%pd`` prints -``n`` last components. ``%pD`` does the same thing for struct file. +For printing dentry name; if we race with :c:func:`d_move`, the name might +be a mix of old and new ones, but it won't oops. %pd dentry is a safer +equivalent of %s dentry->d_name.name we used to use, %pd prints ``n`` +last components. %pD does the same thing for struct file. Passed by reference. block_device names -================== +------------------ :: @@ -353,7 +355,7 @@ block_device names For printing name of block_device pointers. struct va_format -================ +---------------- :: @@ -375,31 +377,27 @@ correctness of the format string and va_list arguments. Passed by reference. kobjects -======== +-------- :: - %pO - - Base specifier for kobject based structs. Must be followed with - character for specific type of kobject as listed below: - - Device tree nodes: - %pOF[fnpPcCF] - For printing device tree nodes. The optional arguments are: - f device node full_name - n device node name - p device node phandle - P device node path spec (name + @unit) - F device node flags - c major compatible string - C full compatible string - Without any arguments prints full_name (same as %pOFf) - The separator when using multiple arguments is ':' - Examples: +For printing kobject based structs (device nodes). Default behaviour is +equivalent to %pOFf. + + - f - device node full_name + - n - device node name + - p - device node phandle + - P - device node path spec (name + @unit) + - F - device node flags + - c - major compatible string + - C - full compatible string + +The separator when using multiple arguments is ':' + +Examples:: %pOF /foo/bar@0 - Node full name %pOFf /foo/bar@0 - Same as above @@ -412,11 +410,10 @@ kobjects P - Populated B - Populated bus - Passed by reference. - +Passed by reference. struct clk -========== +---------- :: @@ -424,14 +421,14 @@ struct clk %pCn pll1 %pCr 1560000000 -For printing struct clk structures. ``%pC`` and ``%pCn`` print the name +For printing struct clk structures. %pC and %pCn print the name (Common Clock Framework) or address (legacy clock framework) of the -structure; ``%pCr`` prints the current clock rate. +structure; %pCr prints the current clock rate. Passed by reference. bitmap and its derivatives such as cpumask and nodemask -======================================================= +------------------------------------------------------- :: @@ -439,13 +436,13 @@ bitmap and its derivatives such as cpumask and nodemask %*pbl 0,3-6,8-10 For printing bitmap and its derivatives such as cpumask and nodemask, -``%*pb`` output the bitmap with field width as the number of bits and ``%*pbl`` +%*pb outputs the bitmap with field width as the number of bits and %*pbl output the bitmap as range list with field width as the number of bits. Passed by reference. Flags bitfields such as page flags, gfp_flags -============================================= +--------------------------------------------- :: @@ -459,14 +456,14 @@ character. Currently supported are [p]age flags, [v]ma_flags (both expect ``unsigned long *``) and [g]fp_flags (expects ``gfp_t *``). The flag names and print order depends on the particular type. -Note that this format should not be used directly in :c:func:`TP_printk()` part -of a tracepoint. Instead, use the ``show_*_flags()`` functions from -. +Note that this format should not be used directly in the +:c:func:`TP_printk()` part of a tracepoint. Instead, use the show_*_flags() +functions from . Passed by reference. Network device features -======================= +----------------------- :: @@ -476,8 +473,10 @@ For printing netdev_features_t. Passed by reference. -If you add other ``%p`` extensions, please extend lib/test_printf.c with +Thanks +====== + +If you add other %p extensions, please extend with one or more test cases, if at all feasible. - Thank you for your cooperation and attention. diff --git a/Documentation/core-api/refcount-vs-atomic.rst b/Documentation/core-api/refcount-vs-atomic.rst new file mode 100644 index 000000000000..83351c258cdb --- /dev/null +++ b/Documentation/core-api/refcount-vs-atomic.rst @@ -0,0 +1,150 @@ +=================================== +refcount_t API compared to atomic_t +=================================== + +.. contents:: :local: + +Introduction +============ + +The goal of refcount_t API is to provide a minimal API for implementing +an object's reference counters. While a generic architecture-independent +implementation from lib/refcount.c uses atomic operations underneath, +there are a number of differences between some of the ``refcount_*()`` and +``atomic_*()`` functions with regards to the memory ordering guarantees. +This document outlines the differences and provides respective examples +in order to help maintainers validate their code against the change in +these memory ordering guarantees. + +The terms used through this document try to follow the formal LKMM defined in +github.com/aparri/memory-model/blob/master/Documentation/explanation.txt + +memory-barriers.txt and atomic_t.txt provide more background to the +memory ordering in general and for atomic operations specifically. + +Relevant types of memory ordering +================================= + +.. note:: The following section only covers some of the memory + ordering types that are relevant for the atomics and reference + counters and used through this document. For a much broader picture + please consult memory-barriers.txt document. + +In the absence of any memory ordering guarantees (i.e. fully unordered) +atomics & refcounters only provide atomicity and +program order (po) relation (on the same CPU). It guarantees that +each ``atomic_*()`` and ``refcount_*()`` operation is atomic and instructions +are executed in program order on a single CPU. +This is implemented using :c:func:`READ_ONCE`/:c:func:`WRITE_ONCE` and +compare-and-swap primitives. + +A strong (full) memory ordering guarantees that all prior loads and +stores (all po-earlier instructions) on the same CPU are completed +before any po-later instruction is executed on the same CPU. +It also guarantees that all po-earlier stores on the same CPU +and all propagated stores from other CPUs must propagate to all +other CPUs before any po-later instruction is executed on the original +CPU (A-cumulative property). This is implemented using :c:func:`smp_mb`. + +A RELEASE memory ordering guarantees that all prior loads and +stores (all po-earlier instructions) on the same CPU are completed +before the operation. It also guarantees that all po-earlier +stores on the same CPU and all propagated stores from other CPUs +must propagate to all other CPUs before the release operation +(A-cumulative property). This is implemented using +:c:func:`smp_store_release`. + +A control dependency (on success) for refcounters guarantees that +if a reference for an object was successfully obtained (reference +counter increment or addition happened, function returned true), +then further stores are ordered against this operation. +Control dependency on stores are not implemented using any explicit +barriers, but rely on CPU not to speculate on stores. This is only +a single CPU relation and provides no guarantees for other CPUs. + + +Comparison of functions +======================= + +case 1) - non-"Read/Modify/Write" (RMW) ops +------------------------------------------- + +Function changes: + + * :c:func:`atomic_set` --> :c:func:`refcount_set` + * :c:func:`atomic_read` --> :c:func:`refcount_read` + +Memory ordering guarantee changes: + + * none (both fully unordered) + + +case 2) - increment-based ops that return no value +-------------------------------------------------- + +Function changes: + + * :c:func:`atomic_inc` --> :c:func:`refcount_inc` + * :c:func:`atomic_add` --> :c:func:`refcount_add` + +Memory ordering guarantee changes: + + * none (both fully unordered) + +case 3) - decrement-based RMW ops that return no value +------------------------------------------------------ + +Function changes: + + * :c:func:`atomic_dec` --> :c:func:`refcount_dec` + +Memory ordering guarantee changes: + + * fully unordered --> RELEASE ordering + + +case 4) - increment-based RMW ops that return a value +----------------------------------------------------- + +Function changes: + + * :c:func:`atomic_inc_not_zero` --> :c:func:`refcount_inc_not_zero` + * no atomic counterpart --> :c:func:`refcount_add_not_zero` + +Memory ordering guarantees changes: + + * fully ordered --> control dependency on success for stores + +.. note:: We really assume here that necessary ordering is provided as a + result of obtaining pointer to the object! + + +case 5) - decrement-based RMW ops that return a value +----------------------------------------------------- + +Function changes: + + * :c:func:`atomic_dec_and_test` --> :c:func:`refcount_dec_and_test` + * :c:func:`atomic_sub_and_test` --> :c:func:`refcount_sub_and_test` + * no atomic counterpart --> :c:func:`refcount_dec_if_one` + * ``atomic_add_unless(&var, -1, 1)`` --> ``refcount_dec_not_one(&var)`` + +Memory ordering guarantees changes: + + * fully ordered --> RELEASE ordering + control dependency + +.. note:: :c:func:`atomic_add_unless` only provides full order on success. + + +case 6) - lock-based RMW +------------------------ + +Function changes: + + * :c:func:`atomic_dec_and_lock` --> :c:func:`refcount_dec_and_lock` + * :c:func:`atomic_dec_and_mutex_lock` --> :c:func:`refcount_dec_and_mutex_lock` + +Memory ordering guarantees changes: + + * fully ordered --> RELEASE ordering + control dependency + hold + :c:func:`spin_lock` on success diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt index 434c49cc7330..61546ac578d6 100644 --- a/Documentation/cpu-freq/cpu-drivers.txt +++ b/Documentation/cpu-freq/cpu-drivers.txt @@ -291,3 +291,7 @@ For example: /* Do something with pos */ pos->frequency = ... } + +If you need to work with the position of pos within driver_freq_table, +do not subtract the pointers, as it is quite costly. Instead, use the +macros cpufreq_for_each_entry_idx() and cpufreq_for_each_valid_entry_idx(). diff --git a/Documentation/device-mapper/cache-policies.txt b/Documentation/device-mapper/cache-policies.txt index d3ca8af21a31..86786d87d9a8 100644 --- a/Documentation/device-mapper/cache-policies.txt +++ b/Documentation/device-mapper/cache-policies.txt @@ -60,7 +60,7 @@ Memory usage: The mq policy used a lot of memory; 88 bytes per cache block on a 64 bit machine. -smq uses 28bit indexes to implement it's data structures rather than +smq uses 28bit indexes to implement its data structures rather than pointers. It avoids storing an explicit hit count for each block. It has a 'hotspot' queue, rather than a pre-cache, which uses a quarter of the entries (each hotspot block covers a larger area than a single @@ -84,7 +84,7 @@ resulting in better promotion/demotion decisions. Adaptability: The mq policy maintained a hit count for each cache block. For a -different block to get promoted to the cache it's hit count has to +different block to get promoted to the cache its hit count has to exceed the lowest currently in the cache. This meant it could take a long time for the cache to adapt between varying IO patterns. diff --git a/Documentation/device-mapper/cache.txt b/Documentation/device-mapper/cache.txt index cdfd0feb294e..ff0841711fd5 100644 --- a/Documentation/device-mapper/cache.txt +++ b/Documentation/device-mapper/cache.txt @@ -59,7 +59,7 @@ Fixed block size The origin is divided up into blocks of a fixed size. This block size is configurable when you first create the cache. Typically we've been using block sizes of 256KB - 1024KB. The block size must be between 64 -(32KB) and 2097152 (1GB) and a multiple of 64 (32KB). +sectors (32KB) and 2097152 sectors (1GB) and a multiple of 64 sectors (32KB). Having a fixed block size simplifies the target a lot. But it is something of a compromise. For instance, a small part of a block may be @@ -119,7 +119,7 @@ doing here to avoid migrating during those peak io moments. For the time being, a message "migration_threshold <#sectors>" can be used to set the maximum number of sectors being migrated, -the default being 204800 sectors (or 100MB). +the default being 2048 sectors (1MB). Updating on-disk metadata ------------------------- @@ -143,11 +143,6 @@ the policy how big this chunk is, but it should be kept small. Like the dirty flags this data is lost if there's a crash so a safe fallback value should always be possible. -For instance, the 'mq' policy, which is currently the default policy, -uses this facility to store the hit count of the cache blocks. If -there's a crash this information will be lost, which means the cache -may be less efficient until those hit counts are regenerated. - Policy hints affect performance, not correctness. Policy messaging diff --git a/Documentation/device-mapper/dm-raid.txt b/Documentation/device-mapper/dm-raid.txt index 32df07e29f68..390c145f01d7 100644 --- a/Documentation/device-mapper/dm-raid.txt +++ b/Documentation/device-mapper/dm-raid.txt @@ -343,5 +343,8 @@ Version History 1.11.0 Fix table line argument order (wrong raid10_copies/raid10_format sequence) 1.11.1 Add raid4/5/6 journal write-back support via journal_mode option -1.12.1 fix for MD deadlock between mddev_suspend() and md_write_start() available +1.12.1 Fix for MD deadlock between mddev_suspend() and md_write_start() available 1.13.0 Fix dev_health status at end of "recover" (was 'a', now 'A') +1.13.1 Fix deadlock caused by early md_stop_writes(). Also fix size an + state races. +1.13.2 Fix raid redundancy validation and avoid keeping raid set frozen diff --git a/Documentation/device-mapper/snapshot.txt b/Documentation/device-mapper/snapshot.txt index ad6949bff2e3..b8bbb516f989 100644 --- a/Documentation/device-mapper/snapshot.txt +++ b/Documentation/device-mapper/snapshot.txt @@ -49,6 +49,10 @@ The difference between persistent and transient is with transient snapshots less metadata must be saved on disk - they can be kept in memory by the kernel. +When loading or unloading the snapshot target, the corresponding +snapshot-origin or snapshot-merge target must be suspended. A failure to +suspend the origin target could result in data corruption. + * snapshot-merge diff --git a/Documentation/device-mapper/thin-provisioning.txt b/Documentation/device-mapper/thin-provisioning.txt index 1699a55b7b70..4bcd4b7f79f9 100644 --- a/Documentation/device-mapper/thin-provisioning.txt +++ b/Documentation/device-mapper/thin-provisioning.txt @@ -112,9 +112,11 @@ $low_water_mark is expressed in blocks of size $data_block_size. If free space on the data device drops below this level then a dm event will be triggered which a userspace daemon should catch allowing it to extend the pool device. Only one such event will be sent. -Resuming a device with a new table itself triggers an event so the -userspace daemon can use this to detect a situation where a new table -already exceeds the threshold. + +No special event is triggered if a just resumed device's free space is below +the low water mark. However, resuming a device always triggers an +event; a userspace daemon should verify that free space exceeds the low +water mark when handling this event. A low water mark for the metadata device is maintained in the kernel and will trigger a dm event if free space on the metadata device drops below @@ -274,7 +276,8 @@ ii) Status / / - [no_]discard_passdown ro|rw + ro|rw|out_of_data_space [no_]discard_passdown [error|queue]_if_no_space + needs_check|- transaction id: A 64-bit number used by userspace to help synchronise with metadata @@ -394,3 +397,6 @@ ii) Status If the pool has encountered device errors and failed, the status will just contain the string 'Fail'. The userspace recovery tools should then be used. + + In the case where is 0, there is no highest + mapped sector and the value of is unspecified. diff --git a/Documentation/device-mapper/unstriped.txt b/Documentation/device-mapper/unstriped.txt new file mode 100644 index 000000000000..0b2a306c54ee --- /dev/null +++ b/Documentation/device-mapper/unstriped.txt @@ -0,0 +1,124 @@ +Introduction +============ + +The device-mapper "unstriped" target provides a transparent mechanism to +unstripe a device-mapper "striped" target to access the underlying disks +without having to touch the true backing block-device. It can also be +used to unstripe a hardware RAID-0 to access backing disks. + +Parameters: + + + + The number of stripes in the RAID 0. + + + The amount of 512B sectors in the chunk striping. + + + The block device you wish to unstripe. + + + The stripe number within the device that corresponds to physical + drive you wish to unstripe. This must be 0 indexed. + + +Why use this module? +==================== + +An example of undoing an existing dm-stripe +------------------------------------------- + +This small bash script will setup 4 loop devices and use the existing +striped target to combine the 4 devices into one. It then will use +the unstriped target ontop of the striped device to access the +individual backing loop devices. We write data to the newly exposed +unstriped devices and verify the data written matches the correct +underlying device on the striped array. + +#!/bin/bash + +MEMBER_SIZE=$((128 * 1024 * 1024)) +NUM=4 +SEQ_END=$((${NUM}-1)) +CHUNK=256 +BS=4096 + +RAID_SIZE=$((${MEMBER_SIZE}*${NUM}/512)) +DM_PARMS="0 ${RAID_SIZE} striped ${NUM} ${CHUNK}" +COUNT=$((${MEMBER_SIZE} / ${BS})) + +for i in $(seq 0 ${SEQ_END}); do + dd if=/dev/zero of=member-${i} bs=${MEMBER_SIZE} count=1 oflag=direct + losetup /dev/loop${i} member-${i} + DM_PARMS+=" /dev/loop${i} 0" +done + +echo $DM_PARMS | dmsetup create raid0 +for i in $(seq 0 ${SEQ_END}); do + echo "0 1 unstriped ${NUM} ${CHUNK} ${i} /dev/mapper/raid0 0" | dmsetup create set-${i} +done; + +for i in $(seq 0 ${SEQ_END}); do + dd if=/dev/urandom of=/dev/mapper/set-${i} bs=${BS} count=${COUNT} oflag=direct + diff /dev/mapper/set-${i} member-${i} +done; + +for i in $(seq 0 ${SEQ_END}); do + dmsetup remove set-${i} +done + +dmsetup remove raid0 + +for i in $(seq 0 ${SEQ_END}); do + losetup -d /dev/loop${i} + rm -f member-${i} +done + +Another example +--------------- + +Intel NVMe drives contain two cores on the physical device. +Each core of the drive has segregated access to its LBA range. +The current LBA model has a RAID 0 128k chunk on each core, resulting +in a 256k stripe across the two cores: + + Core 0: Core 1: + __________ __________ + | LBA 512| | LBA 768| + | LBA 0 | | LBA 256| + ---------- ---------- + +The purpose of this unstriping is to provide better QoS in noisy +neighbor environments. When two partitions are created on the +aggregate drive without this unstriping, reads on one partition +can affect writes on another partition. This is because the partitions +are striped across the two cores. When we unstripe this hardware RAID 0 +and make partitions on each new exposed device the two partitions are now +physically separated. + +With the dm-unstriped target we're able to segregate an fio script that +has read and write jobs that are independent of each other. Compared to +when we run the test on a combined drive with partitions, we were able +to get a 92% reduction in read latency using this device mapper target. + + +Example dmsetup usage +===================== + +unstriped ontop of Intel NVMe device that has 2 cores +----------------------------------------------------- +dmsetup create nvmset0 --table '0 512 unstriped 2 256 0 /dev/nvme0n1 0' +dmsetup create nvmset1 --table '0 512 unstriped 2 256 1 /dev/nvme0n1 0' + +There will now be two devices that expose Intel NVMe core 0 and 1 +respectively: +/dev/mapper/nvmset0 +/dev/mapper/nvmset1 + +unstriped ontop of striped with 4 drives using 128K chunk size +-------------------------------------------------------------- +dmsetup create raid_disk0 --table '0 512 unstriped 4 256 0 /dev/mapper/striped 0' +dmsetup create raid_disk1 --table '0 512 unstriped 4 256 1 /dev/mapper/striped 0' +dmsetup create raid_disk2 --table '0 512 unstriped 4 256 2 /dev/mapper/striped 0' +dmsetup create raid_disk3 --table '0 512 unstriped 4 256 3 /dev/mapper/striped 0' diff --git a/Documentation/devicetree/bindings/arm/actions.txt b/Documentation/devicetree/bindings/arm/actions.txt index ced764a8549e..d54f33c4e0da 100644 --- a/Documentation/devicetree/bindings/arm/actions.txt +++ b/Documentation/devicetree/bindings/arm/actions.txt @@ -21,10 +21,26 @@ Boards: Root node property compatible must contain, depending on board: + - Allo.com Sparky: "allo,sparky" - Cubietech CubieBoard6: "cubietech,cubieboard6" - LeMaker Guitar Base Board rev. B: "lemaker,guitar-bb-rev-b", "lemaker,guitar" +S700 SoC +======== + +Required root node properties: + +- compatible : must contain "actions,s700" + + +Boards: + +Root node property compatible must contain, depending on board: + + - Cubietech CubieBoard7: "cubietech,cubieboard7" + + S900 SoC ======== diff --git a/Documentation/devicetree/bindings/arm/arm-dsu-pmu.txt b/Documentation/devicetree/bindings/arm/arm-dsu-pmu.txt new file mode 100644 index 000000000000..6efabba530f1 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/arm-dsu-pmu.txt @@ -0,0 +1,27 @@ +* ARM DynamIQ Shared Unit (DSU) Performance Monitor Unit (PMU) + +ARM DyanmIQ Shared Unit (DSU) integrates one or more CPU cores +with a shared L3 memory system, control logic and external interfaces to +form a multicore cluster. The PMU enables to gather various statistics on +the operations of the DSU. The PMU provides independent 32bit counters that +can count any of the supported events, along with a 64bit cycle counter. +The PMU is accessed via CPU system registers and has no MMIO component. + +** DSU PMU required properties: + +- compatible : should be one of : + + "arm,dsu-pmu" + +- interrupts : Exactly 1 SPI must be listed. + +- cpus : List of phandles for the CPUs connected to this DSU instance. + + +** Example: + +dsu-pmu-0 { + compatible = "arm,dsu-pmu"; + interrupts = ; + cpus = <&cpu_0>, <&cpu_1>; +}; diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 91cb8e4f2a4f..31220b54d85d 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -90,38 +90,6 @@ System Timer (ST) required properties: Its subnodes can be: - watchdog: compatible should be "atmel,at91rm9200-wdt" -TC/TCLIB Timer required properties: -- compatible: Should be "atmel,-tcb". - can be "at91rm9200" or "at91sam9x5" -- reg: Should contain registers location and length -- interrupts: Should contain all interrupts for the TC block - Note that you can specify several interrupt cells if the TC - block has one interrupt per channel. -- clock-names: tuple listing input clock names. - Required elements: "t0_clk", "slow_clk" - Optional elements: "t1_clk", "t2_clk" -- clocks: phandles to input clocks. - -Examples: - -One interrupt per TC block: - tcb0: timer@fff7c000 { - compatible = "atmel,at91rm9200-tcb"; - reg = <0xfff7c000 0x100>; - interrupts = <18 4>; - clocks = <&tcb0_clk>; - clock-names = "t0_clk"; - }; - -One interrupt per TC channel in a TC block: - tcb1: timer@fffdc000 { - compatible = "atmel,at91rm9200-tcb"; - reg = <0xfffdc000 0x100>; - interrupts = <26 4 27 4 28 4>; - clocks = <&tcb1_clk>; - clock-names = "t0_clk"; - }; - RSTC Reset Controller required properties: - compatible: Should be "atmel,-rstc". can be "at91sam9260" or "at91sam9g45" or "sama5d3" diff --git a/Documentation/devicetree/bindings/arm/axentia.txt b/Documentation/devicetree/bindings/arm/axentia.txt index ea3fb96ae465..de58f2463880 100644 --- a/Documentation/devicetree/bindings/arm/axentia.txt +++ b/Documentation/devicetree/bindings/arm/axentia.txt @@ -10,6 +10,15 @@ compatible = "axentia,linea", and following the rules from atmel-at91.txt for a sama5d31 SoC. +Nattis v2 board with Natte v2 power board +----------------------------------------- + +Required root node properties: +compatible = "axentia,nattis-2", "axentia,natte-2", "axentia,linea", + "atmel,sama5d31", "atmel,sama5d3", "atmel,sama5"; +and following the rules from above for the axentia,linea CPU module. + + TSE-850 v3 board ---------------- diff --git a/Documentation/devicetree/bindings/arm/bcm/brcm,brcmstb.txt b/Documentation/devicetree/bindings/arm/bcm/brcm,brcmstb.txt index 790e6b0b8306..c052caad36e8 100644 --- a/Documentation/devicetree/bindings/arm/bcm/brcm,brcmstb.txt +++ b/Documentation/devicetree/bindings/arm/bcm/brcm,brcmstb.txt @@ -17,21 +17,23 @@ Further, syscon nodes that map platform-specific registers used for general system control is required: - compatible: "brcm,bcm-sun-top-ctrl", "syscon" - - compatible: "brcm,bcm-hif-cpubiuctrl", "syscon" + - compatible: "brcm,bcm-cpu-biu-ctrl", + "brcm,brcmstb-cpu-biu-ctrl", + "syscon" - compatible: "brcm,bcm-hif-continuation", "syscon" -hif-cpubiuctrl node +cpu-biu-ctrl node ------------------- -SoCs with Broadcom Brahma15 ARM-based CPUs have a specific Bus Interface Unit -(BIU) block which controls and interfaces the CPU complex to the different -Memory Controller Ports (MCP), one per memory controller (MEMC). This BIU block -offers a feature called Write Pairing which consists in collapsing two adjacent -cache lines into a single (bursted) write transaction towards the memory -controller (MEMC) to maximize write bandwidth. +SoCs with Broadcom Brahma15 ARM-based and Brahma53 ARM64-based CPUs have a +specific Bus Interface Unit (BIU) block which controls and interfaces the CPU +complex to the different Memory Controller Ports (MCP), one per memory +controller (MEMC). This BIU block offers a feature called Write Pairing which +consists in collapsing two adjacent cache lines into a single (bursted) write +transaction towards the memory controller (MEMC) to maximize write bandwidth. Required properties: - - compatible: must be "brcm,bcm7445-hif-cpubiuctrl", "syscon" + - compatible: must be "brcm,bcm7445-cpu-biu-ctrl", "brcm,brcmstb-cpu-biu-ctrl", "syscon" Optional properties: @@ -52,7 +54,7 @@ example: }; hif_cpubiuctrl: syscon@3e2400 { - compatible = "brcm,bcm7445-hif-cpubiuctrl", "syscon"; + compatible = "brcm,bcm7445-cpu-biu-ctrl", "brcm,brcmstb-cpu-biu-ctrl", "syscon"; reg = <0x3e2400 0x5b4>; brcm,write-pairing; }; diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt index a0009b72e9be..f4a777039f03 100644 --- a/Documentation/devicetree/bindings/arm/cpus.txt +++ b/Documentation/devicetree/bindings/arm/cpus.txt @@ -169,6 +169,7 @@ described below. "arm,cortex-r5" "arm,cortex-r7" "brcm,brahma-b15" + "brcm,brahma-b53" "brcm,vulcan" "cavium,thunder" "cavium,thunder2" diff --git a/Documentation/devicetree/bindings/arm/firmware/sdei.txt b/Documentation/devicetree/bindings/arm/firmware/sdei.txt new file mode 100644 index 000000000000..ee3f0ff49889 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/firmware/sdei.txt @@ -0,0 +1,42 @@ +* Software Delegated Exception Interface (SDEI) + +Firmware implementing the SDEI functions described in ARM document number +ARM DEN 0054A ("Software Delegated Exception Interface") can be used by +Linux to receive notification of events such as those generated by +firmware-first error handling, or from an IRQ that has been promoted to +a firmware-assisted NMI. + +The interface provides a number of API functions for registering callbacks +and enabling/disabling events. Functions are invoked by trapping to the +privilege level of the SDEI firmware (specified as part of the binding +below) and passing arguments in a manner specified by the "SMC Calling +Convention (ARM DEN 0028B): + + r0 => 32-bit Function ID / return value + {r1 - r3} => Parameters + +Note that the immediate field of the trapping instruction must be set +to #0. + +The SDEI_EVENT_REGISTER function registers a callback in the kernel +text to handle the specified event number. + +The sdei node should be a child node of '/firmware' and have required +properties: + + - compatible : should contain: + * "arm,sdei-1.0" : For implementations complying to SDEI version 1.x. + + - method : The method of calling the SDEI firmware. Permitted + values are: + * "smc" : SMC #0, with the register assignments specified in this + binding. + * "hvc" : HVC #0, with the register assignments specified in this + binding. +Example: + firmware { + sdei { + compatible = "arm,sdei-1.0"; + method = "smc"; + }; + }; diff --git a/Documentation/devicetree/bindings/arm/marvell/armada-37xx.txt b/Documentation/devicetree/bindings/arm/marvell/armada-37xx.txt index 51336e5fc761..35c3c3460d17 100644 --- a/Documentation/devicetree/bindings/arm/marvell/armada-37xx.txt +++ b/Documentation/devicetree/bindings/arm/marvell/armada-37xx.txt @@ -14,3 +14,22 @@ following property before the previous one: Example: compatible = "marvell,armada-3720-db", "marvell,armada3720", "marvell,armada3710"; + + +Power management +---------------- + +For power management (particularly DVFS and AVS), the North Bridge +Power Management component is needed: + +Required properties: +- compatible : should contain "marvell,armada-3700-nb-pm", "syscon"; +- reg : the register start and length for the North Bridge + Power Management + +Example: + +nb_pm: syscon@14000 { + compatible = "marvell,armada-3700-nb-pm", "syscon"; + reg = <0x14000 0x60>; +} diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt index 7aa3fa167668..6cc7840ff37a 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt @@ -20,4 +20,5 @@ ethsys: clock-controller@1b000000 { compatible = "mediatek,mt2701-ethsys", "syscon"; reg = <0 0x1b000000 0 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt index ccaaec6014bd..6c49db7f8ad2 100644 --- a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt +++ b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt @@ -55,7 +55,7 @@ Note: child nodes can be added for auto probing from device tree. Example: adding device info in dtsi file -adc: adc@12D10000 { +adc: adc@12d10000 { compatible = "samsung,exynos-adc-v1"; reg = <0x12D10000 0x100>; interrupts = <0 106 0>; @@ -71,7 +71,7 @@ adc: adc@12D10000 { Example: adding device info in dtsi file for Exynos3250 with additional sclk -adc: adc@126C0000 { +adc: adc@126c0000 { compatible = "samsung,exynos3250-adc", "samsung,exynos-adc-v2; reg = <0x126C0000 0x100>; interrupts = <0 137 0>; @@ -87,7 +87,7 @@ adc: adc@126C0000 { Example: Adding child nodes in dts file -adc@12D10000 { +adc@12d10000 { /* NTC thermistor is a hwmon device */ ncp15wb473@0 { diff --git a/Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt index e13459618581..469ac98ecf8f 100644 --- a/Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt +++ b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt @@ -72,7 +72,7 @@ Optional nodes: - compatible: only "samsung,secure-firmware" is currently supported - reg: address of non-secure SYSRAM used for communication with firmware - firmware@203F000 { + firmware@203f000 { compatible = "samsung,secure-firmware"; reg = <0x0203F000 0x1000>; }; diff --git a/Documentation/devicetree/bindings/arm/shmobile.txt b/Documentation/devicetree/bindings/arm/shmobile.txt index 020d758fc0c5..5c3af7ef0761 100644 --- a/Documentation/devicetree/bindings/arm/shmobile.txt +++ b/Documentation/devicetree/bindings/arm/shmobile.txt @@ -104,12 +104,16 @@ Boards: compatible = "renesas,salvator-x", "renesas,r8a7796" - Salvator-XS (Salvator-X 2nd version, RTP0RC7795SIPB0012S) compatible = "renesas,salvator-xs", "renesas,r8a7795" + - Salvator-XS (Salvator-X 2nd version, RTP0RC7796SIPB0012S) + compatible = "renesas,salvator-xs", "renesas,r8a7796" - SILK (RTP0RC7794LCB00011S) compatible = "renesas,silk", "renesas,r8a7794" - SK-RZG1E (YR8A77450S000BE) compatible = "renesas,sk-rzg1e", "renesas,r8a7745" - SK-RZG1M (YR8A77430S000BE) compatible = "renesas,sk-rzg1m", "renesas,r8a7743" + - V3MSK + compatible = "renesas,v3msk", "renesas,r8a77970" - Wheat compatible = "renesas,wheat", "renesas,r8a7792" diff --git a/Documentation/devicetree/bindings/arm/stm32.txt b/Documentation/devicetree/bindings/arm/stm32.txt new file mode 100644 index 000000000000..05762b08a7bb --- /dev/null +++ b/Documentation/devicetree/bindings/arm/stm32.txt @@ -0,0 +1,9 @@ +STMicroelectronics STM32 Platforms Device Tree Bindings + +Each device tree must specify which STM32 SoC it uses, +using one of the following compatible strings: + + st,stm32f429 + st,stm32f469 + st,stm32f746 + st,stm32h743 diff --git a/Documentation/devicetree/bindings/arm/technologic.txt b/Documentation/devicetree/bindings/arm/technologic.txt index 33797acad846..f1cedc00dcab 100644 --- a/Documentation/devicetree/bindings/arm/technologic.txt +++ b/Documentation/devicetree/bindings/arm/technologic.txt @@ -1,6 +1,11 @@ Technologic Systems Platforms Device Tree Bindings -------------------------------------------------- +TS-4600 is a System-on-Module based on the Freescale i.MX28 System-on-Chip. +It can be mounted on a carrier board providing additional peripheral connectors. +Required root node properties: + - compatible = "technologic,imx28-ts4600", "fsl,imx28" + TS-4800 board Required root node properties: - compatible = "technologic,imx51-ts4800", "fsl,imx51"; @@ -10,3 +15,9 @@ It can be mounted on a carrier board providing additional peripheral connectors. Required root node properties: - compatible = "technologic,imx6dl-ts4900", "fsl,imx6dl" - compatible = "technologic,imx6q-ts4900", "fsl,imx6q" + +TS-7970 is a System-on-Module based on the Freescale i.MX6 System-on-Chip. +It can be mounted on a carrier board providing additional peripheral connectors. +Required root node properties: + - compatible = "technologic,imx6dl-ts7970", "fsl,imx6dl" + - compatible = "technologic,imx6q-ts7970", "fsl,imx6q" diff --git a/Documentation/devicetree/bindings/bus/ti-sysc.txt b/Documentation/devicetree/bindings/bus/ti-sysc.txt index fb1790e39398..2957a9ae291f 100644 --- a/Documentation/devicetree/bindings/bus/ti-sysc.txt +++ b/Documentation/devicetree/bindings/bus/ti-sysc.txt @@ -19,6 +19,7 @@ Required standard properties: - compatible shall be one of the following generic types: + "ti,sysc" "ti,sysc-omap2" "ti,sysc-omap4" "ti,sysc-omap4-simple" @@ -26,6 +27,8 @@ Required standard properties: or one of the following derivative types for hardware needing special workarounds: + "ti,sysc-omap2-timer" + "ti,sysc-omap4-timer" "ti,sysc-omap3430-sr" "ti,sysc-omap3630-sr" "ti,sysc-omap4-sr" @@ -49,6 +52,26 @@ Required standard properties: Optional properties: +- ti,sysc-mask shall contain mask of supported register bits for the + SYSCONFIG register as documented in the Technical Reference + Manual (TRM) for the interconnect target module + +- ti,sysc-midle list of master idle modes supported by the interconnect + target module as documented in the TRM for SYSCONFIG + register MIDLEMODE bits + +- ti,sysc-sidle list of slave idle modes supported by the interconnect + target module as documented in the TRM for SYSCONFIG + register SIDLEMODE bits + +- ti,sysc-delay-us delay needed after OCP softreset before accssing + SYSCONFIG register again + +- ti,syss-mask optional mask of reset done status bits as described in the + TRM for SYSSTATUS registers, typically 1 with some devices + having separate reset done bits for children like OHCI and + EHCI + - clocks clock specifier for each name in the clock-names as specified in the binding documentation for ti-clkctrl, typically available for all interconnect targets on TI SoCs @@ -61,6 +84,9 @@ Optional properties: - ti,hwmods optional TI interconnect module name to use legacy hwmod platform data +- ti,no-reset-on-init interconnect target module should not be reset at init + +- ti,no-idle-on-init interconnect target module should not be idled at init Example: Single instance of MUSB controller on omap4 using interconnect ranges using offsets from l4_cfg second segment (0x4a000000 + 0x80000 = 0x4a0ab000): @@ -74,6 +100,17 @@ using offsets from l4_cfg second segment (0x4a000000 + 0x80000 = 0x4a0ab000): reg-names = "rev", "sysc", "syss"; clocks = <&l3_init_clkctrl OMAP4_USB_OTG_HS_CLKCTRL 0>; clock-names = "fck"; + ti,sysc-mask = <(SYSC_OMAP2_ENAWAKEUP | + SYSC_OMAP2_SOFTRESET | + SYSC_OMAP2_AUTOIDLE)>; + ti,sysc-midle = , + , + ; + ti,sysc-sidle = , + , + , + ; + ti,syss-mask = <1>; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x2b000 0x1000>; diff --git a/Documentation/devicetree/bindings/chosen.txt b/Documentation/devicetree/bindings/chosen.txt index e3b13ea7d2ae..45e79172a646 100644 --- a/Documentation/devicetree/bindings/chosen.txt +++ b/Documentation/devicetree/bindings/chosen.txt @@ -120,3 +120,18 @@ e.g. While this property does not represent a real hardware, the address and the size are expressed in #address-cells and #size-cells, respectively, of the root node. + +linux,initrd-start and linux,initrd-end +--------------------------------------- + +These properties hold the physical start and end address of an initrd that's +loaded by the bootloader. Note that linux,initrd-start is inclusive, but +linux,initrd-end is exclusive. +e.g. + +/ { + chosen { + linux,initrd-start = <0x82000000>; + linux,initrd-end = <0x82800000>; + }; +}; diff --git a/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt index 924040769186..e2b377ed6f91 100644 --- a/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt +++ b/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt @@ -5,8 +5,11 @@ controllers within the SoC. Required Properties: -- compatible: should be "amlogic,gxbb-clkc" for GXBB SoC, - or "amlogic,gxl-clkc" for GXL and GXM SoC. +- compatible: should be: + "amlogic,gxbb-clkc" for GXBB SoC, + "amlogic,gxl-clkc" for GXL and GXM SoC, + "amlogic,axg-clkc" for AXG SoC. + - reg: physical base address of the clock controller and length of memory mapped region. diff --git a/Documentation/devicetree/bindings/clock/exynos3250-clock.txt b/Documentation/devicetree/bindings/clock/exynos3250-clock.txt index f1738b88c225..7441ed519f02 100644 --- a/Documentation/devicetree/bindings/clock/exynos3250-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos3250-clock.txt @@ -32,7 +32,7 @@ Example 1: Examples of clock controller nodes are listed below. #clock-cells = <1>; }; - cmu_dmc: clock-controller@105C0000 { + cmu_dmc: clock-controller@105c0000 { compatible = "samsung,exynos3250-cmu-dmc"; reg = <0x105C0000 0x2000>; #clock-cells = <1>; diff --git a/Documentation/devicetree/bindings/clock/exynos5260-clock.txt b/Documentation/devicetree/bindings/clock/exynos5260-clock.txt index 5496b2fac483..c79d31f7f66e 100644 --- a/Documentation/devicetree/bindings/clock/exynos5260-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5260-clock.txt @@ -180,7 +180,7 @@ Example 2: UART controller node that consumes the clock generated by the peri clock controller. Refer to the standard clock bindings for information about 'clocks' and 'clock-names' property. - serial@12C00000 { + serial@12c00000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C00000 0x100>; interrupts = <0 146 0>; diff --git a/Documentation/devicetree/bindings/clock/exynos5410-clock.txt b/Documentation/devicetree/bindings/clock/exynos5410-clock.txt index c68b0d29b3d0..217beb27c30e 100644 --- a/Documentation/devicetree/bindings/clock/exynos5410-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5410-clock.txt @@ -41,7 +41,7 @@ Example 2: UART controller node that consumes the clock generated by the clock controller. Refer to the standard clock bindings for information about 'clocks' and 'clock-names' property. - serial@12C20000 { + serial@12c20000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C00000 0x100>; interrupts = <0 51 0>; diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index c473dd38dd55..50d5897c9849 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -472,7 +472,7 @@ Example 2: Examples of clock controller nodes are listed below. Example 3: UART controller node that consumes the clock generated by the clock controller. - serial_0: serial@14C10000 { + serial_0: serial@14c10000 { compatible = "samsung,exynos5433-uart"; reg = <0x14C10000 0x100>; interrupts = <0 421 0>; diff --git a/Documentation/devicetree/bindings/clock/hi3660-clock.txt b/Documentation/devicetree/bindings/clock/hi3660-clock.txt index 0035a7ecaf20..946da7cee54f 100644 --- a/Documentation/devicetree/bindings/clock/hi3660-clock.txt +++ b/Documentation/devicetree/bindings/clock/hi3660-clock.txt @@ -13,12 +13,18 @@ Required Properties: - "hisilicon,hi3660-pmuctrl" - "hisilicon,hi3660-sctrl" - "hisilicon,hi3660-iomcu" + - "hisilicon,hi3660-stub-clk" - reg: physical base address of the controller and length of memory mapped region. - #clock-cells: should be 1. +Optional Properties: + +- mboxes: Phandle to the mailbox for sending message to MCU. + (See: ../mailbox/hisilicon,hi3660-mailbox.txt for more info) + Each clock is assigned an identifier and client nodes use this identifier to specify the clock which they consume. diff --git a/Documentation/devicetree/bindings/clock/qcom,a53pll.txt b/Documentation/devicetree/bindings/clock/qcom,a53pll.txt new file mode 100644 index 000000000000..e3fa8118eaee --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,a53pll.txt @@ -0,0 +1,22 @@ +Qualcomm MSM8916 A53 PLL Binding +-------------------------------- +The A53 PLL on MSM8916 platforms is the main CPU PLL used used for frequencies +above 1GHz. + +Required properties : +- compatible : Shall contain only one of the following: + + "qcom,msm8916-a53pll" + +- reg : shall contain base register location and length + +- #clock-cells : must be set to <0> + +Example: + + a53pll: clock@b016000 { + compatible = "qcom,msm8916-a53pll"; + reg = <0xb016000 0x40>; + #clock-cells = <0>; + }; + diff --git a/Documentation/devicetree/bindings/clock/qcom,spmi-clkdiv.txt b/Documentation/devicetree/bindings/clock/qcom,spmi-clkdiv.txt new file mode 100644 index 000000000000..7474aba36607 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,spmi-clkdiv.txt @@ -0,0 +1,59 @@ +Qualcomm Technologies, Inc. SPMI PMIC clock divider (clkdiv) + +clkdiv configures the clock frequency of a set of outputs on the PMIC. +These clocks are typically wired through alternate functions on +gpio pins. + +======================= +Properties +======================= + +- compatible + Usage: required + Value type: + Definition: must be "qcom,spmi-clkdiv". + +- reg + Usage: required + Value type: + Definition: base address of CLKDIV peripherals. + +- qcom,num-clkdivs + Usage: required + Value type: + Definition: number of CLKDIV peripherals. + +- clocks: + Usage: required + Value type: + Definition: reference to the xo clock. + +- clock-names: + Usage: required + Value type: + Definition: must be "xo". + +- #clock-cells: + Usage: required + Value type: + Definition: shall contain 1. + +======= +Example +======= + +pm8998_clk_divs: clock-controller@5b00 { + compatible = "qcom,spmi-clkdiv"; + reg = <0x5b00>; + #clock-cells = <1>; + qcom,num-clkdivs = <3>; + clocks = <&xo_board>; + clock-names = "xo"; + + assigned-clocks = <&pm8998_clk_divs 1>, + <&pm8998_clk_divs 2>, + <&pm8998_clk_divs 3>; + assigned-clock-rates = <9600000>, + <9600000>, + <9600000>; +}; diff --git a/Documentation/devicetree/bindings/clock/qoriq-clock.txt b/Documentation/devicetree/bindings/clock/qoriq-clock.txt index 6498e1fdbb33..97f46adac85f 100644 --- a/Documentation/devicetree/bindings/clock/qoriq-clock.txt +++ b/Documentation/devicetree/bindings/clock/qoriq-clock.txt @@ -78,6 +78,7 @@ second cell is the clock index for the specified type. 2 hwaccel index (n in CLKCGnHWACSR) 3 fman 0 for fm1, 1 for fm2 4 platform pll 0=pll, 1=pll/2, 2=pll/3, 3=pll/4 + 4=pll/5, 5=pll/6, 6=pll/7, 7=pll/8 5 coreclk must be 0 3. Example diff --git a/Documentation/devicetree/bindings/clock/silabs,si5351.txt b/Documentation/devicetree/bindings/clock/silabs,si5351.txt index a6c4ef343b44..f00191cad8cd 100644 --- a/Documentation/devicetree/bindings/clock/silabs,si5351.txt +++ b/Documentation/devicetree/bindings/clock/silabs,si5351.txt @@ -49,6 +49,7 @@ Optional child node properties: - silabs,multisynth-source: source pll A(0) or B(1) of corresponding multisynth divider. - silabs,pll-master: boolean, multisynth can change pll frequency. +- silabs,pll-reset: boolean, clock output can reset its pll. - silabs,disable-state : clock output disable state, shall be 0 = clock output is driven LOW when disabled 1 = clock output is driven HIGH when disabled diff --git a/Documentation/devicetree/bindings/clock/sprd.txt b/Documentation/devicetree/bindings/clock/sprd.txt new file mode 100644 index 000000000000..e9d179e882d9 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/sprd.txt @@ -0,0 +1,63 @@ +Spreadtrum Clock Binding +------------------------ + +Required properties: +- compatible: should contain the following compatible strings: + - "sprd,sc9860-pmu-gate" + - "sprd,sc9860-pll" + - "sprd,sc9860-ap-clk" + - "sprd,sc9860-aon-prediv" + - "sprd,sc9860-apahb-gate" + - "sprd,sc9860-aon-gate" + - "sprd,sc9860-aonsecure-clk" + - "sprd,sc9860-agcp-gate" + - "sprd,sc9860-gpu-clk" + - "sprd,sc9860-vsp-clk" + - "sprd,sc9860-vsp-gate" + - "sprd,sc9860-cam-clk" + - "sprd,sc9860-cam-gate" + - "sprd,sc9860-disp-clk" + - "sprd,sc9860-disp-gate" + - "sprd,sc9860-apapb-gate" + +- #clock-cells: must be 1 + +- clocks : Should be the input parent clock(s) phandle for the clock, this + property here just simply shows which clock group the clocks' + parents are in, since each clk node would represent many clocks + which are defined in the driver. The detailed dependency + relationship (i.e. how many parents and which are the parents) + are implemented in driver code. + +Optional properties: + +- reg: Contain the registers base address and length. It must be configured + only if no 'sprd,syscon' under the node. + +- sprd,syscon: phandle to the syscon which is in the same address area with + the clock, and so we can get regmap for the clocks from the + syscon device. + +Example: + + pmu_gate: pmu-gate { + compatible = "sprd,sc9860-pmu-gate"; + sprd,syscon = <&pmu_regs>; + clocks = <&ext_26m>; + #clock-cells = <1>; + }; + + pll: pll { + compatible = "sprd,sc9860-pll"; + sprd,syscon = <&ana_regs>; + clocks = <&pmu_gate 0>; + #clock-cells = <1>; + }; + + ap_clk: clock-controller@20000000 { + compatible = "sprd,sc9860-ap-clk"; + reg = <0 0x20000000 0 0x400>; + clocks = <&ext_26m>, <&pll 0>, + <&pmu_gate 0>; + #clock-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/sun8i-de2.txt b/Documentation/devicetree/bindings/clock/sun8i-de2.txt index 631d27cd89d6..f2fa87c4765c 100644 --- a/Documentation/devicetree/bindings/clock/sun8i-de2.txt +++ b/Documentation/devicetree/bindings/clock/sun8i-de2.txt @@ -4,13 +4,14 @@ Allwinner Display Engine 2.0 Clock Control Binding Required properties : - compatible: must contain one of the following compatibles: - "allwinner,sun8i-a83t-de2-clk" + - "allwinner,sun8i-h3-de2-clk" - "allwinner,sun8i-v3s-de2-clk" - "allwinner,sun50i-h5-de2-clk" - reg: Must contain the registers base address and length - clocks: phandle to the clocks feeding the display engine subsystem. Three are needed: - - "mod": the display engine module clock + - "mod": the display engine module clock (on A83T it's the DE PLL) - "bus": the bus clock for the whole display engine subsystem - clock-names: Must contain the clock names described just above - resets: phandle to the reset control for the display engine subsystem. @@ -19,7 +20,7 @@ Required properties : Example: de2_clocks: clock@1000000 { - compatible = "allwinner,sun8i-a83t-de2-clk"; + compatible = "allwinner,sun8i-h3-de2-clk"; reg = <0x01000000 0x100000>; clocks = <&ccu CLK_BUS_DE>, <&ccu CLK_DE>; diff --git a/Documentation/devicetree/bindings/crypto/arm-cryptocell.txt b/Documentation/devicetree/bindings/crypto/arm-cryptocell.txt new file mode 100644 index 000000000000..cec8d5d74e26 --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/arm-cryptocell.txt @@ -0,0 +1,22 @@ +Arm TrustZone CryptoCell cryptographic engine + +Required properties: +- compatible: Should be "arm,cryptocell-712-ree". +- reg: Base physical address of the engine and length of memory mapped region. +- interrupts: Interrupt number for the device. + +Optional properties: +- interrupt-parent: The phandle for the interrupt controller that services + interrupts for this device. +- clocks: Reference to the crypto engine clock. +- dma-coherent: Present if dma operations are coherent. + +Examples: + + arm_cc712: crypto@80000000 { + compatible = "arm,cryptocell-712-ree"; + interrupt-parent = <&intc>; + interrupts = < 0 30 4 >; + reg = < 0x80000000 0x10000 >; + + }; diff --git a/Documentation/devicetree/bindings/crypto/atmel-crypto.txt b/Documentation/devicetree/bindings/crypto/atmel-crypto.txt index 7de1a9674c70..6b458bb2440d 100644 --- a/Documentation/devicetree/bindings/crypto/atmel-crypto.txt +++ b/Documentation/devicetree/bindings/crypto/atmel-crypto.txt @@ -75,7 +75,7 @@ Required properties: - clock-frequency: must be present in the i2c controller node. Example: -atecc508a@C0 { +atecc508a@c0 { compatible = "atmel,atecc508a"; reg = <0xC0>; }; diff --git a/Documentation/devicetree/bindings/crypto/inside-secure-safexcel.txt b/Documentation/devicetree/bindings/crypto/inside-secure-safexcel.txt index fbc07d12322f..30c3ce6b502e 100644 --- a/Documentation/devicetree/bindings/crypto/inside-secure-safexcel.txt +++ b/Documentation/devicetree/bindings/crypto/inside-secure-safexcel.txt @@ -1,7 +1,8 @@ Inside Secure SafeXcel cryptographic engine Required properties: -- compatible: Should be "inside-secure,safexcel-eip197". +- compatible: Should be "inside-secure,safexcel-eip197" or + "inside-secure,safexcel-eip97". - reg: Base physical address of the engine and length of memory mapped region. - interrupts: Interrupt numbers for the rings and engine. - interrupt-names: Should be "ring0", "ring1", "ring2", "ring3", "eip", "mem". diff --git a/Documentation/devicetree/bindings/crypto/samsung,exynos-rng4.txt b/Documentation/devicetree/bindings/crypto/samsung,exynos-rng4.txt index 4ca8dd4d7e66..a13fbdb4bd88 100644 --- a/Documentation/devicetree/bindings/crypto/samsung,exynos-rng4.txt +++ b/Documentation/devicetree/bindings/crypto/samsung,exynos-rng4.txt @@ -2,7 +2,9 @@ Exynos Pseudo Random Number Generator Required properties: -- compatible : Should be "samsung,exynos4-rng". +- compatible : One of: + - "samsung,exynos4-rng" for Exynos4210 and Exynos4412 + - "samsung,exynos5250-prng" for Exynos5250+ - reg : Specifies base physical address and size of the registers map. - clocks : Phandle to clock-controller plus clock-specifier pair. - clock-names : "secss" as a clock name. diff --git a/Documentation/devicetree/bindings/crypto/st,stm32-cryp.txt b/Documentation/devicetree/bindings/crypto/st,stm32-cryp.txt new file mode 100644 index 000000000000..970487fa40b8 --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/st,stm32-cryp.txt @@ -0,0 +1,19 @@ +* STMicroelectronics STM32 CRYP + +Required properties: +- compatible: Should be "st,stm32f756-cryp". +- reg: The address and length of the peripheral registers space +- clocks: The input clock of the CRYP instance +- interrupts: The CRYP interrupt + +Optional properties: +- resets: The input reset of the CRYP instance + +Example: +crypto@50060000 { + compatible = "st,stm32f756-cryp"; + reg = <0x50060000 0x400>; + interrupts = <79>; + clocks = <&rcc 0 STM32F7_AHB2_CLOCK(CRYP)>; + resets = <&rcc STM32F7_AHB2_RESET(CRYP)>; +}; diff --git a/Documentation/devicetree/bindings/devfreq/event/exynos-nocp.txt b/Documentation/devicetree/bindings/devfreq/event/exynos-nocp.txt index fd459f00aa5a..aeaebd425d1f 100644 --- a/Documentation/devicetree/bindings/devfreq/event/exynos-nocp.txt +++ b/Documentation/devicetree/bindings/devfreq/event/exynos-nocp.txt @@ -20,7 +20,7 @@ Optional properties: Example : NoC Probe nodes in Device Tree are listed below. - nocp_mem0_0: nocp@10CA1000 { + nocp_mem0_0: nocp@10ca1000 { compatible = "samsung,exynos5420-nocp"; reg = <0x10CA1000 0x200>; }; diff --git a/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt b/Documentation/devicetree/bindings/display/bridge/ti,ths813x.txt similarity index 69% rename from Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt rename to Documentation/devicetree/bindings/display/bridge/ti,ths813x.txt index 6ec1a880ac18..df3d7c1ac09e 100644 --- a/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt +++ b/Documentation/devicetree/bindings/display/bridge/ti,ths813x.txt @@ -1,11 +1,16 @@ -THS8135 Video DAC ------------------ +THS8134 and THS8135 Video DAC +----------------------------- -This is the binding for Texas Instruments THS8135 Video DAC bridge. +This is the binding for Texas Instruments THS8134, THS8134A, THS8134B and +THS8135 Video DAC bridges. Required properties: -- compatible: Must be "ti,ths8135" +- compatible: Must be one of + "ti,ths8134" + "ti,ths8134a," "ti,ths8134" + "ti,ths8134b", "ti,ths8134" + "ti,ths8135" Required nodes: diff --git a/Documentation/devicetree/bindings/display/exynos/exynos_dsim.txt b/Documentation/devicetree/bindings/display/exynos/exynos_dsim.txt index ca5204b3bc21..2fff8b406f4c 100644 --- a/Documentation/devicetree/bindings/display/exynos/exynos_dsim.txt +++ b/Documentation/devicetree/bindings/display/exynos/exynos_dsim.txt @@ -54,7 +54,7 @@ Video interfaces: Example: - dsi@11C80000 { + dsi@11c80000 { compatible = "samsung,exynos4210-mipi-dsi"; reg = <0x11C80000 0x10000>; interrupts = <0 79 0>; diff --git a/Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.txt b/Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.txt new file mode 100644 index 000000000000..248141c3c7e3 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.txt @@ -0,0 +1,31 @@ +ARM Versatile TFT Panels + +These panels are connected to the daughterboards found on the +ARM Versatile reference designs. + +This device node must appear as a child to a "syscon"-compatible +node. + +Required properties: +- compatible: should be "arm,versatile-tft-panel" + +Required subnodes: +- port: see display/panel/panel-common.txt, graph.txt + + +Example: + +sysreg@0 { + compatible = "arm,versatile-sysreg", "syscon", "simple-mfd"; + reg = <0x00000 0x1000>; + + panel: display@0 { + compatible = "arm,versatile-tft-panel"; + + port { + panel_in: endpoint { + remote-endpoint = <&foo>; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/display/panel/sgd,gktw70sdae4se.txt b/Documentation/devicetree/bindings/display/panel/sgd,gktw70sdae4se.txt new file mode 100644 index 000000000000..d06644b555bd --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/sgd,gktw70sdae4se.txt @@ -0,0 +1,41 @@ +Solomon Goldentek Display GKTW70SDAE4SE LVDS Display Panel +========================================================== + +The GKTW70SDAE4SE is a 7" WVGA TFT-LCD display panel. + +These DT bindings follow the LVDS panel bindings defined in panel-lvds.txt +with the following device-specific properties. + +Required properties: + +- compatible: Shall contain "sgd,gktw70sdae4se" and "panel-lvds", in that order. + +Example +------- + +panel { + compatible = "sgd,gktw70sdae4se", "panel-lvds"; + + width-mm = <153>; + height-mm = <86>; + + data-mapping = "jeida-18"; + + panel-timing { + clock-frequency = <32000000>; + hactive = <800>; + vactive = <480>; + hback-porch = <39>; + hfront-porch = <39>; + vback-porch = <29>; + vfront-porch = <13>; + hsync-len = <47>; + vsync-len = <2>; + }; + + port { + panel_in: endpoint { + remote-endpoint = <&lvds_encoder>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt b/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt index 4c0caaf246c9..89826116628c 100644 --- a/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt +++ b/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt @@ -1,7 +1,7 @@ Toshiba 8.9" WXGA (1280x768) TFT LCD panel Required properties: -- compatible: should be "toshiba,lt089ac29000.txt" +- compatible: should be "toshiba,lt089ac29000" - power-supply: as specified in the base binding This binding is compatible with the simple-panel binding, which is specified diff --git a/Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt new file mode 100644 index 000000000000..8df7d2e393d6 --- /dev/null +++ b/Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt @@ -0,0 +1,74 @@ +Rockchip RK3399 specific extensions to the cdn Display Port +================================ + +Required properties: +- compatible: must be "rockchip,rk3399-cdn-dp" + +- reg: physical base address of the controller and length + +- clocks: from common clock binding: handle to dp clock. + +- clock-names: from common clock binding: + Required elements: "core-clk" "pclk" "spdif" "grf" + +- resets : a list of phandle + reset specifier pairs +- reset-names : string of reset names + Required elements: "apb", "core", "dptx", "spdif" +- power-domains : power-domain property defined with a phandle + to respective power domain. +- assigned-clocks: main clock, should be <&cru SCLK_DP_CORE> +- assigned-clock-rates : the DP core clk frequency, shall be: 100000000 + +- rockchip,grf: this soc should set GRF regs, so need get grf here. + +- ports: contain a port nodes with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. + contained 2 endpoints, connecting to the output of vop. + +- phys: from general PHY binding: the phandle for the PHY device. + +- extcon: extcon specifier for the Power Delivery + +- #sound-dai-cells = it must be 1 if your system is using 2 DAIs: I2S, SPDIF + +------------------------------------------------------------------------------- + +Example: + cdn_dp: dp@fec00000 { + compatible = "rockchip,rk3399-cdn-dp"; + reg = <0x0 0xfec00000 0x0 0x100000>; + interrupts = ; + clocks = <&cru SCLK_DP_CORE>, <&cru PCLK_DP_CTRL>, + <&cru SCLK_SPDIF_REC_DPTX>, <&cru PCLK_VIO_GRF>; + clock-names = "core-clk", "pclk", "spdif", "grf"; + assigned-clocks = <&cru SCLK_DP_CORE>; + assigned-clock-rates = <100000000>; + power-domains = <&power RK3399_PD_HDCP>; + phys = <&tcphy0_dp>, <&tcphy1_dp>; + resets = <&cru SRST_DPTX_SPDIF_REC>; + reset-names = "spdif"; + extcon = <&fusb0>, <&fusb1>; + rockchip,grf = <&grf>; + #address-cells = <1>; + #size-cells = <0>; + #sound-dai-cells = <1>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + dp_in: port { + #address-cells = <1>; + #size-cells = <0>; + dp_in_vopb: endpoint@0 { + reg = <0>; + remote-endpoint = <&vopb_out_dp>; + }; + + dp_in_vopl: endpoint@1 { + reg = <1>; + remote-endpoint = <&vopl_out_dp>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/simple-framebuffer-sunxi.txt b/Documentation/devicetree/bindings/display/simple-framebuffer-sunxi.txt index a9168ae6946c..d693b8dc9a62 100644 --- a/Documentation/devicetree/bindings/display/simple-framebuffer-sunxi.txt +++ b/Documentation/devicetree/bindings/display/simple-framebuffer-sunxi.txt @@ -15,6 +15,10 @@ Required properties: "de_be1-lcd1" "de_be0-lcd0-hdmi" "de_be1-lcd1-hdmi" + "mixer0-lcd0" + "mixer0-lcd0-hdmi" + "mixer1-lcd1-hdmi" + "mixer1-lcd1-tve" Example: diff --git a/Documentation/devicetree/bindings/display/st,stih4xx.txt b/Documentation/devicetree/bindings/display/st,stih4xx.txt index a352ed30cd70..6778b3e7ad5b 100644 --- a/Documentation/devicetree/bindings/display/st,stih4xx.txt +++ b/Documentation/devicetree/bindings/display/st,stih4xx.txt @@ -119,7 +119,7 @@ Example: / { ... - vtg_main_slave: sti-vtg-main-slave@fe85A800 { + vtg_main_slave: sti-vtg-main-slave@fe85a800 { compatible = "st,vtg"; reg = <0xfe85A800 0x300>; interrupts = ; diff --git a/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt b/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt index 029252253ad4..3eb1b48b47dd 100644 --- a/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt +++ b/Documentation/devicetree/bindings/display/st,stm32-ltdc.txt @@ -98,7 +98,7 @@ Example 2: DSI panel compatible = "st,stm32-dsi"; reg = <0x40016c00 0x800>; clocks = <&rcc 1 CLK_F469_DSI>, <&clk_hse>; - clock-names = "ref", "pclk"; + clock-names = "pclk", "ref"; resets = <&rcc STM32F4_APB2_RESET(DSI)>; reset-names = "apb"; diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index cd626ee1147a..b995bfee734a 100644 --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt @@ -64,6 +64,52 @@ Required properties: first port should be the input endpoint. The second should be the output, usually to an HDMI connector. +DWC HDMI TX Encoder +------------------- + +The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP +with Allwinner's own PHY IP. It supports audio and video outputs and CEC. + +These DT bindings follow the Synopsys DWC HDMI TX bindings defined in +Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the +following device-specific properties. + +Required properties: + + - compatible: value must be one of: + * "allwinner,sun8i-a83t-dw-hdmi" + - reg: base address and size of memory-mapped region + - reg-io-width: See dw_hdmi.txt. Shall be 1. + - interrupts: HDMI interrupt number + - clocks: phandles to the clocks feeding the HDMI encoder + * iahb: the HDMI bus clock + * isfr: the HDMI register clock + * tmds: TMDS clock + - clock-names: the clock names mentioned above + - resets: phandle to the reset controller + - reset-names: must be "ctrl" + - phys: phandle to the DWC HDMI PHY + - phy-names: must be "phy" + + - ports: A ports node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. The + first port should be the input endpoint. The second should be the + output, usually to an HDMI connector. + +DWC HDMI PHY +------------ + +Required properties: + - compatible: value must be one of: + * allwinner,sun8i-a83t-hdmi-phy + - reg: base address and size of memory-mapped region + - clocks: phandles to the clocks feeding the HDMI PHY + * bus: the HDMI PHY interface clock + * mod: the HDMI PHY module clock + - clock-names: the clock names mentioned above + - resets: phandle to the reset controller driving the PHY + - reset-names: must be "phy" + TV Encoder ---------- @@ -94,24 +140,26 @@ Required properties: * allwinner,sun7i-a20-tcon * allwinner,sun8i-a33-tcon * allwinner,sun8i-a83t-tcon-lcd + * allwinner,sun8i-a83t-tcon-tv * allwinner,sun8i-v3s-tcon - reg: base address and size of memory-mapped region - interrupts: interrupt associated to this IP - - clocks: phandles to the clocks feeding the TCON. Three are needed: + - clocks: phandles to the clocks feeding the TCON. - 'ahb': the interface clocks - - 'tcon-ch0': The clock driving the TCON channel 0 + - 'tcon-ch0': The clock driving the TCON channel 0, except for A83T TV TCON - resets: phandles to the reset controllers driving the encoder - "lcd": the reset line for the TCON channel 0 - clock-names: the clock names mentioned above - reset-names: the reset names mentioned above - - clock-output-names: Name of the pixel clock created + - clock-output-names: Name of the pixel clock created, if TCON supports + channel 0. - ports: A ports node with endpoint definitions as defined in Documentation/devicetree/bindings/media/video-interfaces.txt. The first port should be the input endpoint, the second one the output - The output may have multiple endpoints. The TCON has two channels, + The output may have multiple endpoints. TCON can have 1 or 2 channels, usually with the first channel being used for the panels interfaces (RGB, LVDS, etc.), and the second being used for the outputs that require another controller (TV Encoder, HDMI, etc.). The endpoints @@ -122,8 +170,8 @@ Required properties: On SoCs other than the A33 and V3s, there is one more clock required: - 'tcon-ch1': The clock driving the TCON channel 1 -On SoCs that support LVDS (all SoCs but the A13, H3, H5 and V3s), you -need one more reset line: +When TCON support LVDS (all TCONs except TV TCON on A83T and those found +in A13, H3, H5 and V3s SoCs), you need one more reset line: - 'lvds': The reset line driving the LVDS logic And on the A23, A31, A31s and A33, you need one more clock line: @@ -226,6 +274,7 @@ supported. Required properties: - compatible: value must be one of: * allwinner,sun8i-a83t-de2-mixer-0 + * allwinner,sun8i-a83t-de2-mixer-1 * allwinner,sun8i-v3s-de2-mixer - reg: base address and size of the memory-mapped region. - clocks: phandles to the clocks feeding the mixer diff --git a/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt b/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt index b3408cc57be6..1ae4748730a8 100644 --- a/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt +++ b/Documentation/devicetree/bindings/dma/qcom_hidma_mgmt.txt @@ -47,8 +47,8 @@ When the OS is not in control of the management interface (i.e. it's a guest), the channel nodes appear on their own, not under a management node. Required properties: -- compatible: must contain "qcom,hidma-1.0" for initial HW or "qcom,hidma-1.1" -for MSI capable HW. +- compatible: must contain "qcom,hidma-1.0" for initial HW or + "qcom,hidma-1.1"/"qcom,hidma-1.2" for MSI capable HW. - reg: Addresses for the transfer and event channel - interrupts: Should contain the event interrupt - desc-count: Number of asynchronous requests this channel can handle diff --git a/Documentation/devicetree/bindings/dma/snps-dma.txt b/Documentation/devicetree/bindings/dma/snps-dma.txt index a122723907ac..99acc712f83a 100644 --- a/Documentation/devicetree/bindings/dma/snps-dma.txt +++ b/Documentation/devicetree/bindings/dma/snps-dma.txt @@ -64,6 +64,6 @@ Example: reg = <0xe0000000 0x1000>; interrupts = <0 35 0x4>; dmas = <&dmahost 12 0 1>, - <&dmahost 13 0 1 0>; + <&dmahost 13 1 0>; dma-names = "rx", "rx"; }; diff --git a/Documentation/devicetree/bindings/dma/ste-dma40.txt b/Documentation/devicetree/bindings/dma/ste-dma40.txt index aa7dbd565ad0..99ab5c4d331e 100644 --- a/Documentation/devicetree/bindings/dma/ste-dma40.txt +++ b/Documentation/devicetree/bindings/dma/ste-dma40.txt @@ -15,7 +15,7 @@ Optional properties: Example: - dma: dma-controller@801C0000 { + dma: dma-controller@801c0000 { compatible = "stericsson,db8500-dma40", "stericsson,dma40"; reg = <0x801C0000 0x1000 0x40010000 0x800>; reg-names = "base", "lcpa"; diff --git a/Documentation/devicetree/bindings/eeprom/at24.txt b/Documentation/devicetree/bindings/eeprom/at24.txt new file mode 100644 index 000000000000..1812c848e369 --- /dev/null +++ b/Documentation/devicetree/bindings/eeprom/at24.txt @@ -0,0 +1,78 @@ +EEPROMs (I2C) + +Required properties: + + - compatible: Must be a "," pair. The following + values are supported (assuming "atmel" as manufacturer): + + "atmel,24c00", + "atmel,24c01", + "atmel,24cs01", + "atmel,24c02", + "atmel,24cs02", + "atmel,24mac402", + "atmel,24mac602", + "atmel,spd", + "atmel,24c04", + "atmel,24cs04", + "atmel,24c08", + "atmel,24cs08", + "atmel,24c16", + "atmel,24cs16", + "atmel,24c32", + "atmel,24cs32", + "atmel,24c64", + "atmel,24cs64", + "atmel,24c128", + "atmel,24c256", + "atmel,24c512", + "atmel,24c1024", + + If is not "atmel", then a fallback must be used + with the same and "atmel" as manufacturer. + + Example: + compatible = "microchip,24c128", "atmel,24c128"; + + Supported manufacturers are: + + "catalyst", + "microchip", + "ramtron", + "renesas", + "nxp", + "st", + + Some vendors use different model names for chips which are just + variants of the above. Known such exceptions are listed below: + + "renesas,r1ex24002" - the fallback is "atmel,24c02" + + - reg: The I2C address of the EEPROM. + +Optional properties: + + - pagesize: The length of the pagesize for writing. Please consult the + manual of your device, that value varies a lot. A wrong value + may result in data loss! If not specified, a safety value of + '1' is used which will be very slow. + + - read-only: This parameterless property disables writes to the eeprom. + + - size: Total eeprom size in bytes. + + - no-read-rollover: This parameterless property indicates that the + multi-address eeprom does not automatically roll over + reads to the next slave address. Please consult the + manual of your device. + + - wp-gpios: GPIO to which the write-protect pin of the chip is connected. + +Example: + +eeprom@52 { + compatible = "atmel,24c32"; + reg = <0x52>; + pagesize = <32>; + wp-gpios = <&gpio1 3 0>; +}; diff --git a/Documentation/devicetree/bindings/eeprom/at25.txt b/Documentation/devicetree/bindings/eeprom/at25.txt index e823d90b802f..b3bde97dc199 100644 --- a/Documentation/devicetree/bindings/eeprom/at25.txt +++ b/Documentation/devicetree/bindings/eeprom/at25.txt @@ -11,7 +11,9 @@ Required properties: - spi-max-frequency : max spi frequency to use - pagesize : size of the eeprom page - size : total eeprom size in bytes -- address-width : number of address bits (one of 8, 16, or 24) +- address-width : number of address bits (one of 8, 9, 16, or 24). + For 9 bits, the MSB of the address is sent as bit 3 of the instruction + byte, before the address byte. Optional properties: - spi-cpha : SPI shifted clock phase, as per spi-bus bindings. diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt deleted file mode 100644 index 27f2bc15298a..000000000000 --- a/Documentation/devicetree/bindings/eeprom/eeprom.txt +++ /dev/null @@ -1,47 +0,0 @@ -EEPROMs (I2C) - -Required properties: - - - compatible : should be ",", like these: - - "atmel,24c00", "atmel,24c01", "atmel,24c02", "atmel,24c04", - "atmel,24c08", "atmel,24c16", "atmel,24c32", "atmel,24c64", - "atmel,24c128", "atmel,24c256", "atmel,24c512", "atmel,24c1024" - - "catalyst,24c32" - - "microchip,24c128" - - "ramtron,24c64" - - "renesas,r1ex24002" - - The following manufacturers values have been deprecated: - "at", "at24" - - If there is no specific driver for , a generic - device with and manufacturer "atmel" should be used. - Possible types are: - "24c00", "24c01", "24c02", "24c04", "24c08", "24c16", "24c32", "24c64", - "24c128", "24c256", "24c512", "24c1024", "spd" - - - reg : the I2C address of the EEPROM - -Optional properties: - - - pagesize : the length of the pagesize for writing. Please consult the - manual of your device, that value varies a lot. A wrong value - may result in data loss! If not specified, a safety value of - '1' is used which will be very slow. - - - read-only: this parameterless property disables writes to the eeprom - - - size: total eeprom size in bytes - -Example: - -eeprom@52 { - compatible = "atmel,24c32"; - reg = <0x52>; - pagesize = <32>; -}; diff --git a/Documentation/devicetree/bindings/gpio/abilis,tb10x-gpio.txt b/Documentation/devicetree/bindings/gpio/abilis,tb10x-gpio.txt index 00611aceed3e..a25c87b650e5 100644 --- a/Documentation/devicetree/bindings/gpio/abilis,tb10x-gpio.txt +++ b/Documentation/devicetree/bindings/gpio/abilis,tb10x-gpio.txt @@ -21,7 +21,7 @@ Documentation/devicetree/bindings/gpio/gpio.txt Example: - gpioa: gpio@FF140000 { + gpioa: gpio@ff140000 { compatible = "abilis,tb10x-gpio"; interrupt-controller; #interrupt-cells = <1>; diff --git a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt index a6611304dd3c..fc42b2caa06d 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt @@ -1,10 +1,17 @@ -AXP209 GPIO controller +AXP209 GPIO & pinctrl controller This driver follows the usual GPIO bindings found in Documentation/devicetree/bindings/gpio/gpio.txt +This driver follows the usual pinctrl bindings found in +Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +This driver employs the per-pin muxing pattern. + Required properties: -- compatible: Should be "x-powers,axp209-gpio" +- compatible: Should be one of: + - "x-powers,axp209-gpio" + - "x-powers,axp813-gpio" - #gpio-cells: Should be two. The first cell is the pin number and the second is the GPIO flags. - gpio-controller: Marks the device node as a GPIO controller. @@ -28,3 +35,41 @@ axp209: pmic@34 { #gpio-cells = <2>; }; }; + +The GPIOs can be muxed to other functions and therefore, must be a subnode of +axp_gpio. + +Example: + +&axp_gpio { + gpio0_adc: gpio0-adc { + pins = "GPIO0"; + function = "adc"; + }; +}; + +&example_node { + pinctrl-names = "default"; + pinctrl-0 = <&gpio0_adc>; +}; + +GPIOs and their functions +------------------------- + +Each GPIO is independent from the other (i.e. GPIO0 in gpio_in function does +not force GPIO1 and GPIO2 to be in gpio_in function as well). + +axp209 +------ +GPIO | Functions +------------------------ +GPIO0 | gpio_in, gpio_out, ldo, adc +GPIO1 | gpio_in, gpio_out, ldo, adc +GPIO2 | gpio_in, gpio_out + +axp813 +------ +GPIO | Functions +------------------------ +GPIO0 | gpio_in, gpio_out, ldo, adc +GPIO1 | gpio_in, gpio_out, ldo diff --git a/Documentation/devicetree/bindings/gpio/gpio-stp-xway.txt b/Documentation/devicetree/bindings/gpio/gpio-stp-xway.txt index 854de130a971..78458adbf4b7 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-stp-xway.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-stp-xway.txt @@ -27,7 +27,7 @@ Optional properties: Example: -gpio1: stp@E100BB0 { +gpio1: stp@e100bb0 { compatible = "lantiq,gpio-stp-xway"; reg = <0xE100BB0 0x40>; #gpio-cells = <2>; diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt index 802402f6cc5d..b5de08e3b1a2 100644 --- a/Documentation/devicetree/bindings/gpio/gpio.txt +++ b/Documentation/devicetree/bindings/gpio/gpio.txt @@ -290,7 +290,7 @@ pins 50..69. Example 2: - gpio_pio_i: gpio-controller@14B0 { + gpio_pio_i: gpio-controller@14b0 { #gpio-cells = <2>; compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank"; reg = <0x1480 0x18>; diff --git a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt index a7ac460ad657..9474138d776e 100644 --- a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt +++ b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt @@ -5,7 +5,7 @@ Required Properties: - compatible: should contain one or more of the following: - "renesas,gpio-r8a7743": for R8A7743 (RZ/G1M) compatible GPIO controller. - "renesas,gpio-r8a7745": for R8A7745 (RZ/G1E) compatible GPIO controller. - - "renesas,gpio-r8a7778": for R8A7778 (R-Mobile M1) compatible GPIO controller. + - "renesas,gpio-r8a7778": for R8A7778 (R-Car M1) compatible GPIO controller. - "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller. - "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) compatible GPIO controller. - "renesas,gpio-r8a7791": for R8A7791 (R-Car M2-W) compatible GPIO controller. diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt b/Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt index c6814d7cc2b2..ad876548ab5d 100644 --- a/Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt +++ b/Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt @@ -17,6 +17,7 @@ Required properties: + rockchip,rk3066-mali + rockchip,rk3188-mali + rockchip,rk3228-mali + + rockchip,rk3328-mali + stericsson,db8500-mali - reg: Physical base address and length of the GPU registers diff --git a/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt b/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt index 367c8203213b..3ac02988a1a5 100644 --- a/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt +++ b/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt @@ -22,8 +22,9 @@ Required properties for pwm-tacho node: - compatible : should be "aspeed,ast2400-pwm-tacho" for AST2400 and "aspeed,ast2500-pwm-tacho" for AST2500. -- clocks : a fixed clock providing input clock frequency(PWM - and Fan Tach clock) +- clocks : phandle to clock provider with the clock number in the second cell + +- resets : phandle to reset controller with the reset number in the second cell fan subnode format: =================== @@ -48,19 +49,14 @@ Required properties for each child node: Examples: -pwm_tacho_fixed_clk: fixedclk { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <24000000>; -}; - pwm_tacho: pwmtachocontroller@1e786000 { #address-cells = <1>; #size-cells = <1>; #cooling-cells = <2>; reg = <0x1E786000 0x1000>; compatible = "aspeed,ast2500-pwm-tacho"; - clocks = <&pwm_tacho_fixed_clk>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_PWM>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default>; diff --git a/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt b/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt index 248a155414c2..548a73cde796 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt @@ -54,7 +54,7 @@ Optional properties: Example: - i2c@12CA0000 { + i2c@12ca0000 { compatible = "acme,some-i2c-device"; #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/i2c/i2c-imx-lpi2c.txt b/Documentation/devicetree/bindings/i2c/i2c-imx-lpi2c.txt index 70c054a9a997..60fe90d69f4e 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-imx-lpi2c.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-imx-lpi2c.txt @@ -11,7 +11,7 @@ Required properties: Examples: -lpi2c7: lpi2c7@40A50000 { +lpi2c7: lpi2c7@40a50000 { compatible = "fsl,imx8dv-lpi2c"; reg = <0x40A50000 0x10000>; interrupt-parent = <&intc>; diff --git a/Documentation/devicetree/bindings/i2c/i2c-meson.txt b/Documentation/devicetree/bindings/i2c/i2c-meson.txt index 611b934c7e10..13d410de077c 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-meson.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-meson.txt @@ -1,7 +1,11 @@ Amlogic Meson I2C controller Required properties: - - compatible: must be "amlogic,meson6-i2c" or "amlogic,meson-gxbb-i2c" + - compatible: must be: + "amlogic,meson6-i2c" for Meson8 and compatible SoCs + "amlogic,meson-gxbb-i2c" for GXBB and compatible SoCs + "amlogic,meson-axg-i2c"for AXG and compatible SoCs + - reg: physical address and length of the device registers - interrupts: a single interrupt specifier - clocks: clock for the device diff --git a/Documentation/devicetree/bindings/i2c/i2c-mtk.txt b/Documentation/devicetree/bindings/i2c/i2c-mtk.txt index ff7bf37deb43..e199695b1c96 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mtk.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mtk.txt @@ -5,6 +5,7 @@ The MediaTek's I2C controller is used to interface with I2C devices. Required properties: - compatible: value should be either of the following. "mediatek,mt2701-i2c", "mediatek,mt6577-i2c": for MediaTek MT2701 + "mediatek,mt2712-i2c": for MediaTek MT2712 "mediatek,mt6577-i2c": for MediaTek MT6577 "mediatek,mt6589-i2c": for MediaTek MT6589 "mediatek,mt7622-i2c": for MediaTek MT7622 diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt index aa097045a10e..34d91501342e 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt @@ -1,10 +1,19 @@ * NXP PCA954x I2C bus switch +The driver supports NXP PCA954x and PCA984x I2C mux/switch devices. + Required Properties: - compatible: Must contain one of the following. - "nxp,pca9540", "nxp,pca9542", "nxp,pca9543", "nxp,pca9544", - "nxp,pca9545", "nxp,pca9546", "nxp,pca9547", "nxp,pca9548" + "nxp,pca9540", + "nxp,pca9542", + "nxp,pca9543", + "nxp,pca9544", + "nxp,pca9545", + "nxp,pca9546", "nxp,pca9846", + "nxp,pca9547", "nxp,pca9847", + "nxp,pca9548", "nxp,pca9848", + "nxp,pca9849" - reg: The I2C address of the device. diff --git a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt index 5c30026921ae..0ffe65a316ae 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt @@ -25,6 +25,15 @@ default frequency is 100kHz whenever you're using the "allwinner,sun6i-a31-i2c" compatible. + - clocks: : pointers to the reference clocks for this device, the + first one is the one used for the clock on the i2c bus, + the second one is the clock used to acces the registers + of the controller + + - clock-names : names of used clocks, mandatory if the second clock is + used, the name must be "core", and "reg" (the latter is + only for Armada 7K/8K). + Examples: i2c@11000 { @@ -42,3 +51,14 @@ For the Armada XP: interrupts = <29>; clock-frequency = <100000>; }; + +For the Armada 7040: + + i2c@701000 { + compatible = "marvell,mv78230-i2c"; + reg = <0x701000 0x20>; + interrupts = <29>; + clock-frequency = <100000>; + clock-names = "core", "reg"; + clocks = <&core_clock>, <®_clock>; + }; diff --git a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt index f413e82c8b83..1e6ee3deb4fa 100644 --- a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt +++ b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt @@ -15,7 +15,6 @@ Required properties: - "clkin" for the reference clock (typically XTAL) - "core" for the SAR ADC core clock optional clocks: - - "sana" for the analog clock - "adc_clk" for the ADC (sampling) clock - "adc_sel" for the ADC (sampling) clock mux - vref-supply: the regulator supply for the ADC reference voltage diff --git a/Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt b/Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt index 674e133b7cd7..034fc2ba100e 100644 --- a/Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt +++ b/Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt @@ -8,6 +8,7 @@ Required properties: - reg: memory window mapping address and length - clocks: Input clock used to derive the sample clock. Expected to be the SoC's APB clock. +- resets: Reset controller phandle - #io-channel-cells: Must be set to <1> to indicate channels are selected by index. @@ -15,6 +16,7 @@ Example: adc@1e6e9000 { compatible = "aspeed,ast2400-adc"; reg = <0x1e6e9000 0xb0>; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_ADC>; #io-channel-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt b/Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt index 552e7a83951d..6469a4cd2a6d 100644 --- a/Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt +++ b/Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt @@ -17,6 +17,11 @@ Required properties: This property uses the IRQ edge types values: IRQ_TYPE_EDGE_RISING , IRQ_TYPE_EDGE_FALLING or IRQ_TYPE_EDGE_BOTH +Optional properties: + - dmas: Phandle to dma channel for the ADC. + - dma-names: Must be "rx" when dmas property is being used. + See ../../dma/dma.txt for details. + Example: adc: adc@fc030000 { @@ -31,4 +36,6 @@ adc: adc@fc030000 { vddana-supply = <&vdd_3v3_lp_reg>; vref-supply = <&vdd_3v3_lp_reg>; atmel,trigger-edge-type = ; + dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | AT91_XDMAC_DT_PERID(25))>; + dma-names = "rx"; } diff --git a/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt b/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt new file mode 100644 index 000000000000..e9ebb8a20e0d --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt @@ -0,0 +1,13 @@ +Device-Tree bindings for sigma delta modulator + +Required properties: +- compatible: should be "ads1201", "sd-modulator". "sd-modulator" can be use + as a generic SD modulator if modulator not specified in compatible list. +- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers". + +Example node: + + ads1202: adc@0 { + compatible = "sd-modulator"; + #io-channel-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt index 48bfcaa3ffcd..e8bb8243e92c 100644 --- a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt +++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt @@ -62,6 +62,15 @@ Required properties: - st,adc-channels: List of single-ended channels muxed for this ADC. It can have up to 16 channels on stm32f4 or 20 channels on stm32h7, numbered from 0 to 15 or 19 (resp. for in0..in15 or in0..in19). +- st,adc-diff-channels: List of differential channels muxed for this ADC. + Depending on part used, some channels can be configured as differential + instead of single-ended (e.g. stm32h7). List here positive and negative + inputs pairs as , ,... vinp and vinn are numbered + from 0 to 19 on stm32h7) + Note: At least one of "st,adc-channels" or "st,adc-diff-channels" is required. + Both properties can be used together. Some channels can be used as + single-ended and some other ones as differential (mixed). But channels + can't be configured both as single-ended and differential (invalid). - #io-channel-cells = <1>: See the IIO bindings section "IIO consumers" in Documentation/devicetree/bindings/iio/iio-bindings.txt @@ -111,3 +120,18 @@ Example: ... other adc child nodes follow... }; + +Example to setup: +- channel 1 as single-ended +- channels 2 & 3 as differential (with resp. 6 & 7 negative inputs) + + adc: adc@40022000 { + compatible = "st,stm32h7-adc-core"; + ... + adc1: adc@0 { + compatible = "st,stm32h7-adc"; + ... + st,adc-channels = <1>; + st,adc-diff-channels = <2 6>, <3 7>; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt new file mode 100644 index 000000000000..911492da48f3 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt @@ -0,0 +1,128 @@ +STMicroelectronics STM32 DFSDM ADC device driver + + +STM32 DFSDM ADC is a sigma delta analog-to-digital converter dedicated to +interface external sigma delta modulators to STM32 micro controllers. +It is mainly targeted for: +- Sigma delta modulators (motor control, metering...) +- PDM microphones (audio digital microphone) + +It features up to 8 serial digital interfaces (SPI or Manchester) and +up to 4 filters on stm32h7. + +Each child node match with a filter instance. + +Contents of a STM32 DFSDM root node: +------------------------------------ +Required properties: +- compatible: Should be "st,stm32h7-dfsdm". +- reg: Offset and length of the DFSDM block register set. +- clocks: IP and serial interfaces clocking. Should be set according + to rcc clock ID and "clock-names". +- clock-names: Input clock name "dfsdm" must be defined, + "audio" is optional. If defined CLKOUT is based on the audio + clock, else "dfsdm" is used. +- #interrupt-cells = <1>; +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties: +- spi-max-frequency: Requested only for SPI master mode. + SPI clock OUT frequency (Hz). This clock must be set according + to "clock" property. Frequency must be a multiple of the rcc + clock frequency. If not, SPI CLKOUT frequency will not be + accurate. + +Contents of a STM32 DFSDM child nodes: +-------------------------------------- + +Required properties: +- compatible: Must be: + "st,stm32-dfsdm-adc" for sigma delta ADCs + "st,stm32-dfsdm-dmic" for audio digital microphone. +- reg: Specifies the DFSDM filter instance used. +- interrupts: IRQ lines connected to each DFSDM filter instance. +- st,adc-channels: List of single-ended channels muxed for this ADC. + valid values: + "st,stm32h7-dfsdm" compatibility: 0 to 7. +- st,adc-channel-names: List of single-ended channel names. +- st,filter-order: SinC filter order from 0 to 5. + 0: FastSinC + [1-5]: order 1 to 5. + For audio purpose it is recommended to use order 3 to 5. +- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers". + +Required properties for "st,stm32-dfsdm-adc" compatibility: +- io-channels: From common IIO binding. Used to pipe external sigma delta + modulator or internal ADC output to DFSDM channel. + This is not required for "st,stm32-dfsdm-pdm" compatibility as + PDM microphone is binded in Audio DT node. + +Required properties for "st,stm32-dfsdm-pdm" compatibility: +- #sound-dai-cells: Must be set to 0. +- dma: DMA controller phandle and DMA request line associated to the + filter instance (specified by the field "reg") +- dma-names: Must be "rx" + +Optional properties: +- st,adc-channel-types: Single-ended channel input type. + - "SPI_R": SPI with data on rising edge (default) + - "SPI_F": SPI with data on falling edge + - "MANCH_R": manchester codec, rising edge = logic 0 + - "MANCH_F": manchester codec, falling edge = logic 1 +- st,adc-channel-clk-src: Conversion clock source. + - "CLKIN": external SPI clock (CLKIN x) + - "CLKOUT": internal SPI clock (CLKOUT) (default) + - "CLKOUT_F": internal SPI clock divided by 2 (falling edge). + - "CLKOUT_R": internal SPI clock divided by 2 (rising edge). + +- st,adc-alt-channel: Must be defined if two sigma delta modulator are + connected on same SPI input. + If not set, channel n is connected to SPI input n. + If set, channel n is connected to SPI input n + 1. + +- st,filter0-sync: Set to 1 to synchronize with DFSDM filter instance 0. + Used for multi microphones synchronization. + +Example of a sigma delta adc connected on DFSDM SPI port 0 +and a pdm microphone connected on DFSDM SPI port 1: + + ads1202: simple_sd_adc@0 { + compatible = "ads1202"; + #io-channel-cells = <1>; + }; + + dfsdm: dfsdm@40017000 { + compatible = "st,stm32h7-dfsdm"; + reg = <0x40017000 0x400>; + clocks = <&rcc DFSDM1_CK>; + clock-names = "dfsdm"; + #interrupt-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + dfsdm_adc0: filter@0 { + compatible = "st,stm32-dfsdm-adc"; + #io-channel-cells = <1>; + reg = <0>; + interrupts = <110>; + st,adc-channels = <0>; + st,adc-channel-names = "sd_adc0"; + st,adc-channel-types = "SPI_F"; + st,adc-channel-clk-src = "CLKOUT"; + io-channels = <&ads1202 0>; + st,filter-order = <3>; + }; + dfsdm_pdm1: filter@1 { + compatible = "st,stm32-dfsdm-dmic"; + reg = <1>; + interrupts = <111>; + dmas = <&dmamux1 102 0x400 0x00>; + dma-names = "rx"; + st,adc-channels = <1>; + st,adc-channel-names = "dmic1"; + st,adc-channel-types = "SPI_R"; + st,adc-channel-clk-src = "CLKOUT"; + st,filter-order = <5>; + }; + } diff --git a/Documentation/devicetree/bindings/iio/health/max30102.txt b/Documentation/devicetree/bindings/iio/health/max30102.txt index 8629c18b0e78..ef2ca0a0306f 100644 --- a/Documentation/devicetree/bindings/iio/health/max30102.txt +++ b/Documentation/devicetree/bindings/iio/health/max30102.txt @@ -1,9 +1,11 @@ Maxim MAX30102 heart rate and pulse oximeter sensor +Maxim MAX30105 optical particle-sensing module * https://datasheets.maximintegrated.com/en/ds/MAX30102.pdf +* https://datasheets.maximintegrated.com/en/ds/MAX30105.pdf Required properties: - - compatible: must be "maxim,max30102" + - compatible: must be "maxim,max30102" or "maxim,max30105" - reg: the I2C address of the sensor - interrupt-parent: should be the phandle for the interrupt controller - interrupts: the sole interrupt generated by the device @@ -12,8 +14,10 @@ Required properties: interrupt client node bindings. Optional properties: - - maxim,red-led-current-microamp: configuration for RED LED current + - maxim,red-led-current-microamp: configuration for red LED current - maxim,ir-led-current-microamp: configuration for IR LED current + - maxim,green-led-current-microamp: configuration for green LED current + (max30105 only) Note that each step is approximately 200 microamps, ranging from 0 uA to 50800 uA. diff --git a/Documentation/devicetree/bindings/iio/light/uvis25.txt b/Documentation/devicetree/bindings/iio/light/uvis25.txt new file mode 100644 index 000000000000..3041207e3f3c --- /dev/null +++ b/Documentation/devicetree/bindings/iio/light/uvis25.txt @@ -0,0 +1,23 @@ +* ST UVIS25 uv sensor + +Required properties: +- compatible: should be "st,uvis25" +- reg: i2c address of the sensor / spi cs line + +Optional properties: +- interrupt-parent: should be the phandle for the interrupt controller +- interrupts: interrupt mapping for IRQ. It should be configured with + flags IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or + IRQ_TYPE_EDGE_FALLING. + + Refer to interrupt-controller/interrupts.txt for generic interrupt + client node bindings. + +Example: + +uvis25@47 { + compatible = "st,uvis25"; + reg = <0x47>; + interrupt-parent = <&gpio0>; + interrupts = <0 IRQ_TYPE_EDGE_RISING>; +}; diff --git a/Documentation/devicetree/bindings/input/hid-over-i2c.txt b/Documentation/devicetree/bindings/input/hid-over-i2c.txt index 28e8bd8b7d64..4d3da9d91de4 100644 --- a/Documentation/devicetree/bindings/input/hid-over-i2c.txt +++ b/Documentation/devicetree/bindings/input/hid-over-i2c.txt @@ -31,7 +31,7 @@ device-specific compatible properties, which should be used in addition to the - vdd-supply: phandle of the regulator that provides the supply voltage. - post-power-on-delay-ms: time required by the device after enabling its regulators - before it is ready for communication. Must be used with 'vdd-supply'. + or powering it on, before it is ready for communication. Example: diff --git a/Documentation/devicetree/bindings/input/samsung-keypad.txt b/Documentation/devicetree/bindings/input/samsung-keypad.txt index 5305e74e5742..4c5c0a82586d 100644 --- a/Documentation/devicetree/bindings/input/samsung-keypad.txt +++ b/Documentation/devicetree/bindings/input/samsung-keypad.txt @@ -45,7 +45,7 @@ Optional Properties specific to linux: Example: - keypad@100A0000 { + keypad@100a0000 { compatible = "samsung,s5pv210-keypad"; reg = <0x100A0000 0x100>; interrupts = <173>; diff --git a/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt b/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt index ac5dff412e25..f127a2117072 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/brcm,iproc-touchscreen.txt @@ -66,7 +66,7 @@ Example: An example of touchscreen node reg = <0x180a6000 0xc30>; }; - touchscreen: touchscreen@180A6000 { + touchscreen: touchscreen@180a6000 { compatible = "brcm,iproc-touchscreen"; #address-cells = <1>; #size-cells = <1>; diff --git a/Documentation/devicetree/bindings/input/touchscreen/mms114.txt b/Documentation/devicetree/bindings/input/touchscreen/mms114.txt index 89d4c56c5671..2cd954051d29 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/mms114.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/mms114.txt @@ -1,17 +1,23 @@ -* MELFAS MMS114 touchscreen controller +* MELFAS MMS114/MMS152 touchscreen controller Required properties: -- compatible: must be "melfas,mms114" +- compatible: should be one of: + - "melfas,mms114" + - "melfas,mms152" - reg: I2C address of the chip - interrupts: interrupt to which the chip is connected -- x-size: horizontal resolution of touchscreen -- y-size: vertical resolution of touchscreen +- touchscreen-size-x: See [1] +- touchscreen-size-y: See [1] Optional properties: -- contact-threshold: -- moving-threshold: -- x-invert: invert X axis -- y-invert: invert Y axis +- touchscreen-fuzz-x: See [1] +- touchscreen-fuzz-y: See [1] +- touchscreen-fuzz-pressure: See [1] +- touchscreen-inverted-x: See [1] +- touchscreen-inverted-y: See [1] +- touchscreen-swapped-x-y: See [1] + +[1]: Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt Example: @@ -22,12 +28,13 @@ Example: compatible = "melfas,mms114"; reg = <0x48>; interrupts = <39 0>; - x-size = <720>; - y-size = <1280>; - contact-threshold = <10>; - moving-threshold = <10>; - x-invert; - y-invert; + touchscreen-size-x = <720>; + touchscreen-size-y = <1280>; + touchscreen-fuzz-x = <10>; + touchscreen-fuzz-y = <10>; + touchscreen-fuzz-pressure = <10>; + touchscreen-inverted-x; + touchscreen-inverted-y; }; /* ... */ diff --git a/Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt b/Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt index 6aa625e0cb8d..84752de12412 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt @@ -23,6 +23,8 @@ Optional properties: - touchscreen-inverted-y : See touchscreen.txt - touchscreen-swapped-x-y : See touchscreen.txt - silead,max-fingers : maximum number of fingers the touchscreen can detect +- silead,home-button : Boolean, set to true on devices which have a + capacitive home-button build into the touchscreen - vddio-supply : regulator phandle for controller VDDIO - avdd-supply : regulator phandle for controller AVDD diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2836-l1-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2836-l1-intc.txt index f320dcd6e69b..8ced1696c325 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2836-l1-intc.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2836-l1-intc.txt @@ -12,7 +12,7 @@ Required properties: registers - interrupt-controller: Identifies the node as an interrupt controller - #interrupt-cells: Specifies the number of cells needed to encode an - interrupt source. The value shall be 1 + interrupt source. The value shall be 2 Please refer to interrupts.txt in this directory for details of the common Interrupt Controllers bindings used by client devices. @@ -32,6 +32,6 @@ local_intc: local_intc { compatible = "brcm,bcm2836-l1-intc"; reg = <0x40000000 0x100>; interrupt-controller; - #interrupt-cells = <1>; + #interrupt-cells = <2>; interrupt-parent = <&local_intc>; }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt b/Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt new file mode 100644 index 000000000000..35f752706e7d --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt @@ -0,0 +1,30 @@ +Android Goldfish PIC + +Android Goldfish programmable interrupt device used by Android +emulator. + +Required properties: + +- compatible : should contain "google,goldfish-pic" +- reg : +- interrupts : + +Example for mips when used in cascade mode: + + cpuintc { + #interrupt-cells = <0x1>; + #address-cells = <0>; + interrupt-controller; + compatible = "mti,cpu-interrupt-controller"; + }; + + interrupt-controller@1f000000 { + compatible = "google,goldfish-pic"; + reg = <0x1f000000 0x1000>; + + interrupt-controller; + #interrupt-cells = <0x1>; + + interrupt-parent = <&cpuintc>; + interrupts = <0x2>; + }; diff --git a/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt b/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt index 857df929a654..1fd5d69647ca 100644 --- a/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt +++ b/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt @@ -16,6 +16,9 @@ Required Properties: - "renesas,ipmmu-r8a7793" for the R8A7793 (R-Car M2-N) IPMMU. - "renesas,ipmmu-r8a7794" for the R8A7794 (R-Car E2) IPMMU. - "renesas,ipmmu-r8a7795" for the R8A7795 (R-Car H3) IPMMU. + - "renesas,ipmmu-r8a7796" for the R8A7796 (R-Car M3-W) IPMMU. + - "renesas,ipmmu-r8a77970" for the R8A77970 (R-Car V3M) IPMMU. + - "renesas,ipmmu-r8a77995" for the R8A77995 (R-Car D3) IPMMU. - "renesas,ipmmu-vmsa" for generic R-Car Gen2 VMSA-compatible IPMMU. - reg: Base address and size of the IPMMU registers. diff --git a/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt b/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt index 85f068805dd8..b1682c80b490 100644 --- a/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt +++ b/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt @@ -56,7 +56,7 @@ Examples: iommus = <&sysmmu_gsc0>; }; - sysmmu_gsc0: sysmmu@13E80000 { + sysmmu_gsc0: sysmmu@13e80000 { compatible = "samsung,exynos-sysmmu"; reg = <0x13E80000 0x1000>; interrupt-parent = <&combiner>; diff --git a/Documentation/devicetree/bindings/leds/leds-lm3692x.txt b/Documentation/devicetree/bindings/leds/leds-lm3692x.txt new file mode 100644 index 000000000000..6c9074f84a51 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/leds-lm3692x.txt @@ -0,0 +1,49 @@ +* Texas Instruments - LM3692x Highly Efficient White LED Driver + +The LM3692x is an ultra-compact, highly efficient, +white-LED driver designed for LCD display backlighting. + +The main difference between the LM36922 and LM36923 is the number of +LED strings it supports. The LM36922 supports two strings while the LM36923 +supports three strings. + +Required properties: + - compatible: + "ti,lm36922" + "ti,lm36923" + - reg : I2C slave address + - #address-cells : 1 + - #size-cells : 0 + +Optional properties: + - enable-gpios : gpio pin to enable/disable the device. + - vled-supply : LED supply + +Required child properties: + - reg : 0 + +Optional child properties: + - label : see Documentation/devicetree/bindings/leds/common.txt + - linux,default-trigger : + see Documentation/devicetree/bindings/leds/common.txt + +Example: + +led-controller@36 { + compatible = "ti,lm3692x"; + reg = <0x36>; + #address-cells = <1>; + #size-cells = <0>; + + enable-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + vled-supply = <&vbatt>; + + led@0 { + reg = <0>; + label = "white:backlight_cluster"; + linux,default-trigger = "backlight"; + }; +} + +For more product information please see the link below: +http://www.ti.com/lit/ds/snvsa29/snvsa29.pdf diff --git a/Documentation/devicetree/bindings/leds/leds-lp8860.txt b/Documentation/devicetree/bindings/leds/leds-lp8860.txt index aad38dd94d4b..5f0e892ad759 100644 --- a/Documentation/devicetree/bindings/leds/leds-lp8860.txt +++ b/Documentation/devicetree/bindings/leds/leds-lp8860.txt @@ -6,23 +6,39 @@ current sinks that can be controlled by a PWM input signal, a SPI/I2C master, or both. Required properties: - - compatible: + - compatible : "ti,lp8860" - - reg - I2C slave address - - label - Used for naming LEDs + - reg : I2C slave address + - #address-cells : 1 + - #size-cells : 0 Optional properties: - - enable-gpio - gpio pin to enable/disable the device. - - supply - "vled" - LED supply + - enable-gpios : gpio pin to enable (active high)/disable the device. + - vled-supply : LED supply + +Required child properties: + - reg : 0 + +Optional child properties: + - label : see Documentation/devicetree/bindings/leds/common.txt + - linux,default-trigger : + see Documentation/devicetree/bindings/leds/common.txt Example: -leds: leds@6 { +led-controller@2d { compatible = "ti,lp8860"; + #address-cells = <1>; + #size-cells = <0>; reg = <0x2d>; - label = "display_cluster"; - enable-gpio = <&gpio1 28 GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; vled-supply = <&vbatt>; + + led@0 { + reg = <0>; + label = "white:backlight"; + linux,default-trigger = "backlight"; + }; } For more product information please see the link below: diff --git a/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt b/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt index 9b40c4925aa9..0ef372656a3e 100644 --- a/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt +++ b/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt @@ -124,7 +124,7 @@ dsp { }; /* AM33xx */ -mailbox: mailbox@480C8000 { +mailbox: mailbox@480c8000 { compatible = "ti,omap4-mailbox"; reg = <0x480C8000 0x200>; interrupts = <77>; diff --git a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.txt b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.txt index fb961c310f44..16964f0c1773 100644 --- a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.txt +++ b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.txt @@ -15,12 +15,21 @@ platforms. Usage: required Value type: Definition: must specify the base address and size of the global block +- clocks: + Usage: required if #clocks-cells property is present + Value type: + Definition: phandle to the input PLL, which feeds the APCS mux/divider - #mbox-cells: Usage: required Value type: Definition: as described in mailbox.txt, must be 1 +- #clock-cells: + Usage: optional + Value type: + Definition: as described in clock.txt, must be 0 + = EXAMPLE The following example describes the APCS HMSS found in MSM8996 and part of the @@ -44,3 +53,12 @@ GLINK RPM referencing the "rpm_hlos" doorbell therein. mbox-names = "rpm_hlos"; }; +Below is another example of the APCS binding on MSM8916 platforms: + + apcs: mailbox@b011000 { + compatible = "qcom,msm8916-apcs-kpss-global"; + reg = <0xb011000 0x1000>; + #mbox-cells = <1>; + clocks = <&a53pll>; + #clock-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/mailbox/ti,message-manager.txt b/Documentation/devicetree/bindings/mailbox/ti,message-manager.txt index c3b55b3ede8a..ebf0e3710cee 100644 --- a/Documentation/devicetree/bindings/mailbox/ti,message-manager.txt +++ b/Documentation/devicetree/bindings/mailbox/ti,message-manager.txt @@ -20,9 +20,9 @@ Required properties: order referring to the transfer path. - interrupt-names: Contains interrupt names matching the rx transfer path for a given SoC. Receive interrupts shall be of the - format: "rx__". + format: "rx_". For ti,k2g-message-manager, this shall contain: - "rx_005_002", "rx_057_002" + "rx_005", "rx_057" - interrupts: Contains the interrupt information corresponding to interrupt-names property. diff --git a/Documentation/devicetree/bindings/media/cec-gpio.txt b/Documentation/devicetree/bindings/media/cec-gpio.txt index 46a0bac8b3b9..12fcd55ed153 100644 --- a/Documentation/devicetree/bindings/media/cec-gpio.txt +++ b/Documentation/devicetree/bindings/media/cec-gpio.txt @@ -4,6 +4,10 @@ The HDMI CEC GPIO module supports CEC implementations where the CEC line is hooked up to a pull-up GPIO line and - optionally - the HPD line is hooked up to another GPIO line. +Please note: the maximum voltage for the CEC line is 3.63V, for the HPD +line it is 5.3V. So you may need some sort of level conversion circuitry +when connecting them to a GPIO line. + Required properties: - compatible: value must be "cec-gpio". - cec-gpios: gpio that the CEC line is connected to. The line should be @@ -21,7 +25,7 @@ the following property is optional: Example for the Raspberry Pi 3 where the CEC line is connected to pin 26 aka BCM7 aka CE1 on the GPIO pin header and the HPD line is -connected to pin 11 aka BCM17: +connected to pin 11 aka BCM17 (some level shifter is needed for this!): #include diff --git a/Documentation/devicetree/bindings/media/i2c/mt9m111.txt b/Documentation/devicetree/bindings/media/i2c/mt9m111.txt index ed5a334b1e57..6b910036b57e 100644 --- a/Documentation/devicetree/bindings/media/i2c/mt9m111.txt +++ b/Documentation/devicetree/bindings/media/i2c/mt9m111.txt @@ -6,6 +6,8 @@ interface. Required Properties: - compatible: value should be "micron,mt9m111" +- clocks: reference to the master clock. +- clock-names: shall be "mclk". For further reading on port node refer to Documentation/devicetree/bindings/media/video-interfaces.txt. @@ -16,6 +18,8 @@ Example: mt9m111@5d { compatible = "micron,mt9m111"; reg = <0x5d>; + clocks = <&mclk>; + clock-names = "mclk"; remote = <&pxa_camera>; port { diff --git a/Documentation/devicetree/bindings/media/i2c/ov5640.txt b/Documentation/devicetree/bindings/media/i2c/ov5640.txt index 540b36c4b1f2..8e36da0d8406 100644 --- a/Documentation/devicetree/bindings/media/i2c/ov5640.txt +++ b/Documentation/devicetree/bindings/media/i2c/ov5640.txt @@ -1,4 +1,4 @@ -* Omnivision OV5640 MIPI CSI-2 sensor +* Omnivision OV5640 MIPI CSI-2 / parallel sensor Required Properties: - compatible: should be "ovti,ov5640" @@ -18,7 +18,25 @@ The device node must contain one 'port' child node for its digital output video port, in accordance with the video interface bindings defined in Documentation/devicetree/bindings/media/video-interfaces.txt. -Example: +OV5640 can be connected to a MIPI CSI-2 bus or a parallel bus endpoint. + +Endpoint node required properties for CSI-2 connection are: +- remote-endpoint: a phandle to the bus receiver's endpoint node. +- clock-lanes: should be set to <0> (clock lane on hardware lane 0) +- data-lanes: should be set to <1> or <1 2> (one or two CSI-2 lanes supported) + +Endpoint node required properties for parallel connection are: +- remote-endpoint: a phandle to the bus receiver's endpoint node. +- bus-width: shall be set to <8> for 8 bits parallel bus + or <10> for 10 bits parallel bus +- data-shift: shall be set to <2> for 8 bits parallel bus + (lines 9:2 are used) or <0> for 10 bits parallel bus +- hsync-active: active state of the HSYNC signal, 0/1 for LOW/HIGH respectively. +- vsync-active: active state of the VSYNC signal, 0/1 for LOW/HIGH respectively. +- pclk-sample: sample data on rising (1) or falling (0) edge of the pixel clock + signal. + +Examples: &i2c1 { ov5640: camera@3c { @@ -35,6 +53,7 @@ Example: reset-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>; port { + /* MIPI CSI-2 bus endpoint */ ov5640_to_mipi_csi2: endpoint { remote-endpoint = <&mipi_csi2_from_ov5640>; clock-lanes = <0>; @@ -43,3 +62,26 @@ Example: }; }; }; + +&i2c1 { + ov5640: camera@3c { + compatible = "ovti,ov5640"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ov5640>; + reg = <0x3c>; + clocks = <&clk_ext_camera>; + clock-names = "xclk"; + + port { + /* Parallel bus endpoint */ + ov5640_to_parallel: endpoint { + remote-endpoint = <¶llel_from_ov5640>; + bus-width = <8>; + data-shift = <2>; /* lines 9:2 are used */ + hsync-active = <0>; + vsync-active = <0>; + pclk-sample = <1>; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/media/i2c/ov7740.txt b/Documentation/devicetree/bindings/media/i2c/ov7740.txt new file mode 100644 index 000000000000..af781c3a5f0e --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ov7740.txt @@ -0,0 +1,47 @@ +* Omnivision OV7740 CMOS image sensor + +The Omnivision OV7740 image sensor supports multiple output image +size, such as VGA, and QVGA, CIF and any size smaller. It also +supports the RAW RGB and YUV output formats. + +The common video interfaces bindings (see video-interfaces.txt) should +be used to specify link to the image data receiver. The OV7740 device +node should contain one 'port' child node with an 'endpoint' subnode. + +Required Properties: +- compatible: "ovti,ov7740". +- reg: I2C slave address of the sensor. +- clocks: Reference to the xvclk input clock. +- clock-names: "xvclk". + +Optional Properties: +- reset-gpios: Rreference to the GPIO connected to the reset_b pin, + if any. Active low with pull-ip resistor. +- powerdown-gpios: Reference to the GPIO connected to the pwdn pin, + if any. Active high with pull-down resistor. + +Endpoint node mandatory properties: +- remote-endpoint: A phandle to the bus receiver's endpoint node. + +Example: + + i2c1: i2c@fc028000 { + ov7740: camera@21 { + compatible = "ovti,ov7740"; + reg = <0x21>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sensor_power &pinctrl_sensor_reset>; + clocks = <&isc>; + clock-names = "xvclk"; + assigned-clocks = <&isc>; + assigned-clock-rates = <24000000>; + reset-gpios = <&pioA 43 GPIO_ACTIVE_LOW>; + powerdown-gpios = <&pioA 44 GPIO_ACTIVE_HIGH>; + + port { + ov7740_0: endpoint { + remote-endpoint = <&isc_0>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt index 0b7b6a4d84ff..e80d5891b7ed 100644 --- a/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt +++ b/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt @@ -20,6 +20,13 @@ Mandatory properties is in hardware standby mode when the signal is in the low state. +Optional properties +------------------- + +- flash-leds: See ../video-interfaces.txt +- lens-focus: See ../video-interfaces.txt + + Endpoint node mandatory properties ---------------------------------- diff --git a/Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt b/Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt new file mode 100644 index 000000000000..470237ed6fe5 --- /dev/null +++ b/Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt @@ -0,0 +1,55 @@ +NVIDIA Tegra Video Decoder Engine + +Required properties: +- compatible : Must contain one of the following values: + - "nvidia,tegra20-vde" + - "nvidia,tegra30-vde" + - "nvidia,tegra114-vde" + - "nvidia,tegra124-vde" + - "nvidia,tegra132-vde" +- reg : Must contain an entry for each entry in reg-names. +- reg-names : Must include the following entries: + - sxe + - bsev + - mbe + - ppe + - mce + - tfe + - ppb + - vdma + - frameid +- iram : Must contain phandle to the mmio-sram device node that represents + IRAM region used by VDE. +- interrupts : Must contain an entry for each entry in interrupt-names. +- interrupt-names : Must include the following entries: + - sync-token + - bsev + - sxe +- clocks : Must include the following entries: + - vde +- resets : Must include the following entries: + - vde + +Example: + +video-codec@6001a000 { + compatible = "nvidia,tegra20-vde"; + reg = <0x6001a000 0x1000 /* Syntax Engine */ + 0x6001b000 0x1000 /* Video Bitstream Engine */ + 0x6001c000 0x100 /* Macroblock Engine */ + 0x6001c200 0x100 /* Post-processing Engine */ + 0x6001c400 0x100 /* Motion Compensation Engine */ + 0x6001c600 0x100 /* Transform Engine */ + 0x6001c800 0x100 /* Pixel prediction block */ + 0x6001ca00 0x100 /* Video DMA */ + 0x6001d800 0x300 /* Video frame controls */>; + reg-names = "sxe", "bsev", "mbe", "ppe", "mce", + "tfe", "ppb", "vdma", "frameid"; + iram = <&vde_pool>; /* IRAM region */ + interrupts = , /* Sync token interrupt */ + , /* BSE-V interrupt */ + ; /* SXE interrupt */ + interrupt-names = "sync-token", "bsev", "sxe"; + clocks = <&tegra_car TEGRA20_CLK_VDE>; + resets = <&tegra_car 61>; +}; diff --git a/Documentation/devicetree/bindings/media/s5p-cec.txt b/Documentation/devicetree/bindings/media/s5p-cec.txt index 6f3756da900f..e847291d4aff 100644 --- a/Documentation/devicetree/bindings/media/s5p-cec.txt +++ b/Documentation/devicetree/bindings/media/s5p-cec.txt @@ -23,7 +23,7 @@ Optional: Example: -hdmicec: cec@100B0000 { +hdmicec: cec@100b0000 { compatible = "samsung,s5p-cec"; reg = <0x100B0000 0x200>; interrupts = <0 114 0>; diff --git a/Documentation/devicetree/bindings/media/samsung-s5c73m3.txt b/Documentation/devicetree/bindings/media/samsung-s5c73m3.txt index 2c85c4538a6d..21f31fdf5543 100644 --- a/Documentation/devicetree/bindings/media/samsung-s5c73m3.txt +++ b/Documentation/devicetree/bindings/media/samsung-s5c73m3.txt @@ -62,7 +62,7 @@ For more details see description of the SPI busses bindings Example: -i2c@138A000000 { +i2c@138a000000 { ... s5c73m3@3c { compatible = "samsung,s5c73m3"; diff --git a/Documentation/devicetree/bindings/media/xilinx/xlnx,v-tpg.txt b/Documentation/devicetree/bindings/media/xilinx/xlnx,v-tpg.txt index 9dd86b3db937..439351ab2a79 100644 --- a/Documentation/devicetree/bindings/media/xilinx/xlnx,v-tpg.txt +++ b/Documentation/devicetree/bindings/media/xilinx/xlnx,v-tpg.txt @@ -66,6 +66,6 @@ Example: tpg1_out: endpoint { remote-endpoint = <&switch_in0>; }; - }: + }; }; }; diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.txt b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.txt index 8dbe47013c2b..14968b048cd3 100644 --- a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.txt +++ b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.txt @@ -12,6 +12,8 @@ Required properties: - clock-names: Must include the following entries: - mc: the module's clock input - interrupts: The interrupt outputs from the controller. + +Required properties for Tegra30, Tegra114, Tegra124, Tegra132 and Tegra210: - #iommu-cells: Should be 1. The single cell of the IOMMU specifier defines the SWGROUP of the master. diff --git a/Documentation/devicetree/bindings/memory-controllers/ti-aemif.txt b/Documentation/devicetree/bindings/memory-controllers/ti-aemif.txt index 9592717f483f..190437a0c146 100644 --- a/Documentation/devicetree/bindings/memory-controllers/ti-aemif.txt +++ b/Documentation/devicetree/bindings/memory-controllers/ti-aemif.txt @@ -138,7 +138,7 @@ from the corresponding HW reg. Example for aemif, davinci nand and nor flash chip select shown below. -memory-controller@21000A00 { +memory-controller@21000a00 { compatible = "ti,davinci-aemif"; #address-cells = <2>; #size-cells = <1>; diff --git a/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt b/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt index 152eeccbde1c..621b41c79faa 100644 --- a/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt +++ b/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt @@ -23,6 +23,13 @@ Required properties: the value shall be "emif" where is the number of the EMIF instance with base 1. +Required only for "ti,emif-am3352" and "ti,emif-am4372": +- sram : Phandles for generic sram driver nodes, + first should be type 'protect-exec' for the driver to use to copy + and run PM functions, second should be regular pool to be used for + data region for code. See Documentation/devicetree/bindings/sram/sram.txt + for more details. + Optional properties: - cs1-used : Have this property if CS1 of this EMIF instance has a memory part attached to it. If there is a memory @@ -44,7 +51,7 @@ Optional properties: - hw-caps-temp-alert : Have this property if the controller has capability for generating SDRAM temperature alerts -Example: +-Examples: emif1: emif@4c000000 { compatible = "ti,emif-4d"; @@ -56,3 +63,11 @@ emif1: emif@4c000000 { hw-caps-ll-interface; hw-caps-temp-alert; }; + +/* From am33xx.dtsi */ +emif: emif@4c000000 { + compatible = "ti,emif-am3352"; + reg = <0x4C000000 0x1000>; + sram = <&pm_sram_code + &pm_sram_data>; +}; diff --git a/Documentation/devicetree/bindings/mfd/atmel-tcb.txt b/Documentation/devicetree/bindings/mfd/atmel-tcb.txt new file mode 100644 index 000000000000..c4a83e364cb6 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/atmel-tcb.txt @@ -0,0 +1,56 @@ +* Device tree bindings for Atmel Timer Counter Blocks +- compatible: Should be "atmel,-tcb", "simple-mfd", "syscon". + can be "at91rm9200" or "at91sam9x5" +- reg: Should contain registers location and length +- #address-cells: has to be 1 +- #size-cells: has to be 0 +- interrupts: Should contain all interrupts for the TC block + Note that you can specify several interrupt cells if the TC + block has one interrupt per channel. +- clock-names: tuple listing input clock names. + Required elements: "t0_clk", "slow_clk" + Optional elements: "t1_clk", "t2_clk" +- clocks: phandles to input clocks. + +The TCB can expose multiple subdevices: + * a timer + - compatible: Should be "atmel,tcb-timer" + - reg: Should contain the TCB channels to be used. If the + counter width is 16 bits (at91rm9200-tcb), two consecutive + channels are needed. Else, only one channel will be used. + +Examples: + +One interrupt per TC block: + tcb0: timer@fff7c000 { + compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xfff7c000 0x100>; + interrupts = <18 4>; + clocks = <&tcb0_clk>, <&clk32k>; + clock-names = "t0_clk", "slow_clk"; + + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + +One interrupt per TC channel in a TC block: + tcb1: timer@fffdc000 { + compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xfffdc000 0x100>; + interrupts = <26 4>, <27 4>, <28 4>; + clocks = <&tcb1_clk>, <&clk32k>; + clock-names = "t0_clk", "slow_clk"; + }; + + diff --git a/Documentation/devicetree/bindings/mfd/cros-ec.txt b/Documentation/devicetree/bindings/mfd/cros-ec.txt index 136e0c2da44d..6245c9b1a68b 100644 --- a/Documentation/devicetree/bindings/mfd/cros-ec.txt +++ b/Documentation/devicetree/bindings/mfd/cros-ec.txt @@ -41,7 +41,7 @@ Optional properties (all): Example for I2C: -i2c@12CA0000 { +i2c@12ca0000 { cros-ec@1e { reg = <0x1e>; compatible = "google,cros-ec-i2c"; diff --git a/Documentation/devicetree/bindings/mfd/mc13xxx.txt b/Documentation/devicetree/bindings/mfd/mc13xxx.txt index ac235fe385fc..8261ea73278a 100644 --- a/Documentation/devicetree/bindings/mfd/mc13xxx.txt +++ b/Documentation/devicetree/bindings/mfd/mc13xxx.txt @@ -130,7 +130,7 @@ ecspi@70010000 { /* ECSPI1 */ #size-cells = <0>; led-control = <0x000 0x000 0x0e0 0x000>; - sysled { + sysled@3 { reg = <3>; label = "system:red:live"; linux,default-trigger = "heartbeat"; diff --git a/Documentation/devicetree/bindings/mfd/syscon.txt b/Documentation/devicetree/bindings/mfd/syscon.txt index 8b92d4576c42..25d9e9c2fd53 100644 --- a/Documentation/devicetree/bindings/mfd/syscon.txt +++ b/Documentation/devicetree/bindings/mfd/syscon.txt @@ -16,9 +16,17 @@ Required properties: Optional property: - reg-io-width: the size (in bytes) of the IO accesses that should be performed on the device. +- hwlocks: reference to a phandle of a hardware spinlock provider node. Examples: gpr: iomuxc-gpr@20e0000 { compatible = "fsl,imx6q-iomuxc-gpr", "syscon"; reg = <0x020e0000 0x38>; + hwlocks = <&hwlock1 1>; +}; + +hwlock1: hwspinlock@40500000 { + ... + reg = <0x40500000 0x1000>; + #hwlock-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/misc/nvidia,tegra186-misc.txt b/Documentation/devicetree/bindings/misc/nvidia,tegra186-misc.txt new file mode 100644 index 000000000000..892ba4384abc --- /dev/null +++ b/Documentation/devicetree/bindings/misc/nvidia,tegra186-misc.txt @@ -0,0 +1,12 @@ +NVIDIA Tegra186 MISC register block + +The MISC register block found on Tegra186 SoCs contains registers that can be +used to identify a given chip and various strapping options. + +Required properties: +- compatible: Must be: + - Tegra186: "nvidia,tegra186-misc" +- reg: Should contain 2 entries: The first entry gives the physical address + and length of the register region which contains revision and debug + features. The second entry specifies the physical address and length + of the register region indicating the strapping options. diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt index fb11ae8b3b72..467cd7b147ce 100644 --- a/Documentation/devicetree/bindings/mmc/mmc.txt +++ b/Documentation/devicetree/bindings/mmc/mmc.txt @@ -67,10 +67,10 @@ logic applies to the "wp-inverted" property. CD and WP lines can be implemented on the hardware in one of two ways: as GPIOs, specified in cd-gpios and wp-gpios properties, or as dedicated pins. Polarity of dedicated pins can be specified, using *-inverted properties. GPIO polarity can -also be specified using the OF_GPIO_ACTIVE_LOW flag. This creates an ambiguity +also be specified using the GPIO_ACTIVE_LOW flag. This creates an ambiguity in the latter case. We choose to use the XOR logic for GPIO CD and WP lines. This means, the two properties are "superimposed," for example leaving the -OF_GPIO_ACTIVE_LOW flag clear and specifying the respective *-inverted +GPIO_ACTIVE_LOW flag clear and specifying the respective *-inverted property property results in a double-inversion and actually means the "normal" line polarity is in effect. diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.txt b/Documentation/devicetree/bindings/mmc/mtk-sd.txt index 72d2a734ab85..9b8017670870 100644 --- a/Documentation/devicetree/bindings/mmc/mtk-sd.txt +++ b/Documentation/devicetree/bindings/mmc/mtk-sd.txt @@ -12,6 +12,8 @@ Required properties: "mediatek,mt8173-mmc": for mmc host ip compatible with mt8173 "mediatek,mt2701-mmc": for mmc host ip compatible with mt2701 "mediatek,mt2712-mmc": for mmc host ip compatible with mt2712 + "mediatek,mt7623-mmc", "mediatek,mt2701-mmc": for MT7623 SoC + - reg: physical base address of the controller and length - interrupts: Should contain MSDC interrupt number - clocks: Should contain phandle for the clock feeding the MMC controller diff --git a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt index 3c6762430fd9..d8685cb83325 100644 --- a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt +++ b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt @@ -26,6 +26,7 @@ Required properties: "renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC "renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC "renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC + "renesas,sdhi-r8a77995" - SDHI IP on R8A77995 SoC "renesas,sdhi-shmobile" - a generic sh-mobile SDHI controller "renesas,rcar-gen1-sdhi" - a generic R-Car Gen1 SDHI controller "renesas,rcar-gen2-sdhi" - a generic R-Car Gen2 or RZ/G1 diff --git a/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt index c34aa6f8a424..63d4d626fbd5 100644 --- a/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt +++ b/Documentation/devicetree/bindings/mtd/fsl-quadspi.txt @@ -12,7 +12,7 @@ Required properties: - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory" - interrupts : Should contain the interrupt for the device - clocks : The clocks needed by the QuadSPI controller - - clock-names : the name of the clocks + - clock-names : Should contain the name of the clocks: "qspi_en" and "qspi". Optional properties: - fsl,qspi-has-second-chip: The controller has two buses, bus A and bus B. diff --git a/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt b/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt index b6e8bfd024f4..e9f01a963a0a 100644 --- a/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt +++ b/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt @@ -9,13 +9,14 @@ Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt Required properties: + - compatible: "ti,omap2-onenand" - reg: The CS line the peripheral is connected to - - gpmc,device-width Width of the ONENAND device connected to the GPMC + - gpmc,device-width: Width of the ONENAND device connected to the GPMC in bytes. Must be 1 or 2. Optional properties: - - dma-channel: DMA Channel index + - int-gpios: GPIO specifier for the INT pin. For inline partition table parsing (optional): @@ -35,6 +36,7 @@ Example for an OMAP3430 board: #size-cells = <1>; onenand@0 { + compatible = "ti,omap2-onenand"; reg = <0 0 0>; /* CS0, offset 0 */ gpmc,device-width = <2>; diff --git a/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt b/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt index d0a37252eb22..6d60bc3063f5 100644 --- a/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt +++ b/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt @@ -23,7 +23,7 @@ Optional subnodes: Example: - mlc: flash@200A8000 { + mlc: flash@200a8000 { compatible = "nxp,lpc3220-mlc"; reg = <0x200A8000 0x11000>; interrupts = <11 0>; diff --git a/Documentation/devicetree/bindings/mtd/marvell-nand.txt b/Documentation/devicetree/bindings/mtd/marvell-nand.txt new file mode 100644 index 000000000000..c08fb477b3c6 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/marvell-nand.txt @@ -0,0 +1,123 @@ +Marvell NAND Flash Controller (NFC) + +Required properties: +- compatible: can be one of the following: + * "marvell,armada-8k-nand-controller" + * "marvell,armada370-nand-controller" + * "marvell,pxa3xx-nand-controller" + * "marvell,armada-8k-nand" (deprecated) + * "marvell,armada370-nand" (deprecated) + * "marvell,pxa3xx-nand" (deprecated) + Compatibles marked deprecated support only the old bindings described + at the bottom. +- reg: NAND flash controller memory area. +- #address-cells: shall be set to 1. Encode the NAND CS. +- #size-cells: shall be set to 0. +- interrupts: shall define the NAND controller interrupt. +- clocks: shall reference the NAND controller clock. +- marvell,system-controller: Set to retrieve the syscon node that handles + NAND controller related registers (only required with the + "marvell,armada-8k-nand[-controller]" compatibles). + +Optional properties: +- label: see partition.txt. New platforms shall omit this property. +- dmas: shall reference DMA channel associated to the NAND controller. + This property is only used with "marvell,pxa3xx-nand[-controller]" + compatible strings. +- dma-names: shall be "rxtx". + This property is only used with "marvell,pxa3xx-nand[-controller]" + compatible strings. + +Optional children nodes: +Children nodes represent the available NAND chips. + +Required properties: +- reg: shall contain the native Chip Select ids (0-3). +- nand-rb: see nand.txt (0-1). + +Optional properties: +- marvell,nand-keep-config: orders the driver not to take the timings + from the core and leaving them completely untouched. Bootloader + timings will then be used. +- label: MTD name. +- nand-on-flash-bbt: see nand.txt. +- nand-ecc-mode: see nand.txt. Will use hardware ECC if not specified. +- nand-ecc-algo: see nand.txt. This property is essentially useful when + not using hardware ECC. Howerver, it may be added when using hardware + ECC for clarification but will be ignored by the driver because ECC + mode is chosen depending on the page size and the strength required by + the NAND chip. This value may be overwritten with nand-ecc-strength + property. +- nand-ecc-strength: see nand.txt. +- nand-ecc-step-size: see nand.txt. Marvell's NAND flash controller does + use fixed strength (1-bit for Hamming, 16-bit for BCH), so the actual + step size will shrink or grow in order to fit the required strength. + Step sizes are not completely random for all and follow certain + patterns described in AN-379, "Marvell SoC NFC ECC". + +See Documentation/devicetree/bindings/mtd/nand.txt for more details on +generic bindings. + + +Example: +nand_controller: nand-controller@d0000 { + compatible = "marvell,armada370-nand-controller"; + reg = <0xd0000 0x54>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clocks = <&coredivclk 0>; + + nand@0 { + reg = <0>; + label = "main-storage"; + nand-rb = <0>; + nand-ecc-mode = "hw"; + marvell,nand-keep-config; + nand-on-flash-bbt; + nand-ecc-strength = <4>; + nand-ecc-step-size = <512>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "Rootfs"; + reg = <0x00000000 0x40000000>; + }; + }; + }; +}; + + +Note on legacy bindings: One can find, in not-updated device trees, +bindings slightly different than described above with other properties +described below as well as the partitions node at the root of a so +called "nand" node (without clear controller/chip separation). + +Legacy properties: +- marvell,nand-enable-arbiter: To enable the arbiter, all boards blindly + used it, this bit was set by the bootloader for many boards and even if + it is marked reserved in several datasheets, it might be needed to set + it (otherwise it is harmless) so whether or not this property is set, + the bit is selected by the driver. +- num-cs: Number of chip-select lines to use, all boards blindly set 1 + to this and for a reason, other values would have failed. The value of + this property is ignored. + +Example: + + nand0: nand@43100000 { + compatible = "marvell,pxa3xx-nand"; + reg = <0x43100000 90>; + interrupts = <45>; + dmas = <&pdma 97 0>; + dma-names = "rxtx"; + #address-cells = <1>; + marvell,nand-keep-config; + marvell,nand-enable-arbiter; + num-cs = <1>; + /* Partitions (optional) */ + }; diff --git a/Documentation/devicetree/bindings/mtd/mtk-nand.txt b/Documentation/devicetree/bindings/mtd/mtk-nand.txt index 0431841de781..1c88526dedfc 100644 --- a/Documentation/devicetree/bindings/mtd/mtk-nand.txt +++ b/Documentation/devicetree/bindings/mtd/mtk-nand.txt @@ -12,8 +12,10 @@ tree nodes. The first part of NFC is NAND Controller Interface (NFI) HW. Required NFI properties: -- compatible: Should be one of "mediatek,mt2701-nfc", - "mediatek,mt2712-nfc". +- compatible: Should be one of + "mediatek,mt2701-nfc", + "mediatek,mt2712-nfc", + "mediatek,mt7622-nfc". - reg: Base physical address and size of NFI. - interrupts: Interrupts of NFI. - clocks: NFI required clocks. @@ -142,7 +144,10 @@ Example: ============== Required BCH properties: -- compatible: Should be one of "mediatek,mt2701-ecc", "mediatek,mt2712-ecc". +- compatible: Should be one of + "mediatek,mt2701-ecc", + "mediatek,mt2712-ecc", + "mediatek,mt7622-ecc". - reg: Base physical address and size of ECC. - interrupts: Interrupts of ECC. - clocks: ECC required clocks. diff --git a/Documentation/devicetree/bindings/mtd/nand.txt b/Documentation/devicetree/bindings/mtd/nand.txt index 133f3813719c..8bb11d809429 100644 --- a/Documentation/devicetree/bindings/mtd/nand.txt +++ b/Documentation/devicetree/bindings/mtd/nand.txt @@ -43,6 +43,7 @@ Optional NAND chip properties: This is particularly useful when only the in-band area is used by the upper layers, and you want to make your NAND as reliable as possible. +- nand-rb: shall contain the native Ready/Busy ids. The ECC strength and ECC step size properties define the correction capability of a controller. Together, they say a controller can correct "{strength} bit diff --git a/Documentation/devicetree/bindings/net/brcm,bcm7445-switch-v4.0.txt b/Documentation/devicetree/bindings/net/brcm,bcm7445-switch-v4.0.txt index 9a734d808aa7..b7336b9d6a3c 100644 --- a/Documentation/devicetree/bindings/net/brcm,bcm7445-switch-v4.0.txt +++ b/Documentation/devicetree/bindings/net/brcm,bcm7445-switch-v4.0.txt @@ -2,7 +2,10 @@ Required properties: -- compatible: should be "brcm,bcm7445-switch-v4.0" or "brcm,bcm7278-switch-v4.0" +- compatible: should be one of + "brcm,bcm7445-switch-v4.0" + "brcm,bcm7278-switch-v4.0" + "brcm,bcm7278-switch-v4.8" - reg: addresses and length of the register sets for the device, must be 6 pairs of register addresses and lengths - interrupts: interrupts for the devices, must be two interrupts diff --git a/Documentation/devicetree/bindings/net/can/can-transceiver.txt b/Documentation/devicetree/bindings/net/can/can-transceiver.txt new file mode 100644 index 000000000000..0011f53ff159 --- /dev/null +++ b/Documentation/devicetree/bindings/net/can/can-transceiver.txt @@ -0,0 +1,24 @@ +Generic CAN transceiver Device Tree binding +------------------------------ + +CAN transceiver typically limits the max speed in standard CAN and CAN FD +modes. Typically these limitations are static and the transceivers themselves +provide no way to detect this limitation at runtime. For this situation, +the "can-transceiver" node can be used. + +Required Properties: + max-bitrate: a positive non 0 value that determines the max + speed that CAN/CAN-FD can run. Any other value + will be ignored. + +Examples: + +Based on Texas Instrument's TCAN1042HGV CAN Transceiver + +m_can0 { + .... + can-transceiver { + max-bitrate = <5000000>; + }; + ... +}; diff --git a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt index 56d6cc336e1c..bfc0c433654f 100644 --- a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt +++ b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt @@ -18,6 +18,12 @@ Optional properties: - xceiver-supply: Regulator that powers the CAN transceiver +- big-endian: This means the registers of FlexCAN controller are big endian. + This is optional property.i.e. if this property is not present in + device tree node then controller is assumed to be little endian. + if this property is present then controller is assumed to be big + endian. + Example: can@1c000 { diff --git a/Documentation/devicetree/bindings/net/can/m_can.txt b/Documentation/devicetree/bindings/net/can/m_can.txt index 63e90421d029..ed614383af9c 100644 --- a/Documentation/devicetree/bindings/net/can/m_can.txt +++ b/Documentation/devicetree/bindings/net/can/m_can.txt @@ -43,6 +43,11 @@ Required properties: Please refer to 2.4.1 Message RAM Configuration in Bosch M_CAN user manual for details. +Optional Subnode: +- can-transceiver : Can-transceiver subnode describing maximum speed + that can be used for CAN/CAN-FD modes. See + Documentation/devicetree/bindings/net/can/can-transceiver.txt + for details. Example: SoC dtsi: m_can1: can@20e8000 { @@ -63,4 +68,8 @@ Board dts: pinctrl-names = "default"; pinctrl-0 = <&pinctrl_m_can1>; status = "enabled"; + + can-transceiver { + max-bitrate = <5000000>; + }; }; diff --git a/Documentation/devicetree/bindings/net/can/rcar_can.txt b/Documentation/devicetree/bindings/net/can/rcar_can.txt index 06bb7cc334c8..94a7f33ac5e9 100644 --- a/Documentation/devicetree/bindings/net/can/rcar_can.txt +++ b/Documentation/devicetree/bindings/net/can/rcar_can.txt @@ -2,7 +2,9 @@ Renesas R-Car CAN controller Device Tree Bindings ------------------------------------------------- Required properties: -- compatible: "renesas,can-r8a7778" if CAN controller is a part of R8A7778 SoC. +- compatible: "renesas,can-r8a7743" if CAN controller is a part of R8A7743 SoC. + "renesas,can-r8a7745" if CAN controller is a part of R8A7745 SoC. + "renesas,can-r8a7778" if CAN controller is a part of R8A7778 SoC. "renesas,can-r8a7779" if CAN controller is a part of R8A7779 SoC. "renesas,can-r8a7790" if CAN controller is a part of R8A7790 SoC. "renesas,can-r8a7791" if CAN controller is a part of R8A7791 SoC. @@ -12,7 +14,8 @@ Required properties: "renesas,can-r8a7795" if CAN controller is a part of R8A7795 SoC. "renesas,can-r8a7796" if CAN controller is a part of R8A7796 SoC. "renesas,rcar-gen1-can" for a generic R-Car Gen1 compatible device. - "renesas,rcar-gen2-can" for a generic R-Car Gen2 compatible device. + "renesas,rcar-gen2-can" for a generic R-Car Gen2 or RZ/G1 + compatible device. "renesas,rcar-gen3-can" for a generic R-Car Gen3 compatible device. When compatible with the generic version, nodes must list the SoC-specific version corresponding to the platform first diff --git a/Documentation/devicetree/bindings/net/cortina,gemini-ethernet.txt b/Documentation/devicetree/bindings/net/cortina,gemini-ethernet.txt new file mode 100644 index 000000000000..6c559981d110 --- /dev/null +++ b/Documentation/devicetree/bindings/net/cortina,gemini-ethernet.txt @@ -0,0 +1,92 @@ +Cortina Systems Gemini Ethernet Controller +========================================== + +This ethernet controller is found in the Gemini SoC family: +StorLink SL3512 and SL3516, also known as Cortina Systems +CS3512 and CS3516. + +Required properties: +- compatible: must be "cortina,gemini-ethernet" +- reg: must contain the global registers and the V-bit and A-bit + memory areas, in total three register sets. +- syscon: a phandle to the system controller +- #address-cells: must be specified, must be <1> +- #size-cells: must be specified, must be <1> +- ranges: should be state like this giving a 1:1 address translation + for the subnodes + +The subnodes represents the two ethernet ports in this device. +They are not independent of each other since they share resources +in the parent node, and are thus children. + +Required subnodes: +- port0: contains the resources for ethernet port 0 +- port1: contains the resources for ethernet port 1 + +Required subnode properties: +- compatible: must be "cortina,gemini-ethernet-port" +- reg: must contain two register areas: the DMA/TOE memory and + the GMAC memory area of the port +- interrupts: should contain the interrupt line of the port. + this is nominally a level interrupt active high. +- resets: this must provide an SoC-integrated reset line for + the port. +- clocks: this should contain a handle to the PCLK clock for + clocking the silicon in this port +- clock-names: must be "PCLK" + +Optional subnode properties: +- phy-mode: see ethernet.txt +- phy-handle: see ethernet.txt + +Example: + +mdio-bus { + (...) + phy0: ethernet-phy@1 { + reg = <1>; + device_type = "ethernet-phy"; + }; + phy1: ethernet-phy@3 { + reg = <3>; + device_type = "ethernet-phy"; + }; +}; + + +ethernet@60000000 { + compatible = "cortina,gemini-ethernet"; + reg = <0x60000000 0x4000>, /* Global registers, queue */ + <0x60004000 0x2000>, /* V-bit */ + <0x60006000 0x2000>; /* A-bit */ + syscon = <&syscon>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + gmac0: ethernet-port@0 { + compatible = "cortina,gemini-ethernet-port"; + reg = <0x60008000 0x2000>, /* Port 0 DMA/TOE */ + <0x6000a000 0x2000>; /* Port 0 GMAC */ + interrupt-parent = <&intcon>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; + resets = <&syscon GEMINI_RESET_GMAC0>; + clocks = <&syscon GEMINI_CLK_GATE_GMAC0>; + clock-names = "PCLK"; + phy-mode = "rgmii"; + phy-handle = <&phy0>; + }; + + gmac1: ethernet-port@1 { + compatible = "cortina,gemini-ethernet-port"; + reg = <0x6000c000 0x2000>, /* Port 1 DMA/TOE */ + <0x6000e000 0x2000>; /* Port 1 GMAC */ + interrupt-parent = <&intcon>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + resets = <&syscon GEMINI_RESET_GMAC1>; + clocks = <&syscon GEMINI_CLK_GATE_GMAC1>; + clock-names = "PCLK"; + phy-mode = "rgmii"; + phy-handle = <&phy1>; + }; +}; diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt index 7cc15c96ea95..4cb4925a28ab 100644 --- a/Documentation/devicetree/bindings/net/cpsw.txt +++ b/Documentation/devicetree/bindings/net/cpsw.txt @@ -61,7 +61,7 @@ file. Examples: - mac: ethernet@4A100000 { + mac: ethernet@4a100000 { compatible = "ti,cpsw"; reg = <0x4A100000 0x1000>; interrupts = <55 0x4>; @@ -91,7 +91,7 @@ Examples: }; (or) - mac: ethernet@4A100000 { + mac: ethernet@4a100000 { compatible = "ti,cpsw"; ti,hwmods = "cpgmac0"; cpdma_channels = <8>; diff --git a/Documentation/devicetree/bindings/net/davinci-mdio.txt b/Documentation/devicetree/bindings/net/davinci-mdio.txt index 621156ca4ffd..e6527de80f10 100644 --- a/Documentation/devicetree/bindings/net/davinci-mdio.txt +++ b/Documentation/devicetree/bindings/net/davinci-mdio.txt @@ -21,7 +21,7 @@ file. Examples: - mdio: davinci_mdio@4A101000 { + mdio: davinci_mdio@4a101000 { compatible = "ti,davinci_mdio"; reg = <0x4A101000 0x1000>; bus_freq = <1000000>; @@ -29,7 +29,7 @@ Examples: (or) - mdio: davinci_mdio@4A101000 { + mdio: davinci_mdio@4a101000 { compatible = "ti,davinci_mdio"; ti,hwmods = "davinci_mdio"; bus_freq = <1000000>; diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt index f0dc94409107..2d41fb96ce0a 100644 --- a/Documentation/devicetree/bindings/net/fsl-fec.txt +++ b/Documentation/devicetree/bindings/net/fsl-fec.txt @@ -59,7 +59,7 @@ ethernet@83fec000 { reg = <0x83fec000 0x4000>; interrupts = <87>; phy-mode = "mii"; - phy-reset-gpios = <&gpio2 14 0>; /* GPIO2_14 */ + phy-reset-gpios = <&gpio2 14 GPIO_ACTIVE_LOW>; /* GPIO2_14 */ local-mac-address = [00 04 9F 01 1B B9]; phy-supply = <®_fec_supply>; }; @@ -71,7 +71,7 @@ ethernet@83fec000 { reg = <0x83fec000 0x4000>; interrupts = <87>; phy-mode = "mii"; - phy-reset-gpios = <&gpio2 14 0>; /* GPIO2_14 */ + phy-reset-gpios = <&gpio2 14 GPIO_ACTIVE_LOW>; /* GPIO2_14 */ local-mac-address = [00 04 9F 01 1B B9]; phy-supply = <®_fec_supply>; phy-handle = <ðphy>; diff --git a/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt b/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt index db74f0dc290c..594982c6b9f9 100644 --- a/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt +++ b/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt @@ -136,7 +136,7 @@ Clock Properties: Example: - ptp_clock@24E00 { + ptp_clock@24e00 { compatible = "fsl,etsec-ptp"; reg = <0x24E00 0xB0>; interrupts = <12 0x8 13 0x8>; diff --git a/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt index dea5124cdc52..d24172cc6d32 100644 --- a/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt +++ b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt @@ -1,7 +1,7 @@ * ADF7242 IEEE 802.15.4 * Required properties: - - compatible: should be "adi,adf7242" + - compatible: should be "adi,adf7242", "adi,adf7241" - spi-max-frequency: maximal bus speed (12.5 MHz) - reg: the chipselect index - interrupts: the interrupt generated by the device via pin IRQ1. diff --git a/Documentation/devicetree/bindings/net/mediatek-net.txt b/Documentation/devicetree/bindings/net/mediatek-net.txt index 214eaa9a6683..53c13ee384a4 100644 --- a/Documentation/devicetree/bindings/net/mediatek-net.txt +++ b/Documentation/devicetree/bindings/net/mediatek-net.txt @@ -28,7 +28,7 @@ Required properties: - mediatek,sgmiisys: phandle to the syscon node that handles the SGMII setup which is required for those SoCs equipped with SGMII such as MT7622 SoC. - mediatek,pctl: phandle to the syscon node that handles the ports slew rate - and driver current + and driver current: only for MT2701 and MT7623 SoC Optional properties: - interrupt-parent: Should be the phandle for the interrupt controller diff --git a/Documentation/devicetree/bindings/net/phy.txt b/Documentation/devicetree/bindings/net/phy.txt index 77d0b2a61ffa..d2169a56f5e3 100644 --- a/Documentation/devicetree/bindings/net/phy.txt +++ b/Documentation/devicetree/bindings/net/phy.txt @@ -53,6 +53,14 @@ Optional Properties: to ensure the integrated PHY is used. The absence of this property indicates the muxers should be configured so that the external PHY is used. +- reset-gpios: The GPIO phandle and specifier for the PHY reset signal. + +- reset-assert-us: Delay after the reset was asserted in microseconds. + If this property is missing the delay will be skipped. + +- reset-deassert-us: Delay after the reset was deasserted in microseconds. + If this property is missing the delay will be skipped. + Example: ethernet-phy@0 { @@ -60,4 +68,8 @@ ethernet-phy@0 { interrupt-parent = <&PIC>; interrupts = <35 IRQ_TYPE_EDGE_RISING>; reg = <0>; + + reset-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; + reset-assert-us = <1000>; + reset-deassert-us = <2000>; }; diff --git a/Documentation/devicetree/bindings/net/sff,sfp.txt b/Documentation/devicetree/bindings/net/sff,sfp.txt index 60e970ce10ee..f1c441bedf68 100644 --- a/Documentation/devicetree/bindings/net/sff,sfp.txt +++ b/Documentation/devicetree/bindings/net/sff,sfp.txt @@ -3,7 +3,9 @@ Transceiver Required properties: -- compatible : must be "sff,sfp" +- compatible : must be one of + "sff,sfp" for SFP modules + "sff,sff" for soldered down SFF modules Optional Properties: @@ -11,7 +13,8 @@ Optional Properties: interface - mod-def0-gpios : GPIO phandle and a specifier of the MOD-DEF0 (AKA Mod_ABS) - module presence input gpio signal, active (module absent) high + module presence input gpio signal, active (module absent) high. Must + not be present for SFF modules - los-gpios : GPIO phandle and a specifier of the Receiver Loss of Signal Indication input gpio signal, active (signal lost) high @@ -24,10 +27,11 @@ Optional Properties: - rate-select0-gpios : GPIO phandle and a specifier of the Rx Signaling Rate Select (AKA RS0) output gpio signal, low: low Rx rate, high: high Rx rate + Must not be present for SFF modules - rate-select1-gpios : GPIO phandle and a specifier of the Tx Signaling Rate Select (AKA RS1) output gpio signal (SFP+ only), low: low Tx rate, high: - high Tx rate + high Tx rate. Must not be present for SFF modules Example #1: Direct serdes to SFP connection diff --git a/Documentation/devicetree/bindings/net/socionext,uniphier-ave4.txt b/Documentation/devicetree/bindings/net/socionext,uniphier-ave4.txt new file mode 100644 index 000000000000..270ea4efff13 --- /dev/null +++ b/Documentation/devicetree/bindings/net/socionext,uniphier-ave4.txt @@ -0,0 +1,48 @@ +* Socionext AVE ethernet controller + +This describes the devicetree bindings for AVE ethernet controller +implemented on Socionext UniPhier SoCs. + +Required properties: + - compatible: Should be + - "socionext,uniphier-pro4-ave4" : for Pro4 SoC + - "socionext,uniphier-pxs2-ave4" : for PXs2 SoC + - "socionext,uniphier-ld11-ave4" : for LD11 SoC + - "socionext,uniphier-ld20-ave4" : for LD20 SoC + - reg: Address where registers are mapped and size of region. + - interrupts: Should contain the MAC interrupt. + - phy-mode: See ethernet.txt in the same directory. Allow to choose + "rgmii", "rmii", or "mii" according to the PHY. + - phy-handle: Should point to the external phy device. + See ethernet.txt file in the same directory. + - clocks: A phandle to the clock for the MAC. + +Optional properties: + - resets: A phandle to the reset control for the MAC. + - local-mac-address: See ethernet.txt in the same directory. + +Required subnode: + - mdio: A container for child nodes representing phy nodes. + See phy.txt in the same directory. + +Example: + + ether: ethernet@65000000 { + compatible = "socionext,uniphier-ld20-ave4"; + reg = <0x65000000 0x8500>; + interrupts = <0 66 4>; + phy-mode = "rgmii"; + phy-handle = <ðphy>; + clocks = <&sys_clk 6>; + resets = <&sys_rst 6>; + local-mac-address = [00 00 00 00 00 00]; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy: ethphy@1 { + reg = <1>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/net/socionext-netsec.txt b/Documentation/devicetree/bindings/net/socionext-netsec.txt new file mode 100644 index 000000000000..0cff94fb0433 --- /dev/null +++ b/Documentation/devicetree/bindings/net/socionext-netsec.txt @@ -0,0 +1,53 @@ +* Socionext NetSec Ethernet Controller IP + +Required properties: +- compatible: Should be "socionext,synquacer-netsec" +- reg: Address and length of the control register area, followed by the + address and length of the EEPROM holding the MAC address and + microengine firmware +- interrupts: Should contain ethernet controller interrupt +- clocks: phandle to the PHY reference clock +- clock-names: Should be "phy_ref_clk" +- phy-mode: See ethernet.txt file in the same directory +- phy-handle: See ethernet.txt in the same directory. + +- mdio device tree subnode: When the Netsec has a phy connected to its local + mdio, there must be device tree subnode with the following + required properties: + + - #address-cells: Must be <1>. + - #size-cells: Must be <0>. + + For each phy on the mdio bus, there must be a node with the following + fields: + - compatible: Refer to phy.txt + - reg: phy id used to communicate to phy. + +Optional properties: (See ethernet.txt file in the same directory) +- dma-coherent: Boolean property, must only be present if memory + accesses performed by the device are cache coherent. +- local-mac-address: See ethernet.txt in the same directory. +- mac-address: See ethernet.txt in the same directory. +- max-speed: See ethernet.txt in the same directory. +- max-frame-size: See ethernet.txt in the same directory. + +Example: + eth0: ethernet@522d0000 { + compatible = "socionext,synquacer-netsec"; + reg = <0 0x522d0000 0x0 0x10000>, <0 0x10000000 0x0 0x10000>; + interrupts = ; + clocks = <&clk_netsec>; + clock-names = "phy_ref_clk"; + phy-mode = "rgmii"; + max-speed = <1000>; + max-frame-size = <9000>; + phy-handle = <&phy1>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; + }; diff --git a/Documentation/devicetree/bindings/net/ti,wilink-st.txt b/Documentation/devicetree/bindings/net/ti-bluetooth.txt similarity index 64% rename from Documentation/devicetree/bindings/net/ti,wilink-st.txt rename to Documentation/devicetree/bindings/net/ti-bluetooth.txt index 1649c1f66b07..6d03ff8c7068 100644 --- a/Documentation/devicetree/bindings/net/ti,wilink-st.txt +++ b/Documentation/devicetree/bindings/net/ti-bluetooth.txt @@ -1,10 +1,18 @@ -TI WiLink 7/8 (wl12xx/wl18xx) Shared Transport BT/FM/GPS devices +Texas Instruments Bluetooth Chips +--------------------------------- + +This documents the binding structure and common properties for serial +attached TI Bluetooth devices. The following chips are included in this +binding: + +* TI CC256x Bluetooth devices +* TI WiLink 7/8 (wl12xx/wl18xx) Shared Transport BT/FM/GPS devices TI WiLink devices have a UART interface for providing Bluetooth, FM radio, and GPS over what's called "shared transport". The shared transport is standard BT HCI protocol with additional channels for the other functions. -These devices also have a separate WiFi interface as described in +TI WiLink devices also have a separate WiFi interface as described in wireless/ti,wlcore.txt. This bindings follows the UART slave device binding in @@ -12,6 +20,7 @@ This bindings follows the UART slave device binding in Required properties: - compatible: should be one of the following: + "ti,cc2560" "ti,wl1271-st" "ti,wl1273-st" "ti,wl1281-st" @@ -32,6 +41,9 @@ Optional properties: See ../clocks/clock-bindings.txt for details. - clock-names : Must include the following entry: "ext_clock" (External clock provided to the TI combo chip). + - nvmem-cells: phandle to nvmem data cell that contains a 6 byte BD address + with the most significant byte first (big-endian). + - nvmem-cell-names: "bd-address" (required when nvmem-cells is specified) Example: @@ -43,5 +55,7 @@ Example: enable-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; clocks = <&clk32k_wl18xx>; clock-names = "ext_clock"; + nvmem-cells = <&bd_address>; + nvmem-cell-names = "bd-address"; }; }; diff --git a/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.txt b/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.txt new file mode 100644 index 000000000000..0c17a0ec9b7b --- /dev/null +++ b/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.txt @@ -0,0 +1,32 @@ +* MediaTek mt76xx devices + +This node provides properties for configuring the MediaTek mt76xx wireless +device. The node is expected to be specified as a child node of the PCI +controller to which the wireless chip is connected. + +Optional properties: + +- mac-address: See ethernet.txt in the parent directory +- local-mac-address: See ethernet.txt in the parent directory +- ieee80211-freq-limit: See ieee80211.txt +- mediatek,mtd-eeprom: Specify a MTD partition + offset containing EEPROM data + +Optional nodes: +- led: Properties for a connected LED + Optional properties: + - led-sources: See Documentation/devicetree/bindings/leds/common.txt + +&pcie { + pcie0 { + wifi@0,0 { + compatible = "mediatek,mt76"; + reg = <0x0000 0 0 0 0>; + ieee80211-freq-limit = <5000000 6000000>; + mediatek,mtd-eeprom = <&factory 0x8000>; + + led { + led-sources = <2>; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt index 74d7f0af209c..3d2a031217da 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt @@ -41,6 +41,9 @@ Optional properties: - qcom,msi_addr: MSI interrupt address. - qcom,msi_base: Base value to add before writing MSI data into MSI address register. +- qcom,ath10k-calibration-variant: string to search for in the board-2.bin + variant list with the same bus and device + specific ids - qcom,ath10k-calibration-data : calibration data + board specific data as an array, the length can vary between hw versions. diff --git a/Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt b/Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt index 60bec4782806..265bdb7dc8aa 100644 --- a/Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt +++ b/Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt @@ -6,12 +6,17 @@ Required properties: - "rockchip,rk3188-efuse" - for RK3188 SoCs. - "rockchip,rk3228-efuse" - for RK3228 SoCs. - "rockchip,rk3288-efuse" - for RK3288 SoCs. + - "rockchip,rk3328-efuse" - for RK3328 SoCs. - "rockchip,rk3368-efuse" - for RK3368 SoCs. - "rockchip,rk3399-efuse" - for RK3399 SoCs. - reg: Should contain the registers location and exact eFuse size - clocks: Should be the clock id of eFuse - clock-names: Should be "pclk_efuse" +Optional properties: +- rockchip,efuse-size: Should be exact eFuse size in byte, the eFuse + size in property will be invalid if define this property. + Deprecated properties: - compatible: "rockchip,rockchip-efuse" Old efuse compatible value compatible to rk3066a, rk3188 and rk3288 diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt index 9d733af26be7..4e4f30288c8b 100644 --- a/Documentation/devicetree/bindings/opp/opp.txt +++ b/Documentation/devicetree/bindings/opp/opp.txt @@ -45,6 +45,11 @@ Devices supporting OPPs must set their "operating-points-v2" property with phandle to a OPP table in their DT node. The OPP core will use this phandle to find the operating points for the device. +This can contain more than one phandle for power domain providers that provide +multiple power domains. That is, one phandle for each power domain. If only one +phandle is available, then the same OPP table will be used for all power domains +provided by the power domain provider. + If required, this can be extended for SoC vendor specific bindings. Such bindings should be documented as Documentation/devicetree/bindings/power/-opp.txt and should have a compatible description like: "operating-points-v2-". @@ -154,6 +159,14 @@ Optional properties: - status: Marks the node enabled/disabled. +- required-opp: This contains phandle to an OPP node in another device's OPP + table. It may contain an array of phandles, where each phandle points to an + OPP of a different device. It should not contain multiple phandles to the OPP + nodes in the same OPP table. This specifies the minimum required OPP of the + device(s), whose OPP's phandle is present in this property, for the + functioning of the current device at the current OPP (where this property is + present). + Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together. / { diff --git a/Documentation/devicetree/bindings/opp/ti-omap5-opp-supply.txt b/Documentation/devicetree/bindings/opp/ti-omap5-opp-supply.txt new file mode 100644 index 000000000000..832346e489a3 --- /dev/null +++ b/Documentation/devicetree/bindings/opp/ti-omap5-opp-supply.txt @@ -0,0 +1,63 @@ +Texas Instruments OMAP compatible OPP supply description + +OMAP5, DRA7, and AM57 family of SoCs have Class0 AVS eFuse registers which +contain data that can be used to adjust voltages programmed for some of their +supplies for more efficient operation. This binding provides the information +needed to read these values and use them to program the main regulator during +an OPP transitions. + +Also, some supplies may have an associated vbb-supply which is an Adaptive Body +Bias regulator which much be transitioned in a specific sequence with regards +to the vdd-supply and clk when making an OPP transition. By supplying two +regulators to the device that will undergo OPP transitions we can make use +of the multi regulator binding that is part of the OPP core described here [1] +to describe both regulators needed by the platform. + +[1] Documentation/devicetree/bindings/opp/opp.txt + +Required Properties for Device Node: +- vdd-supply: phandle to regulator controlling VDD supply +- vbb-supply: phandle to regulator controlling Body Bias supply + (Usually Adaptive Body Bias regulator) + +Required Properties for opp-supply node: +- compatible: Should be one of: + "ti,omap-opp-supply" - basic OPP supply controlling VDD and VBB + "ti,omap5-opp-supply" - OMAP5+ optimized voltages in efuse(class0)VDD + along with VBB + "ti,omap5-core-opp-supply" - OMAP5+ optimized voltages in efuse(class0) VDD + but no VBB. +- reg: Address and length of the efuse register set for the device (mandatory + only for "ti,omap5-opp-supply") +- ti,efuse-settings: An array of u32 tuple items providing information about + optimized efuse configuration. Each item consists of the following: + volt: voltage in uV - reference voltage (OPP voltage) + efuse_offseet: efuse offset from reg where the optimized voltage is stored. +- ti,absolute-max-voltage-uv: absolute maximum voltage for the OPP supply. + +Example: + +/* Device Node (CPU) */ +cpus { + cpu0: cpu@0 { + device_type = "cpu"; + + ... + + vdd-supply = <&vcc>; + vbb-supply = <&abb_mpu>; + }; +}; + +/* OMAP OPP Supply with Class0 registers */ +opp_supply_mpu: opp_supply@4a003b20 { + compatible = "ti,omap5-opp-supply"; + reg = <0x4a003b20 0x8>; + ti,efuse-settings = < + /* uV offset */ + 1060000 0x0 + 1160000 0x4 + 1210000 0x8 + >; + ti,absolute-max-voltage-uv = <1500000>; +}; diff --git a/Documentation/devicetree/bindings/pci/axis,artpec6-pcie.txt b/Documentation/devicetree/bindings/pci/axis,artpec6-pcie.txt index 4e4aee4439ea..979dc7b6cfe8 100644 --- a/Documentation/devicetree/bindings/pci/axis,artpec6-pcie.txt +++ b/Documentation/devicetree/bindings/pci/axis,artpec6-pcie.txt @@ -4,7 +4,10 @@ This PCIe host controller is based on the Synopsys DesignWare PCIe IP and thus inherits all the common properties defined in designware-pcie.txt. Required properties: -- compatible: "axis,artpec6-pcie", "snps,dw-pcie" +- compatible: "axis,artpec6-pcie", "snps,dw-pcie" for ARTPEC-6 in RC mode; + "axis,artpec6-pcie-ep", "snps,dw-pcie" for ARTPEC-6 in EP mode; + "axis,artpec7-pcie", "snps,dw-pcie" for ARTPEC-7 in RC mode; + "axis,artpec7-pcie-ep", "snps,dw-pcie" for ARTPEC-7 in EP mode; - reg: base addresses and lengths of the PCIe controller (DBI), the PHY controller, and configuration address space. - reg-names: Must include the following entries: diff --git a/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-ep.txt b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-ep.txt new file mode 100644 index 000000000000..9a305237fa6e --- /dev/null +++ b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-ep.txt @@ -0,0 +1,22 @@ +* Cadence PCIe endpoint controller + +Required properties: +- compatible: Should contain "cdns,cdns-pcie-ep" to identify the IP used. +- reg: Should contain the controller register base address and AXI interface + region base address respectively. +- reg-names: Must be "reg" and "mem" respectively. +- cdns,max-outbound-regions: Set to maximum number of outbound regions + +Optional properties: +- max-functions: Maximum number of functions that can be configured (default 1). + +Example: + +pcie@fc000000 { + compatible = "cdns,cdns-pcie-ep"; + reg = <0x0 0xfc000000 0x0 0x01000000>, + <0x0 0x80000000 0x0 0x40000000>; + reg-names = "reg", "mem"; + cdns,max-outbound-regions = <16>; + max-functions = /bits/ 8 <8>; +}; diff --git a/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt new file mode 100644 index 000000000000..20a33f38f69d --- /dev/null +++ b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt @@ -0,0 +1,60 @@ +* Cadence PCIe host controller + +This PCIe controller inherits the base properties defined in +host-generic-pci.txt. + +Required properties: +- compatible: Should contain "cdns,cdns-pcie-host" to identify the IP used. +- reg: Should contain the controller register base address, PCIe configuration + window base address, and AXI interface region base address respectively. +- reg-names: Must be "reg", "cfg" and "mem" respectively. +- #address-cells: Set to <3> +- #size-cells: Set to <2> +- device_type: Set to "pci" +- ranges: Ranges for the PCI memory and I/O regions +- #interrupt-cells: Set to <1> +- interrupt-map-mask and interrupt-map: Standard PCI properties to define the + mapping of the PCIe interface to interrupt numbers. + +Optional properties: +- cdns,max-outbound-regions: Set to maximum number of outbound regions + (default 32) +- cdns,no-bar-match-nbits: Set into the no BAR match register to configure the + number of least significant bits kept during inbound (PCIe -> AXI) address + translations (default 32) +- vendor-id: The PCI vendor ID (16 bits, default is design dependent) +- device-id: The PCI device ID (16 bits, default is design dependent) + +Example: + +pcie@fb000000 { + compatible = "cdns,cdns-pcie-host"; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x0 0xff>; + linux,pci-domain = <0>; + cdns,max-outbound-regions = <16>; + cdns,no-bar-match-nbits = <32>; + vendor-id = /bits/ 16 <0x17cd>; + device-id = /bits/ 16 <0x0200>; + + reg = <0x0 0xfb000000 0x0 0x01000000>, + <0x0 0x41000000 0x0 0x00001000>, + <0x0 0x40000000 0x0 0x04000000>; + reg-names = "reg", "cfg", "mem"; + + ranges = <0x02000000 0x0 0x42000000 0x0 0x42000000 0x0 0x1000000>, + <0x01000000 0x0 0x43000000 0x0 0x43000000 0x0 0x0010000>; + + #interrupt-cells = <0x1>; + + interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0x0 0x0 14 0x1 + 0x0 0x0 0x0 0x2 &gic 0x0 0x0 0x0 15 0x1 + 0x0 0x0 0x0 0x3 &gic 0x0 0x0 0x0 16 0x1 + 0x0 0x0 0x0 0x4 &gic 0x0 0x0 0x0 17 0x1>; + + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + + msi-parent = <&its_pci>; +}; diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt index 149d8f7f86b0..cb33421184a0 100644 --- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt +++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt @@ -41,6 +41,7 @@ Optional properties: Additional required properties for imx6sx-pcie: - clock names: Must include the following additional entries: - "pcie_inbound_axi" +- power-domains: Must be set to a phandle pointing to the PCIE_PHY power domain Additional required properties for imx7d-pcie: - power-domains: Must be set to a phandle pointing to PCIE_PHY power domain diff --git a/Documentation/devicetree/bindings/pci/samsung,exynos5440-pcie.txt b/Documentation/devicetree/bindings/pci/samsung,exynos5440-pcie.txt index 34a11bfbfb60..651d957d1051 100644 --- a/Documentation/devicetree/bindings/pci/samsung,exynos5440-pcie.txt +++ b/Documentation/devicetree/bindings/pci/samsung,exynos5440-pcie.txt @@ -6,9 +6,6 @@ and thus inherits all the common properties defined in designware-pcie.txt. Required properties: - compatible: "samsung,exynos5440-pcie" - reg: base addresses and lengths of the PCIe controller, - the PHY controller, additional register for the PHY controller. - (Registers for the PHY controller are DEPRECATED. - Use the PHY framework.) - reg-names : First name should be set to "elbi". And use the "config" instead of getting the configuration address space from "ranges". @@ -23,49 +20,8 @@ For other common properties, refer to Example: -SoC-specific DT Entry: +SoC-specific DT Entry (with using PHY framework): - pcie@290000 { - compatible = "samsung,exynos5440-pcie", "snps,dw-pcie"; - reg = <0x290000 0x1000 - 0x270000 0x1000 - 0x271000 0x40>; - interrupts = <0 20 0>, <0 21 0>, <0 22 0>; - clocks = <&clock 28>, <&clock 27>; - clock-names = "pcie", "pcie_bus"; - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - ranges = <0x00000800 0 0x40000000 0x40000000 0 0x00001000 /* configuration space */ - 0x81000000 0 0 0x40001000 0 0x00010000 /* downstream I/O */ - 0x82000000 0 0x40011000 0x40011000 0 0x1ffef000>; /* non-prefetchable memory */ - #interrupt-cells = <1>; - interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &gic GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; - num-lanes = <4>; - }; - - pcie@2a0000 { - compatible = "samsung,exynos5440-pcie", "snps,dw-pcie"; - reg = <0x2a0000 0x1000 - 0x272000 0x1000 - 0x271040 0x40>; - interrupts = <0 23 0>, <0 24 0>, <0 25 0>; - clocks = <&clock 29>, <&clock 27>; - clock-names = "pcie", "pcie_bus"; - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - ranges = <0x00000800 0 0x60000000 0x60000000 0 0x00001000 /* configuration space */ - 0x81000000 0 0 0x60001000 0 0x00010000 /* downstream I/O */ - 0x82000000 0 0x60011000 0x60011000 0 0x1ffef000>; /* non-prefetchable memory */ - #interrupt-cells = <1>; - interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &gic GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>; - num-lanes = <4>; - }; - -With using PHY framework: pcie_phy0: pcie-phy@270000 { ... reg = <0x270000 0x1000>, <0x271000 0x40>; @@ -74,13 +30,21 @@ With using PHY framework: }; pcie@290000 { - ... + compatible = "samsung,exynos5440-pcie", "snps,dw-pcie"; reg = <0x290000 0x1000>, <0x40000000 0x1000>; reg-names = "elbi", "config"; + clocks = <&clock 28>, <&clock 27>; + clock-names = "pcie", "pcie_bus"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; phys = <&pcie_phy0>; ranges = <0x81000000 0 0 0x60001000 0 0x00010000 0x82000000 0 0x60011000 0x60011000 0 0x1ffef000>; - ... + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; + num-lanes = <4>; }; Board-specific DT Entry: diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt index cd13e6157088..57dfda8a7a1d 100644 --- a/Documentation/devicetree/bindings/phy/ti-phy.txt +++ b/Documentation/devicetree/bindings/phy/ti-phy.txt @@ -120,7 +120,7 @@ usb3phy@4a084400 { "refclk"; }; -sata_phy: phy@4A096000 { +sata_phy: phy@4a096000 { compatible = "ti,phy-pipe3-sata"; reg = <0x4A096000 0x80>, /* phy_rx */ <0x4A096400 0x64>, /* phy_tx */ diff --git a/Documentation/devicetree/bindings/pinctrl/abilis,tb10x-iomux.txt b/Documentation/devicetree/bindings/pinctrl/abilis,tb10x-iomux.txt index 2c11866221c2..c591b9cb5ba0 100644 --- a/Documentation/devicetree/bindings/pinctrl/abilis,tb10x-iomux.txt +++ b/Documentation/devicetree/bindings/pinctrl/abilis,tb10x-iomux.txt @@ -49,7 +49,7 @@ explained in Documentation/devicetree/bindings/gpio/gpio.txt. Example ------- -iomux: iomux@FF10601c { +iomux: iomux@ff10601c { compatible = "abilis,tb10x-iomux"; reg = <0xFF10601c 0x4>; pctl_gpio_a: pctl-gpio-a { @@ -59,7 +59,7 @@ iomux: iomux@FF10601c { abilis,function = "uart0"; }; }; -uart@FF100000 { +uart@ff100000 { compatible = "snps,dw-apb-uart"; reg = <0xFF100000 0x100>; clock-frequency = <166666666>; @@ -69,7 +69,7 @@ uart@FF100000 { pinctrl-names = "default"; pinctrl-0 = <&pctl_uart0>; }; -gpioa: gpio@FF140000 { +gpioa: gpio@ff140000 { compatible = "abilis,tb10x-gpio"; reg = <0xFF140000 0x1000>; gpio-controller; diff --git a/Documentation/devicetree/bindings/pinctrl/cortina,gemini-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/cortina,gemini-pinctrl.txt index d857b67fab72..4346ff2dd8e6 100644 --- a/Documentation/devicetree/bindings/pinctrl/cortina,gemini-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/cortina,gemini-pinctrl.txt @@ -17,6 +17,9 @@ and generic pin config nodes. Supported configurations: - skew-delay is supported on the Ethernet pins +- drive-strength with 4, 8, 12 or 16 mA as argument is supported for + entire groups on the groups "idegrp", "gmii_gmac0_grp", "gmii_gmac1_grp" + and "pcigrp". Example: diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt index a81bbf37ed66..7ca4f6118d9a 100644 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt @@ -4,7 +4,8 @@ Please refer to fsl,imx-pinctrl.txt in this directory for common binding part and usage. Required properties: -- compatible: "fsl,imx6ul-iomuxc" +- compatible: "fsl,imx6ul-iomuxc" for main IOMUX controller or + "fsl,imx6ull-iomuxc-snvs" for i.MX 6ULL's SNVS IOMUX controller. - fsl,pins: each entry consists of 6 integers and represents the mux and config setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can be found in diff --git a/Documentation/devicetree/bindings/pinctrl/img,pistachio-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/img,pistachio-pinctrl.txt index 0326154c7925..a72dc3178179 100644 --- a/Documentation/devicetree/bindings/pinctrl/img,pistachio-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/img,pistachio-pinctrl.txt @@ -152,7 +152,7 @@ resetn Example: -------- -pinctrl@18101C00 { +pinctrl@18101c00 { compatible = "img,pistachio-system-pinctrl"; reg = <0x18101C00 0x400>; diff --git a/Documentation/devicetree/bindings/pinctrl/lantiq,pinctrl-xway.txt b/Documentation/devicetree/bindings/pinctrl/lantiq,pinctrl-xway.txt index 8e5216bcd748..4658f105fa09 100644 --- a/Documentation/devicetree/bindings/pinctrl/lantiq,pinctrl-xway.txt +++ b/Documentation/devicetree/bindings/pinctrl/lantiq,pinctrl-xway.txt @@ -163,7 +163,7 @@ Valid values for xRX300 pin names: io42-io43,io48-io61. Example: - gpio: pinmux@E100B10 { + gpio: pinmux@e100b10 { compatible = "lantiq,danube-pinctrl"; pinctrl-names = "default"; pinctrl-0 = <&state_default>; diff --git a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt index 2392557ede27..2c12f9789116 100644 --- a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt @@ -9,6 +9,8 @@ Required properties for the root node: "amlogic,meson-gxbb-aobus-pinctrl" "amlogic,meson-gxl-periphs-pinctrl" "amlogic,meson-gxl-aobus-pinctrl" + "amlogic,meson-axg-periphs-pinctrl" + "amlogic,meson-axg-aobus-pinctrl" - reg: address and size of registers controlling irq functionality === GPIO sub-nodes === diff --git a/Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.txt new file mode 100644 index 000000000000..24a210e0c59a --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.txt @@ -0,0 +1,39 @@ +Microsemi Ocelot pin controller Device Tree Bindings +---------------------------------------------------- + +Required properties: + - compatible : Should be "mscc,ocelot-pinctrl" + - reg : Address and length of the register set for the device + - gpio-controller : Indicates this device is a GPIO controller + - #gpio-cells : Must be 2. + The first cell is the pin number and the + second cell specifies GPIO flags, as defined in + . + - gpio-ranges : Range of pins managed by the GPIO controller. + + +The ocelot-pinctrl driver uses the generic pin multiplexing and generic pin +configuration documented in pinctrl-bindings.txt. + +The following generic properties are supported: + - function + - pins + +Example: + gpio: pinctrl@71070034 { + compatible = "mscc,ocelot-pinctrl"; + reg = <0x71070034 0x28>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&gpio 0 0 22>; + + uart_pins: uart-pins { + pins = "GPIO_6", "GPIO_7"; + function = "uart"; + }; + + uart2_pins: uart2-pins { + pins = "GPIO_12", "GPIO_13"; + function = "uart2"; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt index 231fa1db7c5e..afa8a18ea11a 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt @@ -81,7 +81,7 @@ Examples: reg = <0 0x10005000 0 0x1000>; }; - syscfg_pctl_b: syscfg_pctl_b@1020C020 { + syscfg_pctl_b: syscfg_pctl_b@1020c020 { compatible = "mediatek,mt8135-pctl-b-syscfg", "syscon"; reg = <0 0x1020C020 0 0x1000>; }; diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt7622.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt7622.txt new file mode 100644 index 000000000000..f18ed99f6e14 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt7622.txt @@ -0,0 +1,351 @@ +== MediaTek MT7622 pinctrl controller == + +Required properties for the root node: + - compatible: Should be one of the following + "mediatek,mt7622-pinctrl" for MT7622 SoC + - reg: offset and length of the pinctrl space + + - gpio-controller: Marks the device node as a GPIO controller. + - #gpio-cells: Should be two. The first cell is the pin number and the + second is the GPIO flags. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +MT7622 pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, slew rate, etc. + +We support 2 types of configuration nodes. Those nodes can be either pinmux +nodes or pinconf nodes. Each configuration node can consist of multiple nodes +describing the pinmux and pinconf options. + +The name of each subnode doesn't matter as long as it is unique; all subnodes +should be enumerated and processed purely based on their content. + +== pinmux nodes content == + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pinmux subnode: + +Required properties are: + - groups: An array of strings. Each string contains the name of a group. + Valid values for these names are listed below. + - function: A string containing the name of the function to mux to the + group. Valid values for function names are listed below. + +== pinconf nodes content == + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pinconf subnode: + +Required properties are: + - pins: An array of strings. Each string contains the name of a pin. + Valid values for these names are listed below. + - groups: An array of strings. Each string contains the name of a group. + Valid values for these names are listed below. + +Optional properies are: + bias-disable, bias-pull, bias-pull-down, input-enable, + input-schmitt-enable, input-schmitt-disable, output-enable + output-low, output-high, drive-strength, slew-rate + + Valid arguments for 'slew-rate' are '0' for no slew rate controlled and '1' for + slower slew rate respectively. + Valid arguments for 'drive-strength', 4, 8, 12, or 16 in mA. + +The following specific properties as defined are valid to specify in a pinconf +subnode: + +Optional properties are: + - mediatek,tdsel: An integer describing the steps for output level shifter duty + cycle when asserted (high pulse width adjustment). Valid arguments are from 0 + to 15. + - mediatek,rdsel: An integer describing the steps for input level shifter duty + cycle when asserted (high pulse width adjustment). Valid arguments are from 0 + to 63. + +== Valid values for pins, function and groups on MT7622 == + +Valid values for pins are: +pins can be referenced via the pin names as the below table shown and the +related physical number is also put ahead of those names which helps cross +references to pins between groups to know whether pins assignment conflict +happens among devices try to acquire those available pins. + + Pin #: Valid values for pins + ----------------------------- + PIN 0: "GPIO_A" + PIN 1: "I2S1_IN" + PIN 2: "I2S1_OUT" + PIN 3: "I2S_BCLK" + PIN 4: "I2S_WS" + PIN 5: "I2S_MCLK" + PIN 6: "TXD0" + PIN 7: "RXD0" + PIN 8: "SPI_WP" + PIN 9: "SPI_HOLD" + PIN 10: "SPI_CLK" + PIN 11: "SPI_MOSI" + PIN 12: "SPI_MISO" + PIN 13: "SPI_CS" + PIN 14: "I2C_SDA" + PIN 15: "I2C_SCL" + PIN 16: "I2S2_IN" + PIN 17: "I2S3_IN" + PIN 18: "I2S4_IN" + PIN 19: "I2S2_OUT" + PIN 20: "I2S3_OUT" + PIN 21: "I2S4_OUT" + PIN 22: "GPIO_B" + PIN 23: "MDC" + PIN 24: "MDIO" + PIN 25: "G2_TXD0" + PIN 26: "G2_TXD1" + PIN 27: "G2_TXD2" + PIN 28: "G2_TXD3" + PIN 29: "G2_TXEN" + PIN 30: "G2_TXC" + PIN 31: "G2_RXD0" + PIN 32: "G2_RXD1" + PIN 33: "G2_RXD2" + PIN 34: "G2_RXD3" + PIN 35: "G2_RXDV" + PIN 36: "G2_RXC" + PIN 37: "NCEB" + PIN 38: "NWEB" + PIN 39: "NREB" + PIN 40: "NDL4" + PIN 41: "NDL5" + PIN 42: "NDL6" + PIN 43: "NDL7" + PIN 44: "NRB" + PIN 45: "NCLE" + PIN 46: "NALE" + PIN 47: "NDL0" + PIN 48: "NDL1" + PIN 49: "NDL2" + PIN 50: "NDL3" + PIN 51: "MDI_TP_P0" + PIN 52: "MDI_TN_P0" + PIN 53: "MDI_RP_P0" + PIN 54: "MDI_RN_P0" + PIN 55: "MDI_TP_P1" + PIN 56: "MDI_TN_P1" + PIN 57: "MDI_RP_P1" + PIN 58: "MDI_RN_P1" + PIN 59: "MDI_RP_P2" + PIN 60: "MDI_RN_P2" + PIN 61: "MDI_TP_P2" + PIN 62: "MDI_TN_P2" + PIN 63: "MDI_TP_P3" + PIN 64: "MDI_TN_P3" + PIN 65: "MDI_RP_P3" + PIN 66: "MDI_RN_P3" + PIN 67: "MDI_RP_P4" + PIN 68: "MDI_RN_P4" + PIN 69: "MDI_TP_P4" + PIN 70: "MDI_TN_P4" + PIN 71: "PMIC_SCL" + PIN 72: "PMIC_SDA" + PIN 73: "SPIC1_CLK" + PIN 74: "SPIC1_MOSI" + PIN 75: "SPIC1_MISO" + PIN 76: "SPIC1_CS" + PIN 77: "GPIO_D" + PIN 78: "WATCHDOG" + PIN 79: "RTS3_N" + PIN 80: "CTS3_N" + PIN 81: "TXD3" + PIN 82: "RXD3" + PIN 83: "PERST0_N" + PIN 84: "PERST1_N" + PIN 85: "WLED_N" + PIN 86: "EPHY_LED0_N" + PIN 87: "AUXIN0" + PIN 88: "AUXIN1" + PIN 89: "AUXIN2" + PIN 90: "AUXIN3" + PIN 91: "TXD4" + PIN 92: "RXD4" + PIN 93: "RTS4_N" + PIN 94: "CST4_N" + PIN 95: "PWM1" + PIN 96: "PWM2" + PIN 97: "PWM3" + PIN 98: "PWM4" + PIN 99: "PWM5" + PIN 100: "PWM6" + PIN 101: "PWM7" + PIN 102: "GPIO_E" + +Valid values for function are: + "emmc", "eth", "i2c", "i2s", "ir", "led", "flash", "pcie", + "pmic", "pwm", "sd", "spi", "tdm", "uart", "watchdog" + +Valid values for groups are: +additional data is put followingly with valid value allowing us to know which +applicable function and which relevant pins (in pin#) are able applied for that +group. + + Valid value function pins (in pin#) + ------------------------------------------------------------------------- + "emmc" "emmc" 40, 41, 42, 43, 44, 45, + 47, 48, 49, 50 + "emmc_rst" "emmc" 37 + "esw" "eth" 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, + 69, 70 + "esw_p0_p1" "eth" 51, 52, 53, 54, 55, 56, + 57, 58 + "esw_p2_p3_p4" "eth" 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70 + "rgmii_via_esw" "eth" 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70 + "rgmii_via_gmac1" "eth" 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70 + "rgmii_via_gmac2" "eth" 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36 + "mdc_mdio" "eth" 23, 24 + "i2c0" "i2c" 14, 15 + "i2c1_0" "i2c" 55, 56 + "i2c1_1" "i2c" 73, 74 + "i2c1_2" "i2c" 87, 88 + "i2c2_0" "i2c" 57, 58 + "i2c2_1" "i2c" 75, 76 + "i2c2_2" "i2c" 89, 90 + "i2s_in_mclk_bclk_ws" "i2s" 3, 4, 5 + "i2s1_in_data" "i2s" 1 + "i2s2_in_data" "i2s" 16 + "i2s3_in_data" "i2s" 17 + "i2s4_in_data" "i2s" 18 + "i2s_out_mclk_bclk_ws" "i2s" 3, 4, 5 + "i2s1_out_data" "i2s" 2 + "i2s2_out_data" "i2s" 19 + "i2s3_out_data" "i2s" 20 + "i2s4_out_data" "i2s" 21 + "ir_0_tx" "ir" 16 + "ir_1_tx" "ir" 59 + "ir_2_tx" "ir" 99 + "ir_0_rx" "ir" 17 + "ir_1_rx" "ir" 60 + "ir_2_rx" "ir" 100 + "ephy_leds" "led" 86, 91, 92, 93, 94 + "ephy0_led" "led" 86 + "ephy1_led" "led" 91 + "ephy2_led" "led" 92 + "ephy3_led" "led" 93 + "ephy4_led" "led" 94 + "wled" "led" 85 + "par_nand" "flash" 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, + 49, 50 + "snfi" "flash" 8, 9, 10, 11, 12, 13 + "spi_nor" "flash" 8, 9, 10, 11, 12, 13 + "pcie0_0_waken" "pcie" 14 + "pcie0_1_waken" "pcie" 79 + "pcie1_0_waken" "pcie" 14 + "pcie0_0_clkreq" "pcie" 15 + "pcie0_1_clkreq" "pcie" 80 + "pcie1_0_clkreq" "pcie" 15 + "pcie0_pad_perst" "pcie" 83 + "pcie1_pad_perst" "pcie" 84 + "pmic_bus" "pmic" 71, 72 + "pwm_ch1_0" "pwm" 51 + "pwm_ch1_1" "pwm" 73 + "pwm_ch1_2" "pwm" 95 + "pwm_ch2_0" "pwm" 52 + "pwm_ch2_1" "pwm" 74 + "pwm_ch2_2" "pwm" 96 + "pwm_ch3_0" "pwm" 53 + "pwm_ch3_1" "pwm" 75 + "pwm_ch3_2" "pwm" 97 + "pwm_ch4_0" "pwm" 54 + "pwm_ch4_1" "pwm" 67 + "pwm_ch4_2" "pwm" 76 + "pwm_ch4_3" "pwm" 98 + "pwm_ch5_0" "pwm" 68 + "pwm_ch5_1" "pwm" 77 + "pwm_ch5_2" "pwm" 99 + "pwm_ch6_0" "pwm" 69 + "pwm_ch6_1" "pwm" 78 + "pwm_ch6_2" "pwm" 81 + "pwm_ch6_3" "pwm" 100 + "pwm_ch7_0" "pwm" 70 + "pwm_ch7_1" "pwm" 82 + "pwm_ch7_2" "pwm" 101 + "sd_0" "sd" 16, 17, 18, 19, 20, 21 + "sd_1" "sd" 25, 26, 27, 28, 29, 30 + "spic0_0" "spi" 63, 64, 65, 66 + "spic0_1" "spi" 79, 80, 81, 82 + "spic1_0" "spi" 67, 68, 69, 70 + "spic1_1" "spi" 73, 74, 75, 76 + "spic2_0_wp_hold" "spi" 8, 9 + "spic2_0" "spi" 10, 11, 12, 13 + "tdm_0_out_mclk_bclk_ws" "tdm" 8, 9, 10 + "tdm_0_in_mclk_bclk_ws" "tdm" 11, 12, 13 + "tdm_0_out_data" "tdm" 20 + "tdm_0_in_data" "tdm" 21 + "tdm_1_out_mclk_bclk_ws" "tdm" 57, 58, 59 + "tdm_1_in_mclk_bclk_ws" "tdm" 60, 61, 62 + "tdm_1_out_data" "tdm" 55 + "tdm_1_in_data" "tdm" 56 + "uart0_0_tx_rx" "uart" 6, 7 + "uart1_0_tx_rx" "uart" 55, 56 + "uart1_0_rts_cts" "uart" 57, 58 + "uart1_1_tx_rx" "uart" 73, 74 + "uart1_1_rts_cts" "uart" 75, 76 + "uart2_0_tx_rx" "uart" 3, 4 + "uart2_0_rts_cts" "uart" 1, 2 + "uart2_1_tx_rx" "uart" 51, 52 + "uart2_1_rts_cts" "uart" 53, 54 + "uart2_2_tx_rx" "uart" 59, 60 + "uart2_2_rts_cts" "uart" 61, 62 + "uart2_3_tx_rx" "uart" 95, 96 + "uart3_0_tx_rx" "uart" 57, 58 + "uart3_1_tx_rx" "uart" 81, 82 + "uart3_1_rts_cts" "uart" 79, 80 + "uart4_0_tx_rx" "uart" 61, 62 + "uart4_1_tx_rx" "uart" 91, 92 + "uart4_1_rts_cts" "uart" 93, 94 + "uart4_2_tx_rx" "uart" 97, 98 + "uart4_2_rts_cts" "uart" 95, 96 + "watchdog" "watchdog" 78 + +Example: + + pio: pinctrl@10211000 { + compatible = "mediatek,mt7622-pinctrl"; + reg = <0 0x10211000 0 0x1000>; + gpio-controller; + #gpio-cells = <2>; + + pinctrl_eth_default: eth-default { + mux-mdio { + groups = "mdc_mdio"; + function = "eth"; + drive-strength = <12>; + }; + + mux-gmac2 { + groups = "gmac2"; + function = "eth"; + drive-strength = <12>; + }; + + mux-esw { + groups = "esw"; + function = "eth"; + drive-strength = <8>; + }; + + conf-mdio { + pins = "MDC"; + bias-pull-up; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.txt new file mode 100644 index 000000000000..e70c79bbbc5b --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.txt @@ -0,0 +1,193 @@ +Qualcomm MSM8998 TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +MSM8998 platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,msm8998-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. + + Valid pins are: + gpio0-gpio149 + Supports mux, bias and drive-strength + + sdc2_clk, sdc2_cmd, sdc2_data + Supports bias and drive-strength + + ufs_reset + Supports bias and drive-strength + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + + gpio, adsp_ext, agera_pll, atest_char, atest_gpsadc0, + atest_gpsadc1, atest_tsens, atest_tsens2, atest_usb1, + atest_usb10, atest_usb11, atest_usb12, atest_usb13, + audio_ref, bimc_dte0, bimc_dte1, blsp10_spi, blsp10_spi_a, + blsp10_spi_b, blsp11_i2c, blsp1_spi, blsp1_spi_a, + blsp1_spi_b, blsp2_spi, blsp9_spi, blsp_i2c1, blsp_i2c2, + blsp_i2c3, blsp_i2c4, blsp_i2c5, blsp_i2c6, blsp_i2c7, + blsp_i2c8, blsp_i2c9, blsp_i2c10, blsp_i2c11, blsp_i2c12, + blsp_spi1, blsp_spi2, blsp_spi3, blsp_spi4, blsp_spi5, + blsp_spi6, blsp_spi7, blsp_spi8, blsp_spi9, blsp_spi10, + blsp_spi11, blsp_spi12, blsp_uart1_a, blsp_uart1_b, + blsp_uart2_a, blsp_uart2_b, blsp_uart3_a, blsp_uart3_b, + blsp_uart7_a, blsp_uart7_b, blsp_uart8, blsp_uart8_a, + blsp_uart8_b, blsp_uart9_a, blsp_uart9_b, blsp_uim1_a, + blsp_uim1_b, blsp_uim2_a, blsp_uim2_b, blsp_uim3_a, + blsp_uim3_b, blsp_uim7_a, blsp_uim7_b, blsp_uim8_a, + blsp_uim8_b, blsp_uim9_a, blsp_uim9_b, bt_reset, + btfm_slimbus, cam_mclk, cci_async, cci_i2c, cci_timer0, + cci_timer1, cci_timer2, cci_timer3, cci_timer4, cri_trng, + cri_trng0, cri_trng1, dbg_out, ddr_bist, edp_hot, edp_lcd, + gcc_gp1_a, gcc_gp1_b, gcc_gp2_a, gcc_gp2_b, gcc_gp3_a, + gcc_gp3_b, hdmi_cec, hdmi_ddc, hdmi_hot, hdmi_rcv, + isense_dbg, jitter_bist, ldo_en, ldo_update, lpass_slimbus, + m_voc, mdp_vsync, mdp_vsync0, mdp_vsync1, mdp_vsync2, + mdp_vsync3, mdp_vsync_a, mdp_vsync_b, modem_tsync, mss_lte, + nav_dr, nav_pps, pa_indicator, pci_e0, phase_flag, + pll_bypassnl, pll_reset, pri_mi2s, pri_mi2s_ws, prng_rosc, + pwr_crypto, pwr_modem, pwr_nav, qdss_cti0_a, qdss_cti0_b, + qdss_cti1_a, qdss_cti1_b, qdss, qlink_enable, + qlink_request, qua_mi2s, sd_card, sd_write, sdc40, sdc41, + sdc42, sdc43, sdc4_clk, sdc4_cmd, sec_mi2s, sp_cmu, + spkr_i2s, ssbi1, ssc_irq, ter_mi2s, tgu_ch0, tgu_ch1, + tsense_pwm1, tsense_pwm2, tsif1_clk, tsif1_data, tsif1_en, + tsif1_error, tsif1_sync, tsif2_clk, tsif2_data, tsif2_en, + tsif2_error, tsif2_sync, uim1_clk, uim1_data, uim1_present, + uim1_reset, uim2_clk, uim2_data, uim2_present, uim2_reset, + uim_batt, usb_phy, vfr_1, vsense_clkout, vsense_data0, + vsense_data1, vsense_mode, wlan1_adc0, wlan1_adc1, + wlan2_adc0, wlan2_adc1, + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@03400000 { + compatible = "qcom,msm8998-pinctrl"; + reg = <0x03400000 0xc00000>; + interrupts = <0 208 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + + uart_console_active: uart_console_active { + mux { + pins = "gpio4", "gpio5"; + function = "blsp_uart8_a"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt index 9b4f8041c36a..bb1790e0b176 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt @@ -24,6 +24,7 @@ Required Properties: - "renesas,pfc-r8a7794": for R8A7794 (R-Car E2) compatible pin-controller. - "renesas,pfc-r8a7795": for R8A7795 (R-Car H3) compatible pin-controller. - "renesas,pfc-r8a7796": for R8A7796 (R-Car M3-W) compatible pin-controller. + - "renesas,pfc-r8a77970": for R8A77970 (R-Car V3M) compatible pin-controller. - "renesas,pfc-r8a77995": for R8A77995 (R-Car D3) compatible pin-controller. - "renesas,pfc-sh73a0": for SH73A0 (SH-Mobile AG5) compatible pin-controller. diff --git a/Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.txt new file mode 100644 index 000000000000..8173b12138ad --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.txt @@ -0,0 +1,27 @@ +UniPhier SoCs pin controller + +Required properties: +- compatible: should be one of the following: + "socionext,uniphier-ld4-pinctrl" - for LD4 SoC + "socionext,uniphier-pro4-pinctrl" - for Pro4 SoC + "socionext,uniphier-sld8-pinctrl" - for sLD8 SoC + "socionext,uniphier-pro5-pinctrl" - for Pro5 SoC + "socionext,uniphier-pxs2-pinctrl" - for PXs2 SoC + "socionext,uniphier-ld6b-pinctrl" - for LD6b SoC + "socionext,uniphier-ld11-pinctrl" - for LD11 SoC + "socionext,uniphier-ld20-pinctrl" - for LD20 SoC + "socionext,uniphier-pxs3-pinctrl" - for PXs3 SoC + +Note: +The UniPhier pinctrl should be a subnode of a "syscon" compatible node. + +Example: + soc-glue@5f800000 { + compatible = "socionext,uniphier-pro4-soc-glue", + "simple-mfd", "syscon"; + reg = <0x5f800000 0x2000>; + + pinctrl: pinctrl { + compatible = "socionext,uniphier-pro4-pinctrl"; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt index 58c2a4c229db..2c46f30b62c5 100644 --- a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt @@ -12,6 +12,8 @@ Required properies: "st,stm32f469-pinctrl" "st,stm32f746-pinctrl" "st,stm32h743-pinctrl" + "st,stm32mp157-pinctrl" + "st,stm32mp157-z-pinctrl" - #address-cells: The value of this property must be 1 - #size-cells : The value of this property must be 1 - ranges : defines mapping between pin controller node (parent) to diff --git a/Documentation/devicetree/bindings/power/actions,owl-sps.txt b/Documentation/devicetree/bindings/power/actions,owl-sps.txt index 007b9a7ae723..78edd63641e8 100644 --- a/Documentation/devicetree/bindings/power/actions,owl-sps.txt +++ b/Documentation/devicetree/bindings/power/actions,owl-sps.txt @@ -2,10 +2,12 @@ Actions Semi Owl Smart Power System (SPS) Required properties: - compatible : "actions,s500-sps" for S500 + "actions,s700-sps" for S700 - reg : Offset and length of the register set for the device. - #power-domain-cells : Must be 1. See macros in: include/dt-bindings/power/owl-s500-powergate.h for S500 + include/dt-bindings/power/owl-s700-powergate.h for S700 Example: diff --git a/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt b/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt index e371b262d709..b31d6bbeee16 100644 --- a/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt +++ b/Documentation/devicetree/bindings/power/fsl,imx-gpc.txt @@ -9,6 +9,7 @@ Required properties: - fsl,imx6q-gpc - fsl,imx6qp-gpc - fsl,imx6sl-gpc + - fsl,imx6sx-gpc - reg: should be register base and length as documented in the datasheet - interrupts: Should contain one interrupt specifier for the GPC interrupt @@ -29,6 +30,8 @@ Required properties: PU_DOMAIN 1 The following additional DOMAIN_INDEX value is valid for i.MX6SL: DISPLAY_DOMAIN 2 + The following additional DOMAIN_INDEX value is valid for i.MX6SX: + PCI_DOMAIN 3 - #power-domain-cells: Should be 0 diff --git a/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.txt b/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.txt index 02f45c65fd87..9acce75b29ab 100644 --- a/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.txt +++ b/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.txt @@ -44,10 +44,10 @@ Example: #address-cells = <1>; #size-cells = <0>; - pgc_pcie_phy: power-domain@3 { + pgc_pcie_phy: power-domain@1 { #power-domain-cells = <0>; - reg = ; + reg = <1>; power-supply = <®_1p0d>; }; }; diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt index 14bd9e945ff6..f3355313c020 100644 --- a/Documentation/devicetree/bindings/power/power_domain.txt +++ b/Documentation/devicetree/bindings/power/power_domain.txt @@ -40,6 +40,12 @@ Optional properties: domain's idle states. In the absence of this property, the domain would be considered as capable of being powered-on or powered-off. +- operating-points-v2 : Phandles to the OPP tables of power domains provided by + a power domain provider. If the provider provides a single power domain only + or all the power domains provided by the provider have identical OPP tables, + then this shall contain a single phandle. Refer to ../opp/opp.txt for more + information. + Example: power: power-controller@12340000 { @@ -120,4 +126,63 @@ The node above defines a typical PM domain consumer device, which is located inside a PM domain with index 0 of a power controller represented by a node with the label "power". +Optional properties: +- required-opp: This contains phandle to an OPP node in another device's OPP + table. It may contain an array of phandles, where each phandle points to an + OPP of a different device. It should not contain multiple phandles to the OPP + nodes in the same OPP table. This specifies the minimum required OPP of the + device(s), whose OPP's phandle is present in this property, for the + functioning of the current device at the current OPP (where this property is + present). + +Example: +- OPP table for domain provider that provides two domains. + + domain0_opp_table: opp-table0 { + compatible = "operating-points-v2"; + + domain0_opp_0: opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <975000 970000 985000>; + }; + domain0_opp_1: opp-1100000000 { + opp-hz = /bits/ 64 <1100000000>; + opp-microvolt = <1000000 980000 1010000>; + }; + }; + + domain1_opp_table: opp-table1 { + compatible = "operating-points-v2"; + + domain1_opp_0: opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <975000 970000 985000>; + }; + domain1_opp_1: opp-1300000000 { + opp-hz = /bits/ 64 <1300000000>; + opp-microvolt = <1000000 980000 1010000>; + }; + }; + + power: power-controller@12340000 { + compatible = "foo,power-controller"; + reg = <0x12340000 0x1000>; + #power-domain-cells = <1>; + operating-points-v2 = <&domain0_opp_table>, <&domain1_opp_table>; + }; + + leaky-device0@12350000 { + compatible = "foo,i-leak-current"; + reg = <0x12350000 0x1000>; + power-domains = <&power 0>; + required-opp = <&domain0_opp_0>; + }; + + leaky-device1@12350000 { + compatible = "foo,i-leak-current"; + reg = <0x12350000 0x1000>; + power-domains = <&power 1>; + required-opp = <&domain1_opp_1>; + }; + [1]. Documentation/devicetree/bindings/power/domain-idle-state.txt diff --git a/Documentation/devicetree/bindings/power/reset/imx-snvs-poweroff.txt b/Documentation/devicetree/bindings/power/reset/imx-snvs-poweroff.txt deleted file mode 100644 index 1b81fcd9fb72..000000000000 --- a/Documentation/devicetree/bindings/power/reset/imx-snvs-poweroff.txt +++ /dev/null @@ -1,23 +0,0 @@ -i.mx6 Poweroff Driver - -SNVS_LPCR in SNVS module can power off the whole system by pull -PMIC_ON_REQ low if PMIC_ON_REQ is connected with external PMIC. -If you don't want to use PMIC_ON_REQ as power on/off control, -please set status='disabled' to disable this driver. - -Required Properties: --compatible: "fsl,sec-v4.0-poweroff" --reg: Specifies the physical address of the SNVS_LPCR register - -Example: - snvs@20cc000 { - compatible = "fsl,sec-v4.0-mon", "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0 0x020cc000 0x4000>; - ..... - snvs_poweroff: snvs-poweroff@38 { - compatible = "fsl,sec-v4.0-poweroff"; - reg = <0x38 0x4>; - }; - } diff --git a/Documentation/devicetree/bindings/power/supply/bq27xxx.txt b/Documentation/devicetree/bindings/power/supply/bq27xxx.txt index 6858e1a804ad..615c1cb6889f 100644 --- a/Documentation/devicetree/bindings/power/supply/bq27xxx.txt +++ b/Documentation/devicetree/bindings/power/supply/bq27xxx.txt @@ -15,6 +15,7 @@ Required properties: * "ti,bq27520g2" - BQ27520-g2 * "ti,bq27520g3" - BQ27520-g3 * "ti,bq27520g4" - BQ27520-g4 + * "ti,bq27521" - BQ27521 * "ti,bq27530" - BQ27530 * "ti,bq27531" - BQ27531 * "ti,bq27541" - BQ27541 diff --git a/Documentation/devicetree/bindings/power/ti-smartreflex.txt b/Documentation/devicetree/bindings/power/ti-smartreflex.txt index 9780957c9115..21ef14d6af12 100644 --- a/Documentation/devicetree/bindings/power/ti-smartreflex.txt +++ b/Documentation/devicetree/bindings/power/ti-smartreflex.txt @@ -7,7 +7,7 @@ Required properties: compatible: Shall be one of the following: "ti,omap3-smartreflex-core" - "ti,omap3-smartreflex-iva" + "ti,omap3-smartreflex-mpu-iva" "ti,omap4-smartreflex-core" "ti,omap4-smartreflex-mpu" "ti,omap4-smartreflex-iva" diff --git a/Documentation/devicetree/bindings/powerpc/fsl/interlaken-lac.txt b/Documentation/devicetree/bindings/powerpc/fsl/interlaken-lac.txt index 641bc13983e1..ed6a414b2e10 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/interlaken-lac.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/interlaken-lac.txt @@ -223,37 +223,37 @@ lac-portals { reg = <0x9000 0x1000>; }; - lportal10: lac-portal@A000 { + lportal10: lac-portal@a000 { compatible = "fsl,interlaken-lac-portal-v1.0"; fsl,liodn = <0x20E>; reg = <0xA000 0x1000>; }; - lportal11: lac-portal@B000 { + lportal11: lac-portal@b000 { compatible = "fsl,interlaken-lac-portal-v1.0"; fsl,liodn = <0x20F>; reg = <0xB000 0x1000>; }; - lportal12: lac-portal@C000 { + lportal12: lac-portal@c000 { compatible = "fsl,interlaken-lac-portal-v1.0"; fsl,liodn = <0x210>; reg = <0xC000 0x1000>; }; - lportal13: lac-portal@D000 { + lportal13: lac-portal@d000 { compatible = "fsl,interlaken-lac-portal-v1.0"; fsl,liodn = <0x211>; reg = <0xD000 0x1000>; }; - lportal14: lac-portal@E000 { + lportal14: lac-portal@e000 { compatible = "fsl,interlaken-lac-portal-v1.0"; fsl,liodn = <0x212>; reg = <0xE000 0x1000>; }; - lportal15: lac-portal@F000 { + lportal15: lac-portal@f000 { compatible = "fsl,interlaken-lac-portal-v1.0"; fsl,liodn = <0x213>; reg = <0xF000 0x1000>; diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpc5200.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpc5200.txt index 4ccb2cd5df94..d096cf461d81 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/mpc5200.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/mpc5200.txt @@ -195,4 +195,4 @@ External interrupts: fsl,mpc5200-mscan nodes ----------------------- -See file can.txt in this directory. +See file Documentation/devicetree/bindings/powerpc/fsl/mpc5200.txt diff --git a/Documentation/devicetree/bindings/pwm/pwm-meson.txt b/Documentation/devicetree/bindings/pwm/pwm-meson.txt index 1ee81321c35e..1fa3f7182133 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-meson.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-meson.txt @@ -5,6 +5,8 @@ Required properties: - compatible: Shall contain "amlogic,meson8b-pwm" or "amlogic,meson-gxbb-pwm" or "amlogic,meson-gxbb-ao-pwm" + or "amlogic,meson-axg-ee-pwm" + or "amlogic,meson-axg-ao-pwm" - #pwm-cells: Should be 3. See pwm.txt in this directory for a description of the cells format. diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index 3cbf56ce66ea..2babe15b618d 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -42,8 +42,16 @@ Optional properties: - regulator-state-[mem/disk] node has following common properties: - regulator-on-in-suspend: regulator should be on in suspend state. - regulator-off-in-suspend: regulator should be off in suspend state. - - regulator-suspend-microvolt: regulator should be set to this voltage - in suspend. + - regulator-suspend-min-microvolt: minimum voltage may be set in + suspend state. + - regulator-suspend-max-microvolt: maximum voltage may be set in + suspend state. + - regulator-suspend-microvolt: the default voltage which regulator + would be set in suspend. This property is now deprecated, instead + setting voltage for suspend mode via the API which regulator + driver provides is recommended. + - regulator-changeable-in-suspend: whether the default voltage and + the regulator on/off in suspend can be changed in runtime. - regulator-mode: operating mode in the given suspend state. The set of possible operating modes depends on the capabilities of every hardware so the valid modes are documented on each regulator diff --git a/Documentation/devicetree/bindings/regulator/sprd,sc2731-regulator.txt b/Documentation/devicetree/bindings/regulator/sprd,sc2731-regulator.txt new file mode 100644 index 000000000000..63dc07877cd6 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/sprd,sc2731-regulator.txt @@ -0,0 +1,43 @@ +Spreadtrum SC2731 Voltage regulators + +The SC2731 integrates low-voltage and low quiescent current DCDC/LDO. +14 LDO and 3 DCDCs are designed for external use. All DCDCs/LDOs have +their own bypass (power-down) control signals. External tantalum or MLCC +ceramic capacitors are recommended to use with these LDOs. + +Required properties: + - compatible: should be "sprd,sc27xx-regulator". + +List of regulators provided by this controller. It is named according to +its regulator type, BUCK_ and LDO_. The definition for each +of these nodes is defined using the standard binding for regulators at +Documentation/devicetree/bindings/regulator/regulator.txt. + +The valid names for regulators are: +BUCK: + BUCK_CPU0, BUCK_CPU1, BUCK_RF +LDO: + LDO_CAMA0, LDO_CAMA1, LDO_CAMMOT, LDO_VLDO, LDO_EMMCCORE, LDO_SDCORE, + LDO_SDIO, LDO_WIFIPA, LDO_USB33, LDO_CAMD0, LDO_CAMD1, LDO_CON, + LDO_CAMIO, LDO_SRAM + +Example: + regulators { + compatible = "sprd,sc27xx-regulator"; + + vddarm0: BUCK_CPU0 { + regulator-name = "vddarm0"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1996875>; + regulator-ramp-delay = <25000>; + regulator-always-on; + }; + + vddcama0: LDO_CAMA0 { + regulator-name = "vddcama0"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3750000>; + regulator-enable-ramp-delay = <100>; + }; + ... + }; diff --git a/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt b/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt index 3944ee3e731e..5ddb8500a929 100644 --- a/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt +++ b/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt @@ -10,7 +10,7 @@ Required properties: - clocks: Must contain an entry for peripheral clock. Example: - vrefbuf: regulator@58003C00 { + vrefbuf: regulator@58003c00 { compatible = "st,stm32-vrefbuf"; reg = <0x58003C00 0x8>; clocks = <&rcc VREF_CK>; diff --git a/Documentation/devicetree/bindings/reset/amlogic,meson-reset.txt b/Documentation/devicetree/bindings/reset/amlogic,meson-reset.txt index e746b631793a..28ef6c295c76 100644 --- a/Documentation/devicetree/bindings/reset/amlogic,meson-reset.txt +++ b/Documentation/devicetree/bindings/reset/amlogic,meson-reset.txt @@ -5,7 +5,8 @@ Please also refer to reset.txt in this directory for common reset controller binding usage. Required properties: -- compatible: Should be "amlogic,meson8b-reset" or "amlogic,meson-gxbb-reset" +- compatible: Should be "amlogic,meson8b-reset", "amlogic,meson-gxbb-reset" or + "amlogic,meson-axg-reset". - reg: should contain the register address base - #reset-cells: 1, see below diff --git a/Documentation/devicetree/bindings/rng/brcm,bcm2835.txt b/Documentation/devicetree/bindings/rng/brcm,bcm2835.txt index 26542690b578..627b29531a32 100644 --- a/Documentation/devicetree/bindings/rng/brcm,bcm2835.txt +++ b/Documentation/devicetree/bindings/rng/brcm,bcm2835.txt @@ -1,11 +1,19 @@ -BCM2835 Random number generator +BCM2835/6368 Random number generator Required properties: -- compatible : should be "brcm,bcm2835-rng" or "brcm,bcm-nsp-rng" or - "brcm,bcm5301x-rng" +- compatible : should be one of + "brcm,bcm2835-rng" + "brcm,bcm-nsp-rng" + "brcm,bcm5301x-rng" or + "brcm,bcm6368-rng" - reg : Specifies base physical address and size of the registers. +Optional properties: + +- clocks : phandle to clock-controller plus clock-specifier pair +- clock-names : "ipsec" as a clock name + Example: rng { @@ -17,3 +25,11 @@ rng@18033000 { compatible = "brcm,bcm-nsp-rng"; reg = <0x18033000 0x14>; }; + +random: rng@10004180 { + compatible = "brcm,bcm6368-rng"; + reg = <0x10004180 0x14>; + + clocks = <&periph_clk 18>; + clock-names = "ipsec"; +}; diff --git a/Documentation/devicetree/bindings/rng/brcm,bcm6368.txt b/Documentation/devicetree/bindings/rng/brcm,bcm6368.txt deleted file mode 100644 index 4b5ac600bfbd..000000000000 --- a/Documentation/devicetree/bindings/rng/brcm,bcm6368.txt +++ /dev/null @@ -1,17 +0,0 @@ -BCM6368 Random number generator - -Required properties: - -- compatible : should be "brcm,bcm6368-rng" -- reg : Specifies base physical address and size of the registers -- clocks : phandle to clock-controller plus clock-specifier pair -- clock-names : "ipsec" as a clock name - -Example: - random: rng@10004180 { - compatible = "brcm,bcm6368-rng"; - reg = <0x10004180 0x14>; - - clocks = <&periph_clk 18>; - clock-names = "ipsec"; - }; diff --git a/Documentation/devicetree/bindings/rtc/rtc-mxc_v2.txt b/Documentation/devicetree/bindings/rtc/rtc-mxc_v2.txt new file mode 100644 index 000000000000..79d7e87b0d91 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/rtc-mxc_v2.txt @@ -0,0 +1,17 @@ +* i.MX53 Secure Real Time Clock (SRTC) + +Required properties: +- compatible: should be: "fsl,imx53-rtc" +- reg: physical base address of the controller and length of memory mapped + region. +- clocks: should contain the phandle for the rtc clock +- interrupts: rtc alarm interrupt + +Example: + +rtc@53fa4000 { + compatible = "fsl,imx53-rtc"; + reg = <0x53fa4000 0x4000>; + interrupts = <24>; + clocks = <&clks IMX5_CLK_SRTC_GATE>; +}; diff --git a/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt b/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt index b6a869f97715..df3bef7998fa 100644 --- a/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt +++ b/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt @@ -8,7 +8,10 @@ Main node required properties: (b) "hisilicon,hip06-sas-v2" for v2 hw in hip06 chipset (c) "hisilicon,hip07-sas-v2" for v2 hw in hip07 chipset - sas-addr : array of 8 bytes for host SAS address - - reg : Address and length of the SAS register + - reg : Contains two regions. The first is the address and length of the SAS + register. The second is the address and length of CPLD register for + SGPIO control. The second is optional, and should be set only when + we use a CPLD for directly attached disk LED control. - hisilicon,sas-syscon: phandle of syscon used for sas control - ctrl-reset-reg : offset to controller reset register in ctrl reg - ctrl-reset-sts-reg : offset to controller reset status register in ctrl reg diff --git a/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt b/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt index 860a9559839a..afcfbc34e243 100644 --- a/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt +++ b/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt @@ -6,10 +6,10 @@ Required properties: - interrupts : Should contain uart interrupt Optional properties: -- fsl,irda-mode : Indicate the uart supports irda mode - fsl,dte-mode : Indicate the uart works in DTE mode. The uart works in DCE mode by default. -- rs485-rts-delay, rs485-rx-during-tx, linux,rs485-enabled-at-boot-time: see rs485.txt +- rs485-rts-delay, rs485-rts-active-low, rs485-rx-during-tx, + linux,rs485-enabled-at-boot-time: see rs485.txt Please check Documentation/devicetree/bindings/serial/serial.txt for the complete list of generic properties. diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt index 59567b51cf09..6bd3f2e93d61 100644 --- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt +++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt @@ -16,7 +16,8 @@ Required properties: Optional properties: - dmas: A list of two dma specifiers, one for each entry in dma-names. - dma-names: should contain "tx" and "rx". -- rs485-rts-delay, rs485-rx-during-tx, linux,rs485-enabled-at-boot-time: see rs485.txt +- rs485-rts-delay, rs485-rts-active-low, rs485-rx-during-tx, + linux,rs485-enabled-at-boot-time: see rs485.txt Note: Optional properties for DMA support. Write them both or both not. diff --git a/Documentation/devicetree/bindings/serial/ingenic,uart.txt b/Documentation/devicetree/bindings/serial/ingenic,uart.txt index 02cb7fe59cb7..c3c6406d5cfe 100644 --- a/Documentation/devicetree/bindings/serial/ingenic,uart.txt +++ b/Documentation/devicetree/bindings/serial/ingenic,uart.txt @@ -1,8 +1,12 @@ * Ingenic SoC UART Required properties: -- compatible : "ingenic,jz4740-uart", "ingenic,jz4760-uart", - "ingenic,jz4775-uart" or "ingenic,jz4780-uart" +- compatible : One of: + - "ingenic,jz4740-uart", + - "ingenic,jz4760-uart", + - "ingenic,jz4770-uart", + - "ingenic,jz4775-uart", + - "ingenic,jz4780-uart". - reg : offset and length of the register set for the device. - interrupts : should contain uart interrupt. - clocks : phandles to the module & baud clocks. diff --git a/Documentation/devicetree/bindings/serial/lantiq_asc.txt b/Documentation/devicetree/bindings/serial/lantiq_asc.txt index 5b78591aaa46..3acbd309ab9d 100644 --- a/Documentation/devicetree/bindings/serial/lantiq_asc.txt +++ b/Documentation/devicetree/bindings/serial/lantiq_asc.txt @@ -8,7 +8,7 @@ Required properties: Example: -asc1: serial@E100C00 { +asc1: serial@e100c00 { compatible = "lantiq,asc"; reg = <0xE100C00 0x400>; interrupt-parent = <&icu0>; diff --git a/Documentation/devicetree/bindings/serial/maxim,max310x.txt b/Documentation/devicetree/bindings/serial/maxim,max310x.txt index 83a919c241b0..823f77dd7978 100644 --- a/Documentation/devicetree/bindings/serial/maxim,max310x.txt +++ b/Documentation/devicetree/bindings/serial/maxim,max310x.txt @@ -24,13 +24,27 @@ Optional properties: 1 = active low. Example: + +/ { + clocks { + spi_uart_clk: osc_max14830 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <3686400>; + }; + + }; +}; + +&spi0 { max14830: max14830@0 { compatible = "maxim,max14830"; reg = <0>; - clocks = <&clk20m>; + clocks = <&spi_uart_clk>; clock-names = "osc"; interrupt-parent = <&gpio3>; - interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; gpio-controller; #gpio-cells = <2>; }; +}; diff --git a/Documentation/devicetree/bindings/serial/mvebu-uart.txt b/Documentation/devicetree/bindings/serial/mvebu-uart.txt index d37fabe17bd1..2ae2fee7e023 100644 --- a/Documentation/devicetree/bindings/serial/mvebu-uart.txt +++ b/Documentation/devicetree/bindings/serial/mvebu-uart.txt @@ -1,13 +1,53 @@ -* Marvell UART : Non standard UART used in some of Marvell EBU SoCs (e.g., Armada-3700) +* Marvell UART : Non standard UART used in some of Marvell EBU SoCs + e.g., Armada-3700. Required properties: -- compatible: "marvell,armada-3700-uart" +- compatible: + - "marvell,armada-3700-uart" for the standard variant of the UART + (32 bytes FIFO, no DMA, level interrupts, 8-bit access to the + FIFO, baudrate limited to 230400). + - "marvell,armada-3700-uart-ext" for the extended variant of the + UART (128 bytes FIFO, DMA, front interrupts, 8-bit or 32-bit + accesses to the FIFO, baudrate unlimited by the dividers). - reg: offset and length of the register set for the device. -- interrupts: device interrupt +- clocks: UART reference clock used to derive the baudrate. If no clock + is provided (possible only with the "marvell,armada-3700-uart" + compatible string for backward compatibility), it will only work + if the baudrate was initialized by the bootloader and no baudrate + change will then be possible. +- interrupts: + - Must contain three elements for the standard variant of the IP + (marvell,armada-3700-uart): "uart-sum", "uart-tx" and "uart-rx", + respectively the UART sum interrupt, the UART TX interrupt and + UART RX interrupt. A corresponding interrupt-names property must + be defined. + - Must contain two elements for the extended variant of the IP + (marvell,armada-3700-uart-ext): "uart-tx" and "uart-rx", + respectively the UART TX interrupt and the UART RX interrupt. A + corresponding interrupts-names property must be defined. + - For backward compatibility reasons, a single element interrupts + property is also supported for the standard variant of the IP, + containing only the UART sum interrupt. This form is deprecated + and should no longer be used. Example: - serial@12000 { + uart0: serial@12000 { compatible = "marvell,armada-3700-uart"; reg = <0x12000 0x200>; - interrupts = <43>; + clocks = <&xtalclk>; + interrupts = + , + , + ; + interrupt-names = "uart-sum", "uart-tx", "uart-rx"; + }; + + uart1: serial@12200 { + compatible = "marvell,armada-3700-uart-ext"; + reg = <0x12200 0x30>; + clocks = <&xtalclk>; + interrupts = + , + ; + interrupt-names = "uart-tx", "uart-rx"; }; diff --git a/Documentation/devicetree/bindings/serial/omap_serial.txt b/Documentation/devicetree/bindings/serial/omap_serial.txt index 43eac675f21f..4b0f05adb228 100644 --- a/Documentation/devicetree/bindings/serial/omap_serial.txt +++ b/Documentation/devicetree/bindings/serial/omap_serial.txt @@ -20,6 +20,7 @@ Optional properties: node and a DMA channel number. - dma-names : "rx" for receive channel, "tx" for transmit channel. - rs485-rts-delay, rs485-rx-during-tx, linux,rs485-enabled-at-boot-time: see rs485.txt +- rs485-rts-active-high: drive RTS high when sending (default is low). Example: diff --git a/Documentation/devicetree/bindings/serial/rs485.txt b/Documentation/devicetree/bindings/serial/rs485.txt index b8415936dfdb..b7c29f74ebb2 100644 --- a/Documentation/devicetree/bindings/serial/rs485.txt +++ b/Documentation/devicetree/bindings/serial/rs485.txt @@ -12,6 +12,7 @@ Optional properties: * b is the delay between end of data sent and rts signal in milliseconds it corresponds to the delay after sending data and actual release of the line. If this property is not specified, <0 0> is assumed. +- rs485-rts-active-low: drive RTS low when sending (default is high). - linux,rs485-enabled-at-boot-time: empty property telling to enable the rs485 feature at boot time. It can be disabled later with proper ioctl. - rs485-rx-during-tx: empty property that enables the receiving of data even diff --git a/Documentation/devicetree/bindings/siox/eckelmann,siox-gpio.txt b/Documentation/devicetree/bindings/siox/eckelmann,siox-gpio.txt new file mode 100644 index 000000000000..55259cf39c25 --- /dev/null +++ b/Documentation/devicetree/bindings/siox/eckelmann,siox-gpio.txt @@ -0,0 +1,19 @@ +Eckelmann SIOX GPIO bus + +Required properties: +- compatible : "eckelmann,siox-gpio" +- din-gpios, dout-gpios, dclk-gpios, dld-gpios: references gpios for the + corresponding bus signals. + +Examples: + + siox { + compatible = "eckelmann,siox-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_siox>; + + din-gpios = <&gpio6 11 0>; + dout-gpios = <&gpio6 8 0>; + dclk-gpios = <&gpio6 9 0>; + dld-gpios = <&gpio6 10 0>; + }; diff --git a/Documentation/devicetree/bindings/slimbus/bus.txt b/Documentation/devicetree/bindings/slimbus/bus.txt new file mode 100644 index 000000000000..52fa6426388c --- /dev/null +++ b/Documentation/devicetree/bindings/slimbus/bus.txt @@ -0,0 +1,50 @@ +SLIM(Serial Low Power Interchip Media Bus) bus + +SLIMbus is a 2-wire bus, and is used to communicate with peripheral +components like audio-codec. + +Required property for SLIMbus controller node: +- compatible - name of SLIMbus controller + +Child nodes: +Every SLIMbus controller node can contain zero or more child nodes +representing slave devices on the bus. Every SLIMbus slave device is +uniquely determined by the enumeration address containing 4 fields: +Manufacturer ID, Product code, Device index, and Instance value for +the device. +If child node is not present and it is instantiated after device +discovery (slave device reporting itself present). + +In some cases it may be necessary to describe non-probeable device +details such as non-standard ways of powering up a device. In +such cases, child nodes for those devices will be present as +slaves of the SLIMbus controller, as detailed below. + +Required property for SLIMbus child node if it is present: +- reg - Should be ('Device index', 'Instance ID') from SLIMbus + Enumeration Address. + Device Index Uniquely identifies multiple Devices within + a single Component. + Instance ID Is for the cases where multiple Devices of the + same type or Class are attached to the bus. + +- compatible -"slimMID,PID". The textual representation of Manufacturer ID, + Product Code, shall be in lower case hexadecimal with leading + zeroes suppressed + +SLIMbus example for Qualcomm's slimbus manager component: + + slim@28080000 { + compatible = "qcom,apq8064-slim", "qcom,slim"; + reg = <0x28080000 0x2000>, + interrupts = <0 33 0>; + clocks = <&lcc SLIMBUS_SRC>, <&lcc AUDIO_SLIMBUS_CLK>; + clock-names = "iface", "core"; + #address-cells = <2>; + #size-cell = <0>; + + codec: wcd9310@1,0{ + compatible = "slim217,60"; + reg = <1 0>; + }; + }; diff --git a/Documentation/devicetree/bindings/slimbus/slim-qcom-ctrl.txt b/Documentation/devicetree/bindings/slimbus/slim-qcom-ctrl.txt new file mode 100644 index 000000000000..922dcb8ff24a --- /dev/null +++ b/Documentation/devicetree/bindings/slimbus/slim-qcom-ctrl.txt @@ -0,0 +1,39 @@ +Qualcomm SLIMbus controller +This controller is used if applications processor driver controls SLIMbus +master component. + +Required properties: + + - #address-cells - refer to Documentation/devicetree/bindings/slimbus/bus.txt + - #size-cells - refer to Documentation/devicetree/bindings/slimbus/bus.txt + + - reg : Offset and length of the register region(s) for the device + - reg-names : Register region name(s) referenced in reg above + Required register resource entries are: + "ctrl": Physical address of controller register blocks + "slew": required for "qcom,apq8064-slim" SOC. + - compatible : should be "qcom,-slim" for SOC specific compatible + followed by "qcom,slim" for fallback. + - interrupts : Interrupt number used by this controller + - clocks : Interface and core clocks used by this SLIMbus controller + - clock-names : Required clock-name entries are: + "iface" : Interface clock for this controller + "core" : Interrupt for controller core's BAM + +Example: + + slim@28080000 { + compatible = "qcom,apq8064-slim", "qcom,slim"; + reg = <0x28080000 0x2000>, <0x80207C 4>; + reg-names = "ctrl", "slew"; + interrupts = <0 33 0>; + clocks = <&lcc SLIMBUS_SRC>, <&lcc AUDIO_SLIMBUS_CLK>; + clock-names = "iface", "core"; + #address-cells = <2>; + #size-cell = <0>; + + wcd9310: audio-codec@1,0{ + compatible = "slim217,60"; + reg = <1 0>; + }; + }; diff --git a/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt index 40056f7990f8..76bf45b893fa 100644 --- a/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt +++ b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt @@ -12,11 +12,13 @@ power/power_domain.txt. It provides the power domains defined in - include/dt-bindings/power/mt8173-power.h - include/dt-bindings/power/mt6797-power.h - include/dt-bindings/power/mt2701-power.h +- include/dt-bindings/power/mt2712-power.h - include/dt-bindings/power/mt7622-power.h Required properties: - compatible: Should be one of: - "mediatek,mt2701-scpsys" + - "mediatek,mt2712-scpsys" - "mediatek,mt6797-scpsys" - "mediatek,mt7622-scpsys" - "mediatek,mt8173-scpsys" @@ -27,6 +29,7 @@ Required properties: These are clocks which hardware needs to be enabled before enabling certain power domains. Required clocks for MT2701: "mm", "mfg", "ethif" + Required clocks for MT2712: "mm", "mfg", "venc", "jpgdec", "audio", "vdec" Required clocks for MT6797: "mm", "mfg", "vdec" Required clocks for MT7622: "hif_sel" Required clocks for MT8173: "mm", "mfg", "venc", "venc_lt" diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt index af9ca37221ce..a35af2dafdad 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt @@ -17,9 +17,15 @@ processor ID) and a string identifier. Value type: Definition: one entry specifying the smp2p notification interrupt -- qcom,ipc: +- mboxes: Usage: required Value type: + Definition: reference to the associated doorbell in APCS, as described + in mailbox/mailbox.txt + +- qcom,ipc: + Usage: required, unless mboxes is specified + Value type: Definition: three entries specifying the outgoing ipc bit used for signaling the remote end of the smp2p edge: - phandle to a syscon node representing the apcs registers diff --git a/Documentation/devicetree/bindings/soc/xilinx/xlnx,vcu.txt b/Documentation/devicetree/bindings/soc/xilinx/xlnx,vcu.txt new file mode 100644 index 000000000000..6786d6715df0 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/xilinx/xlnx,vcu.txt @@ -0,0 +1,31 @@ +LogicoreIP designed compatible with Xilinx ZYNQ family. +------------------------------------------------------- + +General concept +--------------- + +LogicoreIP design to provide the isolation between processing system +and programmable logic. Also provides the list of register set to configure +the frequency. + +Required properties: +- compatible: shall be one of: + "xlnx,vcu" + "xlnx,vcu-logicoreip-1.0" +- reg, reg-names: There are two sets of registers need to provide. + 1. vcu slcr + 2. Logicore + reg-names should contain name for the each register sequence. +- clocks: phandle for aclk and pll_ref clocksource +- clock-names: The identification string, "aclk", is always required for + the axi clock. "pll_ref" is required for pll. +Example: + + xlnx_vcu: vcu@a0040000 { + compatible = "xlnx,vcu-logicoreip-1.0"; + reg = <0x0 0xa0040000 0x0 0x1000>, + <0x0 0xa0041000 0x0 0x1000>; + reg-names = "vcu_slcr", "logicore"; + clocks = <&si570_1>, <&clkc 71>; + clock-names = "pll_ref", "aclk"; + }; diff --git a/Documentation/devicetree/bindings/sound/dmic.txt b/Documentation/devicetree/bindings/sound/dmic.txt index 54c8ef6498a8..f7bf65611453 100644 --- a/Documentation/devicetree/bindings/sound/dmic.txt +++ b/Documentation/devicetree/bindings/sound/dmic.txt @@ -7,10 +7,12 @@ Required properties: Optional properties: - dmicen-gpios: GPIO specifier for dmic to control start and stop + - num-channels: Number of microphones on this DAI Example node: dmic_codec: dmic@0 { compatible = "dmic-codec"; dmicen-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>; + num-channels = <1>; }; diff --git a/Documentation/devicetree/bindings/sound/img,i2s-out.txt b/Documentation/devicetree/bindings/sound/img,i2s-out.txt index 0159415b3338..6b0ee9b7e11b 100644 --- a/Documentation/devicetree/bindings/sound/img,i2s-out.txt +++ b/Documentation/devicetree/bindings/sound/img,i2s-out.txt @@ -35,7 +35,7 @@ Optional Properties: Example: -i2s_out: i2s-out@18100A00 { +i2s_out: i2s-out@18100a00 { compatible = "img,i2s-out"; reg = <0x18100A00 0x200>; interrupts = ; diff --git a/Documentation/devicetree/bindings/sound/img,parallel-out.txt b/Documentation/devicetree/bindings/sound/img,parallel-out.txt index a3015d2a06e0..37a3f94cc126 100644 --- a/Documentation/devicetree/bindings/sound/img,parallel-out.txt +++ b/Documentation/devicetree/bindings/sound/img,parallel-out.txt @@ -29,7 +29,7 @@ Optional Properties: Example: -parallel_out: parallel-out@18100C00 { +parallel_out: parallel-out@18100c00 { compatible = "img,parallel-out"; reg = <0x18100C00 0x100>; interrupts = ; diff --git a/Documentation/devicetree/bindings/sound/img,spdif-in.txt b/Documentation/devicetree/bindings/sound/img,spdif-in.txt index aab9a81f7e13..f7ea8c87bf34 100644 --- a/Documentation/devicetree/bindings/sound/img,spdif-in.txt +++ b/Documentation/devicetree/bindings/sound/img,spdif-in.txt @@ -29,7 +29,7 @@ Optional Properties: Example: -spdif_in: spdif-in@18100E00 { +spdif_in: spdif-in@18100e00 { compatible = "img,spdif-in"; reg = <0x18100E00 0x100>; interrupts = ; diff --git a/Documentation/devicetree/bindings/sound/img,spdif-out.txt b/Documentation/devicetree/bindings/sound/img,spdif-out.txt index 470a5191e101..413ed8b01870 100644 --- a/Documentation/devicetree/bindings/sound/img,spdif-out.txt +++ b/Documentation/devicetree/bindings/sound/img,spdif-out.txt @@ -29,7 +29,7 @@ Optional Properties: Example: -spdif_out: spdif-out@18100D00 { +spdif_out: spdif-out@18100d00 { compatible = "img,spdif-out"; reg = <0x18100D00 0x100>; interrupts = ; diff --git a/Documentation/devicetree/bindings/sound/max98373.txt b/Documentation/devicetree/bindings/sound/max98373.txt new file mode 100644 index 000000000000..456cb1c59353 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/max98373.txt @@ -0,0 +1,40 @@ +Maxim Integrated MAX98373 Speaker Amplifier + +This device supports I2C. + +Required properties: + + - compatible : "maxim,max98373" + + - reg : the I2C address of the device. + +Optional properties: + + - maxim,vmon-slot-no : slot number used to send voltage information + or in inteleave mode this will be used as + interleave slot. + slot range : 0 ~ 15, Default : 0 + + - maxim,imon-slot-no : slot number used to send current information + slot range : 0 ~ 15, Default : 0 + + - maxim,spkfb-slot-no : slot number used to send speaker feedback information + slot range : 0 ~ 15, Default : 0 + + - maxim,interleave-mode : For cases where a single combined channel + for the I/V sense data is not sufficient, the device can also be configured + to share a single data output channel on alternating frames. + In this configuration, the current and voltage data will be frame interleaved + on a single output channel. + Boolean, define to enable the interleave mode, Default : false + +Example: + +codec: max98373@31 { + compatible = "maxim,max98373"; + reg = <0x31>; + maxim,vmon-slot-no = <0>; + maxim,imon-slot-no = <1>; + maxim,spkfb-slot-no = <2>; + maxim,interleave-mode; +}; diff --git a/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt b/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt index 77a57f84bed4..6df87b97f7cb 100644 --- a/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt +++ b/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt @@ -2,153 +2,143 @@ Mediatek AFE PCM controller for mt2701 Required properties: - compatible = "mediatek,mt2701-audio"; -- reg: register location and size - interrupts: should contain AFE and ASYS interrupts - interrupt-names: should be "afe" and "asys" - power-domains: should define the power domain +- clocks: Must contain an entry for each entry in clock-names + See ../clocks/clock-bindings.txt for details - clock-names: should have these clock names: "infra_sys_audio_clk", "top_audio_mux1_sel", "top_audio_mux2_sel", - "top_audio_mux1_div", - "top_audio_mux2_div", - "top_audio_48k_timing", - "top_audio_44k_timing", - "top_audpll_mux_sel", - "top_apll_sel", - "top_aud1_pll_98M", - "top_aud2_pll_90M", - "top_hadds2_pll_98M", - "top_hadds2_pll_294M", - "top_audpll", - "top_audpll_d4", - "top_audpll_d8", - "top_audpll_d16", - "top_audpll_d24", - "top_audintbus_sel", - "clk_26m", - "top_syspll1_d4", - "top_aud_k1_src_sel", - "top_aud_k2_src_sel", - "top_aud_k3_src_sel", - "top_aud_k4_src_sel", - "top_aud_k5_src_sel", - "top_aud_k6_src_sel", - "top_aud_k1_src_div", - "top_aud_k2_src_div", - "top_aud_k3_src_div", - "top_aud_k4_src_div", - "top_aud_k5_src_div", - "top_aud_k6_src_div", - "top_aud_i2s1_mclk", - "top_aud_i2s2_mclk", - "top_aud_i2s3_mclk", - "top_aud_i2s4_mclk", - "top_aud_i2s5_mclk", - "top_aud_i2s6_mclk", - "top_asm_m_sel", - "top_asm_h_sel", - "top_univpll2_d4", - "top_univpll2_d2", - "top_syspll_d5"; + "top_audio_a1sys_hp", + "top_audio_a2sys_hp", + "i2s0_src_sel", + "i2s1_src_sel", + "i2s2_src_sel", + "i2s3_src_sel", + "i2s0_src_div", + "i2s1_src_div", + "i2s2_src_div", + "i2s3_src_div", + "i2s0_mclk_en", + "i2s1_mclk_en", + "i2s2_mclk_en", + "i2s3_mclk_en", + "i2so0_hop_ck", + "i2so1_hop_ck", + "i2so2_hop_ck", + "i2so3_hop_ck", + "i2si0_hop_ck", + "i2si1_hop_ck", + "i2si2_hop_ck", + "i2si3_hop_ck", + "asrc0_out_ck", + "asrc1_out_ck", + "asrc2_out_ck", + "asrc3_out_ck", + "audio_afe_pd", + "audio_afe_conn_pd", + "audio_a1sys_pd", + "audio_a2sys_pd", + "audio_mrgif_pd"; +- assigned-clocks: list of input clocks and dividers for the audio system. + See ../clocks/clock-bindings.txt for details. +- assigned-clocks-parents: parent of input clocks of assigned clocks. +- assigned-clock-rates: list of clock frequencies of assigned clocks. + +Must be a subnode of MediaTek audsys device tree node. +See ../arm/mediatek/mediatek,audsys.txt for details about the parent node. Example: - afe: mt2701-afe-pcm@11220000 { - compatible = "mediatek,mt2701-audio"; - reg = <0 0x11220000 0 0x2000>, - <0 0x112A0000 0 0x20000>; - interrupts = , - ; - interrupt-names = "afe", "asys"; - power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>; - clocks = <&infracfg CLK_INFRA_AUDIO>, - <&topckgen CLK_TOP_AUD_MUX1_SEL>, - <&topckgen CLK_TOP_AUD_MUX2_SEL>, - <&topckgen CLK_TOP_AUD_MUX1_DIV>, - <&topckgen CLK_TOP_AUD_MUX2_DIV>, - <&topckgen CLK_TOP_AUD_48K_TIMING>, - <&topckgen CLK_TOP_AUD_44K_TIMING>, - <&topckgen CLK_TOP_AUDPLL_MUX_SEL>, - <&topckgen CLK_TOP_APLL_SEL>, - <&topckgen CLK_TOP_AUD1PLL_98M>, - <&topckgen CLK_TOP_AUD2PLL_90M>, - <&topckgen CLK_TOP_HADDS2PLL_98M>, - <&topckgen CLK_TOP_HADDS2PLL_294M>, - <&topckgen CLK_TOP_AUDPLL>, - <&topckgen CLK_TOP_AUDPLL_D4>, - <&topckgen CLK_TOP_AUDPLL_D8>, - <&topckgen CLK_TOP_AUDPLL_D16>, - <&topckgen CLK_TOP_AUDPLL_D24>, - <&topckgen CLK_TOP_AUDINTBUS_SEL>, - <&clk26m>, - <&topckgen CLK_TOP_SYSPLL1_D4>, - <&topckgen CLK_TOP_AUD_K1_SRC_SEL>, - <&topckgen CLK_TOP_AUD_K2_SRC_SEL>, - <&topckgen CLK_TOP_AUD_K3_SRC_SEL>, - <&topckgen CLK_TOP_AUD_K4_SRC_SEL>, - <&topckgen CLK_TOP_AUD_K5_SRC_SEL>, - <&topckgen CLK_TOP_AUD_K6_SRC_SEL>, - <&topckgen CLK_TOP_AUD_K1_SRC_DIV>, - <&topckgen CLK_TOP_AUD_K2_SRC_DIV>, - <&topckgen CLK_TOP_AUD_K3_SRC_DIV>, - <&topckgen CLK_TOP_AUD_K4_SRC_DIV>, - <&topckgen CLK_TOP_AUD_K5_SRC_DIV>, - <&topckgen CLK_TOP_AUD_K6_SRC_DIV>, - <&topckgen CLK_TOP_AUD_I2S1_MCLK>, - <&topckgen CLK_TOP_AUD_I2S2_MCLK>, - <&topckgen CLK_TOP_AUD_I2S3_MCLK>, - <&topckgen CLK_TOP_AUD_I2S4_MCLK>, - <&topckgen CLK_TOP_AUD_I2S5_MCLK>, - <&topckgen CLK_TOP_AUD_I2S6_MCLK>, - <&topckgen CLK_TOP_ASM_M_SEL>, - <&topckgen CLK_TOP_ASM_H_SEL>, - <&topckgen CLK_TOP_UNIVPLL2_D4>, - <&topckgen CLK_TOP_UNIVPLL2_D2>, - <&topckgen CLK_TOP_SYSPLL_D5>; + audsys: audio-subsystem@11220000 { + compatible = "mediatek,mt2701-audsys", "syscon", "simple-mfd"; + ... - clock-names = "infra_sys_audio_clk", - "top_audio_mux1_sel", - "top_audio_mux2_sel", - "top_audio_mux1_div", - "top_audio_mux2_div", - "top_audio_48k_timing", - "top_audio_44k_timing", - "top_audpll_mux_sel", - "top_apll_sel", - "top_aud1_pll_98M", - "top_aud2_pll_90M", - "top_hadds2_pll_98M", - "top_hadds2_pll_294M", - "top_audpll", - "top_audpll_d4", - "top_audpll_d8", - "top_audpll_d16", - "top_audpll_d24", - "top_audintbus_sel", - "clk_26m", - "top_syspll1_d4", - "top_aud_k1_src_sel", - "top_aud_k2_src_sel", - "top_aud_k3_src_sel", - "top_aud_k4_src_sel", - "top_aud_k5_src_sel", - "top_aud_k6_src_sel", - "top_aud_k1_src_div", - "top_aud_k2_src_div", - "top_aud_k3_src_div", - "top_aud_k4_src_div", - "top_aud_k5_src_div", - "top_aud_k6_src_div", - "top_aud_i2s1_mclk", - "top_aud_i2s2_mclk", - "top_aud_i2s3_mclk", - "top_aud_i2s4_mclk", - "top_aud_i2s5_mclk", - "top_aud_i2s6_mclk", - "top_asm_m_sel", - "top_asm_h_sel", - "top_univpll2_d4", - "top_univpll2_d2", - "top_syspll_d5"; + afe: audio-controller { + compatible = "mediatek,mt2701-audio"; + interrupts = , + ; + interrupt-names = "afe", "asys"; + power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>; + + clocks = <&infracfg CLK_INFRA_AUDIO>, + <&topckgen CLK_TOP_AUD_MUX1_SEL>, + <&topckgen CLK_TOP_AUD_MUX2_SEL>, + <&topckgen CLK_TOP_AUD_48K_TIMING>, + <&topckgen CLK_TOP_AUD_44K_TIMING>, + <&topckgen CLK_TOP_AUD_K1_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K2_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K3_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K4_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K1_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K2_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K3_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K4_SRC_DIV>, + <&topckgen CLK_TOP_AUD_I2S1_MCLK>, + <&topckgen CLK_TOP_AUD_I2S2_MCLK>, + <&topckgen CLK_TOP_AUD_I2S3_MCLK>, + <&topckgen CLK_TOP_AUD_I2S4_MCLK>, + <&audsys CLK_AUD_I2SO1>, + <&audsys CLK_AUD_I2SO2>, + <&audsys CLK_AUD_I2SO3>, + <&audsys CLK_AUD_I2SO4>, + <&audsys CLK_AUD_I2SIN1>, + <&audsys CLK_AUD_I2SIN2>, + <&audsys CLK_AUD_I2SIN3>, + <&audsys CLK_AUD_I2SIN4>, + <&audsys CLK_AUD_ASRCO1>, + <&audsys CLK_AUD_ASRCO2>, + <&audsys CLK_AUD_ASRCO3>, + <&audsys CLK_AUD_ASRCO4>, + <&audsys CLK_AUD_AFE>, + <&audsys CLK_AUD_AFE_CONN>, + <&audsys CLK_AUD_A1SYS>, + <&audsys CLK_AUD_A2SYS>, + <&audsys CLK_AUD_AFE_MRGIF>; + + clock-names = "infra_sys_audio_clk", + "top_audio_mux1_sel", + "top_audio_mux2_sel", + "top_audio_a1sys_hp", + "top_audio_a2sys_hp", + "i2s0_src_sel", + "i2s1_src_sel", + "i2s2_src_sel", + "i2s3_src_sel", + "i2s0_src_div", + "i2s1_src_div", + "i2s2_src_div", + "i2s3_src_div", + "i2s0_mclk_en", + "i2s1_mclk_en", + "i2s2_mclk_en", + "i2s3_mclk_en", + "i2so0_hop_ck", + "i2so1_hop_ck", + "i2so2_hop_ck", + "i2so3_hop_ck", + "i2si0_hop_ck", + "i2si1_hop_ck", + "i2si2_hop_ck", + "i2si3_hop_ck", + "asrc0_out_ck", + "asrc1_out_ck", + "asrc2_out_ck", + "asrc3_out_ck", + "audio_afe_pd", + "audio_afe_conn_pd", + "audio_a1sys_pd", + "audio_a2sys_pd", + "audio_mrgif_pd"; + + assigned-clocks = <&topckgen CLK_TOP_AUD_MUX1_SEL>, + <&topckgen CLK_TOP_AUD_MUX2_SEL>, + <&topckgen CLK_TOP_AUD_MUX1_DIV>, + <&topckgen CLK_TOP_AUD_MUX2_DIV>; + assigned-clock-parents = <&topckgen CLK_TOP_AUD1PLL_98M>, + <&topckgen CLK_TOP_AUD2PLL_90M>; + assigned-clock-rates = <0>, <0>, <49152000>, <45158400>; + }; }; diff --git a/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt index 601c518eddaa..4eb980bd0287 100644 --- a/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt +++ b/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt @@ -1,10 +1,31 @@ * Freescale MXS audio complex with SGTL5000 codec Required properties: -- compatible: "fsl,mxs-audio-sgtl5000" -- model: The user-visible name of this sound complex -- saif-controllers: The phandle list of the MXS SAIF controller -- audio-codec: The phandle of the SGTL5000 audio codec +- compatible : "fsl,mxs-audio-sgtl5000" +- model : The user-visible name of this sound complex +- saif-controllers : The phandle list of the MXS SAIF controller +- audio-codec : The phandle of the SGTL5000 audio codec +- audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. Valid names could be power supplies, SGTL5000 + pins, and the jacks on the board: + + Power supplies: + * Mic Bias + + SGTL5000 pins: + * MIC_IN + * LINE_IN + * HP_OUT + * LINE_OUT + + Board connectors: + * Mic Jack + * Line In Jack + * Headphone Jack + * Line Out Jack + * Ext Spk Example: @@ -14,4 +35,8 @@ sound { model = "imx28-evk-sgtl5000"; saif-controllers = <&saif0 &saif1>; audio-codec = <&sgtl5000>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; }; diff --git a/Documentation/devicetree/bindings/sound/nau8825.txt b/Documentation/devicetree/bindings/sound/nau8825.txt index 2f5e973285a6..d16d96839bcb 100644 --- a/Documentation/devicetree/bindings/sound/nau8825.txt +++ b/Documentation/devicetree/bindings/sound/nau8825.txt @@ -69,7 +69,7 @@ Optional properties: - nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms - nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms - - nuvoton,crosstalk-bypass: make crosstalk function bypass if set. + - nuvoton,crosstalk-enable: make crosstalk function enable if set. - clocks: list of phandle and clock specifier pairs according to common clock bindings for the clocks described in clock-names @@ -98,7 +98,7 @@ Example: nuvoton,short-key-debounce = <2>; nuvoton,jack-insert-debounce = <7>; nuvoton,jack-eject-debounce = <7>; - nuvoton,crosstalk-bypass; + nuvoton,crosstalk-enable; clock-names = "mclk"; clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_2>; diff --git a/Documentation/devicetree/bindings/sound/pcm186x.txt b/Documentation/devicetree/bindings/sound/pcm186x.txt new file mode 100644 index 000000000000..1087f4855980 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/pcm186x.txt @@ -0,0 +1,42 @@ +Texas Instruments PCM186x Universal Audio ADC + +These devices support both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : "ti,pcm1862", + "ti,pcm1863", + "ti,pcm1864", + "ti,pcm1865" + + - reg : The I2C address of the device for I2C, the chip select + number for SPI. + + - avdd-supply: Analog core power supply (3.3v) + - dvdd-supply: Digital core power supply + - iovdd-supply: Digital IO power supply + See regulator/regulator.txt for more information + +CODEC input pins: + * VINL1 + * VINR1 + * VINL2 + * VINR2 + * VINL3 + * VINR3 + * VINL4 + * VINR4 + +The pins can be used in referring sound node's audio-routing property. + +Example: + + pcm186x: audio-codec@4a { + compatible = "ti,pcm1865"; + reg = <0x4a>; + + avdd-supply = <®_3v3_analog>; + dvdd-supply = <®_3v3>; + iovdd-supply = <®_1v8>; + }; diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 085bec364caf..5bed9a595772 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -4,7 +4,7 @@ Renesas R-Car sound * Modules ============================================= -Renesas R-Car sound is constructed from below modules +Renesas R-Car and RZ/G sound is constructed from below modules (for Gen2 or later) SCU : Sampling Rate Converter Unit @@ -197,12 +197,17 @@ Ex) [MEM] -> [SRC2] -> [CTU03] -+ sound { + #address-cells = <1>; + #size-cells = <0>; + compatible = "simple-scu-audio-card"; ... - simple-audio-card,cpu-0 { + simple-audio-card,cpu@0 { + reg = <0>; sound-dai = <&rcar_sound 0>; }; - simple-audio-card,cpu-1 { + simple-audio-card,cpu@1 { + reg = <1>; sound-dai = <&rcar_sound 1>; }; simple-audio-card,codec { @@ -334,9 +339,11 @@ Required properties: - compatible : "renesas,rcar_sound-", fallbacks "renesas,rcar_sound-gen1" if generation1, and - "renesas,rcar_sound-gen2" if generation2 + "renesas,rcar_sound-gen2" if generation2 (or RZ/G1) "renesas,rcar_sound-gen3" if generation3 Examples with soctypes are: + - "renesas,rcar_sound-r8a7743" (RZ/G1M) + - "renesas,rcar_sound-r8a7745" (RZ/G1E) - "renesas,rcar_sound-r8a7778" (R-Car M1A) - "renesas,rcar_sound-r8a7779" (R-Car H1) - "renesas,rcar_sound-r8a7790" (R-Car H2) diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt index 166f2290233b..17c13e74667d 100644 --- a/Documentation/devicetree/bindings/sound/simple-card.txt +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -140,6 +140,7 @@ sound { simple-audio-card,name = "Cubox Audio"; simple-audio-card,dai-link@0 { /* I2S - HDMI */ + reg = <0>; format = "i2s"; cpu { sound-dai = <&audio1 0>; @@ -150,6 +151,7 @@ sound { }; simple-audio-card,dai-link@1 { /* S/PDIF - HDMI */ + reg = <1>; cpu { sound-dai = <&audio1 1>; }; @@ -159,6 +161,7 @@ sound { }; simple-audio-card,dai-link@2 { /* S/PDIF - S/PDIF */ + reg = <2>; cpu { sound-dai = <&audio1 1>; }; diff --git a/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt b/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt index 9c1ee52fed5b..4d51f3f5ea98 100644 --- a/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt +++ b/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt @@ -51,7 +51,7 @@ Optional properties: Example: - sti_uni_player1: sti-uni-player@8D81000 { + sti_uni_player1: sti-uni-player@8d81000 { compatible = "st,stih407-uni-player-hdmi"; #sound-dai-cells = <0>; st,syscfg = <&syscfg_core>; @@ -63,7 +63,7 @@ Example: st,tdm-mode = <1>; }; - sti_uni_player2: sti-uni-player@8D82000 { + sti_uni_player2: sti-uni-player@8d82000 { compatible = "st,stih407-uni-player-pcm-out"; #sound-dai-cells = <0>; st,syscfg = <&syscfg_core>; @@ -74,7 +74,7 @@ Example: dma-names = "tx"; }; - sti_uni_player3: sti-uni-player@8D85000 { + sti_uni_player3: sti-uni-player@8d85000 { compatible = "st,stih407-uni-player-spdif"; #sound-dai-cells = <0>; st,syscfg = <&syscfg_core>; @@ -85,7 +85,7 @@ Example: dma-names = "tx"; }; - sti_uni_reader1: sti-uni-reader@8D84000 { + sti_uni_reader1: sti-uni-reader@8d84000 { compatible = "st,stih407-uni-reader-hdmi"; #sound-dai-cells = <0>; st,syscfg = <&syscfg_core>; diff --git a/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt b/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt new file mode 100644 index 000000000000..864f5b00b031 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt @@ -0,0 +1,63 @@ +STMicroelectronics Audio Digital Filter Sigma Delta modulators(DFSDM) + +The DFSDM allows PDM microphones capture through SPI interface. The Audio +interface is seems as a sub block of the DFSDM device. +For details on DFSDM bindings refer to ../iio/adc/st,stm32-dfsdm-adc.txt + +Required properties: + - compatible: "st,stm32h7-dfsdm-dai". + + - #sound-dai-cells : Must be equal to 0 + + - io-channels : phandle to iio dfsdm instance node. + +Example of a sound card using audio DFSDM node. + + sound_card { + compatible = "audio-graph-card"; + + dais = <&cpu_port>; + }; + + dfsdm: dfsdm@40017000 { + compatible = "st,stm32h7-dfsdm"; + reg = <0x40017000 0x400>; + clocks = <&rcc DFSDM1_CK>; + clock-names = "dfsdm"; + #interrupt-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + dfsdm_adc0: filter@0 { + compatible = "st,stm32-dfsdm-dmic"; + reg = <0>; + interrupts = <110>; + dmas = <&dmamux1 101 0x400 0x00>; + dma-names = "rx"; + st,adc-channels = <1>; + st,adc-channel-names = "dmic0"; + st,adc-channel-types = "SPI_R"; + st,adc-channel-clk-src = "CLKOUT"; + st,filter-order = <5>; + + dfsdm_dai0: dfsdm-dai { + compatible = "st,stm32h7-dfsdm-dai"; + #sound-dai-cells = <0>; + io-channels = <&dfsdm_adc0 0>; + cpu_port: port { + dfsdm_endpoint: endpoint { + remote-endpoint = <&dmic0_endpoint>; + }; + }; + }; + }; + + dmic0: dmic@0 { + compatible = "dmic-codec"; + #sound-dai-cells = <0>; + port { + dmic0_endpoint: endpoint { + remote-endpoint = <&dfsdm_endpoint>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt index 1f9cd7095337..b1acc1a256ba 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt @@ -20,11 +20,6 @@ Required properties: Optional properties: - resets: Reference to a reset controller asserting the SAI - - st,sync: specify synchronization mode. - By default SAI sub-block is in asynchronous mode. - This property sets SAI sub-block as slave of another SAI sub-block. - Must contain the phandle and index of the sai sub-block providing - the synchronization. SAI subnodes: Two subnodes corresponding to SAI sub-block instances A et B can be defined. @@ -44,6 +39,13 @@ SAI subnodes required properties: - pinctrl-names: should contain only value "default" - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt +SAI subnodes Optional properties: + - st,sync: specify synchronization mode. + By default SAI sub-block is in asynchronous mode. + This property sets SAI sub-block as slave of another SAI sub-block. + Must contain the phandle and index of the sai sub-block providing + the synchronization. + The device node should contain one 'port' child node with one child 'endpoint' node, according to the bindings defined in Documentation/devicetree/bindings/ graph.txt. diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt index 05d7135a8d2f..b9d50d6cdef3 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt @@ -8,6 +8,7 @@ Required properties: - compatible: should be one of the following: - "allwinner,sun4i-a10-i2s" - "allwinner,sun6i-a31-i2s" + - "allwinner,sun8i-a83t-i2s" - "allwinner,sun8i-h3-i2s" - reg: physical base address of the controller and length of memory mapped region. @@ -23,6 +24,7 @@ Required properties: Required properties for the following compatibles: - "allwinner,sun6i-a31-i2s" + - "allwinner,sun8i-a83t-i2s" - "allwinner,sun8i-h3-i2s" - resets: phandle to the reset line for this codec diff --git a/Documentation/devicetree/bindings/sound/tas5720.txt b/Documentation/devicetree/bindings/sound/tas5720.txt index 40d94f82beb3..7481653fe8e3 100644 --- a/Documentation/devicetree/bindings/sound/tas5720.txt +++ b/Documentation/devicetree/bindings/sound/tas5720.txt @@ -6,10 +6,12 @@ audio playback. For more product information please see the links below: http://www.ti.com/product/TAS5720L http://www.ti.com/product/TAS5720M +http://www.ti.com/product/TAS5722L Required properties: -- compatible : "ti,tas5720" +- compatible : "ti,tas5720", + "ti,tas5722" - reg : I2C slave address - dvdd-supply : phandle to a 3.3-V supply for the digital circuitry - pvdd-supply : phandle to a supply used for the Class-D amp and the analog diff --git a/Documentation/devicetree/bindings/sound/tfa9879.txt b/Documentation/devicetree/bindings/sound/tfa9879.txt index 23ba522d9e2b..1620e6848436 100644 --- a/Documentation/devicetree/bindings/sound/tfa9879.txt +++ b/Documentation/devicetree/bindings/sound/tfa9879.txt @@ -6,18 +6,18 @@ Required properties: - reg : the I2C address of the device +- #sound-dai-cells : must be 0. + Example: &i2c1 { - clock-frequency = <100000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c1>; - status = "okay"; - codec: tfa9879@6c { + amp: amp@6c { #sound-dai-cells = <0>; compatible = "nxp,tfa9879"; reg = <0x6c>; - }; + }; }; diff --git a/Documentation/devicetree/bindings/sound/ti,tas6424.txt b/Documentation/devicetree/bindings/sound/ti,tas6424.txt new file mode 100644 index 000000000000..1c4ada0eef4e --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,tas6424.txt @@ -0,0 +1,20 @@ +Texas Instruments TAS6424 Quad-Channel Audio amplifier + +The TAS6424 serial control bus communicates through I2C protocols. + +Required properties: + - compatible: "ti,tas6424" - TAS6424 + - reg: I2C slave address + - sound-dai-cells: must be equal to 0 + +Example: + +tas6424: tas6424@6a { + compatible = "ti,tas6424"; + reg = <0x6a>; + + #sound-dai-cells = <0>; +}; + +For more product information please see the link below: +http://www.ti.com/product/TAS6424-Q1 diff --git a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt index 6fbba562eaa7..5b3c33bb99e5 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt @@ -22,7 +22,7 @@ Required properties: Optional properties: -- gpio-reset - gpio pin number used for codec reset +- reset-gpios - GPIO specification for the active low RESET input. - ai31xx-micbias-vg - MicBias Voltage setting 1 or MICBIAS_2_0V - MICBIAS output is powered to 2.0V 2 or MICBIAS_2_5V - MICBIAS output is powered to 2.5V @@ -30,6 +30,10 @@ Optional properties: If this node is not mentioned or if the value is unknown, then micbias is set to 2.0V. +Deprecated properties: + +- gpio-reset - gpio pin number used for codec reset + CODEC output pins: * HPL * HPR @@ -48,6 +52,7 @@ CODEC input pins: The pins can be used in referring sound node's audio-routing property. Example: +#include #include tlv320aic31xx: tlv320aic31xx@18 { @@ -56,6 +61,8 @@ tlv320aic31xx: tlv320aic31xx@18 { ai31xx-micbias-vg = ; + reset-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>; + HPVDD-supply = <®ulator>; SPRVDD-supply = <®ulator>; SPLVDD-supply = <®ulator>; diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt index ba5b45c483f5..9796c4639262 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt @@ -17,7 +17,7 @@ Required properties: Optional properties: -- gpio-reset - gpio pin number used for codec reset +- reset-gpios - GPIO specification for the active low RESET input. - ai3x-gpio-func - - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality - Not supported on tlv320aic3104 - ai3x-micbias-vg - MicBias Voltage required. @@ -34,6 +34,10 @@ Optional properties: - AVDD-supply, IOVDD-supply, DRVDD-supply, DVDD-supply : power supplies for the device as covered in Documentation/devicetree/bindings/regulator/regulator.txt +Deprecated properties: + +- gpio-reset - gpio pin number used for codec reset + CODEC output pins: * LLOUT * RLOUT @@ -61,10 +65,14 @@ The pins can be used in referring sound node's audio-routing property. Example: +#include + tlv320aic3x: tlv320aic3x@1b { compatible = "ti,tlv320aic3x"; reg = <0x1b>; + reset-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>; + AVDD-supply = <®ulator>; IOVDD-supply = <®ulator>; DRVDD-supply = <®ulator>; diff --git a/Documentation/devicetree/bindings/sound/tscs42xx.txt b/Documentation/devicetree/bindings/sound/tscs42xx.txt new file mode 100644 index 000000000000..2ac2f0996697 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tscs42xx.txt @@ -0,0 +1,16 @@ +TSCS42XX Audio CODEC + +Required Properties: + + - compatible : "tempo,tscs42A1" for analog mic + "tempo,tscs42A2" for digital mic + + - reg : <0x71> for analog mic + <0x69> for digital mic + +Example: + +wookie: codec@69 { + compatible = "tempo,tscs42A2"; + reg = <0x69>; +}; diff --git a/Documentation/devicetree/bindings/sound/uniphier,evea.txt b/Documentation/devicetree/bindings/sound/uniphier,evea.txt new file mode 100644 index 000000000000..3f31b235f18b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/uniphier,evea.txt @@ -0,0 +1,26 @@ +Socionext EVEA - UniPhier SoC internal codec driver + +Required properties: +- compatible : should be "socionext,uniphier-evea". +- reg : offset and length of the register set for the device. +- clock-names : should include following entries: + "evea", "exiv" +- clocks : a list of phandle, should contain an entry for each + entries in clock-names. +- reset-names : should include following entries: + "evea", "exiv", "adamv" +- resets : a list of phandle, should contain reset entries of + reset-names. +- #sound-dai-cells: should be 1. + +Example: + + codec { + compatible = "socionext,uniphier-evea"; + reg = <0x57900000 0x1000>; + clock-names = "evea", "exiv"; + clocks = <&sys_clk 41>, <&sys_clk 42>; + reset-names = "evea", "exiv", "adamv"; + resets = <&sys_rst 41>, <&sys_rst 42>, <&adamv_rst 0>; + #sound-dai-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt index bdd83959019c..80710f0f0448 100644 --- a/Documentation/devicetree/bindings/spi/sh-msiof.txt +++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt @@ -36,7 +36,21 @@ Required properties: Optional properties: - clocks : Must contain a reference to the functional clock. -- num-cs : Total number of chip-selects (default is 1) +- num-cs : Total number of chip selects (default is 1). + Up to 3 native chip selects are supported: + 0: MSIOF_SYNC + 1: MSIOF_SS1 + 2: MSIOF_SS2 + Hardware limitations related to chip selects: + - Native chip selects are always deasserted in + between transfers that are part of the same + message. Use cs-gpios to work around this. + - All slaves using native chip selects must use the + same spi-cs-high configuration. Use cs-gpios to + work around this. + - When using GPIO chip selects, at least one native + chip select must be left unused, as it will be + driven anyway. - dmas : Must contain a list of two references to DMA specifiers, one for transmission, and one for reception. diff --git a/Documentation/devicetree/bindings/spi/spi-davinci.txt b/Documentation/devicetree/bindings/spi/spi-davinci.txt index 1925277bfc1e..9f5b4c7c0c08 100644 --- a/Documentation/devicetree/bindings/spi/spi-davinci.txt +++ b/Documentation/devicetree/bindings/spi/spi-davinci.txt @@ -68,7 +68,7 @@ SPI_SOMI/SIMO+-----------------+ +----------- Example of a NOR flash slave device (n25q032) connected to DaVinci SPI controller device over the SPI bus. -spi0:spi@20BF0000 { +spi0:spi@20bf0000 { #address-cells = <1>; #size-cells = <0>; compatible = "ti,dm6446-spi"; diff --git a/Documentation/devicetree/bindings/spi/spi-lantiq-ssc.txt b/Documentation/devicetree/bindings/spi/spi-lantiq-ssc.txt index 6069b95a883d..ce3230c8e28d 100644 --- a/Documentation/devicetree/bindings/spi/spi-lantiq-ssc.txt +++ b/Documentation/devicetree/bindings/spi/spi-lantiq-ssc.txt @@ -16,7 +16,7 @@ Optional properties: Example: -spi: spi@E100800 { +spi: spi@e100800 { compatible = "lantiq,xrx200-spi", "lantiq,xrx100-spi"; reg = <0xE100800 0x100>; interrupt-parent = <&icu0>; diff --git a/Documentation/devicetree/bindings/spi/spi-meson.txt b/Documentation/devicetree/bindings/spi/spi-meson.txt index 825c39cae74a..b7f5e86fed22 100644 --- a/Documentation/devicetree/bindings/spi/spi-meson.txt +++ b/Documentation/devicetree/bindings/spi/spi-meson.txt @@ -27,7 +27,9 @@ The Meson SPICC is generic SPI controller for general purpose Full-Duplex communications with dedicated 16 words RX/TX PIO FIFOs. Required properties: - - compatible: should be "amlogic,meson-gx-spicc" on Amlogic GX SoCs. + - compatible: should be: + "amlogic,meson-gx-spicc" on Amlogic GX and compatible SoCs. + "amlogic,meson-axg-spicc" on Amlogic AXG and compatible SoCs - reg: physical base address and length of the controller registers - interrupts: The interrupt specifier - clock-names: Must contain "core" diff --git a/Documentation/devicetree/bindings/spi/spi-orion.txt b/Documentation/devicetree/bindings/spi/spi-orion.txt index df8ec31f2f07..8434a65fc12a 100644 --- a/Documentation/devicetree/bindings/spi/spi-orion.txt +++ b/Documentation/devicetree/bindings/spi/spi-orion.txt @@ -18,8 +18,17 @@ Required properties: The eight register sets following the control registers refer to chip-select lines 0 through 7 respectively. - cell-index : Which of multiple SPI controllers is this. +- clocks : pointers to the reference clocks for this device, the first + one is the one used for the clock on the spi bus, the + second one is optional and is the clock used for the + functional part of the controller + Optional properties: - interrupts : Is currently not used. +- clock-names : names of used clocks, mandatory if the second clock is + used, the name must be "core", and "axi" (the latter + is only for Armada 7K/8K). + Example: spi@10600 { diff --git a/Documentation/devicetree/bindings/spi/spi-xilinx.txt b/Documentation/devicetree/bindings/spi/spi-xilinx.txt index c7b7856bd528..7bf61efc66c8 100644 --- a/Documentation/devicetree/bindings/spi/spi-xilinx.txt +++ b/Documentation/devicetree/bindings/spi/spi-xilinx.txt @@ -2,7 +2,7 @@ Xilinx SPI controller Device Tree Bindings ------------------------------------------------- Required properties: -- compatible : Should be "xlnx,xps-spi-2.00.a" or "xlnx,xps-spi-2.00.b" +- compatible : Should be "xlnx,xps-spi-2.00.a", "xlnx,xps-spi-2.00.b" or "xlnx,axi-quad-spi-1.00.a" - reg : Physical base address and size of SPI registers map. - interrupts : Property with a value describing the interrupt number. diff --git a/Documentation/devicetree/bindings/thermal/armada-thermal.txt b/Documentation/devicetree/bindings/thermal/armada-thermal.txt index 24aacf8948c5..e0d013a2e66d 100644 --- a/Documentation/devicetree/bindings/thermal/armada-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/armada-thermal.txt @@ -2,22 +2,35 @@ Required properties: -- compatible: Should be set to one of the following: - marvell,armada370-thermal - marvell,armada375-thermal - marvell,armada380-thermal - marvell,armadaxp-thermal +- compatible: Should be set to one of the following: + * marvell,armada370-thermal + * marvell,armada375-thermal + * marvell,armada380-thermal + * marvell,armadaxp-thermal + * marvell,armada-ap806-thermal + * marvell,armada-cp110-thermal -- reg: Device's register space. - Two entries are expected, see the examples below. - The first one is required for the sensor register; - the second one is required for the control register - to be used for sensor initialization (a.k.a. calibration). +- reg: Device's register space. + Two entries are expected, see the examples below. The first one points + to the status register (4B). The second one points to the control + registers (8B). + Note: The compatibles marvell,armada370-thermal, + marvell,armada380-thermal, and marvell,armadaxp-thermal must point to + "control MSB/control 1", with size of 4 (deprecated binding), or point + to "control LSB/control 0" with size of 8 (current binding). All other + compatibles must point to "control LSB/control 0" with size of 8. -Example: +Examples: + /* Legacy bindings */ thermal@d0018300 { compatible = "marvell,armada370-thermal"; - reg = <0xd0018300 0x4 + reg = <0xd0018300 0x4 0xd0018304 0x4>; }; + + ap_thermal: thermal@6f8084 { + compatible = "marvell,armada-ap806-thermal"; + reg = <0x6f808C 0x4>, + <0x6f8084 0x8>; + }; diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt index 9b4c7b017495..1b596fd38dc4 100644 --- a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt @@ -70,7 +70,7 @@ Following properties are mandatory (depending on SoC): Example 1): - tmu@100C0000 { + tmu@100c0000 { compatible = "samsung,exynos4412-tmu"; interrupt-parent = <&combiner>; reg = <0x100C0000 0x100>; diff --git a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt index a8e52c8ccfcc..349e635f2d87 100644 --- a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt @@ -6,6 +6,7 @@ Required properties: "renesas,rcar-thermal" (without thermal-zone) as fallback. Examples with soctypes are: - "renesas,thermal-r8a73a4" (R-Mobile APE6) + - "renesas,thermal-r8a7743" (RZ/G1M) - "renesas,thermal-r8a7779" (R-Car H1) - "renesas,thermal-r8a7790" (R-Car H2) - "renesas,thermal-r8a7791" (R-Car M2-W) diff --git a/Documentation/devicetree/bindings/thermal/thermal.txt b/Documentation/devicetree/bindings/thermal/thermal.txt index 44d7cb2cb2c0..1719d47a5e2f 100644 --- a/Documentation/devicetree/bindings/thermal/thermal.txt +++ b/Documentation/devicetree/bindings/thermal/thermal.txt @@ -252,7 +252,7 @@ ocp { /* * A simple IC with a single bandgap temperature sensor. */ - bandgap0: bandgap@0000ED00 { + bandgap0: bandgap@0000ed00 { ... #thermal-sensor-cells = <0>; }; @@ -330,7 +330,7 @@ ocp { /* * A simple IC with several bandgap temperature sensors. */ - bandgap0: bandgap@0000ED00 { + bandgap0: bandgap@0000ed00 { ... #thermal-sensor-cells = <1>; }; @@ -458,7 +458,7 @@ ocp { /* * A simple IC with a single bandgap temperature sensor. */ - bandgap0: bandgap@0000ED00 { + bandgap0: bandgap@0000ed00 { ... #thermal-sensor-cells = <0>; }; diff --git a/Documentation/devicetree/bindings/timer/actions,owl-timer.txt b/Documentation/devicetree/bindings/timer/actions,owl-timer.txt index e3c28da80cb2..977054f87563 100644 --- a/Documentation/devicetree/bindings/timer/actions,owl-timer.txt +++ b/Documentation/devicetree/bindings/timer/actions,owl-timer.txt @@ -2,6 +2,7 @@ Actions Semi Owl Timer Required properties: - compatible : "actions,s500-timer" for S500 + "actions,s700-timer" for S700 "actions,s900-timer" for S900 - reg : Offset and length of the register set for the device. - interrupts : Should contain the interrupts. diff --git a/Documentation/devicetree/bindings/timer/renesas,tpu.txt b/Documentation/devicetree/bindings/timer/renesas,tpu.txt index f8b25897fb31..1d46f9de4feb 100644 --- a/Documentation/devicetree/bindings/timer/renesas,tpu.txt +++ b/Documentation/devicetree/bindings/timer/renesas,tpu.txt @@ -1,4 +1,4 @@ -* Renesas H8/300 Timer Pluse Unit +* Renesas H8/300 Timer Pulse Unit The TPU is a 16bit timer/counter with configurable clock inputs and programmable compare match. diff --git a/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt b/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt index 167d5dab9f64..8f78640ad64c 100644 --- a/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt +++ b/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt @@ -51,7 +51,7 @@ Example 2: In this example, the timer interrupts are connected to two separate interrupt controllers. Hence, an interrupt-map is created to map the interrupts to the respective interrupt controllers. - mct@101C0000 { + mct@101c0000 { compatible = "samsung,exynos4210-mct"; reg = <0x101C0000 0x800>; interrupt-parent = <&mct_map>; diff --git a/Documentation/devicetree/bindings/timer/spreadtrum,sprd-timer.txt b/Documentation/devicetree/bindings/timer/spreadtrum,sprd-timer.txt new file mode 100644 index 000000000000..6d97e7d0f6e8 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/spreadtrum,sprd-timer.txt @@ -0,0 +1,20 @@ +Spreadtrum timers + +The Spreadtrum SC9860 platform provides 3 general-purpose timers. +These timers can support 32bit or 64bit counter, as well as supporting +period mode or one-shot mode, and they are can be wakeup source +during deep sleep. + +Required properties: +- compatible: should be "sprd,sc9860-timer" for SC9860 platform. +- reg: The register address of the timer device. +- interrupts: Should contain the interrupt for the timer device. +- clocks: The phandle to the source clock (usually a 32.768 KHz fixed clock). + +Example: + timer@40050000 { + compatible = "sprd,sc9860-timer"; + reg = <0 0x40050000 0 0x20>; + interrupts = ; + clocks = <&ext_32k>; + }; diff --git a/Documentation/devicetree/bindings/trivial-devices.txt b/Documentation/devicetree/bindings/trivial-devices.txt index 5f3143f97098..2e3740f98c41 100644 --- a/Documentation/devicetree/bindings/trivial-devices.txt +++ b/Documentation/devicetree/bindings/trivial-devices.txt @@ -63,6 +63,7 @@ fsl,sgtl5000 SGTL5000: Ultra Low-Power Audio Codec gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface infineon,slb9635tt Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz) infineon,slb9645tt Infineon SLB9645 I2C TPM (new protocol, max 400khz) +infineon,tlv493d-a1b6 Infineon TLV493D-A1B6 I2C 3D Magnetic Sensor isil,isl1208 Intersil ISL1208 Low Power RTC with Battery Backed SRAM isil,isl1218 Intersil ISL1218 Low Power RTC with Battery Backed SRAM isil,isl12022 Intersil ISL12022 Real-time Clock @@ -151,6 +152,7 @@ national,lm85 Temperature sensor with integrated fan control national,lm92 ±0.33°C Accurate, 12-Bit + Sign Temperature Sensor and Thermal Window Comparator with Two-Wire Interface nuvoton,npct501 i2c trusted platform module (TPM) nuvoton,npct601 i2c trusted platform module (TPM2) +nuvoton,w83773g Nuvoton Temperature Sensor nxp,pca9556 Octal SMBus and I2C registered interface nxp,pca9557 8-bit I2C-bus and SMBus I/O port with reset nxp,pcf2127 Real-time clock diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 52fb41046b34..44e8bab159ad 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -47,6 +47,8 @@ Optional properties: from P0 to P1/P2/P3 without delay. - snps,dis-tx-ipgap-linecheck-quirk: when set, disable u2mac linestate check during HS transmit. + - snps,dis_metastability_quirk: when set, disable metastability workaround. + CAUTION: use only if you are absolutely sure of it. - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal utmi_l1_suspend_n, false when asserts utmi_sleep_n - snps,hird-threshold: HIRD threshold diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt index 30595964876a..88d9f4a4b280 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt @@ -35,10 +35,14 @@ Required properties: - phys : a list of phandle + phy specifier pairs Optional properties: - - mediatek,wakeup-src : 1: ip sleep wakeup mode; 2: line state wakeup - mode; - - mediatek,syscon-wakeup : phandle to syscon used to access USB wakeup - control register, it depends on "mediatek,wakeup-src". + - wakeup-source : enable USB remote wakeup; + - mediatek,syscon-wakeup : phandle to syscon used to access the register + of the USB wakeup glue layer between xHCI and SPM; it depends on + "wakeup-source", and has two arguments: + - the first one : register base address of the glue layer in syscon; + - the second one : hardware version of the glue layer + - 1 : used by mt8173 etc + - 2 : used by mt2712 etc - mediatek,u3p-dis-msk : mask to disable u3ports, bit0 for u3port0, bit1 for u3port1, ... etc; - vbus-supply : reference to the VBUS regulator; @@ -46,6 +50,7 @@ Optional properties: - pinctrl-names : a pinctrl state named "default" must be defined - pinctrl-0 : pin control group See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + - imod-interval-ns: default interrupt moderation interval is 5000ns Example: usb30: usb@11270000 { @@ -64,8 +69,9 @@ usb30: usb@11270000 { vusb33-supply = <&mt6397_vusb_reg>; vbus-supply = <&usb_p1_vbus>; usb3-lpm-capable; - mediatek,syscon-wakeup = <&pericfg>; - mediatek,wakeup-src = <1>; + mediatek,syscon-wakeup = <&pericfg 0x400 1>; + wakeup-source; + imod-interval-ns = <10000>; }; 2nd: dual-role mode with xHCI driver diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt b/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt index b2271d8e6b50..d589a1ef96a1 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt +++ b/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt @@ -42,9 +42,14 @@ Optional properties: - enable-manual-drd : supports manual dual-role switch via debugfs; usually used when receptacle is TYPE-A and also wants to support dual-role mode. - - mediatek,enable-wakeup : supports ip sleep wakeup used by host mode - - mediatek,syscon-wakeup : phandle to syscon used to access USB wakeup - control register, it depends on "mediatek,enable-wakeup". + - wakeup-source: enable USB remote wakeup of host mode. + - mediatek,syscon-wakeup : phandle to syscon used to access the register + of the USB wakeup glue layer between SSUSB and SPM; it depends on + "wakeup-source", and has two arguments: + - the first one : register base address of the glue layer in syscon; + - the second one : hardware version of the glue layer + - 1 : used by mt8173 etc + - 2 : used by mt2712 etc - mediatek,u3p-dis-msk : mask to disable u3ports, bit0 for u3port0, bit1 for u3port1, ... etc; @@ -71,8 +76,8 @@ ssusb: usb@11271000 { vbus-supply = <&usb_p0_vbus>; extcon = <&extcon_usb>; dr_mode = "otg"; - mediatek,enable-wakeup; - mediatek,syscon-wakeup = <&pericfg>; + wakeup-source; + mediatek,syscon-wakeup = <&pericfg 0x400 1>; #address-cells = <2>; #size-cells = <2>; ranges; diff --git a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt index 47394ab788e3..d060172f1529 100644 --- a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt +++ b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt @@ -13,8 +13,10 @@ Required properties: - "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device - "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device - "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device + - "renesas,usbhs-r7s72100" for r7s72100 (RZ/A1) compatible device - "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices - "renesas,rcar-gen3-usbhs" for R-Car Gen3 compatible device + - "renesas,rza1-usbhs" for RZ/A1 compatible device When compatible with the generic version, nodes must list the SoC-specific version corresponding to the platform first followed diff --git a/Documentation/devicetree/bindings/usb/usb-device.txt b/Documentation/devicetree/bindings/usb/usb-device.txt index 1b27cebb47f4..036be172b1ae 100644 --- a/Documentation/devicetree/bindings/usb/usb-device.txt +++ b/Documentation/devicetree/bindings/usb/usb-device.txt @@ -4,8 +4,49 @@ Usually, we only use device tree for hard wired USB device. The reference binding doc is from: http://www.devicetree.org/open-firmware/bindings/usb/usb-1_0.ps +Four types of device-tree nodes are defined: "host-controller nodes" +representing USB host controllers, "device nodes" representing USB devices, +"interface nodes" representing USB interfaces and "combined nodes" +representing simple USB devices. -Required properties: +A combined node shall be used instead of a device node and an interface node +for devices of class 0 or 9 (hub) with a single configuration and a single +interface. + +A "hub node" is a combined node or an interface node that represents a USB +hub. + + +Required properties for device nodes: +- compatible: "usbVID,PID", where VID is the vendor id and PID the product id. + The textual representation of VID and PID shall be in lower case hexadecimal + with leading zeroes suppressed. The other compatible strings from the above + standard binding could also be used, but a device adhering to this binding + may leave out all except for "usbVID,PID". +- reg: the number of the USB hub port or the USB host-controller port to which + this device is attached. The range is 1-255. + + +Required properties for device nodes with interface nodes: +- #address-cells: shall be 2 +- #size-cells: shall be 0 + + +Required properties for interface nodes: +- compatible: "usbifVID,PID.configCN.IN", where VID is the vendor id, PID is + the product id, CN is the configuration value and IN is the interface + number. The textual representation of VID, PID, CN and IN shall be in lower + case hexadecimal with leading zeroes suppressed. The other compatible + strings from the above standard binding could also be used, but a device + adhering to this binding may leave out all except for + "usbifVID,PID.configCN.IN". +- reg: the interface number and configuration value + +The configuration component is not included in the textual representation of +an interface-node unit address for configuration 1. + + +Required properties for combined nodes: - compatible: "usbVID,PID", where VID is the vendor id and PID the product id. The textual representation of VID and PID shall be in lower case hexadecimal with leading zeroes suppressed. The other compatible strings from the above @@ -31,8 +72,31 @@ Example: #address-cells = <1>; #size-cells = <0>; - hub@1 { /* hub connected to port 1 */ + hub@1 { /* hub connected to port 1 */ compatible = "usb5e3,608"; reg = <1>; }; + + device@2 { /* device connected to port 2 */ + compatible = "usb123,4567"; + reg = <2>; + }; + + device@3 { /* device connected to port 3 */ + compatible = "usb123,abcd"; + reg = <3>; + + #address-cells = <2>; + #size-cells = <0>; + + interface@0 { /* interface 0 of configuration 1 */ + compatible = "usbif123,abcd.config1.0"; + reg = <0 1>; + }; + + interface@0,2 { /* interface 0 of configuration 2 */ + compatible = "usbif123,abcd.config2.0"; + reg = <0 2>; + }; + }; }; diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt index ae6e484a8d7c..e2ea59bbca93 100644 --- a/Documentation/devicetree/bindings/usb/usb-xhci.txt +++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt @@ -7,12 +7,14 @@ Required properties: - "marvell,armada3700-xhci" for Armada 37xx SoCs - "marvell,armada-375-xhci" for Armada 375 SoCs - "marvell,armada-380-xhci" for Armada 38x SoCs + - "renesas,xhci-r8a7743" for r8a7743 SoC - "renesas,xhci-r8a7790" for r8a7790 SoC - "renesas,xhci-r8a7791" for r8a7791 SoC - "renesas,xhci-r8a7793" for r8a7793 SoC - "renesas,xhci-r8a7795" for r8a7795 SoC - "renesas,xhci-r8a7796" for r8a7796 SoC - - "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 compatible device + - "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 or RZ/G1 compatible + device - "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 compatible device - "xhci-platform" (deprecated) @@ -29,6 +31,7 @@ Optional properties: - usb2-lpm-disable: indicate if we don't want to enable USB2 HW LPM - usb3-lpm-capable: determines if platform is USB3 LPM capable - quirk-broken-port-ped: set if the controller has broken port disable mechanism + - imod-interval-ns: default interrupt moderation interval is 5000ns Example: usb@f0931000 { diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 159dc5c075c2..ae850d6c0ad3 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -15,6 +15,7 @@ adi Analog Devices, Inc. advantech Advantech Corporation aeroflexgaisler Aeroflex Gaisler AB al Annapurna Labs +allo Allo.com allwinner Allwinner Technology Co., Ltd. alphascale AlphaScale Integrated Circuits Systems, Inc. altr Altera Corp. @@ -97,6 +98,7 @@ dptechnics DPTechnics dragino Dragino Technology Co., Limited ea Embedded Artists AB ebv EBV Elektronik +eckelmann Eckelmann AG edt Emerging Display Technologies eeti eGalax_eMPIA Technology Inc elan Elan Microelectronic Corp. @@ -123,6 +125,7 @@ focaltech FocalTech Systems Co.,Ltd friendlyarm Guangzhou FriendlyARM Computer Tech Co., Ltd fsl Freescale Semiconductor fujitsu Fujitsu Ltd. +gcw Game Consoles Worldwide ge General Electric Company geekbuying GeekBuying gef GE Fanuc Intelligent Platforms Embedded Systems, Inc. @@ -307,6 +310,7 @@ seagate Seagate Technology PLC semtech Semtech Corporation sensirion Sensirion AG sff Small Form Factor Committee +sgd Solomon Goldentek Display Corporation sgx SGX Sensortech sharp Sharp Corporation shimafuji Shimafuji Electric, Inc. @@ -349,6 +353,7 @@ tcg Trusted Computing Group tcl Toby Churchill Ltd. technexion TechNexion technologic Technologic Systems +tempo Tempo Semiconductor terasic Terasic Inc. thine THine Electronics, Inc. ti Texas Instruments diff --git a/Documentation/devicetree/bindings/watchdog/cortina,gemini-watchdog.txt b/Documentation/devicetree/bindings/watchdog/cortina,gemini-watchdog.txt deleted file mode 100644 index bc4b865d178b..000000000000 --- a/Documentation/devicetree/bindings/watchdog/cortina,gemini-watchdog.txt +++ /dev/null @@ -1,17 +0,0 @@ -Cortina Systems Gemini SoC Watchdog - -Required properties: -- compatible : must be "cortina,gemini-watchdog" -- reg : shall contain base register location and length -- interrupts : shall contain the interrupt for the watchdog - -Optional properties: -- timeout-sec : the default watchdog timeout in seconds. - -Example: - -watchdog@41000000 { - compatible = "cortina,gemini-watchdog"; - reg = <0x41000000 0x1000>; - interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; -}; diff --git a/Documentation/devicetree/bindings/watchdog/cortina,gemin-watchdog.txt b/Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.txt similarity index 55% rename from Documentation/devicetree/bindings/watchdog/cortina,gemin-watchdog.txt rename to Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.txt index bc4b865d178b..9ecdb502e605 100644 --- a/Documentation/devicetree/bindings/watchdog/cortina,gemin-watchdog.txt +++ b/Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.txt @@ -1,7 +1,12 @@ -Cortina Systems Gemini SoC Watchdog +Faraday Technology FTWDT010 watchdog + +This is an IP part from Faraday Technology found in the Gemini +SoCs and others. Required properties: -- compatible : must be "cortina,gemini-watchdog" +- compatible : must be one of + "faraday,ftwdt010" + "cortina,gemini-watchdog", "faraday,ftwdt010" - reg : shall contain base register location and length - interrupts : shall contain the interrupt for the watchdog @@ -11,7 +16,7 @@ Optional properties: Example: watchdog@41000000 { - compatible = "cortina,gemini-watchdog"; + compatible = "faraday,ftwdt010"; reg = <0x41000000 0x1000>; interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; }; diff --git a/Documentation/devicetree/bindings/watchdog/ingenic,jz4740-wdt.txt b/Documentation/devicetree/bindings/watchdog/ingenic,jz4740-wdt.txt index 3c7a1cd13b10..cb44918f01a8 100644 --- a/Documentation/devicetree/bindings/watchdog/ingenic,jz4740-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/ingenic,jz4740-wdt.txt @@ -1,7 +1,7 @@ -Ingenic Watchdog Timer (WDT) Controller for JZ4740 +Ingenic Watchdog Timer (WDT) Controller for JZ4740 & JZ4780 Required properties: -compatible: "ingenic,jz4740-watchdog" +compatible: "ingenic,jz4740-watchdog" or "ingenic,jz4780-watchdog" reg: Register address and length for watchdog registers Example: diff --git a/Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt b/Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt index 556d06c17c92..4b76bec62af9 100644 --- a/Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt @@ -10,7 +10,7 @@ Optional properties: Example: - watchdog@4003C000 { + watchdog@4003c000 { compatible = "nxp,pnx4008-wdt"; reg = <0x4003C000 0x1000>; timeout-sec = <10>; diff --git a/Documentation/devicetree/bindings/watchdog/realtek,rtd119x.txt b/Documentation/devicetree/bindings/watchdog/realtek,rtd119x.txt new file mode 100644 index 000000000000..05653054bd5b --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/realtek,rtd119x.txt @@ -0,0 +1,17 @@ +Realtek RTD1295 Watchdog +======================== + +Required properties: + +- compatible : Should be "realtek,rtd1295-watchdog" +- reg : Specifies the physical base address and size of registers +- clocks : Specifies one clock input + + +Example: + + watchdog@98007680 { + compatible = "realtek,rtd1295-watchdog"; + reg = <0x98007680 0x100>; + clocks = <&osc27M>; + }; diff --git a/Documentation/devicetree/bindings/watchdog/renesas-wdt.txt b/Documentation/devicetree/bindings/watchdog/renesas-wdt.txt index bf6d1ca58af7..74b2f03c1515 100644 --- a/Documentation/devicetree/bindings/watchdog/renesas-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/renesas-wdt.txt @@ -4,10 +4,11 @@ Required properties: - compatible : Should be "renesas,-wdt", and "renesas,rcar-gen3-wdt" or "renesas,rza-wdt" as fallback. Examples with soctypes are: + - "renesas,r7s72100-wdt" (RZ/A1) - "renesas,r8a7795-wdt" (R-Car H3) - "renesas,r8a7796-wdt" (R-Car M3-W) + - "renesas,r8a77970-wdt" (R-Car V3M) - "renesas,r8a77995-wdt" (R-Car D3) - - "renesas,r7s72100-wdt" (RZ/A1) When compatible with the generic version, nodes must list the SoC-specific version corresponding to the platform first, followed by the generic diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt index 1f6e101e299a..46dcb48e75b4 100644 --- a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt @@ -25,7 +25,7 @@ Optional properties: Example: -watchdog@101D0000 { +watchdog@101d0000 { compatible = "samsung,exynos5250-wdt"; reg = <0x101D0000 0x100>; interrupts = <0 42 0>; diff --git a/Documentation/devicetree/bindings/watchdog/sprd-wdt.txt b/Documentation/devicetree/bindings/watchdog/sprd-wdt.txt new file mode 100644 index 000000000000..aeaf3e0caf47 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/sprd-wdt.txt @@ -0,0 +1,19 @@ +Spreadtrum SoCs Watchdog timer + +Required properties: +- compatible : Should be "sprd,sp9860-wdt". +- reg : Specifies base physical address and size of the registers. +- interrupts : Exactly one interrupt specifier. +- timeout-sec : Contain the default watchdog timeout in seconds. +- clock-names : Contain the input clock names. +- clocks : Phandles to input clocks. + +Example: + watchdog: watchdog@40310000 { + compatible = "sprd,sp9860-wdt"; + reg = <0 0x40310000 0 0x1000>; + interrupts = ; + timeout-sec = <12>; + clock-names = "enable", "rtc_enable"; + clocks = <&clk_aon_apb_gates1 8>, <&clk_aon_apb_rtc_gates 9>; + }; diff --git a/Documentation/devicetree/bindings/watchdog/zii,rave-sp-wdt.txt b/Documentation/devicetree/bindings/watchdog/zii,rave-sp-wdt.txt new file mode 100644 index 000000000000..3de96186e92e --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/zii,rave-sp-wdt.txt @@ -0,0 +1,39 @@ +Zodiac Inflight Innovations RAVE Supervisory Processor Watchdog Bindings + +RAVE SP watchdog device is a "MFD cell" device corresponding to +watchdog functionality of RAVE Supervisory Processor. It is expected +that its Device Tree node is specified as a child of the node +corresponding to the parent RAVE SP device (as documented in +Documentation/devicetree/bindings/mfd/zii,rave-sp.txt) + +Required properties: + +- compatible: Depending on wire protocol implemented by RAVE SP + firmware, should be one of: + - "zii,rave-sp-watchdog" + - "zii,rave-sp-watchdog-legacy" + +Optional properties: + +- wdt-timeout: Two byte nvmem cell specified as per + Documentation/devicetree/bindings/nvmem/nvmem.txt + +Example: + + rave-sp { + compatible = "zii,rave-sp-rdu1"; + current-speed = <38400>; + + eeprom { + wdt_timeout: wdt-timeout@8E { + reg = <0x8E 2>; + }; + }; + + watchdog { + compatible = "zii,rave-sp-watchdog"; + nvmem-cells = <&wdt_timeout>; + nvmem-cell-names = "wdt-timeout"; + }; + } + diff --git a/Documentation/devicetree/booting-without-of.txt b/Documentation/devicetree/booting-without-of.txt index 417f91110010..e86bd2f64117 100644 --- a/Documentation/devicetree/booting-without-of.txt +++ b/Documentation/devicetree/booting-without-of.txt @@ -1309,7 +1309,7 @@ number and level/sense information. All interrupt children in an OpenPIC interrupt domain use 2 cells per interrupt in their interrupts property. -The PCI bus binding specifies a #interrupt-cell value of 1 to encode +The PCI bus binding specifies a #interrupt-cells value of 1 to encode which interrupt pin (INTA,INTB,INTC,INTD) is used. 2) interrupt-parent property diff --git a/Documentation/doc-guide/kernel-doc.rst b/Documentation/doc-guide/kernel-doc.rst index 0268335414ce..722d4525f7cf 100644 --- a/Documentation/doc-guide/kernel-doc.rst +++ b/Documentation/doc-guide/kernel-doc.rst @@ -112,16 +112,17 @@ Example kernel-doc function comment:: /** * foobar() - Brief description of foobar. - * @arg: Description of argument of foobar. + * @argument1: Description of parameter argument1 of foobar. + * @argument2: Description of parameter argument2 of foobar. * * Longer description of foobar. * * Return: Description of return value of foobar. */ - int foobar(int arg) + int foobar(int argument1, char *argument2) The format is similar for documentation for structures, enums, paragraphs, -etc. See the sections below for details. +etc. See the sections below for specific details of each type. The kernel-doc structure is extracted from the comments, and proper `Sphinx C Domain`_ function and type descriptions with anchors are generated for them. The @@ -130,6 +131,226 @@ cross-references. See below for details. .. _Sphinx C Domain: http://www.sphinx-doc.org/en/stable/domains.html + +Parameters and member arguments +------------------------------- + +The kernel-doc function comments describe each parameter to the function and +function typedefs or each member of struct/union, in order, with the +``@argument:`` descriptions. For each non-private member argument, one +``@argument`` definition is needed. + +The ``@argument:`` descriptions begin on the very next line following +the opening brief function description line, with no intervening blank +comment lines. + +The ``@argument:`` descriptions may span multiple lines. + +.. note:: + + If the ``@argument`` description has multiple lines, the continuation + of the description should be starting exactly at the same column as + the previous line, e. g.:: + + * @argument: some long description + * that continues on next lines + + or:: + + * @argument: + * some long description + * that continues on next lines + +If a function or typedef parameter argument is ``...`` (e. g. a variable +number of arguments), its description should be listed in kernel-doc +notation as:: + + * @...: description + +Private members +~~~~~~~~~~~~~~~ + +Inside a struct or union description, you can use the ``private:`` and +``public:`` comment tags. Structure fields that are inside a ``private:`` +area are not listed in the generated output documentation. + +The ``private:`` and ``public:`` tags must begin immediately following a +``/*`` comment marker. They may optionally include comments between the +``:`` and the ending ``*/`` marker. + +Example:: + + /** + * struct my_struct - short description + * @a: first member + * @b: second member + * @d: fourth member + * + * Longer description + */ + struct my_struct { + int a; + int b; + /* private: internal use only */ + int c; + /* public: the next one is public */ + int d; + }; + +Function documentation +---------------------- + +The general format of a function and function-like macro kernel-doc comment is:: + + /** + * function_name() - Brief description of function. + * @arg1: Describe the first argument. + * @arg2: Describe the second argument. + * One can provide multiple line descriptions + * for arguments. + * + * A longer description, with more discussion of the function function_name() + * that might be useful to those using or modifying it. Begins with an + * empty comment line, and may include additional embedded empty + * comment lines. + * + * The longer description may have multiple paragraphs. + * + * Return: Describe the return value of foobar. + * + * The return value description can also have multiple paragraphs, and should + * be placed at the end of the comment block. + */ + +The brief description following the function name may span multiple lines, and +ends with an argument description, a blank comment line, or the end of the +comment block. + +Return values +~~~~~~~~~~~~~ + +The return value, if any, should be described in a dedicated section +named ``Return``. + +.. note:: + + #) The multi-line descriptive text you provide does *not* recognize + line breaks, so if you try to format some text nicely, as in:: + + * Return: + * 0 - OK + * -EINVAL - invalid argument + * -ENOMEM - out of memory + + this will all run together and produce:: + + Return: 0 - OK -EINVAL - invalid argument -ENOMEM - out of memory + + So, in order to produce the desired line breaks, you need to use a + ReST list, e. g.:: + + * Return: + * * 0 - OK to runtime suspend the device + * * -EBUSY - Device should not be runtime suspended + + #) If the descriptive text you provide has lines that begin with + some phrase followed by a colon, each of those phrases will be taken + as a new section heading, with probably won't produce the desired + effect. + +Structure, union, and enumeration documentation +----------------------------------------------- + +The general format of a struct, union, and enum kernel-doc comment is:: + + /** + * struct struct_name - Brief description. + * @argument: Description of member member_name. + * + * Description of the structure. + */ + +On the above, ``struct`` is used to mean structs. You can also use ``union`` +and ``enum`` to describe unions and enums. ``argument`` is used +to mean struct and union member names as well as enumerations in an enum. + +The brief description following the structure name may span multiple lines, and +ends with a member description, a blank comment line, or the end of the +comment block. + +The kernel-doc data structure comments describe each member of the structure, +in order, with the member descriptions. + +Nested structs/unions +~~~~~~~~~~~~~~~~~~~~~ + +It is possible to document nested structs unions, like:: + + /** + * struct nested_foobar - a struct with nested unions and structs + * @arg1: - first argument of anonymous union/anonymous struct + * @arg2: - second argument of anonymous union/anonymous struct + * @arg3: - third argument of anonymous union/anonymous struct + * @arg4: - fourth argument of anonymous union/anonymous struct + * @bar.st1.arg1 - first argument of struct st1 on union bar + * @bar.st1.arg2 - second argument of struct st1 on union bar + * @bar.st2.arg1 - first argument of struct st2 on union bar + * @bar.st2.arg2 - second argument of struct st2 on union bar + struct nested_foobar { + /* Anonymous union/struct*/ + union { + struct { + int arg1; + int arg2; + } + struct { + void *arg3; + int arg4; + } + } + union { + struct { + int arg1; + int arg2; + } st1; + struct { + void *arg1; + int arg2; + } st2; + } bar; + }; + +.. note:: + + #) When documenting nested structs or unions, if the struct/union ``foo`` + is named, the argument ``bar`` inside it should be documented as + ``@foo.bar:`` + #) When the nested struct/union is anonymous, the argument ``bar`` on it + should be documented as ``@bar:`` + +Typedef documentation +--------------------- + +The general format of a typedef kernel-doc comment is:: + + /** + * typedef type_name - Brief description. + * + * Description of the type. + */ + +Typedefs with function prototypes can also be documented:: + + /** + * typedef type_name - Brief description. + * @arg1: description of arg1 + * @arg2: description of arg2 + * + * Description of the type. + */ + typedef void (*type_name)(struct v4l2_ctrl *arg1, void *arg2); + + Highlights and cross-references ------------------------------- @@ -201,70 +422,7 @@ cross-references. For further details, please refer to the `Sphinx C Domain`_ documentation. -Function documentation ----------------------- -The general format of a function and function-like macro kernel-doc comment is:: - - /** - * function_name() - Brief description of function. - * @arg1: Describe the first argument. - * @arg2: Describe the second argument. - * One can provide multiple line descriptions - * for arguments. - * - * A longer description, with more discussion of the function function_name() - * that might be useful to those using or modifying it. Begins with an - * empty comment line, and may include additional embedded empty - * comment lines. - * - * The longer description may have multiple paragraphs. - * - * Return: Describe the return value of foobar. - * - * The return value description can also have multiple paragraphs, and should - * be placed at the end of the comment block. - */ - -The brief description following the function name may span multiple lines, and -ends with an ``@argument:`` description, a blank comment line, or the end of the -comment block. - -The kernel-doc function comments describe each parameter to the function, in -order, with the ``@argument:`` descriptions. The ``@argument:`` descriptions -must begin on the very next line following the opening brief function -description line, with no intervening blank comment lines. The ``@argument:`` -descriptions may span multiple lines. The continuation lines may contain -indentation. If a function parameter is ``...`` (varargs), it should be listed -in kernel-doc notation as: ``@...:``. - -The return value, if any, should be described in a dedicated section at the end -of the comment starting with "Return:". - -Structure, union, and enumeration documentation ------------------------------------------------ - -The general format of a struct, union, and enum kernel-doc comment is:: - - /** - * struct struct_name - Brief description. - * @member_name: Description of member member_name. - * - * Description of the structure. - */ - -Below, "struct" is used to mean structs, unions and enums, and "member" is used -to mean struct and union members as well as enumerations in an enum. - -The brief description following the structure name may span multiple lines, and -ends with a ``@member:`` description, a blank comment line, or the end of the -comment block. - -The kernel-doc data structure comments describe each member of the structure, in -order, with the ``@member:`` descriptions. The ``@member:`` descriptions must -begin on the very next line following the opening brief function description -line, with no intervening blank comment lines. The ``@member:`` descriptions may -span multiple lines. The continuation lines may contain indentation. In-line member documentation comments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -294,42 +452,6 @@ on a line of their own, like all other kernel-doc comments:: int foobar; } -Private members -~~~~~~~~~~~~~~~ - -Inside a struct description, you can use the "private:" and "public:" comment -tags. Structure fields that are inside a "private:" area are not listed in the -generated output documentation. The "private:" and "public:" tags must begin -immediately following a ``/*`` comment marker. They may optionally include -comments between the ``:`` and the ending ``*/`` marker. - -Example:: - - /** - * struct my_struct - short description - * @a: first member - * @b: second member - * - * Longer description - */ - struct my_struct { - int a; - int b; - /* private: internal use only */ - int c; - }; - - -Typedef documentation ---------------------- - -The general format of a typedef kernel-doc comment is:: - - /** - * typedef type_name - Brief description. - * - * Description of the type. - */ Overview documentation comments ------------------------------- @@ -376,3 +498,37 @@ file. Data structures visible in kernel include files should also be documented using kernel-doc formatted comments. + +How to use kernel-doc to generate man pages +------------------------------------------- + +If you just want to use kernel-doc to generate man pages you can do this +from the Kernel git tree:: + + $ scripts/kernel-doc -man $(git grep -l '/\*\*' |grep -v Documentation/) | ./split-man.pl /tmp/man + +Using the small ``split-man.pl`` script below:: + + + #!/usr/bin/perl + + if ($#ARGV < 0) { + die "where do I put the results?\n"; + } + + mkdir $ARGV[0],0777; + $state = 0; + while () { + if (/^\.TH \"[^\"]*\" 9 \"([^\"]*)\"/) { + if ($state == 1) { close OUT } + $state = 1; + $fn = "$ARGV[0]/$1.9"; + print STDERR "Creating $fn\n"; + open OUT, ">$fn" or die "can't open $fn: $!\n"; + print OUT $_; + } elsif ($state != 0) { + print OUT $_; + } + } + + close OUT; diff --git a/Documentation/driver-api/basics.rst b/Documentation/driver-api/basics.rst index 73fa7d42bbba..826e85d50a16 100644 --- a/Documentation/driver-api/basics.rst +++ b/Documentation/driver-api/basics.rst @@ -13,12 +13,6 @@ Driver device table .. kernel-doc:: include/linux/mod_devicetable.h :internal: -Atomic and pointer manipulation -------------------------------- - -.. kernel-doc:: arch/x86/include/asm/atomic.h - :internal: - Delaying, scheduling, and timer routines ---------------------------------------- @@ -85,6 +79,21 @@ Internal Functions .. kernel-doc:: kernel/kthread.c :export: +Reference counting +------------------ + +.. kernel-doc:: include/linux/refcount.h + :internal: + +.. kernel-doc:: lib/refcount.c + :export: + +Atomics +------- + +.. kernel-doc:: arch/x86/include/asm/atomic.h + :internal: + Kernel objects manipulation --------------------------- diff --git a/Documentation/driver-api/dmaengine/provider.rst b/Documentation/driver-api/dmaengine/provider.rst index 814acb4d2294..dfc4486b5743 100644 --- a/Documentation/driver-api/dmaengine/provider.rst +++ b/Documentation/driver-api/dmaengine/provider.rst @@ -111,40 +111,36 @@ The first thing you need to do in your driver is to allocate this structure. Any of the usual memory allocators will do, but you'll also need to initialize a few fields in there: -- channels: should be initialized as a list using the +- ``channels``: should be initialized as a list using the INIT_LIST_HEAD macro for example -- src_addr_widths: +- ``src_addr_widths``: should contain a bitmask of the supported source transfer width -- dst_addr_widths: +- ``dst_addr_widths``: should contain a bitmask of the supported destination transfer width -- directions: +- ``directions``: should contain a bitmask of the supported slave directions (i.e. excluding mem2mem transfers) -- residue_granularity: +- ``residue_granularity``: + granularity of the transfer residue reported to dma_set_residue. + This can be either: - - Granularity of the transfer residue reported to dma_set_residue. - This can be either: + - Descriptor: + your device doesn't support any kind of residue + reporting. The framework will only know that a particular + transaction descriptor is done. - - Descriptor + - Segment: + your device is able to report which chunks have been transferred - - Your device doesn't support any kind of residue - reporting. The framework will only know that a particular - transaction descriptor is done. + - Burst: + your device is able to report which burst have been transferred - - Segment - - - Your device is able to report which chunks have been transferred - - - Burst - - - Your device is able to report which burst have been transferred - - - dev: should hold the pointer to the ``struct device`` associated - to your current driver instance. +- ``dev``: should hold the pointer to the ``struct device`` associated + to your current driver instance. Supported transaction types --------------------------- diff --git a/Documentation/driver-api/firmware/built-in-fw.rst b/Documentation/driver-api/firmware/built-in-fw.rst index 7300e66857f8..396cdf591ac5 100644 --- a/Documentation/driver-api/firmware/built-in-fw.rst +++ b/Documentation/driver-api/firmware/built-in-fw.rst @@ -11,13 +11,8 @@ options: * CONFIG_EXTRA_FIRMWARE * CONFIG_EXTRA_FIRMWARE_DIR -This should not be confused with CONFIG_FIRMWARE_IN_KERNEL, this is for drivers -which enables firmware to be built as part of the kernel build process. This -option, CONFIG_FIRMWARE_IN_KERNEL, will build all firmware for all drivers -enabled which ship its firmware inside the Linux kernel source tree. - There are a few reasons why you might want to consider building your firmware -into the kernel with CONFIG_EXTRA_FIRMWARE though: +into the kernel with CONFIG_EXTRA_FIRMWARE: * Speed * Firmware is needed for accessing the boot device, and the user doesn't diff --git a/Documentation/driver-api/firmware/fallback-mechanisms.rst b/Documentation/driver-api/firmware/fallback-mechanisms.rst index d19354794e67..4055ac76b288 100644 --- a/Documentation/driver-api/firmware/fallback-mechanisms.rst +++ b/Documentation/driver-api/firmware/fallback-mechanisms.rst @@ -71,7 +71,7 @@ via fw_create_instance(). This call creates a new struct device named after the firmware requested, and establishes it in the device hierarchy by associating the device used to make the request as the device's parent. The sysfs directory's file attributes are defined and controlled through -the new device's class (firmare_class) and group (fw_dev_attr_groups). +the new device's class (firmware_class) and group (fw_dev_attr_groups). This is actually where the original firmware_class.c file name comes from, as originally the only firmware loading mechanism available was the mechanism we now use as a fallback mechanism. diff --git a/Documentation/driver-api/iio/hw-consumer.rst b/Documentation/driver-api/iio/hw-consumer.rst new file mode 100644 index 000000000000..8facce6a6733 --- /dev/null +++ b/Documentation/driver-api/iio/hw-consumer.rst @@ -0,0 +1,51 @@ +=========== +HW consumer +=========== +An IIO device can be directly connected to another device in hardware. in this +case the buffers between IIO provider and IIO consumer are handled by hardware. +The Industrial I/O HW consumer offers a way to bond these IIO devices without +software buffer for data. The implementation can be found under +:file:`drivers/iio/buffer/hw-consumer.c` + + +* struct :c:type:`iio_hw_consumer` — Hardware consumer structure +* :c:func:`iio_hw_consumer_alloc` — Allocate IIO hardware consumer +* :c:func:`iio_hw_consumer_free` — Free IIO hardware consumer +* :c:func:`iio_hw_consumer_enable` — Enable IIO hardware consumer +* :c:func:`iio_hw_consumer_disable` — Disable IIO hardware consumer + + +HW consumer setup +================= + +As standard IIO device the implementation is based on IIO provider/consumer. +A typical IIO HW consumer setup looks like this:: + + static struct iio_hw_consumer *hwc; + + static const struct iio_info adc_info = { + .read_raw = adc_read_raw, + }; + + static int adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) + { + ret = iio_hw_consumer_enable(hwc); + + /* Acquire data */ + + ret = iio_hw_consumer_disable(hwc); + } + + static int adc_probe(struct platform_device *pdev) + { + hwc = devm_iio_hw_consumer_alloc(&iio->dev); + } + +More details +============ +.. kernel-doc:: include/linux/iio/hw-consumer.h +.. kernel-doc:: drivers/iio/buffer/industrialio-hw-consumer.c + :export: + diff --git a/Documentation/driver-api/iio/index.rst b/Documentation/driver-api/iio/index.rst index e5c3922d1b6f..7fba341bd8b2 100644 --- a/Documentation/driver-api/iio/index.rst +++ b/Documentation/driver-api/iio/index.rst @@ -15,3 +15,4 @@ Contents: buffers triggers triggered-buffers + hw-consumer diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst index d17a9876b473..e9b41b1634f3 100644 --- a/Documentation/driver-api/index.rst +++ b/Documentation/driver-api/index.rst @@ -47,6 +47,8 @@ available subsections can be seen below. gpio misc_devices dmaengine/index + slimbus + soundwire/index .. only:: subproject and html diff --git a/Documentation/driver-api/pm/devices.rst b/Documentation/driver-api/pm/devices.rst index 53c1b0b06da5..1128705a5731 100644 --- a/Documentation/driver-api/pm/devices.rst +++ b/Documentation/driver-api/pm/devices.rst @@ -777,17 +777,51 @@ The driver can indicate that by setting ``DPM_FLAG_SMART_SUSPEND`` in runtime suspend at the beginning of the ``suspend_late`` phase of system-wide suspend (or in the ``poweroff_late`` phase of hibernation), when runtime PM has been disabled for it, under the assumption that its state should not change -after that point until the system-wide transition is over. If that happens, the -driver's system-wide resume callbacks, if present, may still be invoked during -the subsequent system-wide resume transition and the device's runtime power -management status may be set to "active" before enabling runtime PM for it, -so the driver must be prepared to cope with the invocation of its system-wide -resume callbacks back-to-back with its ``->runtime_suspend`` one (without the -intervening ``->runtime_resume`` and so on) and the final state of the device -must reflect the "active" status for runtime PM in that case. +after that point until the system-wide transition is over (the PM core itself +does that for devices whose "noirq", "late" and "early" system-wide PM callbacks +are executed directly by it). If that happens, the driver's system-wide resume +callbacks, if present, may still be invoked during the subsequent system-wide +resume transition and the device's runtime power management status may be set +to "active" before enabling runtime PM for it, so the driver must be prepared to +cope with the invocation of its system-wide resume callbacks back-to-back with +its ``->runtime_suspend`` one (without the intervening ``->runtime_resume`` and +so on) and the final state of the device must reflect the "active" runtime PM +status in that case. During system-wide resume from a sleep state it's easiest to put devices into the full-power state, as explained in :file:`Documentation/power/runtime_pm.txt`. -Refer to that document for more information regarding this particular issue as +[Refer to that document for more information regarding this particular issue as well as for information on the device runtime power management framework in -general. +general.] + +However, it often is desirable to leave devices in suspend after system +transitions to the working state, especially if those devices had been in +runtime suspend before the preceding system-wide suspend (or analogous) +transition. Device drivers can use the ``DPM_FLAG_LEAVE_SUSPENDED`` flag to +indicate to the PM core (and middle-layer code) that they prefer the specific +devices handled by them to be left suspended and they have no problems with +skipping their system-wide resume callbacks for this reason. Whether or not the +devices will actually be left in suspend may depend on their state before the +given system suspend-resume cycle and on the type of the system transition under +way. In particular, devices are not left suspended if that transition is a +restore from hibernation, as device states are not guaranteed to be reflected +by the information stored in the hibernation image in that case. + +The middle-layer code involved in the handling of the device is expected to +indicate to the PM core if the device may be left in suspend by setting its +:c:member:`power.may_skip_resume` status bit which is checked by the PM core +during the "noirq" phase of the preceding system-wide suspend (or analogous) +transition. The middle layer is then responsible for handling the device as +appropriate in its "noirq" resume callback, which is executed regardless of +whether or not the device is left suspended, but the other resume callbacks +(except for ``->complete``) will be skipped automatically by the PM core if the +device really can be left in suspend. + +For devices whose "noirq", "late" and "early" driver callbacks are invoked +directly by the PM core, all of the system-wide resume callbacks are skipped if +``DPM_FLAG_LEAVE_SUSPENDED`` is set and the device is in runtime suspend during +the ``suspend_noirq`` (or analogous) phase or the transition under way is a +proper system suspend (rather than anything related to hibernation) and the +device's wakeup settings are suitable for runtime PM (that is, it cannot +generate wakeup signals at all or it is allowed to wake up the system from +sleep). diff --git a/Documentation/driver-api/s390-drivers.rst b/Documentation/driver-api/s390-drivers.rst index ecf8851d3565..30e6aa7e160b 100644 --- a/Documentation/driver-api/s390-drivers.rst +++ b/Documentation/driver-api/s390-drivers.rst @@ -22,9 +22,28 @@ While most I/O devices on a s390 system are typically driven through the channel I/O mechanism described here, there are various other methods (like the diag interface). These are out of the scope of this document. +The s390 common I/O layer also provides access to some devices that are +not strictly considered I/O devices. They are considered here as well, +although they are not the focus of this document. + Some additional information can also be found in the kernel source under Documentation/s390/driver-model.txt. +The css bus +=========== + +The css bus contains the subchannels available on the system. They fall +into several categories: + +* Standard I/O subchannels, for use by the system. They have a child + device on the ccw bus and are described below. +* I/O subchannels bound to the vfio-ccw driver. See + Documentation/s390/vfio-ccw.txt. +* Message subchannels. No Linux driver currently exists. +* CHSC subchannels (at most one). The chsc subchannel driver can be used + to send asynchronous chsc commands. +* eADM subchannels. Used for talking to storage class memory. + The ccw bus =========== @@ -102,10 +121,15 @@ ccw group devices Generic interfaces ================== -Some interfaces are available to other drivers that do not necessarily -have anything to do with the busses described above, but still are -indirectly using basic infrastructure in the common I/O layer. One -example is the support for adapter interrupts. +The following section contains interfaces in use not only by drivers +dealing with ccw devices, but drivers for various other s390 hardware +as well. + +Adapter interrupts +------------------ + +The common I/O layer provides helper functions for dealing with adapter +interrupts and interrupt vectors. .. kernel-doc:: drivers/s390/cio/airq.c :export: diff --git a/Documentation/driver-api/scsi.rst b/Documentation/driver-api/scsi.rst index 9ae03171daca..3ae337929721 100644 --- a/Documentation/driver-api/scsi.rst +++ b/Documentation/driver-api/scsi.rst @@ -224,6 +224,14 @@ mid to lowlevel SCSI driver interface .. kernel-doc:: drivers/scsi/hosts.c :export: +drivers/scsi/scsi_common.c +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +general support functions + +.. kernel-doc:: drivers/scsi/scsi_common.c + :export: + Transport classes ----------------- @@ -332,5 +340,5 @@ todo ~~~~ Parallel (fast/wide/ultra) SCSI, USB, SATA, SAS, Fibre Channel, -FireWire, ATAPI devices, Infiniband, I20, iSCSI, Parallel ports, +FireWire, ATAPI devices, Infiniband, I2O, iSCSI, Parallel ports, netlink... diff --git a/Documentation/driver-api/slimbus.rst b/Documentation/driver-api/slimbus.rst new file mode 100644 index 000000000000..7555ecd538de --- /dev/null +++ b/Documentation/driver-api/slimbus.rst @@ -0,0 +1,127 @@ +============================ +Linux kernel SLIMbus support +============================ + +Overview +======== + +What is SLIMbus? +---------------- +SLIMbus (Serial Low Power Interchip Media Bus) is a specification developed by +MIPI (Mobile Industry Processor Interface) alliance. The bus uses master/slave +configuration, and is a 2-wire multi-drop implementation (clock, and data). + +Currently, SLIMbus is used to interface between application processors of SoCs +(System-on-Chip) and peripheral components (typically codec). SLIMbus uses +Time-Division-Multiplexing to accommodate multiple data channels, and +a control channel. + +The control channel is used for various control functions such as bus +management, configuration and status updates. These messages can be unicast (e.g. +reading/writing device specific values), or multicast (e.g. data channel +reconfiguration sequence is a broadcast message announced to all devices) + +A data channel is used for data-transfer between 2 SLIMbus devices. Data +channel uses dedicated ports on the device. + +Hardware description: +--------------------- +SLIMbus specification has different types of device classifications based on +their capabilities. +A manager device is responsible for enumeration, configuration, and dynamic +channel allocation. Every bus has 1 active manager. + +A generic device is a device providing application functionality (e.g. codec). + +Framer device is responsible for clocking the bus, and transmitting frame-sync +and framing information on the bus. + +Each SLIMbus component has an interface device for monitoring physical layer. + +Typically each SoC contains SLIMbus component having 1 manager, 1 framer device, +1 generic device (for data channel support), and 1 interface device. +External peripheral SLIMbus component usually has 1 generic device (for +functionality/data channel support), and an associated interface device. +The generic device's registers are mapped as 'value elements' so that they can +be written/read using SLIMbus control channel exchanging control/status type of +information. +In case there are multiple framer devices on the same bus, manager device is +responsible to select the active-framer for clocking the bus. + +Per specification, SLIMbus uses "clock gears" to do power management based on +current frequency and bandwidth requirements. There are 10 clock gears and each +gear changes the SLIMbus frequency to be twice its previous gear. + +Each device has a 6-byte enumeration-address and the manager assigns every +device with a 1-byte logical address after the devices report presence on the +bus. + +Software description: +--------------------- +There are 2 types of SLIMbus drivers: + +slim_controller represents a 'controller' for SLIMbus. This driver should +implement duties needed by the SoC (manager device, associated +interface device for monitoring the layers and reporting errors, default +framer device). + +slim_device represents the 'generic device/component' for SLIMbus, and a +slim_driver should implement driver for that slim_device. + +Device notifications to the driver: +----------------------------------- +Since SLIMbus devices have mechanisms for reporting their presence, the +framework allows drivers to bind when corresponding devices report their +presence on the bus. +However, it is possible that the driver needs to be probed +first so that it can enable corresponding SLIMbus device (e.g. power it up and/or +take it out of reset). To support that behavior, the framework allows drivers +to probe first as well (e.g. using standard DeviceTree compatibility field). +This creates the necessity for the driver to know when the device is functional +(i.e. reported present). device_up callback is used for that reason when the +device reports present and is assigned a logical address by the controller. + +Similarly, SLIMbus devices 'report absent' when they go down. A 'device_down' +callback notifies the driver when the device reports absent and its logical +address assignment is invalidated by the controller. + +Another notification "boot_device" is used to notify the slim_driver when +controller resets the bus. This notification allows the driver to take necessary +steps to boot the device so that it's functional after the bus has been reset. + +Driver and Controller APIs: +-------------------------- +.. kernel-doc:: include/linux/slimbus.h + :internal: + +.. kernel-doc:: drivers/slimbus/slimbus.h + :internal: + +.. kernel-doc:: drivers/slimbus/core.c + :export: + +Clock-pause: +------------ +SLIMbus mandates that a reconfiguration sequence (known as clock-pause) be +broadcast to all active devices on the bus before the bus can enter low-power +mode. Controller uses this sequence when it decides to enter low-power mode so +that corresponding clocks and/or power-rails can be turned off to save power. +Clock-pause is exited by waking up framer device (if controller driver initiates +exiting low power mode), or by toggling the data line (if a slave device wants +to initiate it). + +Clock-pause APIs: +~~~~~~~~~~~~~~~~~ +.. kernel-doc:: drivers/slimbus/sched.c + :export: + +Messaging: +---------- +The framework supports regmap and read/write apis to exchange control-information +with a SLIMbus device. APIs can be synchronous or asynchronous. +The header file has more documentation about messaging APIs. + +Messaging APIs: +~~~~~~~~~~~~~~~ +.. kernel-doc:: drivers/slimbus/messaging.c + :export: diff --git a/Documentation/driver-api/soundwire/index.rst b/Documentation/driver-api/soundwire/index.rst new file mode 100644 index 000000000000..647e94654752 --- /dev/null +++ b/Documentation/driver-api/soundwire/index.rst @@ -0,0 +1,15 @@ +======================= +SoundWire Documentation +======================= + +.. toctree:: + :maxdepth: 1 + + summary + +.. only:: subproject + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/driver-api/soundwire/summary.rst b/Documentation/driver-api/soundwire/summary.rst new file mode 100644 index 000000000000..8193125a2bfb --- /dev/null +++ b/Documentation/driver-api/soundwire/summary.rst @@ -0,0 +1,207 @@ +=========================== +SoundWire Subsystem Summary +=========================== + +SoundWire is a new interface ratified in 2015 by the MIPI Alliance. +SoundWire is used for transporting data typically related to audio +functions. SoundWire interface is optimized to integrate audio devices in +mobile or mobile inspired systems. + +SoundWire is a 2-pin multi-drop interface with data and clock line. It +facilitates development of low cost, efficient, high performance systems. +Broad level key features of SoundWire interface include: + + (1) Transporting all of payload data channels, control information, and setup + commands over a single two-pin interface. + + (2) Lower clock frequency, and hence lower power consumption, by use of DDR + (Dual Data Rate) data transmission. + + (3) Clock scaling and optional multiple data lanes to give wide flexibility + in data rate to match system requirements. + + (4) Device status monitoring, including interrupt-style alerts to the Master. + +The SoundWire protocol supports up to eleven Slave interfaces. All the +interfaces share the common Bus containing data and clock line. Each of the +Slaves can support up to 14 Data Ports. 13 Data Ports are dedicated to audio +transport. Data Port0 is dedicated to transport of Bulk control information, +each of the audio Data Ports (1..14) can support up to 8 Channels in +transmit or receiving mode (typically fixed direction but configurable +direction is enabled by the specification). Bandwidth restrictions to +~19.2..24.576Mbits/s don't however allow for 11*13*8 channels to be +transmitted simultaneously. + +Below figure shows an example of connectivity between a SoundWire Master and +two Slave devices. :: + + +---------------+ +---------------+ + | | Clock Signal | | + | Master |-------+-------------------------------| Slave | + | Interface | | Data Signal | Interface 1 | + | |-------|-------+-----------------------| | + +---------------+ | | +---------------+ + | | + | | + | | + +--+-------+--+ + | | + | Slave | + | Interface 2 | + | | + +-------------+ + + +Terminology +=========== + +The MIPI SoundWire specification uses the term 'device' to refer to a Master +or Slave interface, which of course can be confusing. In this summary and +code we use the term interface only to refer to the hardware. We follow the +Linux device model by mapping each Slave interface connected on the bus as a +device managed by a specific driver. The Linux SoundWire subsystem provides +a framework to implement a SoundWire Slave driver with an API allowing +3rd-party vendors to enable implementation-defined functionality while +common setup/configuration tasks are handled by the bus. + +Bus: +Implements SoundWire Linux Bus which handles the SoundWire protocol. +Programs all the MIPI-defined Slave registers. Represents a SoundWire +Master. Multiple instances of Bus may be present in a system. + +Slave: +Registers as SoundWire Slave device (Linux Device). Multiple Slave devices +can register to a Bus instance. + +Slave driver: +Driver controlling the Slave device. MIPI-specified registers are controlled +directly by the Bus (and transmitted through the Master driver/interface). +Any implementation-defined Slave register is controlled by Slave driver. In +practice, it is expected that the Slave driver relies on regmap and does not +request direct register access. + +Programming interfaces (SoundWire Master interface Driver) +========================================================== + +SoundWire Bus supports programming interfaces for the SoundWire Master +implementation and SoundWire Slave devices. All the code uses the "sdw" +prefix commonly used by SoC designers and 3rd party vendors. + +Each of the SoundWire Master interfaces needs to be registered to the Bus. +Bus implements API to read standard Master MIPI properties and also provides +callback in Master ops for Master driver to implement its own functions that +provides capabilities information. DT support is not implemented at this +time but should be trivial to add since capabilities are enabled with the +``device_property_`` API. + +The Master interface along with the Master interface capabilities are +registered based on board file, DT or ACPI. + +Following is the Bus API to register the SoundWire Bus: + +.. code-block:: c + + int sdw_add_bus_master(struct sdw_bus *bus) + { + if (!bus->dev) + return -ENODEV; + + mutex_init(&bus->lock); + INIT_LIST_HEAD(&bus->slaves); + + /* Check ACPI for Slave devices */ + sdw_acpi_find_slaves(bus); + + /* Check DT for Slave devices */ + sdw_of_find_slaves(bus); + + return 0; + } + +This will initialize sdw_bus object for Master device. "sdw_master_ops" and +"sdw_master_port_ops" callback functions are provided to the Bus. + +"sdw_master_ops" is used by Bus to control the Bus in the hardware specific +way. It includes Bus control functions such as sending the SoundWire +read/write messages on Bus, setting up clock frequency & Stream +Synchronization Point (SSP). The "sdw_master_ops" structure abstracts the +hardware details of the Master from the Bus. + +"sdw_master_port_ops" is used by Bus to setup the Port parameters of the +Master interface Port. Master interface Port register map is not defined by +MIPI specification, so Bus calls the "sdw_master_port_ops" callback +function to do Port operations like "Port Prepare", "Port Transport params +set", "Port enable and disable". The implementation of the Master driver can +then perform hardware-specific configurations. + +Programming interfaces (SoundWire Slave Driver) +=============================================== + +The MIPI specification requires each Slave interface to expose a unique +48-bit identifier, stored in 6 read-only dev_id registers. This dev_id +identifier contains vendor and part information, as well as a field enabling +to differentiate between identical components. An additional class field is +currently unused. Slave driver is written for a specific vendor and part +identifier, Bus enumerates the Slave device based on these two ids. +Slave device and driver match is done based on these two ids . Probe +of the Slave driver is called by Bus on successful match between device and +driver id. A parent/child relationship is enforced between Master and Slave +devices (the logical representation is aligned with the physical +connectivity). + +The information on Master/Slave dependencies is stored in platform data, +board-file, ACPI or DT. The MIPI Software specification defines additional +link_id parameters for controllers that have multiple Master interfaces. The +dev_id registers are only unique in the scope of a link, and the link_id +unique in the scope of a controller. Both dev_id and link_id are not +necessarily unique at the system level but the parent/child information is +used to avoid ambiguity. + +.. code-block:: c + + static const struct sdw_device_id slave_id[] = { + SDW_SLAVE_ENTRY(0x025d, 0x700, 0), + {}, + }; + MODULE_DEVICE_TABLE(sdw, slave_id); + + static struct sdw_driver slave_sdw_driver = { + .driver = { + .name = "slave_xxx", + .pm = &slave_runtime_pm, + }, + .probe = slave_sdw_probe, + .remove = slave_sdw_remove, + .ops = &slave_slave_ops, + .id_table = slave_id, + }; + + +For capabilities, Bus implements API to read standard Slave MIPI properties +and also provides callback in Slave ops for Slave driver to implement own +function that provides capabilities information. Bus needs to know a set of +Slave capabilities to program Slave registers and to control the Bus +reconfigurations. + +Future enhancements to be done +============================== + + (1) Bulk Register Access (BRA) transfers. + + + (2) Multiple data lane support. + +Links +===== + +SoundWire MIPI specification 1.1 is available at: +https://members.mipi.org/wg/All-Members/document/70290 + +SoundWire MIPI DisCo (Discovery and Configuration) specification is +available at: +https://www.mipi.org/specifications/mipi-disco-soundwire + +(publicly accessible with registration or directly accessible to MIPI +members) + +MIPI Alliance Manufacturer ID Page: mid.mipi.org diff --git a/Documentation/driver-api/uio-howto.rst b/Documentation/driver-api/uio-howto.rst index f73d660b2956..693e3bd84e79 100644 --- a/Documentation/driver-api/uio-howto.rst +++ b/Documentation/driver-api/uio-howto.rst @@ -667,27 +667,28 @@ Making the driver recognize the device Since the driver does not declare any device GUID's, it will not get loaded automatically and will not automatically bind to any devices, you must load it and allocate id to the driver yourself. For example, to use -the network device GUID:: +the network device class GUID:: modprobe uio_hv_generic echo "f8615163-df3e-46c5-913f-f2d2f965ed0e" > /sys/bus/vmbus/drivers/uio_hv_generic/new_id If there already is a hardware specific kernel driver for the device, the generic driver still won't bind to it, in this case if you want to -use the generic driver (why would you?) you'll have to manually unbind -the hardware specific driver and bind the generic driver, like this:: +use the generic driver for a userspace library you'll have to manually unbind +the hardware specific driver and bind the generic driver, using the device specific GUID +like this:: - echo -n vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3 > /sys/bus/vmbus/drivers/hv_netvsc/unbind - echo -n vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3 > /sys/bus/vmbus/drivers/uio_hv_generic/bind + echo -n ed963694-e847-4b2a-85af-bc9cfc11d6f3 > /sys/bus/vmbus/drivers/hv_netvsc/unbind + echo -n ed963694-e847-4b2a-85af-bc9cfc11d6f3 > /sys/bus/vmbus/drivers/uio_hv_generic/bind You can verify that the device has been bound to the driver by looking for it in sysfs, for example like the following:: - ls -l /sys/bus/vmbus/devices/vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3/driver + ls -l /sys/bus/vmbus/devices/ed963694-e847-4b2a-85af-bc9cfc11d6f3/driver Which if successful should print:: - .../vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3/driver -> ../../../bus/vmbus/drivers/uio_hv_generic + .../ed963694-e847-4b2a-85af-bc9cfc11d6f3/driver -> ../../../bus/vmbus/drivers/uio_hv_generic Things to know about uio_hv_generic ----------------------------------- @@ -697,6 +698,17 @@ prevents the device from generating further interrupts until the bit is cleared. The userspace driver should clear this bit before blocking and waiting for more interrupts. +When host rescinds a device, the interrupt file descriptor is marked down +and any reads of the interrupt file descriptor will return -EIO. Similar +to a closed socket or disconnected serial device. + +The vmbus device regions are mapped into uio device resources: + 0) Channel ring buffers: guest to host and host to guest + 1) Guest to host interrupt signalling pages + 2) Guest to host monitor page + 3) Network receive buffer region + 4) Network send buffer region + Further information =================== diff --git a/Documentation/driver-api/usb/usb3-debug-port.rst b/Documentation/driver-api/usb/usb3-debug-port.rst index feb1a36a65b7..b9fd131f4723 100644 --- a/Documentation/driver-api/usb/usb3-debug-port.rst +++ b/Documentation/driver-api/usb/usb3-debug-port.rst @@ -98,3 +98,55 @@ you to check the sanity of the setup. cat /dev/ttyUSB0 done ===== end of bash scripts =============== + +Serial TTY +========== + +The DbC support has been added to the xHCI driver. You can get a +debug device provided by the DbC at runtime. + +In order to use this, you need to make sure your kernel has been +configured to support USB_XHCI_DBGCAP. A sysfs attribute under +the xHCI device node is used to enable or disable DbC. By default, +DbC is disabled:: + + root@target:/sys/bus/pci/devices/0000:00:14.0# cat dbc + disabled + +Enable DbC with the following command:: + + root@target:/sys/bus/pci/devices/0000:00:14.0# echo enable > dbc + +You can check the DbC state at anytime:: + + root@target:/sys/bus/pci/devices/0000:00:14.0# cat dbc + enabled + +Connect the debug target to the debug host with a USB 3.0 super- +speed A-to-A debugging cable. You can see /dev/ttyDBC0 created +on the debug target. You will see below kernel message lines:: + + root@target: tail -f /var/log/kern.log + [ 182.730103] xhci_hcd 0000:00:14.0: DbC connected + [ 191.169420] xhci_hcd 0000:00:14.0: DbC configured + [ 191.169597] xhci_hcd 0000:00:14.0: DbC now attached to /dev/ttyDBC0 + +Accordingly, the DbC state has been brought up to:: + + root@target:/sys/bus/pci/devices/0000:00:14.0# cat dbc + configured + +On the debug host, you will see the debug device has been enumerated. +You will see below kernel message lines:: + + root@host: tail -f /var/log/kern.log + [ 79.454780] usb 2-2.1: new SuperSpeed USB device number 3 using xhci_hcd + [ 79.475003] usb 2-2.1: LPM exit latency is zeroed, disabling LPM. + [ 79.475389] usb 2-2.1: New USB device found, idVendor=1d6b, idProduct=0010 + [ 79.475390] usb 2-2.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 + [ 79.475391] usb 2-2.1: Product: Linux USB Debug Target + [ 79.475392] usb 2-2.1: Manufacturer: Linux Foundation + [ 79.475393] usb 2-2.1: SerialNumber: 0001 + +The debug device works now. You can use any communication or debugging +program to talk between the host and the target. diff --git a/Documentation/driver-api/usb/writing_usb_driver.rst b/Documentation/driver-api/usb/writing_usb_driver.rst index 69f077dcdb78..4fe1c06b6a13 100644 --- a/Documentation/driver-api/usb/writing_usb_driver.rst +++ b/Documentation/driver-api/usb/writing_usb_driver.rst @@ -321,6 +321,6 @@ linux-usb-devel Mailing List Archives: http://marc.theaimsgroup.com/?l=linux-usb-devel Programming Guide for Linux USB Device Drivers: -http://usb.cs.tum.edu/usbdoc +http://lmu.web.psi.ch/docu/manuals/software_manuals/linux_sl/usb_linux_programming_guide.pdf USB Home Page: http://www.usb.org diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index c180045eb43b..7c1bb3d0c222 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -384,6 +384,9 @@ RESET devm_reset_control_get() devm_reset_controller_register() +SERDEV + devm_serdev_device_open() + SLAVE DMA ENGINE devm_acpi_dma_controller_register() diff --git a/Documentation/fault-injection/fault-injection.txt b/Documentation/fault-injection/fault-injection.txt index 918972babcd8..de1dc35fe500 100644 --- a/Documentation/fault-injection/fault-injection.txt +++ b/Documentation/fault-injection/fault-injection.txt @@ -1,7 +1,7 @@ Fault injection capabilities infrastructure =========================================== -See also drivers/md/faulty.c and "every_nth" module option for scsi_debug. +See also drivers/md/md-faulty.c and "every_nth" module option for scsi_debug. Available fault injection capabilities @@ -30,6 +30,12 @@ o fail_mmc_request injects MMC data errors on devices permitted by setting debugfs entries under /sys/kernel/debug/mmc0/fail_mmc_request +o fail_function + + injects error return on specific functions, which are marked by + ALLOW_ERROR_INJECTION() macro, by setting debugfs entries + under /sys/kernel/debug/fail_function. No boot option supported. + Configure fault-injection capabilities behavior ----------------------------------------------- @@ -123,6 +129,29 @@ configuration of fault-injection capabilities. default is 'N', setting it to 'Y' will disable failure injections when dealing with private (address space) futexes. +- /sys/kernel/debug/fail_function/inject: + + Format: { 'function-name' | '!function-name' | '' } + specifies the target function of error injection by name. + If the function name leads '!' prefix, given function is + removed from injection list. If nothing specified ('') + injection list is cleared. + +- /sys/kernel/debug/fail_function/injectable: + + (read only) shows error injectable functions and what type of + error values can be specified. The error type will be one of + below; + - NULL: retval must be 0. + - ERRNO: retval must be -1 to -MAX_ERRNO (-4096). + - ERR_NULL: retval must be 0 or -1 to -MAX_ERRNO (-4096). + +- /sys/kernel/debug/fail_function//retval: + + specifies the "error" return value to inject to the given + function for given function. This will be created when + user specifies new injection entry. + o Boot option In order to inject faults while debugfs is not available (early boot time), @@ -268,6 +297,45 @@ trap "echo 0 > /sys/kernel/debug/$FAILTYPE/probability" SIGINT SIGTERM EXIT echo "Injecting errors into the module $module... (interrupt to stop)" sleep 1000000 +------------------------------------------------------------------------------ + +o Inject open_ctree error while btrfs mount + +#!/bin/bash + +rm -f testfile.img +dd if=/dev/zero of=testfile.img bs=1M seek=1000 count=1 +DEVICE=$(losetup --show -f testfile.img) +mkfs.btrfs -f $DEVICE +mkdir -p tmpmnt + +FAILTYPE=fail_function +FAILFUNC=open_ctree +echo $FAILFUNC > /sys/kernel/debug/$FAILTYPE/inject +echo -12 > /sys/kernel/debug/$FAILTYPE/$FAILFUNC/retval +echo N > /sys/kernel/debug/$FAILTYPE/task-filter +echo 100 > /sys/kernel/debug/$FAILTYPE/probability +echo 0 > /sys/kernel/debug/$FAILTYPE/interval +echo -1 > /sys/kernel/debug/$FAILTYPE/times +echo 0 > /sys/kernel/debug/$FAILTYPE/space +echo 1 > /sys/kernel/debug/$FAILTYPE/verbose + +mount -t btrfs $DEVICE tmpmnt +if [ $? -ne 0 ] +then + echo "SUCCESS!" +else + echo "FAILED!" + umount tmpmnt +fi + +echo > /sys/kernel/debug/$FAILTYPE/inject + +rmdir tmpmnt +losetup -d $DEVICE +rm testfile.img + + Tool to run command with failslab or fail_page_alloc ---------------------------------------------------- In order to make it easier to accomplish the tasks mentioned above, we can use diff --git a/Documentation/features/debug/KASAN/arch-support.txt b/Documentation/features/debug/KASAN/arch-support.txt index f377290fe48e..3406fae833c3 100644 --- a/Documentation/features/debug/KASAN/arch-support.txt +++ b/Documentation/features/debug/KASAN/arch-support.txt @@ -35,5 +35,5 @@ | um: | TODO | | unicore32: | TODO | | x86: | ok | 64-bit only - | xtensa: | TODO | + | xtensa: | ok | ----------------------- diff --git a/Documentation/features/debug/stackprotector/arch-support.txt b/Documentation/features/debug/stackprotector/arch-support.txt index d7acd7bd3619..59a4c9ffb7f3 100644 --- a/Documentation/features/debug/stackprotector/arch-support.txt +++ b/Documentation/features/debug/stackprotector/arch-support.txt @@ -35,5 +35,5 @@ | um: | TODO | | unicore32: | TODO | | x86: | ok | - | xtensa: | TODO | + | xtensa: | ok | ----------------------- diff --git a/Documentation/filesystems/afs.txt b/Documentation/filesystems/afs.txt index ba99b5ac4fd8..c5254f6d234d 100644 --- a/Documentation/filesystems/afs.txt +++ b/Documentation/filesystems/afs.txt @@ -7,6 +7,7 @@ Contents: - Overview. - Usage. - Mountpoints. + - Dynamic root. - Proc filesystem. - The cell database. - Security. @@ -127,6 +128,22 @@ mounted on /afs in one go by doing: umount /afs +============ +DYNAMIC ROOT +============ + +A mount option is available to create a serverless mount that is only usable +for dynamic lookup. Creating such a mount can be done by, for example: + + mount -t afs none /afs -o dyn + +This creates a mount that just has an empty directory at the root. Attempting +to look up a name in this directory will cause a mountpoint to be created that +looks up a cell of the same name, for example: + + ls /afs/grand.central.org/ + + =============== PROC FILESYSTEM =============== diff --git a/Documentation/filesystems/dax.txt b/Documentation/filesystems/dax.txt index 3be3b266be41..70cb68bed2e8 100644 --- a/Documentation/filesystems/dax.txt +++ b/Documentation/filesystems/dax.txt @@ -46,7 +46,6 @@ stall the CPU for an extended period, you should also not attempt to implement direct_access. These block devices may be used for inspiration: -- axonram: Axon DDR2 device driver - brd: RAM backed block device driver - dcssblk: s390 dcss block device driver - pmem: NVDIMM persistent memory driver diff --git a/Documentation/filesystems/ext2.txt b/Documentation/filesystems/ext2.txt index 55755395d3dc..81c0becab225 100644 --- a/Documentation/filesystems/ext2.txt +++ b/Documentation/filesystems/ext2.txt @@ -49,12 +49,10 @@ sb=n Use alternate superblock at this location. user_xattr Enable "user." POSIX Extended Attributes (requires CONFIG_EXT2_FS_XATTR). - See also http://acl.bestbits.at nouser_xattr Don't support "user." extended attributes. acl Enable POSIX Access Control Lists support (requires CONFIG_EXT2_FS_POSIX_ACL). - See also http://acl.bestbits.at noacl Don't support POSIX ACLs. nobh Do not attach buffer_heads to file pagecache. diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt index 75236c0c2ac2..7f628b9f7c4b 100644 --- a/Documentation/filesystems/ext4.txt +++ b/Documentation/filesystems/ext4.txt @@ -202,15 +202,14 @@ inode_readahead_blks=n This tuning parameter controls the maximum the buffer cache. The default value is 32 blocks. nouser_xattr Disables Extended User Attributes. See the - attr(5) manual page and http://acl.bestbits.at/ - for more information about extended attributes. + attr(5) manual page for more information about + extended attributes. noacl This option disables POSIX Access Control List support. If ACL support is enabled in the kernel configuration (CONFIG_EXT4_FS_POSIX_ACL), ACL is enabled by default on mount. See the acl(5) manual - page and http://acl.bestbits.at/ for more information - about acl. + page for more information about acl. bsddf (*) Make 'df' act like BSD. minixdf Make 'df' act like Minix. @@ -233,7 +232,7 @@ data_err=ignore(*) Just print an error message if an error occurs data_err=abort Abort the journal if an error occurs in a file data buffer in ordered mode. -grpid Give objects the same group ID as their creator. +grpid New objects have the group ID of their parent. bsdgroups nogrpid (*) New objects have the group ID of their creator. diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst index 776ddc655f79..cfbc18f0d9c9 100644 --- a/Documentation/filesystems/fscrypt.rst +++ b/Documentation/filesystems/fscrypt.rst @@ -448,8 +448,14 @@ astute users may notice some differences in behavior: - The st_size of an encrypted symlink will not necessarily give the length of the symlink target as required by POSIX. It will actually - give the length of the ciphertext, which may be slightly longer than - the plaintext due to the NUL-padding. + give the length of the ciphertext, which will be slightly longer + than the plaintext due to NUL-padding and an extra 2-byte overhead. + +- The maximum length of an encrypted symlink is 2 bytes shorter than + the maximum length of an unencrypted symlink. For example, on an + EXT4 filesystem with a 4K block size, unencrypted symlinks can be up + to 4095 bytes long, while encrypted symlinks can only be up to 4093 + bytes long (both lengths excluding the terminating null). Note that mmap *is* supported. This is possible because the pagecache for an encrypted file contains the plaintext, not the ciphertext. diff --git a/Documentation/filesystems/nfs/Exporting b/Documentation/filesystems/nfs/Exporting index 520a4becb75c..63889149f532 100644 --- a/Documentation/filesystems/nfs/Exporting +++ b/Documentation/filesystems/nfs/Exporting @@ -56,13 +56,25 @@ a/ A dentry flag DCACHE_DISCONNECTED which is set on any dentry that might not be part of the proper prefix. This is set when anonymous dentries are created, and cleared when a dentry is noticed to be a child of a dentry which is in the proper - prefix. + prefix. If the refcount on a dentry with this flag set + becomes zero, the dentry is immediately discarded, rather than being + kept in the dcache. If a dentry that is not already in the dcache + is repeatedly accessed by filehandle (as NFSD might do), an new dentry + will be a allocated for each access, and discarded at the end of + the access. -b/ A per-superblock list "s_anon" of dentries which are the roots of - subtrees that are not in the proper prefix. These dentries, as - well as the proper prefix, need to be released at unmount time. As - these dentries will not be hashed, they are linked together on the - d_hash list_head. + Note that such a dentry can acquire children, name, ancestors, etc. + without losing DCACHE_DISCONNECTED - that flag is only cleared when + subtree is successfully reconnected to root. Until then dentries + in such subtree are retained only as long as there are references; + refcount reaching zero means immediate eviction, same as for unhashed + dentries. That guarantees that we won't need to hunt them down upon + umount. + +b/ A primitive for creation of secondary roots - d_obtain_root(inode). + Those do _not_ bear DCACHE_DISCONNECTED. They are placed on the + per-superblock list (->s_roots), so they can be located at umount + time for eviction purposes. c/ Helper routines to allocate anonymous dentries, and to help attach loose directory dentries at lookup time. They are: @@ -77,7 +89,6 @@ c/ Helper routines to allocate anonymous dentries, and to help attach (such as an anonymous one created by d_obtain_alias), if appropriate. It returns NULL when the passed-in dentry is used, following the calling convention of ->lookup. - Filesystem Issues ----------------- diff --git a/Documentation/filesystems/overlayfs.txt b/Documentation/filesystems/overlayfs.txt index e6a5f4912b6d..6ea1e64d1464 100644 --- a/Documentation/filesystems/overlayfs.txt +++ b/Documentation/filesystems/overlayfs.txt @@ -190,6 +190,20 @@ Mount options: Redirects are not created and not followed (equivalent to "redirect_dir=off" if "redirect_always_follow" feature is not enabled). +When the NFS export feature is enabled, every copied up directory is +indexed by the file handle of the lower inode and a file handle of the +upper directory is stored in a "trusted.overlay.upper" extended attribute +on the index entry. On lookup of a merged directory, if the upper +directory does not match the file handle stores in the index, that is an +indication that multiple upper directories may be redirected to the same +lower directory. In that case, lookup returns an error and warns about +a possible inconsistency. + +Because lower layer redirects cannot be verified with the index, enabling +NFS export support on an overlay filesystem with no upper layer requires +turning off redirect follow (e.g. "redirect_dir=nofollow"). + + Non-directories --------------- @@ -281,9 +295,9 @@ filesystem, so both st_dev and st_ino of the file may change. Any open files referring to this inode will access the old data. -If a file with multiple hard links is copied up, then this will -"break" the link. Changes will not be propagated to other names -referring to the same inode. +Unless "inode index" feature is enabled, if a file with multiple hard +links is copied up, then this will "break" the link. Changes will not be +propagated to other names referring to the same inode. Unless "redirect_dir" feature is enabled, rename(2) on a lower or merged directory will fail with EXDEV. @@ -299,6 +313,92 @@ filesystem are not allowed. If the underlying filesystem is changed, the behavior of the overlay is undefined, though it will not result in a crash or deadlock. +When the overlay NFS export feature is enabled, overlay filesystems +behavior on offline changes of the underlying lower layer is different +than the behavior when NFS export is disabled. + +On every copy_up, an NFS file handle of the lower inode, along with the +UUID of the lower filesystem, are encoded and stored in an extended +attribute "trusted.overlay.origin" on the upper inode. + +When the NFS export feature is enabled, a lookup of a merged directory, +that found a lower directory at the lookup path or at the path pointed +to by the "trusted.overlay.redirect" extended attribute, will verify +that the found lower directory file handle and lower filesystem UUID +match the origin file handle that was stored at copy_up time. If a +found lower directory does not match the stored origin, that directory +will not be merged with the upper directory. + + + +NFS export +---------- + +When the underlying filesystems supports NFS export and the "nfs_export" +feature is enabled, an overlay filesystem may be exported to NFS. + +With the "nfs_export" feature, on copy_up of any lower object, an index +entry is created under the index directory. The index entry name is the +hexadecimal representation of the copy up origin file handle. For a +non-directory object, the index entry is a hard link to the upper inode. +For a directory object, the index entry has an extended attribute +"trusted.overlay.upper" with an encoded file handle of the upper +directory inode. + +When encoding a file handle from an overlay filesystem object, the +following rules apply: + +1. For a non-upper object, encode a lower file handle from lower inode +2. For an indexed object, encode a lower file handle from copy_up origin +3. For a pure-upper object and for an existing non-indexed upper object, + encode an upper file handle from upper inode + +The encoded overlay file handle includes: + - Header including path type information (e.g. lower/upper) + - UUID of the underlying filesystem + - Underlying filesystem encoding of underlying inode + +This encoding format is identical to the encoding format file handles that +are stored in extended attribute "trusted.overlay.origin". + +When decoding an overlay file handle, the following steps are followed: + +1. Find underlying layer by UUID and path type information. +2. Decode the underlying filesystem file handle to underlying dentry. +3. For a lower file handle, lookup the handle in index directory by name. +4. If a whiteout is found in index, return ESTALE. This represents an + overlay object that was deleted after its file handle was encoded. +5. For a non-directory, instantiate a disconnected overlay dentry from the + decoded underlying dentry, the path type and index inode, if found. +6. For a directory, use the connected underlying decoded dentry, path type + and index, to lookup a connected overlay dentry. + +Decoding a non-directory file handle may return a disconnected dentry. +copy_up of that disconnected dentry will create an upper index entry with +no upper alias. + +When overlay filesystem has multiple lower layers, a middle layer +directory may have a "redirect" to lower directory. Because middle layer +"redirects" are not indexed, a lower file handle that was encoded from the +"redirect" origin directory, cannot be used to find the middle or upper +layer directory. Similarly, a lower file handle that was encoded from a +descendant of the "redirect" origin directory, cannot be used to +reconstruct a connected overlay path. To mitigate the cases of +directories that cannot be decoded from a lower file handle, these +directories are copied up on encode and encoded as an upper file handle. +On an overlay filesystem with no upper layer this mitigation cannot be +used NFS export in this setup requires turning off redirect follow (e.g. +"redirect_dir=nofollow"). + +The overlay filesystem does not support non-directory connectable file +handles, so exporting with the 'subtree_check' exportfs configuration will +cause failures to lookup files over NFS. + +When the NFS export feature is enabled, all directory index entries are +verified on mount time to check that upper file handles are not stale. +This verification may cause significant overhead in some cases. + + Testsuite --------- diff --git a/Documentation/filesystems/sysfs.txt b/Documentation/filesystems/sysfs.txt index 9a3658cc399e..a1426cabcef1 100644 --- a/Documentation/filesystems/sysfs.txt +++ b/Documentation/filesystems/sysfs.txt @@ -154,8 +154,8 @@ static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, if (dev_attr->show) ret = dev_attr->show(dev, dev_attr, buf); if (ret >= (ssize_t)PAGE_SIZE) { - print_symbol("dev_attr_show: %s returned bad count\n", - (unsigned long)dev_attr->show); + printk("dev_attr_show: %pS returned bad count\n", + dev_attr->show); } return ret; } diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt index cf51360e3a9f..91031298beb1 100644 --- a/Documentation/filesystems/vfat.txt +++ b/Documentation/filesystems/vfat.txt @@ -344,4 +344,4 @@ the following: characters in the final slot are set to Unicode 0xFFFF. Finally, note that the extended name is stored in Unicode. Each Unicode -character takes two bytes. +character takes either two or four bytes, UTF-16LE encoded. diff --git a/Documentation/fpga/fpga-mgr.txt b/Documentation/fpga/fpga-mgr.txt index 78f197fadfd1..cc6413ed6fc9 100644 --- a/Documentation/fpga/fpga-mgr.txt +++ b/Documentation/fpga/fpga-mgr.txt @@ -11,61 +11,65 @@ hidden away in a low level driver which registers a set of ops with the core. The FPGA image data itself is very manufacturer specific, but for our purposes it's just binary data. The FPGA manager core won't parse it. +The FPGA image to be programmed can be in a scatter gather list, a single +contiguous buffer, or a firmware file. Because allocating contiguous kernel +memory for the buffer should be avoided, users are encouraged to use a scatter +gather list instead if possible. + +The particulars for programming the image are presented in a structure (struct +fpga_image_info). This struct contains parameters such as pointers to the +FPGA image as well as image-specific particulars such as whether the image was +built for full or partial reconfiguration. API Functions: ============== -To program the FPGA from a file or from a buffer: -------------------------------------------------- +To program the FPGA: +-------------------- - int fpga_mgr_buf_load(struct fpga_manager *mgr, - struct fpga_image_info *info, - const char *buf, size_t count); + int fpga_mgr_load(struct fpga_manager *mgr, + struct fpga_image_info *info); -Load the FPGA from an image which exists as a contiguous buffer in -memory. Allocating contiguous kernel memory for the buffer should be avoided, -users are encouraged to use the _sg interface instead of this. - - int fpga_mgr_buf_load_sg(struct fpga_manager *mgr, - struct fpga_image_info *info, - struct sg_table *sgt); - -Load the FPGA from an image from non-contiguous in memory. Callers can -construct a sg_table using alloc_page backed memory. - - int fpga_mgr_firmware_load(struct fpga_manager *mgr, - struct fpga_image_info *info, - const char *image_name); - -Load the FPGA from an image which exists as a file. The image file must be on -the firmware search path (see the firmware class documentation). If successful, +Load the FPGA from an image which is indicated in the info. If successful, the FPGA ends up in operating mode. Return 0 on success or a negative error code. -A FPGA design contained in a FPGA image file will likely have particulars that -affect how the image is programmed to the FPGA. These are contained in struct -fpga_image_info. Currently the only such particular is a single flag bit -indicating whether the image is for full or partial reconfiguration. +To allocate or free a struct fpga_image_info: +--------------------------------------------- + + struct fpga_image_info *fpga_image_info_alloc(struct device *dev); + + void fpga_image_info_free(struct fpga_image_info *info); To get/put a reference to a FPGA manager: ----------------------------------------- struct fpga_manager *of_fpga_mgr_get(struct device_node *node); struct fpga_manager *fpga_mgr_get(struct device *dev); - -Given a DT node or device, get an exclusive reference to a FPGA manager. - void fpga_mgr_put(struct fpga_manager *mgr); -Release the reference. +Given a DT node or device, get a reference to a FPGA manager. This pointer +can be saved until you are ready to program the FPGA. fpga_mgr_put releases +the reference. + + +To get exclusive control of a FPGA manager: +------------------------------------------- + + int fpga_mgr_lock(struct fpga_manager *mgr); + void fpga_mgr_unlock(struct fpga_manager *mgr); + +The user should call fpga_mgr_lock and verify that it returns 0 before +attempting to program the FPGA. Likewise, the user should call +fpga_mgr_unlock when done programming the FPGA. To register or unregister the low level FPGA-specific driver: ------------------------------------------------------------- int fpga_mgr_register(struct device *dev, const char *name, - const struct fpga_manager_ops *mops, - void *priv); + const struct fpga_manager_ops *mops, + void *priv); void fpga_mgr_unregister(struct device *dev); @@ -75,62 +79,58 @@ device." How to write an image buffer to a supported FPGA ================================================ -/* Include to get the API */ #include -/* device node that specifies the FPGA manager to use */ -struct device_node *mgr_node = ... - -/* FPGA image is in this buffer. count is size of the buffer. */ -char *buf = ... -int count = ... - -/* struct with information about the FPGA image to program. */ -struct fpga_image_info info; - -/* flags indicates whether to do full or partial reconfiguration */ -info.flags = 0; - +struct fpga_manager *mgr; +struct fpga_image_info *info; int ret; +/* + * Get a reference to FPGA manager. The manager is not locked, so you can + * hold onto this reference without it preventing programming. + * + * This example uses the device node of the manager. Alternatively, use + * fpga_mgr_get(dev) instead if you have the device. + */ +mgr = of_fpga_mgr_get(mgr_node); + +/* struct with information about the FPGA image to program. */ +info = fpga_image_info_alloc(dev); + +/* flags indicates whether to do full or partial reconfiguration */ +info->flags = FPGA_MGR_PARTIAL_RECONFIG; + +/* + * At this point, indicate where the image is. This is pseudo-code; you're + * going to use one of these three. + */ +if (image is in a scatter gather table) { + + info->sgt = [your scatter gather table] + +} else if (image is in a buffer) { + + info->buf = [your image buffer] + info->count = [image buffer size] + +} else if (image is in a firmware file) { + + info->firmware_name = devm_kstrdup(dev, firmware_name, GFP_KERNEL); + +} + /* Get exclusive control of FPGA manager */ -struct fpga_manager *mgr = of_fpga_mgr_get(mgr_node); +ret = fpga_mgr_lock(mgr); /* Load the buffer to the FPGA */ ret = fpga_mgr_buf_load(mgr, &info, buf, count); /* Release the FPGA manager */ +fpga_mgr_unlock(mgr); fpga_mgr_put(mgr); - -How to write an image file to a supported FPGA -============================================== -/* Include to get the API */ -#include - -/* device node that specifies the FPGA manager to use */ -struct device_node *mgr_node = ... - -/* FPGA image is in this file which is in the firmware search path */ -const char *path = "fpga-image-9.rbf" - -/* struct with information about the FPGA image to program. */ -struct fpga_image_info info; - -/* flags indicates whether to do full or partial reconfiguration */ -info.flags = 0; - -int ret; - -/* Get exclusive control of FPGA manager */ -struct fpga_manager *mgr = of_fpga_mgr_get(mgr_node); - -/* Get the firmware image (path) and load it to the FPGA */ -ret = fpga_mgr_firmware_load(mgr, &info, path); - -/* Release the FPGA manager */ -fpga_mgr_put(mgr); - +/* Deallocate the image info if you're done with it */ +fpga_image_info_free(info); How to support a new FPGA device ================================ diff --git a/Documentation/fpga/fpga-region.txt b/Documentation/fpga/fpga-region.txt new file mode 100644 index 000000000000..139a02ba1ff6 --- /dev/null +++ b/Documentation/fpga/fpga-region.txt @@ -0,0 +1,95 @@ +FPGA Regions + +Alan Tull 2017 + +CONTENTS + - Introduction + - The FPGA region API + - Usage example + +Introduction +============ + +This document is meant to be an brief overview of the FPGA region API usage. A +more conceptual look at regions can be found in [1]. + +For the purposes of this API document, let's just say that a region associates +an FPGA Manager and a bridge (or bridges) with a reprogrammable region of an +FPGA or the whole FPGA. The API provides a way to register a region and to +program a region. + +Currently the only layer above fpga-region.c in the kernel is the Device Tree +support (of-fpga-region.c) described in [1]. The DT support layer uses regions +to program the FPGA and then DT to handle enumeration. The common region code +is intended to be used by other schemes that have other ways of accomplishing +enumeration after programming. + +An fpga-region can be set up to know the following things: +* which FPGA manager to use to do the programming +* which bridges to disable before programming and enable afterwards. + +Additional info needed to program the FPGA image is passed in the struct +fpga_image_info [2] including: +* pointers to the image as either a scatter-gather buffer, a contiguous + buffer, or the name of firmware file +* flags indicating specifics such as whether the image if for partial + reconfiguration. + +=================== +The FPGA region API +=================== + +To register or unregister a region: +----------------------------------- + + int fpga_region_register(struct device *dev, + struct fpga_region *region); + int fpga_region_unregister(struct fpga_region *region); + +An example of usage can be seen in the probe function of [3] + +To program an FPGA: +------------------- + int fpga_region_program_fpga(struct fpga_region *region); + +This function operates on info passed in the fpga_image_info +(region->info). + +This function will attempt to: + * lock the region's mutex + * lock the region's FPGA manager + * build a list of FPGA bridges if a method has been specified to do so + * disable the bridges + * program the FPGA + * re-enable the bridges + * release the locks + +============= +Usage example +============= + +First, allocate the info struct: + + info = fpga_image_info_alloc(dev); + if (!info) + return -ENOMEM; + +Set flags as needed, i.e. + + info->flags |= FPGA_MGR_PARTIAL_RECONFIG; + +Point to your FPGA image, such as: + + info->sgt = &sgt; + +Add info to region and do the programming: + + region->info = info; + ret = fpga_region_program_fpga(region); + +Then enumerate whatever hardware has appeared in the FPGA. + +-- +[1] ../devicetree/bindings/fpga/fpga-region.txt +[2] ./fpga-mgr.txt +[3] ../../drivers/fpga/of-fpga-region.c diff --git a/Documentation/fpga/overview.txt b/Documentation/fpga/overview.txt new file mode 100644 index 000000000000..0f1236e7e675 --- /dev/null +++ b/Documentation/fpga/overview.txt @@ -0,0 +1,23 @@ +Linux kernel FPGA support + +Alan Tull 2017 + +The main point of this project has been to separate the out the upper layers +that know when to reprogram a FPGA from the lower layers that know how to +reprogram a specific FPGA device. The intention is to make this manufacturer +agnostic, understanding that of course the FPGA images are very device specific +themselves. + +The framework in the kernel includes: +* low level FPGA manager drivers that know how to program a specific device +* the fpga-mgr framework they are registered with +* low level FPGA bridge drivers for hard/soft bridges which are intended to + be disable during FPGA programming +* the fpga-bridge framework they are registered with +* the fpga-region framework which associates and controls managers and bridges + as reconfigurable regions +* the of-fpga-region support for reprogramming FPGAs when device tree overlays + are applied. + +I would encourage you the user to add code that creates FPGA regions rather +that trying to control managers and bridges separately. diff --git a/Documentation/gpio/board.txt b/Documentation/gpio/board.txt index a0f61898d493..659bb19f5b3c 100644 --- a/Documentation/gpio/board.txt +++ b/Documentation/gpio/board.txt @@ -2,6 +2,7 @@ GPIO Mappings ============= This document explains how GPIOs can be assigned to given devices and functions. + Note that it only applies to the new descriptor-based interface. For a description of the deprecated integer-based GPIO interface please refer to gpio-legacy.txt (actually, there is no real mapping possible with the old @@ -49,7 +50,7 @@ This property will make GPIOs 15, 16 and 17 available to the driver under the power = gpiod_get(dev, "power", GPIOD_OUT_HIGH); -The led GPIOs will be active-high, while the power GPIO will be active-low (i.e. +The led GPIOs will be active high, while the power GPIO will be active low (i.e. gpiod_is_active_low(power) will be true). The second parameter of the gpiod_get() functions, the con_id string, has to be @@ -122,9 +123,14 @@ where can be NULL, in which case it will match any function. - idx is the index of the GPIO within the function. - flags is defined to specify the following properties: - * GPIOF_ACTIVE_LOW - to configure the GPIO as active-low - * GPIOF_OPEN_DRAIN - GPIO pin is open drain type. - * GPIOF_OPEN_SOURCE - GPIO pin is open source type. + * GPIO_ACTIVE_HIGH - GPIO line is active high + * GPIO_ACTIVE_LOW - GPIO line is active low + * GPIO_OPEN_DRAIN - GPIO line is set up as open drain + * GPIO_OPEN_SOURCE - GPIO line is set up as open source + * GPIO_PERSISTENT - GPIO line is persistent during + suspend/resume and maintains its value + * GPIO_TRANSITORY - GPIO line is transitory and may loose its + electrical state during suspend/resume In the future, these flags might be extended to support more properties. diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt index 63e1bd1d88e3..d53e5b5cfc9c 100644 --- a/Documentation/gpio/consumer.txt +++ b/Documentation/gpio/consumer.txt @@ -66,6 +66,15 @@ for the GPIO. Values can be: * GPIOD_IN to initialize the GPIO as input. * GPIOD_OUT_LOW to initialize the GPIO as output with a value of 0. * GPIOD_OUT_HIGH to initialize the GPIO as output with a value of 1. +* GPIOD_OUT_LOW_OPEN_DRAIN same as GPIOD_OUT_LOW but also enforce the line + to be electrically used with open drain. +* GPIOD_OUT_HIGH_OPEN_DRAIN same as GPIOD_OUT_HIGH but also enforce the line + to be electrically used with open drain. + +The two last flags are used for use cases where open drain is mandatory, such +as I2C: if the line is not already configured as open drain in the mappings +(see board.txt), then open drain will be enforced anyway and a warning will be +printed that the board configuration needs to be updated to match the use case. Both functions return either a valid GPIO descriptor, or an error code checkable with IS_ERR() (they will never return a NULL pointer). -ENOENT will be returned @@ -184,7 +193,7 @@ A driver can also query the current direction of a GPIO: int gpiod_get_direction(const struct gpio_desc *desc) -This function will return either GPIOF_DIR_IN or GPIOF_DIR_OUT. +This function returns 0 for output, 1 for input, or an error code in case of error. Be aware that there is no default direction for GPIOs. Therefore, **using a GPIO without setting its direction first is illegal and will result in undefined @@ -240,13 +249,58 @@ that can't be accessed from hardIRQ handlers, these calls act the same as the spinlock-safe calls. -Active-low State and Raw GPIO Values ------------------------------------- -Device drivers like to manage the logical state of a GPIO, i.e. the value their -device will actually receive, no matter what lies between it and the GPIO line. -In some cases, it might make sense to control the actual GPIO line value. The -following set of calls ignore the active-low property of a GPIO and work on the -raw line value: +The active low and open drain semantics +--------------------------------------- +As a consumer should not have to care about the physical line level, all of the +gpiod_set_value_xxx() or gpiod_set_array_value_xxx() functions operate with +the *logical* value. With this they take the active low property into account. +This means that they check whether the GPIO is configured to be active low, +and if so, they manipulate the passed value before the physical line level is +driven. + +The same is applicable for open drain or open source output lines: those do not +actively drive their output high (open drain) or low (open source), they just +switch their output to a high impedance value. The consumer should not need to +care. (For details read about open drain in driver.txt.) + +With this, all the gpiod_set_(array)_value_xxx() functions interpret the +parameter "value" as "asserted" ("1") or "de-asserted" ("0"). The physical line +level will be driven accordingly. + +As an example, if the active low property for a dedicated GPIO is set, and the +gpiod_set_(array)_value_xxx() passes "asserted" ("1"), the physical line level +will be driven low. + +To summarize: + +Function (example) line property physical line +gpiod_set_raw_value(desc, 0); don't care low +gpiod_set_raw_value(desc, 1); don't care high +gpiod_set_value(desc, 0); default (active high) low +gpiod_set_value(desc, 1); default (active high) high +gpiod_set_value(desc, 0); active low high +gpiod_set_value(desc, 1); active low low +gpiod_set_value(desc, 0); default (active high) low +gpiod_set_value(desc, 1); default (active high) high +gpiod_set_value(desc, 0); open drain low +gpiod_set_value(desc, 1); open drain high impedance +gpiod_set_value(desc, 0); open source high impedance +gpiod_set_value(desc, 1); open source high + +It is possible to override these semantics using the *set_raw/'get_raw functions +but it should be avoided as much as possible, especially by system-agnostic drivers +which should not need to care about the actual physical line level and worry about +the logical value instead. + + +Accessing raw GPIO values +------------------------- +Consumers exist that need to manage the logical state of a GPIO line, i.e. the value +their device will actually receive, no matter what lies between it and the GPIO +line. + +The following set of calls ignore the active-low or open drain property of a GPIO and +work on the raw line value: int gpiod_get_raw_value(const struct gpio_desc *desc) void gpiod_set_raw_value(struct gpio_desc *desc, int value) @@ -254,45 +308,12 @@ raw line value: void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value) int gpiod_direction_output_raw(struct gpio_desc *desc, int value) -The active-low state of a GPIO can also be queried using the following call: +The active low state of a GPIO can also be queried using the following call: int gpiod_is_active_low(const struct gpio_desc *desc) -Note that these functions should only be used with great moderation ; a driver -should not have to care about the physical line level. - - -The active-low property ------------------------ - -As a driver should not have to care about the physical line level, all of the -gpiod_set_value_xxx() or gpiod_set_array_value_xxx() functions operate with -the *logical* value. With this they take the active-low property into account. -This means that they check whether the GPIO is configured to be active-low, -and if so, they manipulate the passed value before the physical line level is -driven. - -With this, all the gpiod_set_(array)_value_xxx() functions interpret the -parameter "value" as "active" ("1") or "inactive" ("0"). The physical line -level will be driven accordingly. - -As an example, if the active-low property for a dedicated GPIO is set, and the -gpiod_set_(array)_value_xxx() passes "active" ("1"), the physical line level -will be driven low. - -To summarize: - -Function (example) active-low property physical line -gpiod_set_raw_value(desc, 0); don't care low -gpiod_set_raw_value(desc, 1); don't care high -gpiod_set_value(desc, 0); default (active-high) low -gpiod_set_value(desc, 1); default (active-high) high -gpiod_set_value(desc, 0); active-low high -gpiod_set_value(desc, 1); active-low low - -Please note again that the set_raw/get_raw functions should be avoided as much -as possible, especially by drivers which should not care about the actual -physical line level and worry about the logical value instead. +Note that these functions should only be used with great moderation; a driver +should not have to care about the physical line level or open drain semantics. Access multiple GPIOs with a single function call diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt index d8de1c7de85a..3392a0fd4c23 100644 --- a/Documentation/gpio/driver.txt +++ b/Documentation/gpio/driver.txt @@ -88,6 +88,10 @@ ending up in the pin control back-end "behind" the GPIO controller, usually closer to the actual pins. This way the pin controller can manage the below listed GPIO configurations. +If a pin controller back-end is used, the GPIO controller or hardware +description needs to provide "GPIO ranges" mapping the GPIO line offsets to pin +numbers on the pin controller so they can properly cross-reference each other. + GPIOs with debounce support --------------------------- diff --git a/Documentation/gpio/drivers-on-gpio.txt b/Documentation/gpio/drivers-on-gpio.txt index 9a78d385b92e..a2ccbab12eb7 100644 --- a/Documentation/gpio/drivers-on-gpio.txt +++ b/Documentation/gpio/drivers-on-gpio.txt @@ -28,11 +28,6 @@ hardware descriptions such as device tree or ACPI: - gpio-beeper: drivers/input/misc/gpio-beeper.c is used to provide a beep from an external speaker connected to a GPIO line. -- gpio-tilt-polled: drivers/input/misc/gpio_tilt_polled.c provides tilt - detection switches using GPIO, which is useful for your homebrewn pinball - machine if for nothing else. It can detect different tilt angles of the - monitored object. - - extcon-gpio: drivers/extcon/extcon-gpio.c is used when you need to read an external connector status, such as a headset line for an audio driver or an HDMI connector. It will provide a better userspace sysfs interface than GPIO. diff --git a/Documentation/gpio/sysfs.txt b/Documentation/gpio/sysfs.txt index aeab01aa4d00..6cdeab8650cd 100644 --- a/Documentation/gpio/sysfs.txt +++ b/Documentation/gpio/sysfs.txt @@ -1,6 +1,17 @@ GPIO Sysfs Interface for Userspace ================================== +THIS ABI IS DEPRECATED, THE ABI DOCUMENTATION HAS BEEN MOVED TO +Documentation/ABI/obsolete/sysfs-gpio AND NEW USERSPACE CONSUMERS +ARE SUPPOSED TO USE THE CHARACTER DEVICE ABI. THIS OLD SYSFS ABI WILL +NOT BE DEVELOPED (NO NEW FEATURES), IT WILL JUST BE MAINTAINED. + +Refer to the examples in tools/gpio/* for an introduction to the new +character device ABI. Also see the userspace header in +include/uapi/linux/gpio.h + +The deprecated sysfs ABI +------------------------ Platforms which use the "gpiolib" implementors framework may choose to configure a sysfs user interface to GPIOs. This is different from the debugfs interface, since it provides control over GPIO direction and diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 2dcf5b42015d..56a3780e39b8 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -547,8 +547,9 @@ Explicit Fencing Properties Existing KMS Properties ----------------------- -The following table gives description of drm properties exposed by -various modules/drivers. +The following table gives description of drm properties exposed by various +modules/drivers. Because this table is very unwieldy, do not add any new +properties here. Instead document them in a section above. .. csv-table:: :header-rows: 1 diff --git a/Documentation/gpu/kms-properties.csv b/Documentation/gpu/kms-properties.csv index 927b65e14219..6b28b014cb7d 100644 --- a/Documentation/gpu/kms-properties.csv +++ b/Documentation/gpu/kms-properties.csv @@ -1,5 +1,4 @@ Owner Module/Drivers,Group,Property Name,Type,Property Values,Object attached,Description/Restrictions -,,“scaling mode”,ENUM,"{ ""None"", ""Full"", ""Center"", ""Full aspect"" }",Connector,"Supported by: amdgpu, gma500, i915, nouveau and radeon." ,DVI-I,“subconnector”,ENUM,"{ “Unknown”, “DVI-D”, “DVI-A” }",Connector,TBD ,,“select subconnector”,ENUM,"{ “Automatic”, “DVI-D”, “DVI-A” }",Connector,TBD ,TV,“subconnector”,ENUM,"{ ""Unknown"", ""Composite"", ""SVIDEO"", ""Component"", ""SCART"" }",Connector,TBD diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 459936c04aa5..f4d0b3476d9c 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -212,6 +212,16 @@ probably use drm_fb_helper_fbdev_teardown(). Contact: Maintainer of the driver you plan to convert +idr_init_base() +--------------- + +DRM core&drivers uses a lot of idr (integer lookup directories) for mapping +userspace IDs to internal objects, and in most places ID=0 means NULL and hence +is never used. Switching to idr_init_base() for these would make the idr more +efficient. + +Contact: Daniel Vetter + Core refactorings ================= diff --git a/Documentation/hwmon/lm25066 b/Documentation/hwmon/lm25066 index 3fa6bf820c88..51b32aa203a8 100644 --- a/Documentation/hwmon/lm25066 +++ b/Documentation/hwmon/lm25066 @@ -8,11 +8,6 @@ Supported chips: Datasheets: http://www.ti.com/lit/gpn/lm25056 http://www.ti.com/lit/gpn/lm25056a - * TI LM25063 - Prefix: 'lm25063' - Addresses scanned: - - Datasheet: - To be announced * National Semiconductor LM25066 Prefix: 'lm25066' Addresses scanned: - @@ -42,7 +37,7 @@ Description ----------- This driver supports hardware monitoring for National Semiconductor / TI LM25056, -LM25063, LM25066, LM5064, and LM5066/LM5066I Power Management, Monitoring, +LM25066, LM5064, and LM5066/LM5066I Power Management, Monitoring, Control, and Protection ICs. The driver is a client driver to the core PMBus driver. Please see @@ -74,12 +69,8 @@ in1_input Measured input voltage. in1_average Average measured input voltage. in1_min Minimum input voltage. in1_max Maximum input voltage. -in1_crit Critical high input voltage (LM25063 only). -in1_lcrit Critical low input voltage (LM25063 only). in1_min_alarm Input voltage low alarm. in1_max_alarm Input voltage high alarm. -in1_lcrit_alarm Input voltage critical low alarm (LM25063 only). -in1_crit_alarm Input voltage critical high alarm. (LM25063 only). in2_label "vmon" in2_input Measured voltage on VAUX pin @@ -94,16 +85,12 @@ in3_input Measured output voltage. in3_average Average measured output voltage. in3_min Minimum output voltage. in3_min_alarm Output voltage low alarm. -in3_highest Historical minimum output voltage (LM25063 only). -in3_lowest Historical maximum output voltage (LM25063 only). curr1_label "iin" curr1_input Measured input current. curr1_average Average measured input current. curr1_max Maximum input current. -curr1_crit Critical input current (LM25063 only). curr1_max_alarm Input current high alarm. -curr1_crit_alarm Input current critical high alarm (LM25063 only). power1_label "pin" power1_input Measured input power. @@ -113,11 +100,6 @@ power1_alarm Input power alarm power1_input_highest Historical maximum power. power1_reset_history Write any value to reset maximum power history. -power2_label "pout". LM25063 only. -power2_input Measured output power. -power2_max Maximum output power limit. -power2_crit Critical output power limit. - temp1_input Measured temperature. temp1_max Maximum temperature. temp1_crit Critical high temperature. diff --git a/Documentation/hwmon/max31785 b/Documentation/hwmon/max31785 index 45fb6093dec2..270c5f865261 100644 --- a/Documentation/hwmon/max31785 +++ b/Documentation/hwmon/max31785 @@ -17,8 +17,9 @@ management with temperature and remote voltage sensing. Various fan control features are provided, including PWM frequency control, temperature hysteresis, dual tachometer measurements, and fan health monitoring. -For dual rotor fan configuration, the MAX31785 exposes the slowest rotor of the -two in the fan[1-4]_input attributes. +For dual-rotor configurations the MAX31785A exposes the second rotor tachometer +readings in attributes fan[5-8]_input. By contrast the MAX31785 only exposes +the slowest rotor measurement, and does so in the fan[1-4]_input attributes. Usage Notes ----------- @@ -31,7 +32,9 @@ Sysfs attributes fan[1-4]_alarm Fan alarm. fan[1-4]_fault Fan fault. -fan[1-4]_input Fan RPM. +fan[1-8]_input Fan RPM. On the MAX31785A, inputs 5-8 correspond to the + second rotor of fans 1-4 +fan[1-4]_target Fan input target in[1-6]_crit Critical maximum output voltage in[1-6]_crit_alarm Output voltage critical high alarm @@ -44,6 +47,12 @@ in[1-6]_max_alarm Output voltage high alarm in[1-6]_min Minimum output voltage in[1-6]_min_alarm Output voltage low alarm +pwm[1-4] Fan target duty cycle (0..255) +pwm[1-4]_enable 0: Full-speed + 1: Manual PWM control + 2: Automatic PWM (tach-feedback RPM fan-control) + 3: Automatic closed-loop (temp-feedback fan-control) + temp[1-11]_crit Critical high temperature temp[1-11]_crit_alarm Chip temperature critical high alarm temp[1-11]_input Measured temperature diff --git a/Documentation/hwmon/w83773g b/Documentation/hwmon/w83773g new file mode 100644 index 000000000000..4cc6c0b8257f --- /dev/null +++ b/Documentation/hwmon/w83773g @@ -0,0 +1,33 @@ +Kernel driver w83773g +==================== + +Supported chips: + * Nuvoton W83773G + Prefix: 'w83773g' + Addresses scanned: I2C 0x4c and 0x4d + Datasheet: https://www.nuvoton.com/resource-files/W83773G_SG_DatasheetV1_2.pdf + +Authors: + Lei YU + +Description +----------- + +This driver implements support for Nuvoton W83773G temperature sensor +chip. This chip implements one local and two remote sensors. +The chip also features offsets for the two remote sensors which get added to +the input readings. The chip does all the scaling by itself and the driver +therefore reports true temperatures that don't need any user-space adjustments. +Temperature is measured in degrees Celsius. +The chip is wired over I2C/SMBus and specified over a temperature +range of -40 to +125 degrees Celsius (for local sensor) and -40 to +127 +degrees Celsius (for remote sensors). +Resolution for both the local and remote channels is 0.125 degree C. + +The chip supports only temperature measurement. The driver exports +the temperature values via the following sysfs files: + +temp[1-3]_input +temp[2-3]_fault +temp[2-3]_offset +update_interval diff --git a/Documentation/i2c/DMA-considerations b/Documentation/i2c/DMA-considerations new file mode 100644 index 000000000000..966610aa4620 --- /dev/null +++ b/Documentation/i2c/DMA-considerations @@ -0,0 +1,67 @@ +================= +Linux I2C and DMA +================= + +Given that i2c is a low-speed bus, over which the majority of messages +transferred are small, it is not considered a prime user of DMA access. At this +time of writing, only 10% of I2C bus master drivers have DMA support +implemented. And the vast majority of transactions are so small that setting up +DMA for it will likely add more overhead than a plain PIO transfer. + +Therefore, it is *not* mandatory that the buffer of an I2C message is DMA safe. +It does not seem reasonable to apply additional burdens when the feature is so +rarely used. However, it is recommended to use a DMA-safe buffer if your +message size is likely applicable for DMA. Most drivers have this threshold +around 8 bytes (as of today, this is mostly an educated guess, however). For +any message of 16 byte or larger, it is probably a really good idea. Please +note that other subsystems you use might add requirements. E.g., if your +I2C bus master driver is using USB as a bridge, then you need to have DMA +safe buffers always, because USB requires it. + +Clients +------- + +For clients, if you use a DMA safe buffer in i2c_msg, set the I2C_M_DMA_SAFE +flag with it. Then, the I2C core and drivers know they can safely operate DMA +on it. Note that using this flag is optional. I2C host drivers which are not +updated to use this flag will work like before. And like before, they risk +using an unsafe DMA buffer. To improve this situation, using I2C_M_DMA_SAFE in +more and more clients and host drivers is the planned way forward. Note also +that setting this flag makes only sense in kernel space. User space data is +copied into kernel space anyhow. The I2C core makes sure the destination +buffers in kernel space are always DMA capable. Also, when the core emulates +SMBus transactions via I2C, the buffers for block transfers are DMA safe. Users +of i2c_master_send() and i2c_master_recv() functions can now use DMA safe +variants (i2c_master_send_dmasafe() and i2c_master_recv_dmasafe()) once they +know their buffers are DMA safe. Users of i2c_transfer() must set the +I2C_M_DMA_SAFE flag manually. + +Masters +------- + +Bus master drivers wishing to implement safe DMA can use helper functions from +the I2C core. One gives you a DMA-safe buffer for a given i2c_msg as long as a +certain threshold is met:: + + dma_buf = i2c_get_dma_safe_msg_buf(msg, threshold_in_byte); + +If a buffer is returned, it is either msg->buf for the I2C_M_DMA_SAFE case or a +bounce buffer. But you don't need to care about that detail, just use the +returned buffer. If NULL is returned, the threshold was not met or a bounce +buffer could not be allocated. Fall back to PIO in that case. + +In any case, a buffer obtained from above needs to be released. It ensures data +is copied back to the message and a potentially used bounce buffer is freed:: + + i2c_release_dma_safe_msg_buf(msg, dma_buf); + +The bounce buffer handling from the core is generic and simple. It will always +allocate a new bounce buffer. If you want a more sophisticated handling (e.g. +reusing pre-allocated buffers), you are free to implement your own. + +Please also check the in-kernel documentation for details. The i2c-sh_mobile +driver can be used as a reference example how to use the above helpers. + +Final note: If you plan to use DMA with I2C (or with anything else, actually) +make sure you have CONFIG_DMA_API_DEBUG enabled during development. It can help +you find various issues which can be complex to debug otherwise. diff --git a/Documentation/i2c/dev-interface b/Documentation/i2c/dev-interface index 5ff19447ac44..d04e6e4964ee 100644 --- a/Documentation/i2c/dev-interface +++ b/Documentation/i2c/dev-interface @@ -17,13 +17,16 @@ i2c-10, ...). All 256 minor device numbers are reserved for i2c. C example ========= -So let's say you want to access an i2c adapter from a C program. The -first thing to do is "#include ". Please note that -there are two files named "i2c-dev.h" out there, one is distributed -with the Linux kernel and is meant to be included from kernel -driver code, the other one is distributed with i2c-tools and is -meant to be included from user-space programs. You obviously want -the second one here. +So let's say you want to access an i2c adapter from a C program. +First, you need to include these two headers: + + #include + #include + +(Please note that there are two files named "i2c-dev.h" out there. One is +distributed with the Linux kernel and the other one is included in the +source tree of i2c-tools. They used to be different in content but since 2012 +they're identical. You should use "linux/i2c-dev.h"). Now, you have to decide which adapter you want to access. You should inspect /sys/class/i2c-dev/ or run "i2cdetect -l" to decide this. diff --git a/Documentation/i2c/gpio-fault-injection b/Documentation/i2c/gpio-fault-injection new file mode 100644 index 000000000000..e0c4f775e239 --- /dev/null +++ b/Documentation/i2c/gpio-fault-injection @@ -0,0 +1,54 @@ +Linux I2C fault injection +========================= + +The GPIO based I2C bus master driver can be configured to provide fault +injection capabilities. It is then meant to be connected to another I2C bus +which is driven by the I2C bus master driver under test. The GPIO fault +injection driver can create special states on the bus which the other I2C bus +master driver should handle gracefully. + +Once the Kconfig option I2C_GPIO_FAULT_INJECTOR is enabled, there will be an +'i2c-fault-injector' subdirectory in the Kernel debugfs filesystem, usually +mounted at /sys/kernel/debug. There will be a separate subdirectory per GPIO +driven I2C bus. Each subdirectory will contain files to trigger the fault +injection. They will be described now along with their intended use-cases. + +"scl" +----- + +By reading this file, you get the current state of SCL. By writing, you can +change its state to either force it low or to release it again. So, by using +"echo 0 > scl" you force SCL low and thus, no communication will be possible +because the bus master under test will not be able to clock. It should detect +the condition of SCL being unresponsive and report an error to the upper +layers. + +"sda" +----- + +By reading this file, you get the current state of SDA. By writing, you can +change its state to either force it low or to release it again. So, by using +"echo 0 > sda" you force SDA low and thus, data cannot be transmitted. The bus +master under test should detect this condition and trigger a bus recovery (see +I2C specification version 4, section 3.1.16) using the helpers of the Linux I2C +core (see 'struct bus_recovery_info'). However, the bus recovery will not +succeed because SDA is still pinned low until you manually release it again +with "echo 1 > sda". A test with an automatic release can be done with the +'incomplete_transfer' file. + +"incomplete_transfer" +--------------------- + +This file is write only and you need to write the address of an existing I2C +client device to it. Then, a transfer to this device will be started, but it +will stop at the ACK phase after the address of the client has been +transmitted. Because the device will ACK its presence, this results in SDA +being pulled low by the device while SCL is high. So, similar to the "sda" file +above, the bus master under test should detect this condition and try a bus +recovery. This time, however, it should succeed and the device should release +SDA after toggling SCL. Please note: there are I2C client devices which detect +a stuck SDA on their side and release it on their own after a few milliseconds. +Also, there are external devices deglitching and monitoring the I2C bus. They +can also detect a stuck SDA and will init a bus recovery on their own. If you +want to implement bus recovery in a bus master driver, make sure you checked +your hardware setup carefully before. diff --git a/Documentation/index.rst b/Documentation/index.rst index cb7f1ba5b3b1..ef5080cbf009 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -13,6 +13,18 @@ documents into a coherent whole. Please note that improvements to the documentation are welcome; join the linux-doc list at vger.kernel.org if you want to help out. +Licensing documentation +----------------------- + +The following describes the license of the Linux kernel source code +(GPLv2), how to properly mark the license of individual files in the source +tree, as well as links to the full license text. + +.. toctree:: + :maxdepth: 2 + + process/license-rules.rst + User-oriented documentation --------------------------- @@ -52,6 +64,7 @@ merged much easier. dev-tools/index doc-guide/index kernel-hacking/index + maintainer/index Kernel API documentation ------------------------ diff --git a/Documentation/infiniband/user_verbs.txt b/Documentation/infiniband/user_verbs.txt index e5092d696da2..df049b9f5b6e 100644 --- a/Documentation/infiniband/user_verbs.txt +++ b/Documentation/infiniband/user_verbs.txt @@ -5,7 +5,7 @@ USERSPACE VERBS ACCESS described in chapter 11 of the InfiniBand Architecture Specification. To use the verbs, the libibverbs library, available from - http://www.openfabrics.org/, is required. libibverbs contains a + https://github.com/linux-rdma/rdma-core, is required. libibverbs contains a device-independent API for using the ib_uverbs interface. libibverbs also requires appropriate device-dependent kernel and userspace driver for your InfiniBand hardware. For example, to use diff --git a/Documentation/input/devices/gpio-tilt.rst b/Documentation/input/devices/gpio-tilt.rst deleted file mode 100644 index fa6e64570aa7..000000000000 --- a/Documentation/input/devices/gpio-tilt.rst +++ /dev/null @@ -1,103 +0,0 @@ -Driver for tilt-switches connected via GPIOs -============================================ - -Generic driver to read data from tilt switches connected via gpios. -Orientation can be provided by one or more than one tilt switches, -i.e. each tilt switch providing one axis, and the number of axes -is also not limited. - - -Data structures ---------------- - -The array of struct gpio in the gpios field is used to list the gpios -that represent the current tilt state. - -The array of struct gpio_tilt_axis describes the axes that are reported -to the input system. The values set therein are used for the -input_set_abs_params calls needed to init the axes. - -The array of struct gpio_tilt_state maps gpio states to the corresponding -values to report. The gpio state is represented as a bitfield where the -bit-index corresponds to the index of the gpio in the struct gpio array. -In the same manner the values stored in the axes array correspond to -the elements of the gpio_tilt_axis-array. - - -Example -------- - -Example configuration for a single TS1003 tilt switch that rotates around -one axis in 4 steps and emits the current tilt via two GPIOs:: - - static int sg060_tilt_enable(struct device *dev) { - /* code to enable the sensors */ - }; - - static void sg060_tilt_disable(struct device *dev) { - /* code to disable the sensors */ - }; - - static struct gpio sg060_tilt_gpios[] = { - { SG060_TILT_GPIO_SENSOR1, GPIOF_IN, "tilt_sensor1" }, - { SG060_TILT_GPIO_SENSOR2, GPIOF_IN, "tilt_sensor2" }, - }; - - static struct gpio_tilt_state sg060_tilt_states[] = { - { - .gpios = (0 << 1) | (0 << 0), - .axes = (int[]) { - 0, - }, - }, { - .gpios = (0 << 1) | (1 << 0), - .axes = (int[]) { - 1, /* 90 degrees */ - }, - }, { - .gpios = (1 << 1) | (1 << 0), - .axes = (int[]) { - 2, /* 180 degrees */ - }, - }, { - .gpios = (1 << 1) | (0 << 0), - .axes = (int[]) { - 3, /* 270 degrees */ - }, - }, - }; - - static struct gpio_tilt_axis sg060_tilt_axes[] = { - { - .axis = ABS_RY, - .min = 0, - .max = 3, - .fuzz = 0, - .flat = 0, - }, - }; - - static struct gpio_tilt_platform_data sg060_tilt_pdata= { - .gpios = sg060_tilt_gpios, - .nr_gpios = ARRAY_SIZE(sg060_tilt_gpios), - - .axes = sg060_tilt_axes, - .nr_axes = ARRAY_SIZE(sg060_tilt_axes), - - .states = sg060_tilt_states, - .nr_states = ARRAY_SIZE(sg060_tilt_states), - - .debounce_interval = 100, - - .poll_interval = 1000, - .enable = sg060_tilt_enable, - .disable = sg060_tilt_disable, - }; - - static struct platform_device sg060_device_tilt = { - .name = "gpio-tilt-polled", - .id = -1, - .dev = { - .platform_data = &sg060_tilt_pdata, - }, - }; diff --git a/Documentation/input/devices/rotary-encoder.rst b/Documentation/input/devices/rotary-encoder.rst index b07b20a295ac..810ae02bdaa0 100644 --- a/Documentation/input/devices/rotary-encoder.rst +++ b/Documentation/input/devices/rotary-encoder.rst @@ -108,9 +108,9 @@ example below: }; static const struct property_entry rotary_encoder_properties[] __initconst = { - PROPERTY_ENTRY_INTEGER("rotary-encoder,steps-per-period", u32, 24), - PROPERTY_ENTRY_INTEGER("linux,axis", u32, ABS_X), - PROPERTY_ENTRY_INTEGER("rotary-encoder,relative_axis", u32, 0), + PROPERTY_ENTRY_U32("rotary-encoder,steps-per-period", 24), + PROPERTY_ENTRY_U32("linux,axis", ABS_X), + PROPERTY_ENTRY_U32("rotary-encoder,relative_axis", 0), { }, }; diff --git a/Documentation/input/ff.rst b/Documentation/input/ff.rst index 26d461998e08..0c02e87ee86d 100644 --- a/Documentation/input/ff.rst +++ b/Documentation/input/ff.rst @@ -31,7 +31,7 @@ To enable force feedback, you have to: Before you start, let me WARN you that some devices shake violently during the initialisation phase. This happens for example with my "AVB Top Shot Pegasus". -To stop this annoying behaviour, move you joystick to its limits. Anyway, you +To stop this annoying behaviour, move your joystick to its limits. Anyway, you should keep a hand on your device, in order to avoid it to break down if something goes wrong. @@ -121,7 +121,7 @@ uploaded, but not played. The content of effect may be modified. In particular, its field "id" is set to the unique id assigned by the driver. This data is required for performing some operations (removing an effect, controlling the playback). -This if field must be set to -1 by the user in order to tell the driver to +The "id" field must be set to -1 by the user in order to tell the driver to allocate a new effect. Effects are file descriptor specific. @@ -178,7 +178,7 @@ Control of playing is done with write(). Below is an example: stop.code = effect.id; stop.value = 0; - write(fd, (const void*) &play, sizeof(stop)); + write(fd, (const void*) &stop, sizeof(stop)); Setting the gain ---------------- diff --git a/Documentation/input/multi-touch-protocol.rst b/Documentation/input/multi-touch-protocol.rst index 8035868c56bc..b51751a0cd5d 100644 --- a/Documentation/input/multi-touch-protocol.rst +++ b/Documentation/input/multi-touch-protocol.rst @@ -269,10 +269,11 @@ ABS_MT_ORIENTATION The orientation of the touching ellipse. The value should describe a signed quarter of a revolution clockwise around the touch center. The signed value range is arbitrary, but zero should be returned for an ellipse aligned with - the Y axis of the surface, a negative value when the ellipse is turned to - the left, and a positive value when the ellipse is turned to the - right. When completely aligned with the X axis, the range max should be - returned. + the Y axis (north) of the surface, a negative value when the ellipse is + turned to the left, and a positive value when the ellipse is turned to the + right. When aligned with the X axis in the positive direction, the range + max should be returned; when aligned with the X axis in the negative + direction, the range -max should be returned. Touch ellipsis are symmetrical by default. For devices capable of true 360 degree orientation, the reported orientation must exceed the range max to diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 3e3fdae5f3ed..6501389d55b9 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -326,6 +326,7 @@ Code Seq#(hex) Include File Comments 0xB5 00-0F uapi/linux/rpmsg.h 0xC0 00-0F linux/usb/iowarrior.h 0xCA 00-0F uapi/misc/cxl.h +0xCA 10-2F uapi/misc/ocxl.h 0xCA 80-BF uapi/scsi/cxlflash_ioctl.h 0xCB 00-1F CBM serial IEC bus in development: diff --git a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt index c4a293a03c33..f5b9493f04ad 100644 --- a/Documentation/kbuild/kconfig-language.txt +++ b/Documentation/kbuild/kconfig-language.txt @@ -77,6 +77,27 @@ applicable everywhere (see syntax). Optionally, dependencies only for this default value can be added with "if". + The default value deliberately defaults to 'n' in order to avoid bloating the + build. With few exceptions, new config options should not change this. The + intent is for "make oldconfig" to add as little as possible to the config from + release to release. + + Note: + Things that merit "default y/m" include: + + a) A new Kconfig option for something that used to always be built + should be "default y". + + b) A new gatekeeping Kconfig option that hides/shows other Kconfig + options (but does not generate any code of its own), should be + "default y" so people will see those other options. + + c) Sub-driver behavior or similar options for a driver that is + "default n". This allows you to provide sane defaults. + + d) Hardware or infrastructure that everybody expects, such as CONFIG_NET + or CONFIG_BLOCK. These are rare exceptions. + - type definition + default value: "def_bool"/"def_tristate" ["if" ] This is a shorthand notation for a type definition plus a value. diff --git a/Documentation/kernel-doc-nano-HOWTO.txt b/Documentation/kernel-doc-nano-HOWTO.txt deleted file mode 100644 index c23e2c5ab80d..000000000000 --- a/Documentation/kernel-doc-nano-HOWTO.txt +++ /dev/null @@ -1,322 +0,0 @@ -NOTE: this document is outdated and will eventually be removed. See -Documentation/doc-guide/ for current information. - -kernel-doc nano-HOWTO -===================== - -How to format kernel-doc comments ---------------------------------- - -In order to provide embedded, 'C' friendly, easy to maintain, -but consistent and extractable documentation of the functions and -data structures in the Linux kernel, the Linux kernel has adopted -a consistent style for documenting functions and their parameters, -and structures and their members. - -The format for this documentation is called the kernel-doc format. -It is documented in this Documentation/kernel-doc-nano-HOWTO.txt file. - -This style embeds the documentation within the source files, using -a few simple conventions. The scripts/kernel-doc perl script, the -Documentation/sphinx/kerneldoc.py Sphinx extension and other tools understand -these conventions, and are used to extract this embedded documentation -into various documents. - -In order to provide good documentation of kernel functions and data -structures, please use the following conventions to format your -kernel-doc comments in Linux kernel source. - -We definitely need kernel-doc formatted documentation for functions -that are exported to loadable modules using EXPORT_SYMBOL. - -We also look to provide kernel-doc formatted documentation for -functions externally visible to other kernel files (not marked -"static"). - -We also recommend providing kernel-doc formatted documentation -for private (file "static") routines, for consistency of kernel -source code layout. But this is lower priority and at the -discretion of the MAINTAINER of that kernel source file. - -Data structures visible in kernel include files should also be -documented using kernel-doc formatted comments. - -The opening comment mark "/**" is reserved for kernel-doc comments. -Only comments so marked will be considered by the kernel-doc scripts, -and any comment so marked must be in kernel-doc format. Do not use -"/**" to be begin a comment block unless the comment block contains -kernel-doc formatted comments. The closing comment marker for -kernel-doc comments can be either "*/" or "**/", but "*/" is -preferred in the Linux kernel tree. - -Kernel-doc comments should be placed just before the function -or data structure being described. - -Example kernel-doc function comment: - -/** - * foobar() - short function description of foobar - * @arg1: Describe the first argument to foobar. - * @arg2: Describe the second argument to foobar. - * One can provide multiple line descriptions - * for arguments. - * - * A longer description, with more discussion of the function foobar() - * that might be useful to those using or modifying it. Begins with - * empty comment line, and may include additional embedded empty - * comment lines. - * - * The longer description can have multiple paragraphs. - * - * Return: Describe the return value of foobar. - */ - -The short description following the subject can span multiple lines -and ends with an @argument description, an empty line or the end of -the comment block. - -The @argument descriptions must begin on the very next line following -this opening short function description line, with no intervening -empty comment lines. - -If a function parameter is "..." (varargs), it should be listed in -kernel-doc notation as: - * @...: description - -The return value, if any, should be described in a dedicated section -named "Return". - -Example kernel-doc data structure comment. - -/** - * struct blah - the basic blah structure - * @mem1: describe the first member of struct blah - * @mem2: describe the second member of struct blah, - * perhaps with more lines and words. - * - * Longer description of this structure. - */ - -The kernel-doc function comments describe each parameter to the -function, in order, with the @name lines. - -The kernel-doc data structure comments describe each structure member -in the data structure, with the @name lines. - -The longer description formatting is "reflowed", losing your line -breaks. So presenting carefully formatted lists within these -descriptions won't work so well; derived documentation will lose -the formatting. - -See the section below "How to add extractable documentation to your -source files" for more details and notes on how to format kernel-doc -comments. - -Components of the kernel-doc system ------------------------------------ - -Many places in the source tree have extractable documentation in the -form of block comments above functions. The components of this system -are: - -- scripts/kernel-doc - - This is a perl script that hunts for the block comments and can mark - them up directly into DocBook, ReST, man, text, and HTML. (No, not - texinfo.) - -- scripts/docproc.c - - This is a program for converting SGML template files into SGML - files. When a file is referenced it is searched for symbols - exported (EXPORT_SYMBOL), to be able to distinguish between internal - and external functions. - It invokes kernel-doc, giving it the list of functions that - are to be documented. - Additionally it is used to scan the SGML template files to locate - all the files referenced herein. This is used to generate dependency - information as used by make. - -- Makefile - - The targets 'xmldocs', 'latexdocs', 'pdfdocs', 'epubdocs'and 'htmldocs' - are used to build XML DocBook files, LaTeX files, PDF files, - ePub files and html files in Documentation/. - -How to extract the documentation --------------------------------- - -If you just want to read the ready-made books on the various -subsystems, just type 'make epubdocs', or 'make pdfdocs', or 'make htmldocs', -depending on your preference. If you would rather read a different format, -you can type 'make xmldocs' and then use DocBook tools to convert -Documentation/output/*.xml to a format of your choice (for example, -'db2html ...' if 'make htmldocs' was not defined). - -If you want to see man pages instead, you can do this: - -$ cd linux -$ scripts/kernel-doc -man $(find -name '*.c') | split-man.pl /tmp/man -$ scripts/kernel-doc -man $(find -name '*.h') | split-man.pl /tmp/man - -Here is split-man.pl: - ---> -#!/usr/bin/perl - -if ($#ARGV < 0) { - die "where do I put the results?\n"; -} - -mkdir $ARGV[0],0777; -$state = 0; -while () { - if (/^\.TH \"[^\"]*\" 9 \"([^\"]*)\"/) { - if ($state == 1) { close OUT } - $state = 1; - $fn = "$ARGV[0]/$1.9"; - print STDERR "Creating $fn\n"; - open OUT, ">$fn" or die "can't open $fn: $!\n"; - print OUT $_; - } elsif ($state != 0) { - print OUT $_; - } -} - -close OUT; -<-- - -If you just want to view the documentation for one function in one -file, you can do this: - -$ scripts/kernel-doc -man -function fn file | nroff -man | less - -or this: - -$ scripts/kernel-doc -text -function fn file - - -How to add extractable documentation to your source files ---------------------------------------------------------- - -The format of the block comment is like this: - -/** - * function_name(:)? (- short description)? -(* @parameterx(space)*: (description of parameter x)?)* -(* a blank line)? - * (Description:)? (Description of function)? - * (section header: (section description)? )* -(*)?*/ - -All "description" text can span multiple lines, although the -function_name & its short description are traditionally on a single line. -Description text may also contain blank lines (i.e., lines that contain -only a "*"). - -"section header:" names must be unique per function (or struct, -union, typedef, enum). - -Use the section header "Return" for sections describing the return value -of a function. - -Avoid putting a spurious blank line after the function name, or else the -description will be repeated! - -All descriptive text is further processed, scanning for the following special -patterns, which are highlighted appropriately. - -'funcname()' - function -'$ENVVAR' - environment variable -'&struct_name' - name of a structure (up to two words including 'struct') -'@parameter' - name of a parameter -'%CONST' - name of a constant. - -NOTE 1: The multi-line descriptive text you provide does *not* recognize -line breaks, so if you try to format some text nicely, as in: - - Return: - 0 - cool - 1 - invalid arg - 2 - out of memory - -this will all run together and produce: - - Return: 0 - cool 1 - invalid arg 2 - out of memory - -NOTE 2: If the descriptive text you provide has lines that begin with -some phrase followed by a colon, each of those phrases will be taken as -a new section heading, which means you should similarly try to avoid text -like: - - Return: - 0: cool - 1: invalid arg - 2: out of memory - -every line of which would start a new section. Again, probably not -what you were after. - -Take a look around the source tree for examples. - - -kernel-doc for structs, unions, enums, and typedefs ---------------------------------------------------- - -Beside functions you can also write documentation for structs, unions, -enums and typedefs. Instead of the function name you must write the name -of the declaration; the struct/union/enum/typedef must always precede -the name. Nesting of declarations is not supported. -Use the argument mechanism to document members or constants. - -Inside a struct description, you can use the "private:" and "public:" -comment tags. Structure fields that are inside a "private:" area -are not listed in the generated output documentation. The "private:" -and "public:" tags must begin immediately following a "/*" comment -marker. They may optionally include comments between the ":" and the -ending "*/" marker. - -Example: - -/** - * struct my_struct - short description - * @a: first member - * @b: second member - * - * Longer description - */ -struct my_struct { - int a; - int b; -/* private: internal use only */ - int c; -}; - - -Including documentation blocks in source files ----------------------------------------------- - -To facilitate having source code and comments close together, you can -include kernel-doc documentation blocks that are free-form comments -instead of being kernel-doc for functions, structures, unions, -enums, or typedefs. This could be used for something like a -theory of operation for a driver or library code, for example. - -This is done by using a DOC: section keyword with a section title. E.g.: - -/** - * DOC: Theory of Operation - * - * The whizbang foobar is a dilly of a gizmo. It can do whatever you - * want it to do, at any time. It reads your mind. Here's how it works. - * - * foo bar splat - * - * The only drawback to this gizmo is that is can sometimes damage - * hardware, software, or its subject(s). - */ - -DOC: sections are used in ReST files. - -Tim. -*/ diff --git a/Documentation/kernel-hacking/hacking.rst b/Documentation/kernel-hacking/hacking.rst index daf3883b2694..9999c8468293 100644 --- a/Documentation/kernel-hacking/hacking.rst +++ b/Documentation/kernel-hacking/hacking.rst @@ -523,7 +523,7 @@ this expression is true, or ``-ERESTARTSYS`` if a signal is received. The Waking Up Queued Tasks ---------------------- -Call :c:func:`wake_up()` (``include/linux/wait.h``);, which will wake +Call :c:func:`wake_up()` (``include/linux/wait.h``), which will wake up every process in the queue. The exception is if one has ``TASK_EXCLUSIVE`` set, in which case the remainder of the queue will not be woken. There are other variants of this basic function available @@ -690,8 +690,8 @@ not provide the necessary runtime environment and the include files are not tested for it. It is still possible, but not recommended. If you really want to do this, forget about exceptions at least. -NUMif ------ +#if +--- It is generally considered cleaner to use macros in header files (or at the top of .c files) to abstract away functions rather than using \`#if' diff --git a/Documentation/livepatch/livepatch.txt b/Documentation/livepatch/livepatch.txt index ecdb18104ab0..1ae2de758c08 100644 --- a/Documentation/livepatch/livepatch.txt +++ b/Documentation/livepatch/livepatch.txt @@ -72,8 +72,7 @@ example, they add a NULL pointer or a boundary check, fix a race by adding a missing memory barrier, or add some locking around a critical section. Most of these changes are self contained and the function presents itself the same way to the rest of the system. In this case, the functions might -be updated independently one by one. (This can be done by setting the -'immediate' flag in the klp_patch struct.) +be updated independently one by one. But there are more complex fixes. For example, a patch might change ordering of locking in multiple functions at the same time. Or a patch @@ -125,12 +124,6 @@ safe to patch tasks: b) Patching CPU-bound user tasks. If the task is highly CPU-bound then it will get patched the next time it gets interrupted by an IRQ. - c) In the future it could be useful for applying patches for - architectures which don't yet have HAVE_RELIABLE_STACKTRACE. In - this case you would have to signal most of the tasks on the - system. However this isn't supported yet because there's - currently no way to patch kthreads without - HAVE_RELIABLE_STACKTRACE. 3. For idle "swapper" tasks, since they don't ever exit the kernel, they instead have a klp_update_patch_state() call in the idle loop which @@ -138,27 +131,16 @@ safe to patch tasks: (Note there's not yet such an approach for kthreads.) -All the above approaches may be skipped by setting the 'immediate' flag -in the 'klp_patch' struct, which will disable per-task consistency and -patch all tasks immediately. This can be useful if the patch doesn't -change any function or data semantics. Note that, even with this flag -set, it's possible that some tasks may still be running with an old -version of the function, until that function returns. +Architectures which don't have HAVE_RELIABLE_STACKTRACE solely rely on +the second approach. It's highly likely that some tasks may still be +running with an old version of the function, until that function +returns. In this case you would have to signal the tasks. This +especially applies to kthreads. They may not be woken up and would need +to be forced. See below for more information. -There's also an 'immediate' flag in the 'klp_func' struct which allows -you to specify that certain functions in the patch can be applied -without per-task consistency. This might be useful if you want to patch -a common function like schedule(), and the function change doesn't need -consistency but the rest of the patch does. - -For architectures which don't have HAVE_RELIABLE_STACKTRACE, the user -must set patch->immediate which causes all tasks to be patched -immediately. This option should be used with care, only when the patch -doesn't change any function or data semantics. - -In the future, architectures which don't have HAVE_RELIABLE_STACKTRACE -may be allowed to use per-task consistency if we can come up with -another way to patch kthreads. +Unless we can come up with another way to patch kthreads, architectures +without HAVE_RELIABLE_STACKTRACE are not considered fully supported by +the kernel livepatching. The /sys/kernel/livepatch//transition file shows whether a patch is in transition. Only a single patch (the topmost patch on the stack) @@ -176,8 +158,31 @@ If a patch is in transition, this file shows 0 to indicate the task is unpatched and 1 to indicate it's patched. Otherwise, if no patch is in transition, it shows -1. Any tasks which are blocking the transition can be signaled with SIGSTOP and SIGCONT to force them to change their -patched state. +patched state. This may be harmful to the system though. +/sys/kernel/livepatch//signal attribute provides a better alternative. +Writing 1 to the attribute sends a fake signal to all remaining blocking +tasks. No proper signal is actually delivered (there is no data in signal +pending structures). Tasks are interrupted or woken up, and forced to change +their patched state. +Administrator can also affect a transition through +/sys/kernel/livepatch//force attribute. Writing 1 there clears +TIF_PATCH_PENDING flag of all tasks and thus forces the tasks to the patched +state. Important note! The force attribute is intended for cases when the +transition gets stuck for a long time because of a blocking task. Administrator +is expected to collect all necessary data (namely stack traces of such blocking +tasks) and request a clearance from a patch distributor to force the transition. +Unauthorized usage may cause harm to the system. It depends on the nature of the +patch, which functions are (un)patched, and which functions the blocking tasks +are sleeping in (/proc//stack may help here). Removal (rmmod) of patch +modules is permanently disabled when the force feature is used. It cannot be +guaranteed there is no task sleeping in such module. It implies unbounded +reference count if a patch module is disabled and enabled in a loop. + +Moreover, the usage of force may also affect future applications of live +patches and cause even more harm to the system. Administrator should first +consider to simply cancel a transition (see above). If force is used, reboot +should be planned and no more live patches applied. 3.1 Adding consistency model support to new architectures --------------------------------------------------------- @@ -216,13 +221,6 @@ few options: a good backup option for those architectures which don't have reliable stack traces yet. -In the meantime, patches for such architectures can bypass the -consistency model by setting klp_patch.immediate to true. This option -is perfectly fine for patches which don't change the semantics of the -patched functions. In practice, this is usable for ~90% of security -fixes. Use of this option also means the patch can't be unloaded after -it has been disabled. - 4. Livepatch module =================== @@ -278,9 +276,6 @@ into three levels: only for a particular object ( vmlinux or a kernel module ). Note that kallsyms allows for searching symbols according to the object name. - There's also an 'immediate' flag which, when set, patches the - function immediately, bypassing the consistency model safety checks. - + struct klp_object defines an array of patched functions (struct klp_func) in the same object. Where the object is either vmlinux (NULL) or a module name. @@ -299,9 +294,6 @@ into three levels: symbols are found. The only exception are symbols from objects (kernel modules) that have not been loaded yet. - Setting the 'immediate' flag applies the patch to all tasks - immediately, bypassing the consistency model safety checks. - For more details on how the patch is applied on a per-task basis, see the "Consistency model" section. @@ -316,14 +308,12 @@ section "Livepatch life-cycle" below for more details about these two operations. Module removal is only safe when there are no users of the underlying -functions. The immediate consistency model is not able to detect this. The -code just redirects the functions at the very beginning and it does not -check if the functions are in use. In other words, it knows when the -functions get called but it does not know when the functions return. -Therefore it cannot be decided when the livepatch module can be safely -removed. This is solved by a hybrid consistency model. When the system is -transitioned to a new patch state (patched/unpatched) it is guaranteed that -no task sleeps or runs in the old code. +functions. This is the reason why the force feature permanently disables +the removal. The forced tasks entered the functions but we cannot say +that they returned back. Therefore it cannot be decided when the +livepatch module can be safely removed. When the system is successfully +transitioned to a new patch state (patched/unpatched) without being +forced it is guaranteed that no task sleeps or runs in the old code. 5. Livepatch life-cycle @@ -337,19 +327,12 @@ First, the patch is applied only when all patched symbols for already loaded objects are found. The error handling is much easier if this check is done before particular functions get redirected. -Second, the immediate consistency model does not guarantee that anyone is not -sleeping in the new code after the patch is reverted. This means that the new -code needs to stay around "forever". If the code is there, one could apply it -again. Therefore it makes sense to separate the operations that might be done -once and those that need to be repeated when the patch is enabled (applied) -again. - -Third, it might take some time until the entire system is migrated -when a more complex consistency model is used. The patch revert might -block the livepatch module removal for too long. Therefore it is useful -to revert the patch using a separate operation that might be called -explicitly. But it does not make sense to remove all information -until the livepatch module is really removed. +Second, it might take some time until the entire system is migrated with +the hybrid consistency model being used. The patch revert might block +the livepatch module removal for too long. Therefore it is useful to +revert the patch using a separate operation that might be called +explicitly. But it does not make sense to remove all information until +the livepatch module is really removed. 5.1. Registration @@ -435,6 +418,9 @@ Information about the registered patches can be found under /sys/kernel/livepatch. The patches could be enabled and disabled by writing there. +/sys/kernel/livepatch//signal and /sys/kernel/livepatch//force +attributes allow administrator to affect a patching operation. + See Documentation/ABI/testing/sysfs-kernel-livepatch for more details. diff --git a/Documentation/locking/locktorture.txt b/Documentation/locking/locktorture.txt index a2ef3a929bf1..6a8df4cd19bf 100644 --- a/Documentation/locking/locktorture.txt +++ b/Documentation/locking/locktorture.txt @@ -57,11 +57,6 @@ torture_type Type of lock to torture. By default, only spinlocks will o "rwsem_lock": read/write down() and up() semaphore pairs. -torture_runnable Start locktorture at boot time in the case where the - module is built into the kernel, otherwise wait for - torture_runnable to be set via sysfs before starting. - By default it will begin once the module is loaded. - ** Torture-framework (RCU + locking) ** diff --git a/Documentation/maintainer/conf.py b/Documentation/maintainer/conf.py new file mode 100644 index 000000000000..81e9eb7a7884 --- /dev/null +++ b/Documentation/maintainer/conf.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8; mode: python -*- + +project = 'Linux Kernel Development Documentation' + +tags.add("subproject") + +latex_documents = [ + ('index', 'maintainer.tex', 'Linux Kernel Development Documentation', + 'The kernel development community', 'manual'), +] diff --git a/Documentation/maintainer/configure-git.rst b/Documentation/maintainer/configure-git.rst new file mode 100644 index 000000000000..78bbbb0d2c84 --- /dev/null +++ b/Documentation/maintainer/configure-git.rst @@ -0,0 +1,34 @@ +.. _configuregit: + +Configure Git +============= + +This chapter describes maintainer level git configuration. + +Tagged branches used in :ref:`Documentation/maintainer/pull-requests.rst +` should be signed with the developers public GPG key. Signed +tags can be created by passing the ``-u`` flag to ``git tag``. However, +since you would *usually* use the same key for the same project, you can +set it once with +:: + + git config user.signingkey "keyname" + +Alternatively, edit your ``.git/config`` or ``~/.gitconfig`` file by hand: +:: + + [user] + name = Jane Developer + email = jd@domain.org + signingkey = jd@domain.org + +You may need to tell ``git`` to use ``gpg2`` +:: + + [gpg] + program = /path/to/gpg2 + +You may also like to tell ``gpg`` which ``tty`` to use (add to your shell rc file) +:: + + export GPG_TTY=$(tty) diff --git a/Documentation/maintainer/index.rst b/Documentation/maintainer/index.rst new file mode 100644 index 000000000000..2a14916930cb --- /dev/null +++ b/Documentation/maintainer/index.rst @@ -0,0 +1,14 @@ +========================== +Kernel Maintainer Handbook +========================== + +This document is the humble beginning of a manual for kernel maintainers. +There is a lot yet to go here! Please feel free to propose (and write) +additions to this manual. + +.. toctree:: + :maxdepth: 2 + + configure-git + pull-requests + diff --git a/Documentation/maintainer/pull-requests.rst b/Documentation/maintainer/pull-requests.rst new file mode 100644 index 000000000000..a19db3458b56 --- /dev/null +++ b/Documentation/maintainer/pull-requests.rst @@ -0,0 +1,178 @@ +.. _pullrequests: + +Creating Pull Requests +====================== + +This chapter describes how maintainers can create and submit pull requests +to other maintainers. This is useful for transferring changes from one +maintainers tree to another maintainers tree. + +This document was written by Tobin C. Harding (who at that time, was not an +experienced maintainer) primarily from comments made by Greg Kroah-Hartman +and Linus Torvalds on LKML. Suggestions and fixes by Jonathan Corbet and +Mauro Carvalho Chehab. Misrepresentation was unintentional but inevitable, +please direct abuse to Tobin C. Harding . + +Original email thread:: + + http://lkml.kernel.org/r/20171114110500.GA21175@kroah.com + + +Create Branch +------------- + +To start with you will need to have all the changes you wish to include in +the pull request on a separate branch. Typically you will base this branch +off of a branch in the developers tree whom you intend to send the pull +request to. + +In order to create the pull request you must first tag the branch that you +have just created. It is recommended that you choose a meaningful tag name, +in a way that you and others can understand, even after some time. A good +practice is to include in the name an indicator of the sybsystem of origin +and the target kernel version. + +Greg offers the following. A pull request with miscellaneous stuff for +drivers/char, to be applied at the Kernel version 4.15-rc1 could be named +as ``char-misc-4.15-rc1``. If such tag would be produced from a branch +named ``char-misc-next``, you would be using the following command:: + + git tag -s char-misc-4.15-rc1 char-misc-next + +that will create a signed tag called ``char-misc-4.15-rc1`` based on the +last commit in the ``char-misc-next`` branch, and sign it with your gpg key +(see :ref:`Documentation/maintainer/configure_git.rst `). + +Linus will only accept pull requests based on a signed tag. Other +maintainers may differ. + +When you run the above command ``git`` will drop you into an editor and ask +you to describe the tag. In this case, you are describing a pull request, +so outline what is contained here, why it should be merged, and what, if +any, testing has been done. All of this information will end up in the tag +itself, and then in the merge commit that the maintainer makes if/when they +merge the pull request. So write it up well, as it will be in the kernel +tree for forever. + +As said by Linus:: + + Anyway, at least to me, the important part is the *message*. I want + to understand what I'm pulling, and why I should pull it. I also + want to use that message as the message for the merge, so it should + not just make sense to me, but make sense as a historical record + too. + + Note that if there is something odd about the pull request, that + should very much be in the explanation. If you're touching files + that you don't maintain, explain _why_. I will see it in the + diffstat anyway, and if you didn't mention it, I'll just be extra + suspicious. And when you send me new stuff after the merge window + (or even bug-fixes, but ones that look scary), explain not just + what they do and why they do it, but explain the _timing_. What + happened that this didn't go through the merge window.. + + I will take both what you write in the email pull request _and_ in + the signed tag, so depending on your workflow, you can either + describe your work in the signed tag (which will also automatically + make it into the pull request email), or you can make the signed + tag just a placeholder with nothing interesting in it, and describe + the work later when you actually send me the pull request. + + And yes, I will edit the message. Partly because I tend to do just + trivial formatting (the whole indentation and quoting etc), but + partly because part of the message may make sense for me at pull + time (describing the conflicts and your personal issues for sending + it right now), but may not make sense in the context of a merge + commit message, so I will try to make it all make sense. I will + also fix any speeling mistaeks and bad grammar I notice, + particularly for non-native speakers (but also for native ones + ;^). But I may miss some, or even add some. + + Linus + +Greg gives, as an example pull request:: + + Char/Misc patches for 4.15-rc1 + + Here is the big char/misc patch set for the 4.15-rc1 merge window. + Contained in here is the normal set of new functions added to all + of these crazy drivers, as well as the following brand new + subsystems: + - time_travel_controller: Finally a set of drivers for the + latest time travel bus architecture that provides i/o to + the CPU before it asked for it, allowing uninterrupted + processing + - relativity_shifters: due to the affect that the + time_travel_controllers have on the overall system, there + was a need for a new set of relativity shifter drivers to + accommodate the newly formed black holes that would + threaten to suck CPUs into them. This subsystem handles + this in a way to successfully neutralize the problems. + There is a Kconfig option to force these to be enabled + when needed, so problems should not occur. + + All of these patches have been successfully tested in the latest + linux-next releases, and the original problems that it found have + all been resolved (apologies to anyone living near Canberra for the + lack of the Kconfig options in the earlier versions of the + linux-next tree creations.) + + Signed-off-by: Your-name-here + + +The tag message format is just like a git commit id. One line at the top +for a "summary subject" and be sure to sign-off at the bottom. + +Now that you have a local signed tag, you need to push it up to where it +can be retrieved:: + + git push origin char-misc-4.15-rc1 + + +Create Pull Request +------------------- + +The last thing to do is create the pull request message. ``git`` handily +will do this for you with the ``git request-pull`` command, but it needs a +bit of help determining what you want to pull, and on what to base the pull +against (to show the correct changes to be pulled and the diffstat). The +following command(s) will generate a pull request:: + + git request-pull master git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git/ char-misc-4.15-rc1 + +Quoting Greg:: + + This is asking git to compare the difference from the + 'char-misc-4.15-rc1' tag location, to the head of the 'master' + branch (which in my case points to the last location in Linus's + tree that I diverged from, usually a -rc release) and to use the + git:// protocol to pull from. If you wish to use https://, that + can be used here instead as well (but note that some people behind + firewalls will have problems with https git pulls). + + If the char-misc-4.15-rc1 tag is not present in the repo that I am + asking to be pulled from, git will complain saying it is not there, + a handy way to remember to actually push it to a public location. + + The output of 'git request-pull' will contain the location of the + git tree and specific tag to pull from, and the full text + description of that tag (which is why you need to provide good + information in that tag). It will also create a diffstat of the + pull request, and a shortlog of the individual commits that the + pull request will provide. + +Linus responded that he tends to prefer the ``git://`` protocol. Other +maintainers may have different preferences. Also, note that if you are +creating pull requests without a signed tag then ``https://`` may be a +better choice. Please see the original thread for the full discussion. + + +Submit Pull Request +------------------- + +A pull request is submitted in the same way as an ordinary patch. Send as +inline email to the maintainer and CC LKML and any sub-system specific +lists if required. Pull requests to Linus typically have a subject line +something like:: + + [GIT PULL] changes for v4.15-rc1 diff --git a/Documentation/md/raid5-ppl.txt b/Documentation/md/raid5-ppl.txt index 127072b09363..bfa092589e00 100644 --- a/Documentation/md/raid5-ppl.txt +++ b/Documentation/md/raid5-ppl.txt @@ -39,6 +39,7 @@ case the behavior is the same as in plain raid5. PPL is available for md version-1 metadata and external (specifically IMSM) metadata arrays. It can be enabled using mdadm option --consistency-policy=ppl. -Currently, volatile write-back cache should be disabled on all member drives -when using PPL. Otherwise it cannot guarantee consistency in case of power -failure. +There is a limitation of maximum 64 disks in the array for PPL. It allows to +keep data structures and implementation simple. RAID5 arrays with so many disks +are not likely due to high risk of multiple disks failure. Such restriction +should not be a real life limitation. diff --git a/Documentation/media/dmx.h.rst.exceptions b/Documentation/media/dmx.h.rst.exceptions index 629db384104a..63f55a9ae2b1 100644 --- a/Documentation/media/dmx.h.rst.exceptions +++ b/Documentation/media/dmx.h.rst.exceptions @@ -54,3 +54,5 @@ ignore symbol DMX_OUT_DECODER ignore symbol DMX_OUT_TAP ignore symbol DMX_OUT_TS_TAP ignore symbol DMX_OUT_TSDEMUX_TAP + +replace ioctl DMX_DQBUF dmx_qbuf diff --git a/Documentation/media/kapi/cec-core.rst b/Documentation/media/kapi/cec-core.rst index d37e107f2fde..62b9a1448177 100644 --- a/Documentation/media/kapi/cec-core.rst +++ b/Documentation/media/kapi/cec-core.rst @@ -103,6 +103,7 @@ your driver: /* Low-level callbacks */ int (*adap_enable)(struct cec_adapter *adap, bool enable); int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable); + int (*adap_monitor_pin_enable)(struct cec_adapter *adap, bool enable); int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr); int (*adap_transmit)(struct cec_adapter *adap, u8 attempts, u32 signal_free_time, struct cec_msg *msg); @@ -144,6 +145,19 @@ called if the CEC_CAP_MONITOR_ALL capability is set. This callback is optional Note that adap_monitor_all_enable must return 0 if enable is false. +To enable/disable the 'monitor pin' mode: + +.. c:function:: + int (*adap_monitor_pin_enable)(struct cec_adapter *adap, bool enable); + +If enabled, then the adapter should be put in a mode to also monitor CEC pin +changes. Not all hardware supports this and this function is only called if +the CEC_CAP_MONITOR_PIN capability is set. This callback is optional +(some hardware may always be in 'monitor pin' mode). + +Note that adap_monitor_pin_enable must return 0 if enable is false. + + To program a new logical address: .. c:function:: diff --git a/Documentation/media/kapi/dtv-ca.rst b/Documentation/media/kapi/dtv-ca.rst index a4dd700189b0..fded096b937c 100644 --- a/Documentation/media/kapi/dtv-ca.rst +++ b/Documentation/media/kapi/dtv-ca.rst @@ -1,4 +1,4 @@ Digital TV Conditional Access kABI ---------------------------------- -.. kernel-doc:: drivers/media/dvb-core/dvb_ca_en50221.h +.. kernel-doc:: include/media/dvb_ca_en50221.h diff --git a/Documentation/media/kapi/dtv-common.rst b/Documentation/media/kapi/dtv-common.rst index 40cf1033b5e1..7a9574f03190 100644 --- a/Documentation/media/kapi/dtv-common.rst +++ b/Documentation/media/kapi/dtv-common.rst @@ -7,7 +7,7 @@ Math functions Provide some commonly-used math functions, usually required in order to estimate signal strength and signal to noise measurements in dB. -.. kernel-doc:: drivers/media/dvb-core/dvb_math.h +.. kernel-doc:: include/media/dvb_math.h DVB devices @@ -15,7 +15,7 @@ DVB devices Those functions are responsible for handling the DVB device nodes. -.. kernel-doc:: drivers/media/dvb-core/dvbdev.h +.. kernel-doc:: include/media/dvbdev.h Digital TV Ring buffer ~~~~~~~~~~~~~~~~~~~~~~ @@ -52,4 +52,9 @@ copy it from/to userspace. Resetting the buffer counts as a read and write operation. Two or more writers must be locked against each other. -.. kernel-doc:: drivers/media/dvb-core/dvb_ringbuffer.h +.. kernel-doc:: include/media/dvb_ringbuffer.h + +Digital TV VB2 handler +~~~~~~~~~~~~~~~~~~~~~~ + +.. kernel-doc:: include/media/dvb_vb2.h diff --git a/Documentation/media/kapi/dtv-demux.rst b/Documentation/media/kapi/dtv-demux.rst index 7aa865a2b43f..24857133e4e8 100644 --- a/Documentation/media/kapi/dtv-demux.rst +++ b/Documentation/media/kapi/dtv-demux.rst @@ -8,7 +8,7 @@ The Kernel Digital TV Demux kABI defines a driver-internal interface for registering low-level, hardware specific driver to a hardware independent demux layer. It is only of interest for Digital TV device driver writers. The header file for this kABI is named ``demux.h`` and located in -``drivers/media/dvb-core``. +``include/media``. The demux kABI should be implemented for each demux in the system. It is used to select the TS source of a demux and to manage the demux resources. @@ -69,14 +69,14 @@ callbacks. Digital TV Demux device registration functions and data structures ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. kernel-doc:: drivers/media/dvb-core/dmxdev.h +.. kernel-doc:: include/media/dmxdev.h High-level Digital TV demux interface ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. kernel-doc:: drivers/media/dvb-core/dvb_demux.h +.. kernel-doc:: include/media/dvb_demux.h Driver-internal low-level hardware specific driver demux interface ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. kernel-doc:: drivers/media/dvb-core/demux.h +.. kernel-doc:: include/media/demux.h diff --git a/Documentation/media/kapi/dtv-frontend.rst b/Documentation/media/kapi/dtv-frontend.rst index f1a2fdaab5ba..472650cdb100 100644 --- a/Documentation/media/kapi/dtv-frontend.rst +++ b/Documentation/media/kapi/dtv-frontend.rst @@ -8,7 +8,7 @@ The Digital TV Frontend kABI defines a driver-internal interface for registering low-level, hardware specific driver to a hardware independent frontend layer. It is only of interest for Digital TV device driver writers. The header file for this API is named ``dvb_frontend.h`` and located in -``drivers/media/dvb-core``. +``include/media/``. Demodulator driver ^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ The demodulator driver is responsible to talk with the decoding part of the hardware. Such driver should implement :c:type:`dvb_frontend_ops`, with tells what type of digital TV standards are supported, and points to a series of functions that allow the DVB core to command the hardware via -the code under ``drivers/media/dvb-core/dvb_frontend.c``. +the code under ``include/media/dvb_frontend.c``. A typical example of such struct in a driver ``foo`` is:: @@ -118,7 +118,7 @@ Satellite TV reception is:: .. |delta| unicode:: U+00394 -The ``drivers/media/dvb-core/dvb_frontend.c`` has a kernel thread with is +The ``include/media/dvb_frontend.c`` has a kernel thread with is responsible for tuning the device. It supports multiple algorithms to detect a channel, as defined at enum :c:func:`dvbfe_algo`. @@ -440,4 +440,4 @@ monotonic stats at the right time. Digital TV Frontend functions and types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. kernel-doc:: drivers/media/dvb-core/dvb_frontend.h +.. kernel-doc:: include/media/dvb_frontend.h diff --git a/Documentation/media/kapi/dtv-net.rst b/Documentation/media/kapi/dtv-net.rst index ced991b73d69..158c7cbd7600 100644 --- a/Documentation/media/kapi/dtv-net.rst +++ b/Documentation/media/kapi/dtv-net.rst @@ -1,4 +1,4 @@ Digital TV Network kABI ----------------------- -.. kernel-doc:: drivers/media/dvb-core/dvb_net.h +.. kernel-doc:: include/media/dvb_net.h diff --git a/Documentation/media/kapi/rc-core.rst b/Documentation/media/kapi/rc-core.rst index a45895886257..4759f020d6b2 100644 --- a/Documentation/media/kapi/rc-core.rst +++ b/Documentation/media/kapi/rc-core.rst @@ -4,11 +4,83 @@ Remote Controller devices Remote Controller core ~~~~~~~~~~~~~~~~~~~~~~ +The remote controller core implements infrastructure to receive and send +remote controller keyboard keystrokes and mouse events. + +Every time a key is pressed on a remote controller, a scan code is produced. +Also, on most hardware, keeping a key pressed for more than a few dozens of +milliseconds produce a repeat key event. That's somewhat similar to what +a normal keyboard or mouse is handled internally on Linux\ [#f1]_. So, the +remote controller core is implemented on the top of the linux input/evdev +interface. + +.. [#f1] + + The main difference is that, on keyboard events, the keyboard controller + produces one event for a key press and another one for key release. On + infrared-based remote controllers, there's no key release event. Instead, + an extra code is produced to indicate key repeats. + +However, most of the remote controllers use infrared (IR) to transmit signals. +As there are several protocols used to modulate infrared signals, one +important part of the core is dedicated to adjust the driver and the core +system to support the infrared protocol used by the emitter. + +The infrared transmission is done by blinking a infrared emitter using a +carrier. The carrier can be switched on or off by the IR transmitter +hardware. When the carrier is switched on, it is called *PULSE*. +When the carrier is switched off, it is called *SPACE*. + +In other words, a typical IR transmission can be viewed as a sequence of +*PULSE* and *SPACE* events, each with a given duration. + +The carrier parameters (frequency, duty cycle) and the intervals for +*PULSE* and *SPACE* events depend on the protocol. +For example, the NEC protocol uses a carrier of 38kHz, and transmissions +start with a 9ms *PULSE* and a 4.5ms SPACE. It then transmits 16 bits of +scan code, being 8 bits for address (usually it is a fixed number for a +given remote controller), followed by 8 bits of code. A bit "1" is modulated +with 560µs *PULSE* followed by 1690µs *SPACE* and a bit "0" is modulated +with 560µs *PULSE* followed by 560µs *SPACE*. + +At receiver, a simple low-pass filter can be used to convert the received +signal in a sequence of *PULSE/SPACE* events, filtering out the carrier +frequency. Due to that, the receiver doesn't care about the carrier's +actual frequency parameters: all it has to do is to measure the amount +of time it receives *PULSE/SPACE* events. +So, a simple IR receiver hardware will just provide a sequence of timings +for those events to the Kernel. The drivers for hardware with such kind of +receivers are identified by ``RC_DRIVER_IR_RAW``, as defined by +:c:type:`rc_driver_type`\ [#f2]_. Other hardware come with a +microcontroller that decode the *PULSE/SPACE* sequence and return scan +codes to the Kernel. Such kind of receivers are identified +by ``RC_DRIVER_SCANCODE``. + +.. [#f2] + + The RC core also supports devices that have just IR emitters, + without any receivers. Right now, all such devices work only in + raw TX mode. Such kind of hardware is identified as + ``RC_DRIVER_IR_RAW_TX``. + +When the RC core receives events produced by ``RC_DRIVER_IR_RAW`` IR +receivers, it needs to decode the IR protocol, in order to obtain the +corresponding scan code. The protocols supported by the RC core are +defined at enum :c:type:`rc_proto`. + +When the RC code receives a scan code (either directly, by a driver +of the type ``RC_DRIVER_SCANCODE``, or via its IR decoders), it needs +to convert into a Linux input event code. This is done via a mapping +table. + +The Kernel has support for mapping tables available on most media +devices. It also supports loading a table in runtime, via some +sysfs nodes. See the :ref:`RC userspace API ` +for more details. + +Remote controller data structures and functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + .. kernel-doc:: include/media/rc-core.h .. kernel-doc:: include/media/rc-map.h - -LIRC -~~~~ - -.. kernel-doc:: include/media/lirc_dev.h diff --git a/Documentation/media/kapi/v4l2-dev.rst b/Documentation/media/kapi/v4l2-dev.rst index b29aa616c267..7bb0505b60f1 100644 --- a/Documentation/media/kapi/v4l2-dev.rst +++ b/Documentation/media/kapi/v4l2-dev.rst @@ -196,11 +196,18 @@ device. Which device is registered depends on the type argument. The following types exist: -- ``VFL_TYPE_GRABBER``: ``/dev/videoX`` for video input/output devices -- ``VFL_TYPE_VBI``: ``/dev/vbiX`` for vertical blank data (i.e. closed captions, teletext) -- ``VFL_TYPE_RADIO``: ``/dev/radioX`` for radio tuners -- ``VFL_TYPE_SDR``: ``/dev/swradioX`` for Software Defined Radio tuners -- ``VFL_TYPE_TOUCH``: ``/dev/v4l-touchX`` for touch sensors +========================== ==================== ============================== +:c:type:`vfl_devnode_type` Device name Usage +========================== ==================== ============================== +``VFL_TYPE_GRABBER`` ``/dev/videoX`` for video input/output devices +``VFL_TYPE_VBI`` ``/dev/vbiX`` for vertical blank data (i.e. + closed captions, teletext) +``VFL_TYPE_RADIO`` ``/dev/radioX`` for radio tuners +``VFL_TYPE_SUBDEV`` ``/dev/v4l-subdevX`` for V4L2 subdevices +``VFL_TYPE_SDR`` ``/dev/swradioX`` for Software Defined Radio + (SDR) tuners +``VFL_TYPE_TOUCH`` ``/dev/v4l-touchX`` for touch sensors +========================== ==================== ============================== The last argument gives you a certain amount of control over the device device node number used (i.e. the X in ``videoX``). Normally you will pass -1 diff --git a/Documentation/media/kapi/v4l2-event.rst b/Documentation/media/kapi/v4l2-event.rst index 9938d21ef4d1..5c7e31224ddc 100644 --- a/Documentation/media/kapi/v4l2-event.rst +++ b/Documentation/media/kapi/v4l2-event.rst @@ -5,27 +5,68 @@ V4L2 events The V4L2 events provide a generic way to pass events to user space. The driver must use :c:type:`v4l2_fh` to be able to support V4L2 events. -Events are defined by a type and an optional ID. The ID may refer to a V4L2 -object such as a control ID. If unused, then the ID is 0. +Events are subscribed per-filehandle. An event specification consists of a +``type`` and is optionally associated with an object identified through the +``id`` field. If unused, then the ``id`` is 0. So an event is uniquely +identified by the ``(type, id)`` tuple. -When the user subscribes to an event the driver will allocate a number of -kevent structs for that event. So every (type, ID) event tuple will have -its own set of kevent structs. This guarantees that if a driver is generating -lots of events of one type in a short time, then that will not overwrite -events of another type. +The :c:type:`v4l2_fh` struct has a list of subscribed events on its +``subscribed`` field. -But if you get more events of one type than the number of kevents that were -reserved, then the oldest event will be dropped and the new one added. +When the user subscribes to an event, a :c:type:`v4l2_subscribed_event` +struct is added to :c:type:`v4l2_fh`\ ``.subscribed``, one for every +subscribed event. + +Each :c:type:`v4l2_subscribed_event` struct ends with a +:c:type:`v4l2_kevent` ringbuffer, with the size given by the caller +of :c:func:`v4l2_event_subscribe`. This ringbuffer is used to store any events +raised by the driver. + +So every ``(type, ID)`` event tuple will have its own +:c:type:`v4l2_kevent` ringbuffer. This guarantees that if a driver is +generating lots of events of one type in a short time, then that will +not overwrite events of another type. + +But if you get more events of one type than the size of the +:c:type:`v4l2_kevent` ringbuffer, then the oldest event will be dropped +and the new one added. + +The :c:type:`v4l2_kevent` struct links into the ``available`` +list of the :c:type:`v4l2_fh` struct so :ref:`VIDIOC_DQEVENT` will +know which event to dequeue first. + +Finally, if the event subscription is associated with a particular object +such as a V4L2 control, then that object needs to know about that as well +so that an event can be raised by that object. So the ``node`` field can +be used to link the :c:type:`v4l2_subscribed_event` struct into a list of +such objects. + +So to summarize: + +- struct :c:type:`v4l2_fh` has two lists: one of the ``subscribed`` events, + and one of the ``available`` events. + +- struct :c:type:`v4l2_subscribed_event` has a ringbuffer of raised + (pending) events of that particular type. + +- If struct :c:type:`v4l2_subscribed_event` is associated with a specific + object, then that object will have an internal list of + struct :c:type:`v4l2_subscribed_event` so it knows who subscribed an + event to that object. Furthermore, the internal struct :c:type:`v4l2_subscribed_event` has ``merge()`` and ``replace()`` callbacks which drivers can set. These callbacks are called when a new event is raised and there is no more room. + The ``replace()`` callback allows you to replace the payload of the old event with that of the new event, merging any relevant data from the old payload into the new payload that replaces it. It is called when this event type has -only one kevent struct allocated. The ``merge()`` callback allows you to merge -the oldest event payload into that of the second-oldest event payload. It is -called when there are two or more kevent structs allocated. +a ringbuffer with size is one, i.e. only one event can be stored in the +ringbuffer. + +The ``merge()`` callback allows you to merge the oldest event payload into +that of the second-oldest event payload. It is called when +the ringbuffer has size is greater than one. This way no status information is lost, just the intermediate steps leading up to that state. @@ -73,7 +114,7 @@ The ops argument allows the driver to specify a number of callbacks: Callback Description ======== ============================================================== add called when a new listener gets added (subscribing to the same - event twice will only cause this callback to get called once) + event twice will only cause this callback to get called once) del called when a listener stops listening replace replace event 'old' with event 'new'. merge merge event 'old' into event 'new'. diff --git a/Documentation/media/lirc.h.rst.exceptions b/Documentation/media/lirc.h.rst.exceptions index c130617a9986..c6e3a35d2c4e 100644 --- a/Documentation/media/lirc.h.rst.exceptions +++ b/Documentation/media/lirc.h.rst.exceptions @@ -28,6 +28,36 @@ ignore define LIRC_CAN_SEND_MASK ignore define LIRC_CAN_REC_MASK ignore define LIRC_CAN_SET_REC_DUTY_CYCLE +# Obsolete ioctls + +ignore ioctl LIRC_GET_LENGTH + +# rc protocols + +ignore symbol RC_PROTO_UNKNOWN +ignore symbol RC_PROTO_OTHER +ignore symbol RC_PROTO_RC5 +ignore symbol RC_PROTO_RC5X_20 +ignore symbol RC_PROTO_RC5_SZ +ignore symbol RC_PROTO_JVC +ignore symbol RC_PROTO_SONY12 +ignore symbol RC_PROTO_SONY15 +ignore symbol RC_PROTO_SONY20 +ignore symbol RC_PROTO_NEC +ignore symbol RC_PROTO_NECX +ignore symbol RC_PROTO_NEC32 +ignore symbol RC_PROTO_SANYO +ignore symbol RC_PROTO_MCIR2_KBD +ignore symbol RC_PROTO_MCIR2_MSE +ignore symbol RC_PROTO_RC6_0 +ignore symbol RC_PROTO_RC6_6A_20 +ignore symbol RC_PROTO_RC6_6A_24 +ignore symbol RC_PROTO_RC6_6A_32 +ignore symbol RC_PROTO_RC6_MCE +ignore symbol RC_PROTO_SHARP +ignore symbol RC_PROTO_XMP +ignore symbol RC_PROTO_CEC + # Undocumented macros ignore define PULSE_BIT @@ -40,3 +70,4 @@ ignore define LIRC_VALUE_MASK ignore define LIRC_MODE2_MASK ignore define LIRC_MODE_RAW +ignore define LIRC_MODE_LIRCCODE diff --git a/Documentation/media/uapi/dvb/dmx-expbuf.rst b/Documentation/media/uapi/dvb/dmx-expbuf.rst new file mode 100644 index 000000000000..2d96cfe891df --- /dev/null +++ b/Documentation/media/uapi/dvb/dmx-expbuf.rst @@ -0,0 +1,88 @@ +.. _DMX_EXPBUF: + +**************** +ioctl DMX_EXPBUF +**************** + +Name +==== + +DMX_EXPBUF - Export a buffer as a DMABUF file descriptor. + +.. warning:: this API is still experimental + + +Synopsis +======== + +.. c:function:: int ioctl( int fd, DMX_EXPBUF, struct dmx_exportbuffer *argp ) + :name: DMX_EXPBUF + + +Arguments +========= + +``fd`` + File descriptor returned by :ref:`open() `. + +``argp`` + Pointer to struct :c:type:`dmx_exportbuffer`. + + +Description +=========== + +This ioctl is an extension to the memory mapping I/O method. +It can be used to export a buffer as a DMABUF file at any time after +buffers have been allocated with the :ref:`DMX_REQBUFS` ioctl. + +To export a buffer, applications fill struct :c:type:`dmx_exportbuffer`. +Applications must set the ``index`` field. Valid index numbers +range from zero to the number of buffers allocated with :ref:`DMX_REQBUFS` +(struct :c:type:`dmx_requestbuffers` ``count``) minus one. +Additional flags may be posted in the ``flags`` field. Refer to a manual +for open() for details. Currently only O_CLOEXEC, O_RDONLY, O_WRONLY, +and O_RDWR are supported. +All other fields must be set to zero. In the +case of multi-planar API, every plane is exported separately using +multiple :ref:`DMX_EXPBUF` calls. + +After calling :ref:`DMX_EXPBUF` the ``fd`` field will be set by a +driver, on success. This is a DMABUF file descriptor. The application may +pass it to other DMABUF-aware devices. It is recommended to close a DMABUF +file when it is no longer used to allow the associated memory to be reclaimed. + + +Examples +======== + + +.. code-block:: c + + int buffer_export(int v4lfd, enum dmx_buf_type bt, int index, int *dmafd) + { + struct dmx_exportbuffer expbuf; + + memset(&expbuf, 0, sizeof(expbuf)); + expbuf.type = bt; + expbuf.index = index; + if (ioctl(v4lfd, DMX_EXPBUF, &expbuf) == -1) { + perror("DMX_EXPBUF"); + return -1; + } + + *dmafd = expbuf.fd; + + return 0; + } + +Return Value +============ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. + +EINVAL + A queue is not in MMAP mode or DMABUF exporting is not supported or + ``flags`` or ``index`` fields are invalid. diff --git a/Documentation/media/uapi/dvb/dmx-mmap.rst b/Documentation/media/uapi/dvb/dmx-mmap.rst new file mode 100644 index 000000000000..15d107348b9f --- /dev/null +++ b/Documentation/media/uapi/dvb/dmx-mmap.rst @@ -0,0 +1,116 @@ +.. _dmx-mmap: + +***************** +Digital TV mmap() +***************** + +Name +==== + +dmx-mmap - Map device memory into application address space + +.. warning:: this API is still experimental + +Synopsis +======== + +.. code-block:: c + + #include + #include + + +.. c:function:: void *mmap( void *start, size_t length, int prot, int flags, int fd, off_t offset ) + :name: dmx-mmap + +Arguments +========= + +``start`` + Map the buffer to this address in the application's address space. + When the ``MAP_FIXED`` flag is specified, ``start`` must be a + multiple of the pagesize and mmap will fail when the specified + address cannot be used. Use of this option is discouraged; + applications should just specify a ``NULL`` pointer here. + +``length`` + Length of the memory area to map. This must be a multiple of the + DVB packet length (188, on most drivers). + +``prot`` + The ``prot`` argument describes the desired memory protection. + Regardless of the device type and the direction of data exchange it + should be set to ``PROT_READ`` | ``PROT_WRITE``, permitting read + and write access to image buffers. Drivers should support at least + this combination of flags. + +``flags`` + The ``flags`` parameter specifies the type of the mapped object, + mapping options and whether modifications made to the mapped copy of + the page are private to the process or are to be shared with other + references. + + ``MAP_FIXED`` requests that the driver selects no other address than + the one specified. If the specified address cannot be used, + :ref:`mmap() ` will fail. If ``MAP_FIXED`` is specified, + ``start`` must be a multiple of the pagesize. Use of this option is + discouraged. + + One of the ``MAP_SHARED`` or ``MAP_PRIVATE`` flags must be set. + ``MAP_SHARED`` allows applications to share the mapped memory with + other (e. g. child-) processes. + + .. note:: + + The Linux Digital TV applications should not set the + ``MAP_PRIVATE``, ``MAP_DENYWRITE``, ``MAP_EXECUTABLE`` or ``MAP_ANON`` + flags. + +``fd`` + File descriptor returned by :ref:`open() `. + +``offset`` + Offset of the buffer in device memory, as returned by + :ref:`DMX_QUERYBUF` ioctl. + + +Description +=========== + +The :ref:`mmap() ` function asks to map ``length`` bytes starting at +``offset`` in the memory of the device specified by ``fd`` into the +application address space, preferably at address ``start``. This latter +address is a hint only, and is usually specified as 0. + +Suitable length and offset parameters are queried with the +:ref:`DMX_QUERYBUF` ioctl. Buffers must be allocated with the +:ref:`DMX_REQBUFS` ioctl before they can be queried. + +To unmap buffers the :ref:`munmap() ` function is used. + + +Return Value +============ + +On success :ref:`mmap() ` returns a pointer to the mapped buffer. On +error ``MAP_FAILED`` (-1) is returned, and the ``errno`` variable is set +appropriately. Possible error codes are: + +EBADF + ``fd`` is not a valid file descriptor. + +EACCES + ``fd`` is not open for reading and writing. + +EINVAL + The ``start`` or ``length`` or ``offset`` are not suitable. (E. g. + they are too large, or not aligned on a ``PAGESIZE`` boundary.) + + The ``flags`` or ``prot`` value is not supported. + + No buffers have been allocated with the + :ref:`DMX_REQBUFS` ioctl. + +ENOMEM + Not enough physical or virtual memory was available to complete the + request. diff --git a/Documentation/media/uapi/dvb/dmx-munmap.rst b/Documentation/media/uapi/dvb/dmx-munmap.rst new file mode 100644 index 000000000000..d77218732bb6 --- /dev/null +++ b/Documentation/media/uapi/dvb/dmx-munmap.rst @@ -0,0 +1,54 @@ +.. _dmx-munmap: + +************ +DVB munmap() +************ + +Name +==== + +dmx-munmap - Unmap device memory + +.. warning:: This API is still experimental. + + +Synopsis +======== + +.. code-block:: c + + #include + #include + + +.. c:function:: int munmap( void *start, size_t length ) + :name: dmx-munmap + +Arguments +========= + +``start`` + Address of the mapped buffer as returned by the + :ref:`mmap() ` function. + +``length`` + Length of the mapped buffer. This must be the same value as given to + :ref:`mmap() `. + + +Description +=========== + +Unmaps a previously with the :ref:`mmap() ` function mapped +buffer and frees it, if possible. + + +Return Value +============ + +On success :ref:`munmap() ` returns 0, on failure -1 and the +``errno`` variable is set appropriately: + +EINVAL + The ``start`` or ``length`` is incorrect, or no buffers have been + mapped yet. diff --git a/Documentation/media/uapi/dvb/dmx-qbuf.rst b/Documentation/media/uapi/dvb/dmx-qbuf.rst new file mode 100644 index 000000000000..b48c4931658e --- /dev/null +++ b/Documentation/media/uapi/dvb/dmx-qbuf.rst @@ -0,0 +1,83 @@ +.. _DMX_QBUF: + +************************* +ioctl DMX_QBUF, DMX_DQBUF +************************* + +Name +==== + +DMX_QBUF - DMX_DQBUF - Exchange a buffer with the driver + +.. warning:: this API is still experimental + + +Synopsis +======== + +.. c:function:: int ioctl( int fd, DMX_QBUF, struct dmx_buffer *argp ) + :name: DMX_QBUF + +.. c:function:: int ioctl( int fd, DMX_DQBUF, struct dmx_buffer *argp ) + :name: DMX_DQBUF + + +Arguments +========= + +``fd`` + File descriptor returned by :ref:`open() `. + +``argp`` + Pointer to struct :c:type:`dmx_buffer`. + + +Description +=========== + +Applications call the ``DMX_QBUF`` ioctl to enqueue an empty +(capturing) or filled (output) buffer in the driver's incoming queue. +The semantics depend on the selected I/O method. + +To enqueue a buffer applications set the ``index`` field. Valid index +numbers range from zero to the number of buffers allocated with +:ref:`DMX_REQBUFS` (struct :c:type:`dmx_requestbuffers` ``count``) minus +one. The contents of the struct :c:type:`dmx_buffer` returned +by a :ref:`DMX_QUERYBUF` ioctl will do as well. + +When ``DMX_QBUF`` is called with a pointer to this structure, it locks the +memory pages of the buffer in physical memory, so they cannot be swapped +out to disk. Buffers remain locked until dequeued, until the +the device is closed. + +Applications call the ``DMX_DQBUF`` ioctl to dequeue a filled +(capturing) buffer from the driver's outgoing queue. They just set the ``reserved`` field array to zero. When ``DMX_DQBUF`` is called with a +pointer to this structure, the driver fills the remaining fields or +returns an error code. + +By default ``DMX_DQBUF`` blocks when no buffer is in the outgoing +queue. When the ``O_NONBLOCK`` flag was given to the +:ref:`open() ` function, ``DMX_DQBUF`` returns +immediately with an ``EAGAIN`` error code when no buffer is available. + +The struct :c:type:`dmx_buffer` structure is specified in +:ref:`buffer`. + + +Return Value +============ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. + +EAGAIN + Non-blocking I/O has been selected using ``O_NONBLOCK`` and no + buffer was in the outgoing queue. + +EINVAL + The ``index`` is out of bounds, or no buffers have been allocated yet. + +EIO + ``DMX_DQBUF`` failed due to an internal error. Can also indicate + temporary problems like signal loss or CRC errors. diff --git a/Documentation/media/uapi/dvb/dmx-querybuf.rst b/Documentation/media/uapi/dvb/dmx-querybuf.rst new file mode 100644 index 000000000000..89481e24bb86 --- /dev/null +++ b/Documentation/media/uapi/dvb/dmx-querybuf.rst @@ -0,0 +1,63 @@ +.. _DMX_QUERYBUF: + +****************** +ioctl DMX_QUERYBUF +****************** + +Name +==== + +DMX_QUERYBUF - Query the status of a buffer + +.. warning:: this API is still experimental + + +Synopsis +======== + +.. c:function:: int ioctl( int fd, DMX_QUERYBUF, struct dvb_buffer *argp ) + :name: DMX_QUERYBUF + + +Arguments +========= + +``fd`` + File descriptor returned by :ref:`open() `. + +``argp`` + Pointer to struct :c:type:`dvb_buffer`. + + +Description +=========== + +This ioctl is part of the mmap streaming I/O method. It can +be used to query the status of a buffer at any time after buffers have +been allocated with the :ref:`DMX_REQBUFS` ioctl. + +Applications set the ``index`` field. Valid index numbers range from zero +to the number of buffers allocated with :ref:`DMX_REQBUFS` +(struct :c:type:`dvb_requestbuffers` ``count``) minus one. + +After calling :ref:`DMX_QUERYBUF` with a pointer to this structure, +drivers return an error code or fill the rest of the structure. + +On success, the ``offset`` will contain the offset of the buffer from the +start of the device memory, the ``length`` field its size, and the +``bytesused`` the number of bytes occupied by data in the buffer (payload). + +Return Value +============ + +On success 0 is returned, the ``offset`` will contain the offset of the +buffer from the start of the device memory, the ``length`` field its size, +and the ``bytesused`` the number of bytes occupied by data in the buffer +(payload). + +On error it returns -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. + +EINVAL + The ``index`` is out of bounds. diff --git a/Documentation/media/uapi/dvb/dmx-reqbufs.rst b/Documentation/media/uapi/dvb/dmx-reqbufs.rst new file mode 100644 index 000000000000..14b80d60bf35 --- /dev/null +++ b/Documentation/media/uapi/dvb/dmx-reqbufs.rst @@ -0,0 +1,74 @@ +.. _DMX_REQBUFS: + +***************** +ioctl DMX_REQBUFS +***************** + +Name +==== + +DMX_REQBUFS - Initiate Memory Mapping and/or DMA buffer I/O + +.. warning:: this API is still experimental + + +Synopsis +======== + +.. c:function:: int ioctl( int fd, DMX_REQBUFS, struct dmx_requestbuffers *argp ) + :name: DMX_REQBUFS + + +Arguments +========= + +``fd`` + File descriptor returned by :ref:`open() `. + +``argp`` + Pointer to struct :c:type:`dmx_requestbuffers`. + +Description +=========== + +This ioctl is used to initiate a memory mapped or DMABUF based demux I/O. + +Memory mapped buffers are located in device memory and must be allocated +with this ioctl before they can be mapped into the application's address +space. User buffers are allocated by applications themselves, and this +ioctl is merely used to switch the driver into user pointer I/O mode and +to setup some internal structures. Similarly, DMABUF buffers are +allocated by applications through a device driver, and this ioctl only +configures the driver into DMABUF I/O mode without performing any direct +allocation. + +To allocate device buffers applications initialize all fields of the +struct :c:type:`dmx_requestbuffers` structure. They set the ``count`` field +to the desired number of buffers, and ``size`` to the size of each +buffer. + +When the ioctl is called with a pointer to this structure, the driver will +attempt to allocate the requested number of buffers and it stores the actual +number allocated in the ``count`` field. The ``count`` can be smaller than the number requested, even zero, when the driver runs out of free memory. A larger +number is also possible when the driver requires more buffers to +function correctly. The actual allocated buffer size can is returned +at ``size``, and can be smaller than what's requested. + +When this I/O method is not supported, the ioctl returns an ``EOPNOTSUPP`` +error code. + +Applications can call :ref:`DMX_REQBUFS` again to change the number of +buffers, however this cannot succeed when any buffers are still mapped. +A ``count`` value of zero frees all buffers, after aborting or finishing +any DMA in progress. + + +Return Value +============ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes ` chapter. + +EOPNOTSUPP + The the requested I/O method is not supported. diff --git a/Documentation/media/uapi/dvb/dmx_fcalls.rst b/Documentation/media/uapi/dvb/dmx_fcalls.rst index a17289143220..4c391cf2554f 100644 --- a/Documentation/media/uapi/dvb/dmx_fcalls.rst +++ b/Documentation/media/uapi/dvb/dmx_fcalls.rst @@ -13,6 +13,8 @@ Demux Function Calls dmx-fclose dmx-fread dmx-fwrite + dmx-mmap + dmx-munmap dmx-start dmx-stop dmx-set-filter @@ -22,3 +24,7 @@ Demux Function Calls dmx-get-pes-pids dmx-add-pid dmx-remove-pid + dmx-reqbufs + dmx-querybuf + dmx-expbuf + dmx-qbuf diff --git a/Documentation/media/uapi/dvb/fe_property_parameters.rst b/Documentation/media/uapi/dvb/fe_property_parameters.rst index 6eef507fea50..3524dcae4604 100644 --- a/Documentation/media/uapi/dvb/fe_property_parameters.rst +++ b/Documentation/media/uapi/dvb/fe_property_parameters.rst @@ -987,3 +987,21 @@ Possible values: 0, 1, LNA_AUTO 1, LNA on use the special macro LNA_AUTO to set LNA auto + + +.. _DTV-SCRAMBLING-SEQUENCE-INDEX: + +DTV_SCRAMBLING_SEQUENCE_INDEX +============================= + +Used on DVB-S2. + +This 18 bit field, when present, carries the index of the DVB-S2 physical +layer scrambling sequence as defined in clause 5.5.4 of EN 302 307. +There is no explicit signalling method to convey scrambling sequence index +to the receiver. If S2 satellite delivery system descriptor is available +it can be used to read the scrambling sequence index (EN 300 468 table 41). + +By default, gold scrambling sequence index 0 is used. + +The valid scrambling sequence index range is from 0 to 262142. diff --git a/Documentation/media/uapi/dvb/frontend-property-satellite-systems.rst b/Documentation/media/uapi/dvb/frontend-property-satellite-systems.rst index 1f40399c68ff..2929e6999a7a 100644 --- a/Documentation/media/uapi/dvb/frontend-property-satellite-systems.rst +++ b/Documentation/media/uapi/dvb/frontend-property-satellite-systems.rst @@ -60,6 +60,8 @@ following parameters: - :ref:`DTV_STREAM_ID ` +- :ref:`DTV_SCRAMBLING_SEQUENCE_INDEX ` + In addition, the :ref:`DTV QoS statistics ` are also valid. diff --git a/Documentation/media/uapi/rc/lirc-dev-intro.rst b/Documentation/media/uapi/rc/lirc-dev-intro.rst index d1936eeb9ce0..3a74fec66d69 100644 --- a/Documentation/media/uapi/rc/lirc-dev-intro.rst +++ b/Documentation/media/uapi/rc/lirc-dev-intro.rst @@ -6,11 +6,12 @@ Introduction ************ -The LIRC device interface is a bi-directional interface for transporting -raw IR data between userspace and kernelspace. Fundamentally, it is just -a chardev (/dev/lircX, for X = 0, 1, 2, ...), with a number of standard -struct file_operations defined on it. With respect to transporting raw -IR data to and fro, the essential fops are read, write and ioctl. +LIRC stands for Linux Infrared Remote Control. The LIRC device interface is +a bi-directional interface for transporting raw IR and decoded scancodes +data between userspace and kernelspace. Fundamentally, it is just a chardev +(/dev/lircX, for X = 0, 1, 2, ...), with a number of standard struct +file_operations defined on it. With respect to transporting raw IR and +decoded scancodes to and fro, the essential fops are read, write and ioctl. Example dmesg output upon a driver registering w/LIRC: @@ -18,7 +19,7 @@ Example dmesg output upon a driver registering w/LIRC: $ dmesg |grep lirc_dev lirc_dev: IR Remote Control driver registered, major 248 - rc rc0: lirc_dev: driver ir-lirc-codec (mceusb) registered at minor = 0 + rc rc0: lirc_dev: driver mceusb registered at minor = 0 What you should see for a chardev: @@ -36,6 +37,43 @@ LIRC modes LIRC supports some modes of receiving and sending IR codes, as shown on the following table. +.. _lirc-mode-scancode: +.. _lirc-scancode-flag-toggle: +.. _lirc-scancode-flag-repeat: + +``LIRC_MODE_SCANCODE`` + + This mode is for both sending and receiving IR. + + For transmitting (aka sending), create a ``struct lirc_scancode`` with + the desired scancode set in the ``scancode`` member, :c:type:`rc_proto` + set the IR protocol, and all other members set to 0. Write this struct to + the lirc device. + + For receiving, you read ``struct lirc_scancode`` from the lirc device, + with ``scancode`` set to the received scancode and the IR protocol + :c:type:`rc_proto`. If the scancode maps to a valid key code, this is set + in the ``keycode`` field, else it is set to ``KEY_RESERVED``. + + The ``flags`` can have ``LIRC_SCANCODE_FLAG_TOGGLE`` set if the toggle + bit is set in protocols that support it (e.g. rc-5 and rc-6), or + ``LIRC_SCANCODE_FLAG_REPEAT`` for when a repeat is received for protocols + that support it (e.g. nec). + + In the Sanyo and NEC protocol, if you hold a button on remote, rather than + repeating the entire scancode, the remote sends a shorter message with + no scancode, which just means button is held, a "repeat". When this is + received, the ``LIRC_SCANCODE_FLAG_REPEAT`` is set and the scancode and + keycode is repeated. + + With nec, there is no way to distinguish "button hold" from "repeatedly + pressing the same button". The rc-5 and rc-6 protocols have a toggle bit. + When a button is released and pressed again, the toggle bit is inverted. + If the toggle bit is set, the ``LIRC_SCANCODE_FLAG_TOGGLE`` is set. + + The ``timestamp`` field is filled with the time nanoseconds + (in ``CLOCK_MONOTONIC``) when the scancode was decoded. + .. _lirc-mode-mode2: ``LIRC_MODE_MODE2`` @@ -72,21 +110,6 @@ on the following table. this packet will be sent, with the number of microseconds with no IR. -.. _lirc-mode-lirccode: - -``LIRC_MODE_LIRCCODE`` - - This mode can be used for IR receive and send. - - The IR signal is decoded internally by the receiver, or encoded by the - transmitter. The LIRC interface represents the scancode as byte string, - which might not be a u32, it can be any length. The value is entirely - driver dependent. This mode is used by some older lirc drivers. - - The length of each code depends on the driver, which can be retrieved - with :ref:`lirc_get_length`. This length is used both - for transmitting and receiving IR. - .. _lirc-mode-pulse: ``LIRC_MODE_PULSE`` @@ -99,3 +122,13 @@ on the following table. of entries. This mode is used only for IR send. + + +************************** +Remote Controller protocol +************************** + +An enum :c:type:`rc_proto` in the :ref:`lirc_header` lists all the +supported IR protocols: + +.. kernel-doc:: include/uapi/linux/lirc.h diff --git a/Documentation/media/uapi/rc/lirc-func.rst b/Documentation/media/uapi/rc/lirc-func.rst index 9b5a772ec96c..ddb4620de294 100644 --- a/Documentation/media/uapi/rc/lirc-func.rst +++ b/Documentation/media/uapi/rc/lirc-func.rst @@ -18,7 +18,6 @@ LIRC Function Reference lirc-set-send-duty-cycle lirc-get-timeout lirc-set-rec-timeout - lirc-get-length lirc-set-rec-carrier lirc-set-rec-carrier-range lirc-set-send-carrier diff --git a/Documentation/media/uapi/rc/lirc-get-features.rst b/Documentation/media/uapi/rc/lirc-get-features.rst index 64f89a4f9d9c..889a8807037b 100644 --- a/Documentation/media/uapi/rc/lirc-get-features.rst +++ b/Documentation/media/uapi/rc/lirc-get-features.rst @@ -55,15 +55,24 @@ LIRC features ``LIRC_CAN_REC_MODE2`` - The driver is capable of receiving using - :ref:`LIRC_MODE_MODE2 `. + This is raw IR driver for receiving. This means that + :ref:`LIRC_MODE_MODE2 ` is used. This also implies + that :ref:`LIRC_MODE_SCANCODE ` is also supported, + as long as the kernel is recent enough. Use the + :ref:`lirc_set_rec_mode` to switch modes. .. _LIRC-CAN-REC-LIRCCODE: ``LIRC_CAN_REC_LIRCCODE`` - The driver is capable of receiving using - :ref:`LIRC_MODE_LIRCCODE `. + Unused. Kept just to avoid breaking uAPI. + +.. _LIRC-CAN-REC-SCANCODE: + +``LIRC_CAN_REC_SCANCODE`` + + This is a scancode driver for receiving. This means that + :ref:`LIRC_MODE_SCANCODE ` is used. .. _LIRC-CAN-SET-SEND-CARRIER: @@ -157,7 +166,10 @@ LIRC features ``LIRC_CAN_SEND_PULSE`` The driver supports sending (also called as IR blasting or IR TX) using - :ref:`LIRC_MODE_PULSE `. + :ref:`LIRC_MODE_PULSE `. This implies that + :ref:`LIRC_MODE_SCANCODE ` is also supported for + transmit, as long as the kernel is recent enough. Use the + :ref:`lirc_set_send_mode` to switch modes. .. _LIRC-CAN-SEND-MODE2: @@ -170,8 +182,7 @@ LIRC features ``LIRC_CAN_SEND_LIRCCODE`` - The driver supports sending (also called as IR blasting or IR TX) using - :ref:`LIRC_MODE_LIRCCODE `. + Unused. Kept just to avoid breaking uAPI. Return Value diff --git a/Documentation/media/uapi/rc/lirc-get-length.rst b/Documentation/media/uapi/rc/lirc-get-length.rst deleted file mode 100644 index 3990af5de0e9..000000000000 --- a/Documentation/media/uapi/rc/lirc-get-length.rst +++ /dev/null @@ -1,44 +0,0 @@ -.. -*- coding: utf-8; mode: rst -*- - -.. _lirc_get_length: - -********************* -ioctl LIRC_GET_LENGTH -********************* - -Name -==== - -LIRC_GET_LENGTH - Retrieves the code length in bits. - -Synopsis -======== - -.. c:function:: int ioctl( int fd, LIRC_GET_LENGTH, __u32 *length ) - :name: LIRC_GET_LENGTH - -Arguments -========= - -``fd`` - File descriptor returned by open(). - -``length`` - length, in bits - - -Description -=========== - -Retrieves the code length in bits (only for -:ref:`LIRC_MODE_LIRCCODE `). -Reads on the device must be done in blocks matching the bit count. -The bit could should be rounded up so that it matches full bytes. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/rc/lirc-get-rec-mode.rst b/Documentation/media/uapi/rc/lirc-get-rec-mode.rst index a4eb6c0a26e9..2722118484fa 100644 --- a/Documentation/media/uapi/rc/lirc-get-rec-mode.rst +++ b/Documentation/media/uapi/rc/lirc-get-rec-mode.rst @@ -10,15 +10,15 @@ ioctls LIRC_GET_REC_MODE and LIRC_SET_REC_MODE Name ==== -LIRC_GET_REC_MODE/LIRC_SET_REC_MODE - Get/set supported receive modes. +LIRC_GET_REC_MODE/LIRC_SET_REC_MODE - Get/set current receive mode. Synopsis ======== -.. c:function:: int ioctl( int fd, LIRC_GET_REC_MODE, __u32 rx_modes) +.. c:function:: int ioctl( int fd, LIRC_GET_REC_MODE, __u32 *mode) :name: LIRC_GET_REC_MODE -.. c:function:: int ioctl( int fd, LIRC_SET_REC_MODE, __u32 rx_modes) +.. c:function:: int ioctl( int fd, LIRC_SET_REC_MODE, __u32 *mode) :name: LIRC_SET_REC_MODE Arguments @@ -27,20 +27,41 @@ Arguments ``fd`` File descriptor returned by open(). -``rx_modes`` - Bitmask with the supported transmit modes. +``mode`` + Mode used for receive. Description =========== -Get/set supported receive modes. Only :ref:`LIRC_MODE_MODE2 ` -and :ref:`LIRC_MODE_LIRCCODE ` are supported for IR -receive. Use :ref:`lirc_get_features` to find out which modes the driver -supports. +Get and set the current receive mode. Only +:ref:`LIRC_MODE_MODE2 ` and +:ref:`LIRC_MODE_SCANCODE ` are supported. +Use :ref:`lirc_get_features` to find out which modes the driver supports. Return Value ============ -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. +.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + + - .. row 1 + + - ``ENODEV`` + + - Device not available. + + - .. row 2 + + - ``ENOTTY`` + + - Device does not support receiving. + + - .. row 3 + + - ``EINVAL`` + + - Invalid mode or invalid mode for this device. diff --git a/Documentation/media/uapi/rc/lirc-get-send-mode.rst b/Documentation/media/uapi/rc/lirc-get-send-mode.rst index a169b234290e..c44e61a79ad1 100644 --- a/Documentation/media/uapi/rc/lirc-get-send-mode.rst +++ b/Documentation/media/uapi/rc/lirc-get-send-mode.rst @@ -10,15 +10,15 @@ ioctls LIRC_GET_SEND_MODE and LIRC_SET_SEND_MODE Name ==== -LIRC_GET_SEND_MODE/LIRC_SET_SEND_MODE - Get/set supported transmit mode. +LIRC_GET_SEND_MODE/LIRC_SET_SEND_MODE - Get/set current transmit mode. Synopsis ======== -.. c:function:: int ioctl( int fd, LIRC_GET_SEND_MODE, __u32 *tx_modes ) +.. c:function:: int ioctl( int fd, LIRC_GET_SEND_MODE, __u32 *mode ) :name: LIRC_GET_SEND_MODE -.. c:function:: int ioctl( int fd, LIRC_SET_SEND_MODE, __u32 *tx_modes ) +.. c:function:: int ioctl( int fd, LIRC_SET_SEND_MODE, __u32 *mode ) :name: LIRC_SET_SEND_MODE Arguments @@ -27,8 +27,8 @@ Arguments ``fd`` File descriptor returned by open(). -``tx_modes`` - Bitmask with the supported transmit modes. +``mode`` + The mode used for transmitting. Description @@ -37,13 +37,35 @@ Description Get/set current transmit mode. Only :ref:`LIRC_MODE_PULSE ` and -:ref:`LIRC_MODE_LIRCCODE ` is supported by for IR send, +:ref:`LIRC_MODE_SCANCODE ` are supported by for IR send, depending on the driver. Use :ref:`lirc_get_features` to find out which modes the driver supports. Return Value ============ -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. + +.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + + - .. row 1 + + - ``ENODEV`` + + - Device not available. + + - .. row 2 + + - ``ENOTTY`` + + - Device does not support transmitting. + + - .. row 3 + + - ``EINVAL`` + + - Invalid mode or invalid mode for this device. diff --git a/Documentation/media/uapi/rc/lirc-read.rst b/Documentation/media/uapi/rc/lirc-read.rst index ff14a69104e5..c024aaffb8ad 100644 --- a/Documentation/media/uapi/rc/lirc-read.rst +++ b/Documentation/media/uapi/rc/lirc-read.rst @@ -45,13 +45,20 @@ descriptor ``fd`` into the buffer starting at ``buf``. If ``count`` is zero, is greater than ``SSIZE_MAX``, the result is unspecified. The exact format of the data depends on what :ref:`lirc_modes` a driver -uses. Use :ref:`lirc_get_features` to get the supported mode. +uses. Use :ref:`lirc_get_features` to get the supported mode, and use +:ref:`lirc_set_rec_mode` set the current active mode. -The generally preferred mode for receive is -:ref:`LIRC_MODE_MODE2 `, -in which packets containing an int value describing an IR signal are +The mode :ref:`LIRC_MODE_MODE2 ` is for raw IR, +in which packets containing an unsigned int value describing an IR signal are read from the chardev. +Alternatively, :ref:`LIRC_MODE_SCANCODE ` can be available, +in this mode scancodes which are either decoded by software decoders, or +by hardware decoders. The :c:type:`rc_proto` member is set to the +protocol used for transmission, and ``scancode`` to the decoded scancode, +and the ``keycode`` set to the keycode or ``KEY_RESERVED``. + + Return Value ============ diff --git a/Documentation/media/uapi/rc/lirc-write.rst b/Documentation/media/uapi/rc/lirc-write.rst index 2aad0fef4a5b..d4566b0a2015 100644 --- a/Documentation/media/uapi/rc/lirc-write.rst +++ b/Documentation/media/uapi/rc/lirc-write.rst @@ -42,21 +42,32 @@ Description referenced by the file descriptor ``fd`` from the buffer starting at ``buf``. -The exact format of the data depends on what mode a driver uses, use -:ref:`lirc_get_features` to get the supported mode. +The exact format of the data depends on what mode a driver is in, use +:ref:`lirc_get_features` to get the supported modes and use +:ref:`lirc_set_send_mode` set the mode. When in :ref:`LIRC_MODE_PULSE ` mode, the data written to the chardev is a pulse/space sequence of integer values. Pulses and spaces are only marked implicitly by their position. The data must start and end with a pulse, therefore, the data must always include an uneven number of -samples. The write function must block until the data has been transmitted +samples. The write function blocks until the data has been transmitted by the hardware. If more data is provided than the hardware can send, the driver returns ``EINVAL``. +When in :ref:`LIRC_MODE_SCANCODE ` mode, one +``struct lirc_scancode`` must be written to the chardev at a time, else +``EINVAL`` is returned. Set the desired scancode in the ``scancode`` member, +and the protocol in the :c:type:`rc_proto`: member. All other members must be +set to 0, else ``EINVAL`` is returned. If there is no protocol encoder +for the protocol or the scancode is not valid for the specified protocol, +``EINVAL`` is returned. The write function blocks until the scancode +is transmitted by the hardware. + + Return Value ============ -On success, the number of bytes read is returned. It is not an error if +On success, the number of bytes written is returned. It is not an error if this number is smaller than the number of bytes requested, or the amount of data required for one frame. On error, -1 is returned, and the ``errno`` variable is set appropriately. The generic error codes are described at the diff --git a/Documentation/media/uapi/v4l/meta-formats.rst b/Documentation/media/uapi/v4l/meta-formats.rst index 01e24e3df571..0c4e1ecf5879 100644 --- a/Documentation/media/uapi/v4l/meta-formats.rst +++ b/Documentation/media/uapi/v4l/meta-formats.rst @@ -12,5 +12,6 @@ These formats are used for the :ref:`metadata` interface only. .. toctree:: :maxdepth: 1 + pixfmt-meta-uvc pixfmt-meta-vsp1-hgo pixfmt-meta-vsp1-hgt diff --git a/Documentation/media/uapi/v4l/pixfmt-meta-uvc.rst b/Documentation/media/uapi/v4l/pixfmt-meta-uvc.rst new file mode 100644 index 000000000000..b5165dc090c2 --- /dev/null +++ b/Documentation/media/uapi/v4l/pixfmt-meta-uvc.rst @@ -0,0 +1,51 @@ +.. -*- coding: utf-8; mode: rst -*- + +.. _v4l2-meta-fmt-uvc: + +******************************* +V4L2_META_FMT_UVC ('UVCH') +******************************* + +UVC Payload Header Data + + +Description +=========== + +This format describes standard UVC metadata, extracted from UVC packet headers +and provided by the UVC driver through metadata video nodes. That data includes +exact copies of the standard part of UVC Payload Header contents and auxiliary +timing information, required for precise interpretation of timestamps, contained +in those headers. See section "2.4.3.3 Video and Still Image Payload Headers" of +the "UVC 1.5 Class specification" for details. + +Each UVC payload header can be between 2 and 12 bytes large. Buffers can +contain multiple headers, if multiple such headers have been transmitted by the +camera for the respective frame. However, the driver may drop headers when the +buffer is full, when they contain no useful information (e.g. those without the +SCR field or with that field identical to the previous header), or generally to +perform rate limiting when the device sends a large number of headers. + +Each individual block contains the following fields: + +.. flat-table:: UVC Metadata Block + :widths: 1 4 + :header-rows: 1 + :stub-columns: 0 + + * - Field + - Description + * - __u64 ts; + - system timestamp in host byte order, measured by the driver upon + reception of the payload + * - __u16 sof; + - USB Frame Number in host byte order, also obtained by the driver as + close as possible to the above timestamp to enable correlation between + them + * - :cspan:`1` *The rest is an exact copy of the UVC payload header:* + * - __u8 length; + - length of the rest of the block, including this field + * - __u8 flags; + - Flags, indicating presence of other standard UVC fields + * - __u8 buf[]; + - The rest of the header, possibly including UVC PTS and SCR fields diff --git a/Documentation/media/uapi/v4l/pixfmt-rgb.rst b/Documentation/media/uapi/v4l/pixfmt-rgb.rst index 4cc27195dc79..cf2ef7df9616 100644 --- a/Documentation/media/uapi/v4l/pixfmt-rgb.rst +++ b/Documentation/media/uapi/v4l/pixfmt-rgb.rst @@ -16,6 +16,7 @@ RGB Formats pixfmt-srggb10p pixfmt-srggb10alaw8 pixfmt-srggb10dpcm8 + pixfmt-srggb10-ipu3 pixfmt-srggb12 pixfmt-srggb12p pixfmt-srggb16 diff --git a/Documentation/media/uapi/v4l/pixfmt-srggb10-ipu3.rst b/Documentation/media/uapi/v4l/pixfmt-srggb10-ipu3.rst new file mode 100644 index 000000000000..99cde5077519 --- /dev/null +++ b/Documentation/media/uapi/v4l/pixfmt-srggb10-ipu3.rst @@ -0,0 +1,335 @@ +.. -*- coding: utf-8; mode: rst -*- + +.. _v4l2-pix-fmt-ipu3-sbggr10: +.. _v4l2-pix-fmt-ipu3-sgbrg10: +.. _v4l2-pix-fmt-ipu3-sgrbg10: +.. _v4l2-pix-fmt-ipu3-srggb10: + +********************************************************************************************************************************************** +V4L2_PIX_FMT_IPU3_SBGGR10 ('ip3b'), V4L2_PIX_FMT_IPU3_SGBRG10 ('ip3g'), V4L2_PIX_FMT_IPU3_SGRBG10 ('ip3G'), V4L2_PIX_FMT_IPU3_SRGGB10 ('ip3r') +********************************************************************************************************************************************** + +10-bit Bayer formats + +Description +=========== + +These four pixel formats are used by Intel IPU3 driver, they are raw +sRGB / Bayer formats with 10 bits per sample with every 25 pixels packed +to 32 bytes leaving 6 most significant bits padding in the last byte. +The format is little endian. + +In other respects this format is similar to :ref:`V4L2-PIX-FMT-SRGGB10`. +Below is an example of a small image in V4L2_PIX_FMT_IPU3_SBGGR10 format. + +**Byte Order.** +Each cell is one byte. + +.. tabularcolumns:: |p{0.8cm}|p{4.0cm}|p{4.0cm}|p{4.0cm}|p{4.0cm}| + +.. flat-table:: + + * - start + 0: + - B\ :sub:`0000low` + - G\ :sub:`0001low`\ (bits 7--2) + + B\ :sub:`0000high`\ (bits 1--0) + - B\ :sub:`0002low`\ (bits 7--4) + + G\ :sub:`0001high`\ (bits 3--0) + - G\ :sub:`0003low`\ (bits 7--6) + + B\ :sub:`0002high`\ (bits 5--0) + * - start + 4: + - G\ :sub:`0003high` + - B\ :sub:`0004low` + - G\ :sub:`0005low`\ (bits 7--2) + + B\ :sub:`0004high`\ (bits 1--0) + - B\ :sub:`0006low`\ (bits 7--4) + + G\ :sub:`0005high`\ (bits 3--0) + * - start + 8: + - G\ :sub:`0007low`\ (bits 7--6) + + B\ :sub:`0006high`\ (bits 5--0) + - G\ :sub:`0007high` + - B\ :sub:`0008low` + - G\ :sub:`0009low`\ (bits 7--2) + + B\ :sub:`0008high`\ (bits 1--0) + * - start + 12: + - B\ :sub:`0010low`\ (bits 7--4) + + G\ :sub:`0009high`\ (bits 3--0) + - G\ :sub:`0011low`\ (bits 7--6) + + B\ :sub:`0010high`\ (bits 5--0) + - G\ :sub:`0011high` + - B\ :sub:`0012low` + * - start + 16: + - G\ :sub:`0013low`\ (bits 7--2) + + B\ :sub:`0012high`\ (bits 1--0) + - B\ :sub:`0014low`\ (bits 7--4) + + G\ :sub:`0013high`\ (bits 3--0) + - G\ :sub:`0015low`\ (bits 7--6) + + B\ :sub:`0014high`\ (bits 5--0) + - G\ :sub:`0015high` + * - start + 20 + - B\ :sub:`0016low` + - G\ :sub:`0017low`\ (bits 7--2) + + B\ :sub:`0016high`\ (bits 1--0) + - B\ :sub:`0018low`\ (bits 7--4) + + G\ :sub:`0017high`\ (bits 3--0) + - G\ :sub:`0019low`\ (bits 7--6) + + B\ :sub:`0018high`\ (bits 5--0) + * - start + 24: + - G\ :sub:`0019high` + - B\ :sub:`0020low` + - G\ :sub:`0021low`\ (bits 7--2) + + B\ :sub:`0020high`\ (bits 1--0) + - B\ :sub:`0022low`\ (bits 7--4) + + G\ :sub:`0021high`\ (bits 3--0) + * - start + 28: + - G\ :sub:`0023low`\ (bits 7--6) + + B\ :sub:`0022high`\ (bits 5--0) + - G\ :sub:`0023high` + - B\ :sub:`0024low` + - B\ :sub:`0024high`\ (bits 1--0) + * - start + 32: + - G\ :sub:`0100low` + - R\ :sub:`0101low`\ (bits 7--2) + + G\ :sub:`0100high`\ (bits 1--0) + - G\ :sub:`0102low`\ (bits 7--4) + + R\ :sub:`0101high`\ (bits 3--0) + - R\ :sub:`0103low`\ (bits 7--6) + + G\ :sub:`0102high`\ (bits 5--0) + * - start + 36: + - R\ :sub:`0103high` + - G\ :sub:`0104low` + - R\ :sub:`0105low`\ (bits 7--2) + + G\ :sub:`0104high`\ (bits 1--0) + - G\ :sub:`0106low`\ (bits 7--4) + + R\ :sub:`0105high`\ (bits 3--0) + * - start + 40: + - R\ :sub:`0107low`\ (bits 7--6) + + G\ :sub:`0106high`\ (bits 5--0) + - R\ :sub:`0107high` + - G\ :sub:`0108low` + - R\ :sub:`0109low`\ (bits 7--2) + + G\ :sub:`0108high`\ (bits 1--0) + * - start + 44: + - G\ :sub:`0110low`\ (bits 7--4) + + R\ :sub:`0109high`\ (bits 3--0) + - R\ :sub:`0111low`\ (bits 7--6) + + G\ :sub:`0110high`\ (bits 5--0) + - R\ :sub:`0111high` + - G\ :sub:`0112low` + * - start + 48: + - R\ :sub:`0113low`\ (bits 7--2) + + G\ :sub:`0112high`\ (bits 1--0) + - G\ :sub:`0114low`\ (bits 7--4) + + R\ :sub:`0113high`\ (bits 3--0) + - R\ :sub:`0115low`\ (bits 7--6) + + G\ :sub:`0114high`\ (bits 5--0) + - R\ :sub:`0115high` + * - start + 52: + - G\ :sub:`0116low` + - R\ :sub:`0117low`\ (bits 7--2) + + G\ :sub:`0116high`\ (bits 1--0) + - G\ :sub:`0118low`\ (bits 7--4) + + R\ :sub:`0117high`\ (bits 3--0) + - R\ :sub:`0119low`\ (bits 7--6) + + G\ :sub:`0118high`\ (bits 5--0) + * - start + 56: + - R\ :sub:`0119high` + - G\ :sub:`0120low` + - R\ :sub:`0121low`\ (bits 7--2) + + G\ :sub:`0120high`\ (bits 1--0) + - G\ :sub:`0122low`\ (bits 7--4) + + R\ :sub:`0121high`\ (bits 3--0) + * - start + 60: + - R\ :sub:`0123low`\ (bits 7--6) + + G\ :sub:`0122high`\ (bits 5--0) + - R\ :sub:`0123high` + - G\ :sub:`0124low` + - G\ :sub:`0124high`\ (bits 1--0) + * - start + 64: + - B\ :sub:`0200low` + - G\ :sub:`0201low`\ (bits 7--2) + + B\ :sub:`0200high`\ (bits 1--0) + - B\ :sub:`0202low`\ (bits 7--4) + + G\ :sub:`0201high`\ (bits 3--0) + - G\ :sub:`0203low`\ (bits 7--6) + + B\ :sub:`0202high`\ (bits 5--0) + * - start + 68: + - G\ :sub:`0203high` + - B\ :sub:`0204low` + - G\ :sub:`0205low`\ (bits 7--2) + + B\ :sub:`0204high`\ (bits 1--0) + - B\ :sub:`0206low`\ (bits 7--4) + + G\ :sub:`0205high`\ (bits 3--0) + * - start + 72: + - G\ :sub:`0207low`\ (bits 7--6) + + B\ :sub:`0206high`\ (bits 5--0) + - G\ :sub:`0207high` + - B\ :sub:`0208low` + - G\ :sub:`0209low`\ (bits 7--2) + + B\ :sub:`0208high`\ (bits 1--0) + * - start + 76: + - B\ :sub:`0210low`\ (bits 7--4) + + G\ :sub:`0209high`\ (bits 3--0) + - G\ :sub:`0211low`\ (bits 7--6) + + B\ :sub:`0210high`\ (bits 5--0) + - G\ :sub:`0211high` + - B\ :sub:`0212low` + * - start + 80: + - G\ :sub:`0213low`\ (bits 7--2) + + B\ :sub:`0212high`\ (bits 1--0) + - B\ :sub:`0214low`\ (bits 7--4) + + G\ :sub:`0213high`\ (bits 3--0) + - G\ :sub:`0215low`\ (bits 7--6) + + B\ :sub:`0214high`\ (bits 5--0) + - G\ :sub:`0215high` + * - start + 84: + - B\ :sub:`0216low` + - G\ :sub:`0217low`\ (bits 7--2) + + B\ :sub:`0216high`\ (bits 1--0) + - B\ :sub:`0218low`\ (bits 7--4) + + G\ :sub:`0217high`\ (bits 3--0) + - G\ :sub:`0219low`\ (bits 7--6) + + B\ :sub:`0218high`\ (bits 5--0) + * - start + 88: + - G\ :sub:`0219high` + - B\ :sub:`0220low` + - G\ :sub:`0221low`\ (bits 7--2) + + B\ :sub:`0220high`\ (bits 1--0) + - B\ :sub:`0222low`\ (bits 7--4) + + G\ :sub:`0221high`\ (bits 3--0) + * - start + 92: + - G\ :sub:`0223low`\ (bits 7--6) + + B\ :sub:`0222high`\ (bits 5--0) + - G\ :sub:`0223high` + - B\ :sub:`0224low` + - B\ :sub:`0224high`\ (bits 1--0) + * - start + 96: + - G\ :sub:`0300low` + - R\ :sub:`0301low`\ (bits 7--2) + + G\ :sub:`0300high`\ (bits 1--0) + - G\ :sub:`0302low`\ (bits 7--4) + + R\ :sub:`0301high`\ (bits 3--0) + - R\ :sub:`0303low`\ (bits 7--6) + + G\ :sub:`0302high`\ (bits 5--0) + * - start + 100: + - R\ :sub:`0303high` + - G\ :sub:`0304low` + - R\ :sub:`0305low`\ (bits 7--2) + + G\ :sub:`0304high`\ (bits 1--0) + - G\ :sub:`0306low`\ (bits 7--4) + + R\ :sub:`0305high`\ (bits 3--0) + * - start + 104: + - R\ :sub:`0307low`\ (bits 7--6) + + G\ :sub:`0306high`\ (bits 5--0) + - R\ :sub:`0307high` + - G\ :sub:`0308low` + - R\ :sub:`0309low`\ (bits 7--2) + + G\ :sub:`0308high`\ (bits 1--0) + * - start + 108: + - G\ :sub:`0310low`\ (bits 7--4) + + R\ :sub:`0309high`\ (bits 3--0) + - R\ :sub:`0311low`\ (bits 7--6) + + G\ :sub:`0310high`\ (bits 5--0) + - R\ :sub:`0311high` + - G\ :sub:`0312low` + * - start + 112: + - R\ :sub:`0313low`\ (bits 7--2) + + G\ :sub:`0312high`\ (bits 1--0) + - G\ :sub:`0314low`\ (bits 7--4) + + R\ :sub:`0313high`\ (bits 3--0) + - R\ :sub:`0315low`\ (bits 7--6) + + G\ :sub:`0314high`\ (bits 5--0) + - R\ :sub:`0315high` + * - start + 116: + - G\ :sub:`0316low` + - R\ :sub:`0317low`\ (bits 7--2) + + G\ :sub:`0316high`\ (bits 1--0) + - G\ :sub:`0318low`\ (bits 7--4) + + R\ :sub:`0317high`\ (bits 3--0) + - R\ :sub:`0319low`\ (bits 7--6) + + G\ :sub:`0318high`\ (bits 5--0) + * - start + 120: + - R\ :sub:`0319high` + - G\ :sub:`0320low` + - R\ :sub:`0321low`\ (bits 7--2) + + G\ :sub:`0320high`\ (bits 1--0) + - G\ :sub:`0322low`\ (bits 7--4) + + R\ :sub:`0321high`\ (bits 3--0) + * - start + 124: + - R\ :sub:`0323low`\ (bits 7--6) + + G\ :sub:`0322high`\ (bits 5--0) + - R\ :sub:`0323high` + - G\ :sub:`0324low` + - G\ :sub:`0324high`\ (bits 1--0) diff --git a/Documentation/media/uapi/v4l/vidioc-g-dv-timings.rst b/Documentation/media/uapi/v4l/vidioc-g-dv-timings.rst index 2696380626d4..1a034e825161 100644 --- a/Documentation/media/uapi/v4l/vidioc-g-dv-timings.rst +++ b/Documentation/media/uapi/v4l/vidioc-g-dv-timings.rst @@ -267,7 +267,7 @@ EBUSY will also be cleared. * - ``V4L2_DV_FL_HALF_LINE`` - Specific to interlaced formats: if set, then the vertical - frontporch of field 1 (aka the odd field) is really one half-line + backporch of field 1 (aka the odd field) is really one half-line longer and the vertical backporch of field 2 (aka the even field) is really one half-line shorter, so each field has exactly the same number of half-lines. Whether half-lines can be detected or diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 479ecec80593..a863009849a3 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -227,17 +227,20 @@ There are some minimal guarantees that may be expected of a CPU: (*) On any given CPU, dependent memory accesses will be issued in order, with respect to itself. This means that for: - Q = READ_ONCE(P); smp_read_barrier_depends(); D = READ_ONCE(*Q); + Q = READ_ONCE(P); D = READ_ONCE(*Q); the CPU will issue the following memory operations: Q = LOAD P, D = LOAD *Q - and always in that order. On most systems, smp_read_barrier_depends() - does nothing, but it is required for DEC Alpha. The READ_ONCE() - is required to prevent compiler mischief. Please note that you - should normally use something like rcu_dereference() instead of - open-coding smp_read_barrier_depends(). + and always in that order. However, on DEC Alpha, READ_ONCE() also + emits a memory-barrier instruction, so that a DEC Alpha CPU will + instead issue the following memory operations: + + Q = LOAD P, MEMORY_BARRIER, D = LOAD *Q, MEMORY_BARRIER + + Whether on DEC Alpha or not, the READ_ONCE() also prevents compiler + mischief. (*) Overlapping loads and stores within a particular CPU will appear to be ordered within that CPU. This means that for: @@ -1815,7 +1818,7 @@ The Linux kernel has eight basic CPU memory barriers: GENERAL mb() smp_mb() WRITE wmb() smp_wmb() READ rmb() smp_rmb() - DATA DEPENDENCY read_barrier_depends() smp_read_barrier_depends() + DATA DEPENDENCY READ_ONCE() All memory barriers except the data dependency barriers imply a compiler @@ -2864,7 +2867,10 @@ access depends on a read, not all do, so it may not be relied on. Other CPUs may also have split caches, but must coordinate between the various cachelets for normal memory accesses. The semantics of the Alpha removes the -need for coordination in the absence of memory barriers. +need for hardware coordination in the absence of memory barriers, which +permitted Alpha to sport higher CPU clock rates back in the day. However, +please note that smp_read_barrier_depends() should not be used except in +Alpha arch-specific code and within the READ_ONCE() macro. CACHE COHERENCY VS DMA diff --git a/Documentation/mips/AU1xxx_IDE.README b/Documentation/mips/AU1xxx_IDE.README index 52844a58cc8a..ff675a1b1422 100644 --- a/Documentation/mips/AU1xxx_IDE.README +++ b/Documentation/mips/AU1xxx_IDE.README @@ -56,8 +56,6 @@ Following extra configs variables are introduced: CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA - enable the PIO+DBDMA mode CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - enable the MWDMA mode - CONFIG_BLK_DEV_IDE_AU1XXX_BURSTABLE_ON - set Burstable FIFO in DBDMA - controller SUPPORTED IDE MODES @@ -82,11 +80,9 @@ CONFIG_IDE_GENERIC=y CONFIG_BLK_DEV_IDEPCI=y CONFIG_BLK_DEV_GENERIC=y CONFIG_BLK_DEV_IDEDMA_PCI=y -CONFIG_IDEDMA_PCI_AUTO=y CONFIG_BLK_DEV_IDE_AU1XXX=y CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA=y CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_AUTO=y Also define 'IDE_AU1XXX_BURSTMODE' in 'drivers/ide/mips/au1xxx-ide.c' to enable the burst support on DBDMA controller. @@ -94,16 +90,13 @@ the burst support on DBDMA controller. If the used system need the USB support enable the following kernel configs for high IDE to USB throughput. -CONFIG_BLK_DEV_IDEDISK=y CONFIG_IDE_GENERIC=y CONFIG_BLK_DEV_IDEPCI=y CONFIG_BLK_DEV_GENERIC=y CONFIG_BLK_DEV_IDEDMA_PCI=y -CONFIG_IDEDMA_PCI_AUTO=y CONFIG_BLK_DEV_IDE_AU1XXX=y CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA=y CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_AUTO=y Also undefine 'IDE_AU1XXX_BURSTMODE' in 'drivers/ide/mips/au1xxx-ide.c' to disable the burst support on DBDMA controller. diff --git a/Documentation/mtd/spi-nor.txt b/Documentation/mtd/spi-nor.txt index 548d6306ebca..da1fbff5a24c 100644 --- a/Documentation/mtd/spi-nor.txt +++ b/Documentation/mtd/spi-nor.txt @@ -60,3 +60,6 @@ The main API is spi_nor_scan(). Before you call the hook, a driver should initialize the necessary fields for spi_nor{}. Please see drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to fsl-quadspi.c when you want to write a new driver for a SPI NOR controller. +Another API is spi_nor_restore(), this is used to restore the status of SPI +flash chip such as addressing mode. Call it whenever detach the driver from +device or reboot the system. diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX index 7a79b3587dd3..2b89d91b376f 100644 --- a/Documentation/networking/00-INDEX +++ b/Documentation/networking/00-INDEX @@ -36,8 +36,6 @@ bonding.txt - Linux Ethernet Bonding Driver HOWTO: link aggregation in Linux. bridge.txt - where to get user space programs for ethernet bridging with Linux. -can.txt - - documentation on CAN protocol family. cdc_mbim.txt - 3G/LTE USB modem (Mobile Broadband Interface Model) checksum-offloads.txt @@ -228,6 +226,8 @@ x25.txt - general info on X.25 development. x25-iface.txt - description of the X.25 Packet Layer to LAPB device interface. +xfrm_device.txt + - description of XFRM offload API xfrm_proc.txt - description of the statistics package for XFRM. xfrm_sync.txt diff --git a/Documentation/networking/batman-adv.rst b/Documentation/networking/batman-adv.rst index a342b2cc3dc6..245fb6c0ab6f 100644 --- a/Documentation/networking/batman-adv.rst +++ b/Documentation/networking/batman-adv.rst @@ -1,3 +1,5 @@ +.. SPDX-License-Identifier: GPL-2.0 + ========== batman-adv ========== diff --git a/Documentation/networking/can.rst b/Documentation/networking/can.rst new file mode 100644 index 000000000000..d23c51abf8c6 --- /dev/null +++ b/Documentation/networking/can.rst @@ -0,0 +1,1437 @@ +=================================== +SocketCAN - Controller Area Network +=================================== + +Overview / What is SocketCAN +============================ + +The socketcan package is an implementation of CAN protocols +(Controller Area Network) for Linux. CAN is a networking technology +which has widespread use in automation, embedded devices, and +automotive fields. While there have been other CAN implementations +for Linux based on character devices, SocketCAN uses the Berkeley +socket API, the Linux network stack and implements the CAN device +drivers as network interfaces. The CAN socket API has been designed +as similar as possible to the TCP/IP protocols to allow programmers, +familiar with network programming, to easily learn how to use CAN +sockets. + + +.. _socketcan-motivation: + +Motivation / Why Using the Socket API +===================================== + +There have been CAN implementations for Linux before SocketCAN so the +question arises, why we have started another project. Most existing +implementations come as a device driver for some CAN hardware, they +are based on character devices and provide comparatively little +functionality. Usually, there is only a hardware-specific device +driver which provides a character device interface to send and +receive raw CAN frames, directly to/from the controller hardware. +Queueing of frames and higher-level transport protocols like ISO-TP +have to be implemented in user space applications. Also, most +character-device implementations support only one single process to +open the device at a time, similar to a serial interface. Exchanging +the CAN controller requires employment of another device driver and +often the need for adaption of large parts of the application to the +new driver's API. + +SocketCAN was designed to overcome all of these limitations. A new +protocol family has been implemented which provides a socket interface +to user space applications and which builds upon the Linux network +layer, enabling use all of the provided queueing functionality. A device +driver for CAN controller hardware registers itself with the Linux +network layer as a network device, so that CAN frames from the +controller can be passed up to the network layer and on to the CAN +protocol family module and also vice-versa. Also, the protocol family +module provides an API for transport protocol modules to register, so +that any number of transport protocols can be loaded or unloaded +dynamically. In fact, the can core module alone does not provide any +protocol and cannot be used without loading at least one additional +protocol module. Multiple sockets can be opened at the same time, +on different or the same protocol module and they can listen/send +frames on different or the same CAN IDs. Several sockets listening on +the same interface for frames with the same CAN ID are all passed the +same received matching CAN frames. An application wishing to +communicate using a specific transport protocol, e.g. ISO-TP, just +selects that protocol when opening the socket, and then can read and +write application data byte streams, without having to deal with +CAN-IDs, frames, etc. + +Similar functionality visible from user-space could be provided by a +character device, too, but this would lead to a technically inelegant +solution for a couple of reasons: + +* **Intricate usage:** Instead of passing a protocol argument to + socket(2) and using bind(2) to select a CAN interface and CAN ID, an + application would have to do all these operations using ioctl(2)s. + +* **Code duplication:** A character device cannot make use of the Linux + network queueing code, so all that code would have to be duplicated + for CAN networking. + +* **Abstraction:** In most existing character-device implementations, the + hardware-specific device driver for a CAN controller directly + provides the character device for the application to work with. + This is at least very unusual in Unix systems for both, char and + block devices. For example you don't have a character device for a + certain UART of a serial interface, a certain sound chip in your + computer, a SCSI or IDE controller providing access to your hard + disk or tape streamer device. Instead, you have abstraction layers + which provide a unified character or block device interface to the + application on the one hand, and a interface for hardware-specific + device drivers on the other hand. These abstractions are provided + by subsystems like the tty layer, the audio subsystem or the SCSI + and IDE subsystems for the devices mentioned above. + + The easiest way to implement a CAN device driver is as a character + device without such a (complete) abstraction layer, as is done by most + existing drivers. The right way, however, would be to add such a + layer with all the functionality like registering for certain CAN + IDs, supporting several open file descriptors and (de)multiplexing + CAN frames between them, (sophisticated) queueing of CAN frames, and + providing an API for device drivers to register with. However, then + it would be no more difficult, or may be even easier, to use the + networking framework provided by the Linux kernel, and this is what + SocketCAN does. + +The use of the networking framework of the Linux kernel is just the +natural and most appropriate way to implement CAN for Linux. + + +.. _socketcan-concept: + +SocketCAN Concept +================= + +As described in :ref:`socketcan-motivation` the main goal of SocketCAN is to +provide a socket interface to user space applications which builds +upon the Linux network layer. In contrast to the commonly known +TCP/IP and ethernet networking, the CAN bus is a broadcast-only(!) +medium that has no MAC-layer addressing like ethernet. The CAN-identifier +(can_id) is used for arbitration on the CAN-bus. Therefore the CAN-IDs +have to be chosen uniquely on the bus. When designing a CAN-ECU +network the CAN-IDs are mapped to be sent by a specific ECU. +For this reason a CAN-ID can be treated best as a kind of source address. + + +.. _socketcan-receive-lists: + +Receive Lists +------------- + +The network transparent access of multiple applications leads to the +problem that different applications may be interested in the same +CAN-IDs from the same CAN network interface. The SocketCAN core +module - which implements the protocol family CAN - provides several +high efficient receive lists for this reason. If e.g. a user space +application opens a CAN RAW socket, the raw protocol module itself +requests the (range of) CAN-IDs from the SocketCAN core that are +requested by the user. The subscription and unsubscription of +CAN-IDs can be done for specific CAN interfaces or for all(!) known +CAN interfaces with the can_rx_(un)register() functions provided to +CAN protocol modules by the SocketCAN core (see :ref:`socketcan-core-module`). +To optimize the CPU usage at runtime the receive lists are split up +into several specific lists per device that match the requested +filter complexity for a given use-case. + + +.. _socketcan-local-loopback1: + +Local Loopback of Sent Frames +----------------------------- + +As known from other networking concepts the data exchanging +applications may run on the same or different nodes without any +change (except for the according addressing information): + +.. code:: + + ___ ___ ___ _______ ___ + | _ | | _ | | _ | | _ _ | | _ | + ||A|| ||B|| ||C|| ||A| |B|| ||C|| + |___| |___| |___| |_______| |___| + | | | | | + -----------------(1)- CAN bus -(2)--------------- + +To ensure that application A receives the same information in the +example (2) as it would receive in example (1) there is need for +some kind of local loopback of the sent CAN frames on the appropriate +node. + +The Linux network devices (by default) just can handle the +transmission and reception of media dependent frames. Due to the +arbitration on the CAN bus the transmission of a low prio CAN-ID +may be delayed by the reception of a high prio CAN frame. To +reflect the correct [*]_ traffic on the node the loopback of the sent +data has to be performed right after a successful transmission. If +the CAN network interface is not capable of performing the loopback for +some reason the SocketCAN core can do this task as a fallback solution. +See :ref:`socketcan-local-loopback1` for details (recommended). + +The loopback functionality is enabled by default to reflect standard +networking behaviour for CAN applications. Due to some requests from +the RT-SocketCAN group the loopback optionally may be disabled for each +separate socket. See sockopts from the CAN RAW sockets in :ref:`socketcan-raw-sockets`. + +.. [*] you really like to have this when you're running analyser + tools like 'candump' or 'cansniffer' on the (same) node. + + +.. _socketcan-network-problem-notifications: + +Network Problem Notifications +----------------------------- + +The use of the CAN bus may lead to several problems on the physical +and media access control layer. Detecting and logging of these lower +layer problems is a vital requirement for CAN users to identify +hardware issues on the physical transceiver layer as well as +arbitration problems and error frames caused by the different +ECUs. The occurrence of detected errors are important for diagnosis +and have to be logged together with the exact timestamp. For this +reason the CAN interface driver can generate so called Error Message +Frames that can optionally be passed to the user application in the +same way as other CAN frames. Whenever an error on the physical layer +or the MAC layer is detected (e.g. by the CAN controller) the driver +creates an appropriate error message frame. Error messages frames can +be requested by the user application using the common CAN filter +mechanisms. Inside this filter definition the (interested) type of +errors may be selected. The reception of error messages is disabled +by default. The format of the CAN error message frame is briefly +described in the Linux header file "include/uapi/linux/can/error.h". + + +How to use SocketCAN +==================== + +Like TCP/IP, you first need to open a socket for communicating over a +CAN network. Since SocketCAN implements a new protocol family, you +need to pass PF_CAN as the first argument to the socket(2) system +call. Currently, there are two CAN protocols to choose from, the raw +socket protocol and the broadcast manager (BCM). So to open a socket, +you would write:: + + s = socket(PF_CAN, SOCK_RAW, CAN_RAW); + +and:: + + s = socket(PF_CAN, SOCK_DGRAM, CAN_BCM); + +respectively. After the successful creation of the socket, you would +normally use the bind(2) system call to bind the socket to a CAN +interface (which is different from TCP/IP due to different addressing +- see :ref:`socketcan-concept`). After binding (CAN_RAW) or connecting (CAN_BCM) +the socket, you can read(2) and write(2) from/to the socket or use +send(2), sendto(2), sendmsg(2) and the recv* counterpart operations +on the socket as usual. There are also CAN specific socket options +described below. + +The basic CAN frame structure and the sockaddr structure are defined +in include/linux/can.h: + +.. code-block:: C + + struct can_frame { + canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ + __u8 can_dlc; /* frame payload length in byte (0 .. 8) */ + __u8 __pad; /* padding */ + __u8 __res0; /* reserved / padding */ + __u8 __res1; /* reserved / padding */ + __u8 data[8] __attribute__((aligned(8))); + }; + +The alignment of the (linear) payload data[] to a 64bit boundary +allows the user to define their own structs and unions to easily access +the CAN payload. There is no given byteorder on the CAN bus by +default. A read(2) system call on a CAN_RAW socket transfers a +struct can_frame to the user space. + +The sockaddr_can structure has an interface index like the +PF_PACKET socket, that also binds to a specific interface: + +.. code-block:: C + + struct sockaddr_can { + sa_family_t can_family; + int can_ifindex; + union { + /* transport protocol class address info (e.g. ISOTP) */ + struct { canid_t rx_id, tx_id; } tp; + + /* reserved for future CAN protocols address information */ + } can_addr; + }; + +To determine the interface index an appropriate ioctl() has to +be used (example for CAN_RAW sockets without error checking): + +.. code-block:: C + + int s; + struct sockaddr_can addr; + struct ifreq ifr; + + s = socket(PF_CAN, SOCK_RAW, CAN_RAW); + + strcpy(ifr.ifr_name, "can0" ); + ioctl(s, SIOCGIFINDEX, &ifr); + + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + + bind(s, (struct sockaddr *)&addr, sizeof(addr)); + + (..) + +To bind a socket to all(!) CAN interfaces the interface index must +be 0 (zero). In this case the socket receives CAN frames from every +enabled CAN interface. To determine the originating CAN interface +the system call recvfrom(2) may be used instead of read(2). To send +on a socket that is bound to 'any' interface sendto(2) is needed to +specify the outgoing interface. + +Reading CAN frames from a bound CAN_RAW socket (see above) consists +of reading a struct can_frame: + +.. code-block:: C + + struct can_frame frame; + + nbytes = read(s, &frame, sizeof(struct can_frame)); + + if (nbytes < 0) { + perror("can raw socket read"); + return 1; + } + + /* paranoid check ... */ + if (nbytes < sizeof(struct can_frame)) { + fprintf(stderr, "read: incomplete CAN frame\n"); + return 1; + } + + /* do something with the received CAN frame */ + +Writing CAN frames can be done similarly, with the write(2) system call:: + + nbytes = write(s, &frame, sizeof(struct can_frame)); + +When the CAN interface is bound to 'any' existing CAN interface +(addr.can_ifindex = 0) it is recommended to use recvfrom(2) if the +information about the originating CAN interface is needed: + +.. code-block:: C + + struct sockaddr_can addr; + struct ifreq ifr; + socklen_t len = sizeof(addr); + struct can_frame frame; + + nbytes = recvfrom(s, &frame, sizeof(struct can_frame), + 0, (struct sockaddr*)&addr, &len); + + /* get interface name of the received CAN frame */ + ifr.ifr_ifindex = addr.can_ifindex; + ioctl(s, SIOCGIFNAME, &ifr); + printf("Received a CAN frame from interface %s", ifr.ifr_name); + +To write CAN frames on sockets bound to 'any' CAN interface the +outgoing interface has to be defined certainly: + +.. code-block:: C + + strcpy(ifr.ifr_name, "can0"); + ioctl(s, SIOCGIFINDEX, &ifr); + addr.can_ifindex = ifr.ifr_ifindex; + addr.can_family = AF_CAN; + + nbytes = sendto(s, &frame, sizeof(struct can_frame), + 0, (struct sockaddr*)&addr, sizeof(addr)); + +An accurate timestamp can be obtained with an ioctl(2) call after reading +a message from the socket: + +.. code-block:: C + + struct timeval tv; + ioctl(s, SIOCGSTAMP, &tv); + +The timestamp has a resolution of one microsecond and is set automatically +at the reception of a CAN frame. + +Remark about CAN FD (flexible data rate) support: + +Generally the handling of CAN FD is very similar to the formerly described +examples. The new CAN FD capable CAN controllers support two different +bitrates for the arbitration phase and the payload phase of the CAN FD frame +and up to 64 bytes of payload. This extended payload length breaks all the +kernel interfaces (ABI) which heavily rely on the CAN frame with fixed eight +bytes of payload (struct can_frame) like the CAN_RAW socket. Therefore e.g. +the CAN_RAW socket supports a new socket option CAN_RAW_FD_FRAMES that +switches the socket into a mode that allows the handling of CAN FD frames +and (legacy) CAN frames simultaneously (see :ref:`socketcan-rawfd`). + +The struct canfd_frame is defined in include/linux/can.h: + +.. code-block:: C + + struct canfd_frame { + canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ + __u8 len; /* frame payload length in byte (0 .. 64) */ + __u8 flags; /* additional flags for CAN FD */ + __u8 __res0; /* reserved / padding */ + __u8 __res1; /* reserved / padding */ + __u8 data[64] __attribute__((aligned(8))); + }; + +The struct canfd_frame and the existing struct can_frame have the can_id, +the payload length and the payload data at the same offset inside their +structures. This allows to handle the different structures very similar. +When the content of a struct can_frame is copied into a struct canfd_frame +all structure elements can be used as-is - only the data[] becomes extended. + +When introducing the struct canfd_frame it turned out that the data length +code (DLC) of the struct can_frame was used as a length information as the +length and the DLC has a 1:1 mapping in the range of 0 .. 8. To preserve +the easy handling of the length information the canfd_frame.len element +contains a plain length value from 0 .. 64. So both canfd_frame.len and +can_frame.can_dlc are equal and contain a length information and no DLC. +For details about the distinction of CAN and CAN FD capable devices and +the mapping to the bus-relevant data length code (DLC), see :ref:`socketcan-can-fd-driver`. + +The length of the two CAN(FD) frame structures define the maximum transfer +unit (MTU) of the CAN(FD) network interface and skbuff data length. Two +definitions are specified for CAN specific MTUs in include/linux/can.h: + +.. code-block:: C + + #define CAN_MTU (sizeof(struct can_frame)) == 16 => 'legacy' CAN frame + #define CANFD_MTU (sizeof(struct canfd_frame)) == 72 => CAN FD frame + + +.. _socketcan-raw-sockets: + +RAW Protocol Sockets with can_filters (SOCK_RAW) +------------------------------------------------ + +Using CAN_RAW sockets is extensively comparable to the commonly +known access to CAN character devices. To meet the new possibilities +provided by the multi user SocketCAN approach, some reasonable +defaults are set at RAW socket binding time: + +- The filters are set to exactly one filter receiving everything +- The socket only receives valid data frames (=> no error message frames) +- The loopback of sent CAN frames is enabled (see :ref:`socketcan-local-loopback2`) +- The socket does not receive its own sent frames (in loopback mode) + +These default settings may be changed before or after binding the socket. +To use the referenced definitions of the socket options for CAN_RAW +sockets, include . + + +.. _socketcan-rawfilter: + +RAW socket option CAN_RAW_FILTER +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The reception of CAN frames using CAN_RAW sockets can be controlled +by defining 0 .. n filters with the CAN_RAW_FILTER socket option. + +The CAN filter structure is defined in include/linux/can.h: + +.. code-block:: C + + struct can_filter { + canid_t can_id; + canid_t can_mask; + }; + +A filter matches, when: + +.. code-block:: C + + & mask == can_id & mask + +which is analogous to known CAN controllers hardware filter semantics. +The filter can be inverted in this semantic, when the CAN_INV_FILTER +bit is set in can_id element of the can_filter structure. In +contrast to CAN controller hardware filters the user may set 0 .. n +receive filters for each open socket separately: + +.. code-block:: C + + struct can_filter rfilter[2]; + + rfilter[0].can_id = 0x123; + rfilter[0].can_mask = CAN_SFF_MASK; + rfilter[1].can_id = 0x200; + rfilter[1].can_mask = 0x700; + + setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter)); + +To disable the reception of CAN frames on the selected CAN_RAW socket: + +.. code-block:: C + + setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); + +To set the filters to zero filters is quite obsolete as to not read +data causes the raw socket to discard the received CAN frames. But +having this 'send only' use-case we may remove the receive list in the +Kernel to save a little (really a very little!) CPU usage. + +CAN Filter Usage Optimisation +............................. + +The CAN filters are processed in per-device filter lists at CAN frame +reception time. To reduce the number of checks that need to be performed +while walking through the filter lists the CAN core provides an optimized +filter handling when the filter subscription focusses on a single CAN ID. + +For the possible 2048 SFF CAN identifiers the identifier is used as an index +to access the corresponding subscription list without any further checks. +For the 2^29 possible EFF CAN identifiers a 10 bit XOR folding is used as +hash function to retrieve the EFF table index. + +To benefit from the optimized filters for single CAN identifiers the +CAN_SFF_MASK or CAN_EFF_MASK have to be set into can_filter.mask together +with set CAN_EFF_FLAG and CAN_RTR_FLAG bits. A set CAN_EFF_FLAG bit in the +can_filter.mask makes clear that it matters whether a SFF or EFF CAN ID is +subscribed. E.g. in the example from above: + +.. code-block:: C + + rfilter[0].can_id = 0x123; + rfilter[0].can_mask = CAN_SFF_MASK; + +both SFF frames with CAN ID 0x123 and EFF frames with 0xXXXXX123 can pass. + +To filter for only 0x123 (SFF) and 0x12345678 (EFF) CAN identifiers the +filter has to be defined in this way to benefit from the optimized filters: + +.. code-block:: C + + struct can_filter rfilter[2]; + + rfilter[0].can_id = 0x123; + rfilter[0].can_mask = (CAN_EFF_FLAG | CAN_RTR_FLAG | CAN_SFF_MASK); + rfilter[1].can_id = 0x12345678 | CAN_EFF_FLAG; + rfilter[1].can_mask = (CAN_EFF_FLAG | CAN_RTR_FLAG | CAN_EFF_MASK); + + setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter)); + + +RAW Socket Option CAN_RAW_ERR_FILTER +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As described in :ref:`socketcan-network-problem-notifications` the CAN interface driver can generate so +called Error Message Frames that can optionally be passed to the user +application in the same way as other CAN frames. The possible +errors are divided into different error classes that may be filtered +using the appropriate error mask. To register for every possible +error condition CAN_ERR_MASK can be used as value for the error mask. +The values for the error mask are defined in linux/can/error.h: + +.. code-block:: C + + can_err_mask_t err_mask = ( CAN_ERR_TX_TIMEOUT | CAN_ERR_BUSOFF ); + + setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, + &err_mask, sizeof(err_mask)); + + +RAW Socket Option CAN_RAW_LOOPBACK +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To meet multi user needs the local loopback is enabled by default +(see :ref:`socketcan-local-loopback1` for details). But in some embedded use-cases +(e.g. when only one application uses the CAN bus) this loopback +functionality can be disabled (separately for each socket): + +.. code-block:: C + + int loopback = 0; /* 0 = disabled, 1 = enabled (default) */ + + setsockopt(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback)); + + +RAW socket option CAN_RAW_RECV_OWN_MSGS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When the local loopback is enabled, all the sent CAN frames are +looped back to the open CAN sockets that registered for the CAN +frames' CAN-ID on this given interface to meet the multi user +needs. The reception of the CAN frames on the same socket that was +sending the CAN frame is assumed to be unwanted and therefore +disabled by default. This default behaviour may be changed on +demand: + +.. code-block:: C + + int recv_own_msgs = 1; /* 0 = disabled (default), 1 = enabled */ + + setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, + &recv_own_msgs, sizeof(recv_own_msgs)); + + +.. _socketcan-rawfd: + +RAW Socket Option CAN_RAW_FD_FRAMES +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +CAN FD support in CAN_RAW sockets can be enabled with a new socket option +CAN_RAW_FD_FRAMES which is off by default. When the new socket option is +not supported by the CAN_RAW socket (e.g. on older kernels), switching the +CAN_RAW_FD_FRAMES option returns the error -ENOPROTOOPT. + +Once CAN_RAW_FD_FRAMES is enabled the application can send both CAN frames +and CAN FD frames. OTOH the application has to handle CAN and CAN FD frames +when reading from the socket: + +.. code-block:: C + + CAN_RAW_FD_FRAMES enabled: CAN_MTU and CANFD_MTU are allowed + CAN_RAW_FD_FRAMES disabled: only CAN_MTU is allowed (default) + +Example: + +.. code-block:: C + + [ remember: CANFD_MTU == sizeof(struct canfd_frame) ] + + struct canfd_frame cfd; + + nbytes = read(s, &cfd, CANFD_MTU); + + if (nbytes == CANFD_MTU) { + printf("got CAN FD frame with length %d\n", cfd.len); + /* cfd.flags contains valid data */ + } else if (nbytes == CAN_MTU) { + printf("got legacy CAN frame with length %d\n", cfd.len); + /* cfd.flags is undefined */ + } else { + fprintf(stderr, "read: invalid CAN(FD) frame\n"); + return 1; + } + + /* the content can be handled independently from the received MTU size */ + + printf("can_id: %X data length: %d data: ", cfd.can_id, cfd.len); + for (i = 0; i < cfd.len; i++) + printf("%02X ", cfd.data[i]); + +When reading with size CANFD_MTU only returns CAN_MTU bytes that have +been received from the socket a legacy CAN frame has been read into the +provided CAN FD structure. Note that the canfd_frame.flags data field is +not specified in the struct can_frame and therefore it is only valid in +CANFD_MTU sized CAN FD frames. + +Implementation hint for new CAN applications: + +To build a CAN FD aware application use struct canfd_frame as basic CAN +data structure for CAN_RAW based applications. When the application is +executed on an older Linux kernel and switching the CAN_RAW_FD_FRAMES +socket option returns an error: No problem. You'll get legacy CAN frames +or CAN FD frames and can process them the same way. + +When sending to CAN devices make sure that the device is capable to handle +CAN FD frames by checking if the device maximum transfer unit is CANFD_MTU. +The CAN device MTU can be retrieved e.g. with a SIOCGIFMTU ioctl() syscall. + + +RAW socket option CAN_RAW_JOIN_FILTERS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The CAN_RAW socket can set multiple CAN identifier specific filters that +lead to multiple filters in the af_can.c filter processing. These filters +are indenpendent from each other which leads to logical OR'ed filters when +applied (see :ref:`socketcan-rawfilter`). + +This socket option joines the given CAN filters in the way that only CAN +frames are passed to user space that matched *all* given CAN filters. The +semantic for the applied filters is therefore changed to a logical AND. + +This is useful especially when the filterset is a combination of filters +where the CAN_INV_FILTER flag is set in order to notch single CAN IDs or +CAN ID ranges from the incoming traffic. + + +RAW Socket Returned Message Flags +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When using recvmsg() call, the msg->msg_flags may contain following flags: + +MSG_DONTROUTE: + set when the received frame was created on the local host. + +MSG_CONFIRM: + set when the frame was sent via the socket it is received on. + This flag can be interpreted as a 'transmission confirmation' when the + CAN driver supports the echo of frames on driver level, see + :ref:`socketcan-local-loopback1` and :ref:`socketcan-local-loopback2`. + In order to receive such messages, CAN_RAW_RECV_OWN_MSGS must be set. + + +Broadcast Manager Protocol Sockets (SOCK_DGRAM) +----------------------------------------------- + +The Broadcast Manager protocol provides a command based configuration +interface to filter and send (e.g. cyclic) CAN messages in kernel space. + +Receive filters can be used to down sample frequent messages; detect events +such as message contents changes, packet length changes, and do time-out +monitoring of received messages. + +Periodic transmission tasks of CAN frames or a sequence of CAN frames can be +created and modified at runtime; both the message content and the two +possible transmit intervals can be altered. + +A BCM socket is not intended for sending individual CAN frames using the +struct can_frame as known from the CAN_RAW socket. Instead a special BCM +configuration message is defined. The basic BCM configuration message used +to communicate with the broadcast manager and the available operations are +defined in the linux/can/bcm.h include. The BCM message consists of a +message header with a command ('opcode') followed by zero or more CAN frames. +The broadcast manager sends responses to user space in the same form: + +.. code-block:: C + + struct bcm_msg_head { + __u32 opcode; /* command */ + __u32 flags; /* special flags */ + __u32 count; /* run 'count' times with ival1 */ + struct timeval ival1, ival2; /* count and subsequent interval */ + canid_t can_id; /* unique can_id for task */ + __u32 nframes; /* number of can_frames following */ + struct can_frame frames[0]; + }; + +The aligned payload 'frames' uses the same basic CAN frame structure defined +at the beginning of :ref:`socketcan-rawfd` and in the include/linux/can.h include. All +messages to the broadcast manager from user space have this structure. + +Note a CAN_BCM socket must be connected instead of bound after socket +creation (example without error checking): + +.. code-block:: C + + int s; + struct sockaddr_can addr; + struct ifreq ifr; + + s = socket(PF_CAN, SOCK_DGRAM, CAN_BCM); + + strcpy(ifr.ifr_name, "can0"); + ioctl(s, SIOCGIFINDEX, &ifr); + + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + + connect(s, (struct sockaddr *)&addr, sizeof(addr)); + + (..) + +The broadcast manager socket is able to handle any number of in flight +transmissions or receive filters concurrently. The different RX/TX jobs are +distinguished by the unique can_id in each BCM message. However additional +CAN_BCM sockets are recommended to communicate on multiple CAN interfaces. +When the broadcast manager socket is bound to 'any' CAN interface (=> the +interface index is set to zero) the configured receive filters apply to any +CAN interface unless the sendto() syscall is used to overrule the 'any' CAN +interface index. When using recvfrom() instead of read() to retrieve BCM +socket messages the originating CAN interface is provided in can_ifindex. + + +Broadcast Manager Operations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The opcode defines the operation for the broadcast manager to carry out, +or details the broadcast managers response to several events, including +user requests. + +Transmit Operations (user space to broadcast manager): + +TX_SETUP: + Create (cyclic) transmission task. + +TX_DELETE: + Remove (cyclic) transmission task, requires only can_id. + +TX_READ: + Read properties of (cyclic) transmission task for can_id. + +TX_SEND: + Send one CAN frame. + +Transmit Responses (broadcast manager to user space): + +TX_STATUS: + Reply to TX_READ request (transmission task configuration). + +TX_EXPIRED: + Notification when counter finishes sending at initial interval + 'ival1'. Requires the TX_COUNTEVT flag to be set at TX_SETUP. + +Receive Operations (user space to broadcast manager): + +RX_SETUP: + Create RX content filter subscription. + +RX_DELETE: + Remove RX content filter subscription, requires only can_id. + +RX_READ: + Read properties of RX content filter subscription for can_id. + +Receive Responses (broadcast manager to user space): + +RX_STATUS: + Reply to RX_READ request (filter task configuration). + +RX_TIMEOUT: + Cyclic message is detected to be absent (timer ival1 expired). + +RX_CHANGED: + BCM message with updated CAN frame (detected content change). + Sent on first message received or on receipt of revised CAN messages. + + +Broadcast Manager Message Flags +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When sending a message to the broadcast manager the 'flags' element may +contain the following flag definitions which influence the behaviour: + +SETTIMER: + Set the values of ival1, ival2 and count + +STARTTIMER: + Start the timer with the actual values of ival1, ival2 + and count. Starting the timer leads simultaneously to emit a CAN frame. + +TX_COUNTEVT: + Create the message TX_EXPIRED when count expires + +TX_ANNOUNCE: + A change of data by the process is emitted immediately. + +TX_CP_CAN_ID: + Copies the can_id from the message header to each + subsequent frame in frames. This is intended as usage simplification. For + TX tasks the unique can_id from the message header may differ from the + can_id(s) stored for transmission in the subsequent struct can_frame(s). + +RX_FILTER_ID: + Filter by can_id alone, no frames required (nframes=0). + +RX_CHECK_DLC: + A change of the DLC leads to an RX_CHANGED. + +RX_NO_AUTOTIMER: + Prevent automatically starting the timeout monitor. + +RX_ANNOUNCE_RESUME: + If passed at RX_SETUP and a receive timeout occurred, a + RX_CHANGED message will be generated when the (cyclic) receive restarts. + +TX_RESET_MULTI_IDX: + Reset the index for the multiple frame transmission. + +RX_RTR_FRAME: + Send reply for RTR-request (placed in op->frames[0]). + + +Broadcast Manager Transmission Timers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Periodic transmission configurations may use up to two interval timers. +In this case the BCM sends a number of messages ('count') at an interval +'ival1', then continuing to send at another given interval 'ival2'. When +only one timer is needed 'count' is set to zero and only 'ival2' is used. +When SET_TIMER and START_TIMER flag were set the timers are activated. +The timer values can be altered at runtime when only SET_TIMER is set. + + +Broadcast Manager message sequence transmission +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Up to 256 CAN frames can be transmitted in a sequence in the case of a cyclic +TX task configuration. The number of CAN frames is provided in the 'nframes' +element of the BCM message head. The defined number of CAN frames are added +as array to the TX_SETUP BCM configuration message: + +.. code-block:: C + + /* create a struct to set up a sequence of four CAN frames */ + struct { + struct bcm_msg_head msg_head; + struct can_frame frame[4]; + } mytxmsg; + + (..) + mytxmsg.msg_head.nframes = 4; + (..) + + write(s, &mytxmsg, sizeof(mytxmsg)); + +With every transmission the index in the array of CAN frames is increased +and set to zero at index overflow. + + +Broadcast Manager Receive Filter Timers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The timer values ival1 or ival2 may be set to non-zero values at RX_SETUP. +When the SET_TIMER flag is set the timers are enabled: + +ival1: + Send RX_TIMEOUT when a received message is not received again within + the given time. When START_TIMER is set at RX_SETUP the timeout detection + is activated directly - even without a former CAN frame reception. + +ival2: + Throttle the received message rate down to the value of ival2. This + is useful to reduce messages for the application when the signal inside the + CAN frame is stateless as state changes within the ival2 periode may get + lost. + +Broadcast Manager Multiplex Message Receive Filter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To filter for content changes in multiplex message sequences an array of more +than one CAN frames can be passed in a RX_SETUP configuration message. The +data bytes of the first CAN frame contain the mask of relevant bits that +have to match in the subsequent CAN frames with the received CAN frame. +If one of the subsequent CAN frames is matching the bits in that frame data +mark the relevant content to be compared with the previous received content. +Up to 257 CAN frames (multiplex filter bit mask CAN frame plus 256 CAN +filters) can be added as array to the TX_SETUP BCM configuration message: + +.. code-block:: C + + /* usually used to clear CAN frame data[] - beware of endian problems! */ + #define U64_DATA(p) (*(unsigned long long*)(p)->data) + + struct { + struct bcm_msg_head msg_head; + struct can_frame frame[5]; + } msg; + + msg.msg_head.opcode = RX_SETUP; + msg.msg_head.can_id = 0x42; + msg.msg_head.flags = 0; + msg.msg_head.nframes = 5; + U64_DATA(&msg.frame[0]) = 0xFF00000000000000ULL; /* MUX mask */ + U64_DATA(&msg.frame[1]) = 0x01000000000000FFULL; /* data mask (MUX 0x01) */ + U64_DATA(&msg.frame[2]) = 0x0200FFFF000000FFULL; /* data mask (MUX 0x02) */ + U64_DATA(&msg.frame[3]) = 0x330000FFFFFF0003ULL; /* data mask (MUX 0x33) */ + U64_DATA(&msg.frame[4]) = 0x4F07FC0FF0000000ULL; /* data mask (MUX 0x4F) */ + + write(s, &msg, sizeof(msg)); + + +Broadcast Manager CAN FD Support +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The programming API of the CAN_BCM depends on struct can_frame which is +given as array directly behind the bcm_msg_head structure. To follow this +schema for the CAN FD frames a new flag 'CAN_FD_FRAME' in the bcm_msg_head +flags indicates that the concatenated CAN frame structures behind the +bcm_msg_head are defined as struct canfd_frame: + +.. code-block:: C + + struct { + struct bcm_msg_head msg_head; + struct canfd_frame frame[5]; + } msg; + + msg.msg_head.opcode = RX_SETUP; + msg.msg_head.can_id = 0x42; + msg.msg_head.flags = CAN_FD_FRAME; + msg.msg_head.nframes = 5; + (..) + +When using CAN FD frames for multiplex filtering the MUX mask is still +expected in the first 64 bit of the struct canfd_frame data section. + + +Connected Transport Protocols (SOCK_SEQPACKET) +---------------------------------------------- + +(to be written) + + +Unconnected Transport Protocols (SOCK_DGRAM) +-------------------------------------------- + +(to be written) + + +.. _socketcan-core-module: + +SocketCAN Core Module +===================== + +The SocketCAN core module implements the protocol family +PF_CAN. CAN protocol modules are loaded by the core module at +runtime. The core module provides an interface for CAN protocol +modules to subscribe needed CAN IDs (see :ref:`socketcan-receive-lists`). + + +can.ko Module Params +-------------------- + +- **stats_timer**: + To calculate the SocketCAN core statistics + (e.g. current/maximum frames per second) this 1 second timer is + invoked at can.ko module start time by default. This timer can be + disabled by using stattimer=0 on the module commandline. + +- **debug**: + (removed since SocketCAN SVN r546) + + +procfs content +-------------- + +As described in :ref:`socketcan-receive-lists` the SocketCAN core uses several filter +lists to deliver received CAN frames to CAN protocol modules. These +receive lists, their filters and the count of filter matches can be +checked in the appropriate receive list. All entries contain the +device and a protocol module identifier:: + + foo@bar:~$ cat /proc/net/can/rcvlist_all + + receive list 'rx_all': + (vcan3: no entry) + (vcan2: no entry) + (vcan1: no entry) + device can_id can_mask function userdata matches ident + vcan0 000 00000000 f88e6370 f6c6f400 0 raw + (any: no entry) + +In this example an application requests any CAN traffic from vcan0:: + + rcvlist_all - list for unfiltered entries (no filter operations) + rcvlist_eff - list for single extended frame (EFF) entries + rcvlist_err - list for error message frames masks + rcvlist_fil - list for mask/value filters + rcvlist_inv - list for mask/value filters (inverse semantic) + rcvlist_sff - list for single standard frame (SFF) entries + +Additional procfs files in /proc/net/can:: + + stats - SocketCAN core statistics (rx/tx frames, match ratios, ...) + reset_stats - manual statistic reset + version - prints the SocketCAN core version and the ABI version + + +Writing Own CAN Protocol Modules +-------------------------------- + +To implement a new protocol in the protocol family PF_CAN a new +protocol has to be defined in include/linux/can.h . +The prototypes and definitions to use the SocketCAN core can be +accessed by including include/linux/can/core.h . +In addition to functions that register the CAN protocol and the +CAN device notifier chain there are functions to subscribe CAN +frames received by CAN interfaces and to send CAN frames:: + + can_rx_register - subscribe CAN frames from a specific interface + can_rx_unregister - unsubscribe CAN frames from a specific interface + can_send - transmit a CAN frame (optional with local loopback) + +For details see the kerneldoc documentation in net/can/af_can.c or +the source code of net/can/raw.c or net/can/bcm.c . + + +CAN Network Drivers +=================== + +Writing a CAN network device driver is much easier than writing a +CAN character device driver. Similar to other known network device +drivers you mainly have to deal with: + +- TX: Put the CAN frame from the socket buffer to the CAN controller. +- RX: Put the CAN frame from the CAN controller to the socket buffer. + +See e.g. at Documentation/networking/netdevices.txt . The differences +for writing CAN network device driver are described below: + + +General Settings +---------------- + +.. code-block:: C + + dev->type = ARPHRD_CAN; /* the netdevice hardware type */ + dev->flags = IFF_NOARP; /* CAN has no arp */ + + dev->mtu = CAN_MTU; /* sizeof(struct can_frame) -> legacy CAN interface */ + + or alternative, when the controller supports CAN with flexible data rate: + dev->mtu = CANFD_MTU; /* sizeof(struct canfd_frame) -> CAN FD interface */ + +The struct can_frame or struct canfd_frame is the payload of each socket +buffer (skbuff) in the protocol family PF_CAN. + + +.. _socketcan-local-loopback2: + +Local Loopback of Sent Frames +----------------------------- + +As described in :ref:`socketcan-local-loopback1` the CAN network device driver should +support a local loopback functionality similar to the local echo +e.g. of tty devices. In this case the driver flag IFF_ECHO has to be +set to prevent the PF_CAN core from locally echoing sent frames +(aka loopback) as fallback solution:: + + dev->flags = (IFF_NOARP | IFF_ECHO); + + +CAN Controller Hardware Filters +------------------------------- + +To reduce the interrupt load on deep embedded systems some CAN +controllers support the filtering of CAN IDs or ranges of CAN IDs. +These hardware filter capabilities vary from controller to +controller and have to be identified as not feasible in a multi-user +networking approach. The use of the very controller specific +hardware filters could make sense in a very dedicated use-case, as a +filter on driver level would affect all users in the multi-user +system. The high efficient filter sets inside the PF_CAN core allow +to set different multiple filters for each socket separately. +Therefore the use of hardware filters goes to the category 'handmade +tuning on deep embedded systems'. The author is running a MPC603e +@133MHz with four SJA1000 CAN controllers from 2002 under heavy bus +load without any problems ... + + +The Virtual CAN Driver (vcan) +----------------------------- + +Similar to the network loopback devices, vcan offers a virtual local +CAN interface. A full qualified address on CAN consists of + +- a unique CAN Identifier (CAN ID) +- the CAN bus this CAN ID is transmitted on (e.g. can0) + +so in common use cases more than one virtual CAN interface is needed. + +The virtual CAN interfaces allow the transmission and reception of CAN +frames without real CAN controller hardware. Virtual CAN network +devices are usually named 'vcanX', like vcan0 vcan1 vcan2 ... +When compiled as a module the virtual CAN driver module is called vcan.ko + +Since Linux Kernel version 2.6.24 the vcan driver supports the Kernel +netlink interface to create vcan network devices. The creation and +removal of vcan network devices can be managed with the ip(8) tool:: + + - Create a virtual CAN network interface: + $ ip link add type vcan + + - Create a virtual CAN network interface with a specific name 'vcan42': + $ ip link add dev vcan42 type vcan + + - Remove a (virtual CAN) network interface 'vcan42': + $ ip link del vcan42 + + +The CAN Network Device Driver Interface +--------------------------------------- + +The CAN network device driver interface provides a generic interface +to setup, configure and monitor CAN network devices. The user can then +configure the CAN device, like setting the bit-timing parameters, via +the netlink interface using the program "ip" from the "IPROUTE2" +utility suite. The following chapter describes briefly how to use it. +Furthermore, the interface uses a common data structure and exports a +set of common functions, which all real CAN network device drivers +should use. Please have a look to the SJA1000 or MSCAN driver to +understand how to use them. The name of the module is can-dev.ko. + + +Netlink interface to set/get devices properties +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The CAN device must be configured via netlink interface. The supported +netlink message types are defined and briefly described in +"include/linux/can/netlink.h". CAN link support for the program "ip" +of the IPROUTE2 utility suite is available and it can be used as shown +below: + +Setting CAN device properties:: + + $ ip link set can0 type can help + Usage: ip link set DEVICE type can + [ bitrate BITRATE [ sample-point SAMPLE-POINT] ] | + [ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1 + phase-seg2 PHASE-SEG2 [ sjw SJW ] ] + + [ dbitrate BITRATE [ dsample-point SAMPLE-POINT] ] | + [ dtq TQ dprop-seg PROP_SEG dphase-seg1 PHASE-SEG1 + dphase-seg2 PHASE-SEG2 [ dsjw SJW ] ] + + [ loopback { on | off } ] + [ listen-only { on | off } ] + [ triple-sampling { on | off } ] + [ one-shot { on | off } ] + [ berr-reporting { on | off } ] + [ fd { on | off } ] + [ fd-non-iso { on | off } ] + [ presume-ack { on | off } ] + + [ restart-ms TIME-MS ] + [ restart ] + + Where: BITRATE := { 1..1000000 } + SAMPLE-POINT := { 0.000..0.999 } + TQ := { NUMBER } + PROP-SEG := { 1..8 } + PHASE-SEG1 := { 1..8 } + PHASE-SEG2 := { 1..8 } + SJW := { 1..4 } + RESTART-MS := { 0 | NUMBER } + +Display CAN device details and statistics:: + + $ ip -details -statistics link show can0 + 2: can0: mtu 16 qdisc pfifo_fast state UP qlen 10 + link/can + can state ERROR-ACTIVE restart-ms 100 + bitrate 125000 sample_point 0.875 + tq 125 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1 + sja1000: tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..64 brp-inc 1 + clock 8000000 + re-started bus-errors arbit-lost error-warn error-pass bus-off + 41 17457 0 41 42 41 + RX: bytes packets errors dropped overrun mcast + 140859 17608 17457 0 0 0 + TX: bytes packets errors dropped carrier collsns + 861 112 0 41 0 0 + +More info to the above output: + +"" + Shows the list of selected CAN controller modes: LOOPBACK, + LISTEN-ONLY, or TRIPLE-SAMPLING. + +"state ERROR-ACTIVE" + The current state of the CAN controller: "ERROR-ACTIVE", + "ERROR-WARNING", "ERROR-PASSIVE", "BUS-OFF" or "STOPPED" + +"restart-ms 100" + Automatic restart delay time. If set to a non-zero value, a + restart of the CAN controller will be triggered automatically + in case of a bus-off condition after the specified delay time + in milliseconds. By default it's off. + +"bitrate 125000 sample-point 0.875" + Shows the real bit-rate in bits/sec and the sample-point in the + range 0.000..0.999. If the calculation of bit-timing parameters + is enabled in the kernel (CONFIG_CAN_CALC_BITTIMING=y), the + bit-timing can be defined by setting the "bitrate" argument. + Optionally the "sample-point" can be specified. By default it's + 0.000 assuming CIA-recommended sample-points. + +"tq 125 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1" + Shows the time quanta in ns, propagation segment, phase buffer + segment 1 and 2 and the synchronisation jump width in units of + tq. They allow to define the CAN bit-timing in a hardware + independent format as proposed by the Bosch CAN 2.0 spec (see + chapter 8 of http://www.semiconductors.bosch.de/pdf/can2spec.pdf). + +"sja1000: tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..64 brp-inc 1 clock 8000000" + Shows the bit-timing constants of the CAN controller, here the + "sja1000". The minimum and maximum values of the time segment 1 + and 2, the synchronisation jump width in units of tq, the + bitrate pre-scaler and the CAN system clock frequency in Hz. + These constants could be used for user-defined (non-standard) + bit-timing calculation algorithms in user-space. + +"re-started bus-errors arbit-lost error-warn error-pass bus-off" + Shows the number of restarts, bus and arbitration lost errors, + and the state changes to the error-warning, error-passive and + bus-off state. RX overrun errors are listed in the "overrun" + field of the standard network statistics. + +Setting the CAN Bit-Timing +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The CAN bit-timing parameters can always be defined in a hardware +independent format as proposed in the Bosch CAN 2.0 specification +specifying the arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" +and "sjw":: + + $ ip link set canX type can tq 125 prop-seg 6 \ + phase-seg1 7 phase-seg2 2 sjw 1 + +If the kernel option CONFIG_CAN_CALC_BITTIMING is enabled, CIA +recommended CAN bit-timing parameters will be calculated if the bit- +rate is specified with the argument "bitrate":: + + $ ip link set canX type can bitrate 125000 + +Note that this works fine for the most common CAN controllers with +standard bit-rates but may *fail* for exotic bit-rates or CAN system +clock frequencies. Disabling CONFIG_CAN_CALC_BITTIMING saves some +space and allows user-space tools to solely determine and set the +bit-timing parameters. The CAN controller specific bit-timing +constants can be used for that purpose. They are listed by the +following command:: + + $ ip -details link show can0 + ... + sja1000: clock 8000000 tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..64 brp-inc 1 + + +Starting and Stopping the CAN Network Device +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A CAN network device is started or stopped as usual with the command +"ifconfig canX up/down" or "ip link set canX up/down". Be aware that +you *must* define proper bit-timing parameters for real CAN devices +before you can start it to avoid error-prone default settings:: + + $ ip link set canX up type can bitrate 125000 + +A device may enter the "bus-off" state if too many errors occurred on +the CAN bus. Then no more messages are received or sent. An automatic +bus-off recovery can be enabled by setting the "restart-ms" to a +non-zero value, e.g.:: + + $ ip link set canX type can restart-ms 100 + +Alternatively, the application may realize the "bus-off" condition +by monitoring CAN error message frames and do a restart when +appropriate with the command:: + + $ ip link set canX type can restart + +Note that a restart will also create a CAN error message frame (see +also :ref:`socketcan-network-problem-notifications`). + + +.. _socketcan-can-fd-driver: + +CAN FD (Flexible Data Rate) Driver Support +------------------------------------------ + +CAN FD capable CAN controllers support two different bitrates for the +arbitration phase and the payload phase of the CAN FD frame. Therefore a +second bit timing has to be specified in order to enable the CAN FD bitrate. + +Additionally CAN FD capable CAN controllers support up to 64 bytes of +payload. The representation of this length in can_frame.can_dlc and +canfd_frame.len for userspace applications and inside the Linux network +layer is a plain value from 0 .. 64 instead of the CAN 'data length code'. +The data length code was a 1:1 mapping to the payload length in the legacy +CAN frames anyway. The payload length to the bus-relevant DLC mapping is +only performed inside the CAN drivers, preferably with the helper +functions can_dlc2len() and can_len2dlc(). + +The CAN netdevice driver capabilities can be distinguished by the network +devices maximum transfer unit (MTU):: + + MTU = 16 (CAN_MTU) => sizeof(struct can_frame) => 'legacy' CAN device + MTU = 72 (CANFD_MTU) => sizeof(struct canfd_frame) => CAN FD capable device + +The CAN device MTU can be retrieved e.g. with a SIOCGIFMTU ioctl() syscall. +N.B. CAN FD capable devices can also handle and send legacy CAN frames. + +When configuring CAN FD capable CAN controllers an additional 'data' bitrate +has to be set. This bitrate for the data phase of the CAN FD frame has to be +at least the bitrate which was configured for the arbitration phase. This +second bitrate is specified analogue to the first bitrate but the bitrate +setting keywords for the 'data' bitrate start with 'd' e.g. dbitrate, +dsample-point, dsjw or dtq and similar settings. When a data bitrate is set +within the configuration process the controller option "fd on" can be +specified to enable the CAN FD mode in the CAN controller. This controller +option also switches the device MTU to 72 (CANFD_MTU). + +The first CAN FD specification presented as whitepaper at the International +CAN Conference 2012 needed to be improved for data integrity reasons. +Therefore two CAN FD implementations have to be distinguished today: + +- ISO compliant: The ISO 11898-1:2015 CAN FD implementation (default) +- non-ISO compliant: The CAN FD implementation following the 2012 whitepaper + +Finally there are three types of CAN FD controllers: + +1. ISO compliant (fixed) +2. non-ISO compliant (fixed, like the M_CAN IP core v3.0.1 in m_can.c) +3. ISO/non-ISO CAN FD controllers (switchable, like the PEAK PCAN-USB FD) + +The current ISO/non-ISO mode is announced by the CAN controller driver via +netlink and displayed by the 'ip' tool (controller option FD-NON-ISO). +The ISO/non-ISO-mode can be altered by setting 'fd-non-iso {on|off}' for +switchable CAN FD controllers only. + +Example configuring 500 kbit/s arbitration bitrate and 4 Mbit/s data bitrate:: + + $ ip link set can0 up type can bitrate 500000 sample-point 0.75 \ + dbitrate 4000000 dsample-point 0.8 fd on + $ ip -details link show can0 + 5: can0: mtu 72 qdisc pfifo_fast state UNKNOWN \ + mode DEFAULT group default qlen 10 + link/can promiscuity 0 + can state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 0 + bitrate 500000 sample-point 0.750 + tq 50 prop-seg 14 phase-seg1 15 phase-seg2 10 sjw 1 + pcan_usb_pro_fd: tseg1 1..64 tseg2 1..16 sjw 1..16 brp 1..1024 \ + brp-inc 1 + dbitrate 4000000 dsample-point 0.800 + dtq 12 dprop-seg 7 dphase-seg1 8 dphase-seg2 4 dsjw 1 + pcan_usb_pro_fd: dtseg1 1..16 dtseg2 1..8 dsjw 1..4 dbrp 1..1024 \ + dbrp-inc 1 + clock 80000000 + +Example when 'fd-non-iso on' is added on this switchable CAN FD adapter:: + + can state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 0 + + +Supported CAN Hardware +---------------------- + +Please check the "Kconfig" file in "drivers/net/can" to get an actual +list of the support CAN hardware. On the SocketCAN project website +(see :ref:`socketcan-resources`) there might be further drivers available, also for +older kernel versions. + + +.. _socketcan-resources: + +SocketCAN Resources +=================== + +The Linux CAN / SocketCAN project resources (project site / mailing list) +are referenced in the MAINTAINERS file in the Linux source tree. +Search for CAN NETWORK [LAYERS|DRIVERS]. + +Credits +======= + +- Oliver Hartkopp (PF_CAN core, filters, drivers, bcm, SJA1000 driver) +- Urs Thuermann (PF_CAN core, kernel integration, socket interfaces, raw, vcan) +- Jan Kizka (RT-SocketCAN core, Socket-API reconciliation) +- Wolfgang Grandegger (RT-SocketCAN core & drivers, Raw Socket-API reviews, CAN device driver interface, MSCAN driver) +- Robert Schwebel (design reviews, PTXdist integration) +- Marc Kleine-Budde (design reviews, Kernel 2.6 cleanups, drivers) +- Benedikt Spranger (reviews) +- Thomas Gleixner (LKML reviews, coding style, posting hints) +- Andrey Volkov (kernel subtree structure, ioctls, MSCAN driver) +- Matthias Brukner (first SJA1000 CAN netdevice implementation Q2/2003) +- Klaus Hitschler (PEAK driver integration) +- Uwe Koppe (CAN netdevices with PF_PACKET approach) +- Michael Schulze (driver layer loopback requirement, RT CAN drivers review) +- Pavel Pisa (Bit-timing calculation) +- Sascha Hauer (SJA1000 platform driver) +- Sebastian Haas (SJA1000 EMS PCI driver) +- Markus Plessing (SJA1000 EMS PCI driver) +- Per Dalen (SJA1000 Kvaser PCI driver) +- Sam Ravnborg (reviews, coding style, kbuild help) diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt deleted file mode 100644 index aa15b9ee2e70..000000000000 --- a/Documentation/networking/can.txt +++ /dev/null @@ -1,1308 +0,0 @@ -============================================================================ - -can.txt - -Readme file for the Controller Area Network Protocol Family (aka SocketCAN) - -This file contains - - 1 Overview / What is SocketCAN - - 2 Motivation / Why using the socket API - - 3 SocketCAN concept - 3.1 receive lists - 3.2 local loopback of sent frames - 3.3 network problem notifications - - 4 How to use SocketCAN - 4.1 RAW protocol sockets with can_filters (SOCK_RAW) - 4.1.1 RAW socket option CAN_RAW_FILTER - 4.1.2 RAW socket option CAN_RAW_ERR_FILTER - 4.1.3 RAW socket option CAN_RAW_LOOPBACK - 4.1.4 RAW socket option CAN_RAW_RECV_OWN_MSGS - 4.1.5 RAW socket option CAN_RAW_FD_FRAMES - 4.1.6 RAW socket option CAN_RAW_JOIN_FILTERS - 4.1.7 RAW socket returned message flags - 4.2 Broadcast Manager protocol sockets (SOCK_DGRAM) - 4.2.1 Broadcast Manager operations - 4.2.2 Broadcast Manager message flags - 4.2.3 Broadcast Manager transmission timers - 4.2.4 Broadcast Manager message sequence transmission - 4.2.5 Broadcast Manager receive filter timers - 4.2.6 Broadcast Manager multiplex message receive filter - 4.2.7 Broadcast Manager CAN FD support - 4.3 connected transport protocols (SOCK_SEQPACKET) - 4.4 unconnected transport protocols (SOCK_DGRAM) - - 5 SocketCAN core module - 5.1 can.ko module params - 5.2 procfs content - 5.3 writing own CAN protocol modules - - 6 CAN network drivers - 6.1 general settings - 6.2 local loopback of sent frames - 6.3 CAN controller hardware filters - 6.4 The virtual CAN driver (vcan) - 6.5 The CAN network device driver interface - 6.5.1 Netlink interface to set/get devices properties - 6.5.2 Setting the CAN bit-timing - 6.5.3 Starting and stopping the CAN network device - 6.6 CAN FD (flexible data rate) driver support - 6.7 supported CAN hardware - - 7 SocketCAN resources - - 8 Credits - -============================================================================ - -1. Overview / What is SocketCAN --------------------------------- - -The socketcan package is an implementation of CAN protocols -(Controller Area Network) for Linux. CAN is a networking technology -which has widespread use in automation, embedded devices, and -automotive fields. While there have been other CAN implementations -for Linux based on character devices, SocketCAN uses the Berkeley -socket API, the Linux network stack and implements the CAN device -drivers as network interfaces. The CAN socket API has been designed -as similar as possible to the TCP/IP protocols to allow programmers, -familiar with network programming, to easily learn how to use CAN -sockets. - -2. Motivation / Why using the socket API ----------------------------------------- - -There have been CAN implementations for Linux before SocketCAN so the -question arises, why we have started another project. Most existing -implementations come as a device driver for some CAN hardware, they -are based on character devices and provide comparatively little -functionality. Usually, there is only a hardware-specific device -driver which provides a character device interface to send and -receive raw CAN frames, directly to/from the controller hardware. -Queueing of frames and higher-level transport protocols like ISO-TP -have to be implemented in user space applications. Also, most -character-device implementations support only one single process to -open the device at a time, similar to a serial interface. Exchanging -the CAN controller requires employment of another device driver and -often the need for adaption of large parts of the application to the -new driver's API. - -SocketCAN was designed to overcome all of these limitations. A new -protocol family has been implemented which provides a socket interface -to user space applications and which builds upon the Linux network -layer, enabling use all of the provided queueing functionality. A device -driver for CAN controller hardware registers itself with the Linux -network layer as a network device, so that CAN frames from the -controller can be passed up to the network layer and on to the CAN -protocol family module and also vice-versa. Also, the protocol family -module provides an API for transport protocol modules to register, so -that any number of transport protocols can be loaded or unloaded -dynamically. In fact, the can core module alone does not provide any -protocol and cannot be used without loading at least one additional -protocol module. Multiple sockets can be opened at the same time, -on different or the same protocol module and they can listen/send -frames on different or the same CAN IDs. Several sockets listening on -the same interface for frames with the same CAN ID are all passed the -same received matching CAN frames. An application wishing to -communicate using a specific transport protocol, e.g. ISO-TP, just -selects that protocol when opening the socket, and then can read and -write application data byte streams, without having to deal with -CAN-IDs, frames, etc. - -Similar functionality visible from user-space could be provided by a -character device, too, but this would lead to a technically inelegant -solution for a couple of reasons: - -* Intricate usage. Instead of passing a protocol argument to - socket(2) and using bind(2) to select a CAN interface and CAN ID, an - application would have to do all these operations using ioctl(2)s. - -* Code duplication. A character device cannot make use of the Linux - network queueing code, so all that code would have to be duplicated - for CAN networking. - -* Abstraction. In most existing character-device implementations, the - hardware-specific device driver for a CAN controller directly - provides the character device for the application to work with. - This is at least very unusual in Unix systems for both, char and - block devices. For example you don't have a character device for a - certain UART of a serial interface, a certain sound chip in your - computer, a SCSI or IDE controller providing access to your hard - disk or tape streamer device. Instead, you have abstraction layers - which provide a unified character or block device interface to the - application on the one hand, and a interface for hardware-specific - device drivers on the other hand. These abstractions are provided - by subsystems like the tty layer, the audio subsystem or the SCSI - and IDE subsystems for the devices mentioned above. - - The easiest way to implement a CAN device driver is as a character - device without such a (complete) abstraction layer, as is done by most - existing drivers. The right way, however, would be to add such a - layer with all the functionality like registering for certain CAN - IDs, supporting several open file descriptors and (de)multiplexing - CAN frames between them, (sophisticated) queueing of CAN frames, and - providing an API for device drivers to register with. However, then - it would be no more difficult, or may be even easier, to use the - networking framework provided by the Linux kernel, and this is what - SocketCAN does. - - The use of the networking framework of the Linux kernel is just the - natural and most appropriate way to implement CAN for Linux. - -3. SocketCAN concept ---------------------- - - As described in chapter 2 it is the main goal of SocketCAN to - provide a socket interface to user space applications which builds - upon the Linux network layer. In contrast to the commonly known - TCP/IP and ethernet networking, the CAN bus is a broadcast-only(!) - medium that has no MAC-layer addressing like ethernet. The CAN-identifier - (can_id) is used for arbitration on the CAN-bus. Therefore the CAN-IDs - have to be chosen uniquely on the bus. When designing a CAN-ECU - network the CAN-IDs are mapped to be sent by a specific ECU. - For this reason a CAN-ID can be treated best as a kind of source address. - - 3.1 receive lists - - The network transparent access of multiple applications leads to the - problem that different applications may be interested in the same - CAN-IDs from the same CAN network interface. The SocketCAN core - module - which implements the protocol family CAN - provides several - high efficient receive lists for this reason. If e.g. a user space - application opens a CAN RAW socket, the raw protocol module itself - requests the (range of) CAN-IDs from the SocketCAN core that are - requested by the user. The subscription and unsubscription of - CAN-IDs can be done for specific CAN interfaces or for all(!) known - CAN interfaces with the can_rx_(un)register() functions provided to - CAN protocol modules by the SocketCAN core (see chapter 5). - To optimize the CPU usage at runtime the receive lists are split up - into several specific lists per device that match the requested - filter complexity for a given use-case. - - 3.2 local loopback of sent frames - - As known from other networking concepts the data exchanging - applications may run on the same or different nodes without any - change (except for the according addressing information): - - ___ ___ ___ _______ ___ - | _ | | _ | | _ | | _ _ | | _ | - ||A|| ||B|| ||C|| ||A| |B|| ||C|| - |___| |___| |___| |_______| |___| - | | | | | - -----------------(1)- CAN bus -(2)--------------- - - To ensure that application A receives the same information in the - example (2) as it would receive in example (1) there is need for - some kind of local loopback of the sent CAN frames on the appropriate - node. - - The Linux network devices (by default) just can handle the - transmission and reception of media dependent frames. Due to the - arbitration on the CAN bus the transmission of a low prio CAN-ID - may be delayed by the reception of a high prio CAN frame. To - reflect the correct* traffic on the node the loopback of the sent - data has to be performed right after a successful transmission. If - the CAN network interface is not capable of performing the loopback for - some reason the SocketCAN core can do this task as a fallback solution. - See chapter 6.2 for details (recommended). - - The loopback functionality is enabled by default to reflect standard - networking behaviour for CAN applications. Due to some requests from - the RT-SocketCAN group the loopback optionally may be disabled for each - separate socket. See sockopts from the CAN RAW sockets in chapter 4.1. - - * = you really like to have this when you're running analyser tools - like 'candump' or 'cansniffer' on the (same) node. - - 3.3 network problem notifications - - The use of the CAN bus may lead to several problems on the physical - and media access control layer. Detecting and logging of these lower - layer problems is a vital requirement for CAN users to identify - hardware issues on the physical transceiver layer as well as - arbitration problems and error frames caused by the different - ECUs. The occurrence of detected errors are important for diagnosis - and have to be logged together with the exact timestamp. For this - reason the CAN interface driver can generate so called Error Message - Frames that can optionally be passed to the user application in the - same way as other CAN frames. Whenever an error on the physical layer - or the MAC layer is detected (e.g. by the CAN controller) the driver - creates an appropriate error message frame. Error messages frames can - be requested by the user application using the common CAN filter - mechanisms. Inside this filter definition the (interested) type of - errors may be selected. The reception of error messages is disabled - by default. The format of the CAN error message frame is briefly - described in the Linux header file "include/uapi/linux/can/error.h". - -4. How to use SocketCAN ------------------------- - - Like TCP/IP, you first need to open a socket for communicating over a - CAN network. Since SocketCAN implements a new protocol family, you - need to pass PF_CAN as the first argument to the socket(2) system - call. Currently, there are two CAN protocols to choose from, the raw - socket protocol and the broadcast manager (BCM). So to open a socket, - you would write - - s = socket(PF_CAN, SOCK_RAW, CAN_RAW); - - and - - s = socket(PF_CAN, SOCK_DGRAM, CAN_BCM); - - respectively. After the successful creation of the socket, you would - normally use the bind(2) system call to bind the socket to a CAN - interface (which is different from TCP/IP due to different addressing - - see chapter 3). After binding (CAN_RAW) or connecting (CAN_BCM) - the socket, you can read(2) and write(2) from/to the socket or use - send(2), sendto(2), sendmsg(2) and the recv* counterpart operations - on the socket as usual. There are also CAN specific socket options - described below. - - The basic CAN frame structure and the sockaddr structure are defined - in include/linux/can.h: - - struct can_frame { - canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ - __u8 can_dlc; /* frame payload length in byte (0 .. 8) */ - __u8 __pad; /* padding */ - __u8 __res0; /* reserved / padding */ - __u8 __res1; /* reserved / padding */ - __u8 data[8] __attribute__((aligned(8))); - }; - - The alignment of the (linear) payload data[] to a 64bit boundary - allows the user to define their own structs and unions to easily access - the CAN payload. There is no given byteorder on the CAN bus by - default. A read(2) system call on a CAN_RAW socket transfers a - struct can_frame to the user space. - - The sockaddr_can structure has an interface index like the - PF_PACKET socket, that also binds to a specific interface: - - struct sockaddr_can { - sa_family_t can_family; - int can_ifindex; - union { - /* transport protocol class address info (e.g. ISOTP) */ - struct { canid_t rx_id, tx_id; } tp; - - /* reserved for future CAN protocols address information */ - } can_addr; - }; - - To determine the interface index an appropriate ioctl() has to - be used (example for CAN_RAW sockets without error checking): - - int s; - struct sockaddr_can addr; - struct ifreq ifr; - - s = socket(PF_CAN, SOCK_RAW, CAN_RAW); - - strcpy(ifr.ifr_name, "can0" ); - ioctl(s, SIOCGIFINDEX, &ifr); - - addr.can_family = AF_CAN; - addr.can_ifindex = ifr.ifr_ifindex; - - bind(s, (struct sockaddr *)&addr, sizeof(addr)); - - (..) - - To bind a socket to all(!) CAN interfaces the interface index must - be 0 (zero). In this case the socket receives CAN frames from every - enabled CAN interface. To determine the originating CAN interface - the system call recvfrom(2) may be used instead of read(2). To send - on a socket that is bound to 'any' interface sendto(2) is needed to - specify the outgoing interface. - - Reading CAN frames from a bound CAN_RAW socket (see above) consists - of reading a struct can_frame: - - struct can_frame frame; - - nbytes = read(s, &frame, sizeof(struct can_frame)); - - if (nbytes < 0) { - perror("can raw socket read"); - return 1; - } - - /* paranoid check ... */ - if (nbytes < sizeof(struct can_frame)) { - fprintf(stderr, "read: incomplete CAN frame\n"); - return 1; - } - - /* do something with the received CAN frame */ - - Writing CAN frames can be done similarly, with the write(2) system call: - - nbytes = write(s, &frame, sizeof(struct can_frame)); - - When the CAN interface is bound to 'any' existing CAN interface - (addr.can_ifindex = 0) it is recommended to use recvfrom(2) if the - information about the originating CAN interface is needed: - - struct sockaddr_can addr; - struct ifreq ifr; - socklen_t len = sizeof(addr); - struct can_frame frame; - - nbytes = recvfrom(s, &frame, sizeof(struct can_frame), - 0, (struct sockaddr*)&addr, &len); - - /* get interface name of the received CAN frame */ - ifr.ifr_ifindex = addr.can_ifindex; - ioctl(s, SIOCGIFNAME, &ifr); - printf("Received a CAN frame from interface %s", ifr.ifr_name); - - To write CAN frames on sockets bound to 'any' CAN interface the - outgoing interface has to be defined certainly. - - strcpy(ifr.ifr_name, "can0"); - ioctl(s, SIOCGIFINDEX, &ifr); - addr.can_ifindex = ifr.ifr_ifindex; - addr.can_family = AF_CAN; - - nbytes = sendto(s, &frame, sizeof(struct can_frame), - 0, (struct sockaddr*)&addr, sizeof(addr)); - - An accurate timestamp can be obtained with an ioctl(2) call after reading - a message from the socket: - - struct timeval tv; - ioctl(s, SIOCGSTAMP, &tv); - - The timestamp has a resolution of one microsecond and is set automatically - at the reception of a CAN frame. - - Remark about CAN FD (flexible data rate) support: - - Generally the handling of CAN FD is very similar to the formerly described - examples. The new CAN FD capable CAN controllers support two different - bitrates for the arbitration phase and the payload phase of the CAN FD frame - and up to 64 bytes of payload. This extended payload length breaks all the - kernel interfaces (ABI) which heavily rely on the CAN frame with fixed eight - bytes of payload (struct can_frame) like the CAN_RAW socket. Therefore e.g. - the CAN_RAW socket supports a new socket option CAN_RAW_FD_FRAMES that - switches the socket into a mode that allows the handling of CAN FD frames - and (legacy) CAN frames simultaneously (see section 4.1.5). - - The struct canfd_frame is defined in include/linux/can.h: - - struct canfd_frame { - canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ - __u8 len; /* frame payload length in byte (0 .. 64) */ - __u8 flags; /* additional flags for CAN FD */ - __u8 __res0; /* reserved / padding */ - __u8 __res1; /* reserved / padding */ - __u8 data[64] __attribute__((aligned(8))); - }; - - The struct canfd_frame and the existing struct can_frame have the can_id, - the payload length and the payload data at the same offset inside their - structures. This allows to handle the different structures very similar. - When the content of a struct can_frame is copied into a struct canfd_frame - all structure elements can be used as-is - only the data[] becomes extended. - - When introducing the struct canfd_frame it turned out that the data length - code (DLC) of the struct can_frame was used as a length information as the - length and the DLC has a 1:1 mapping in the range of 0 .. 8. To preserve - the easy handling of the length information the canfd_frame.len element - contains a plain length value from 0 .. 64. So both canfd_frame.len and - can_frame.can_dlc are equal and contain a length information and no DLC. - For details about the distinction of CAN and CAN FD capable devices and - the mapping to the bus-relevant data length code (DLC), see chapter 6.6. - - The length of the two CAN(FD) frame structures define the maximum transfer - unit (MTU) of the CAN(FD) network interface and skbuff data length. Two - definitions are specified for CAN specific MTUs in include/linux/can.h : - - #define CAN_MTU (sizeof(struct can_frame)) == 16 => 'legacy' CAN frame - #define CANFD_MTU (sizeof(struct canfd_frame)) == 72 => CAN FD frame - - 4.1 RAW protocol sockets with can_filters (SOCK_RAW) - - Using CAN_RAW sockets is extensively comparable to the commonly - known access to CAN character devices. To meet the new possibilities - provided by the multi user SocketCAN approach, some reasonable - defaults are set at RAW socket binding time: - - - The filters are set to exactly one filter receiving everything - - The socket only receives valid data frames (=> no error message frames) - - The loopback of sent CAN frames is enabled (see chapter 3.2) - - The socket does not receive its own sent frames (in loopback mode) - - These default settings may be changed before or after binding the socket. - To use the referenced definitions of the socket options for CAN_RAW - sockets, include . - - 4.1.1 RAW socket option CAN_RAW_FILTER - - The reception of CAN frames using CAN_RAW sockets can be controlled - by defining 0 .. n filters with the CAN_RAW_FILTER socket option. - - The CAN filter structure is defined in include/linux/can.h: - - struct can_filter { - canid_t can_id; - canid_t can_mask; - }; - - A filter matches, when - - & mask == can_id & mask - - which is analogous to known CAN controllers hardware filter semantics. - The filter can be inverted in this semantic, when the CAN_INV_FILTER - bit is set in can_id element of the can_filter structure. In - contrast to CAN controller hardware filters the user may set 0 .. n - receive filters for each open socket separately: - - struct can_filter rfilter[2]; - - rfilter[0].can_id = 0x123; - rfilter[0].can_mask = CAN_SFF_MASK; - rfilter[1].can_id = 0x200; - rfilter[1].can_mask = 0x700; - - setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter)); - - To disable the reception of CAN frames on the selected CAN_RAW socket: - - setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); - - To set the filters to zero filters is quite obsolete as to not read - data causes the raw socket to discard the received CAN frames. But - having this 'send only' use-case we may remove the receive list in the - Kernel to save a little (really a very little!) CPU usage. - - 4.1.1.1 CAN filter usage optimisation - - The CAN filters are processed in per-device filter lists at CAN frame - reception time. To reduce the number of checks that need to be performed - while walking through the filter lists the CAN core provides an optimized - filter handling when the filter subscription focusses on a single CAN ID. - - For the possible 2048 SFF CAN identifiers the identifier is used as an index - to access the corresponding subscription list without any further checks. - For the 2^29 possible EFF CAN identifiers a 10 bit XOR folding is used as - hash function to retrieve the EFF table index. - - To benefit from the optimized filters for single CAN identifiers the - CAN_SFF_MASK or CAN_EFF_MASK have to be set into can_filter.mask together - with set CAN_EFF_FLAG and CAN_RTR_FLAG bits. A set CAN_EFF_FLAG bit in the - can_filter.mask makes clear that it matters whether a SFF or EFF CAN ID is - subscribed. E.g. in the example from above - - rfilter[0].can_id = 0x123; - rfilter[0].can_mask = CAN_SFF_MASK; - - both SFF frames with CAN ID 0x123 and EFF frames with 0xXXXXX123 can pass. - - To filter for only 0x123 (SFF) and 0x12345678 (EFF) CAN identifiers the - filter has to be defined in this way to benefit from the optimized filters: - - struct can_filter rfilter[2]; - - rfilter[0].can_id = 0x123; - rfilter[0].can_mask = (CAN_EFF_FLAG | CAN_RTR_FLAG | CAN_SFF_MASK); - rfilter[1].can_id = 0x12345678 | CAN_EFF_FLAG; - rfilter[1].can_mask = (CAN_EFF_FLAG | CAN_RTR_FLAG | CAN_EFF_MASK); - - setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter)); - - 4.1.2 RAW socket option CAN_RAW_ERR_FILTER - - As described in chapter 3.3 the CAN interface driver can generate so - called Error Message Frames that can optionally be passed to the user - application in the same way as other CAN frames. The possible - errors are divided into different error classes that may be filtered - using the appropriate error mask. To register for every possible - error condition CAN_ERR_MASK can be used as value for the error mask. - The values for the error mask are defined in linux/can/error.h . - - can_err_mask_t err_mask = ( CAN_ERR_TX_TIMEOUT | CAN_ERR_BUSOFF ); - - setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, - &err_mask, sizeof(err_mask)); - - 4.1.3 RAW socket option CAN_RAW_LOOPBACK - - To meet multi user needs the local loopback is enabled by default - (see chapter 3.2 for details). But in some embedded use-cases - (e.g. when only one application uses the CAN bus) this loopback - functionality can be disabled (separately for each socket): - - int loopback = 0; /* 0 = disabled, 1 = enabled (default) */ - - setsockopt(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback)); - - 4.1.4 RAW socket option CAN_RAW_RECV_OWN_MSGS - - When the local loopback is enabled, all the sent CAN frames are - looped back to the open CAN sockets that registered for the CAN - frames' CAN-ID on this given interface to meet the multi user - needs. The reception of the CAN frames on the same socket that was - sending the CAN frame is assumed to be unwanted and therefore - disabled by default. This default behaviour may be changed on - demand: - - int recv_own_msgs = 1; /* 0 = disabled (default), 1 = enabled */ - - setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, - &recv_own_msgs, sizeof(recv_own_msgs)); - - 4.1.5 RAW socket option CAN_RAW_FD_FRAMES - - CAN FD support in CAN_RAW sockets can be enabled with a new socket option - CAN_RAW_FD_FRAMES which is off by default. When the new socket option is - not supported by the CAN_RAW socket (e.g. on older kernels), switching the - CAN_RAW_FD_FRAMES option returns the error -ENOPROTOOPT. - - Once CAN_RAW_FD_FRAMES is enabled the application can send both CAN frames - and CAN FD frames. OTOH the application has to handle CAN and CAN FD frames - when reading from the socket. - - CAN_RAW_FD_FRAMES enabled: CAN_MTU and CANFD_MTU are allowed - CAN_RAW_FD_FRAMES disabled: only CAN_MTU is allowed (default) - - Example: - [ remember: CANFD_MTU == sizeof(struct canfd_frame) ] - - struct canfd_frame cfd; - - nbytes = read(s, &cfd, CANFD_MTU); - - if (nbytes == CANFD_MTU) { - printf("got CAN FD frame with length %d\n", cfd.len); - /* cfd.flags contains valid data */ - } else if (nbytes == CAN_MTU) { - printf("got legacy CAN frame with length %d\n", cfd.len); - /* cfd.flags is undefined */ - } else { - fprintf(stderr, "read: invalid CAN(FD) frame\n"); - return 1; - } - - /* the content can be handled independently from the received MTU size */ - - printf("can_id: %X data length: %d data: ", cfd.can_id, cfd.len); - for (i = 0; i < cfd.len; i++) - printf("%02X ", cfd.data[i]); - - When reading with size CANFD_MTU only returns CAN_MTU bytes that have - been received from the socket a legacy CAN frame has been read into the - provided CAN FD structure. Note that the canfd_frame.flags data field is - not specified in the struct can_frame and therefore it is only valid in - CANFD_MTU sized CAN FD frames. - - Implementation hint for new CAN applications: - - To build a CAN FD aware application use struct canfd_frame as basic CAN - data structure for CAN_RAW based applications. When the application is - executed on an older Linux kernel and switching the CAN_RAW_FD_FRAMES - socket option returns an error: No problem. You'll get legacy CAN frames - or CAN FD frames and can process them the same way. - - When sending to CAN devices make sure that the device is capable to handle - CAN FD frames by checking if the device maximum transfer unit is CANFD_MTU. - The CAN device MTU can be retrieved e.g. with a SIOCGIFMTU ioctl() syscall. - - 4.1.6 RAW socket option CAN_RAW_JOIN_FILTERS - - The CAN_RAW socket can set multiple CAN identifier specific filters that - lead to multiple filters in the af_can.c filter processing. These filters - are indenpendent from each other which leads to logical OR'ed filters when - applied (see 4.1.1). - - This socket option joines the given CAN filters in the way that only CAN - frames are passed to user space that matched *all* given CAN filters. The - semantic for the applied filters is therefore changed to a logical AND. - - This is useful especially when the filterset is a combination of filters - where the CAN_INV_FILTER flag is set in order to notch single CAN IDs or - CAN ID ranges from the incoming traffic. - - 4.1.7 RAW socket returned message flags - - When using recvmsg() call, the msg->msg_flags may contain following flags: - - MSG_DONTROUTE: set when the received frame was created on the local host. - - MSG_CONFIRM: set when the frame was sent via the socket it is received on. - This flag can be interpreted as a 'transmission confirmation' when the - CAN driver supports the echo of frames on driver level, see 3.2 and 6.2. - In order to receive such messages, CAN_RAW_RECV_OWN_MSGS must be set. - - 4.2 Broadcast Manager protocol sockets (SOCK_DGRAM) - - The Broadcast Manager protocol provides a command based configuration - interface to filter and send (e.g. cyclic) CAN messages in kernel space. - - Receive filters can be used to down sample frequent messages; detect events - such as message contents changes, packet length changes, and do time-out - monitoring of received messages. - - Periodic transmission tasks of CAN frames or a sequence of CAN frames can be - created and modified at runtime; both the message content and the two - possible transmit intervals can be altered. - - A BCM socket is not intended for sending individual CAN frames using the - struct can_frame as known from the CAN_RAW socket. Instead a special BCM - configuration message is defined. The basic BCM configuration message used - to communicate with the broadcast manager and the available operations are - defined in the linux/can/bcm.h include. The BCM message consists of a - message header with a command ('opcode') followed by zero or more CAN frames. - The broadcast manager sends responses to user space in the same form: - - struct bcm_msg_head { - __u32 opcode; /* command */ - __u32 flags; /* special flags */ - __u32 count; /* run 'count' times with ival1 */ - struct timeval ival1, ival2; /* count and subsequent interval */ - canid_t can_id; /* unique can_id for task */ - __u32 nframes; /* number of can_frames following */ - struct can_frame frames[0]; - }; - - The aligned payload 'frames' uses the same basic CAN frame structure defined - at the beginning of section 4 and in the include/linux/can.h include. All - messages to the broadcast manager from user space have this structure. - - Note a CAN_BCM socket must be connected instead of bound after socket - creation (example without error checking): - - int s; - struct sockaddr_can addr; - struct ifreq ifr; - - s = socket(PF_CAN, SOCK_DGRAM, CAN_BCM); - - strcpy(ifr.ifr_name, "can0"); - ioctl(s, SIOCGIFINDEX, &ifr); - - addr.can_family = AF_CAN; - addr.can_ifindex = ifr.ifr_ifindex; - - connect(s, (struct sockaddr *)&addr, sizeof(addr)); - - (..) - - The broadcast manager socket is able to handle any number of in flight - transmissions or receive filters concurrently. The different RX/TX jobs are - distinguished by the unique can_id in each BCM message. However additional - CAN_BCM sockets are recommended to communicate on multiple CAN interfaces. - When the broadcast manager socket is bound to 'any' CAN interface (=> the - interface index is set to zero) the configured receive filters apply to any - CAN interface unless the sendto() syscall is used to overrule the 'any' CAN - interface index. When using recvfrom() instead of read() to retrieve BCM - socket messages the originating CAN interface is provided in can_ifindex. - - 4.2.1 Broadcast Manager operations - - The opcode defines the operation for the broadcast manager to carry out, - or details the broadcast managers response to several events, including - user requests. - - Transmit Operations (user space to broadcast manager): - - TX_SETUP: Create (cyclic) transmission task. - - TX_DELETE: Remove (cyclic) transmission task, requires only can_id. - - TX_READ: Read properties of (cyclic) transmission task for can_id. - - TX_SEND: Send one CAN frame. - - Transmit Responses (broadcast manager to user space): - - TX_STATUS: Reply to TX_READ request (transmission task configuration). - - TX_EXPIRED: Notification when counter finishes sending at initial interval - 'ival1'. Requires the TX_COUNTEVT flag to be set at TX_SETUP. - - Receive Operations (user space to broadcast manager): - - RX_SETUP: Create RX content filter subscription. - - RX_DELETE: Remove RX content filter subscription, requires only can_id. - - RX_READ: Read properties of RX content filter subscription for can_id. - - Receive Responses (broadcast manager to user space): - - RX_STATUS: Reply to RX_READ request (filter task configuration). - - RX_TIMEOUT: Cyclic message is detected to be absent (timer ival1 expired). - - RX_CHANGED: BCM message with updated CAN frame (detected content change). - Sent on first message received or on receipt of revised CAN messages. - - 4.2.2 Broadcast Manager message flags - - When sending a message to the broadcast manager the 'flags' element may - contain the following flag definitions which influence the behaviour: - - SETTIMER: Set the values of ival1, ival2 and count - - STARTTIMER: Start the timer with the actual values of ival1, ival2 - and count. Starting the timer leads simultaneously to emit a CAN frame. - - TX_COUNTEVT: Create the message TX_EXPIRED when count expires - - TX_ANNOUNCE: A change of data by the process is emitted immediately. - - TX_CP_CAN_ID: Copies the can_id from the message header to each - subsequent frame in frames. This is intended as usage simplification. For - TX tasks the unique can_id from the message header may differ from the - can_id(s) stored for transmission in the subsequent struct can_frame(s). - - RX_FILTER_ID: Filter by can_id alone, no frames required (nframes=0). - - RX_CHECK_DLC: A change of the DLC leads to an RX_CHANGED. - - RX_NO_AUTOTIMER: Prevent automatically starting the timeout monitor. - - RX_ANNOUNCE_RESUME: If passed at RX_SETUP and a receive timeout occurred, a - RX_CHANGED message will be generated when the (cyclic) receive restarts. - - TX_RESET_MULTI_IDX: Reset the index for the multiple frame transmission. - - RX_RTR_FRAME: Send reply for RTR-request (placed in op->frames[0]). - - 4.2.3 Broadcast Manager transmission timers - - Periodic transmission configurations may use up to two interval timers. - In this case the BCM sends a number of messages ('count') at an interval - 'ival1', then continuing to send at another given interval 'ival2'. When - only one timer is needed 'count' is set to zero and only 'ival2' is used. - When SET_TIMER and START_TIMER flag were set the timers are activated. - The timer values can be altered at runtime when only SET_TIMER is set. - - 4.2.4 Broadcast Manager message sequence transmission - - Up to 256 CAN frames can be transmitted in a sequence in the case of a cyclic - TX task configuration. The number of CAN frames is provided in the 'nframes' - element of the BCM message head. The defined number of CAN frames are added - as array to the TX_SETUP BCM configuration message. - - /* create a struct to set up a sequence of four CAN frames */ - struct { - struct bcm_msg_head msg_head; - struct can_frame frame[4]; - } mytxmsg; - - (..) - mytxmsg.msg_head.nframes = 4; - (..) - - write(s, &mytxmsg, sizeof(mytxmsg)); - - With every transmission the index in the array of CAN frames is increased - and set to zero at index overflow. - - 4.2.5 Broadcast Manager receive filter timers - - The timer values ival1 or ival2 may be set to non-zero values at RX_SETUP. - When the SET_TIMER flag is set the timers are enabled: - - ival1: Send RX_TIMEOUT when a received message is not received again within - the given time. When START_TIMER is set at RX_SETUP the timeout detection - is activated directly - even without a former CAN frame reception. - - ival2: Throttle the received message rate down to the value of ival2. This - is useful to reduce messages for the application when the signal inside the - CAN frame is stateless as state changes within the ival2 periode may get - lost. - - 4.2.6 Broadcast Manager multiplex message receive filter - - To filter for content changes in multiplex message sequences an array of more - than one CAN frames can be passed in a RX_SETUP configuration message. The - data bytes of the first CAN frame contain the mask of relevant bits that - have to match in the subsequent CAN frames with the received CAN frame. - If one of the subsequent CAN frames is matching the bits in that frame data - mark the relevant content to be compared with the previous received content. - Up to 257 CAN frames (multiplex filter bit mask CAN frame plus 256 CAN - filters) can be added as array to the TX_SETUP BCM configuration message. - - /* usually used to clear CAN frame data[] - beware of endian problems! */ - #define U64_DATA(p) (*(unsigned long long*)(p)->data) - - struct { - struct bcm_msg_head msg_head; - struct can_frame frame[5]; - } msg; - - msg.msg_head.opcode = RX_SETUP; - msg.msg_head.can_id = 0x42; - msg.msg_head.flags = 0; - msg.msg_head.nframes = 5; - U64_DATA(&msg.frame[0]) = 0xFF00000000000000ULL; /* MUX mask */ - U64_DATA(&msg.frame[1]) = 0x01000000000000FFULL; /* data mask (MUX 0x01) */ - U64_DATA(&msg.frame[2]) = 0x0200FFFF000000FFULL; /* data mask (MUX 0x02) */ - U64_DATA(&msg.frame[3]) = 0x330000FFFFFF0003ULL; /* data mask (MUX 0x33) */ - U64_DATA(&msg.frame[4]) = 0x4F07FC0FF0000000ULL; /* data mask (MUX 0x4F) */ - - write(s, &msg, sizeof(msg)); - - 4.2.7 Broadcast Manager CAN FD support - - The programming API of the CAN_BCM depends on struct can_frame which is - given as array directly behind the bcm_msg_head structure. To follow this - schema for the CAN FD frames a new flag 'CAN_FD_FRAME' in the bcm_msg_head - flags indicates that the concatenated CAN frame structures behind the - bcm_msg_head are defined as struct canfd_frame. - - struct { - struct bcm_msg_head msg_head; - struct canfd_frame frame[5]; - } msg; - - msg.msg_head.opcode = RX_SETUP; - msg.msg_head.can_id = 0x42; - msg.msg_head.flags = CAN_FD_FRAME; - msg.msg_head.nframes = 5; - (..) - - When using CAN FD frames for multiplex filtering the MUX mask is still - expected in the first 64 bit of the struct canfd_frame data section. - - 4.3 connected transport protocols (SOCK_SEQPACKET) - 4.4 unconnected transport protocols (SOCK_DGRAM) - - -5. SocketCAN core module -------------------------- - - The SocketCAN core module implements the protocol family - PF_CAN. CAN protocol modules are loaded by the core module at - runtime. The core module provides an interface for CAN protocol - modules to subscribe needed CAN IDs (see chapter 3.1). - - 5.1 can.ko module params - - - stats_timer: To calculate the SocketCAN core statistics - (e.g. current/maximum frames per second) this 1 second timer is - invoked at can.ko module start time by default. This timer can be - disabled by using stattimer=0 on the module commandline. - - - debug: (removed since SocketCAN SVN r546) - - 5.2 procfs content - - As described in chapter 3.1 the SocketCAN core uses several filter - lists to deliver received CAN frames to CAN protocol modules. These - receive lists, their filters and the count of filter matches can be - checked in the appropriate receive list. All entries contain the - device and a protocol module identifier: - - foo@bar:~$ cat /proc/net/can/rcvlist_all - - receive list 'rx_all': - (vcan3: no entry) - (vcan2: no entry) - (vcan1: no entry) - device can_id can_mask function userdata matches ident - vcan0 000 00000000 f88e6370 f6c6f400 0 raw - (any: no entry) - - In this example an application requests any CAN traffic from vcan0. - - rcvlist_all - list for unfiltered entries (no filter operations) - rcvlist_eff - list for single extended frame (EFF) entries - rcvlist_err - list for error message frames masks - rcvlist_fil - list for mask/value filters - rcvlist_inv - list for mask/value filters (inverse semantic) - rcvlist_sff - list for single standard frame (SFF) entries - - Additional procfs files in /proc/net/can - - stats - SocketCAN core statistics (rx/tx frames, match ratios, ...) - reset_stats - manual statistic reset - version - prints the SocketCAN core version and the ABI version - - 5.3 writing own CAN protocol modules - - To implement a new protocol in the protocol family PF_CAN a new - protocol has to be defined in include/linux/can.h . - The prototypes and definitions to use the SocketCAN core can be - accessed by including include/linux/can/core.h . - In addition to functions that register the CAN protocol and the - CAN device notifier chain there are functions to subscribe CAN - frames received by CAN interfaces and to send CAN frames: - - can_rx_register - subscribe CAN frames from a specific interface - can_rx_unregister - unsubscribe CAN frames from a specific interface - can_send - transmit a CAN frame (optional with local loopback) - - For details see the kerneldoc documentation in net/can/af_can.c or - the source code of net/can/raw.c or net/can/bcm.c . - -6. CAN network drivers ----------------------- - - Writing a CAN network device driver is much easier than writing a - CAN character device driver. Similar to other known network device - drivers you mainly have to deal with: - - - TX: Put the CAN frame from the socket buffer to the CAN controller. - - RX: Put the CAN frame from the CAN controller to the socket buffer. - - See e.g. at Documentation/networking/netdevices.txt . The differences - for writing CAN network device driver are described below: - - 6.1 general settings - - dev->type = ARPHRD_CAN; /* the netdevice hardware type */ - dev->flags = IFF_NOARP; /* CAN has no arp */ - - dev->mtu = CAN_MTU; /* sizeof(struct can_frame) -> legacy CAN interface */ - - or alternative, when the controller supports CAN with flexible data rate: - dev->mtu = CANFD_MTU; /* sizeof(struct canfd_frame) -> CAN FD interface */ - - The struct can_frame or struct canfd_frame is the payload of each socket - buffer (skbuff) in the protocol family PF_CAN. - - 6.2 local loopback of sent frames - - As described in chapter 3.2 the CAN network device driver should - support a local loopback functionality similar to the local echo - e.g. of tty devices. In this case the driver flag IFF_ECHO has to be - set to prevent the PF_CAN core from locally echoing sent frames - (aka loopback) as fallback solution: - - dev->flags = (IFF_NOARP | IFF_ECHO); - - 6.3 CAN controller hardware filters - - To reduce the interrupt load on deep embedded systems some CAN - controllers support the filtering of CAN IDs or ranges of CAN IDs. - These hardware filter capabilities vary from controller to - controller and have to be identified as not feasible in a multi-user - networking approach. The use of the very controller specific - hardware filters could make sense in a very dedicated use-case, as a - filter on driver level would affect all users in the multi-user - system. The high efficient filter sets inside the PF_CAN core allow - to set different multiple filters for each socket separately. - Therefore the use of hardware filters goes to the category 'handmade - tuning on deep embedded systems'. The author is running a MPC603e - @133MHz with four SJA1000 CAN controllers from 2002 under heavy bus - load without any problems ... - - 6.4 The virtual CAN driver (vcan) - - Similar to the network loopback devices, vcan offers a virtual local - CAN interface. A full qualified address on CAN consists of - - - a unique CAN Identifier (CAN ID) - - the CAN bus this CAN ID is transmitted on (e.g. can0) - - so in common use cases more than one virtual CAN interface is needed. - - The virtual CAN interfaces allow the transmission and reception of CAN - frames without real CAN controller hardware. Virtual CAN network - devices are usually named 'vcanX', like vcan0 vcan1 vcan2 ... - When compiled as a module the virtual CAN driver module is called vcan.ko - - Since Linux Kernel version 2.6.24 the vcan driver supports the Kernel - netlink interface to create vcan network devices. The creation and - removal of vcan network devices can be managed with the ip(8) tool: - - - Create a virtual CAN network interface: - $ ip link add type vcan - - - Create a virtual CAN network interface with a specific name 'vcan42': - $ ip link add dev vcan42 type vcan - - - Remove a (virtual CAN) network interface 'vcan42': - $ ip link del vcan42 - - 6.5 The CAN network device driver interface - - The CAN network device driver interface provides a generic interface - to setup, configure and monitor CAN network devices. The user can then - configure the CAN device, like setting the bit-timing parameters, via - the netlink interface using the program "ip" from the "IPROUTE2" - utility suite. The following chapter describes briefly how to use it. - Furthermore, the interface uses a common data structure and exports a - set of common functions, which all real CAN network device drivers - should use. Please have a look to the SJA1000 or MSCAN driver to - understand how to use them. The name of the module is can-dev.ko. - - 6.5.1 Netlink interface to set/get devices properties - - The CAN device must be configured via netlink interface. The supported - netlink message types are defined and briefly described in - "include/linux/can/netlink.h". CAN link support for the program "ip" - of the IPROUTE2 utility suite is available and it can be used as shown - below: - - - Setting CAN device properties: - - $ ip link set can0 type can help - Usage: ip link set DEVICE type can - [ bitrate BITRATE [ sample-point SAMPLE-POINT] ] | - [ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1 - phase-seg2 PHASE-SEG2 [ sjw SJW ] ] - - [ dbitrate BITRATE [ dsample-point SAMPLE-POINT] ] | - [ dtq TQ dprop-seg PROP_SEG dphase-seg1 PHASE-SEG1 - dphase-seg2 PHASE-SEG2 [ dsjw SJW ] ] - - [ loopback { on | off } ] - [ listen-only { on | off } ] - [ triple-sampling { on | off } ] - [ one-shot { on | off } ] - [ berr-reporting { on | off } ] - [ fd { on | off } ] - [ fd-non-iso { on | off } ] - [ presume-ack { on | off } ] - - [ restart-ms TIME-MS ] - [ restart ] - - Where: BITRATE := { 1..1000000 } - SAMPLE-POINT := { 0.000..0.999 } - TQ := { NUMBER } - PROP-SEG := { 1..8 } - PHASE-SEG1 := { 1..8 } - PHASE-SEG2 := { 1..8 } - SJW := { 1..4 } - RESTART-MS := { 0 | NUMBER } - - - Display CAN device details and statistics: - - $ ip -details -statistics link show can0 - 2: can0: mtu 16 qdisc pfifo_fast state UP qlen 10 - link/can - can state ERROR-ACTIVE restart-ms 100 - bitrate 125000 sample_point 0.875 - tq 125 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1 - sja1000: tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..64 brp-inc 1 - clock 8000000 - re-started bus-errors arbit-lost error-warn error-pass bus-off - 41 17457 0 41 42 41 - RX: bytes packets errors dropped overrun mcast - 140859 17608 17457 0 0 0 - TX: bytes packets errors dropped carrier collsns - 861 112 0 41 0 0 - - More info to the above output: - - "" - Shows the list of selected CAN controller modes: LOOPBACK, - LISTEN-ONLY, or TRIPLE-SAMPLING. - - "state ERROR-ACTIVE" - The current state of the CAN controller: "ERROR-ACTIVE", - "ERROR-WARNING", "ERROR-PASSIVE", "BUS-OFF" or "STOPPED" - - "restart-ms 100" - Automatic restart delay time. If set to a non-zero value, a - restart of the CAN controller will be triggered automatically - in case of a bus-off condition after the specified delay time - in milliseconds. By default it's off. - - "bitrate 125000 sample-point 0.875" - Shows the real bit-rate in bits/sec and the sample-point in the - range 0.000..0.999. If the calculation of bit-timing parameters - is enabled in the kernel (CONFIG_CAN_CALC_BITTIMING=y), the - bit-timing can be defined by setting the "bitrate" argument. - Optionally the "sample-point" can be specified. By default it's - 0.000 assuming CIA-recommended sample-points. - - "tq 125 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1" - Shows the time quanta in ns, propagation segment, phase buffer - segment 1 and 2 and the synchronisation jump width in units of - tq. They allow to define the CAN bit-timing in a hardware - independent format as proposed by the Bosch CAN 2.0 spec (see - chapter 8 of http://www.semiconductors.bosch.de/pdf/can2spec.pdf). - - "sja1000: tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..64 brp-inc 1 - clock 8000000" - Shows the bit-timing constants of the CAN controller, here the - "sja1000". The minimum and maximum values of the time segment 1 - and 2, the synchronisation jump width in units of tq, the - bitrate pre-scaler and the CAN system clock frequency in Hz. - These constants could be used for user-defined (non-standard) - bit-timing calculation algorithms in user-space. - - "re-started bus-errors arbit-lost error-warn error-pass bus-off" - Shows the number of restarts, bus and arbitration lost errors, - and the state changes to the error-warning, error-passive and - bus-off state. RX overrun errors are listed in the "overrun" - field of the standard network statistics. - - 6.5.2 Setting the CAN bit-timing - - The CAN bit-timing parameters can always be defined in a hardware - independent format as proposed in the Bosch CAN 2.0 specification - specifying the arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" - and "sjw": - - $ ip link set canX type can tq 125 prop-seg 6 \ - phase-seg1 7 phase-seg2 2 sjw 1 - - If the kernel option CONFIG_CAN_CALC_BITTIMING is enabled, CIA - recommended CAN bit-timing parameters will be calculated if the bit- - rate is specified with the argument "bitrate": - - $ ip link set canX type can bitrate 125000 - - Note that this works fine for the most common CAN controllers with - standard bit-rates but may *fail* for exotic bit-rates or CAN system - clock frequencies. Disabling CONFIG_CAN_CALC_BITTIMING saves some - space and allows user-space tools to solely determine and set the - bit-timing parameters. The CAN controller specific bit-timing - constants can be used for that purpose. They are listed by the - following command: - - $ ip -details link show can0 - ... - sja1000: clock 8000000 tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..64 brp-inc 1 - - 6.5.3 Starting and stopping the CAN network device - - A CAN network device is started or stopped as usual with the command - "ifconfig canX up/down" or "ip link set canX up/down". Be aware that - you *must* define proper bit-timing parameters for real CAN devices - before you can start it to avoid error-prone default settings: - - $ ip link set canX up type can bitrate 125000 - - A device may enter the "bus-off" state if too many errors occurred on - the CAN bus. Then no more messages are received or sent. An automatic - bus-off recovery can be enabled by setting the "restart-ms" to a - non-zero value, e.g.: - - $ ip link set canX type can restart-ms 100 - - Alternatively, the application may realize the "bus-off" condition - by monitoring CAN error message frames and do a restart when - appropriate with the command: - - $ ip link set canX type can restart - - Note that a restart will also create a CAN error message frame (see - also chapter 3.3). - - 6.6 CAN FD (flexible data rate) driver support - - CAN FD capable CAN controllers support two different bitrates for the - arbitration phase and the payload phase of the CAN FD frame. Therefore a - second bit timing has to be specified in order to enable the CAN FD bitrate. - - Additionally CAN FD capable CAN controllers support up to 64 bytes of - payload. The representation of this length in can_frame.can_dlc and - canfd_frame.len for userspace applications and inside the Linux network - layer is a plain value from 0 .. 64 instead of the CAN 'data length code'. - The data length code was a 1:1 mapping to the payload length in the legacy - CAN frames anyway. The payload length to the bus-relevant DLC mapping is - only performed inside the CAN drivers, preferably with the helper - functions can_dlc2len() and can_len2dlc(). - - The CAN netdevice driver capabilities can be distinguished by the network - devices maximum transfer unit (MTU): - - MTU = 16 (CAN_MTU) => sizeof(struct can_frame) => 'legacy' CAN device - MTU = 72 (CANFD_MTU) => sizeof(struct canfd_frame) => CAN FD capable device - - The CAN device MTU can be retrieved e.g. with a SIOCGIFMTU ioctl() syscall. - N.B. CAN FD capable devices can also handle and send legacy CAN frames. - - When configuring CAN FD capable CAN controllers an additional 'data' bitrate - has to be set. This bitrate for the data phase of the CAN FD frame has to be - at least the bitrate which was configured for the arbitration phase. This - second bitrate is specified analogue to the first bitrate but the bitrate - setting keywords for the 'data' bitrate start with 'd' e.g. dbitrate, - dsample-point, dsjw or dtq and similar settings. When a data bitrate is set - within the configuration process the controller option "fd on" can be - specified to enable the CAN FD mode in the CAN controller. This controller - option also switches the device MTU to 72 (CANFD_MTU). - - The first CAN FD specification presented as whitepaper at the International - CAN Conference 2012 needed to be improved for data integrity reasons. - Therefore two CAN FD implementations have to be distinguished today: - - - ISO compliant: The ISO 11898-1:2015 CAN FD implementation (default) - - non-ISO compliant: The CAN FD implementation following the 2012 whitepaper - - Finally there are three types of CAN FD controllers: - - 1. ISO compliant (fixed) - 2. non-ISO compliant (fixed, like the M_CAN IP core v3.0.1 in m_can.c) - 3. ISO/non-ISO CAN FD controllers (switchable, like the PEAK PCAN-USB FD) - - The current ISO/non-ISO mode is announced by the CAN controller driver via - netlink and displayed by the 'ip' tool (controller option FD-NON-ISO). - The ISO/non-ISO-mode can be altered by setting 'fd-non-iso {on|off}' for - switchable CAN FD controllers only. - - Example configuring 500 kbit/s arbitration bitrate and 4 Mbit/s data bitrate: - - $ ip link set can0 up type can bitrate 500000 sample-point 0.75 \ - dbitrate 4000000 dsample-point 0.8 fd on - $ ip -details link show can0 - 5: can0: mtu 72 qdisc pfifo_fast state UNKNOWN \ - mode DEFAULT group default qlen 10 - link/can promiscuity 0 - can state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 0 - bitrate 500000 sample-point 0.750 - tq 50 prop-seg 14 phase-seg1 15 phase-seg2 10 sjw 1 - pcan_usb_pro_fd: tseg1 1..64 tseg2 1..16 sjw 1..16 brp 1..1024 \ - brp-inc 1 - dbitrate 4000000 dsample-point 0.800 - dtq 12 dprop-seg 7 dphase-seg1 8 dphase-seg2 4 dsjw 1 - pcan_usb_pro_fd: dtseg1 1..16 dtseg2 1..8 dsjw 1..4 dbrp 1..1024 \ - dbrp-inc 1 - clock 80000000 - - Example when 'fd-non-iso on' is added on this switchable CAN FD adapter: - can state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 0 - - 6.7 Supported CAN hardware - - Please check the "Kconfig" file in "drivers/net/can" to get an actual - list of the support CAN hardware. On the SocketCAN project website - (see chapter 7) there might be further drivers available, also for - older kernel versions. - -7. SocketCAN resources ------------------------ - - The Linux CAN / SocketCAN project resources (project site / mailing list) - are referenced in the MAINTAINERS file in the Linux source tree. - Search for CAN NETWORK [LAYERS|DRIVERS]. - -8. Credits ----------- - - Oliver Hartkopp (PF_CAN core, filters, drivers, bcm, SJA1000 driver) - Urs Thuermann (PF_CAN core, kernel integration, socket interfaces, raw, vcan) - Jan Kizka (RT-SocketCAN core, Socket-API reconciliation) - Wolfgang Grandegger (RT-SocketCAN core & drivers, Raw Socket-API reviews, - CAN device driver interface, MSCAN driver) - Robert Schwebel (design reviews, PTXdist integration) - Marc Kleine-Budde (design reviews, Kernel 2.6 cleanups, drivers) - Benedikt Spranger (reviews) - Thomas Gleixner (LKML reviews, coding style, posting hints) - Andrey Volkov (kernel subtree structure, ioctls, MSCAN driver) - Matthias Brukner (first SJA1000 CAN netdevice implementation Q2/2003) - Klaus Hitschler (PEAK driver integration) - Uwe Koppe (CAN netdevices with PF_PACKET approach) - Michael Schulze (driver layer loopback requirement, RT CAN drivers review) - Pavel Pisa (Bit-timing calculation) - Sascha Hauer (SJA1000 platform driver) - Sebastian Haas (SJA1000 EMS PCI driver) - Markus Plessing (SJA1000 EMS PCI driver) - Per Dalen (SJA1000 Kvaser PCI driver) - Sam Ravnborg (reviews, coding style, kbuild help) diff --git a/Documentation/networking/dsa/dsa.txt b/Documentation/networking/dsa/dsa.txt index b8b40753133e..25170ad7d25b 100644 --- a/Documentation/networking/dsa/dsa.txt +++ b/Documentation/networking/dsa/dsa.txt @@ -385,11 +385,6 @@ Switch configuration avoid relying on what a previous software agent such as a bootloader/firmware may have previously configured. -- set_addr: Some switches require the programming of the management interface's - Ethernet MAC address, switch drivers can also disable ageing of MAC addresses - on the management interface and "hardcode"/"force" this MAC address for the - CPU/management interface as an optimization - PHY devices and link management ------------------------------- diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt index 87814859cfc2..a4508ec1816b 100644 --- a/Documentation/networking/filter.txt +++ b/Documentation/networking/filter.txt @@ -1134,7 +1134,7 @@ The verifier's knowledge about the variable offset consists of: mask and value; no bit should ever be 1 in both. For example, if a byte is read into a register from memory, the register's top 56 bits are known zero, while the low 8 are unknown - which is represented as the tnum (0x0; 0xff). If we -then OR this with 0x40, we get (0x40; 0xcf), then if we add 1 we get (0x0; +then OR this with 0x40, we get (0x40; 0xbf), then if we add 1 we get (0x0; 0x1ff), because of potential carries. Besides arithmetic, the register state can also be updated by conditional branches. For instance, if a SCALAR_VALUE is compared > 8, in the 'true' branch diff --git a/Documentation/networking/ieee802154.txt b/Documentation/networking/ieee802154.txt index 057e9fdbfac9..e74d8e1da0e2 100644 --- a/Documentation/networking/ieee802154.txt +++ b/Documentation/networking/ieee802154.txt @@ -97,6 +97,46 @@ The include/net/mac802154.h defines following functions: - void ieee802154_unregister_hw(struct ieee802154_hw *hw): freeing registered PHY + - void ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, + u8 lqi): + telling 802.15.4 module there is a new received frame in the skb with + the RF Link Quality Indicator (LQI) from the hardware device + + - void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb, + bool ifs_handling): + telling 802.15.4 module the frame in the skb is or going to be + transmitted through the hardware device + +The device driver must implement the following callbacks in the IEEE 802.15.4 +operations structure at least: +struct ieee802154_ops { + ... + int (*start)(struct ieee802154_hw *hw); + void (*stop)(struct ieee802154_hw *hw); + ... + int (*xmit_async)(struct ieee802154_hw *hw, struct sk_buff *skb); + int (*ed)(struct ieee802154_hw *hw, u8 *level); + int (*set_channel)(struct ieee802154_hw *hw, u8 page, u8 channel); + ... +}; + + - int start(struct ieee802154_hw *hw): + handler that 802.15.4 module calls for the hardware device initialization. + + - void stop(struct ieee802154_hw *hw): + handler that 802.15.4 module calls for the hardware device cleanup. + + - int xmit_async(struct ieee802154_hw *hw, struct sk_buff *skb): + handler that 802.15.4 module calls for each frame in the skb going to be + transmitted through the hardware device. + + - int ed(struct ieee802154_hw *hw, u8 *level): + handler that 802.15.4 module calls for Energy Detection from the hardware + device. + + - int set_channel(struct ieee802154_hw *hw, u8 page, u8 channel): + set radio for listening on specific channel of the hardware device. + Moreover IEEE 802.15.4 device operations structure should be filled. Fake drivers diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst index 7d4b15977d61..90966c2692d8 100644 --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@ -7,6 +7,7 @@ Contents: :maxdepth: 2 batman-adv + can kapi z8530book msg_zerocopy diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 46c7e1085efc..a553d4e4a0fb 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -508,7 +508,7 @@ tcp_rmem - vector of 3 INTEGERs: min, default, max min: Minimal size of receive buffer used by TCP sockets. It is guaranteed to each TCP socket, even under moderate memory pressure. - Default: 1 page + Default: 4K default: initial size of receive buffer used by TCP sockets. This value overrides net.core.rmem_default used by other protocols. @@ -606,6 +606,7 @@ tcp_fastopen_blackhole_timeout_sec - INTEGER This time period will grow exponentially when more blackhole issues get detected right after Fastopen is re-enabled and will reset to initial value when the blackhole issue goes away. + 0 to disable the blackhole detection. By default, it is set to 1hr. tcp_syn_retries - INTEGER @@ -666,7 +667,7 @@ tcp_window_scaling - BOOLEAN tcp_wmem - vector of 3 INTEGERs: min, default, max min: Amount of memory reserved for send buffers for TCP sockets. Each TCP socket has rights to use it due to fact of its birth. - Default: 1 page + Default: 4K default: initial size of send buffer used by TCP sockets. This value overrides net.core.wmem_default used by other protocols. diff --git a/Documentation/networking/kapi.rst b/Documentation/networking/kapi.rst index 580289f345da..f03ae64be8bc 100644 --- a/Documentation/networking/kapi.rst +++ b/Documentation/networking/kapi.rst @@ -145,3 +145,27 @@ PHY Support .. kernel-doc:: drivers/net/phy/mdio_bus.c :internal: + +PHYLINK +------- + + PHYLINK interfaces traditional network drivers with PHYLIB, fixed-links, + and SFF modules (eg, hot-pluggable SFP) that may contain PHYs. PHYLINK + provides management of the link state and link modes. + +.. kernel-doc:: include/linux/phylink.h + :internal: + +.. kernel-doc:: drivers/net/phy/phylink.c + +SFP support +----------- + +.. kernel-doc:: drivers/net/phy/sfp-bus.c + :internal: + +.. kernel-doc:: include/linux/sfp.h + :internal: + +.. kernel-doc:: drivers/net/phy/sfp-bus.c + :export: diff --git a/Documentation/networking/netdev-features.txt b/Documentation/networking/netdev-features.txt index 7413eb05223b..c77f9d57eb91 100644 --- a/Documentation/networking/netdev-features.txt +++ b/Documentation/networking/netdev-features.txt @@ -163,3 +163,12 @@ This requests that the NIC receive all possible frames, including errored frames (such as bad FCS, etc). This can be helpful when sniffing a link with bad packets on it. Some NICs may receive more packets if also put into normal PROMISC mode. + +* rx-gro-hw + +This requests that the NIC enables Hardware GRO (generic receive offload). +Hardware GRO is basically the exact reverse of TSO, and is generally +stricter than Hardware LRO. A packet stream merged by Hardware GRO must +be re-segmentable by GSO or TSO back to the exact original packet stream. +Hardware GRO is dependent on RXCSUM since every packet successfully merged +by hardware must also have the checksum verified by hardware. diff --git a/Documentation/networking/pktgen.txt b/Documentation/networking/pktgen.txt index 2c4e3354e128..d2fd78f85aa4 100644 --- a/Documentation/networking/pktgen.txt +++ b/Documentation/networking/pktgen.txt @@ -12,8 +12,8 @@ suitable sample script and configure that. On a dual CPU: ps aux | grep pkt -root 129 0.3 0.0 0 0 ? SW 2003 523:20 [pktgen/0] -root 130 0.3 0.0 0 0 ? SW 2003 509:50 [pktgen/1] +root 129 0.3 0.0 0 0 ? SW 2003 523:20 [kpktgend_0] +root 130 0.3 0.0 0 0 ? SW 2003 509:50 [kpktgend_1] For monitoring and control pktgen creates: @@ -113,9 +113,16 @@ Configuring devices =================== This is done via the /proc interface, and most easily done via pgset as defined in the sample scripts. +You need to specify PGDEV environment variable to use functions from sample +scripts, i.e.: +export PGDEV=/proc/net/pktgen/eth4@0 +source samples/pktgen/functions.sh Examples: + pg_ctrl start starts injection. + pg_ctrl stop aborts injection. Also, ^C aborts generator. + pgset "clone_skb 1" sets the number of copies of the same packet pgset "clone_skb 0" use single SKB for all transmits pgset "burst 8" uses xmit_more API to queue 8 copies of the same @@ -165,8 +172,12 @@ Examples: IPSEC # IPsec encapsulation (needs CONFIG_XFRM) NODE_ALLOC # node specific memory allocation NO_TIMESTAMP # disable timestamping + pgset 'flag ![name]' Clear a flag to determine behaviour. + Note that you might need to use single quote in + interactive mode, so that your shell wouldn't expand + the specified flag as a history command. - pgset spi SPI_VALUE Set specific SA used to transform packet. + pgset "spi [SPI_VALUE]" Set specific SA used to transform packet. pgset "udp_src_min 9" set UDP source port min, If < udp_src_max, then cycle through the port range. @@ -207,8 +218,6 @@ Examples: pgset "tos XX" set former IPv4 TOS field (e.g. "tos 28" for AF11 no ECN, default 00) pgset "traffic_class XX" set former IPv6 TRAFFIC CLASS (e.g. "traffic_class B8" for EF no ECN, default 00) - pgset stop aborts injection. Also, ^C aborts generator. - pgset "rate 300M" set rate to 300 Mb/s pgset "ratep 1000000" set rate to 1Mpps diff --git a/Documentation/networking/xfrm_device.txt b/Documentation/networking/xfrm_device.txt new file mode 100644 index 000000000000..50c34ca65efe --- /dev/null +++ b/Documentation/networking/xfrm_device.txt @@ -0,0 +1,135 @@ + +=============================================== +XFRM device - offloading the IPsec computations +=============================================== +Shannon Nelson + + +Overview +======== + +IPsec is a useful feature for securing network traffic, but the +computational cost is high: a 10Gbps link can easily be brought down +to under 1Gbps, depending on the traffic and link configuration. +Luckily, there are NICs that offer a hardware based IPsec offload which +can radically increase throughput and decrease CPU utilization. The XFRM +Device interface allows NIC drivers to offer to the stack access to the +hardware offload. + +Userland access to the offload is typically through a system such as +libreswan or KAME/raccoon, but the iproute2 'ip xfrm' command set can +be handy when experimenting. An example command might look something +like this: + + ip x s add proto esp dst 14.0.0.70 src 14.0.0.52 spi 0x07 mode transport \ + reqid 0x07 replay-window 32 \ + aead 'rfc4106(gcm(aes))' 0x44434241343332312423222114131211f4f3f2f1 128 \ + sel src 14.0.0.52/24 dst 14.0.0.70/24 proto tcp \ + offload dev eth4 dir in + +Yes, that's ugly, but that's what shell scripts and/or libreswan are for. + + + +Callbacks to implement +====================== + +/* from include/linux/netdevice.h */ +struct xfrmdev_ops { + int (*xdo_dev_state_add) (struct xfrm_state *x); + void (*xdo_dev_state_delete) (struct xfrm_state *x); + void (*xdo_dev_state_free) (struct xfrm_state *x); + bool (*xdo_dev_offload_ok) (struct sk_buff *skb, + struct xfrm_state *x); + void (*xdo_dev_state_advance_esn) (struct xfrm_state *x); +}; + +The NIC driver offering ipsec offload will need to implement these +callbacks to make the offload available to the network stack's +XFRM subsytem. Additionally, the feature bits NETIF_F_HW_ESP and +NETIF_F_HW_ESP_TX_CSUM will signal the availability of the offload. + + + +Flow +==== + +At probe time and before the call to register_netdev(), the driver should +set up local data structures and XFRM callbacks, and set the feature bits. +The XFRM code's listener will finish the setup on NETDEV_REGISTER. + + adapter->netdev->xfrmdev_ops = &ixgbe_xfrmdev_ops; + adapter->netdev->features |= NETIF_F_HW_ESP; + adapter->netdev->hw_enc_features |= NETIF_F_HW_ESP; + +When new SAs are set up with a request for "offload" feature, the +driver's xdo_dev_state_add() will be given the new SA to be offloaded +and an indication of whether it is for Rx or Tx. The driver should + - verify the algorithm is supported for offloads + - store the SA information (key, salt, target-ip, protocol, etc) + - enable the HW offload of the SA + +The driver can also set an offload_handle in the SA, an opaque void pointer +that can be used to convey context into the fast-path offload requests. + + xs->xso.offload_handle = context; + + +When the network stack is preparing an IPsec packet for an SA that has +been setup for offload, it first calls into xdo_dev_offload_ok() with +the skb and the intended offload state to ask the driver if the offload +will serviceable. This can check the packet information to be sure the +offload can be supported (e.g. IPv4 or IPv6, no IPv4 options, etc) and +return true of false to signify its support. + +When ready to send, the driver needs to inspect the Tx packet for the +offload information, including the opaque context, and set up the packet +send accordingly. + + xs = xfrm_input_state(skb); + context = xs->xso.offload_handle; + set up HW for send + +The stack has already inserted the appropriate IPsec headers in the +packet data, the offload just needs to do the encryption and fix up the +header values. + + +When a packet is received and the HW has indicated that it offloaded a +decryption, the driver needs to add a reference to the decoded SA into +the packet's skb. At this point the data should be decrypted but the +IPsec headers are still in the packet data; they are removed later up +the stack in xfrm_input(). + + find and hold the SA that was used to the Rx skb + get spi, protocol, and destination IP from packet headers + xs = find xs from (spi, protocol, dest_IP) + xfrm_state_hold(xs); + + store the state information into the skb + skb->sp = secpath_dup(skb->sp); + skb->sp->xvec[skb->sp->len++] = xs; + skb->sp->olen++; + + indicate the success and/or error status of the offload + xo = xfrm_offload(skb); + xo->flags = CRYPTO_DONE; + xo->status = crypto_status; + + hand the packet to napi_gro_receive() as usual + +In ESN mode, xdo_dev_state_advance_esn() is called from xfrm_replay_advance_esn(). +Driver will check packet seq number and update HW ESN state machine if needed. + +When the SA is removed by the user, the driver's xdo_dev_state_delete() +is asked to disable the offload. Later, xdo_dev_state_free() is called +from a garbage collection routine after all reference counts to the state +have been removed and any remaining resources can be cleared for the +offload state. How these are used by the driver will depend on specific +hardware needs. + +As a netdev is set to DOWN the XFRM stack's netdev listener will call +xdo_dev_state_delete() and xdo_dev_state_free() on any remaining offloaded +states. + + diff --git a/Documentation/networking/xfrm_proc.txt b/Documentation/networking/xfrm_proc.txt index d0d8bafa9016..2eae619ab67b 100644 --- a/Documentation/networking/xfrm_proc.txt +++ b/Documentation/networking/xfrm_proc.txt @@ -5,13 +5,15 @@ Masahide NAKAMURA Transformation Statistics ------------------------- -xfrm_proc is a statistics shown factor dropped by transformation -for developer. -It is a counter designed from current transformation source code -and defined like linux private MIB. -Inbound statistics -~~~~~~~~~~~~~~~~~~ +The xfrm_proc code is a set of statistics showing numbers of packets +dropped by the transformation code and why. These counters are defined +as part of the linux private MIB. These counters can be viewed in +/proc/net/xfrm_stat. + + +Inbound errors +~~~~~~~~~~~~~~ XfrmInError: All errors which is not matched others XfrmInBufferError: @@ -46,6 +48,10 @@ XfrmInPolBlock: Policy discards XfrmInPolError: Policy error +XfrmAcquireError: + State hasn't been fully acquired before use +XfrmFwdHdrError: + Forward routing of a packet is not allowed Outbound errors ~~~~~~~~~~~~~~~ @@ -72,3 +78,5 @@ XfrmOutPolDead: Policy is dead XfrmOutPolError: Policy error +XfrmOutStateInvalid: + State is invalid, perhaps expired diff --git a/Documentation/perf/arm_dsu_pmu.txt b/Documentation/perf/arm_dsu_pmu.txt new file mode 100644 index 000000000000..d611e15f5add --- /dev/null +++ b/Documentation/perf/arm_dsu_pmu.txt @@ -0,0 +1,28 @@ +ARM DynamIQ Shared Unit (DSU) PMU +================================== + +ARM DynamIQ Shared Unit integrates one or more cores with an L3 memory system, +control logic and external interfaces to form a multicore cluster. The PMU +allows counting the various events related to the L3 cache, Snoop Control Unit +etc, using 32bit independent counters. It also provides a 64bit cycle counter. + +The PMU can only be accessed via CPU system registers and are common to the +cores connected to the same DSU. Like most of the other uncore PMUs, DSU +PMU doesn't support process specific events and cannot be used in sampling mode. + +The DSU provides a bitmap for a subset of implemented events via hardware +registers. There is no way for the driver to determine if the other events +are available or not. Hence the driver exposes only those events advertised +by the DSU, in "events" directory under : + + /sys/bus/event_sources/devices/arm_dsu_/ + +The user should refer to the TRM of the product to figure out the supported events +and use the raw event code for the unlisted events. + +The driver also exposes the CPUs connected to the DSU instance in "associated_cpus". + + +e.g usage : + + perf stat -a -e arm_dsu_0/cycles/ diff --git a/Documentation/power/pci.txt b/Documentation/power/pci.txt index 704cd36079b8..8eaf9ee24d43 100644 --- a/Documentation/power/pci.txt +++ b/Documentation/power/pci.txt @@ -994,6 +994,17 @@ into D0 going forward), but if it is in runtime suspend in pci_pm_thaw_noirq(), the function will set the power.direct_complete flag for it (to make the PM core skip the subsequent "thaw" callbacks for it) and return. +Setting the DPM_FLAG_LEAVE_SUSPENDED flag means that the driver prefers the +device to be left in suspend after system-wide transitions to the working state. +This flag is checked by the PM core, but the PCI bus type informs the PM core +which devices may be left in suspend from its perspective (that happens during +the "noirq" phase of system-wide suspend and analogous transitions) and next it +uses the dev_pm_may_skip_resume() helper to decide whether or not to return from +pci_pm_resume_noirq() early, as the PM core will skip the remaining resume +callbacks for the device during the transition under way and will set its +runtime PM status to "suspended" if dev_pm_may_skip_resume() returns "true" for +it. + 3.2. Device Runtime Power Management ------------------------------------ In addition to providing device power management callbacks PCI device drivers diff --git a/Documentation/power/regulator/machine.txt b/Documentation/power/regulator/machine.txt index 757e3b53dc11..eff4dcaaa252 100644 --- a/Documentation/power/regulator/machine.txt +++ b/Documentation/power/regulator/machine.txt @@ -23,16 +23,12 @@ struct regulator_consumer_supply { e.g. for the machine above static struct regulator_consumer_supply regulator1_consumers[] = { -{ - .dev_name = "dev_name(consumer B)", - .supply = "Vcc", -},}; + REGULATOR_SUPPLY("Vcc", "consumer B"), +}; static struct regulator_consumer_supply regulator2_consumers[] = { -{ - .dev = "dev_name(consumer A"), - .supply = "Vcc", -},}; + REGULATOR_SUPPLY("Vcc", "consumer A"), +}; This maps Regulator-1 to the 'Vcc' supply for Consumer B and maps Regulator-2 to the 'Vcc' supply for Consumer A. @@ -78,20 +74,20 @@ static struct regulator_init_data regulator2_data = { Finally the regulator devices must be registered in the usual manner. static struct platform_device regulator_devices[] = { -{ - .name = "regulator", - .id = DCDC_1, - .dev = { - .platform_data = ®ulator1_data, + { + .name = "regulator", + .id = DCDC_1, + .dev = { + .platform_data = ®ulator1_data, + }, }, -}, -{ - .name = "regulator", - .id = DCDC_2, - .dev = { - .platform_data = ®ulator2_data, + { + .name = "regulator", + .id = DCDC_2, + .dev = { + .platform_data = ®ulator2_data, + }, }, -}, }; /* register regulator 1 device */ platform_device_register(®ulator_devices[0]); diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst index 560beaef5a7c..81cdb528ad46 100644 --- a/Documentation/process/changes.rst +++ b/Documentation/process/changes.rst @@ -32,6 +32,8 @@ you probably needn't concern yourself with isdn4k-utils. GNU C 3.2 gcc --version GNU make 3.81 make --version binutils 2.20 ld -v +flex 2.5.35 flex --version +bison 2.0 bison --version util-linux 2.10o fdformat --version module-init-tools 0.9.10 depmod -V e2fsprogs 1.41.4 e2fsck -V @@ -79,6 +81,19 @@ The build system has, as of 4.13, switched to using thin archives (`ar T`) rather than incremental linking (`ld -r`) for built-in.o intermediate steps. This requires binutils 2.20 or newer. +Flex +---- + +Since Linux 4.16, the build system generates lexical analyzers +during build. This requires flex 2.5.35 or later. + + +Bison +----- + +Since Linux 4.16, the build system generates parsers +during build. This requires bison 2.0 or later. + Perl ---- @@ -333,6 +348,16 @@ Binutils - +Flex +---- + +- + +Bison +----- + +- + OpenSSL ------- diff --git a/Documentation/process/index.rst b/Documentation/process/index.rst index a430f6eee756..1c9fe657ed01 100644 --- a/Documentation/process/index.rst +++ b/Documentation/process/index.rst @@ -24,6 +24,7 @@ Below are the essential guides that every developer should read. development-process submitting-patches coding-style + maintainer-pgp-guide email-clients kernel-enforcement-statement kernel-driver-statement diff --git a/Documentation/process/kernel-docs.rst b/Documentation/process/kernel-docs.rst index b8cac85a4001..3fb28de556e4 100644 --- a/Documentation/process/kernel-docs.rst +++ b/Documentation/process/kernel-docs.rst @@ -58,7 +58,7 @@ On-line docs * Title: **Linux Kernel Mailing List Glossary** :Author: various - :URL: http://kernelnewbies.org/glossary/ + :URL: https://kernelnewbies.org/KernelGlossary :Date: rolling version :Keywords: glossary, terms, linux-kernel. :Description: From the introduction: "This glossary is intended as diff --git a/Documentation/process/kernel-enforcement-statement.rst b/Documentation/process/kernel-enforcement-statement.rst index b3170671a1df..6816c12d6956 100644 --- a/Documentation/process/kernel-enforcement-statement.rst +++ b/Documentation/process/kernel-enforcement-statement.rst @@ -68,6 +68,7 @@ we might work for today, have in the past, or will in the future. - Paul Burton - Javier Martinez Canillas - Rob Clark + - Kees Cook (Google) - Jonathan Corbet - Dennis Dalessandro - Vivien Didelot (Savoir-faire Linux) @@ -118,6 +119,7 @@ we might work for today, have in the past, or will in the future. - Mike Marshall - Chris Mason - Paul E. McKenney + - Arnaldo Carvalho de Melo - David S. Miller - Ingo Molnar - Kuninori Morimoto @@ -136,6 +138,7 @@ we might work for today, have in the past, or will in the future. - Anna Schumaker - Jes Sorensen - K.Y. Srinivasan + - David Sterba (SUSE) - Heiko Stuebner - Jiri Kosina (SUSE) - Willy Tarreau @@ -143,6 +146,7 @@ we might work for today, have in the past, or will in the future. - Linus Torvalds - Thierry Reding - Rik van Riel + - Luis R. Rodriguez - Geert Uytterhoeven (Glider bvba) - Eduardo Valentin (Amazon.com) - Daniel Vetter diff --git a/Documentation/process/license-rules.rst b/Documentation/process/license-rules.rst new file mode 100644 index 000000000000..408f77dc6157 --- /dev/null +++ b/Documentation/process/license-rules.rst @@ -0,0 +1,370 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Linux kernel licensing rules +============================ + +The Linux Kernel is provided under the terms of the GNU General Public +License version 2 only (GPL-2.0), as published by the Free Software +Foundation, and provided in the COPYING file. This documentation file is +not meant to replace the COPYING file, but provides a description of how +each source file should be annotated to make the licensing it is governed +under clear and unambiguous. + +The license in the COPYING file applies to the kernel source as a whole, +though individual source files can have a different license which is +required to be compatible with the GPL-2.0:: + + GPL-1.0+ : GNU General Public License v1.0 or later + GPL-2.0+ : GNU General Public License v2.0 or later + LGPL-2.0 : GNU Library General Public License v2 only + LGPL-2.0+ : GNU Library General Public License v2 or later + LGPL-2.1 : GNU Lesser General Public License v2.1 only + LGPL-2.1+ : GNU Lesser General Public License v2.1 or later + +Aside from that, individual files can be provided under a dual license, +e.g. one of the compatible GPL variants and alternatively under a +permissive license like BSD, MIT etc. + +The User-space API (UAPI) header files, which describe the interface of +user-space programs to the kernel are a special case. According to the +note in the kernel COPYING file, the syscall interface is a clear boundary, +which does not extend the GPL requirements to any software which uses it to +communicate with the kernel. Because the UAPI headers must be includable +into any source files which create an executable running on the Linux +kernel, the exception must be documented by a special license expression. + +The common way of expressing the license of a source file is to add the +matching boilerplate text into the top comment of the file. Due to +formatting, typos etc. these "boilerplates" are hard to validate for +tools which are used in the context of license compliance. + +An alternative to boilerplate text is the use of Software Package Data +Exchange (SPDX) license identifiers in each source file. SPDX license +identifiers are machine parsable and precise shorthands for the license +under which the content of the file is contributed. SPDX license +identifiers are managed by the SPDX Workgroup at the Linux Foundation and +have been agreed on by partners throughout the industry, tool vendors, and +legal teams. For further information see https://spdx.org/ + +The Linux kernel requires the precise SPDX identifier in all source files. +The valid identifiers used in the kernel are explained in the section +`License identifiers`_ and have been retrieved from the official SPDX +license list at https://spdx.org/licenses/ along with the license texts. + +License identifier syntax +------------------------- + +1. Placement: + + The SPDX license identifier in kernel files shall be added at the first + possible line in a file which can contain a comment. For the majority + or files this is the first line, except for scripts which require the + '#!PATH_TO_INTERPRETER' in the first line. For those scripts the SPDX + identifier goes into the second line. + +| + +2. Style: + + The SPDX license identifier is added in form of a comment. The comment + style depends on the file type:: + + C source: // SPDX-License-Identifier: + C header: /* SPDX-License-Identifier: */ + ASM: /* SPDX-License-Identifier: */ + scripts: # SPDX-License-Identifier: + .rst: .. SPDX-License-Identifier: + .dts{i}: // SPDX-License-Identifier: + + If a specific tool cannot handle the standard comment style, then the + appropriate comment mechanism which the tool accepts shall be used. This + is the reason for having the "/\* \*/" style comment in C header + files. There was build breakage observed with generated .lds files where + 'ld' failed to parse the C++ comment. This has been fixed by now, but + there are still older assembler tools which cannot handle C++ style + comments. + +| + +3. Syntax: + + A is either an SPDX short form license + identifier found on the SPDX License List, or the combination of two + SPDX short form license identifiers separated by "WITH" when a license + exception applies. When multiple licenses apply, an expression consists + of keywords "AND", "OR" separating sub-expressions and surrounded by + "(", ")" . + + License identifiers for licenses like [L]GPL with the 'or later' option + are constructed by using a "+" for indicating the 'or later' option.:: + + // SPDX-License-Identifier: GPL-2.0+ + // SPDX-License-Identifier: LGPL-2.1+ + + WITH should be used when there is a modifier to a license needed. + For example, the linux kernel UAPI files use the expression:: + + // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note + // SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note + + Other examples using WITH exceptions found in the kernel are:: + + // SPDX-License-Identifier: GPL-2.0 WITH mif-exception + // SPDX-License-Identifier: GPL-2.0+ WITH GCC-exception-2.0 + + Exceptions can only be used with particular License identifiers. The + valid License identifiers are listed in the tags of the exception text + file. For details see the point `Exceptions`_ in the chapter `License + identifiers`_. + + OR should be used if the file is dual licensed and only one license is + to be selected. For example, some dtsi files are available under dual + licenses:: + + // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + + Examples from the kernel for license expressions in dual licensed files:: + + // SPDX-License-Identifier: GPL-2.0 OR MIT + // SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause + // SPDX-License-Identifier: GPL-2.0 OR Apache-2.0 + // SPDX-License-Identifier: GPL-2.0 OR MPL-1.1 + // SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT + // SPDX-License-Identifier: GPL-1.0+ OR BSD-3-Clause OR OpenSSL + + AND should be used if the file has multiple licenses whose terms all + apply to use the file. For example, if code is inherited from another + project and permission has been given to put it in the kernel, but the + original license terms need to remain in effect:: + + // SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) AND MIT + + Another other example where both sets of license terms need to be + adhered to is:: + + // SPDX-License-Identifier: GPL-1.0+ AND LGPL-2.1+ + +License identifiers +------------------- + +The licenses currently used, as well as the licenses for code added to the +kernel, can be broken down into: + +1. _`Preferred licenses`: + + Whenever possible these licenses should be used as they are known to be + fully compatible and widely used. These licenses are available from the + directory:: + + LICENSES/preferred/ + + in the kernel source tree. + + The files in this directory contain the full license text and + `Metatags`_. The file names are identical to the SPDX license + identifier which shall be used for the license in source files. + + Examples:: + + LICENSES/preferred/GPL-2.0 + + Contains the GPL version 2 license text and the required metatags:: + + LICENSES/preferred/MIT + + Contains the MIT license text and the required metatags + + _`Metatags`: + + The following meta tags must be available in a license file: + + - Valid-License-Identifier: + + One or more lines which declare which License Identifiers are valid + inside the project to reference this particular license text. Usually + this is a single valid identifier, but e.g. for licenses with the 'or + later' options two identifiers are valid. + + - SPDX-URL: + + The URL of the SPDX page which contains additional information related + to the license. + + - Usage-Guidance: + + Freeform text for usage advice. The text must include correct examples + for the SPDX license identifiers as they should be put into source + files according to the `License identifier syntax`_ guidelines. + + - License-Text: + + All text after this tag is treated as the original license text + + File format examples:: + + Valid-License-Identifier: GPL-2.0 + Valid-License-Identifier: GPL-2.0+ + SPDX-URL: https://spdx.org/licenses/GPL-2.0.html + Usage-Guide: + To use this license in source code, put one of the following SPDX + tag/value pairs into a comment according to the placement + guidelines in the licensing rules documentation. + For 'GNU General Public License (GPL) version 2 only' use: + SPDX-License-Identifier: GPL-2.0 + For 'GNU General Public License (GPL) version 2 or any later version' use: + SPDX-License-Identifier: GPL-2.0+ + License-Text: + Full license text + + :: + + SPDX-License-Identifier: MIT + SPDX-URL: https://spdx.org/licenses/MIT.html + Usage-Guide: + To use this license in source code, put the following SPDX + tag/value pair into a comment according to the placement + guidelines in the licensing rules documentation. + SPDX-License-Identifier: MIT + License-Text: + Full license text + +| + +2. Not recommended licenses: + + These licenses should only be used for existing code or for importing + code from a different project. These licenses are available from the + directory:: + + LICENSES/other/ + + in the kernel source tree. + + The files in this directory contain the full license text and + `Metatags`_. The file names are identical to the SPDX license + identifier which shall be used for the license in source files. + + Examples:: + + LICENSES/other/ISC + + Contains the Internet Systems Consortium license text and the required + metatags:: + + LICENSES/other/ZLib + + Contains the ZLIB license text and the required metatags. + + Metatags: + + The metatag requirements for 'other' licenses are identical to the + requirements of the `Preferred licenses`_. + + File format example:: + + Valid-License-Identifier: ISC + SPDX-URL: https://spdx.org/licenses/ISC.html + Usage-Guide: + Usage of this license in the kernel for new code is discouraged + and it should solely be used for importing code from an already + existing project. + To use this license in source code, put the following SPDX + tag/value pair into a comment according to the placement + guidelines in the licensing rules documentation. + SPDX-License-Identifier: ISC + License-Text: + Full license text + +| + +3. _`Exceptions`: + + Some licenses can be amended with exceptions which grant certain rights + which the original license does not. These exceptions are available + from the directory:: + + LICENSES/exceptions/ + + in the kernel source tree. The files in this directory contain the full + exception text and the required `Exception Metatags`_. + + Examples:: + + LICENSES/exceptions/Linux-syscall-note + + Contains the Linux syscall exception as documented in the COPYING + file of the Linux kernel, which is used for UAPI header files. + e.g. /\* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note \*/:: + + LICENSES/exceptions/GCC-exception-2.0 + + Contains the GCC 'linking exception' which allows to link any binary + independent of its license against the compiled version of a file marked + with this exception. This is required for creating runnable executables + from source code which is not compatible with the GPL. + + _`Exception Metatags`: + + The following meta tags must be available in an exception file: + + - SPDX-Exception-Identifier: + + One exception identifier which can be used with SPDX license + identifiers. + + - SPDX-URL: + + The URL of the SPDX page which contains additional information related + to the exception. + + - SPDX-Licenses: + + A comma separated list of SPDX license identifiers for which the + exception can be used. + + - Usage-Guidance: + + Freeform text for usage advice. The text must be followed by correct + examples for the SPDX license identifiers as they should be put into + source files according to the `License identifier syntax`_ guidelines. + + - Exception-Text: + + All text after this tag is treated as the original exception text + + File format examples:: + + SPDX-Exception-Identifier: Linux-syscall-note + SPDX-URL: https://spdx.org/licenses/Linux-syscall-note.html + SPDX-Licenses: GPL-2.0, GPL-2.0+, GPL-1.0+, LGPL-2.0, LGPL-2.0+, LGPL-2.1, LGPL-2.1+ + Usage-Guidance: + This exception is used together with one of the above SPDX-Licenses + to mark user-space API (uapi) header files so they can be included + into non GPL compliant user-space application code. + To use this exception add it with the keyword WITH to one of the + identifiers in the SPDX-Licenses tag: + SPDX-License-Identifier: WITH Linux-syscall-note + Exception-Text: + Full exception text + + :: + + SPDX-Exception-Identifier: GCC-exception-2.0 + SPDX-URL: https://spdx.org/licenses/GCC-exception-2.0.html + SPDX-Licenses: GPL-2.0, GPL-2.0+ + Usage-Guidance: + The "GCC Runtime Library exception 2.0" is used together with one + of the above SPDX-Licenses for code imported from the GCC runtime + library. + To use this exception add it with the keyword WITH to one of the + identifiers in the SPDX-Licenses tag: + SPDX-License-Identifier: WITH GCC-exception-2.0 + Exception-Text: + Full exception text + + +All SPDX license identifiers and exceptions must have a corresponding file +in the LICENSE subdirectories. This is required to allow tool +verification (e.g. checkpatch.pl) and to have the licenses ready to read +and extract right from the source, which is recommended by various FOSS +organizations, e.g. the `FSFE REUSE initiative `_. diff --git a/Documentation/process/maintainer-pgp-guide.rst b/Documentation/process/maintainer-pgp-guide.rst new file mode 100644 index 000000000000..b453561a7148 --- /dev/null +++ b/Documentation/process/maintainer-pgp-guide.rst @@ -0,0 +1,929 @@ +.. _pgpguide: + +=========================== +Kernel Maintainer PGP guide +=========================== + +:Author: Konstantin Ryabitsev + +This document is aimed at Linux kernel developers, and especially at +subsystem maintainers. It contains a subset of information discussed in +the more general "`Protecting Code Integrity`_" guide published by the +Linux Foundation. Please read that document for more in-depth discussion +on some of the topics mentioned in this guide. + +.. _`Protecting Code Integrity`: https://github.com/lfit/itpol/blob/master/protecting-code-integrity.md + +The role of PGP in Linux Kernel development +=========================================== + +PGP helps ensure the integrity of the code that is produced by the Linux +kernel development community and, to a lesser degree, establish trusted +communication channels between developers via PGP-signed email exchange. + +The Linux kernel source code is available in two main formats: + +- Distributed source repositories (git) +- Periodic release snapshots (tarballs) + +Both git repositories and tarballs carry PGP signatures of the kernel +developers who create official kernel releases. These signatures offer a +cryptographic guarantee that downloadable versions made available via +kernel.org or any other mirrors are identical to what these developers +have on their workstations. To this end: + +- git repositories provide PGP signatures on all tags +- tarballs provide detached PGP signatures with all downloads + +.. _devs_not_infra: + +Trusting the developers, not infrastructure +------------------------------------------- + +Ever since the 2011 compromise of core kernel.org systems, the main +operating principle of the Kernel Archives project has been to assume +that any part of the infrastructure can be compromised at any time. For +this reason, the administrators have taken deliberate steps to emphasize +that trust must always be placed with developers and never with the code +hosting infrastructure, regardless of how good the security practices +for the latter may be. + +The above guiding principle is the reason why this guide is needed. We +want to make sure that by placing trust into developers we do not simply +shift the blame for potential future security incidents to someone else. +The goal is to provide a set of guidelines developers can use to create +a secure working environment and safeguard the PGP keys used to +establish the integrity of the Linux kernel itself. + +.. _pgp_tools: + +PGP tools +========= + +Use GnuPG v2 +------------ + +Your distro should already have GnuPG installed by default, you just +need to verify that you are using version 2.x and not the legacy 1.4 +release -- many distributions still package both, with the default +``gpg`` command invoking GnuPG v.1. To check, run:: + + $ gpg --version | head -n1 + +If you see ``gpg (GnuPG) 1.4.x``, then you are using GnuPG v.1. Try the +``gpg2`` command (if you don't have it, you may need to install the +gnupg2 package):: + + $ gpg2 --version | head -n1 + +If you see ``gpg (GnuPG) 2.x.x``, then you are good to go. This guide +will assume you have the version 2.2 of GnuPG (or later). If you are +using version 2.0 of GnuPG, then some of the commands in this guide will +not work, and you should consider installing the latest 2.2 version of +GnuPG. Versions of gnupg-2.1.11 and later should be compatible for the +purposes of this guide as well. + +If you have both ``gpg`` and ``gpg2`` commands, you should make sure you +are always using GnuPG v2, not the legacy version. You can enforce this +by setting the appropriate alias:: + + $ alias gpg=gpg2 + +You can put that in your ``.bashrc`` to make sure it's always the case. + +Configure gpg-agent options +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The GnuPG agent is a helper tool that will start automatically whenever +you use the ``gpg`` command and run in the background with the purpose +of caching the private key passphrase. There are two options you should +know in order to tweak when the passphrase should be expired from cache: + +- ``default-cache-ttl`` (seconds): If you use the same key again before + the time-to-live expires, the countdown will reset for another period. + The default is 600 (10 minutes). +- ``max-cache-ttl`` (seconds): Regardless of how recently you've used + the key since initial passphrase entry, if the maximum time-to-live + countdown expires, you'll have to enter the passphrase again. The + default is 30 minutes. + +If you find either of these defaults too short (or too long), you can +edit your ``~/.gnupg/gpg-agent.conf`` file to set your own values:: + + # set to 30 minutes for regular ttl, and 2 hours for max ttl + default-cache-ttl 1800 + max-cache-ttl 7200 + +.. note:: + + It is no longer necessary to start gpg-agent manually at the + beginning of your shell session. You may want to check your rc files + to remove anything you had in place for older versions of GnuPG, as + it may not be doing the right thing any more. + +Set up a refresh cronjob +~~~~~~~~~~~~~~~~~~~~~~~~ + +You will need to regularly refresh your keyring in order to get the +latest changes on other people's public keys, which is best done with a +daily cronjob:: + + @daily /usr/bin/gpg2 --refresh >/dev/null 2>&1 + +Check the full path to your ``gpg`` or ``gpg2`` command and use the +``gpg2`` command if regular ``gpg`` for you is the legacy GnuPG v.1. + +.. _master_key: + +Protect your master PGP key +=========================== + +This guide assumes that you already have a PGP key that you use for Linux +kernel development purposes. If you do not yet have one, please see the +"`Protecting Code Integrity`_" document mentioned earlier for guidance +on how to create a new one. + +You should also make a new key if your current one is weaker than 2048 bits +(RSA). + +Master key vs. Subkeys +---------------------- + +Subkeys are fully independent PGP keypairs that are tied to the "master" +key using certifying key signatures (certificates). It is important to +understand the following: + +1. There are no technical differences between the "master key" and "subkeys." +2. At creation time, we assign functional limitations to each key by + giving it specific capabilities. +3. A PGP key can have 4 capabilities: + + - **[S]** key can be used for signing + - **[E]** key can be used for encryption + - **[A]** key can be used for authentication + - **[C]** key can be used for certifying other keys + +4. A single key may have multiple capabilities. +5. A subkey is fully independent from the master key. A message + encrypted to a subkey cannot be decrypted with the master key. If you + lose your private subkey, it cannot be recreated from the master key + in any way. + +The key carrying the **[C]** (certify) capability is considered the +"master" key because it is the only key that can be used to indicate +relationship with other keys. Only the **[C]** key can be used to: + +- add or revoke other keys (subkeys) with S/E/A capabilities +- add, change or revoke identities (uids) associated with the key +- add or change the expiration date on itself or any subkey +- sign other people's keys for web of trust purposes + +By default, GnuPG creates the following when generating new keys: + +- A master key carrying both Certify and Sign capabilities (**[SC]**) +- A separate subkey with the Encryption capability (**[E]**) + +If you used the default parameters when generating your key, then that +is what you will have. You can verify by running ``gpg --list-secret-keys``, +for example:: + + sec rsa2048 2018-01-23 [SC] [expires: 2020-01-23] + 000000000000000000000000AAAABBBBCCCCDDDD + uid [ultimate] Alice Dev + ssb rsa2048 2018-01-23 [E] [expires: 2020-01-23] + +Any key carrying the **[C]** capability is your master key, regardless +of any other capabilities it may have assigned to it. + +The long line under the ``sec`` entry is your key fingerprint -- +whenever you see ``[fpr]`` in the examples below, that 40-character +string is what it refers to. + +Ensure your passphrase is strong +-------------------------------- + +GnuPG uses passphrases to encrypt your private keys before storing them on +disk. This way, even if your ``.gnupg`` directory is leaked or stolen in +its entirety, the attackers cannot use your private keys without first +obtaining the passphrase to decrypt them. + +It is absolutely essential that your private keys are protected by a +strong passphrase. To set it or change it, use:: + + $ gpg --change-passphrase [fpr] + +Create a separate Signing subkey +-------------------------------- + +Our goal is to protect your master key by moving it to offline media, so +if you only have a combined **[SC]** key, then you should create a separate +signing subkey:: + + $ gpg --quick-add-key [fpr] ed25519 sign + +Remember to tell the keyservers about this change, so others can pull down +your new subkey:: + + $ gpg --send-key [fpr] + +.. note:: ECC support in GnuPG + + GnuPG 2.1 and later has full support for Elliptic Curve + Cryptography, with ability to combine ECC subkeys with traditional + RSA master keys. The main upside of ECC cryptography is that it is + much faster computationally and creates much smaller signatures when + compared byte for byte with 2048+ bit RSA keys. Unless you plan on + using a smartcard device that does not support ECC operations, we + recommend that you create an ECC signing subkey for your kernel + work. + + If for some reason you prefer to stay with RSA subkeys, just replace + "ed25519" with "rsa2048" in the above command. + + +Back up your master key for disaster recovery +--------------------------------------------- + +The more signatures you have on your PGP key from other developers, the +more reasons you have to create a backup version that lives on something +other than digital media, for disaster recovery reasons. + +The best way to create a printable hardcopy of your private key is by +using the ``paperkey`` software written for this very purpose. See ``man +paperkey`` for more details on the output format and its benefits over +other solutions. Paperkey should already be packaged for most +distributions. + +Run the following command to create a hardcopy backup of your private +key:: + + $ gpg --export-secret-key [fpr] | paperkey -o /tmp/key-backup.txt + +Print out that file (or pipe the output straight to lpr), then take a +pen and write your passphrase on the margin of the paper. **This is +strongly recommended** because the key printout is still encrypted with +that passphrase, and if you ever change it you will not remember what it +used to be when you had created the backup -- *guaranteed*. + +Put the resulting printout and the hand-written passphrase into an envelope +and store in a secure and well-protected place, preferably away from your +home, such as your bank vault. + +.. note:: + + Your printer is probably no longer a simple dumb device connected to + your parallel port, but since the output is still encrypted with + your passphrase, printing out even to "cloud-integrated" modern + printers should remain a relatively safe operation. One option is to + change the passphrase on your master key immediately after you are + done with paperkey. + +Back up your whole GnuPG directory +---------------------------------- + +.. warning:: + + **!!!Do not skip this step!!!** + +It is important to have a readily available backup of your PGP keys +should you need to recover them. This is different from the +disaster-level preparedness we did with ``paperkey``. You will also rely +on these external copies whenever you need to use your Certify key -- +such as when making changes to your own key or signing other people's +keys after conferences and summits. + +Start by getting a small USB "thumb" drive (preferably two!) that you +will use for backup purposes. You will need to encrypt them using LUKS +-- refer to your distro's documentation on how to accomplish this. + +For the encryption passphrase, you can use the same one as on your +master key. + +Once the encryption process is over, re-insert the USB drive and make +sure it gets properly mounted. Copy your entire ``.gnupg`` directory +over to the encrypted storage:: + + $ cp -a ~/.gnupg /media/disk/foo/gnupg-backup + +You should now test to make sure everything still works:: + + $ gpg --homedir=/media/disk/foo/gnupg-backup --list-key [fpr] + +If you don't get any errors, then you should be good to go. Unmount the +USB drive, distinctly label it so you don't blow it away next time you +need to use a random USB drive, and put in a safe place -- but not too +far away, because you'll need to use it every now and again for things +like editing identities, adding or revoking subkeys, or signing other +people's keys. + +Remove the master key from your homedir +---------------------------------------- + +The files in our home directory are not as well protected as we like to +think. They can be leaked or stolen via many different means: + +- by accident when making quick homedir copies to set up a new workstation +- by systems administrator negligence or malice +- via poorly secured backups +- via malware in desktop apps (browsers, pdf viewers, etc) +- via coercion when crossing international borders + +Protecting your key with a good passphrase greatly helps reduce the risk +of any of the above, but passphrases can be discovered via keyloggers, +shoulder-surfing, or any number of other means. For this reason, the +recommended setup is to remove your master key from your home directory +and store it on offline storage. + +.. warning:: + + Please see the previous section and make sure you have backed up + your GnuPG directory in its entirety. What we are about to do will + render your key useless if you do not have a usable backup! + +First, identify the keygrip of your master key:: + + $ gpg --with-keygrip --list-key [fpr] + +The output will be something like this:: + + pub rsa2048 2018-01-24 [SC] [expires: 2020-01-24] + 000000000000000000000000AAAABBBBCCCCDDDD + Keygrip = 1111000000000000000000000000000000000000 + uid [ultimate] Alice Dev + sub rsa2048 2018-01-24 [E] [expires: 2020-01-24] + Keygrip = 2222000000000000000000000000000000000000 + sub ed25519 2018-01-24 [S] + Keygrip = 3333000000000000000000000000000000000000 + +Find the keygrip entry that is beneath the ``pub`` line (right under the +master key fingerprint). This will correspond directly to a file in your +``~/.gnupg`` directory:: + + $ cd ~/.gnupg/private-keys-v1.d + $ ls + 1111000000000000000000000000000000000000.key + 2222000000000000000000000000000000000000.key + 3333000000000000000000000000000000000000.key + +All you have to do is simply remove the .key file that corresponds to +the master keygrip:: + + $ cd ~/.gnupg/private-keys-v1.d + $ rm 1111000000000000000000000000000000000000.key + +Now, if you issue the ``--list-secret-keys`` command, it will show that +the master key is missing (the ``#`` indicates it is not available):: + + $ gpg --list-secret-keys + sec# rsa2048 2018-01-24 [SC] [expires: 2020-01-24] + 000000000000000000000000AAAABBBBCCCCDDDD + uid [ultimate] Alice Dev + ssb rsa2048 2018-01-24 [E] [expires: 2020-01-24] + ssb ed25519 2018-01-24 [S] + +You should also remove any ``secring.gpg`` files in the ``~/.gnupg`` +directory, which are left over from earlier versions of GnuPG. + +If you don't have the "private-keys-v1.d" directory +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you do not have a ``~/.gnupg/private-keys-v1.d`` directory, then your +secret keys are still stored in the legacy ``secring.gpg`` file used by +GnuPG v1. Making any changes to your key, such as changing the +passphrase or adding a subkey, should automatically convert the old +``secring.gpg`` format to use ``private-keys-v1.d`` instead. + +Once you get that done, make sure to delete the obsolete ``secring.gpg`` +file, which still contains your private keys. + +.. _smartcards: + +Move the subkeys to a dedicated crypto device +============================================= + +Even though the master key is now safe from being leaked or stolen, the +subkeys are still in your home directory. Anyone who manages to get +their hands on those will be able to decrypt your communication or fake +your signatures (if they know the passphrase). Furthermore, each time a +GnuPG operation is performed, the keys are loaded into system memory and +can be stolen from there by sufficiently advanced malware (think +Meltdown and Spectre). + +The best way to completely protect your keys is to move them to a +specialized hardware device that is capable of smartcard operations. + +The benefits of smartcards +-------------------------- + +A smartcard contains a cryptographic chip that is capable of storing +private keys and performing crypto operations directly on the card +itself. Because the key contents never leave the smartcard, the +operating system of the computer into which you plug in the hardware +device is not able to retrieve the private keys themselves. This is very +different from the encrypted USB storage device we used earlier for +backup purposes -- while that USB device is plugged in and mounted, the +operating system is able to access the private key contents. + +Using external encrypted USB media is not a substitute to having a +smartcard-capable device. + +Available smartcard devices +--------------------------- + +Unless all your laptops and workstations have smartcard readers, the +easiest is to get a specialized USB device that implements smartcard +functionality. There are several options available: + +- `Nitrokey Start`_: Open hardware and Free Software, based on FSI + Japan's `Gnuk`_. Offers support for ECC keys, but fewest security + features (such as resistance to tampering or some side-channel + attacks). +- `Nitrokey Pro`_: Similar to the Nitrokey Start, but more + tamper-resistant and offers more security features, but no ECC + support. +- `Yubikey 4`_: proprietary hardware and software, but cheaper than + Nitrokey Pro and comes available in the USB-C form that is more useful + with newer laptops. Offers additional security features such as FIDO + U2F, but no ECC. + +`LWN has a good review`_ of some of the above models, as well as several +others. If you want to use ECC keys, your best bet among commercially +available devices is the Nitrokey Start. + +.. _`Nitrokey Start`: https://shop.nitrokey.com/shop/product/nitrokey-start-6 +.. _`Nitrokey Pro`: https://shop.nitrokey.com/shop/product/nitrokey-pro-3 +.. _`Yubikey 4`: https://www.yubico.com/product/yubikey-4-series/ +.. _Gnuk: http://www.fsij.org/doc-gnuk/ +.. _`LWN has a good review`: https://lwn.net/Articles/736231/ + +Configure your smartcard device +------------------------------- + +Your smartcard device should Just Work (TM) the moment you plug it into +any modern Linux workstation. You can verify it by running:: + + $ gpg --card-status + +If you see full smartcard details, then you are good to go. +Unfortunately, troubleshooting all possible reasons why things may not +be working for you is way beyond the scope of this guide. If you are +having trouble getting the card to work with GnuPG, please seek help via +usual support channels. + +To configure your smartcard, you will need to use the GnuPG menu system, as +there are no convenient command-line switches:: + + $ gpg --card-edit + [...omitted...] + gpg/card> admin + Admin commands are allowed + gpg/card> passwd + +You should set the user PIN (1), Admin PIN (3), and the Reset Code (4). +Please make sure to record and store these in a safe place -- especially +the Admin PIN and the Reset Code (which allows you to completely wipe +the smartcard). You so rarely need to use the Admin PIN, that you will +inevitably forget what it is if you do not record it. + +Getting back to the main card menu, you can also set other values (such +as name, sex, login data, etc), but it's not necessary and will +additionally leak information about your smartcard should you lose it. + +.. note:: + + Despite having the name "PIN", neither the user PIN nor the admin + PIN on the card need to be numbers. + +Move the subkeys to your smartcard +---------------------------------- + +Exit the card menu (using "q") and save all changes. Next, let's move +your subkeys onto the smartcard. You will need both your PGP key +passphrase and the admin PIN of the card for most operations:: + + $ gpg --edit-key [fpr] + + Secret subkeys are available. + + pub rsa2048/AAAABBBBCCCCDDDD + created: 2018-01-23 expires: 2020-01-23 usage: SC + trust: ultimate validity: ultimate + ssb rsa2048/1111222233334444 + created: 2018-01-23 expires: never usage: E + ssb ed25519/5555666677778888 + created: 2017-12-07 expires: never usage: S + [ultimate] (1). Alice Dev + + gpg> + +Using ``--edit-key`` puts us into the menu mode again, and you will +notice that the key listing is a little different. From here on, all +commands are done from inside this menu mode, as indicated by ``gpg>``. + +First, let's select the key we'll be putting onto the card -- you do +this by typing ``key 1`` (it's the first one in the listing, the **[E]** +subkey):: + + gpg> key 1 + +In the output, you should now see ``ssb*`` on the **[E]** key. The ``*`` +indicates which key is currently "selected." It works as a *toggle*, +meaning that if you type ``key 1`` again, the ``*`` will disappear and +the key will not be selected any more. + +Now, let's move that key onto the smartcard:: + + gpg> keytocard + Please select where to store the key: + (2) Encryption key + Your selection? 2 + +Since it's our **[E]** key, it makes sense to put it into the Encryption +slot. When you submit your selection, you will be prompted first for +your PGP key passphrase, and then for the admin PIN. If the command +returns without an error, your key has been moved. + +**Important**: Now type ``key 1`` again to unselect the first key, and +``key 2`` to select the **[S]** key:: + + gpg> key 1 + gpg> key 2 + gpg> keytocard + Please select where to store the key: + (1) Signature key + (3) Authentication key + Your selection? 1 + +You can use the **[S]** key both for Signature and Authentication, but +we want to make sure it's in the Signature slot, so choose (1). Once +again, if your command returns without an error, then the operation was +successful:: + + gpg> q + Save changes? (y/N) y + +Saving the changes will delete the keys you moved to the card from your +home directory (but it's okay, because we have them in our backups +should we need to do this again for a replacement smartcard). + +Verifying that the keys were moved +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you perform ``--list-secret-keys`` now, you will see a subtle +difference in the output:: + + $ gpg --list-secret-keys + sec# rsa2048 2018-01-24 [SC] [expires: 2020-01-24] + 000000000000000000000000AAAABBBBCCCCDDDD + uid [ultimate] Alice Dev + ssb> rsa2048 2018-01-24 [E] [expires: 2020-01-24] + ssb> ed25519 2018-01-24 [S] + +The ``>`` in the ``ssb>`` output indicates that the subkey is only +available on the smartcard. If you go back into your secret keys +directory and look at the contents there, you will notice that the +``.key`` files there have been replaced with stubs:: + + $ cd ~/.gnupg/private-keys-v1.d + $ strings *.key | grep 'private-key' + +The output should contain ``shadowed-private-key`` to indicate that +these files are only stubs and the actual content is on the smartcard. + +Verifying that the smartcard is functioning +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To verify that the smartcard is working as intended, you can create a +signature:: + + $ echo "Hello world" | gpg --clearsign > /tmp/test.asc + $ gpg --verify /tmp/test.asc + +This should ask for your smartcard PIN on your first command, and then +show "Good signature" after you run ``gpg --verify``. + +Congratulations, you have successfully made it extremely difficult to +steal your digital developer identity! + +Other common GnuPG operations +----------------------------- + +Here is a quick reference for some common operations you'll need to do +with your PGP key. + +Mounting your master key offline storage +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You will need your master key for any of the operations below, so you +will first need to mount your backup offline storage and tell GnuPG to +use it:: + + $ export GNUPGHOME=/media/disk/foo/gnupg-backup + $ gpg --list-secret-keys + +You want to make sure that you see ``sec`` and not ``sec#`` in the +output (the ``#`` means the key is not available and you're still using +your regular home directory location). + +Extending key expiration date +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The master key has the default expiration date of 2 years from the date +of creation. This is done both for security reasons and to make obsolete +keys eventually disappear from keyservers. + +To extend the expiration on your key by a year from current date, just +run:: + + $ gpg --quick-set-expire [fpr] 1y + +You can also use a specific date if that is easier to remember (e.g. +your birthday, January 1st, or Canada Day):: + + $ gpg --quick-set-expire [fpr] 2020-07-01 + +Remember to send the updated key back to keyservers:: + + $ gpg --send-key [fpr] + +Updating your work directory after any changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +After you make any changes to your key using the offline storage, you will +want to import these changes back into your regular working directory:: + + $ gpg --export | gpg --homedir ~/.gnupg --import + $ unset GNUPGHOME + + +Using PGP with Git +================== + +One of the core features of Git is its decentralized nature -- once a +repository is cloned to your system, you have full history of the +project, including all of its tags, commits and branches. However, with +hundreds of cloned repositories floating around, how does anyone verify +that their copy of linux.git has not been tampered with by a malicious +third party? + +Or what happens if a backdoor is discovered in the code and the "Author" +line in the commit says it was done by you, while you're pretty sure you +had `nothing to do with it`_? + +To address both of these issues, Git introduced PGP integration. Signed +tags prove the repository integrity by assuring that its contents are +exactly the same as on the workstation of the developer who created the +tag, while signed commits make it nearly impossible for someone to +impersonate you without having access to your PGP keys. + +.. _`nothing to do with it`: https://github.com/jayphelps/git-blame-someone-else + +Configure git to use your PGP key +--------------------------------- + +If you only have one secret key in your keyring, then you don't really +need to do anything extra, as it becomes your default key. However, if +you happen to have multiple secret keys, you can tell git which key +should be used (``[fpr]`` is the fingerprint of your key):: + + $ git config --global user.signingKey [fpr] + +**IMPORTANT**: If you have a distinct ``gpg2`` command, then you should +tell git to always use it instead of the legacy ``gpg`` from version 1:: + + $ git config --global gpg.program gpg2 + +How to work with signed tags +---------------------------- + +To create a signed tag, simply pass the ``-s`` switch to the tag +command:: + + $ git tag -s [tagname] + +Our recommendation is to always sign git tags, as this allows other +developers to ensure that the git repository they are pulling from has +not been maliciously altered. + +How to verify signed tags +~~~~~~~~~~~~~~~~~~~~~~~~~ + +To verify a signed tag, simply use the ``verify-tag`` command:: + + $ git verify-tag [tagname] + +If you are pulling a tag from another fork of the project repository, +git should automatically verify the signature at the tip you're pulling +and show you the results during the merge operation:: + + $ git pull [url] tags/sometag + +The merge message will contain something like this:: + + Merge tag 'sometag' of [url] + + [Tag message] + + # gpg: Signature made [...] + # gpg: Good signature from [...] + +If you are verifying someone else's git tag, then you will need to +import their PGP key. Please refer to the +":ref:`verify_identities`" section below. + +Configure git to always sign annotated tags +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Chances are, if you're creating an annotated tag, you'll want to sign +it. To force git to always sign annotated tags, you can set a global +configuration option:: + + $ git config --global tag.forceSignAnnotated true + +How to work with signed commits +------------------------------- + +It is easy to create signed commits, but it is much more difficult to +use them in Linux kernel development, since it relies on patches sent to +the mailing list, and this workflow does not preserve PGP commit +signatures. Furthermore, when rebasing your repository to match +upstream, even your own PGP commit signatures will end up discarded. For +this reason, most kernel developers don't bother signing their commits +and will ignore signed commits in any external repositories that they +rely upon in their work. + +However, if you have your working git tree publicly available at some +git hosting service (kernel.org, infradead.org, ozlabs.org, or others), +then the recommendation is that you sign all your git commits even if +upstream developers do not directly benefit from this practice. + +We recommend this for the following reasons: + +1. Should there ever be a need to perform code forensics or track code + provenance, even externally maintained trees carrying PGP commit + signatures will be valuable for such purposes. +2. If you ever need to re-clone your local repository (for example, + after a disk failure), this lets you easily verify the repository + integrity before resuming your work. +3. If someone needs to cherry-pick your commits, this allows them to + quickly verify their integrity before applying them. + +Creating signed commits +~~~~~~~~~~~~~~~~~~~~~~~ + +To create a signed commit, you just need to pass the ``-S`` flag to the +``git commit`` command (it's capital ``-S`` due to collision with +another flag):: + + $ git commit -S + +Configure git to always sign commits +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can tell git to always sign commits:: + + git config --global commit.gpgSign true + +.. note:: + + Make sure you configure ``gpg-agent`` before you turn this on. + +.. _verify_identities: + +How to verify kernel developer identities +========================================= + +Signing tags and commits is easy, but how does one go about verifying +that the key used to sign something belongs to the actual kernel +developer and not to a malicious imposter? + +Configure auto-key-retrieval using WKD and DANE +----------------------------------------------- + +If you are not already someone with an extensive collection of other +developers' public keys, then you can jumpstart your keyring by relying +on key auto-discovery and auto-retrieval. GnuPG can piggyback on other +delegated trust technologies, namely DNSSEC and TLS, to get you going if +the prospect of starting your own Web of Trust from scratch is too +daunting. + +Add the following to your ``~/.gnupg/gpg.conf``:: + + auto-key-locate wkd,dane,local + auto-key-retrieve + +DNS-Based Authentication of Named Entities ("DANE") is a method for +publishing public keys in DNS and securing them using DNSSEC signed +zones. Web Key Directory ("WKD") is the alternative method that uses +https lookups for the same purpose. When using either DANE or WKD for +looking up public keys, GnuPG will validate DNSSEC or TLS certificates, +respectively, before adding auto-retrieved public keys to your local +keyring. + +Kernel.org publishes the WKD for all developers who have kernel.org +accounts. Once you have the above changes in your ``gpg.conf``, you can +auto-retrieve the keys for Linus Torvalds and Greg Kroah-Hartman (if you +don't already have them):: + + $ gpg --locate-keys torvalds@kernel.org gregkh@kernel.org + +If you have a kernel.org account, then you should `add the kernel.org +UID to your key`_ to make WKD more useful to other kernel developers. + +.. _`add the kernel.org UID to your key`: https://korg.wiki.kernel.org/userdoc/mail#adding_a_kernelorg_uid_to_your_pgp_key + +Web of Trust (WOT) vs. Trust on First Use (TOFU) +------------------------------------------------ + +PGP incorporates a trust delegation mechanism known as the "Web of +Trust." At its core, this is an attempt to replace the need for +centralized Certification Authorities of the HTTPS/TLS world. Instead of +various software makers dictating who should be your trusted certifying +entity, PGP leaves this responsibility to each user. + +Unfortunately, very few people understand how the Web of Trust works. +While it remains an important aspect of the OpenPGP specification, +recent versions of GnuPG (2.2 and above) have implemented an alternative +mechanism called "Trust on First Use" (TOFU). You can think of TOFU as +"the SSH-like approach to trust." With SSH, the first time you connect +to a remote system, its key fingerprint is recorded and remembered. If +the key changes in the future, the SSH client will alert you and refuse +to connect, forcing you to make a decision on whether you choose to +trust the changed key or not. Similarly, the first time you import +someone's PGP key, it is assumed to be valid. If at any point in the +future GnuPG comes across another key with the same identity, both the +previously imported key and the new key will be marked as invalid and +you will need to manually figure out which one to keep. + +We recommend that you use the combined TOFU+PGP trust model (which is +the new default in GnuPG v2). To set it, add (or modify) the +``trust-model`` setting in ``~/.gnupg/gpg.conf``:: + + trust-model tofu+pgp + +How to use keyservers (more) safely +----------------------------------- + +If you get a "No public key" error when trying to validate someone's +tag, then you should attempt to lookup that key using a keyserver. It is +important to keep in mind that there is absolutely no guarantee that the +key you retrieve from PGP keyservers belongs to the actual person -- +that much is by design. You are supposed to use the Web of Trust to +establish key validity. + +How to properly maintain the Web of Trust is beyond the scope of this +document, simply because doing it properly requires both effort and +dedication that tends to be beyond the caring threshold of most human +beings. Here are some shortcuts that will help you reduce the risk of +importing a malicious key. + +First, let's say you've tried to run ``git verify-tag`` but it returned +an error saying the key is not found:: + + $ git verify-tag sunxi-fixes-for-4.15-2 + gpg: Signature made Sun 07 Jan 2018 10:51:55 PM EST + gpg: using RSA key DA73759BF8619E484E5A3B47389A54219C0F2430 + gpg: issuer "wens@...org" + gpg: Can't check signature: No public key + +Let's query the keyserver for more info about that key fingerprint (the +fingerprint probably belongs to a subkey, so we can't use it directly +without finding out the ID of the master key it is associated with):: + + $ gpg --search DA73759BF8619E484E5A3B47389A54219C0F2430 + gpg: data source: hkp://keys.gnupg.net + (1) Chen-Yu Tsai + 4096 bit RSA key C94035C21B4F2AEB, created: 2017-03-14, expires: 2019-03-15 + Keys 1-1 of 1 for "DA73759BF8619E484E5A3B47389A54219C0F2430". Enter number(s), N)ext, or Q)uit > q + +Locate the ID of the master key in the output, in our example +``C94035C21B4F2AEB``. Now display the key of Linus Torvalds that you +have on your keyring:: + + $ gpg --list-key torvalds@kernel.org + pub rsa2048 2011-09-20 [SC] + ABAF11C65A2970B130ABE3C479BE3E4300411886 + uid [ unknown] Linus Torvalds + sub rsa2048 2011-09-20 [E] + +Next, open the `PGP pathfinder`_. In the "From" field, paste the key +fingerprint of Linus Torvalds from the output above. In the "To" field, +paste they key-id you found via ``gpg --search`` of the unknown key, and +check the results: + +- `Finding paths to Linus`_ + +If you get a few decent trust paths, then it's a pretty good indication +that it is a valid key. You can add it to your keyring from the +keyserver now:: + + $ gpg --recv-key C94035C21B4F2AEB + +This process is not perfect, and you are obviously trusting the +administrators of the PGP Pathfinder service to not be malicious (in +fact, this goes against :ref:`devs_not_infra`). However, if you +do not carefully maintain your own web of trust, then it is a marked +improvement over blindly trusting keyservers. + +.. _`PGP pathfinder`: https://pgp.cs.uu.nl/ +.. _`Finding paths to Linus`: https://pgp.cs.uu.nl/paths/79BE3E4300411886/to/C94035C21B4F2AEB.html diff --git a/Documentation/process/submit-checklist.rst b/Documentation/process/submit-checklist.rst index a0d9d34bfb6d..367353c54949 100644 --- a/Documentation/process/submit-checklist.rst +++ b/Documentation/process/submit-checklist.rst @@ -37,7 +37,9 @@ and elsewhere regarding submitting Linux kernel patches. You should be able to justify all violations that remain in your patch. -6) Any new or modified ``CONFIG`` options don't muck up the config menu. +6) Any new or modified ``CONFIG`` options do not muck up the config menu and + default to off unless they meet the exception criteria documented in + ``Documentation/kbuild/kconfig-language.txt`` Menu attributes: default value. 7) All new ``Kconfig`` options have help text. diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt index c0c977445fb9..a129acf38537 100644 --- a/Documentation/rtc.txt +++ b/Documentation/rtc.txt @@ -136,82 +136,5 @@ a high functionality RTC is integrated into the SOC. That system might read the system clock from the discrete RTC, but use the integrated one for all other tasks, because of its greater functionality. -SYSFS interface ---------------- - -The sysfs interface under /sys/class/rtc/rtcN provides access to various -rtc attributes without requiring the use of ioctls. All dates and times -are in the RTC's timezone, rather than in system time. - -================ ============================================================== -date RTC-provided date -hctosys 1 if the RTC provided the system time at boot via the - CONFIG_RTC_HCTOSYS kernel option, 0 otherwise -max_user_freq The maximum interrupt rate an unprivileged user may request - from this RTC. -name The name of the RTC corresponding to this sysfs directory -since_epoch The number of seconds since the epoch according to the RTC -time RTC-provided time -wakealarm The time at which the clock will generate a system wakeup - event. This is a one shot wakeup event, so must be reset - after wake if a daily wakeup is required. Format is seconds - since the epoch by default, or if there's a leading +, seconds - in the future, or if there is a leading +=, seconds ahead of - the current alarm. -offset The amount which the rtc clock has been adjusted in firmware. - Visible only if the driver supports clock offset adjustment. - The unit is parts per billion, i.e. The number of clock ticks - which are added to or removed from the rtc's base clock per - billion ticks. A positive value makes a day pass more slowly, - longer, and a negative value makes a day pass more quickly. -*/nvmem The non volatile storage exported as a raw file, as described - in Documentation/nvmem/nvmem.txt -================ ============================================================== - -IOCTL interface ---------------- - -The ioctl() calls supported by /dev/rtc are also supported by the RTC class -framework. However, because the chips and systems are not standardized, -some PC/AT functionality might not be provided. And in the same way, some -newer features -- including those enabled by ACPI -- are exposed by the -RTC class framework, but can't be supported by the older driver. - - * RTC_RD_TIME, RTC_SET_TIME ... every RTC supports at least reading - time, returning the result as a Gregorian calendar date and 24 hour - wall clock time. To be most useful, this time may also be updated. - - * RTC_AIE_ON, RTC_AIE_OFF, RTC_ALM_SET, RTC_ALM_READ ... when the RTC - is connected to an IRQ line, it can often issue an alarm IRQ up to - 24 hours in the future. (Use RTC_WKALM_* by preference.) - - * RTC_WKALM_SET, RTC_WKALM_RD ... RTCs that can issue alarms beyond - the next 24 hours use a slightly more powerful API, which supports - setting the longer alarm time and enabling its IRQ using a single - request (using the same model as EFI firmware). - - * RTC_UIE_ON, RTC_UIE_OFF ... if the RTC offers IRQs, the RTC framework - will emulate this mechanism. - - * RTC_PIE_ON, RTC_PIE_OFF, RTC_IRQP_SET, RTC_IRQP_READ ... these icotls - are emulated via a kernel hrtimer. - -In many cases, the RTC alarm can be a system wake event, used to force -Linux out of a low power sleep state (or hibernation) back to a fully -operational state. For example, a system could enter a deep power saving -state until it's time to execute some scheduled tasks. - -Note that many of these ioctls are handled by the common rtc-dev interface. -Some common examples: - - * RTC_RD_TIME, RTC_SET_TIME: the read_time/set_time functions will be - called with appropriate values. - - * RTC_ALM_SET, RTC_ALM_READ, RTC_WKALM_SET, RTC_WKALM_RD: gets or sets - the alarm rtc_timer. May call the set_alarm driver function. - - * RTC_IRQP_SET, RTC_IRQP_READ: These are emulated by the generic code. - - * RTC_PIE_ON, RTC_PIE_OFF: These are also emulated by the generic code. - -If all else fails, check out the tools/testing/selftests/timers/rtctest.c test! +Check out tools/testing/selftests/timers/rtctest.c for an example usage of the +ioctl interface. diff --git a/Documentation/security/credentials.rst b/Documentation/security/credentials.rst index 66a2e24939d8..5bb7125faeee 100644 --- a/Documentation/security/credentials.rst +++ b/Documentation/security/credentials.rst @@ -451,6 +451,13 @@ checks and hooks done. Both the current and the proposed sets of credentials are available for this purpose as current_cred() will return the current set still at this point. +When replacing the group list, the new list must be sorted before it +is added to the credential, as a binary search is used to test for +membership. In practice, this means :c:func:`groups_sort` should be +called before :c:func:`set_groups` or :c:func:`set_current_groups`. +:c:func:`groups_sort)` must not be called on a ``struct group_list`` which +is shared as it may permute elements as part of the sorting process +even if the array is already sorted. When the credential set is ready, it should be committed to the current process by calling:: diff --git a/Documentation/security/self-protection.rst b/Documentation/security/self-protection.rst index 60c8bd8b77bf..0f53826c78b9 100644 --- a/Documentation/security/self-protection.rst +++ b/Documentation/security/self-protection.rst @@ -270,6 +270,21 @@ attacks, it is important to defend against exposure of both kernel memory addresses and kernel memory contents (since they may contain kernel addresses or other sensitive things like canary values). +Kernel addresses +---------------- + +Printing kernel addresses to userspace leaks sensitive information about +the kernel memory layout. Care should be exercised when using any printk +specifier that prints the raw address, currently %px, %p[ad], (and %p[sSb] +in certain circumstances [*]). Any file written to using one of these +specifiers should be readable only by privileged processes. + +Kernels 4.14 and older printed the raw address using %p. As of 4.15-rc1 +addresses printed with the specifier %p are hashed before printing. + +[*] If KALLSYMS is enabled and symbol lookup fails, the raw address is +printed. If KALLSYMS is not enabled the raw address is printed. + Unique identifiers ------------------ diff --git a/Documentation/sparc/oradax/dax-hv-api.txt b/Documentation/sparc/oradax/dax-hv-api.txt new file mode 100644 index 000000000000..73e8d506cf64 --- /dev/null +++ b/Documentation/sparc/oradax/dax-hv-api.txt @@ -0,0 +1,1433 @@ +Excerpt from UltraSPARC Virtual Machine Specification +Compiled from version 3.0.20+15 +Publication date 2017-09-25 08:21 +Copyright © 2008, 2015 Oracle and/or its affiliates. All rights reserved. +Extracted via "pdftotext -f 547 -l 572 -layout sun4v_20170925.pdf" +Authors: + Charles Kunzman + Sam Glidden + Mark Cianchetti + + +Chapter 36. Coprocessor services + The following APIs provide access via the Hypervisor to hardware assisted data processing functionality. + These APIs may only be provided by certain platforms, and may not be available to all virtual machines + even on supported platforms. Restrictions on the use of these APIs may be imposed in order to support + live-migration and other system management activities. + +36.1. Data Analytics Accelerator + The Data Analytics Accelerator (DAX) functionality is a collection of hardware coprocessors that provide + high speed processoring of database-centric operations. The coprocessors may support one or more of + the following data query operations: search, extraction, compression, decompression, and translation. The + functionality offered may vary by virtual machine implementation. + + The DAX is a virtual device to sun4v guests, with supported data operations indicated by the virtual device + compatibilty property. Functionality is accessed through the submission of Command Control Blocks + (CCBs) via the ccb_submit API function. The operations are processed asynchronously, with the status + of the submitted operations reported through a Completion Area linked to each CCB. Each CCB has a + separate Completion Area and, unless execution order is specifically restricted through the use of serial- + conditional flags, the execution order of submitted CCBs is arbitrary. Likewise, the time to completion + for a given CCB is never guaranteed. + + Guest software may implement a software timeout on CCB operations, and if the timeout is exceeded, the + operation may be cancelled or killed via the ccb_kill API function. It is recommended for guest software + to implement a software timeout to account for certain RAS errors which may result in lost CCBs. It is + recommended such implementation use the ccb_info API function to check the status of a CCB prior to + killing it in order to determine if the CCB is still in queue, or may have been lost due to a RAS error. + + There is no fixed limit on the number of outstanding CCBs guest software may have queued in the virtual + machine, however, internal resource limitations within the virtual machine can cause CCB submissions + to be temporarily rejected with EWOULDBLOCK. In such cases, guests should continue to attempt + submissions until they succeed; waiting for an outstanding CCB to complete is not necessary, and would + not be a guarantee that a future submission would succeed. + + The availablility of DAX coprocessor command service is indicated by the presence of the DAX virtual + device node in the guest MD (Section 8.24.17, “Database Analytics Accelerators (DAX) virtual-device + node”). + +36.1.1. DAX Compatibility Property + The query functionality may vary based on the compatibility property of the virtual device: + +36.1.1.1. "ORCL,sun4v-dax" Device Compatibility + Available CCB commands: + + • No-op/Sync + + • Extract + + • Scan Value + + • Inverted Scan Value + + • Scan Range + + + 509 + Coprocessor services + + + • Inverted Scan Range + + • Translate + + • Inverted Translate + + • Select + + See Section 36.2.1, “Query CCB Command Formats” for the corresponding CCB input and output formats. + + Only version 0 CCBs are available. + +36.1.1.2. "ORCL,sun4v-dax-fc" Device Compatibility + "ORCL,sun4v-dax-fc" is compatible with the "ORCL,sun4v-dax" interface, and includes additional CCB + bit fields and controls. + +36.1.1.3. "ORCL,sun4v-dax2" Device Compatibility + Available CCB commands: + + • No-op/Sync + + • Extract + + • Scan Value + + • Inverted Scan Value + + • Scan Range + + • Inverted Scan Range + + • Translate + + • Inverted Translate + + • Select + + See Section 36.2.1, “Query CCB Command Formats” for the corresponding CCB input and output formats. + + Version 0 and 1 CCBs are available. Only version 0 CCBs may use Huffman encoded data, whereas only + version 1 CCBs may use OZIP. + +36.1.2. DAX Virtual Device Interrupts + The DAX virtual device has multiple interrupts associated with it which may be used by the guest if + desired. The number of device interrupts available to the guest is indicated in the virtual device node of the + guest MD (Section 8.24.17, “Database Analytics Accelerators (DAX) virtual-device node”). If the device + node indicates N interrupts available, the guest may use any value from 0 to N - 1 (inclusive) in a CCB + interrupt number field. Using values outside this range will result in the CCB being rejected for an invalid + field value. + + The interrupts may be bound and managed using the standard sun4v device interrupts API (Chapter 16, + Device interrupt services). Sysino interrupts are not available for DAX devices. + +36.2. Coprocessor Control Block (CCB) + CCBs are either 64 or 128 bytes long, depending on the operation type. The exact contents of the CCB + are command specific, but all CCBs contain at least one memory buffer address. All memory locations + + + 510 + Coprocessor services + + +referenced by a CCB must be pinned in memory until the CCB either completes execution or is killed +via the ccb_kill API call. Changes in virtual address mappings occurring after CCB submission are not +guaranteed to be visible, and as such all virtual address updates need to be synchronized with CCB +execution. + +All CCBs begin with a common 32-bit header. + +Table 36.1. CCB Header Format +Bits Field Description +[31:28] CCB version. For API version 2.0: set to 1 if CCB uses OZIP encoding; set to 0 if the CCB + uses Huffman encoding; otherwise either 0 or 1. For API version 1.0: always set to 0. +[27] When API version 2.0 is negotiated, this is the Pipeline Flag [512]. It is reserved in + API version 1.0 +[26] Long CCB flag [512] +[25] Conditional synchronization flag [512] +[24] Serial synchronization flag +[23:16] CCB operation code: + 0x00 No Operation (No-op) or Sync + 0x01 Extract + 0x02 Scan Value + 0x12 Inverted Scan Value + 0x03 Scan Range + 0x13 Inverted Scan Range + 0x04 Translate + 0x14 Inverted Translate + 0x05 Select +[15:13] Reserved +[12:11] Table address type + 0b'00 No address + 0b'01 Alternate context virtual address + 0b'10 Real address + 0b'11 Primary context virtual address +[10:8] Output/Destination address type + 0b'000 No address + 0b'001 Alternate context virtual address + 0b'010 Real address + 0b'011 Primary context virtual address + 0b'100 Reserved + 0b'101 Reserved + 0b'110 Reserved + 0b'111 Reserved +[7:5] Secondary source address type + + + 511 + Coprocessor services + + +Bits Field Description + 0b'000 No address + 0b'001 Alternate context virtual address + 0b'010 Real address + 0b'011 Primary context virtual address + 0b'100 Reserved + 0b'101 Reserved + 0b'110 Reserved + 0b'111 Reserved +[4:2] Primary source address type + 0b'000 No address + 0b'001 Alternate context virtual address + 0b'010 Real address + 0b'011 Primary context virtual address + 0b'100 Reserved + 0b'101 Reserved + 0b'110 Reserved + 0b'111 Reserved +[1:0] Completion area address type + 0b'00 No address + 0b'01 Alternate context virtual address + 0b'10 Real address + 0b'11 Primary context virtual address + +The Long CCB flag indicates whether the submitted CCB is 64 or 128 bytes long; value is 0 for 64 bytes +and 1 for 128 bytes. + +The Serial and Conditional flags allow simple relative ordering between CCBs. Any CCB with the Serial +flag set will execute sequentially relative to any previous CCB that is also marked as Serial in the same +CCB submission. CCBs without the Serial flag set execute independently, even if they are between CCBs +with the Serial flag set. CCBs marked solely with the Serial flag will execute upon the completion of the +previous Serial CCB, regardless of the completion status of that CCB. The Conditional flag allows CCBs +to conditionally execute based on the successful execution of the closest CCB marked with the Serial flag. +A CCB may only be conditional on exactly one CCB, however, a CCB may be marked both Conditional +and Serial to allow execution chaining. The flags do NOT allow fan-out chaining, where multiple CCBs +execute in parallel based on the completion of another CCB. + +The Pipeline flag is an optimization that directs the output of one CCB (the "source" CCB) directly to +the input of the next CCB (the "target" CCB). The target CCB thus does not need to read the input from +memory. The Pipeline flag is advisory and may be dropped. + +Both the Pipeline and Serial bits must be set in the source CCB. The Conditional bit must be set in the +target CCB. Exactly one CCB must be made conditional on the source CCB; either 0 or 2 target CCBs +is invalid. However, Pipelines can be extended beyond two CCBs: the sequence would start with a CCB +with both the Pipeline and Serial bits set, proceed through CCBs with the Pipeline, Serial, and Conditional +bits set, and terminate at a CCB that has the Conditional bit set, but not the Pipeline bit. + + + 512 + Coprocessor services + + + The input of the target CCB must start within 64 bytes of the output of the source CCB or the pipeline flag + will be ignored. All CCBs in a pipeline must be submitted in the same call to ccb_submit. + + The various address type fields indicate how the various address values used in the CCB should be + interpreted by the virtual machine. Not all of the types specified are used by every CCB format. Types + which are not applicable to the given CCB command should be indicated as type 0 (No address). Virtual + addresses used in the CCB must have translation entries present in either the TLB or a configured TSB + for the submitting virtual processor. Virtual addresses which cannot be translated by the virtual machine + will result in the CCB submission being rejected, with the causal virtual address indicated. The CCB + may be resubmitted after inserting the translation, or the address may be translated by guest software and + resubmitted using the real address translation. + +36.2.1. Query CCB Command Formats +36.2.1.1. Supported Data Formats, Elements Sizes and Offsets + Data for query commands may be encoded in multiple possible formats. The data query commands use a + common set of values to indicate the encoding formats of the data being processed. Some encoding formats + require multiple data streams for processing, requiring the specification of both primary data formats (the + encoded data) and secondary data streams (meta-data for the encoded data). + +36.2.1.1.1. Primary Input Format + + The primary input format code is a 4-bit field when it is used. There are 10 primary input formats available. + The packed formats are not endian neutral. Code values not listed below are reserved. + + Code Format Description + 0x0 Fixed width byte packed Up to 16 bytes + 0x1 Fixed width bit packed Up to 15 bits (CCB version 0) or 23 bits (CCB version + 1); bits are read most significant bit to least significant bit + within a byte + 0x2 Variable width byte packed Data stream of lengths must be provided as a secondary + input + 0x4 Fixed width byte packed with run Up to 16 bytes; data stream of run lengths must be + length encoding provided as a secondary input + 0x5 Fixed width bit packed with run Up to 15 bits (CCB version 0) or 23 bits (CCB version + length encoding 1); bits are read most significant bit to least significant bit + within a byte; data stream of run lengths must be provided + as a secondary input + 0x8 Fixed width byte packed with Up to 16 bytes before the encoding; compressed stream + Huffman (CCB version 0) or bits are read most significant bit to least significant bit + OZIP (CCB version 1) encoding within a byte; pointer to the encoding table must be + provided + 0x9 Fixed width bit packed with Up to 15 bits (CCB version 0) or 23 bits (CCB version + Huffman (CCB version 0) or 1); compressed stream bits are read most significant bit to + OZIP (CCB version 1) encoding least significant bit within a byte; pointer to the encoding + table must be provided + 0xA Variable width byte packed with Up to 16 bytes before the encoding; compressed stream + Huffman (CCB version 0) or bits are read most significant bit to least significant bit + OZIP (CCB version 1) encoding within a byte; data stream of lengths must be provided as + a secondary input; pointer to the encoding table must be + provided + + + 513 + Coprocessor services + + + Code Format Description + 0xC Fixed width byte packed with Up to 16 bytes before the encoding; compressed stream + run length encoding, followed by bits are read most significant bit to least significant bit + Huffman (CCB version 0) or within a byte; data stream of run lengths must be provided + OZIP (CCB version 1) encoding as a secondary input; pointer to the encoding table must + be provided + 0xD Fixed width bit packed with Up to 15 bits (CCB version 0) or 23 bits(CCB version 1) + run length encoding, followed by before the encoding; compressed stream bits are read most + Huffman (CCB version 0) or significant bit to least significant bit within a byte; data + OZIP (CCB version 1) encoding stream of run lengths must be provided as a secondary + input; pointer to the encoding table must be provided + + If OZIP encoding is used, there must be no reserved bytes in the table. + +36.2.1.1.2. Primary Input Element Size + + For primary input data streams with fixed size elements, the element size must be indicated in the CCB + command. The size is encoded as the number of bits or bytes, minus one. The valid value range for this + field depends on the input format selected, as listed in the table above. + +36.2.1.1.3. Secondary Input Format + + For primary input data streams which require a secondary input stream, the secondary input stream is + always encoded in a fixed width, bit-packed format. The bits are read from most significant bit to least + significant bit within a byte. There are two encoding options for the secondary input stream data elements, + depending on whether the value of 0 is needed: + + Secondary Input Description + Format Code + 0 Element is stored as value minus 1 (0 evalutes to 1, 1 evalutes + to 2, etc) + 1 Element is stored as value + +36.2.1.1.4. Secondary Input Element Size + + Secondary input element size is encoded as a two bit field: + + Secondary Input Size Description + Code + 0x0 1 bit + 0x1 2 bits + 0x2 4 bits + 0x3 8 bits + +36.2.1.1.5. Input Element Offsets + + Bit-wise input data streams may have any alignment within the base addressed byte. The offset, specified + from most significant bit to least significant bit, is provided as a fixed 3 bit field for each input type. A + value of 0 indicates that the first input element begins at the most significant bit in the first byte, and a + value of 7 indicates it begins with the least significant bit. + + This field should be zero for any byte-wise primary input data streams. + + + 514 + Coprocessor services + + +36.2.1.1.6. Output Format + + Query commands support multiple sizes and encodings for output data streams. There are four possible + output encodings, and up to four supported element sizes per encoding. Not all output encodings are + supported for every command. The format is indicated by a 4-bit field in the CCB: + + Output Format Code Description + 0x0 Byte aligned, 1 byte elements + 0x1 Byte aligned, 2 byte elements + 0x2 Byte aligned, 4 byte elements + 0x3 Byte aligned, 8 byte elements + 0x4 16 byte aligned, 16 byte elements + 0x5 Reserved + 0x6 Reserved + 0x7 Reserved + 0x8 Packed vector of single bit elements + 0x9 Reserved + 0xA Reserved + 0xB Reserved + 0xC Reserved + 0xD 2 byte elements where each element is the index value of a bit, + from an bit vector, which was 1. + 0xE 4 byte elements where each element is the index value of a bit, + from an bit vector, which was 1. + 0xF Reserved + +36.2.1.1.7. Application Data Integrity (ADI) + + On platforms which support ADI, the ADI version number may be specified for each separate memory + access type used in the CCB command. ADI checking only occurs when reading data. When writing data, + the specified ADI version number overwrites any existing ADI value in memory. + + An ADI version value of 0 or 0xF indicates the ADI checking is disabled for that data access, even if it is + enabled in memory. By setting the appropriate flag in CCB_SUBMIT (Section 36.3.1, “ccb_submit”) it is + also an option to disable ADI checking for all inputs accessed via virtual address for all CCBs submitted + during that hypercall invocation. + + The ADI value is only guaranteed to be checked on the first 64 bytes of each data access. Mismatches on + subsequent data chunks may not be detected, so guest software should be careful to use page size checking + to protect against buffer overruns. + +36.2.1.1.8. Page size checking + + All data accesses used in CCB commands must be bounded within a single memory page. When addresses + are provided using a virtual address, the page size for checking is extracted from the TTE for that virtual + address. When using real addresses, the guest must supply the page size in the same field as the address + value. The page size must be one of the sizes supported by the underlying virtual machine. Using a value + that is not supported may result in the CCB submission being rejected or the generation of a CCB parsing + error in the completion area. + + + 515 + Coprocessor services + + +36.2.1.2. Extract command + + Converts an input vector in one format to an output vector in another format. All input format types are + supported. + + The only supported output format is a padded, byte-aligned output stream, using output codes 0x0 - 0x4. + When the specified output element size is larger than the extracted input element size, zeros are padded to + the extracted input element. First, if the decompressed input size is not a whole number of bytes, 0 bits are + padded to the most significant bit side till the next byte boundary. Next, if the output element size is larger + than the byte padded input element, bytes of value 0 are added based on the Padding Direction bit in the + CCB. If the output element size is smaller than the byte-padded input element size, the input element is + truncated by dropped from the least significant byte side until the selected output size is reached. + + The return value of the CCB completion area is invalid. The “number of elements processed” field in the + CCB completion area will be valid. + + The extract CCB is a 64-byte “short format” CCB. + + The extract CCB command format can be specified by the following packed C structure for a big-endian + machine: + + + struct extract_ccb { + uint32_t header; + uint32_t control; + uint64_t completion; + uint64_t primary_input; + uint64_t data_access_control; + uint64_t secondary_input; + uint64_t reserved; + uint64_t output; + uint64_t table; + }; + + + The exact field offsets, sizes, and composition are as follows: + + Offset Size Field Description + 0 4 CCB header (Table 36.1, “CCB Header Format”) + 4 4 Command control + Bits Field Description + [31:28] Primary Input Format (see Section 36.2.1.1.1, “Primary Input + Format”) + [27:23] Primary Input Element Size (see Section 36.2.1.1.2, “Primary + Input Element Size”) + [22:20] Primary Input Starting Offset (see Section 36.2.1.1.5, “Input + Element Offsets”) + [19] Secondary Input Format (see Section 36.2.1.1.3, “Secondary + Input Format”) + [18:16] Secondary Input Starting Offset (see Section 36.2.1.1.5, “Input + Element Offsets”) + + + 516 + Coprocessor services + + +Offset Size Field Description + Bits Field Description + [15:14] Secondary Input Element Size (see Section 36.2.1.1.4, + “Secondary Input Element Size” + [13:10] Output Format (see Section 36.2.1.1.6, “Output Format”) + [9] Padding Direction selector: A value of 1 causes padding bytes + to be added to the left side of output elements. A value of 0 + causes padding bytes to be added to the right side of output + elements. + [8:0] Reserved +8 8 Completion + Bits Field Description + [63:60] ADI version (see Section 36.2.1.1.7, “Application Data + Integrity (ADI)”) + [59] If set to 1, a virtual device interrupt will be generated using + the device interrupt number specified in the lower bits of this + completion word. If 0, the lower bits of this completion word + are ignored. + [58:6] Completion area address bits [58:6]. Address type is + determined by CCB header. + [5:0] Virtual device interrupt number for completion interrupt, if + enabled. +16 8 Primary Input + Bits Field Description + [63:60] ADI version (see Section 36.2.1.1.7, “Application Data + Integrity (ADI)”) + [59:56] If using real address, these bits should be filled in with the + page size code for the page boundary checking the guest wants + the virtual machine to use when accessing this data stream + (checking is only guaranteed to be performed when using API + version 1.1 and later). If using a virtual address, this field will + be used as as primary input address bits [59:56]. + [55:0] Primary input address bits [55:0]. Address type is determined + by CCB header. +24 8 Data Access Control + Bits Field Description + [63:62] Flow Control + Value Description + 0b'00 Disable flow control + 0b'01 Enable flow control (only valid with "ORCL,sun4v- + dax-fc" compatible virtual device variants) + 0b'10 Reserved + 0b'11 Reserved + [61:60] Reserved (API 1.0) + + + 517 + Coprocessor services + + +Offset Size Field Description + Bits Field Description + Pipeline target (API 2.0) + Value Description + 0b'00 Connect to primary input + 0b'01 Connect to secondary input + 0b'10 Reserved + 0b'11 Reserved + [59:40] Output buffer size given in units of 64 bytes, minus 1. Value of + 0 means 64 bytes, value of 1 means 128 bytes, etc. Buffer size is + only enforced if flow control is enabled in Flow Control field. + [39:32] Reserved + [31:30] Output Data Cache Allocation + Value Description + 0b'00 Do not allocate cache lines for output data stream. + 0b'01 Force cache lines for output data stream to be + allocated in the cache that is local to the submitting + virtual cpu. + 0b'10 Allocate cache lines for output data stream, but allow + existing cache lines associated with the data to remain + in their current cache instance. Any memory not + already in cache will be allocated in the cache local + to the submitting virtual cpu. + 0b'11 Reserved + [29:26] Reserved + [25:24] Primary Input Length Format + Value Description + 0b'00 Number of primary symbols + 0b'01 Number of primary bytes + 0b'10 Number of primary bits + 0b'11 Reserved + [23:0] Primary Input Length + Format Field Value + # of primary symbols Number of input elements to process, + minus 1. Command execution stops + once count is reached. + # of primary bytes Number of input bytes to process, + minus 1. Command execution stops + once count is reached. The count is + done before any decompression or + decoding. + # of primary bits Number of input bits to process, + minus 1. Command execution stops + + + + 518 + Coprocessor services + + + Offset Size Field Description + Bits Field Description + Format Field Value + once count is reached. The count is + done before any decompression or + decoding, and does not include any + bits skipped by the Primary Input + Offset field value of the command + control word. + 32 8 Secondary Input, if used by Primary Input Format. Same fields as Primary + Input. + 40 8 Reserved + 48 8 Output (same fields as Primary Input) + 56 8 Symbol Table (if used by Primary Input) + Bits Field Description + [63:60] ADI version (see Section 36.2.1.1.7, “Application Data + Integrity (ADI)”) + [59:56] If using real address, these bits should be filled in with the + page size code for the page boundary checking the guest wants + the virtual machine to use when accessing this data stream + (checking is only guaranteed to be performed when using API + version 1.1 and later). If using a virtual address, this field will + be used as as symbol table address bits [59:56]. + [55:4] Symbol table address bits [55:4]. Address type is determined + by CCB header. + [3:0] Symbol table version + Value Description + 0 Huffman encoding. Must use 64 byte aligned table + address. (Only available when using version 0 CCBs) + 1 OZIP encoding. Must use 16 byte aligned table + address. (Only available when using version 1 CCBs) + + +36.2.1.3. Scan commands + + The scan commands search a stream of input data elements for values which match the selection criteria. + All the input format types are supported. There are multiple formats for the scan commands, allowing the + scan to search for exact matches to one value, exact matches to either of two values, or any value within + a specified range. The specific type of scan is indicated by the command code in the CCB header. For the + scan range commands, the boundary conditions can be specified as greater-than-or-equal-to a value, less- + than-or-equal-to a value, or both by using two boundary values. + + There are two supported formats for the output stream: the bit vector and index array formats (codes 0x8, + 0xD, and 0xE). For the standard scan command using the bit vector output, for each input element there + exists one bit in the vector that is set if the input element matched the scan criteria, or clear if not. The + inverted scan command inverts the polarity of the bits in the output. The most significant bit of the first + byte of the output stream corresponds to the first element in the input stream. The standard index array + output format contains one array entry for each input element that matched the scan criteria. Each array + + + + 519 + Coprocessor services + + +entry is the index of an input element that matched the scan criteria. An inverted scan command produces +a similar array, but of all the input elements which did NOT match the scan criteria. + +The return value of the CCB completion area contains the number of input elements found which match +the scan criteria (or number that did not match for the inverted scans). The “number of elements processed” +field in the CCB completion area will be valid, indicating the number of input elements processed. + +These commands are 128-byte “long format” CCBs. + +The scan CCB command format can be specified by the following packed C structure for a big-endian +machine: + + + struct scan_ccb { + uint32_t header; + uint32_t control; + uint64_t completion; + uint64_t primary_input; + uint64_t data_access_control; + uint64_t secondary_input; + uint64_t match_criteria0; + uint64_t output; + uint64_t table; + uint64_t match_criteria1; + uint64_t match_criteria2; + uint64_t match_criteria3; + uint64_t reserved[5]; + }; + + +The exact field offsets, sizes, and composition are as follows: + +Offset Size Field Description +0 4 CCB header (Table 36.1, “CCB Header Format”) +4 4 Command control + Bits Field Description + [31:28] Primary Input Format (see Section 36.2.1.1.1, “Primary Input + Format”) + [27:23] Primary Input Element Size (see Section 36.2.1.1.2, “Primary + Input Element Size”) + [22:20] Primary Input Starting Offset (see Section 36.2.1.1.5, “Input + Element Offsets”) + [19] Secondary Input Format (see Section 36.2.1.1.3, “Secondary + Input Format”) + [18:16] Secondary Input Starting Offset (see Section 36.2.1.1.5, “Input + Element Offsets”) + [15:14] Secondary Input Element Size (see Section 36.2.1.1.4, + “Secondary Input Element Size” + [13:10] Output Format (see Section 36.2.1.1.6, “Output Format”) + [9:5] Operand size for first scan criteria value. In a scan value + operation, this is one of two potential extact match values. + In a scan range operation, this is the size of the upper range + + + 520 + Coprocessor services + + +Offset Size Field Description + Bits Field Description + boundary. The value of this field is the number of bytes in the + operand, minus 1. Values 0xF-0x1E are reserved. A value of + 0x1F indicates this operand is not in use for this scan operation. + [4:0] Operand size for second scan criteria value. In a scan value + operation, this is one of two potential extact match values. + In a scan range operation, this is the size of the lower range + boundary. The value of this field is the number of bytes in the + operand, minus 1. Values 0xF-0x1E are reserved. A value of + 0x1F indicates this operand is not in use for this scan operation. +8 8 Completion (same fields as Section 36.2.1.2, “Extract command”) +16 8 Primary Input (same fields as Section 36.2.1.2, “Extract command”) +24 8 Data Access Control (same fields as Section 36.2.1.2, “Extract command”) +32 8 Secondary Input, if used by Primary Input Format. Same fields as Primary + Input. +40 4 Most significant 4 bytes of first scan criteria operand. If first operand is less + than 4 bytes, the value is left-aligned to the lowest address bytes. +44 4 Most significant 4 bytes of second scan criteria operand. If second operand + is less than 4 bytes, the value is left-aligned to the lowest address bytes. +48 8 Output (same fields as Primary Input) +56 8 Symbol Table (if used by Primary Input). Same fields as Section 36.2.1.2, + “Extract command” +64 4 Next 4 most significant bytes of first scan criteria operand occuring after the + bytes specified at offset 40, if needed by the operand size. If first operand + is less than 8 bytes, the valid bytes are left-aligned to the lowest address. +68 4 Next 4 most significant bytes of second scan criteria operand occuring after + the bytes specified at offset 44, if needed by the operand size. If second + operand is less than 8 bytes, the valid bytes are left-aligned to the lowest + address. +72 4 Next 4 most significant bytes of first scan criteria operand occuring after the + bytes specified at offset 64, if needed by the operand size. If first operand + is less than 12 bytes, the valid bytes are left-aligned to the lowest address. +76 4 Next 4 most significant bytes of second scan criteria operand occuring after + the bytes specified at offset 68, if needed by the operand size. If second + operand is less than 12 bytes, the valid bytes are left-aligned to the lowest + address. +80 4 Next 4 most significant bytes of first scan criteria operand occuring after the + bytes specified at offset 72, if needed by the operand size. If first operand + is less than 16 bytes, the valid bytes are left-aligned to the lowest address. +84 4 Next 4 most significant bytes of second scan criteria operand occuring after + the bytes specified at offset 76, if needed by the operand size. If second + operand is less than 16 bytes, the valid bytes are left-aligned to the lowest + address. + + + + + 521 + Coprocessor services + + +36.2.1.4. Translate commands + + The translate commands takes an input array of indicies, and a table of single bit values indexed by those + indicies, and outputs a bit vector or index array created by reading the tables bit value at each index in + the input array. The output should therefore contain exactly one bit per index in the input data stream, + when outputing as a bit vector. When outputing as an index array, the number of elements depends on the + values read in the bit table, but will always be less than, or equal to, the number of input elements. Only + a restricted subset of the possible input format types are supported. No variable width or Huffman/OZIP + encoded input streams are allowed. The primary input data element size must be 3 bytes or less. + + The maximum table index size allowed is 15 bits, however, larger input elements may be used to provide + additional processing of the output values. If 2 or 3 byte values are used, the least significant 15 bits are + used as an index into the bit table. The most significant 9 bits (when using 3-byte input elements) or single + bit (when using 2-byte input elements) are compared against a fixed 9-bit test value provided in the CCB. + If the values match, the value from the bit table is used as the output element value. If the values do not + match, the output data element value is forced to 0. + + In the inverted translate operation, the bit value read from bit table is inverted prior to its use. The additional + additional processing based on any additional non-index bits remains unchanged, and still forces the output + element value to 0 on a mismatch. The specific type of translate command is indicated by the command + code in the CCB header. + + There are two supported formats for the output stream: the bit vector and index array formats (codes 0x8, + 0xD, and 0xE). The index array format is an array of indicies of bits which would have been set if the + output format was a bit array. + + The return value of the CCB completion area contains the number of bits set in the output bit vector, + or number of elements in the output index array. The “number of elements processed” field in the CCB + completion area will be valid, indicating the number of input elements processed. + + These commands are 64-byte “short format” CCBs. + + The translate CCB command format can be specified by the following packed C structure for a big-endian + machine: + + + struct translate_ccb { + uint32_t header; + uint32_t control; + uint64_t completion; + uint64_t primary_input; + uint64_t data_access_control; + uint64_t secondary_input; + uint64_t reserved; + uint64_t output; + uint64_t table; + }; + + + The exact field offsets, sizes, and composition are as follows: + + + Offset Size Field Description + 0 4 CCB header (Table 36.1, “CCB Header Format”) + + + 522 + Coprocessor services + + +Offset Size Field Description +4 4 Command control + Bits Field Description + [31:28] Primary Input Format (see Section 36.2.1.1.1, “Primary Input + Format”) + [27:23] Primary Input Element Size (see Section 36.2.1.1.2, “Primary + Input Element Size”) + [22:20] Primary Input Starting Offset (see Section 36.2.1.1.5, “Input + Element Offsets”) + [19] Secondary Input Format (see Section 36.2.1.1.3, “Secondary + Input Format”) + [18:16] Secondary Input Starting Offset (see Section 36.2.1.1.5, “Input + Element Offsets”) + [15:14] Secondary Input Element Size (see Section 36.2.1.1.4, + “Secondary Input Element Size” + [13:10] Output Format (see Section 36.2.1.1.6, “Output Format”) + [9] Reserved + [8:0] Test value used for comparison against the most significant bits + in the input values, when using 2 or 3 byte input elements. +8 8 Completion (same fields as Section 36.2.1.2, “Extract command” +16 8 Primary Input (same fields as Section 36.2.1.2, “Extract command” +24 8 Data Access Control (same fields as Section 36.2.1.2, “Extract command”, + except Primary Input Length Format may not use the 0x0 value) +32 8 Secondary Input, if used by Primary Input Format. Same fields as Primary + Input. +40 8 Reserved +48 8 Output (same fields as Primary Input) +56 8 Bit Table + Bits Field Description + [63:60] ADI version (see Section 36.2.1.1.7, “Application Data + Integrity (ADI)”) + [59:56] If using real address, these bits should be filled in with the + page size code for the page boundary checking the guest wants + the virtual machine to use when accessing this data stream + (checking is only guaranteed to be performed when using API + version 1.1 and later). If using a virtual address, this field will + be used as as bit table address bits [59:56] + [55:4] Bit table address bits [55:4]. Address type is determined by + CCB header. Address must be 64-byte aligned (CCB version + 0) or 16-byte aligned (CCB version 1). + [3:0] Bit table version + Value Description + 0 4KB table size + 1 8KB table size + + + + 523 + Coprocessor services + + +36.2.1.5. Select command + The select command filters the primary input data stream by using a secondary input bit vector to determine + which input elements to include in the output. For each bit set at a given index N within the bit vector, + the Nth input element is included in the output. If the bit is not set, the element is not included. Only a + restricted subset of the possible input format types are supported. No variable width or run length encoded + input streams are allowed, since the secondary input stream is used for the filtering bit vector. + + The only supported output format is a padded, byte-aligned output stream. The stream follows the same + rules and restrictions as padded output stream described in Section 36.2.1.2, “Extract command”. + + The return value of the CCB completion area contains the number of bits set in the input bit vector. The + "number of elements processed" field in the CCB completion area will be valid, indicating the number + of input elements processed. + + The select CCB is a 64-byte “short format” CCB. + + The select CCB command format can be specified by the following packed C structure for a big-endian + machine: + + + struct select_ccb { + uint32_t header; + uint32_t control; + uint64_t completion; + uint64_t primary_input; + uint64_t data_access_control; + uint64_t secondary_input; + uint64_t reserved; + uint64_t output; + uint64_t table; + }; + + + The exact field offsets, sizes, and composition are as follows: + + Offset Size Field Description + 0 4 CCB header (Table 36.1, “CCB Header Format”) + 4 4 Command control + Bits Field Description + [31:28] Primary Input Format (see Section 36.2.1.1.1, “Primary Input + Format”) + [27:23] Primary Input Element Size (see Section 36.2.1.1.2, “Primary + Input Element Size”) + [22:20] Primary Input Starting Offset (see Section 36.2.1.1.5, “Input + Element Offsets”) + [19] Secondary Input Format (see Section 36.2.1.1.3, “Secondary + Input Format”) + [18:16] Secondary Input Starting Offset (see Section 36.2.1.1.5, “Input + Element Offsets”) + [15:14] Secondary Input Element Size (see Section 36.2.1.1.4, + “Secondary Input Element Size” + + + 524 + Coprocessor services + + + Offset Size Field Description + Bits Field Description + [13:10] Output Format (see Section 36.2.1.1.6, “Output Format”) + [9] Padding Direction selector: A value of 1 causes padding bytes + to be added to the left side of output elements. A value of 0 + causes padding bytes to be added to the right side of output + elements. + [8:0] Reserved + 8 8 Completion (same fields as Section 36.2.1.2, “Extract command” + 16 8 Primary Input (same fields as Section 36.2.1.2, “Extract command” + 24 8 Data Access Control (same fields as Section 36.2.1.2, “Extract command”) + 32 8 Secondary Bit Vector Input. Same fields as Primary Input. + 40 8 Reserved + 48 8 Output (same fields as Primary Input) + 56 8 Symbol Table (if used by Primary Input). Same fields as Section 36.2.1.2, + “Extract command” + +36.2.1.6. No-op and Sync commands + The no-op (no operation) command is a CCB which has no processing effect. The CCB, when processed + by the virtual machine, simply updates the completion area with its execution status. The CCB may have + the serial-conditional flags set in order to restrict when it executes. + + The sync command is a variant of the no-op command which with restricted execution timing. A sync + command CCB will only execute when all previous commands submitted in the same request have + completed. This is stronger than the conditional flag sequencing, which is only dependent on a single + previous serial CCB. While the relative ordering is guaranteed, virtual machine implementations with + shared hardware resources may cause the sync command to wait for longer than the minimum required + time. + + The return value of the CCB completion area is invalid for these CCBs. The “number of elements + processed” field is also invalid for these CCBs. + + These commands are 64-byte “short format” CCBs. + + The no-op CCB command format can be specified by the following packed C structure for a big-endian + machine: + + + struct nop_ccb { + uint32_t header; + uint32_t control; + uint64_t completion; + uint64_t reserved[6]; + }; + + + The exact field offsets, sizes, and composition are as follows: + + Offset Size Field Description + 0 4 CCB header (Table 36.1, “CCB Header Format”) + + + 525 + Coprocessor services + + + Offset Size Field Description + 4 4 Command control + Bits Field Description + [31] If set, this CCB functions as a Sync command. If clear, this + CCB functions as a No-op command. + [30:0] Reserved + 8 8 Completion (same fields as Section 36.2.1.2, “Extract command” + 16 46 Reserved + +36.2.2. CCB Completion Area + All CCB commands use a common 128-byte Completion Area format, which can be specified by the + following packed C structure for a big-endian machine: + + + struct completion_area { + uint8_t status_flag; + uint8_t error_note; + uint8_t rsvd0[2]; + uint32_t error_values; + uint32_t output_size; + uint32_t rsvd1; + uint64_t run_time; + uint64_t run_stats; + uint32_t elements; + uint8_t rsvd2[20]; + uint64_t return_value; + uint64_t extra_return_value[8]; + }; + + + The Completion Area must be a 128-byte aligned memory location. The exact layout can be described + using byte offsets and sizes relative to the memory base: + + Offset Size Field Description + 0 1 CCB execution status + 0x0 Command not yet completed + 0x1 Command ran and succeeded + 0x2 Command ran and failed (partial results may be been + produced) + 0x3 Command ran and was killed (partial execution may + have occurred) + 0x4 Command was not run + 0x5-0xF Reserved + 1 1 Error reason code + 0x0 Reserved + 0x1 Buffer overflow + + + 526 + Coprocessor services + + +Offset Size Field Description + 0x2 CCB decoding error + 0x3 Page overflow + 0x4-0x6 Reserved + 0x7 Command was killed + 0x8 Command execution timeout + 0x9 ADI miscompare error + 0xA Data format error + 0xB-0xD Reserved + 0xE Unexpected hardware error (Do not retry) + 0xF Unexpected hardware error (Retry is ok) + 0x10-0x7F Reserved + 0x80 Partial Symbol Warning + 0x81-0xFF Reserved +2 2 Reserved +4 4 If a partial symbol warning was generated, this field contains the number + of remaining bits which were not decoded. +8 4 Number of bytes of output produced +12 4 Reserved +16 8 Runtime of command (unspecified time units) +24 8 Reserved +32 4 Number of elements processed +36 20 Reserved +56 8 Return value +64 64 Extended return value + +The CCB completion area should be treated as read-only by guest software. The CCB execution status +byte will be cleared by the Hypervisor to reflect the pending execution status when the CCB is submitted +successfully. All other fields are considered invalid upon CCB submission until the CCB execution status +byte becomes non-zero. + +CCBs which complete with status 0x2 or 0x3 may produce partial results and/or side effects due to partial +execution of the CCB command. Some valid data may be accessible depending on the fault type, however, +it is recommended that guest software treat the destination buffer as being in an unknown state. If a CCB +completes with a status byte of 0x2, the error reason code byte can be read to determine what corrective +action should be taken. + +A buffer overflow indicates that the results of the operation exceeded the size of the output buffer indicated +in the CCB. The operation can be retried by resubmitting the CCB with a larger output buffer. + +A CCB decoding error indicates that the CCB contained some invalid field values. It may be also be +triggered if the CCB output is directed at a non-existent secondary input and the pipelining hint is followed. + +A page overflow error indicates that the operation required accessing a memory location beyond the page +size associated with a given address. No data will have been read or written past the page boundary, but +partial results may have been written to the destination buffer. The CCB can be resubmitted with a larger +page size memory allocation to complete the operation. + + + 527 + Coprocessor services + + + In the case of pipelined CCBs, a page overflow error will be triggered if the output from the pipeline source + CCB ends before the input of the pipeline target CCB. Page boundaries are ignored when the pipeline + hint is followed. + + Command kill indicates that the CCB execution was halted or prevented by use of the ccb_kill API call. + + Command timeout indicates that the CCB execution began, but did not complete within a pre-determined + limit set by the virtual machine. The command may have produced some or no output. The CCB may be + resubmitted with no alterations. + + ADI miscompare indicates that the memory buffer version specified in the CCB did not match the value + in memory when accessed by the virtual machine. Guest software should not attempt to resubmit the CCB + without determining the cause of the version mismatch. + + A data format error indicates that the input data stream did not follow the specified data input formatting + selected in the CCB. + + Some CCBs which encounter hardware errors may be resubmitted without change. Persistent hardware + errors may result in multiple failures until RAS software can identify and isolate the faulty component. + + The output size field indicates the number of bytes of valid output in the destination buffer. This field is + not valid for all possible CCB commands. + + The runtime field indicates the execution time of the CCB command once it leaves the internal virtual + machine queue. The time units are fixed, but unspecified, allowing only relative timing comparisons + by guest software. The time units may also vary by hardware platform, and should not be construed to + represent any absolute time value. + + Some data query commands process data in units of elements. If applicable to the command, the number of + elements processed is indicated in the listed field. This field is not valid for all possible CCB commands. + + The return value and extended return value fields are output locations for commands which do not use + a destination output buffer, or have secondary return results. The field is not valid for all possible CCB + commands. + +36.3. Hypervisor API Functions +36.3.1. ccb_submit + trap# FAST_TRAP + function# CCB_SUBMIT + arg0 address + arg1 length + arg2 flags + arg3 reserved + ret0 status + ret1 length + ret2 status data + ret3 reserved + + Submit one or more coprocessor control blocks (CCBs) for evaluation and processing by the virtual + machine. The CCBs are passed in a linear array indicated by address. length indicates the size of + the array in bytes. + + + 528 + Coprocessor services + + +The address should be aligned to the size indicated by length, rounded up to the nearest power of +two. Virtual machines implementations may reject submissions which do not adhere to that alignment. +length must be a multiple of 64 bytes. If length is zero, the maximum supported array length will be +returned as length in ret1. In all other cases, the length value in ret1 will reflect the number of bytes +successfully consumed from the input CCB array. + + Implementation note + Virtual machines should never reject submissions based on the alignment of address if the + entire array is contained within a single memory page of the smallest page size supported by the + virtual machine. + +A guest may choose to submit addresses used in this API function, including the CCB array address, +as either a real or virtual addresses, with the type of each address indicated in flags. Virtual addresses +must be present in either the TLB or an active TSB to be processed. The translation context for virtual +addresses is determined by a combination of CCB contents and the flags argument. + +The flags argument is divided into multiple fields defined as follows: + + +Bits Field Description +[63:16] Reserved +[15] Disable ADI for VA reads (in API 2.0) + Reserved (in API 1.0) +[14] Virtual addresses within CCBs are translated in privileged context +[13:12] Alternate translation context for virtual addresses within CCBs: + 0b'00 CCBs requesting alternate context are rejected + 0b'01 Reserved + 0b'10 CCBs requesting alternate context use secondary context + 0b'11 CCBs requesting alternate context use nucleus context +[11:9] Reserved +[8] Queue info flag +[7] All-or-nothing flag +[6] If address is a virtual address, treat its translation context as privileged +[5:4] Address type of address: + 0b'00 Real address + 0b'01 Virtual address in primary context + 0b'10 Virtual address in secondary context + 0b'11 Virtual address in nucleus context +[3:2] Reserved +[1:0] CCB command type: + 0b'00 Reserved + 0b'01 Reserved + 0b'10 Query command + 0b'11 Reserved + + + + 529 + Coprocessor services + + + The CCB submission type and address type for the CCB array must be provided in the flags argument. + All other fields are optional values which change the default behavior of the CCB processing. + + When set to one, the "Disable ADI for VA reads" bit will turn off ADI checking when using a virtual + address to load data. ADI checking will still be done when loading real-addressed memory. This bit is only + available when using major version 2 of the coprocessor API group; at major version 1 it is reserved. For + more information about using ADI and DAX, see Section 36.2.1.1.7, “Application Data Integrity (ADI)”. + + By default, all virtual addresses are treated as user addresses. If the virtual address translations are + privileged, they must be marked as such in the appropriate flags field. The virtual addresses used within + the submitted CCBs must all be translated with the same privilege level. + + By default, all virtual addresses used within the submitted CCBs are translated using the primary context + active at the time of the submission. The address type field within a CCB allows each address to request + translation in an alternate address context. The address context used when the alternate address context is + requested is selected in the flags argument. + + The all-or-nothing flag specifies whether the virtual machine should allow partial submissions of the + input CCB array. When using CCBs with serial-conditional flags, it is strongly recommended to use + the all-or-nothing flag to avoid broken conditional chains. Using long CCB chains on a machine under + high coprocessor load may make this impractical, however, and require submitting without the flag. + When submitting serial-conditional CCBs without the all-or-nothing flag, guest software must manually + implement the serial-conditional behavior at any point where the chain was not submitted in a single API + call, and resubmission of the remaining CCBs should clear any conditional flag that might be set in the + first remaining CCB. Failure to do so will produce indeterminate CCB execution status and ordering. + + When the all-or-nothing flag is not specified, callers should check the value of length in ret1 to determine + how many CCBs from the array were successfully submitted. Any remaining CCBs can be resubmitted + without modifications. + + The value of length in ret1 is also valid when the API call returns an error, and callers should always + check its value to determine which CCBs in the array were already processed. This will additionally + identify which CCB encountered the processing error, and was not submitted successfully. + + If the queue info flag is used during submission, and at least one CCB was successfully submitted, the + length value in ret1 will be a multi-field value defined as follows: + Bits Field Description + [63:48] DAX unit instance identifier + [47:32] DAX queue instance identifier + [31:16] Reserved + [15:0] Number of CCB bytes successfully submitted + + The value of status data depends on the status value. See error status code descriptions for details. + The value is undefined for status values that do not specifically list a value for the status data. + + The API has a reserved input and output register which will be used in subsequent minor versions of this + API function. Guest software implementations should treat that register as voltile across the function call + in order to maintain forward compatibility. + +36.3.1.1. Errors + EOK One or more CCBs have been accepted and enqueued in the virtual machine + and no errors were been encountered during submission. Some submitted + CCBs may not have been enqueued due to internal virtual machine limitations, + and may be resubmitted without changes. + + + 530 + Coprocessor services + + +EWOULDBLOCK An internal resource conflict within the virtual machine has prevented it from + being able to complete the CCB submissions sufficiently quickly, requiring + it to abandon processing before it was complete. Some CCBs may have been + successfully enqueued prior to the block, and all remaining CCBs may be + resubmitted without changes. +EBADALIGN CCB array is not on a 64-byte boundary, or the array length is not a multiple + of 64 bytes. +ENORADDR A real address used either for the CCB array, or within one of the submitted + CCBs, is not valid for the guest. Some CCBs may have been enqueued prior + to the error being detected. +ENOMAP A virtual address used either for the CCB array, or within one of the submitted + CCBs, could not be translated by the virtual machine using either the TLB + or TSB contents. The submission may be retried after adding the required + mapping, or by converting the virtual address into a real address. Due to the + shared nature of address translation resources, there is no theoretical limit on + the number of times the translation may fail, and it is recommended all guests + implement some real address based backup. The virtual address which failed + translation is returned as status data in ret2. Some CCBs may have been + enqueued prior to the error being detected. +EINVAL The virtual machine detected an invalid CCB during submission, or invalid + input arguments, such as bad flag values. Note that not all invalid CCB values + will be detected during submission, and some may be reported as errors in the + completion area instead. Some CCBs may have been enqueued prior to the + error being detected. This error may be returned if the CCB version is invalid. +ETOOMANY The request was submitted with the all-or-nothing flag set, and the array size is + greater than the virtual machine can support in a single request. The maximum + supported size for the current virtual machine can be queried by submitting a + request with a zero length array, as described above. +ENOACCESS The guest does not have permission to submit CCBs, or an address used in a + CCBs lacks sufficient permissions to perform the required operation (no write + permission on the destination buffer address, for example). A virtual address + which fails permission checking is returned as status data in ret2. Some + CCBs may have been enqueued prior to the error being detected. +EUNAVAILABLE The requested CCB operation could not be performed at this time. The + restricted operation availability may apply only to the first unsuccessfully + submitted CCB, or may apply to a larger scope. The status should not be + interpreted as permanent, and the guest should attempt to submit CCBs in + the future which had previously been unable to be performed. The status + data provides additional information about scope of the retricted availability + as follows: + Value Description + 0 Processing for the exact CCB instance submitted was unavailable, + and it is recommended the guest emulate the operation. The + guest should continue to submit all other CCBs, and assume no + restrictions beyond this exact CCB instance. + 1 Processing is unavailable for all CCBs using the requested opcode, + and it is recommended the guest emulate the operation. The + guest should continue to submit all other CCBs that use different + opcodes, but can expect continued rejections of CCBs using the + same opcode in the near future. + + + 531 + Coprocessor services + + + Value Description + 2 Processing is unavailable for all CCBs using the requested CCB + version, and it is recommended the guest emulate the operation. + The guest should continue to submit all other CCBs that use + different CCB versions, but can expect continued rejections of + CCBs using the same CCB version in the near future. + 3 Processing is unavailable for all CCBs on the submitting vcpu, + and it is recommended the guest emulate the operation or resubmit + the CCB on a different vcpu. The guest should continue to submit + CCBs on all other vcpus but can expect continued rejections of all + CCBs on this vcpu in the near future. + 4 Processing is unavailable for all CCBs, and it is recommended + the guest emulate the operation. The guest should expect all CCB + submissions to be similarly rejected in the near future. + + +36.3.2. ccb_info + + trap# FAST_TRAP + function# CCB_INFO + arg0 address + ret0 status + ret1 CCB state + ret2 position + ret3 dax + ret4 queue + + Requests status information on a previously submitted CCB. The previously submitted CCB is identified + by the 64-byte aligned real address of the CCBs completion area. + + A CCB can be in one of 4 states: + + + State Value Description + COMPLETED 0 The CCB has been fetched and executed, and is no longer active in + the virtual machine. + ENQUEUED 1 The requested CCB is current in a queue awaiting execution. + INPROGRESS 2 The CCB has been fetched and is currently being executed. It may still + be possible to stop the execution using the ccb_kill hypercall. + NOTFOUND 3 The CCB could not be located in the virtual machine, and does not + appear to have been executed. This may occur if the CCB was lost + due to a hardware error, or the CCB may not have been successfully + submitted to the virtual machine in the first place. + + Implementation note + Some platforms may not be able to report CCBs that are currently being processed, and therefore + guest software should invoke the ccb_kill hypercall prior to assuming the request CCB will never + be executed because it was in the NOTFOUND state. + + + 532 + Coprocessor services + + + The position return value is only valid when the state is ENQUEUED. The value returned is the number + of other CCBs ahead of the requested CCB, to provide a relative estimate of when the CCB may execute. + + The dax return value is only valid when the state is ENQUEUED. The value returned is the DAX unit + instance indentifier for the DAX unit processing the queue where the requested CCB is located. The value + matches the value that would have been, or was, returned by ccb_submit using the queue info flag. + + The queue return value is only valid when the state is ENQUEUED. The value returned is the DAX + queue instance indentifier for the DAX unit processing the queue where the requested CCB is located. The + value matches the value that would have been, or was, returned by ccb_submit using the queue info flag. + +36.3.2.1. Errors + + EOK The request was proccessed and the CCB state is valid. + EBADALIGN address is not on a 64-byte aligned. + ENORADDR The real address provided for address is not valid. + EINVAL The CCB completion area contents are not valid. + EWOULDBLOCK Internal resource contraints prevented the CCB state from being queried at this + time. The guest should retry the request. + ENOACCESS The guest does not have permission to access the coprocessor virtual device + functionality. + +36.3.3. ccb_kill + + trap# FAST_TRAP + function# CCB_KILL + arg0 address + ret0 status + ret1 result + + Request to stop execution of a previously submitted CCB. The previously submitted CCB is identified by + the 64-byte aligned real address of the CCBs completion area. + + The kill attempt can produce one of several values in the result return value, reflecting the CCB state + and actions taken by the Hypervisor: + + Result Value Description + COMPLETED 0 The CCB has been fetched and executed, and is no longer active in + the virtual machine. It could not be killed and no action was taken. + DEQUEUED 1 The requested CCB was still enqueued when the kill request was + submitted, and has been removed from the queue. Since the CCB + never began execution, no memory modifications were produced by + it, and the completion area will never be updated. The same CCB may + be submitted again, if desired, with no modifications required. + KILLED 2 The CCB had been fetched and was being executed when the kill + request was submitted. The CCB execution was stopped, and the CCB + is no longer active in the virtual machine. The CCB completion area + will reflect the killed status, with the subsequent implications that + partial results may have been produced. Partial results may include full + + + 533 + Coprocessor services + + + Result Value Description + command execution if the command was stopped just prior to writing + to the completion area. + NOTFOUND 3 The CCB could not be located in the virtual machine, and does not + appear to have been executed. This may occur if the CCB was lost + due to a hardware error, or the CCB may not have been successfully + submitted to the virtual machine in the first place. CCBs in the state + are guaranteed to never execute in the future unless resubmitted. + +36.3.3.1. Interactions with Pipelined CCBs + + If the pipeline target CCB is killed but the pipeline source CCB was skipped, the completion area of the + target CCB may contain status (4,0) "Command was skipped" instead of (3,7) "Command was killed". + + If the pipeline source CCB is killed, the pipeline target CCB's completion status may read (1,0) "Success". + This does not mean the target CCB was processed; since the source CCB was killed, there was no + meaningful output on which the target CCB could operate. + +36.3.3.2. Errors + + EOK The request was proccessed and the result is valid. + EBADALIGN address is not on a 64-byte aligned. + ENORADDR The real address provided for address is not valid. + EINVAL The CCB completion area contents are not valid. + EWOULDBLOCK Internal resource contraints prevented the CCB from being killed at this time. + The guest should retry the request. + ENOACCESS The guest does not have permission to access the coprocessor virtual device + functionality. + +36.3.4. dax_info + trap# FAST_TRAP + function# DAX_INFO + ret0 status + ret1 Number of enabled DAX units + ret2 Number of disabled DAX units + + Returns the number of DAX units that are enabled for the calling guest to submit CCBs. The number of + DAX units that are disabled for the calling guest are also returned. A disabled DAX unit would have been + available for CCB submission to the calling guest had it not been offlined. + +36.3.4.1. Errors + + EOK The request was proccessed and the number of enabled/disabled DAX units + are valid. + + + + + 534 + diff --git a/Documentation/sparc/oradax/oracle-dax.txt b/Documentation/sparc/oradax/oracle-dax.txt new file mode 100644 index 000000000000..9d53ac93286f --- /dev/null +++ b/Documentation/sparc/oradax/oracle-dax.txt @@ -0,0 +1,429 @@ +Oracle Data Analytics Accelerator (DAX) +--------------------------------------- + +DAX is a coprocessor which resides on the SPARC M7 (DAX1) and M8 +(DAX2) processor chips, and has direct access to the CPU's L3 caches +as well as physical memory. It can perform several operations on data +streams with various input and output formats. A driver provides a +transport mechanism and has limited knowledge of the various opcodes +and data formats. A user space library provides high level services +and translates these into low level commands which are then passed +into the driver and subsequently the Hypervisor and the coprocessor. +The library is the recommended way for applications to use the +coprocessor, and the driver interface is not intended for general use. +This document describes the general flow of the driver, its +structures, and its programmatic interface. It also provides example +code sufficient to write user or kernel applications that use DAX +functionality. + +The user library is open source and available at: + https://oss.oracle.com/git/gitweb.cgi?p=libdax.git + +The Hypervisor interface to the coprocessor is described in detail in +the accompanying document, dax-hv-api.txt, which is a plain text +excerpt of the (Oracle internal) "UltraSPARC Virtual Machine +Specification" version 3.0.20+15, dated 2017-09-25. + + +High Level Overview +------------------- + +A coprocessor request is described by a Command Control Block +(CCB). The CCB contains an opcode and various parameters. The opcode +specifies what operation is to be done, and the parameters specify +options, flags, sizes, and addresses. The CCB (or an array of CCBs) +is passed to the Hypervisor, which handles queueing and scheduling of +requests to the available coprocessor execution units. A status code +returned indicates if the request was submitted successfully or if +there was an error. One of the addresses given in each CCB is a +pointer to a "completion area", which is a 128 byte memory block that +is written by the coprocessor to provide execution status. No +interrupt is generated upon completion; the completion area must be +polled by software to find out when a transaction has finished, but +the M7 and later processors provide a mechanism to pause the virtual +processor until the completion status has been updated by the +coprocessor. This is done using the monitored load and mwait +instructions, which are described in more detail later. The DAX +coprocessor was designed so that after a request is submitted, the +kernel is no longer involved in the processing of it. The polling is +done at the user level, which results in almost zero latency between +completion of a request and resumption of execution of the requesting +thread. + + +Addressing Memory +----------------- + +The kernel does not have access to physical memory in the Sun4v +architecture, as there is an additional level of memory virtualization +present. This intermediate level is called "real" memory, and the +kernel treats this as if it were physical. The Hypervisor handles the +translations between real memory and physical so that each logical +domain (LDOM) can have a partition of physical memory that is isolated +from that of other LDOMs. When the kernel sets up a virtual mapping, +it specifies a virtual address and the real address to which it should +be mapped. + +The DAX coprocessor can only operate on physical memory, so before a +request can be fed to the coprocessor, all the addresses in a CCB must +be converted into physical addresses. The kernel cannot do this since +it has no visibility into physical addresses. So a CCB may contain +either the virtual or real addresses of the buffers or a combination +of them. An "address type" field is available for each address that +may be given in the CCB. In all cases, the Hypervisor will translate +all the addresses to physical before dispatching to hardware. Address +translations are performed using the context of the process initiating +the request. + + +The Driver API +-------------- + +An application makes requests to the driver via the write() system +call, and gets results (if any) via read(). The completion areas are +made accessible via mmap(), and are read-only for the application. + +The request may either be an immediate command or an array of CCBs to +be submitted to the hardware. + +Each open instance of the device is exclusive to the thread that +opened it, and must be used by that thread for all subsequent +operations. The driver open function creates a new context for the +thread and initializes it for use. This context contains pointers and +values used internally by the driver to keep track of submitted +requests. The completion area buffer is also allocated, and this is +large enough to contain the completion areas for many concurrent +requests. When the device is closed, any outstanding transactions are +flushed and the context is cleaned up. + +On a DAX1 system (M7), the device will be called "oradax1", while on a +DAX2 system (M8) it will be "oradax2". If an application requires one +or the other, it should simply attempt to open the appropriate +device. Only one of the devices will exist on any given system, so the +name can be used to determine what the platform supports. + +The immediate commands are CCB_DEQUEUE, CCB_KILL, and CCB_INFO. For +all of these, success is indicated by a return value from write() +equal to the number of bytes given in the call. Otherwise -1 is +returned and errno is set. + +CCB_DEQUEUE + +Tells the driver to clean up resources associated with past +requests. Since no interrupt is generated upon the completion of a +request, the driver must be told when it may reclaim resources. No +further status information is returned, so the user should not +subsequently call read(). + +CCB_KILL + +Kills a CCB during execution. The CCB is guaranteed to not continue +executing once this call returns successfully. On success, read() must +be called to retrieve the result of the action. + +CCB_INFO + +Retrieves information about a currently executing CCB. Note that some +Hypervisors might return 'notfound' when the CCB is in 'inprogress' +state. To ensure a CCB in the 'notfound' state will never be executed, +CCB_KILL must be invoked on that CCB. Upon success, read() must be +called to retrieve the details of the action. + +Submission of an array of CCBs for execution + +A write() whose length is a multiple of the CCB size is treated as a +submit operation. The file offset is treated as the index of the +completion area to use, and may be set via lseek() or using the +pwrite() system call. If -1 is returned then errno is set to indicate +the error. Otherwise, the return value is the length of the array that +was actually accepted by the coprocessor. If the accepted length is +equal to the requested length, then the submission was completely +successful and there is no further status needed; hence, the user +should not subsequently call read(). Partial acceptance of the CCB +array is indicated by a return value less than the requested length, +and read() must be called to retrieve further status information. The +status will reflect the error caused by the first CCB that was not +accepted, and status_data will provide additional data in some cases. + +MMAP + +The mmap() function provides access to the completion area allocated +in the driver. Note that the completion area is not writeable by the +user process, and the mmap call must not specify PROT_WRITE. + + +Completion of a Request +----------------------- + +The first byte in each completion area is the command status which is +updated by the coprocessor hardware. Software may take advantage of +new M7/M8 processor capabilities to efficiently poll this status byte. +First, a "monitored load" is achieved via a Load from Alternate Space +(ldxa, lduba, etc.) with ASI 0x84 (ASI_MONITOR_PRIMARY). Second, a +"monitored wait" is achieved via the mwait instruction (a write to +%asr28). This instruction is like pause in that it suspends execution +of the virtual processor for the given number of nanoseconds, but in +addition will terminate early when one of several events occur. If the +block of data containing the monitored location is modified, then the +mwait terminates. This causes software to resume execution immediately +(without a context switch or kernel to user transition) after a +transaction completes. Thus the latency between transaction completion +and resumption of execution may be just a few nanoseconds. + + +Application Life Cycle of a DAX Submission +------------------------------------------ + + - open dax device + - call mmap() to get the completion area address + - allocate a CCB and fill in the opcode, flags, parameters, addresses, etc. + - submit CCB via write() or pwrite() + - go into a loop executing monitored load + monitored wait and + terminate when the command status indicates the request is complete + (CCB_KILL or CCB_INFO may be used any time as necessary) + - perform a CCB_DEQUEUE + - call munmap() for completion area + - close the dax device + + +Memory Constraints +------------------ + +The DAX hardware operates only on physical addresses. Therefore, it is +not aware of virtual memory mappings and the discontiguities that may +exist in the physical memory that a virtual buffer maps to. There is +no I/O TLB or any scatter/gather mechanism. All buffers, whether input +or output, must reside in a physically contiguous region of memory. + +The Hypervisor translates all addresses within a CCB to physical +before handing off the CCB to DAX. The Hypervisor determines the +virtual page size for each virtual address given, and uses this to +program a size limit for each address. This prevents the coprocessor +from reading or writing beyond the bound of the virtual page, even +though it is accessing physical memory directly. A simpler way of +saying this is that a DAX operation will never "cross" a virtual page +boundary. If an 8k virtual page is used, then the data is strictly +limited to 8k. If a user's buffer is larger than 8k, then a larger +page size must be used, or the transaction size will be truncated to +8k. + +Huge pages. A user may allocate huge pages using standard interfaces. +Memory buffers residing on huge pages may be used to achieve much +larger DAX transaction sizes, but the rules must still be followed, +and no transaction will cross a page boundary, even a huge page. A +major caveat is that Linux on Sparc presents 8Mb as one of the huge +page sizes. Sparc does not actually provide a 8Mb hardware page size, +and this size is synthesized by pasting together two 4Mb pages. The +reasons for this are historical, and it creates an issue because only +half of this 8Mb page can actually be used for any given buffer in a +DAX request, and it must be either the first half or the second half; +it cannot be a 4Mb chunk in the middle, since that crosses a +(hardware) page boundary. Note that this entire issue may be hidden by +higher level libraries. + + +CCB Structure +------------- +A CCB is an array of 8 64-bit words. Several of these words provide +command opcodes, parameters, flags, etc., and the rest are addresses +for the completion area, output buffer, and various inputs: + + struct ccb { + u64 control; + u64 completion; + u64 input0; + u64 access; + u64 input1; + u64 op_data; + u64 output; + u64 table; + }; + +See libdax/common/sys/dax1/dax1_ccb.h for a detailed description of +each of these fields, and see dax-hv-api.txt for a complete description +of the Hypervisor API available to the guest OS (ie, Linux kernel). + +The first word (control) is examined by the driver for the following: + - CCB version, which must be consistent with hardware version + - Opcode, which must be one of the documented allowable commands + - Address types, which must be set to "virtual" for all the addresses + given by the user, thereby ensuring that the application can + only access memory that it owns + + +Example Code +------------ + +The DAX is accessible to both user and kernel code. The kernel code +can make hypercalls directly while the user code must use wrappers +provided by the driver. The setup of the CCB is nearly identical for +both; the only difference is in preparation of the completion area. An +example of user code is given now, with kernel code afterwards. + +In order to program using the driver API, the file +arch/sparc/include/uapi/asm/oradax.h must be included. + +First, the proper device must be opened. For M7 it will be +/dev/oradax1 and for M8 it will be /dev/oradax2. The simplest +procedure is to attempt to open both, as only one will succeed: + + fd = open("/dev/oradax1", O_RDWR); + if (fd < 0) + fd = open("/dev/oradax2", O_RDWR); + if (fd < 0) + /* No DAX found */ + +Next, the completion area must be mapped: + + completion_area = mmap(NULL, DAX_MMAP_LEN, PROT_READ, MAP_SHARED, fd, 0); + +All input and output buffers must be fully contained in one hardware +page, since as explained above, the DAX is strictly constrained by +virtual page boundaries. In addition, the output buffer must be +64-byte aligned and its size must be a multiple of 64 bytes because +the coprocessor writes in units of cache lines. + +This example demonstrates the DAX Scan command, which takes as input a +vector and a match value, and produces a bitmap as the output. For +each input element that matches the value, the corresponding bit is +set in the output. + +In this example, the input vector consists of a series of single bits, +and the match value is 0. So each 0 bit in the input will produce a 1 +in the output, and vice versa, which produces an output bitmap which +is the input bitmap inverted. + +For details of all the parameters and bits used in this CCB, please +refer to section 36.2.1.3 of the DAX Hypervisor API document, which +describes the Scan command in detail. + + ccb->control = /* Table 36.1, CCB Header Format */ + (2L << 48) /* command = Scan Value */ + | (3L << 40) /* output address type = primary virtual */ + | (3L << 34) /* primary input address type = primary virtual */ + /* Section 36.2.1, Query CCB Command Formats */ + | (1 << 28) /* 36.2.1.1.1 primary input format = fixed width bit packed */ + | (0 << 23) /* 36.2.1.1.2 primary input element size = 0 (1 bit) */ + | (8 << 10) /* 36.2.1.1.6 output format = bit vector */ + | (0 << 5) /* 36.2.1.3 First scan criteria size = 0 (1 byte) */ + | (31 << 0); /* 36.2.1.3 Disable second scan criteria */ + + ccb->completion = 0; /* Completion area address, to be filled in by driver */ + + ccb->input0 = (unsigned long) input; /* primary input address */ + + ccb->access = /* Section 36.2.1.2, Data Access Control */ + (2 << 24) /* Primary input length format = bits */ + | (nbits - 1); /* number of bits in primary input stream, minus 1 */ + + ccb->input1 = 0; /* secondary input address, unused */ + + ccb->op_data = 0; /* scan criteria (value to be matched) */ + + ccb->output = (unsigned long) output; /* output address */ + + ccb->table = 0; /* table address, unused */ + +The CCB submission is a write() or pwrite() system call to the +driver. If the call fails, then a read() must be used to retrieve the +status: + + if (pwrite(fd, ccb, 64, 0) != 64) { + struct ccb_exec_result status; + read(fd, &status, sizeof(status)); + /* bail out */ + } + +After a successful submission of the CCB, the completion area may be +polled to determine when the DAX is finished. Detailed information on +the contents of the completion area can be found in section 36.2.2 of +the DAX HV API document. + + while (1) { + /* Monitored Load */ + __asm__ __volatile__("lduba [%1] 0x84, %0\n" + : "=r" (status) + : "r" (completion_area)); + + if (status) /* 0 indicates command in progress */ + break; + + /* MWAIT */ + __asm__ __volatile__("wr %%g0, 1000, %%asr28\n" ::); /* 1000 ns */ + } + +A completion area status of 1 indicates successful completion of the +CCB and validity of the output bitmap, which may be used immediately. +All other non-zero values indicate error conditions which are +described in section 36.2.2. + + if (completion_area[0] != 1) { /* section 36.2.2, 1 = command ran and succeeded */ + /* completion_area[0] contains the completion status */ + /* completion_area[1] contains an error code, see 36.2.2 */ + } + +After the completion area has been processed, the driver must be +notified that it can release any resources associated with the +request. This is done via the dequeue operation: + + struct dax_command cmd; + cmd.command = CCB_DEQUEUE; + if (write(fd, &cmd, sizeof(cmd)) != sizeof(cmd)) { + /* bail out */ + } + +Finally, normal program cleanup should be done, i.e., unmapping +completion area, closing the dax device, freeing memory etc. + +[Kernel example] + +The only difference in using the DAX in kernel code is the treatment +of the completion area. Unlike user applications which mmap the +completion area allocated by the driver, kernel code must allocate its +own memory to use for the completion area, and this address and its +type must be given in the CCB: + + ccb->control |= /* Table 36.1, CCB Header Format */ + (3L << 32); /* completion area address type = primary virtual */ + + ccb->completion = (unsigned long) completion_area; /* Completion area address */ + +The dax submit hypercall is made directly. The flags used in the +ccb_submit call are documented in the DAX HV API in section 36.3.1. + +#include + + hv_rv = sun4v_ccb_submit((unsigned long)ccb, 64, + HV_CCB_QUERY_CMD | + HV_CCB_ARG0_PRIVILEGED | HV_CCB_ARG0_TYPE_PRIMARY | + HV_CCB_VA_PRIVILEGED, + 0, &bytes_accepted, &status_data); + + if (hv_rv != HV_EOK) { + /* hv_rv is an error code, status_data contains */ + /* potential additional status, see 36.3.1.1 */ + } + +After the submission, the completion area polling code is identical to +that in user land: + + while (1) { + /* Monitored Load */ + __asm__ __volatile__("lduba [%1] 0x84, %0\n" + : "=r" (status) + : "r" (completion_area)); + + if (status) /* 0 indicates command in progress */ + break; + + /* MWAIT */ + __asm__ __volatile__("wr %%g0, 1000, %%asr28\n" ::); /* 1000 ns */ + } + + if (completion_area[0] != 1) { /* section 36.2.2, 1 = command ran and succeeded */ + /* completion_area[0] contains the completion status */ + /* completion_area[1] contains an error code, see 36.2.2 */ + } + +The output bitmap is ready for consumption immediately after the +completion status indicates success. diff --git a/Documentation/speculation.txt b/Documentation/speculation.txt new file mode 100644 index 000000000000..e9e6cbae2841 --- /dev/null +++ b/Documentation/speculation.txt @@ -0,0 +1,90 @@ +This document explains potential effects of speculation, and how undesirable +effects can be mitigated portably using common APIs. + +=========== +Speculation +=========== + +To improve performance and minimize average latencies, many contemporary CPUs +employ speculative execution techniques such as branch prediction, performing +work which may be discarded at a later stage. + +Typically speculative execution cannot be observed from architectural state, +such as the contents of registers. However, in some cases it is possible to +observe its impact on microarchitectural state, such as the presence or +absence of data in caches. Such state may form side-channels which can be +observed to extract secret information. + +For example, in the presence of branch prediction, it is possible for bounds +checks to be ignored by code which is speculatively executed. Consider the +following code: + + int load_array(int *array, unsigned int index) + { + if (index >= MAX_ARRAY_ELEMS) + return 0; + else + return array[index]; + } + +Which, on arm64, may be compiled to an assembly sequence such as: + + CMP , #MAX_ARRAY_ELEMS + B.LT less + MOV , #0 + RET + less: + LDR , [, ] + RET + +It is possible that a CPU mis-predicts the conditional branch, and +speculatively loads array[index], even if index >= MAX_ARRAY_ELEMS. This +value will subsequently be discarded, but the speculated load may affect +microarchitectural state which can be subsequently measured. + +More complex sequences involving multiple dependent memory accesses may +result in sensitive information being leaked. Consider the following +code, building on the prior example: + + int load_dependent_arrays(int *arr1, int *arr2, int index) + { + int val1, val2, + + val1 = load_array(arr1, index); + val2 = load_array(arr2, val1); + + return val2; + } + +Under speculation, the first call to load_array() may return the value +of an out-of-bounds address, while the second call will influence +microarchitectural state dependent on this value. This may provide an +arbitrary read primitive. + +==================================== +Mitigating speculation side-channels +==================================== + +The kernel provides a generic API to ensure that bounds checks are +respected even under speculation. Architectures which are affected by +speculation-based side-channels are expected to implement these +primitives. + +The array_index_nospec() helper in can be used to +prevent information from being leaked via side-channels. + +A call to array_index_nospec(index, size) returns a sanitized index +value that is bounded to [0, size) even under cpu speculation +conditions. + +This can be used to protect the earlier load_array() example: + + int load_array(int *array, unsigned int index) + { + if (index >= MAX_ARRAY_ELEMS) + return 0; + else { + index = array_index_nospec(index, MAX_ARRAY_ELEMS); + return array[index]; + } + } diff --git a/Documentation/sphinx/kfigure.py b/Documentation/sphinx/kfigure.py index cef4ad19624c..b97228d2cc0e 100644 --- a/Documentation/sphinx/kfigure.py +++ b/Documentation/sphinx/kfigure.py @@ -81,7 +81,7 @@ __version__ = '1.0.0' # ------------- def which(cmd): - """Searches the ``cmd`` in the ``PATH`` enviroment. + """Searches the ``cmd`` in the ``PATH`` environment. This *which* searches the PATH for executable ``cmd`` . First match is returned, if nothing is found, ``None` is returned. @@ -419,7 +419,7 @@ def visit_kernel_render(self, node): tmp_ext = RENDER_MARKUP_EXT.get(srclang, None) if tmp_ext is None: - app.warn('kernel-render: "%s" unknow / include raw.' % (srclang)) + app.warn('kernel-render: "%s" unknown / include raw.' % (srclang)) return if not dot_cmd and tmp_ext == '.dot': @@ -482,7 +482,7 @@ class KernelRender(Figure): srclang = self.arguments[0].strip() if srclang not in RENDER_MARKUP_EXT.keys(): return [self.state_machine.reporter.warning( - 'Unknow source language "%s", use one of: %s.' % ( + 'Unknown source language "%s", use one of: %s.' % ( srclang, ",".join(RENDER_MARKUP_EXT.keys())), line=self.lineno)] diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 694968c7523c..412314eebda6 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -34,6 +34,7 @@ show up in /proc/sys/kernel: - hostname - hotplug - hardlockup_all_cpu_backtrace +- hardlockup_panic - hung_task_panic - hung_task_check_count - hung_task_timeout_secs @@ -313,6 +314,19 @@ will be initiated. 1: on detection capture more debug information. ============================================================== +hardlockup_panic: + +This parameter can be used to control whether the kernel panics +when a hard lockup is detected. + + 0 - don't panic on hard lockup + 1 - panic on hard lockup + +See Documentation/lockup-watchdogs.txt for more information. This can +also be set using the nmi_watchdog kernel parameter. + +============================================================== + hotplug: Path for the hotplug policy agent. @@ -377,7 +391,8 @@ kptr_restrict: This toggle indicates whether restrictions are placed on exposing kernel addresses via /proc and other interfaces. -When kptr_restrict is set to (0), the default, there are no restrictions. +When kptr_restrict is set to 0 (the default) the address is hashed before +printing. (This is the equivalent to %p.) When kptr_restrict is set to (1), kernel pointers printed using the %pK format specifier will be replaced with 0's unless the user has CAP_SYSLOG diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt index b67044a2575f..35c62f522754 100644 --- a/Documentation/sysctl/net.txt +++ b/Documentation/sysctl/net.txt @@ -95,7 +95,9 @@ dev_weight -------------- The maximum number of packets that kernel can handle on a NAPI interrupt, -it's a Per-CPU variable. +it's a Per-CPU variable. For drivers that support LRO or GRO_HW, a hardware +aggregated packet is counted as one packet in this context. + Default: 64 dev_weight_rx_bias diff --git a/Documentation/sysctl/user.txt b/Documentation/sysctl/user.txt index 1291c498f78f..a5882865836e 100644 --- a/Documentation/sysctl/user.txt +++ b/Documentation/sysctl/user.txt @@ -3,7 +3,7 @@ Documentation for /proc/sys/user/* kernel version 4.9.0 ============================================================== -This file contains the documetation for the sysctl files in +This file contains the documentation for the sysctl files in /proc/sys/user. The files in this directory can be used to override the default diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index 5025ff9307e6..ff234d229cbb 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -30,7 +30,6 @@ Currently, these files are in /proc/sys/vm: - dirty_writeback_centisecs - drop_caches - extfrag_threshold -- hugepages_treat_as_movable - hugetlb_shm_group - laptop_mode - legacy_va_layout @@ -261,30 +260,6 @@ any throttling. ============================================================== -hugepages_treat_as_movable - -This parameter controls whether we can allocate hugepages from ZONE_MOVABLE -or not. If set to non-zero, hugepages can be allocated from ZONE_MOVABLE. -ZONE_MOVABLE is created when kernel boot parameter kernelcore= is specified, -so this parameter has no effect if used without kernelcore=. - -Hugepage migration is now available in some situations which depend on the -architecture and/or the hugepage size. If a hugepage supports migration, -allocation from ZONE_MOVABLE is always enabled for the hugepage regardless -of the value of this parameter. -IOW, this parameter affects only non-migratable hugepages. - -Assuming that hugepages are not migratable in your system, one usecase of -this parameter is that users can make hugepage pool more extensible by -enabling the allocation from ZONE_MOVABLE. This is because on ZONE_MOVABLE -page reclaim/migration/compaction work more and you can get contiguous -memory more likely. Note that using ZONE_MOVABLE for non-migratable -hugepages can do harm to other features like memory hotremove (because -memory hotremove expects that memory blocks on ZONE_MOVABLE are always -removable,) so it's a trade-off responsible for the users. - -============================================================== - hugetlb_shm_group hugetlb_shm_group contains group id that is allowed to create SysV diff --git a/Documentation/thermal/cpu-cooling-api.txt b/Documentation/thermal/cpu-cooling-api.txt index 71653584cd03..7df567eaea1a 100644 --- a/Documentation/thermal/cpu-cooling-api.txt +++ b/Documentation/thermal/cpu-cooling-api.txt @@ -26,39 +26,16 @@ the user. The registration APIs returns the cooling device pointer. clip_cpus: cpumask of cpus where the frequency constraints will happen. 1.1.2 struct thermal_cooling_device *of_cpufreq_cooling_register( - struct device_node *np, const struct cpumask *clip_cpus) + struct cpufreq_policy *policy) This interface function registers the cpufreq cooling device with the name "thermal-cpufreq-%x" linking it with a device tree node, in order to bind it via the thermal DT code. This api can support multiple instances of cpufreq cooling devices. - np: pointer to the cooling device device tree node - clip_cpus: cpumask of cpus where the frequency constraints will happen. + policy: CPUFreq policy. -1.1.3 struct thermal_cooling_device *cpufreq_power_cooling_register( - const struct cpumask *clip_cpus, u32 capacitance, - get_static_t plat_static_func) - -Similar to cpufreq_cooling_register, this function registers a cpufreq -cooling device. Using this function, the cooling device will -implement the power extensions by using a simple cpu power model. The -cpus must have registered their OPPs using the OPP library. - -The additional parameters are needed for the power model (See 2. Power -models). "capacitance" is the dynamic power coefficient (See 2.1 -Dynamic power). "plat_static_func" is a function to calculate the -static power consumed by these cpus (See 2.2 Static power). - -1.1.4 struct thermal_cooling_device *of_cpufreq_power_cooling_register( - struct device_node *np, const struct cpumask *clip_cpus, u32 capacitance, - get_static_t plat_static_func) - -Similar to cpufreq_power_cooling_register, this function register a -cpufreq cooling device with power extensions using the device tree -information supplied by the np parameter. - -1.1.5 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) +1.1.3 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) This interface function unregisters the "thermal-cpufreq-%x" cooling device. @@ -67,20 +44,14 @@ information supplied by the np parameter. 2. Power models The power API registration functions provide a simple power model for -CPUs. The current power is calculated as dynamic + (optionally) -static power. This power model requires that the operating-points of +CPUs. The current power is calculated as dynamic power (static power isn't +supported currently). This power model requires that the operating-points of the CPUs are registered using the kernel's opp library and the `cpufreq_frequency_table` is assigned to the `struct device` of the cpu. If you are using CONFIG_CPUFREQ_DT then the `cpufreq_frequency_table` should already be assigned to the cpu device. -The `plat_static_func` parameter of `cpufreq_power_cooling_register()` -and `of_cpufreq_power_cooling_register()` is optional. If you don't -provide it, only dynamic power will be considered. - -2.1 Dynamic power - The dynamic power consumption of a processor depends on many factors. For a given processor implementation the primary factors are: @@ -119,79 +90,3 @@ mW/MHz/uVolt^2. Typical values for mobile CPUs might lie in range from 100 to 500. For reference, the approximate values for the SoC in ARM's Juno Development Platform are 530 for the Cortex-A57 cluster and 140 for the Cortex-A53 cluster. - - -2.2 Static power - -Static leakage power consumption depends on a number of factors. For a -given circuit implementation the primary factors are: - -- Time the circuit spends in each 'power state' -- Temperature -- Operating voltage -- Process grade - -The time the circuit spends in each 'power state' for a given -evaluation period at first order means OFF or ON. However, -'retention' states can also be supported that reduce power during -inactive periods without loss of context. - -Note: The visibility of state entries to the OS can vary, according to -platform specifics, and this can then impact the accuracy of a model -based on OS state information alone. It might be possible in some -cases to extract more accurate information from system resources. - -The temperature, operating voltage and process 'grade' (slow to fast) -of the circuit are all significant factors in static leakage power -consumption. All of these have complex relationships to static power. - -Circuit implementation specific factors include the chosen silicon -process as well as the type, number and size of transistors in both -the logic gates and any RAM elements included. - -The static power consumption modelling must take into account the -power managed regions that are implemented. Taking the example of an -ARM processor cluster, the modelling would take into account whether -each CPU can be powered OFF separately or if only a single power -region is implemented for the complete cluster. - -In one view, there are others, a static power consumption model can -then start from a set of reference values for each power managed -region (e.g. CPU, Cluster/L2) in each state (e.g. ON, OFF) at an -arbitrary process grade, voltage and temperature point. These values -are then scaled for all of the following: the time in each state, the -process grade, the current temperature and the operating voltage. -However, since both implementation specific and complex relationships -dominate the estimate, the appropriate interface to the model from the -cpu cooling device is to provide a function callback that calculates -the static power in this platform. When registering the cpu cooling -device pass a function pointer that follows the `get_static_t` -prototype: - - int plat_get_static(cpumask_t *cpumask, int interval, - unsigned long voltage, u32 &power); - -`cpumask` is the cpumask of the cpus involved in the calculation. -`voltage` is the voltage at which they are operating. The function -should calculate the average static power for the last `interval` -milliseconds. It returns 0 on success, -E* on error. If it -succeeds, it should store the static power in `power`. Reading the -temperature of the cpus described by `cpumask` is left for -plat_get_static() to do as the platform knows best which thermal -sensor is closest to the cpu. - -If `plat_static_func` is NULL, static power is considered to be -negligible for this platform and only dynamic power is considered. - -The platform specific callback can then use any combination of tables -and/or equations to permute the estimated value. Process grade -information is not passed to the model since access to such data, from -on-chip measurement capability or manufacture time data, is platform -specific. - -Note: the significance of static power for CPUs in comparison to -dynamic power is highly dependent on implementation. Given the -potential complexity in implementation, the importance and accuracy of -its inclusion when using cpu cooling devices should be assessed on a -case by case basis. - diff --git a/Documentation/trace/ftrace-uses.rst b/Documentation/trace/ftrace-uses.rst index 8494a801d341..3aed560a12ee 100644 --- a/Documentation/trace/ftrace-uses.rst +++ b/Documentation/trace/ftrace-uses.rst @@ -42,9 +42,9 @@ as well as what protections the callback will perform and not require ftrace to handle. There is only one field that is needed to be set when registering -an ftrace_ops with ftrace:: +an ftrace_ops with ftrace: -.. code-block: c +.. code-block:: c struct ftrace_ops ops = { .func = my_callback_func, @@ -81,12 +81,12 @@ may take some time to finish. The callback function ===================== -The prototype of the callback function is as follows (as of v4.14):: +The prototype of the callback function is as follows (as of v4.14): -.. code-block: c +.. code-block:: c - void callback_func(unsigned long ip, unsigned long parent_ip, - struct ftrace_ops *op, struct pt_regs *regs); + void callback_func(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct pt_regs *regs); @ip This is the instruction pointer of the function that is being traced. @@ -176,10 +176,10 @@ Filtering which functions to trace If a callback is only to be called from specific functions, a filter must be set up. The filters are added by name, or ip if it is known. -.. code-block: c +.. code-block:: c - int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf, - int len, int reset); + int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf, + int len, int reset); @ops The ops to set the filter with @@ -202,9 +202,9 @@ See Filter Commands in :file:`Documentation/trace/ftrace.txt`. To just trace the schedule function:: -.. code-block: c +.. code-block:: c - ret = ftrace_set_filter(&ops, "schedule", strlen("schedule"), 0); + ret = ftrace_set_filter(&ops, "schedule", strlen("schedule"), 0); To add more functions, call the ftrace_set_filter() more than once with the @reset parameter set to zero. To remove the current filter set and replace it @@ -212,17 +212,17 @@ with new functions defined by @buf, have @reset be non-zero. To remove all the filtered functions and trace all functions:: -.. code-block: c +.. code-block:: c - ret = ftrace_set_filter(&ops, NULL, 0, 1); + ret = ftrace_set_filter(&ops, NULL, 0, 1); Sometimes more than one function has the same name. To trace just a specific function in this case, ftrace_set_filter_ip() can be used. -.. code-block: c +.. code-block:: c - ret = ftrace_set_filter_ip(&ops, ip, 0, 0); + ret = ftrace_set_filter_ip(&ops, ip, 0, 0); Although the ip must be the address where the call to fentry or mcount is located in the function. This function is used by perf and kprobes that @@ -237,10 +237,10 @@ be called by any function. An empty "notrace" list means to allow all functions defined by the filter to be traced. -.. code-block: c +.. code-block:: c - int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf, - int len, int reset); + int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf, + int len, int reset); This takes the same parameters as ftrace_set_filter() but will add the functions it finds to not be traced. This is a separate list from the @@ -251,7 +251,7 @@ that match @buf to it. Clearing the "notrace" list is the same as clearing the filter list -.. code-block: c +.. code-block:: c ret = ftrace_set_notrace(&ops, NULL, 0, 1); @@ -264,29 +264,29 @@ If a filter is in place, and the @reset is non-zero, and @buf contains a matching glob to functions, the switch will happen during the time of the ftrace_set_filter() call. At no time will all functions call the callback. -.. code-block: c +.. code-block:: c - ftrace_set_filter(&ops, "schedule", strlen("schedule"), 1); + ftrace_set_filter(&ops, "schedule", strlen("schedule"), 1); - register_ftrace_function(&ops); + register_ftrace_function(&ops); - msleep(10); + msleep(10); - ftrace_set_filter(&ops, "try_to_wake_up", strlen("try_to_wake_up"), 1); + ftrace_set_filter(&ops, "try_to_wake_up", strlen("try_to_wake_up"), 1); is not the same as: -.. code-block: c +.. code-block:: c - ftrace_set_filter(&ops, "schedule", strlen("schedule"), 1); + ftrace_set_filter(&ops, "schedule", strlen("schedule"), 1); - register_ftrace_function(&ops); + register_ftrace_function(&ops); - msleep(10); + msleep(10); - ftrace_set_filter(&ops, NULL, 0, 1); + ftrace_set_filter(&ops, NULL, 0, 1); - ftrace_set_filter(&ops, "try_to_wake_up", strlen("try_to_wake_up"), 0); + ftrace_set_filter(&ops, "try_to_wake_up", strlen("try_to_wake_up"), 0); As the latter will have a short time where all functions will call the callback, between the time of the reset, and the time of the diff --git a/Documentation/translations/zh_CN/filesystems/sysfs.txt b/Documentation/translations/zh_CN/filesystems/sysfs.txt index 7d3b05edb8ce..452271dda141 100644 --- a/Documentation/translations/zh_CN/filesystems/sysfs.txt +++ b/Documentation/translations/zh_CN/filesystems/sysfs.txt @@ -167,8 +167,8 @@ static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, if (dev_attr->show) ret = dev_attr->show(dev, dev_attr, buf); if (ret >= (ssize_t)PAGE_SIZE) { - print_symbol("dev_attr_show: %s returned bad count\n", - (unsigned long)dev_attr->show); + printk("dev_attr_show: %pS returned bad count\n", + dev_attr->show); } return ret; } diff --git a/Documentation/usb/chipidea.txt b/Documentation/usb/chipidea.txt index edf7cdfddc88..d1eedc01b00a 100644 --- a/Documentation/usb/chipidea.txt +++ b/Documentation/usb/chipidea.txt @@ -23,13 +23,13 @@ cat /sys/kernel/debug/ci_hdrc.0/registers 2) Connect 2 boards with usb cable with one end is micro A plug, the other end is micro B plug. - The A-device(with micro A plug inserted) should enumrate B-device. + The A-device(with micro A plug inserted) should enumerate B-device. 3) Role switch On B-device: echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req - B-device should take host role and enumrate A-device. + B-device should take host role and enumerate A-device. 4) A-device switch back to host. On B-device: @@ -40,13 +40,13 @@ cat /sys/kernel/debug/ci_hdrc.0/registers side by answering the polling from B-Host, this can be done on A-device: echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req - A-device should switch back to host and enumrate B-device. + A-device should switch back to host and enumerate B-device. 5) Remove B-device(unplug micro B plug) and insert again in 10 seconds, - A-device should enumrate B-device again. + A-device should enumerate B-device again. 6) Remove B-device(unplug micro B plug) and insert again after 10 seconds, - A-device should NOT enumrate B-device. + A-device should NOT enumerate B-device. if A-device wants to use bus: On A-device: @@ -67,7 +67,7 @@ cat /sys/kernel/debug/ci_hdrc.0/registers On B-device: echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req - A-device should resume usb bus and enumrate B-device. + A-device should resume usb bus and enumerate B-device. 1.3 Reference document ---------------------- diff --git a/Documentation/usb/usbip_protocol.txt b/Documentation/usb/usbip_protocol.txt index 16b6fe27284c..c7a0f4c7e7f1 100644 --- a/Documentation/usb/usbip_protocol.txt +++ b/Documentation/usb/usbip_protocol.txt @@ -274,7 +274,6 @@ USBIP_CMD_SUBMIT: Submit an URB URB_SHORT_NOT_OK | 0x00000001 | only in | only in | only in | no URB_ISO_ASAP | 0x00000002 | no | no | no | yes URB_NO_TRANSFER_DMA_MAP | 0x00000004 | yes | yes | yes | yes - URB_NO_FSBR | 0x00000020 | yes | no | no | no URB_ZERO_PACKET | 0x00000040 | no | no | only out | no URB_NO_INTERRUPT | 0x00000080 | yes | yes | yes | yes URB_FREE_BUFFER | 0x00000100 | yes | yes | yes | yes diff --git a/Documentation/virtual/kvm/00-INDEX b/Documentation/virtual/kvm/00-INDEX index 69fe1a8b7ad1..3da73aabff5a 100644 --- a/Documentation/virtual/kvm/00-INDEX +++ b/Documentation/virtual/kvm/00-INDEX @@ -26,3 +26,6 @@ s390-diag.txt - Diagnose hypercall description (for IBM S/390) timekeeping.txt - timekeeping virtualization for x86-based architectures. +amd-memory-encryption.txt + - notes on AMD Secure Encrypted Virtualization feature and SEV firmware + command description diff --git a/Documentation/virtual/kvm/amd-memory-encryption.rst b/Documentation/virtual/kvm/amd-memory-encryption.rst new file mode 100644 index 000000000000..71d6d257074f --- /dev/null +++ b/Documentation/virtual/kvm/amd-memory-encryption.rst @@ -0,0 +1,247 @@ +====================================== +Secure Encrypted Virtualization (SEV) +====================================== + +Overview +======== + +Secure Encrypted Virtualization (SEV) is a feature found on AMD processors. + +SEV is an extension to the AMD-V architecture which supports running +virtual machines (VMs) under the control of a hypervisor. When enabled, +the memory contents of a VM will be transparently encrypted with a key +unique to that VM. + +The hypervisor can determine the SEV support through the CPUID +instruction. The CPUID function 0x8000001f reports information related +to SEV:: + + 0x8000001f[eax]: + Bit[1] indicates support for SEV + ... + [ecx]: + Bits[31:0] Number of encrypted guests supported simultaneously + +If support for SEV is present, MSR 0xc001_0010 (MSR_K8_SYSCFG) and MSR 0xc001_0015 +(MSR_K7_HWCR) can be used to determine if it can be enabled:: + + 0xc001_0010: + Bit[23] 1 = memory encryption can be enabled + 0 = memory encryption can not be enabled + + 0xc001_0015: + Bit[0] 1 = memory encryption can be enabled + 0 = memory encryption can not be enabled + +When SEV support is available, it can be enabled in a specific VM by +setting the SEV bit before executing VMRUN.:: + + VMCB[0x90]: + Bit[1] 1 = SEV is enabled + 0 = SEV is disabled + +SEV hardware uses ASIDs to associate a memory encryption key with a VM. +Hence, the ASID for the SEV-enabled guests must be from 1 to a maximum value +defined in the CPUID 0x8000001f[ecx] field. + +SEV Key Management +================== + +The SEV guest key management is handled by a separate processor called the AMD +Secure Processor (AMD-SP). Firmware running inside the AMD-SP provides a secure +key management interface to perform common hypervisor activities such as +encrypting bootstrap code, snapshot, migrating and debugging the guest. For more +information, see the SEV Key Management spec [api-spec]_ + +KVM implements the following commands to support common lifecycle events of SEV +guests, such as launching, running, snapshotting, migrating and decommissioning. + +1. KVM_SEV_INIT +--------------- + +The KVM_SEV_INIT command is used by the hypervisor to initialize the SEV platform +context. In a typical workflow, this command should be the first command issued. + +Returns: 0 on success, -negative on error + +2. KVM_SEV_LAUNCH_START +----------------------- + +The KVM_SEV_LAUNCH_START command is used for creating the memory encryption +context. To create the encryption context, user must provide a guest policy, +the owner's public Diffie-Hellman (PDH) key and session information. + +Parameters: struct kvm_sev_launch_start (in/out) + +Returns: 0 on success, -negative on error + +:: + + struct kvm_sev_launch_start { + __u32 handle; /* if zero then firmware creates a new handle */ + __u32 policy; /* guest's policy */ + + __u64 dh_uaddr; /* userspace address pointing to the guest owner's PDH key */ + __u32 dh_len; + + __u64 session_addr; /* userspace address which points to the guest session information */ + __u32 session_len; + }; + +On success, the 'handle' field contains a new handle and on error, a negative value. + +For more details, see SEV spec Section 6.2. + +3. KVM_SEV_LAUNCH_UPDATE_DATA +----------------------------- + +The KVM_SEV_LAUNCH_UPDATE_DATA is used for encrypting a memory region. It also +calculates a measurement of the memory contents. The measurement is a signature +of the memory contents that can be sent to the guest owner as an attestation +that the memory was encrypted correctly by the firmware. + +Parameters (in): struct kvm_sev_launch_update_data + +Returns: 0 on success, -negative on error + +:: + + struct kvm_sev_launch_update { + __u64 uaddr; /* userspace address to be encrypted (must be 16-byte aligned) */ + __u32 len; /* length of the data to be encrypted (must be 16-byte aligned) */ + }; + +For more details, see SEV spec Section 6.3. + +4. KVM_SEV_LAUNCH_MEASURE +------------------------- + +The KVM_SEV_LAUNCH_MEASURE command is used to retrieve the measurement of the +data encrypted by the KVM_SEV_LAUNCH_UPDATE_DATA command. The guest owner may +wait to provide the guest with confidential information until it can verify the +measurement. Since the guest owner knows the initial contents of the guest at +boot, the measurement can be verified by comparing it to what the guest owner +expects. + +Parameters (in): struct kvm_sev_launch_measure + +Returns: 0 on success, -negative on error + +:: + + struct kvm_sev_launch_measure { + __u64 uaddr; /* where to copy the measurement */ + __u32 len; /* length of measurement blob */ + }; + +For more details on the measurement verification flow, see SEV spec Section 6.4. + +5. KVM_SEV_LAUNCH_FINISH +------------------------ + +After completion of the launch flow, the KVM_SEV_LAUNCH_FINISH command can be +issued to make the guest ready for the execution. + +Returns: 0 on success, -negative on error + +6. KVM_SEV_GUEST_STATUS +----------------------- + +The KVM_SEV_GUEST_STATUS command is used to retrieve status information about a +SEV-enabled guest. + +Parameters (out): struct kvm_sev_guest_status + +Returns: 0 on success, -negative on error + +:: + + struct kvm_sev_guest_status { + __u32 handle; /* guest handle */ + __u32 policy; /* guest policy */ + __u8 state; /* guest state (see enum below) */ + }; + +SEV guest state: + +:: + + enum { + SEV_STATE_INVALID = 0; + SEV_STATE_LAUNCHING, /* guest is currently being launched */ + SEV_STATE_SECRET, /* guest is being launched and ready to accept the ciphertext data */ + SEV_STATE_RUNNING, /* guest is fully launched and running */ + SEV_STATE_RECEIVING, /* guest is being migrated in from another SEV machine */ + SEV_STATE_SENDING /* guest is getting migrated out to another SEV machine */ + }; + +7. KVM_SEV_DBG_DECRYPT +---------------------- + +The KVM_SEV_DEBUG_DECRYPT command can be used by the hypervisor to request the +firmware to decrypt the data at the given memory region. + +Parameters (in): struct kvm_sev_dbg + +Returns: 0 on success, -negative on error + +:: + + struct kvm_sev_dbg { + __u64 src_uaddr; /* userspace address of data to decrypt */ + __u64 dst_uaddr; /* userspace address of destination */ + __u32 len; /* length of memory region to decrypt */ + }; + +The command returns an error if the guest policy does not allow debugging. + +8. KVM_SEV_DBG_ENCRYPT +---------------------- + +The KVM_SEV_DEBUG_ENCRYPT command can be used by the hypervisor to request the +firmware to encrypt the data at the given memory region. + +Parameters (in): struct kvm_sev_dbg + +Returns: 0 on success, -negative on error + +:: + + struct kvm_sev_dbg { + __u64 src_uaddr; /* userspace address of data to encrypt */ + __u64 dst_uaddr; /* userspace address of destination */ + __u32 len; /* length of memory region to encrypt */ + }; + +The command returns an error if the guest policy does not allow debugging. + +9. KVM_SEV_LAUNCH_SECRET +------------------------ + +The KVM_SEV_LAUNCH_SECRET command can be used by the hypervisor to inject secret +data after the measurement has been validated by the guest owner. + +Parameters (in): struct kvm_sev_launch_secret + +Returns: 0 on success, -negative on error + +:: + + struct kvm_sev_launch_secret { + __u64 hdr_uaddr; /* userspace address containing the packet header */ + __u32 hdr_len; + + __u64 guest_uaddr; /* the guest memory region where the secret should be injected */ + __u32 guest_len; + + __u64 trans_uaddr; /* the hypervisor memory region which contains the secret */ + __u32 trans_len; + }; + +References +========== + +.. [white-paper] http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2013/12/AMD_Memory_Encryption_Whitepaper_v7-Public.pdf +.. [api-spec] http://support.amd.com/TechDocs/55766_SEV-KM%20API_Specification.pdf +.. [amd-apm] http://support.amd.com/TechDocs/24593.pdf (section 15.34) +.. [kvm-forum] http://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 57d3ee9e4bde..792fa8717d13 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -1841,6 +1841,7 @@ registers, find a list below: PPC | KVM_REG_PPC_DBSR | 32 PPC | KVM_REG_PPC_TIDR | 64 PPC | KVM_REG_PPC_PSSCR | 64 + PPC | KVM_REG_PPC_DEC_EXPIRY | 64 PPC | KVM_REG_PPC_TM_GPR0 | 64 ... PPC | KVM_REG_PPC_TM_GPR31 | 64 @@ -3403,6 +3404,103 @@ invalid, if invalid pages are written to (e.g. after the end of memory) or if no page table is present for the addresses (e.g. when using hugepages). +4.109 KVM_PPC_GET_CPU_CHAR + +Capability: KVM_CAP_PPC_GET_CPU_CHAR +Architectures: powerpc +Type: vm ioctl +Parameters: struct kvm_ppc_cpu_char (out) +Returns: 0 on successful completion + -EFAULT if struct kvm_ppc_cpu_char cannot be written + +This ioctl gives userspace information about certain characteristics +of the CPU relating to speculative execution of instructions and +possible information leakage resulting from speculative execution (see +CVE-2017-5715, CVE-2017-5753 and CVE-2017-5754). The information is +returned in struct kvm_ppc_cpu_char, which looks like this: + +struct kvm_ppc_cpu_char { + __u64 character; /* characteristics of the CPU */ + __u64 behaviour; /* recommended software behaviour */ + __u64 character_mask; /* valid bits in character */ + __u64 behaviour_mask; /* valid bits in behaviour */ +}; + +For extensibility, the character_mask and behaviour_mask fields +indicate which bits of character and behaviour have been filled in by +the kernel. If the set of defined bits is extended in future then +userspace will be able to tell whether it is running on a kernel that +knows about the new bits. + +The character field describes attributes of the CPU which can help +with preventing inadvertent information disclosure - specifically, +whether there is an instruction to flash-invalidate the L1 data cache +(ori 30,30,0 or mtspr SPRN_TRIG2,rN), whether the L1 data cache is set +to a mode where entries can only be used by the thread that created +them, whether the bcctr[l] instruction prevents speculation, and +whether a speculation barrier instruction (ori 31,31,0) is provided. + +The behaviour field describes actions that software should take to +prevent inadvertent information disclosure, and thus describes which +vulnerabilities the hardware is subject to; specifically whether the +L1 data cache should be flushed when returning to user mode from the +kernel, and whether a speculation barrier should be placed between an +array bounds check and the array access. + +These fields use the same bit definitions as the new +H_GET_CPU_CHARACTERISTICS hypercall. + +4.110 KVM_MEMORY_ENCRYPT_OP + +Capability: basic +Architectures: x86 +Type: system +Parameters: an opaque platform specific structure (in/out) +Returns: 0 on success; -1 on error + +If the platform supports creating encrypted VMs then this ioctl can be used +for issuing platform-specific memory encryption commands to manage those +encrypted VMs. + +Currently, this ioctl is used for issuing Secure Encrypted Virtualization +(SEV) commands on AMD Processors. The SEV commands are defined in +Documentation/virtual/kvm/amd-memory-encryption.txt. + +4.111 KVM_MEMORY_ENCRYPT_REG_REGION + +Capability: basic +Architectures: x86 +Type: system +Parameters: struct kvm_enc_region (in) +Returns: 0 on success; -1 on error + +This ioctl can be used to register a guest memory region which may +contain encrypted data (e.g. guest RAM, SMRAM etc). + +It is used in the SEV-enabled guest. When encryption is enabled, a guest +memory region may contain encrypted data. The SEV memory encryption +engine uses a tweak such that two identical plaintext pages, each at +different locations will have differing ciphertexts. So swapping or +moving ciphertext of those pages will not result in plaintext being +swapped. So relocating (or migrating) physical backing pages for the SEV +guest will require some additional steps. + +Note: The current SEV key management spec does not provide commands to +swap or migrate (move) ciphertext pages. Hence, for now we pin the guest +memory region registered with the ioctl. + +4.112 KVM_MEMORY_ENCRYPT_UNREG_REGION + +Capability: basic +Architectures: x86 +Type: system +Parameters: struct kvm_enc_region (in) +Returns: 0 on success; -1 on error + +This ioctl can be used to unregister the guest memory region registered +with KVM_MEMORY_ENCRYPT_REG_REGION ioctl above. + + 5. The kvm_run structure ------------------------ diff --git a/Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt b/Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt deleted file mode 100644 index 38bca2835278..000000000000 --- a/Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt +++ /dev/null @@ -1,187 +0,0 @@ -KVM/ARM VGIC Forwarded Physical Interrupts -========================================== - -The KVM/ARM code implements software support for the ARM Generic -Interrupt Controller's (GIC's) hardware support for virtualization by -allowing software to inject virtual interrupts to a VM, which the guest -OS sees as regular interrupts. The code is famously known as the VGIC. - -Some of these virtual interrupts, however, correspond to physical -interrupts from real physical devices. One example could be the -architected timer, which itself supports virtualization, and therefore -lets a guest OS program the hardware device directly to raise an -interrupt at some point in time. When such an interrupt is raised, the -host OS initially handles the interrupt and must somehow signal this -event as a virtual interrupt to the guest. Another example could be a -passthrough device, where the physical interrupts are initially handled -by the host, but the device driver for the device lives in the guest OS -and KVM must therefore somehow inject a virtual interrupt on behalf of -the physical one to the guest OS. - -These virtual interrupts corresponding to a physical interrupt on the -host are called forwarded physical interrupts, but are also sometimes -referred to as 'virtualized physical interrupts' and 'mapped interrupts'. - -Forwarded physical interrupts are handled slightly differently compared -to virtual interrupts generated purely by a software emulated device. - - -The HW bit ----------- -Virtual interrupts are signalled to the guest by programming the List -Registers (LRs) on the GIC before running a VCPU. The LR is programmed -with the virtual IRQ number and the state of the interrupt (Pending, -Active, or Pending+Active). When the guest ACKs and EOIs a virtual -interrupt, the LR state moves from Pending to Active, and finally to -inactive. - -The LRs include an extra bit, called the HW bit. When this bit is set, -KVM must also program an additional field in the LR, the physical IRQ -number, to link the virtual with the physical IRQ. - -When the HW bit is set, KVM must EITHER set the Pending OR the Active -bit, never both at the same time. - -Setting the HW bit causes the hardware to deactivate the physical -interrupt on the physical distributor when the guest deactivates the -corresponding virtual interrupt. - - -Forwarded Physical Interrupts Life Cycle ----------------------------------------- - -The state of forwarded physical interrupts is managed in the following way: - - - The physical interrupt is acked by the host, and becomes active on - the physical distributor (*). - - KVM sets the LR.Pending bit, because this is the only way the GICV - interface is going to present it to the guest. - - LR.Pending will stay set as long as the guest has not acked the interrupt. - - LR.Pending transitions to LR.Active on the guest read of the IAR, as - expected. - - On guest EOI, the *physical distributor* active bit gets cleared, - but the LR.Active is left untouched (set). - - KVM clears the LR on VM exits when the physical distributor - active state has been cleared. - -(*): The host handling is slightly more complicated. For some forwarded -interrupts (shared), KVM directly sets the active state on the physical -distributor before entering the guest, because the interrupt is never actually -handled on the host (see details on the timer as an example below). For other -forwarded interrupts (non-shared) the host does not deactivate the interrupt -when the host ISR completes, but leaves the interrupt active until the guest -deactivates it. Leaving the interrupt active is allowed, because Linux -configures the physical GIC with EOIMode=1, which causes EOI operations to -perform a priority drop allowing the GIC to receive other interrupts of the -default priority. - - -Forwarded Edge and Level Triggered PPIs and SPIs ------------------------------------------------- -Forwarded physical interrupts injected should always be active on the -physical distributor when injected to a guest. - -Level-triggered interrupts will keep the interrupt line to the GIC -asserted, typically until the guest programs the device to deassert the -line. This means that the interrupt will remain pending on the physical -distributor until the guest has reprogrammed the device. Since we -always run the VM with interrupts enabled on the CPU, a pending -interrupt will exit the guest as soon as we switch into the guest, -preventing the guest from ever making progress as the process repeats -over and over. Therefore, the active state on the physical distributor -must be set when entering the guest, preventing the GIC from forwarding -the pending interrupt to the CPU. As soon as the guest deactivates the -interrupt, the physical line is sampled by the hardware again and the host -takes a new interrupt if and only if the physical line is still asserted. - -Edge-triggered interrupts do not exhibit the same problem with -preventing guest execution that level-triggered interrupts do. One -option is to not use HW bit at all, and inject edge-triggered interrupts -from a physical device as pure virtual interrupts. But that would -potentially slow down handling of the interrupt in the guest, because a -physical interrupt occurring in the middle of the guest ISR would -preempt the guest for the host to handle the interrupt. Additionally, -if you configure the system to handle interrupts on a separate physical -core from that running your VCPU, you still have to interrupt the VCPU -to queue the pending state onto the LR, even though the guest won't use -this information until the guest ISR completes. Therefore, the HW -bit should always be set for forwarded edge-triggered interrupts. With -the HW bit set, the virtual interrupt is injected and additional -physical interrupts occurring before the guest deactivates the interrupt -simply mark the state on the physical distributor as Pending+Active. As -soon as the guest deactivates the interrupt, the host takes another -interrupt if and only if there was a physical interrupt between injecting -the forwarded interrupt to the guest and the guest deactivating the -interrupt. - -Consequently, whenever we schedule a VCPU with one or more LRs with the -HW bit set, the interrupt must also be active on the physical -distributor. - - -Forwarded LPIs --------------- -LPIs, introduced in GICv3, are always edge-triggered and do not have an -active state. They become pending when a device signal them, and as -soon as they are acked by the CPU, they are inactive again. - -It therefore doesn't make sense, and is not supported, to set the HW bit -for physical LPIs that are forwarded to a VM as virtual interrupts, -typically virtual SPIs. - -For LPIs, there is no other choice than to preempt the VCPU thread if -necessary, and queue the pending state onto the LR. - - -Putting It Together: The Architected Timer ------------------------------------------- -The architected timer is a device that signals interrupts with level -triggered semantics. The timer hardware is directly accessed by VCPUs -which program the timer to fire at some point in time. Each VCPU on a -system programs the timer to fire at different times, and therefore the -hardware is multiplexed between multiple VCPUs. This is implemented by -context-switching the timer state along with each VCPU thread. - -However, this means that a scenario like the following is entirely -possible, and in fact, typical: - -1. KVM runs the VCPU -2. The guest programs the time to fire in T+100 -3. The guest is idle and calls WFI (wait-for-interrupts) -4. The hardware traps to the host -5. KVM stores the timer state to memory and disables the hardware timer -6. KVM schedules a soft timer to fire in T+(100 - time since step 2) -7. KVM puts the VCPU thread to sleep (on a waitqueue) -8. The soft timer fires, waking up the VCPU thread -9. KVM reprograms the timer hardware with the VCPU's values -10. KVM marks the timer interrupt as active on the physical distributor -11. KVM injects a forwarded physical interrupt to the guest -12. KVM runs the VCPU - -Notice that KVM injects a forwarded physical interrupt in step 11 without -the corresponding interrupt having actually fired on the host. That is -exactly why we mark the timer interrupt as active in step 10, because -the active state on the physical distributor is part of the state -belonging to the timer hardware, which is context-switched along with -the VCPU thread. - -If the guest does not idle because it is busy, the flow looks like this -instead: - -1. KVM runs the VCPU -2. The guest programs the time to fire in T+100 -4. At T+100 the timer fires and a physical IRQ causes the VM to exit - (note that this initially only traps to EL2 and does not run the host ISR - until KVM has returned to the host). -5. With interrupts still disabled on the CPU coming back from the guest, KVM - stores the virtual timer state to memory and disables the virtual hw timer. -6. KVM looks at the timer state (in memory) and injects a forwarded physical - interrupt because it concludes the timer has expired. -7. KVM marks the timer interrupt as active on the physical distributor -7. KVM enables the timer, enables interrupts, and runs the VCPU - -Notice that again the forwarded physical interrupt is injected to the -guest without having actually been handled on the host. In this case it -is because the physical interrupt is never actually seen by the host because the -timer is disabled upon guest return, and the virtual forwarded interrupt is -injected on the KVM guest entry path. diff --git a/Documentation/virtual/kvm/cpuid.txt b/Documentation/virtual/kvm/cpuid.txt index 3c65feb83010..dcab6dc11e3b 100644 --- a/Documentation/virtual/kvm/cpuid.txt +++ b/Documentation/virtual/kvm/cpuid.txt @@ -54,6 +54,10 @@ KVM_FEATURE_PV_UNHALT || 7 || guest checks this feature bit || || before enabling paravirtualized || || spinlock support. ------------------------------------------------------------------------------ +KVM_FEATURE_PV_TLB_FLUSH || 9 || guest checks this feature bit + || || before enabling paravirtualized + || || tlb flush. +------------------------------------------------------------------------------ KVM_FEATURE_CLOCKSOURCE_STABLE_BIT || 24 || host will warn if no guest-side || || per-cpu warps are expected in || || kvmclock. diff --git a/Documentation/vm/hugetlbpage.txt b/Documentation/vm/hugetlbpage.txt index 59cbc803aad6..faf077d50d42 100644 --- a/Documentation/vm/hugetlbpage.txt +++ b/Documentation/vm/hugetlbpage.txt @@ -20,19 +20,20 @@ options. The /proc/meminfo file provides information about the total number of persistent hugetlb pages in the kernel's huge page pool. It also displays -information about the number of free, reserved and surplus huge pages and the -default huge page size. The huge page size is needed for generating the -proper alignment and size of the arguments to system calls that map huge page -regions. +default huge page size and information about the number of free, reserved +and surplus huge pages in the pool of huge pages of default size. +The huge page size is needed for generating the proper alignment and +size of the arguments to system calls that map huge page regions. The output of "cat /proc/meminfo" will include lines like: ..... -HugePages_Total: vvv -HugePages_Free: www -HugePages_Rsvd: xxx -HugePages_Surp: yyy -Hugepagesize: zzz kB +HugePages_Total: uuu +HugePages_Free: vvv +HugePages_Rsvd: www +HugePages_Surp: xxx +Hugepagesize: yyy kB +Hugetlb: zzz kB where: HugePages_Total is the size of the pool of huge pages. @@ -47,6 +48,14 @@ HugePages_Surp is short for "surplus," and is the number of huge pages in the pool above the value in /proc/sys/vm/nr_hugepages. The maximum number of surplus huge pages is controlled by /proc/sys/vm/nr_overcommit_hugepages. +Hugepagesize is the default hugepage size (in Kb). +Hugetlb is the total amount of memory (in kB), consumed by huge + pages of all sizes. + If huge pages of different sizes are in use, this number + will exceed HugePages_Total * Hugepagesize. To get more + detailed information, please, refer to + /sys/kernel/mm/hugepages (described below). + /proc/filesystems should also show a filesystem of type "hugetlbfs" configured in the kernel. diff --git a/Documentation/vm/hwpoison.txt b/Documentation/vm/hwpoison.txt index 6ae89a9edf2a..e912d7eee769 100644 --- a/Documentation/vm/hwpoison.txt +++ b/Documentation/vm/hwpoison.txt @@ -104,7 +104,7 @@ madvise(MADV_HWPOISON, ....) hwpoison-inject module through debugfs -/sys/debug/hwpoison/ +/sys/kernel/debug/hwpoison/ corrupt-pfn diff --git a/Documentation/w1/masters/w1-gpio b/Documentation/w1/masters/w1-gpio index af5d3b4aa851..623961d9e83f 100644 --- a/Documentation/w1/masters/w1-gpio +++ b/Documentation/w1/masters/w1-gpio @@ -8,17 +8,27 @@ Description ----------- GPIO 1-wire bus master driver. The driver uses the GPIO API to control the -wire and the GPIO pin can be specified using platform data. +wire and the GPIO pin can be specified using GPIO machine descriptor tables. +It is also possible to define the master using device tree, see +Documentation/devicetree/bindings/w1/w1-gpio.txt Example (mach-at91) ------------------- +#include #include +static struct gpiod_lookup_table foo_w1_gpiod_table = { + .dev_id = "w1-gpio", + .table = { + GPIO_LOOKUP_IDX("at91-gpio", AT91_PIN_PB20, NULL, 0, + GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN), + }, +}; + static struct w1_gpio_platform_data foo_w1_gpio_pdata = { - .pin = AT91_PIN_PB20, - .is_open_drain = 1, + .ext_pullup_enable_pin = -EINVAL, }; static struct platform_device foo_w1_device = { @@ -30,4 +40,5 @@ static struct platform_device foo_w1_device = { ... at91_set_GPIO_periph(foo_w1_gpio_pdata.pin, 1); at91_set_multi_drive(foo_w1_gpio_pdata.pin, 1); + gpiod_add_lookup_table(&foo_w1_gpiod_table); platform_device_register(&foo_w1_device); diff --git a/Documentation/w1/w1.generic b/Documentation/w1/w1.generic index b3ffaf8cfab2..c51b1ab012d0 100644 --- a/Documentation/w1/w1.generic +++ b/Documentation/w1/w1.generic @@ -76,7 +76,7 @@ See struct w1_bus_master definition in w1.h for details. w1 master sysfs interface ------------------------------------------------------------------ - - A directory for a found device. The format is family-serial + - A directory for a found device. The format is family-serial bus - (standard) symlink to the w1 bus driver - (standard) symlink to the w1 driver w1_master_add - (rw) manually register a slave device diff --git a/Documentation/watchdog/watchdog-parameters.txt b/Documentation/watchdog/watchdog-parameters.txt index 6f9d7b418917..beea975980f6 100644 --- a/Documentation/watchdog/watchdog-parameters.txt +++ b/Documentation/watchdog/watchdog-parameters.txt @@ -40,11 +40,6 @@ margin: Watchdog margin in seconds (default=60) nowayout: Disable watchdog shutdown on close (default=kernel config parameter) ------------------------------------------------- -at32ap700x_wdt: -timeout: Timeout value. Limited to be 1 or 2 seconds. (default=2) -nowayout: Watchdog cannot be stopped once started - (default=kernel config parameter) -------------------------------------------------- at91rm9200_wdt: wdt_time: Watchdog time in seconds. (default=5) nowayout: Watchdog cannot be stopped once started @@ -162,11 +157,6 @@ testmode: Watchdog test mode (1 = no reboot), default=0 nowayout: Watchdog cannot be stopped once started (default=kernel config parameter) ------------------------------------------------- -ixp2000_wdt: -heartbeat: Watchdog heartbeat in seconds (default 60s) -nowayout: Watchdog cannot be stopped once started - (default=kernel config parameter) -------------------------------------------------- ixp4xx_wdt: heartbeat: Watchdog heartbeat in seconds (default 60s) nowayout: Watchdog cannot be stopped once started @@ -381,19 +371,6 @@ timeout: Watchdog timeout in seconds. 1 <= timeout <= 255, default=60. nowayout: Watchdog cannot be stopped once started (default=kernel config parameter) ------------------------------------------------- -w83697hf_wdt: -wdt_io: w83697hf/hg WDT io port (default 0x2e, 0 = autodetect) -timeout: Watchdog timeout in seconds. 1<= timeout <=255 (default=60) -nowayout: Watchdog cannot be stopped once started - (default=kernel config parameter) -early_disable: Watchdog gets disabled at boot time (default=1) -------------------------------------------------- -w83697ug_wdt: -wdt_io: w83697ug/uf WDT io port (default 0x2e) -timeout: Watchdog timeout in seconds. 1<= timeout <=255 (default=60) -nowayout: Watchdog cannot be stopped once started - (default=kernel config parameter) -------------------------------------------------- w83877f_wdt: timeout: Watchdog timeout in seconds. (1<=timeout<=3600, default=30) nowayout: Watchdog cannot be stopped once started diff --git a/Documentation/x86/intel_rdt_ui.txt b/Documentation/x86/intel_rdt_ui.txt index 6851854cf69d..756fd76b78a6 100644 --- a/Documentation/x86/intel_rdt_ui.txt +++ b/Documentation/x86/intel_rdt_ui.txt @@ -7,15 +7,24 @@ Tony Luck Vikas Shivappa This feature is enabled by the CONFIG_INTEL_RDT Kconfig and the -X86 /proc/cpuinfo flag bits "rdt", "cqm", "cat_l3" and "cdp_l3". +X86 /proc/cpuinfo flag bits: +RDT (Resource Director Technology) Allocation - "rdt_a" +CAT (Cache Allocation Technology) - "cat_l3", "cat_l2" +CDP (Code and Data Prioritization ) - "cdp_l3", "cdp_l2" +CQM (Cache QoS Monitoring) - "cqm_llc", "cqm_occup_llc" +MBM (Memory Bandwidth Monitoring) - "cqm_mbm_total", "cqm_mbm_local" +MBA (Memory Bandwidth Allocation) - "mba" To use the feature mount the file system: - # mount -t resctrl resctrl [-o cdp] /sys/fs/resctrl + # mount -t resctrl resctrl [-o cdp[,cdpl2]] /sys/fs/resctrl mount options are: "cdp": Enable code/data prioritization in L3 cache allocations. +"cdpl2": Enable code/data prioritization in L2 cache allocations. + +L2 and L3 CDP are controlled seperately. RDT features are orthogonal. A particular system may support only monitoring, only control, or both monitoring and control. diff --git a/Documentation/x86/microcode.txt b/Documentation/x86/microcode.txt index f57e1b45e628..79fdb4a8148a 100644 --- a/Documentation/x86/microcode.txt +++ b/Documentation/x86/microcode.txt @@ -108,12 +108,11 @@ packages already put them there. ==================== The loader supports also loading of a builtin microcode supplied through -the regular firmware builtin method CONFIG_FIRMWARE_IN_KERNEL. Only -64-bit is currently supported. +the regular builtin firmware method CONFIG_EXTRA_FIRMWARE. Only 64-bit is +currently supported. Here's an example: -CONFIG_FIRMWARE_IN_KERNEL=y CONFIG_EXTRA_FIRMWARE="intel-ucode/06-3a-09 amd-ucode/microcode_amd_fam15h.bin" CONFIG_EXTRA_FIRMWARE_DIR="/lib/firmware" diff --git a/Documentation/x86/pti.txt b/Documentation/x86/pti.txt index d11eff61fc9a..5cd58439ad2d 100644 --- a/Documentation/x86/pti.txt +++ b/Documentation/x86/pti.txt @@ -78,7 +78,7 @@ this protection comes at a cost: non-PTI SYSCALL entry code, so requires mapping fewer things into the userspace page tables. The downside is that stacks must be switched at entry time. - d. Global pages are disabled for all kernel structures not + c. Global pages are disabled for all kernel structures not mapped into both kernel and userspace page tables. This feature of the MMU allows different processes to share TLB entries mapping the kernel. Losing the feature means more diff --git a/Documentation/xtensa/mmu.txt b/Documentation/xtensa/mmu.txt index 5de8715d5bec..318114de63f3 100644 --- a/Documentation/xtensa/mmu.txt +++ b/Documentation/xtensa/mmu.txt @@ -69,8 +69,19 @@ Default MMUv2-compatible layout. | Userspace | 0x00000000 TASK_SIZE +------------------+ 0x40000000 +------------------+ -| Page table | 0x80000000 -+------------------+ 0x80400000 +| Page table | XCHAL_PAGE_TABLE_VADDR 0x80000000 XCHAL_PAGE_TABLE_SIZE ++------------------+ +| KASAN shadow map | KASAN_SHADOW_START 0x80400000 KASAN_SHADOW_SIZE ++------------------+ 0x8e400000 ++------------------+ +| VMALLOC area | VMALLOC_START 0xc0000000 128MB - 64KB ++------------------+ VMALLOC_END +| Cache aliasing | TLBTEMP_BASE_1 0xc7ff0000 DCACHE_WAY_SIZE +| remap area 1 | ++------------------+ +| Cache aliasing | TLBTEMP_BASE_2 DCACHE_WAY_SIZE +| remap area 2 | ++------------------+ +------------------+ | KMAP area | PKMAP_BASE PTRS_PER_PTE * | | DCACHE_N_COLORS * @@ -81,16 +92,7 @@ Default MMUv2-compatible layout. | | NR_CPUS * | | DCACHE_N_COLORS * | | PAGE_SIZE -+------------------+ FIXADDR_TOP 0xbffff000 -+------------------+ -| VMALLOC area | VMALLOC_START 0xc0000000 128MB - 64KB -+------------------+ VMALLOC_END -| Cache aliasing | TLBTEMP_BASE_1 0xc7ff0000 DCACHE_WAY_SIZE -| remap area 1 | -+------------------+ -| Cache aliasing | TLBTEMP_BASE_2 DCACHE_WAY_SIZE -| remap area 2 | -+------------------+ ++------------------+ FIXADDR_TOP 0xcffff000 +------------------+ | Cached KSEG | XCHAL_KSEG_CACHED_VADDR 0xd0000000 128MB +------------------+ @@ -109,8 +111,19 @@ Default MMUv2-compatible layout. | Userspace | 0x00000000 TASK_SIZE +------------------+ 0x40000000 +------------------+ -| Page table | 0x80000000 -+------------------+ 0x80400000 +| Page table | XCHAL_PAGE_TABLE_VADDR 0x80000000 XCHAL_PAGE_TABLE_SIZE ++------------------+ +| KASAN shadow map | KASAN_SHADOW_START 0x80400000 KASAN_SHADOW_SIZE ++------------------+ 0x8e400000 ++------------------+ +| VMALLOC area | VMALLOC_START 0xa0000000 128MB - 64KB ++------------------+ VMALLOC_END +| Cache aliasing | TLBTEMP_BASE_1 0xa7ff0000 DCACHE_WAY_SIZE +| remap area 1 | ++------------------+ +| Cache aliasing | TLBTEMP_BASE_2 DCACHE_WAY_SIZE +| remap area 2 | ++------------------+ +------------------+ | KMAP area | PKMAP_BASE PTRS_PER_PTE * | | DCACHE_N_COLORS * @@ -121,16 +134,7 @@ Default MMUv2-compatible layout. | | NR_CPUS * | | DCACHE_N_COLORS * | | PAGE_SIZE -+------------------+ FIXADDR_TOP 0x9ffff000 -+------------------+ -| VMALLOC area | VMALLOC_START 0xa0000000 128MB - 64KB -+------------------+ VMALLOC_END -| Cache aliasing | TLBTEMP_BASE_1 0xa7ff0000 DCACHE_WAY_SIZE -| remap area 1 | -+------------------+ -| Cache aliasing | TLBTEMP_BASE_2 DCACHE_WAY_SIZE -| remap area 2 | -+------------------+ ++------------------+ FIXADDR_TOP 0xaffff000 +------------------+ | Cached KSEG | XCHAL_KSEG_CACHED_VADDR 0xb0000000 256MB +------------------+ @@ -150,19 +154,10 @@ Default MMUv2-compatible layout. | Userspace | 0x00000000 TASK_SIZE +------------------+ 0x40000000 +------------------+ -| Page table | 0x80000000 -+------------------+ 0x80400000 +| Page table | XCHAL_PAGE_TABLE_VADDR 0x80000000 XCHAL_PAGE_TABLE_SIZE +------------------+ -| KMAP area | PKMAP_BASE PTRS_PER_PTE * -| | DCACHE_N_COLORS * -| | PAGE_SIZE -| | (4MB * DCACHE_N_COLORS) -+------------------+ -| Atomic KMAP area | FIXADDR_START KM_TYPE_NR * -| | NR_CPUS * -| | DCACHE_N_COLORS * -| | PAGE_SIZE -+------------------+ FIXADDR_TOP 0x8ffff000 +| KASAN shadow map | KASAN_SHADOW_START 0x80400000 KASAN_SHADOW_SIZE ++------------------+ 0x8e400000 +------------------+ | VMALLOC area | VMALLOC_START 0x90000000 128MB - 64KB +------------------+ VMALLOC_END @@ -173,6 +168,17 @@ Default MMUv2-compatible layout. | remap area 2 | +------------------+ +------------------+ +| KMAP area | PKMAP_BASE PTRS_PER_PTE * +| | DCACHE_N_COLORS * +| | PAGE_SIZE +| | (4MB * DCACHE_N_COLORS) ++------------------+ +| Atomic KMAP area | FIXADDR_START KM_TYPE_NR * +| | NR_CPUS * +| | DCACHE_N_COLORS * +| | PAGE_SIZE ++------------------+ FIXADDR_TOP 0x9ffff000 ++------------------+ | Cached KSEG | XCHAL_KSEG_CACHED_VADDR 0xa0000000 512MB +------------------+ | Uncached KSEG | XCHAL_KSEG_BYPASS_VADDR 0xc0000000 512MB diff --git a/LICENSES/exceptions/Linux-syscall-note b/LICENSES/exceptions/Linux-syscall-note new file mode 100644 index 000000000000..6b60b61be4e9 --- /dev/null +++ b/LICENSES/exceptions/Linux-syscall-note @@ -0,0 +1,25 @@ +SPDX-Exception-Identifier: Linux-syscall-note +SPDX-URL: https://spdx.org/licenses/Linux-syscall-note.html +SPDX-Licenses: GPL-2.0, GPL-2.0+, GPL-1.0+, LGPL-2.0, LGPL-2.0+, LGPL-2.1, LGPL-2.1+ +Usage-Guide: + This exception is used together with one of the above SPDX-Licenses + to mark user space API (uapi) header files so they can be included + into non GPL compliant user space application code. + To use this exception add it with the keyword WITH to one of the + identifiers in the SPDX-Licenses tag: + SPDX-License-Identifier: WITH Linux-syscall-note +License-Text: + + NOTE! This copyright does *not* cover user programs that use kernel + services by normal system calls - this is merely considered normal use + of the kernel, and does *not* fall under the heading of "derived work". + Also note that the GPL below is copyrighted by the Free Software + Foundation, but the instance of code that it refers to (the Linux + kernel) is copyrighted by me and others who actually wrote it. + + Also note that the only valid version of the GPL as far as the kernel + is concerned is _this_ particular version of the license (ie v2, not + v2.2 or v3.x or whatever), unless explicitly otherwise stated. + + Linus Torvalds + diff --git a/LICENSES/other/GPL-1.0 b/LICENSES/other/GPL-1.0 new file mode 100644 index 000000000000..3a4fa969e4c2 --- /dev/null +++ b/LICENSES/other/GPL-1.0 @@ -0,0 +1,260 @@ +Valid-License-Identifier: GPL-1.0+ +SPDX-URL: https://spdx.org/licenses/GPL-1.0.html +Usage-Guide: + The GNU General Public License (GPL) version 1 should not be used in new + code. For existing kernel code the 'or any later version' option is + required to be compatible with the general license of the project: GPLv2. + To use the license in source code, put the following SPDX tag/value pair + into a comment according to the placement guidelines in the licensing + rules documentation: + SPDX-License-Identifier: GPL-1.0+ +License-Text: + + GNU GENERAL PUBLIC LICENSE + Version 1, February 1989 + + Copyright (C) 1989 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The license agreements of most software companies try to keep users +at the mercy of those companies. By contrast, our General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. The +General Public License applies to the Free Software Foundation's +software and to any other program whose authors commit to using it. +You can use it for your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Specifically, the General Public License is designed to make +sure that you have the freedom to give away or sell copies of free +software, that you receive source code or can get it if you want it, +that you can change the software or use pieces of it in new free +programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of a such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must tell them their rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any program or other work which +contains a notice placed by the copyright holder saying it may be +distributed under the terms of this General Public License. The +"Program", below, refers to any such program or work, and a "work based +on the Program" means either the Program or any work containing the +Program or a portion of it, either verbatim or with modifications. Each +licensee is addressed as "you". + + 1. You may copy and distribute verbatim copies of the Program's source +code as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this +General Public License and to the absence of any warranty; and give any +other recipients of the Program a copy of this General Public License +along with the Program. You may charge a fee for the physical act of +transferring a copy. + + 2. You may modify your copy or copies of the Program or any portion of +it, and copy and distribute such modifications under the terms of Paragraph +1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating that + you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, that + in whole or in part contains the Program or any part thereof, either + with or without modifications, to be licensed at no charge to all + third parties under the terms of this General Public License (except + that you may choose to grant warranty protection to some or all + third parties, at your option). + + c) If the modified program normally reads commands interactively when + run, you must cause it, when started running for such interactive use + in the simplest and most usual way, to print or display an + announcement including an appropriate copyright notice and a notice + that there is no warranty (or else, saying that you provide a + warranty) and that users may redistribute the program under these + conditions, and telling the user how to view a copy of this General + Public License. + + d) You may charge a fee for the physical act of transferring a + copy, and you may at your option offer warranty protection in + exchange for a fee. + +Mere aggregation of another independent work with the Program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other work under the scope of these terms. + + 3. You may copy and distribute the Program (or a portion or derivative of +it, under Paragraph 2) in object code or executable form under the terms of +Paragraphs 1 and 2 above provided that you also do one of the following: + + a) accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of + Paragraphs 1 and 2 above; or, + + b) accompany it with a written offer, valid for at least three + years, to give any third party free (except for a nominal charge + for the cost of distribution) a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Paragraphs 1 and 2 above; or, + + c) accompany it with the information you received as to where the + corresponding source code may be obtained. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form alone.) + +Source code for a work means the preferred form of the work for making +modifications to it. For an executable file, complete source code means +all the source code for all modules it contains; but, as a special +exception, it need not include source code for modules which are standard +libraries that accompany the operating system on which the executable +file runs, or for standard header files or definitions files that +accompany that operating system. + + 4. You may not copy, modify, sublicense, distribute or transfer the +Program except as expressly provided under this General Public License. +Any attempt otherwise to copy, modify, sublicense, distribute or transfer +the Program is void, and will automatically terminate your rights to use +the Program under this License. However, parties who have received +copies, or rights to use copies, from you under this General Public +License will not have their licenses terminated so long as such parties +remain in full compliance. + + 5. By copying, distributing or modifying the Program (or any work based +on the Program) you indicate your acceptance of this license to do so, +and all its terms and conditions. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the original +licensor to copy, distribute or modify the Program subject to these +terms and conditions. You may not impose any further restrictions on the +recipients' exercise of the rights granted herein. + + 7. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of the license which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +the license, you may choose any version ever published by the Free Software +Foundation. + + 8. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to humanity, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + + To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively convey +the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19xx name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and `show +c'; they could even be mouse-clicks or menu items--whatever suits your +program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + program `Gnomovision' (a program to direct compilers to make passes + at assemblers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/LICENSES/other/MPL-1.1 b/LICENSES/other/MPL-1.1 new file mode 100644 index 000000000000..568b6049efe6 --- /dev/null +++ b/LICENSES/other/MPL-1.1 @@ -0,0 +1,478 @@ +Valid-License-Identifier: MPL-1.1 +SPDX-URL: https://spdx.org/licenses/MPL-1.1.html +Usage-Guide: + To use the Mozilla Public License version 1.1 put the following SPDX + tag/value pair into a comment according to the placement guidelines in + the licensing rules documentation: + SPDX-License-Identifier: MPL-1.1 +License-Text: + + MOZILLA PUBLIC LICENSE + Version 1.1 + + --------------- + +1. Definitions. + + 1.0.1. "Commercial Use" means distribution or otherwise making the + Covered Code available to a third party. + + 1.1. "Contributor" means each entity that creates or contributes to + the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Code, prior Modifications used by a Contributor, and the Modifications + made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the + combination of the Original Code and Modifications, in each case + including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism generally + accepted in the software development community for the electronic + transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source + Code. + + 1.6. "Initial Developer" means the individual or entity identified + as the Initial Developer in the Source Code notice required by Exhibit + A. + + 1.7. "Larger Work" means a work which combines Covered Code or + portions thereof with code not governed by the terms of this License. + + 1.8. "License" means this document. + + 1.8.1. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means any addition to or deletion from the + substance or structure of either the Original Code or any previous + Modifications. When Covered Code is released as a series of files, a + Modification is: + A. Any addition to or deletion from the contents of a file + containing Original Code or previous Modifications. + + B. Any new file that contains any part of the Original Code or + previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code + which is described in the Source Code notice required by Exhibit A as + Original Code, and which, at the time of its release under this + License is not already Covered Code governed by this License. + + 1.10.1. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, process, + and apparatus claims, in any patent Licensable by grantor. + + 1.11. "Source Code" means the preferred form of the Covered Code for + making modifications to it, including all modules it contains, plus + any associated interface definition files, scripts used to control + compilation and installation of an Executable, or source code + differential comparisons against either the Original Code or another + well known, available Covered Code of the Contributor's choice. The + Source Code can be in a compressed or archival form, provided the + appropriate decompression or de-archiving software is widely available + for no charge. + + 1.12. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms of, this + License or a future version of this License issued under Section 6.1. + For legal entities, "You" includes any entity which controls, is + controlled by, or is under common control with You. For purposes of + this definition, "control" means (a) the power, direct or indirect, + to cause the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty percent + (50%) of the outstanding shares or beneficial ownership of such + entity. + +2. Source Code License. + + 2.1. The Initial Developer Grant. + The Initial Developer hereby grants You a world-wide, royalty-free, + non-exclusive license, subject to third party intellectual property + claims: + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer to use, reproduce, + modify, display, perform, sublicense and distribute the Original + Code (or portions thereof) with or without Modifications, and/or + as part of a Larger Work; and + + (b) under Patents Claims infringed by the making, using or + selling of Original Code, to make, have made, use, practice, + sell, and offer for sale, and/or otherwise dispose of the + Original Code (or portions thereof). + + (c) the licenses granted in this Section 2.1(a) and (b) are + effective on the date Initial Developer first distributes + Original Code under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: 1) for code that You delete from the Original Code; 2) + separate from the Original Code; or 3) for infringements caused + by: i) the modification of the Original Code or ii) the + combination of the Original Code with other software or devices. + + 2.2. Contributor Grant. + Subject to third party intellectual property claims, each Contributor + hereby grants You a world-wide, royalty-free, non-exclusive license + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor, to use, reproduce, modify, + display, perform, sublicense and distribute the Modifications + created by such Contributor (or portions thereof) either on an + unmodified basis, with other Modifications, as Covered Code + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either alone + and/or in combination with its Contributor Version (or portions + of such combination), to make, use, sell, offer for sale, have + made, and/or otherwise dispose of: 1) Modifications made by that + Contributor (or portions thereof); and 2) the combination of + Modifications made by that Contributor with its Contributor + Version (or portions of such combination). + + (c) the licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first makes Commercial Use of + the Covered Code. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: 1) for any code that Contributor has deleted from the + Contributor Version; 2) separate from the Contributor Version; + 3) for infringements caused by: i) third party modifications of + Contributor Version or ii) the combination of Modifications made + by that Contributor with other software (except as part of the + Contributor Version) or other devices; or 4) under Patent Claims + infringed by Covered Code in the absence of Modifications made by + that Contributor. + +3. Distribution Obligations. + + 3.1. Application of License. + The Modifications which You create or to which You contribute are + governed by the terms of this License, including without limitation + Section 2.2. The Source Code version of Covered Code may be + distributed only under the terms of this License or a future version + of this License released under Section 6.1, and You must include a + copy of this License with every copy of the Source Code You + distribute. You may not offer or impose any terms on any Source Code + version that alters or restricts the applicable version of this + License or the recipients' rights hereunder. However, You may include + an additional document offering the additional rights described in + Section 3.5. + + 3.2. Availability of Source Code. + Any Modification which You create or to which You contribute must be + made available in Source Code form under the terms of this License + either on the same media as an Executable version or via an accepted + Electronic Distribution Mechanism to anyone to whom you made an + Executable version available; and if made available via Electronic + Distribution Mechanism, must remain available for at least twelve (12) + months after the date it initially became available, or at least six + (6) months after a subsequent version of that particular Modification + has been made available to such recipients. You are responsible for + ensuring that the Source Code version remains available even if the + Electronic Distribution Mechanism is maintained by a third party. + + 3.3. Description of Modifications. + You must cause all Covered Code to which You contribute to contain a + file documenting the changes You made to create that Covered Code and + the date of any change. You must include a prominent statement that + the Modification is derived, directly or indirectly, from Original + Code provided by the Initial Developer and including the name of the + Initial Developer in (a) the Source Code, and (b) in any notice in an + Executable version or related documentation in which You describe the + origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + (a) Third Party Claims. + If Contributor has knowledge that a license under a third party's + intellectual property rights is required to exercise the rights + granted by such Contributor under Sections 2.1 or 2.2, + Contributor must include a text file with the Source Code + distribution titled "LEGAL" which describes the claim and the + party making the claim in sufficient detail that a recipient will + know whom to contact. If Contributor obtains such knowledge after + the Modification is made available as described in Section 3.2, + Contributor shall promptly modify the LEGAL file in all copies + Contributor makes available thereafter and shall take other steps + (such as notifying appropriate mailing lists or newsgroups) + reasonably calculated to inform those who received the Covered + Code that new knowledge has been obtained. + + (b) Contributor APIs. + If Contributor's Modifications include an application programming + interface and Contributor has knowledge of patent licenses which + are reasonably necessary to implement that API, Contributor must + also include this information in the LEGAL file. + + (c) Representations. + Contributor represents that, except as disclosed pursuant to + Section 3.4(a) above, Contributor believes that Contributor's + Modifications are Contributor's original creation(s) and/or + Contributor has sufficient rights to grant the rights conveyed by + this License. + + 3.5. Required Notices. + You must duplicate the notice in Exhibit A in each file of the Source + Code. If it is not possible to put such notice in a particular Source + Code file due to its structure, then You must include such notice in a + location (such as a relevant directory) where a user would be likely + to look for such a notice. If You created one or more Modification(s) + You may add your name as a Contributor to the notice described in + Exhibit A. You must also duplicate this License in any documentation + for the Source Code where You describe recipients' rights or ownership + rights relating to Covered Code. You may choose to offer, and to + charge a fee for, warranty, support, indemnity or liability + obligations to one or more recipients of Covered Code. However, You + may do so only on Your own behalf, and not on behalf of the Initial + Developer or any Contributor. You must make it absolutely clear than + any such warranty, support, indemnity or liability obligation is + offered by You alone, and You hereby agree to indemnify the Initial + Developer and every Contributor for any liability incurred by the + Initial Developer or such Contributor as a result of warranty, + support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. + You may distribute Covered Code in Executable form only if the + requirements of Section 3.1-3.5 have been met for that Covered Code, + and if You include a notice stating that the Source Code version of + the Covered Code is available under the terms of this License, + including a description of how and where You have fulfilled the + obligations of Section 3.2. The notice must be conspicuously included + in any notice in an Executable version, related documentation or + collateral in which You describe recipients' rights relating to the + Covered Code. You may distribute the Executable version of Covered + Code or ownership rights under a license of Your choice, which may + contain terms different from this License, provided that You are in + compliance with the terms of this License and that the license for the + Executable version does not attempt to limit or alter the recipient's + rights in the Source Code version from the rights set forth in this + License. If You distribute the Executable version under a different + license You must make it absolutely clear that any terms which differ + from this License are offered by You alone, not by the Initial + Developer or any Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred by + the Initial Developer or such Contributor as a result of any such + terms You offer. + + 3.7. Larger Works. + You may create a Larger Work by combining Covered Code with other code + not governed by the terms of this License and distribute the Larger + Work as a single product. In such a case, You must make sure the + requirements of this License are fulfilled for the Covered Code. + +4. Inability to Comply Due to Statute or Regulation. + + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Code due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description + must be included in the LEGAL file described in Section 3.4 and must + be included with all distributions of the Source Code. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Application of this License. + + This License applies to code to which the Initial Developer has + attached the notice in Exhibit A and to related Covered Code. + +6. Versions of the License. + + 6.1. New Versions. + Netscape Communications Corporation ("Netscape") may publish revised + and/or new versions of the License from time to time. Each version + will be given a distinguishing version number. + + 6.2. Effect of New Versions. + Once Covered Code has been published under a particular version of the + License, You may always continue to use it under the terms of that + version. You may also choose to use such Covered Code under the terms + of any subsequent version of the License published by Netscape. No one + other than Netscape has the right to modify the terms applicable to + Covered Code created under this License. + + 6.3. Derivative Works. + If You create or use a modified version of this License (which you may + only do in order to apply it to code which is not already Covered Code + governed by this License), You must (a) rename Your license so that + the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", + "MPL", "NPL" or any confusingly similar phrase do not appear in your + license (except to note that your license differs from this License) + and (b) otherwise make it clear that Your version of the license + contains terms which differ from the Mozilla Public License and + Netscape Public License. (Filling in the name of the Initial + Developer, Original Code or Contributor in the notice described in + Exhibit A shall not of themselves be deemed to be modifications of + this License.) + +7. DISCLAIMER OF WARRANTY. + + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF + DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE + IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, + YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE + COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER + OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +8. TERMINATION. + + 8.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to cure + such breach within 30 days of becoming aware of the breach. All + sublicenses to the Covered Code which are properly granted shall + survive any termination of this License. Provisions which, by their + nature, must remain in effect beyond the termination of this License + shall survive. + + 8.2. If You initiate litigation by asserting a patent infringement + claim (excluding declatory judgment actions) against Initial Developer + or a Contributor (the Initial Developer or Contributor against whom + You file such action is referred to as "Participant") alleging that: + + (a) such Participant's Contributor Version directly or indirectly + infringes any patent, then any and all rights granted by such + Participant to You under Sections 2.1 and/or 2.2 of this License + shall, upon 60 days notice from Participant terminate prospectively, + unless if within 60 days after receipt of notice You either: (i) + agree in writing to pay Participant a mutually agreeable reasonable + royalty for Your past and future use of Modifications made by such + Participant, or (ii) withdraw Your litigation claim with respect to + the Contributor Version against such Participant. If within 60 days + of notice, a reasonable royalty and payment arrangement are not + mutually agreed upon in writing by the parties or the litigation claim + is not withdrawn, the rights granted by Participant to You under + Sections 2.1 and/or 2.2 automatically terminate at the expiration of + the 60 day notice period specified above. + + (b) any software, hardware, or device, other than such Participant's + Contributor Version, directly or indirectly infringes any patent, then + any rights granted to You by such Participant under Sections 2.1(b) + and 2.2(b) are revoked effective as of the date You first made, used, + sold, distributed, or had made, Modifications made by that + Participant. + + 8.3. If You assert a patent infringement claim against Participant + alleging that such Participant's Contributor Version directly or + indirectly infringes any patent where such claim is resolved (such as + by license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, + all end user license agreements (excluding distributors and resellers) + which have been validly granted by You or any distributor hereunder + prior to termination shall survive termination. + +9. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL + DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, + OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR + ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY + CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, + WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO + THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. GOVERNMENT END USERS. + + The Covered Code is a "commercial item," as that term is defined in + 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer + software" and "commercial computer software documentation," as such + terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 + C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), + all U.S. Government End Users acquire Covered Code with only those + rights set forth herein. + +11. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed by + California law provisions (except to the extent applicable law, if + any, provides otherwise), excluding its conflict-of-law provisions. + With respect to disputes in which at least one party is a citizen of, + or an entity chartered or registered to do business in the United + States of America, any litigation relating to this License shall be + subject to the jurisdiction of the Federal Courts of the Northern + District of California, with venue lying in Santa Clara County, + California, with the losing party responsible for costs, including + without limitation, court costs and reasonable attorneys' fees and + expenses. The application of the United Nations Convention on + Contracts for the International Sale of Goods is expressly excluded. + Any law or regulation which provides that the language of a contract + shall be construed against the drafter shall not apply to this + License. + +12. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or indirectly, + out of its utilization of rights under this License and You agree to + work with Initial Developer and Contributors to distribute such + responsibility on an equitable basis. Nothing herein is intended or + shall be deemed to constitute any admission of liability. + +13. MULTIPLE-LICENSED CODE. + + Initial Developer may designate portions of the Covered Code as + "Multiple-Licensed". "Multiple-Licensed" means that the Initial + Developer permits you to utilize portions of the Covered Code under + Your choice of the MPL or the alternative licenses, if any, specified + by the Initial Developer in the file described in Exhibit A. + +EXHIBIT A -Mozilla Public License. + + ``The contents of this file are subject to the Mozilla Public License + Version 1.1 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + https://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + License for the specific language governing rights and limitations + under the License. + + The Original Code is ______________________________________. + + The Initial Developer of the Original Code is ________________________. + Portions created by ______________________ are Copyright (C) ______ + _______________________. All Rights Reserved. + + Contributor(s): ______________________________________. + + Alternatively, the contents of this file may be used under the terms + of the _____ license (the "[___] License"), in which case the + provisions of [______] License are applicable instead of those + above. If you wish to allow use of your version of this file only + under the terms of the [____] License and not to allow others to use + your version of this file under the MPL, indicate your decision by + deleting the provisions above and replace them with the notice and + other provisions required by the [___] License. If you do not delete + the provisions above, a recipient may use your version of this file + under either the MPL or the [___] License." + + [NOTE: The text of this Exhibit A may differ slightly from the text of + the notices in the Source Code files of the Original Code. You should + use the text of this Exhibit A rather than the text found in the + Original Code Source Code for Your Modifications.] diff --git a/LICENSES/preferred/BSD-2-Clause b/LICENSES/preferred/BSD-2-Clause new file mode 100644 index 000000000000..da366e2ce50b --- /dev/null +++ b/LICENSES/preferred/BSD-2-Clause @@ -0,0 +1,32 @@ +Valid-License-Identifier: BSD-2-Clause +SPDX-URL: https://spdx.org/licenses/BSD-2-Clause.html +Usage-Guide: + To use the BSD 2-clause "Simplified" License put the following SPDX + tag/value pair into a comment according to the placement guidelines in + the licensing rules documentation: + SPDX-License-Identifier: BSD-2-Clause +License-Text: + +Copyright (c) . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSES/preferred/BSD-3-Clause b/LICENSES/preferred/BSD-3-Clause new file mode 100644 index 000000000000..34c7f057c8d5 --- /dev/null +++ b/LICENSES/preferred/BSD-3-Clause @@ -0,0 +1,36 @@ +Valid-License-Identifier: BSD-3-Clause +SPDX-URL: https://spdx.org/licenses/BSD-3-Clause.html +Usage-Guide: + To use the BSD 3-clause "New" or "Revised" License put the following SPDX + tag/value pair into a comment according to the placement guidelines in + the licensing rules documentation: + SPDX-License-Identifier: BSD-3-Clause +License-Text: + +Copyright (c) . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSES/preferred/BSD-3-Clause-Clear b/LICENSES/preferred/BSD-3-Clause-Clear new file mode 100644 index 000000000000..e53b56092b90 --- /dev/null +++ b/LICENSES/preferred/BSD-3-Clause-Clear @@ -0,0 +1,41 @@ +Valid-License-Identifier: BSD-3-Clause-Clear +SPDX-URL: https://spdx.org/licenses/BSD-3-Clause-Clear.html +Usage-Guide: + To use the BSD 3-clause "Clear" License put the following SPDX + tag/value pair into a comment according to the placement guidelines in + the licensing rules documentation: + SPDX-License-Identifier: BSD-3-Clause-Clear +License-Text: + +The Clear BSD License + +Copyright (c) [xxxx]-[xxxx] [Owner Organization] +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted (subject to the limitations in the disclaimer +below) provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of [Owner Organization] nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY +THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSES/preferred/GPL-2.0 b/LICENSES/preferred/GPL-2.0 new file mode 100644 index 000000000000..b8db91d3a1cb --- /dev/null +++ b/LICENSES/preferred/GPL-2.0 @@ -0,0 +1,353 @@ +Valid-License-Identifier: GPL-2.0 +Valid-License-Identifier: GPL-2.0+ +SPDX-URL: https://spdx.org/licenses/GPL-2.0.html +Usage-Guide: + To use this license in source code, put one of the following SPDX + tag/value pairs into a comment according to the placement + guidelines in the licensing rules documentation. + For 'GNU General Public License (GPL) version 2 only' use: + SPDX-License-Identifier: GPL-2.0 + For 'GNU General Public License (GPL) version 2 or any later version' use: + SPDX-License-Identifier: GPL-2.0+ +License-Text: + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/LICENSES/preferred/LGPL-2.0 b/LICENSES/preferred/LGPL-2.0 new file mode 100644 index 000000000000..957d798fe037 --- /dev/null +++ b/LICENSES/preferred/LGPL-2.0 @@ -0,0 +1,487 @@ +Valid-License-Identifier: LGPL-2.0 +Valid-License-Identifier: LGPL-2.0+ +SPDX-URL: https://spdx.org/licenses/LGPL-2.0.html +Usage-Guide: + To use this license in source code, put one of the following SPDX + tag/value pairs into a comment according to the placement + guidelines in the licensing rules documentation. + For 'GNU Library General Public License (LGPL) version 2.0 only' use: + SPDX-License-Identifier: LGPL-2.0 + For 'GNU Library General Public License (LGPL) version 2.0 or any later + version' use: + SPDX-License-Identifier: LGPL-2.0+ +License-Text: + +GNU LIBRARY GENERAL PUBLIC LICENSE +Version 2, June 1991 + +Copyright (C) 1991 Free Software Foundation, Inc. +51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is numbered 2 +because it goes with version 2 of the ordinary GPL.] + +Preamble + +The licenses for most software are designed to take away your freedom to +share and change it. By contrast, the GNU General Public Licenses are +intended to guarantee your freedom to share and change free software--to +make sure the software is free for all its users. + +This license, the Library General Public License, applies to some specially +designated Free Software Foundation software, and to any other libraries +whose authors decide to use it. You can use it for your libraries, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom +to distribute copies of free software (and charge for this service if you +wish), that you receive source code or can get it if you want it, that you +can change the software or use pieces of it in new free programs; and that +you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to +deny you these rights or to ask you to surrender the rights. These +restrictions translate to certain responsibilities for you if you +distribute copies of the library, or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for +a fee, you must give the recipients all the rights that we gave you. You +must make sure that they, too, receive or can get the source code. If you +link a program with the library, you must provide complete object files to +the recipients so that they can relink them with the library, after making +changes to the library and recompiling it. And you must show them these +terms so they know their rights. + +Our method of protecting your rights has two steps: (1) copyright the +library, and (2) offer you this license which gives you legal permission to +copy, distribute and/or modify the library. + +Also, for each distributor's protection, we want to make certain that +everyone understands that there is no warranty for this free library. If +the library is modified by someone else and passed on, we want its +recipients to know that what they have is not the original version, so that +any problems introduced by others will not reflect on the original authors' +reputations. + +Finally, any free program is threatened constantly by software patents. We +wish to avoid the danger that companies distributing free software will +individually obtain patent licenses, thus in effect transforming the +program into proprietary software. To prevent this, we have made it clear +that any patent must be licensed for everyone's free use or not licensed at +all. + +Most GNU software, including some libraries, is covered by the ordinary GNU +General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + +The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + +Because of this blurred distinction, using the ordinary General Public +License for libraries did not effectively promote software sharing, because +most developers did not use the libraries. We concluded that weaker +conditions might promote sharing better. + +However, unrestricted linking of non-free programs would deprive the users +of those programs of all benefit from the free status of the libraries +themselves. This Library General Public License is intended to permit +developers of non-free programs to use free libraries, while preserving +your freedom as a user of such programs to change the free libraries that +are incorporated in them. (We have not seen how to achieve this as regards +changes in header files, but we have achieved it as regards changes in the +actual functions of the Library.) The hope is that this will lead to faster +development of free libraries. + +The precise terms and conditions for copying, distribution and modification +follow. Pay close attention to the difference between a "work based on the +library" and a "work that uses the library". The former contains code +derived from the library, while the latter only works together with the +library. + +Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library which contains a + notice placed by the copyright holder or other authorized party saying + it may be distributed under the terms of this Library General Public + License (also called "this License"). Each licensee is addressed as + "you". + + A "library" means a collection of software functions and/or data + prepared so as to be conveniently linked with application programs + (which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work which + has been distributed under these terms. A "work based on the Library" + means either the Library or any derivative work under copyright law: + that is to say, a work containing the Library or a portion of it, either + verbatim or with modifications and/or translated straightforwardly into + another language. (Hereinafter, translation is included without + limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for making + modifications to it. For a library, complete source code means all the + source code for all modules it contains, plus any associated interface + definition files, plus the scripts used to control compilation and + installation of the library. + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of running + a program using the Library is not restricted, and output from such a + program is covered only if its contents constitute a work based on the + Library (independent of the use of the Library in a tool for writing + it). Whether that is true depends on what the Library does and what the + program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete + source code as you receive it, in any medium, provided that you + conspicuously and appropriately publish on each copy an appropriate + copyright notice and disclaimer of warranty; keep intact all the notices + that refer to this License and to the absence of any warranty; and + distribute a copy of this License along with the Library. + + You may charge a fee for the physical act of transferring a copy, and + you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of it, + thus forming a work based on the Library, and copy and distribute such + modifications or work under the terms of Section 1 above, provided that + you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices stating + that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no charge to + all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a table + of data to be supplied by an application program that uses the + facility, other than as an argument passed when the facility is + invoked, then you must make a good faith effort to ensure that, in + the event an application does not supply such function or table, the + facility still operates, and performs whatever part of its purpose + remains meaningful. + + (For example, a function in a library to compute square roots has a + purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must be + optional: if the application does not supply it, the square root + function must still compute square roots.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Library, and + can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based on + the Library, the distribution of the whole must be on the terms of this + License, whose permissions for other licensees extend to the entire + whole, and thus to each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Library. + + In addition, mere aggregation of another work not based on the Library + with the Library (or with a work based on the Library) on a volume of a + storage or distribution medium does not bring the other work under the + scope of this License. + +3. You may opt to apply the terms of the ordinary GNU General Public + License instead of this License to a given copy of the Library. To do + this, you must alter all the notices that refer to this License, so that + they refer to the ordinary GNU General Public License, version 2, + instead of to this License. (If a newer version than version 2 of the + ordinary GNU General Public License has appeared, then you can specify + that version instead if you wish.) Do not make any other change in these + notices. + + Once this change is made in a given copy, it is irreversible for that + copy, so the ordinary GNU General Public License applies to all + subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of the + Library into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of + it, under Section 2) in object code or executable form under the terms + of Sections 1 and 2 above provided that you accompany it with the + complete corresponding machine-readable source code, which must be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange. + + If distribution of object code is made by offering access to copy from a + designated place, then offering equivalent access to copy the source + code from the same place satisfies the requirement to distribute the + source code, even though third parties are not compelled to copy the + source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but + is designed to work with the Library by being compiled or linked with + it, is called a "work that uses the Library". Such a work, in isolation, + is not a derivative work of the Library, and therefore falls outside the + scope of this License. + + However, linking a "work that uses the Library" with the Library creates + an executable that is a derivative of the Library (because it contains + portions of the Library), rather than a "work that uses the + library". The executable is therefore covered by this License. Section 6 + states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file + that is part of the Library, the object code for the work may be a + derivative work of the Library even though the source code is + not. Whether this is true is especially significant if the work can be + linked without the Library, or if the work is itself a library. The + threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data structure + layouts and accessors, and small macros and small inline functions (ten + lines or less in length), then the use of the object file is + unrestricted, regardless of whether it is legally a derivative + work. (Executables containing this object code plus portions of the + Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may + distribute the object code for the work under the terms of Section + 6. Any executables containing that work also fall under Section 6, + whether or not they are linked directly with the Library itself. + +6. As an exception to the Sections above, you may also compile or link a + "work that uses the Library" with the Library to produce a work + containing portions of the Library, and distribute that work under terms + of your choice, provided that the terms permit modification of the work + for the customer's own use and reverse engineering for debugging such + modifications. + + You must give prominent notice with each copy of the work that the + Library is used in it and that the Library and its use are covered by + this License. You must supply a copy of this License. If the work during + execution displays copyright notices, you must include the copyright + notice for the Library among them, as well as a reference directing the + user to the copy of this License. Also, you must do one of these things: + + a) Accompany the work with the complete corresponding machine-readable + source code for the Library including whatever changes were used in + the work (which must be distributed under Sections 1 and 2 above); + and, if the work is an executable linked with the Library, with the + complete machine-readable "work that uses the Library", as object + code and/or source code, so that the user can modify the Library and + then relink to produce a modified executable containing the modified + Library. (It is understood that the user who changes the contents of + definitions files in the Library will not necessarily be able to + recompile the application to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at least three + years, to give the same user the materials specified in Subsection + 6a, above, for a charge no more than the cost of performing this + distribution. + + c) If distribution of the work is made by offering access to copy from a + designated place, offer equivalent access to copy the above specified + materials from the same place. + + d) Verify that the user has already received a copy of these materials + or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the Library" + must include any data and utility programs needed for reproducing the + executable from it. However, as a special exception, the source code + distributed need not include anything that is normally distributed (in + either source or binary form) with the major components (compiler, + kernel, and so on) of the operating system on which the executable runs, + unless that component itself accompanies the executable. + + It may happen that this requirement contradicts the license restrictions + of other proprietary libraries that do not normally accompany the + operating system. Such a contradiction means you cannot use both them + and the Library together in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library + side-by-side in a single library together with other library facilities + not covered by this License, and distribute such a combined library, + provided that the separate distribution of the work based on the Library + and of the other library facilities is otherwise permitted, and provided + that you do these two things: + + a) Accompany the combined library with a copy of the same work based on + the Library, uncombined with any other library facilities. This must + be distributed under the terms of the Sections above. + + b) Give prominent notice with the combined library of the fact that part + of it is a work based on the Library, and explaining where to find + the accompanying uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the + Library except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense, link with, or distribute the + Library is void, and will automatically terminate your rights under this + License. However, parties who have received copies, or rights, from you + under this License will not have their licenses terminated so long as + such parties remain in full compliance. + +9. You are not required to accept this License, since you have not signed + it. However, nothing else grants you permission to modify or distribute + the Library or its derivative works. These actions are prohibited by law + if you do not accept this License. Therefore, by modifying or + distributing the Library (or any work based on the Library), you + indicate your acceptance of this License to do so, and all its terms and + conditions for copying, distributing or modifying the Library or works + based on it. + +10. Each time you redistribute the Library (or any work based on the + Library), the recipient automatically receives a license from the + original licensor to copy, distribute, link with or modify the Library + subject to these terms and conditions. You may not impose any further + restrictions on the recipients' exercise of the rights granted + herein. You are not responsible for enforcing compliance by third + parties to this License. + +11. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot + distribute so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you + may not distribute the Library at all. For example, if a patent license + would not permit royalty-free redistribution of the Library by all + those who receive copies directly or indirectly through you, then the + only way you could satisfy both it and this License would be to refrain + entirely from distribution of the Library. + + If any portion of this section is held invalid or unenforceable under + any particular circumstance, the balance of the section is intended to + apply, and the section as a whole is intended to apply in other + circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system which is implemented + by public license practices. Many people have made generous + contributions to the wide range of software distributed through that + system in reliance on consistent application of that system; it is up + to the author/donor to decide if he or she is willing to distribute + software through any other system and a licensee cannot impose that + choice. + + This section is intended to make thoroughly clear what is believed to + be a consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in certain + countries either by patents or by copyrighted interfaces, the original + copyright holder who places the Library under this License may add an + explicit geographical distribution limitation excluding those + countries, so that distribution is permitted only in or among countries + not thus excluded. In such case, this License incorporates the + limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions of + the Library General Public License from time to time. Such new versions + will be similar in spirit to the present version, but may differ in + detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the Library + specifies a version number of this License which applies to it and "any + later version", you have the option of following the terms and + conditions either of that version or of any later version published by + the Free Software Foundation. If the Library does not specify a license + version number, you may choose any version ever published by the Free + Software Foundation. + +14. If you wish to incorporate parts of the Library into other free + programs whose distribution conditions are incompatible with these, + write to the author to ask for permission. For software which is + copyrighted by the Free Software Foundation, write to the Free Software + Foundation; we sometimes make exceptions for this. Our decision will be + guided by the two goals of preserving the free status of all + derivatives of our free software and of promoting the sharing and reuse + of software generally. + +NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER + EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH + YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL + NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR + REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR + DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL + DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY + (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED + INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF + THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR + OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Libraries + +If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + +To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + +one line to give the library's name and an idea of what it does. +Copyright (C) year name of author + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This library 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 Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in +the library `Frob' (a library for tweaking knobs) written +by James Random Hacker. + +signature of Ty Coon, 1 April 1990 +Ty Coon, President of Vice + +That's all there is to it! diff --git a/LICENSES/preferred/LGPL-2.1 b/LICENSES/preferred/LGPL-2.1 new file mode 100644 index 000000000000..27bb4342a3e8 --- /dev/null +++ b/LICENSES/preferred/LGPL-2.1 @@ -0,0 +1,503 @@ +Valid-License-Identifier: LGPL-2.1 +Valid-License-Identifier: LGPL-2.1+ +SPDX-URL: https://spdx.org/licenses/LGPL-2.1.html +Usage-Guide: + To use this license in source code, put one of the following SPDX + tag/value pairs into a comment according to the placement + guidelines in the licensing rules documentation. + For 'GNU Lesser General Public License (LGPL) version 2.1 only' use: + SPDX-License-Identifier: LGPL-2.1 + For 'GNU Lesser General Public License (LGPL) version 2.1 or any later + version' use: + SPDX-License-Identifier: LGPL-2.1+ +License-Text: + +GNU LESSER GENERAL PUBLIC LICENSE +Version 2.1, February 1999 + +Copyright (C) 1991, 1999 Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts as +the successor of the GNU Library Public License, version 2, hence the +version number 2.1.] + +Preamble + +The licenses for most software are designed to take away your freedom to +share and change it. By contrast, the GNU General Public Licenses are +intended to guarantee your freedom to share and change free software--to +make sure the software is free for all its users. + +This license, the Lesser General Public License, applies to some specially +designated software packages--typically libraries--of the Free Software +Foundation and other authors who decide to use it. You can use it too, but +we suggest you first think carefully about whether this license or the +ordinary General Public License is the better strategy to use in any +particular case, based on the explanations below. + +When we speak of free software, we are referring to freedom of use, not +price. Our General Public Licenses are designed to make sure that you have +the freedom to distribute copies of free software (and charge for this +service if you wish); that you receive source code or can get it if you +want it; that you can change the software and use pieces of it in new free +programs; and that you are informed that you can do these things. + +To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for you if +you distribute copies of the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for +a fee, you must give the recipients all the rights that we gave you. You +must make sure that they, too, receive or can get the source code. If you +link other code with the library, you must provide complete object files to +the recipients, so that they can relink them with the library after making +changes to the library and recompiling it. And you must show them these +terms so they know their rights. + +We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is no +warranty for the free library. Also, if the library is modified by someone +else and passed on, the recipients should know that what they have is not +the original version, so that the original author's reputation will not be +affected by problems that might be introduced by others. + +Finally, software patents pose a constant threat to the existence of any +free program. We wish to make sure that a company cannot effectively +restrict the users of a free program by obtaining a restrictive license +from a patent holder. Therefore, we insist that any patent license obtained +for a version of the library must be consistent with the full freedom of +use specified in this license. + +Most GNU software, including some libraries, is covered by the ordinary GNU +General Public License. This license, the GNU Lesser General Public +License, applies to certain designated libraries, and is quite different +from the ordinary General Public License. We use this license for certain +libraries in order to permit linking those libraries into non-free +programs. + +When a program is linked with a library, whether statically or using a +shared library, the combination of the two is legally speaking a combined +work, a derivative of the original library. The ordinary General Public +License therefore permits such linking only if the entire combination fits +its criteria of freedom. The Lesser General Public License permits more lax +criteria for linking other code with the library. + +We call this license the "Lesser" General Public License because it does +Less to protect the user's freedom than the ordinary General Public +License. It also provides other free software developers Less of an +advantage over competing non-free programs. These disadvantages are the +reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + +For example, on rare occasions, there may be a special need to encourage +the widest possible use of a certain library, so that it becomes a de-facto +standard. To achieve this, non-free programs must be allowed to use the +library. A more frequent case is that a free library does the same job as +widely used non-free libraries. In this case, there is little to gain by +limiting the free library to free software only, so we use the Lesser +General Public License. + +In other cases, permission to use a particular library in non-free programs +enables a greater number of people to use a large body of free +software. For example, permission to use the GNU C Library in non-free +programs enables many more people to use the whole GNU operating system, as +well as its variant, the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the users' +freedom, it does ensure that the user of a program that is linked with the +Library has the freedom and the wherewithal to run that program using a +modified version of the Library. + +The precise terms and conditions for copying, distribution and modification +follow. Pay close attention to the difference between a "work based on the +library" and a "work that uses the library". The former contains code +derived from the library, whereas the latter must be combined with the +library in order to run. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library or other program + which contains a notice placed by the copyright holder or other + authorized party saying it may be distributed under the terms of this + Lesser General Public License (also called "this License"). Each + licensee is addressed as "you". + + A "library" means a collection of software functions and/or data + prepared so as to be conveniently linked with application programs + (which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work which + has been distributed under these terms. A "work based on the Library" + means either the Library or any derivative work under copyright law: + that is to say, a work containing the Library or a portion of it, either + verbatim or with modifications and/or translated straightforwardly into + another language. (Hereinafter, translation is included without + limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for making + modifications to it. For a library, complete source code means all the + source code for all modules it contains, plus any associated interface + definition files, plus the scripts used to control compilation and + installation of the library. + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of running + a program using the Library is not restricted, and output from such a + program is covered only if its contents constitute a work based on the + Library (independent of the use of the Library in a tool for writing + it). Whether that is true depends on what the Library does and what the + program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete + source code as you receive it, in any medium, provided that you + conspicuously and appropriately publish on each copy an appropriate + copyright notice and disclaimer of warranty; keep intact all the notices + that refer to this License and to the absence of any warranty; and + distribute a copy of this License along with the Library. + + You may charge a fee for the physical act of transferring a copy, and + you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of it, + thus forming a work based on the Library, and copy and distribute such + modifications or work under the terms of Section 1 above, provided that + you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices stating + that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no charge to + all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a table + of data to be supplied by an application program that uses the + facility, other than as an argument passed when the facility is + invoked, then you must make a good faith effort to ensure that, in + the event an application does not supply such function or table, the + facility still operates, and performs whatever part of its purpose + remains meaningful. + + (For example, a function in a library to compute square roots has a + purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must be + optional: if the application does not supply it, the square root + function must still compute square roots.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Library, and + can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based on + the Library, the distribution of the whole must be on the terms of this + License, whose permissions for other licensees extend to the entire + whole, and thus to each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Library. + + In addition, mere aggregation of another work not based on the Library + with the Library (or with a work based on the Library) on a volume of a + storage or distribution medium does not bring the other work under the + scope of this License. + +3. You may opt to apply the terms of the ordinary GNU General Public + License instead of this License to a given copy of the Library. To do + this, you must alter all the notices that refer to this License, so that + they refer to the ordinary GNU General Public License, version 2, + instead of to this License. (If a newer version than version 2 of the + ordinary GNU General Public License has appeared, then you can specify + that version instead if you wish.) Do not make any other change in these + notices. + + Once this change is made in a given copy, it is irreversible for that + copy, so the ordinary GNU General Public License applies to all + subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of the + Library into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of + it, under Section 2) in object code or executable form under the terms + of Sections 1 and 2 above provided that you accompany it with the + complete corresponding machine-readable source code, which must be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange. + + If distribution of object code is made by offering access to copy from a + designated place, then offering equivalent access to copy the source + code from the same place satisfies the requirement to distribute the + source code, even though third parties are not compelled to copy the + source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but + is designed to work with the Library by being compiled or linked with + it, is called a "work that uses the Library". Such a work, in isolation, + is not a derivative work of the Library, and therefore falls outside the + scope of this License. + + However, linking a "work that uses the Library" with the Library creates + an executable that is a derivative of the Library (because it contains + portions of the Library), rather than a "work that uses the + library". The executable is therefore covered by this License. Section 6 + states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file + that is part of the Library, the object code for the work may be a + derivative work of the Library even though the source code is + not. Whether this is true is especially significant if the work can be + linked without the Library, or if the work is itself a library. The + threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data structure + layouts and accessors, and small macros and small inline functions (ten + lines or less in length), then the use of the object file is + unrestricted, regardless of whether it is legally a derivative + work. (Executables containing this object code plus portions of the + Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may + distribute the object code for the work under the terms of Section + 6. Any executables containing that work also fall under Section 6, + whether or not they are linked directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a + "work that uses the Library" with the Library to produce a work + containing portions of the Library, and distribute that work under terms + of your choice, provided that the terms permit modification of the work + for the customer's own use and reverse engineering for debugging such + modifications. + + You must give prominent notice with each copy of the work that the + Library is used in it and that the Library and its use are covered by + this License. You must supply a copy of this License. If the work during + execution displays copyright notices, you must include the copyright + notice for the Library among them, as well as a reference directing the + user to the copy of this License. Also, you must do one of these things: + + a) Accompany the work with the complete corresponding machine-readable + source code for the Library including whatever changes were used in + the work (which must be distributed under Sections 1 and 2 above); + and, if the work is an executable linked with the Library, with the + complete machine-readable "work that uses the Library", as object + code and/or source code, so that the user can modify the Library and + then relink to produce a modified executable containing the modified + Library. (It is understood that the user who changes the contents of + definitions files in the Library will not necessarily be able to + recompile the application to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a copy + of the library already present on the user's computer system, rather + than copying library functions into the executable, and (2) will + operate properly with a modified version of the library, if the user + installs one, as long as the modified version is interface-compatible + with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least three + years, to give the same user the materials specified in Subsection + 6a, above, for a charge no more than the cost of performing this + distribution. + + d) If distribution of the work is made by offering access to copy from a + designated place, offer equivalent access to copy the above specified + materials from the same place. + + e) Verify that the user has already received a copy of these materials + or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the Library" + must include any data and utility programs needed for reproducing the + executable from it. However, as a special exception, the materials to be + distributed need not include anything that is normally distributed (in + either source or binary form) with the major components (compiler, + kernel, and so on) of the operating system on which the executable runs, + unless that component itself accompanies the executable. + + It may happen that this requirement contradicts the license restrictions + of other proprietary libraries that do not normally accompany the + operating system. Such a contradiction means you cannot use both them + and the Library together in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library + side-by-side in a single library together with other library facilities + not covered by this License, and distribute such a combined library, + provided that the separate distribution of the work based on the Library + and of the other library facilities is otherwise permitted, and provided + that you do these two things: + + a) Accompany the combined library with a copy of the same work based on + the Library, uncombined with any other library facilities. This must + be distributed under the terms of the Sections above. + + b) Give prominent notice with the combined library of the fact that part + of it is a work based on the Library, and explaining where to find + the accompanying uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the + Library except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense, link with, or distribute the + Library is void, and will automatically terminate your rights under this + License. However, parties who have received copies, or rights, from you + under this License will not have their licenses terminated so long as + such parties remain in full compliance. + +9. You are not required to accept this License, since you have not signed + it. However, nothing else grants you permission to modify or distribute + the Library or its derivative works. These actions are prohibited by law + if you do not accept this License. Therefore, by modifying or + distributing the Library (or any work based on the Library), you + indicate your acceptance of this License to do so, and all its terms and + conditions for copying, distributing or modifying the Library or works + based on it. + +10. Each time you redistribute the Library (or any work based on the + Library), the recipient automatically receives a license from the + original licensor to copy, distribute, link with or modify the Library + subject to these terms and conditions. You may not impose any further + restrictions on the recipients' exercise of the rights granted + herein. You are not responsible for enforcing compliance by third + parties with this License. + +11. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot + distribute so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you + may not distribute the Library at all. For example, if a patent license + would not permit royalty-free redistribution of the Library by all + those who receive copies directly or indirectly through you, then the + only way you could satisfy both it and this License would be to refrain + entirely from distribution of the Library. + + If any portion of this section is held invalid or unenforceable under + any particular circumstance, the balance of the section is intended to + apply, and the section as a whole is intended to apply in other + circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system which is implemented + by public license practices. Many people have made generous + contributions to the wide range of software distributed through that + system in reliance on consistent application of that system; it is up + to the author/donor to decide if he or she is willing to distribute + software through any other system and a licensee cannot impose that + choice. + + This section is intended to make thoroughly clear what is believed to + be a consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in certain + countries either by patents or by copyrighted interfaces, the original + copyright holder who places the Library under this License may add an + explicit geographical distribution limitation excluding those + countries, so that distribution is permitted only in or among countries + not thus excluded. In such case, this License incorporates the + limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions of + the Lesser General Public License from time to time. Such new versions + will be similar in spirit to the present version, but may differ in + detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the Library + specifies a version number of this License which applies to it and "any + later version", you have the option of following the terms and + conditions either of that version or of any later version published by + the Free Software Foundation. If the Library does not specify a license + version number, you may choose any version ever published by the Free + Software Foundation. + +14. If you wish to incorporate parts of the Library into other free + programs whose distribution conditions are incompatible with these, + write to the author to ask for permission. For software which is + copyrighted by the Free Software Foundation, write to the Free Software + Foundation; we sometimes make exceptions for this. Our decision will be + guided by the two goals of preserving the free status of all + derivatives of our free software and of promoting the sharing and reuse + of software generally. + +NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER + EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH + YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL + NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR + REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR + DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL + DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY + (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED + INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF + THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR + OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Libraries + +If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + +To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + +one line to give the library's name and an idea of what it does. +Copyright (C) year name of author + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at +your option) any later version. + +This library 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 Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add +information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in +the library `Frob' (a library for tweaking knobs) written +by James Random Hacker. + +signature of Ty Coon, 1 April 1990 +Ty Coon, President of Vice +That's all there is to it! diff --git a/LICENSES/preferred/MIT b/LICENSES/preferred/MIT new file mode 100644 index 000000000000..f33a68ceb3ea --- /dev/null +++ b/LICENSES/preferred/MIT @@ -0,0 +1,30 @@ +Valid-License-Identifier: MIT +SPDX-URL: https://spdx.org/licenses/MIT.html +Usage-Guide: + To use the MIT License put the following SPDX tag/value pair into a + comment according to the placement guidelines in the licensing rules + documentation: + SPDX-License-Identifier: MIT +License-Text: + +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/MAINTAINERS b/MAINTAINERS index 5bc088f27c83..2afba909724c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -62,7 +62,15 @@ trivial patch so apply some common sense. 7. When sending security related changes or reports to a maintainer please Cc: security@kernel.org, especially if the maintainer - does not respond. + does not respond. Please keep in mind that the security team is + a small set of people who can be efficient only when working on + verified bugs. Please only Cc: this list when you have identified + that the bug would present a short-term risk to other users if it + were publicly disclosed. For example, reports of address leaks do + not represent an immediate threat and are better handled publicly, + and ideally, should come with a patch proposal. Please do not send + automated reports to this list either. Such bugs will be handled + better and faster in the usual public places. 8. Happy hacking. @@ -262,6 +270,7 @@ ACCES 104-QUAD-8 IIO DRIVER M: William Breathitt Gray L: linux-iio@vger.kernel.org S: Maintained +F: Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 F: drivers/iio/counter/104-quad-8.c ACCES PCI-IDIO-16 GPIO DRIVER @@ -270,6 +279,12 @@ L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-pci-idio-16.c +ACCES PCIe-IDIO-24 GPIO DRIVER +M: William Breathitt Gray +L: linux-gpio@vger.kernel.org +S: Maintained +F: drivers/gpio/gpio-pcie-idio-24.c + ACENIC DRIVER M: Jes Sorensen L: linux-acenic@sunsite.dk @@ -321,7 +336,7 @@ F: drivers/acpi/apei/ ACPI COMPONENT ARCHITECTURE (ACPICA) M: Robert Moore -M: Lv Zheng +M: Erik Schmauss M: "Rafael J. Wysocki" L: linux-acpi@vger.kernel.org L: devel@acpica.org @@ -845,6 +860,8 @@ M: Michael Hennerich W: http://wiki.analog.com/ W: http://ez.analog.com/community/linux-device-drivers S: Supported +F: Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523 +F: Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350 F: drivers/iio/*/ad* F: drivers/iio/adc/ltc2497* X: drivers/iio/*/adjd* @@ -867,6 +884,12 @@ S: Supported F: drivers/android/ F: drivers/staging/android/ +ANDROID GOLDFISH PIC DRIVER +M: Miodrag Dinic +S: Supported +F: Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt +F: drivers/irqchip/irq-goldfish-pic.c + ANDROID GOLDFISH RTC DRIVER M: Miodrag Dinic S: Supported @@ -880,7 +903,6 @@ L: devel@driverdev.osuosl.org S: Supported F: drivers/staging/android/ion F: drivers/staging/android/uapi/ion.h -F: drivers/staging/android/uapi/ion_test.h AOA (Apple Onboard Audio) ALSA DRIVER M: Johannes Berg @@ -1255,6 +1277,12 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported F: drivers/net/ethernet/cavium/thunder/ +ARM/CIRRUS LOGIC BK3 MACHINE SUPPORT +M: Lukasz Majewski +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Maintained +F: arch/arm/mach-ep93xx/ts72xx.c + ARM/CIRRUS LOGIC CLPS711X ARM ARCHITECTURE M: Alexander Shiyan L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -1279,7 +1307,6 @@ M: Russell King L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained T: git git://git.armlinux.org.uk/~rmk/linux-arm.git clkdev -F: arch/arm/include/asm/clkdev.h F: drivers/clk/clkdev.c ARM/COMPULAB CM-X270/EM-X270 and CM-X300 MACHINE SUPPORT @@ -1313,7 +1340,8 @@ F: tools/perf/arch/arm/util/pmu.c F: tools/perf/arch/arm/util/auxtrace.c F: tools/perf/arch/arm/util/cs-etm.c F: tools/perf/arch/arm/util/cs-etm.h -F: tools/perf/util/cs-etm.h +F: tools/perf/util/cs-etm.* +F: tools/perf/util/cs-etm-decoder/* ARM/CORGI MACHINE SUPPORT M: Richard Purdie @@ -1327,8 +1355,10 @@ T: git git://github.com/ulli-kroll/linux.git S: Maintained F: Documentation/devicetree/bindings/arm/gemini.txt F: Documentation/devicetree/bindings/pinctrl/cortina,gemini-pinctrl.txt +F: Documentation/devicetree/bindings/net/cortina,gemini-ethernet.txt F: Documentation/devicetree/bindings/rtc/faraday,ftrtc010.txt F: arch/arm/mach-gemini/ +F: drivers/net/ethernet/cortina/ F: drivers/pinctrl/pinctrl-gemini.c F: drivers/rtc/rtc-ftrtc010.c @@ -1583,6 +1613,7 @@ F: arch/arm/boot/dts/kirkwood* F: arch/arm/configs/mvebu_*_defconfig F: arch/arm/mach-mvebu/ F: arch/arm64/boot/dts/marvell/armada* +F: drivers/cpufreq/armada-37xx-cpufreq.c F: drivers/cpufreq/mvebu-cpufreq.c F: drivers/irqchip/irq-armada-370-xp.c F: drivers/irqchip/irq-mvebu-* @@ -1635,14 +1666,38 @@ ARM/NEC MOBILEPRO 900/c MACHINE SUPPORT M: Michael Petchkovsky S: Maintained -ARM/NOMADIK ARCHITECTURE -M: Alessandro Rubini +ARM/NOMADIK/U300/Ux500 ARCHITECTURES M: Linus Walleij L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/mach-nomadik/ -F: drivers/pinctrl/nomadik/ +F: arch/arm/mach-u300/ +F: arch/arm/mach-ux500/ +F: arch/arm/boot/dts/ste-* +F: drivers/clk/clk-nomadik.c +F: drivers/clk/clk-u300.c +F: drivers/clocksource/clksrc-dbx500-prcmu.c +F: drivers/clocksource/timer-u300.c +F: drivers/dma/coh901318* +F: drivers/dma/ste_dma40* +F: drivers/hwspinlock/u8500_hsem.c F: drivers/i2c/busses/i2c-nomadik.c +F: drivers/i2c/busses/i2c-stu300.c +F: drivers/mfd/ab3100* +F: drivers/mfd/ab8500* +F: drivers/mfd/abx500* +F: drivers/mfd/dbx500* +F: drivers/mfd/db8500* +F: drivers/pinctrl/nomadik/ +F: drivers/pinctrl/pinctrl-coh901* +F: drivers/pinctrl/pinctrl-u300.c +F: drivers/rtc/rtc-ab3100.c +F: drivers/rtc/rtc-ab8500.c +F: drivers/rtc/rtc-coh901331.c +F: drivers/rtc/rtc-pl031.c +F: drivers/watchdog/coh901327_wdt.c +F: Documentation/devicetree/bindings/arm/ste-* +F: Documentation/devicetree/bindings/arm/ux500/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik.git ARM/NUVOTON W90X900 ARM ARCHITECTURE @@ -1680,9 +1735,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-oxnas@lists.tuxfamily.org (moderated for non-subscribers) S: Maintained F: arch/arm/mach-oxnas/ -F: arch/arm/boot/dts/ox8*.dtsi -F: arch/arm/boot/dts/wd-mbwe.dts -F: arch/arm/boot/dts/cloudengines-pogoplug-series-3.dts +F: arch/arm/boot/dts/ox8*.dts* N: oxnas ARM/PALM TREO SUPPORT @@ -1690,8 +1743,7 @@ M: Tomas Cech L: linux-arm-kernel@lists.infradead.org W: http://hackndev.com S: Maintained -F: arch/arm/mach-pxa/include/mach/palmtreo.h -F: arch/arm/mach-pxa/palmtreo.c +F: arch/arm/mach-pxa/palmtreo.* ARM/PALMTX,PALMT5,PALMLD,PALMTE2,PALMTC SUPPORT M: Marek Vasut @@ -1700,12 +1752,10 @@ W: http://hackndev.com S: Maintained F: arch/arm/mach-pxa/include/mach/palmtx.h F: arch/arm/mach-pxa/palmtx.c -F: arch/arm/mach-pxa/include/mach/palmt5.h -F: arch/arm/mach-pxa/palmt5.c +F: arch/arm/mach-pxa/palmt5.* F: arch/arm/mach-pxa/include/mach/palmld.h F: arch/arm/mach-pxa/palmld.c -F: arch/arm/mach-pxa/include/mach/palmte2.h -F: arch/arm/mach-pxa/palmte2.c +F: arch/arm/mach-pxa/palmte2.* F: arch/arm/mach-pxa/include/mach/palmtc.h F: arch/arm/mach-pxa/palmtc.c @@ -1714,8 +1764,7 @@ M: Sergey Lapin L: linux-arm-kernel@lists.infradead.org W: http://hackndev.com S: Maintained -F: arch/arm/mach-pxa/include/mach/palmz72.h -F: arch/arm/mach-pxa/palmz72.c +F: arch/arm/mach-pxa/palmz72.* ARM/PLEB SUPPORT M: Peter Chubb @@ -1744,7 +1793,6 @@ F: drivers/clk/qcom/ F: drivers/dma/qcom/ F: drivers/soc/qcom/ F: drivers/spi/spi-qup.c -F: drivers/tty/serial/msm_serial.h F: drivers/tty/serial/msm_serial.c F: drivers/*/pm8???-* F: drivers/mfd/ssbi.c @@ -1956,9 +2004,10 @@ N: stm32 F: drivers/clocksource/armv7m_systick.c ARM/TANGO ARCHITECTURE -M: Marc Gonzalez +M: Marc Gonzalez +M: Mans Rullgard L: linux-arm-kernel@lists.infradead.org -S: Maintained +S: Odd Fixes N: tango ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT @@ -2022,27 +2071,13 @@ M: Dmitry Eremin-Solenikov M: Dirk Opfer S: Maintained -ARM/U300 MACHINE SUPPORT -M: Linus Walleij -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Supported -F: arch/arm/mach-u300/ -F: drivers/clocksource/timer-u300.c -F: drivers/i2c/busses/i2c-stu300.c -F: drivers/rtc/rtc-coh901331.c -F: drivers/watchdog/coh901327_wdt.c -F: drivers/dma/coh901318* -F: drivers/mfd/ab3100* -F: drivers/rtc/rtc-ab3100.c -F: drivers/rtc/rtc-coh901331.c -T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git - ARM/UNIPHIER ARCHITECTURE M: Masahiro Yamada L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) T: git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-uniphier.git S: Maintained F: Documentation/devicetree/bindings/gpio/gpio-uniphier.txt +F: Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.txt F: arch/arm/boot/dts/uniphier* F: arch/arm/include/asm/hardware/cache-uniphier.h F: arch/arm/mach-uniphier/ @@ -2058,24 +2093,6 @@ F: drivers/reset/reset-uniphier.c F: drivers/tty/serial/8250/8250_uniphier.c N: uniphier -ARM/Ux500 ARM ARCHITECTURE -M: Linus Walleij -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Maintained -F: arch/arm/mach-ux500/ -F: drivers/clocksource/clksrc-dbx500-prcmu.c -F: drivers/dma/ste_dma40* -F: drivers/hwspinlock/u8500_hsem.c -F: drivers/mfd/abx500* -F: drivers/mfd/ab8500* -F: drivers/mfd/dbx500* -F: drivers/mfd/db8500* -F: drivers/pinctrl/nomadik/pinctrl-ab* -F: drivers/pinctrl/nomadik/pinctrl-nomadik* -F: drivers/rtc/rtc-ab8500.c -F: drivers/rtc/rtc-pl031.c -T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git - ARM/Ux500 CLOCK FRAMEWORK SUPPORT M: Ulf Hansson L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -2202,14 +2219,6 @@ L: linux-leds@vger.kernel.org S: Maintained F: drivers/leds/leds-as3645a.c -AS3645A LED FLASH CONTROLLER DRIVER -M: Laurent Pinchart -L: linux-media@vger.kernel.org -T: git git://linuxtv.org/media_tree.git -S: Maintained -F: drivers/media/i2c/as3645a.c -F: include/media/i2c/as3645a.h - ASAHI KASEI AK8974 DRIVER M: Linus Walleij L: linux-iio@vger.kernel.org @@ -2262,7 +2271,9 @@ F: include/linux/async_tx.h AT24 EEPROM DRIVER M: Bartosz Golaszewski L: linux-i2c@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git S: Maintained +F: Documentation/devicetree/bindings/eeprom/at24.txt F: drivers/misc/eeprom/at24.c F: include/linux/platform_data/at24.h @@ -2383,13 +2394,6 @@ F: Documentation/devicetree/bindings/input/atmel,maxtouch.txt F: drivers/input/touchscreen/atmel_mxt_ts.c F: include/linux/platform_data/atmel_mxt_ts.h -ATMEL NAND DRIVER -M: Wenyou Yang -M: Josh Wu -L: linux-mtd@lists.infradead.org -S: Supported -F: drivers/mtd/nand/atmel/* - ATMEL SAMA5D2 ADC DRIVER M: Ludovic Desroches L: linux-iio@vger.kernel.org @@ -2501,6 +2505,8 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/arm/axentia.txt F: arch/arm/boot/dts/at91-linea.dtsi +F: arch/arm/boot/dts/at91-natte.dtsi +F: arch/arm/boot/dts/at91-nattis-2-natte-2.dts F: arch/arm/boot/dts/at91-tse850-3.dts AXENTIA ASOC DRIVERS @@ -2564,6 +2570,7 @@ S: Maintained F: Documentation/ABI/testing/sysfs-class-net-batman-adv F: Documentation/ABI/testing/sysfs-class-net-mesh F: Documentation/networking/batman-adv.rst +F: include/uapi/linux/batadv_packet.h F: include/uapi/linux/batman_adv.h F: net/batman-adv/ @@ -2687,7 +2694,6 @@ F: drivers/mtd/devices/block2mtd.c BLUETOOTH DRIVERS M: Marcel Holtmann -M: Gustavo Padovan M: Johan Hedberg L: linux-bluetooth@vger.kernel.org W: http://www.bluez.org/ @@ -2698,7 +2704,6 @@ F: drivers/bluetooth/ BLUETOOTH SUBSYSTEM M: Marcel Holtmann -M: Gustavo Padovan M: Johan Hedberg L: linux-bluetooth@vger.kernel.org W: http://www.bluez.org/ @@ -2723,12 +2728,16 @@ M: Alexei Starovoitov M: Daniel Borkmann L: netdev@vger.kernel.org L: linux-kernel@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git S: Supported F: arch/x86/net/bpf_jit* F: Documentation/networking/filter.txt F: Documentation/bpf/ F: include/linux/bpf* F: include/linux/filter.h +F: include/trace/events/bpf.h +F: include/trace/events/xdp.h F: include/uapi/linux/bpf* F: include/uapi/linux/filter.h F: kernel/bpf/ @@ -2832,6 +2841,8 @@ S: Maintained F: arch/arm/mach-bcm/*brcmstb* F: arch/arm/boot/dts/bcm7*.dts* F: drivers/bus/brcmstb_gisb.c +F: arch/arm/mm/cache-b15-rac.c +F: arch/arm/include/asm/hardware/cache-b15-rac.h N: brcmstb BROADCOM BMIPS CPUFREQ DRIVER @@ -3193,7 +3204,7 @@ W: https://github.com/linux-can T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git S: Maintained -F: Documentation/networking/can.txt +F: Documentation/networking/can.rst F: net/can/ F: include/linux/can/core.h F: include/uapi/linux/can.h @@ -3398,8 +3409,8 @@ M: Arnd Bergmann M: Greg Kroah-Hartman T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git S: Supported -F: drivers/char/* -F: drivers/misc/* +F: drivers/char/ +F: drivers/misc/ F: include/linux/miscdevice.h CHECKPATCH @@ -3547,7 +3558,7 @@ F: drivers/media/platform/coda/ COMMON CLK FRAMEWORK M: Michael Turquette -M: Stephen Boyd +M: Stephen Boyd L: linux-clk@vger.kernel.org Q: http://patchwork.kernel.org/project/linux-clk/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git @@ -4125,6 +4136,7 @@ DEVANTECH SRF ULTRASONIC RANGER IIO DRIVER M: Andreas Klinger L: linux-iio@vger.kernel.org S: Maintained +F: Documentation/ABI/testing/sysfs-bus-iio-distance-srf08 F: drivers/iio/proximity/srf*.c DEVICE COREDUMP (DEV_COREDUMP) @@ -4334,10 +4346,12 @@ T: git git://git.infradead.org/users/hch/dma-mapping.git W: http://git.infradead.org/users/hch/dma-mapping.git S: Supported F: lib/dma-debug.c -F: lib/dma-noop.c +F: lib/dma-direct.c F: lib/dma-virt.c F: drivers/base/dma-mapping.c F: drivers/base/dma-coherent.c +F: include/asm-generic/dma-mapping.h +F: include/linux/dma-direct.h F: include/linux/dma-mapping.h DME1737 HARDWARE MONITOR DRIVER @@ -4442,6 +4456,13 @@ T: git git://anongit.freedesktop.org/drm/drm-misc S: Supported F: drivers/gpu/drm/pl111/ +DRM DRIVER FOR ARM VERSATILE TFT PANELS +M: Linus Walleij +T: git git://anongit.freedesktop.org/drm/drm-misc +S: Maintained +F: drivers/gpu/drm/panel/panel-arm-versatile.c +F: Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.txt + DRM DRIVER FOR AST SERVER GRAPHICS CHIPS M: Dave Airlie S: Odd Fixes @@ -4596,8 +4617,8 @@ F: include/uapi/drm/ F: include/linux/vga* DRM DRIVERS AND MISC GPU PATCHES -M: Daniel Vetter M: Gustavo Padovan +M: Maarten Lankhorst M: Sean Paul W: https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html S: Maintained @@ -4961,6 +4982,11 @@ S: Maintained F: lib/dynamic_debug.c F: include/linux/dynamic_debug.h +DYNAMIC INTERRUPT MODERATION +M: Tal Gilboa +S: Maintained +F: include/linux/net_dim.h + DZ DECSTATION DZ11 SERIAL DRIVER M: "Maciej W. Rozycki" S: Maintained @@ -5161,6 +5187,12 @@ L: linux-edac@vger.kernel.org S: Maintained F: drivers/edac/skx_edac.c +EDAC-TI +M: Tero Kristo +L: linux-edac@vger.kernel.org +S: Maintained +F: drivers/edac/ti_edac.c + EDIROL UA-101/UA-1000 DRIVER M: Clemens Ladisch L: alsa-devel@alsa-project.org (moderated for non-subscribers) @@ -5967,6 +5999,12 @@ L: linux-input@vger.kernel.org S: Maintained F: drivers/input/touchscreen/goodix.c +GPD POCKET FAN DRIVER +M: Hans de Goede +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/gpd-pocket-fan.c + GPIO ACPI SUPPORT M: Mika Westerberg M: Andy Shevchenko @@ -5984,6 +6022,7 @@ F: drivers/media/rc/gpio-ir-tx.c GPIO MOCKUP DRIVER M: Bamvor Jian Zhang +R: Bartosz Golaszewski L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-mockup.c @@ -6539,6 +6578,12 @@ F: drivers/i2c/i2c-mux.c F: drivers/i2c/muxes/ F: include/linux/i2c-mux.h +I2C MV64XXX MARVELL AND ALLWINNER DRIVER +M: Gregory CLEMENT +L: linux-i2c@vger.kernel.org +S: Maintained +F: drivers/i2c/busses/i2c-mv64xxx.c + I2C OVER PARALLEL PORT M: Jean Delvare L: linux-i2c@vger.kernel.org @@ -6631,16 +6676,6 @@ L: linux-i2c@vger.kernel.org S: Maintained F: drivers/i2c/i2c-stub.c -i386 BOOT CODE -M: "H. Peter Anvin" -S: Maintained -F: arch/x86/boot/ - -i386 SETUP CODE / CPU ERRATA WORKAROUNDS -M: "H. Peter Anvin" -T: git git://git.kernel.org/pub/scm/linux/kernel/git/hpa/linux-2.6-x86setup.git -S: Maintained - IA64 (Itanium) PLATFORM M: Tony Luck M: Fenghua Yu @@ -6848,6 +6883,8 @@ R: Peter Meerwald-Stadler L: linux-iio@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git S: Maintained +F: Documentation/ABI/testing/configfs-iio* +F: Documentation/ABI/testing/sysfs-bus-iio* F: Documentation/devicetree/bindings/iio/ F: drivers/iio/ F: drivers/staging/iio/ @@ -6905,9 +6942,9 @@ INFINIBAND SUBSYSTEM M: Doug Ledford M: Jason Gunthorpe L: linux-rdma@vger.kernel.org -W: http://www.openfabrics.org/ +W: https://github.com/linux-rdma/rdma-core Q: http://patchwork.kernel.org/project/linux-rdma/list/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma.git S: Supported F: Documentation/devicetree/bindings/infiniband/ F: Documentation/infiniband/ @@ -7095,6 +7132,14 @@ R: Dan Williams S: Odd fixes F: drivers/dma/iop-adma.c +INTEL IPU3 CSI-2 CIO2 DRIVER +M: Yong Zhi +M: Sakari Ailus +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/pci/intel/ipu3/ +F: Documentation/media/uapi/v4l/pixfmt-srggb10-ipu3.rst + INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT M: Krzysztof Halasa S: Maintained @@ -7329,17 +7374,16 @@ F: drivers/tty/ipwireless/ IPX NETWORK LAYER L: netdev@vger.kernel.org -S: Odd fixes -F: include/net/ipx.h +S: Obsolete F: include/uapi/linux/ipx.h -F: net/ipx/ +F: drivers/staging/ipx/ IRDA SUBSYSTEM M: Samuel Ortiz L: irda-users@lists.sourceforge.net (subscribers-only) L: netdev@vger.kernel.org W: http://irda.sourceforge.net/ -S: Maintained +S: Obsolete T: git git://git.kernel.org/pub/scm/linux/kernel/git/sameo/irda-2.6.git F: Documentation/networking/irda.txt F: drivers/staging/irda/ @@ -7711,7 +7755,9 @@ F: arch/powerpc/kernel/kvm* KERNEL VIRTUAL MACHINE for s390 (KVM/s390) M: Christian Borntraeger -M: Cornelia Huck +M: Janosch Frank +R: David Hildenbrand +R: Cornelia Huck L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git @@ -7763,6 +7809,7 @@ F: include/keys/encrypted-type.h F: security/keys/encrypted-keys/ KEYS-TRUSTED +M: James Bottomley M: Mimi Zohar L: linux-integrity@vger.kernel.org L: keyrings@vger.kernel.org @@ -8214,6 +8261,7 @@ F: arch/*/include/asm/rwsem.h F: include/linux/seqlock.h F: lib/locking*.[ch] F: kernel/locking/ +X: kernel/locking/locktorture.c LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP/Vista Dynamic Disks) M: "Richard Russon (FlatCap)" @@ -8429,6 +8477,13 @@ L: linux-wireless@vger.kernel.org S: Odd Fixes F: drivers/net/wireless/marvell/mwl8k.c +MARVELL NAND CONTROLLER DRIVER +M: Miquel Raynal +L: linux-mtd@lists.infradead.org +S: Maintained +F: drivers/mtd/nand/marvell_nand.c +F: Documentation/devicetree/bindings/mtd/marvell-nand.txt + MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER M: Nicolas Pitre S: Odd Fixes @@ -8700,6 +8755,15 @@ T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/dvb-frontends/stv6111* +MEDIA DRIVERS FOR NVIDIA TEGRA - VDE +M: Dmitry Osipenko +L: linux-media@vger.kernel.org +L: linux-tegra@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt +F: drivers/staging/media/tegra-vde/ + MEDIA INPUT INFRASTRUCTURE (V4L/DVB) M: Mauro Carvalho Chehab M: Mauro Carvalho Chehab @@ -8743,6 +8807,13 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/mediatek/ +MEDIATEK SWITCH DRIVER +M: Sean Wang +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/dsa/mt7530.* +F: net/dsa/tag_mtk.c + MEDIATEK JPEG DRIVER M: Rick Chang M: Bin Liu @@ -8874,12 +8945,13 @@ W: http://www.mellanox.com Q: http://patchwork.ozlabs.org/project/netdev/list/ F: drivers/net/ethernet/mellanox/mlxfw/ -MELLANOX MLX CPLD HOTPLUG DRIVER +MELLANOX HARDWARE PLATFORM SUPPORT +M: Andy Shevchenko +M: Darren Hart M: Vadim Pasternak L: platform-driver-x86@vger.kernel.org S: Supported -F: drivers/platform/x86/mlxcpld-hotplug.c -F: include/linux/platform_data/mlxcpld-hotplug.h +F: drivers/platform/mellanox/ MELLANOX MLX4 core VPI driver M: Tariq Toukan @@ -8953,6 +9025,7 @@ L: linux-kernel@vger.kernel.org S: Supported F: kernel/sched/membarrier.c F: include/uapi/linux/membarrier.h +F: arch/powerpc/include/asm/membarrier.h MEMORY MANAGEMENT L: linux-mm@kvack.org @@ -8976,7 +9049,7 @@ L: linux-mtd@lists.infradead.org W: http://www.linux-mtd.infradead.org/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ T: git git://git.infradead.org/linux-mtd.git master -T: git git://git.infradead.org/l2-mtd.git master +T: git git://git.infradead.org/linux-mtd.git mtd/next S: Maintained F: Documentation/devicetree/bindings/mtd/ F: drivers/mtd/ @@ -9065,6 +9138,14 @@ F: drivers/media/platform/atmel/atmel-isc.c F: drivers/media/platform/atmel/atmel-isc-regs.h F: devicetree/bindings/media/atmel-isc.txt +MICROCHIP / ATMEL NAND DRIVER +M: Wenyou Yang +M: Josh Wu +L: linux-mtd@lists.infradead.org +S: Supported +F: drivers/mtd/nand/atmel/* +F: Documentation/devicetree/bindings/mtd/atmel-nand.txt + MICROCHIP KSZ SERIES ETHERNET SWITCH DRIVER M: Woojung Huh M: Microchip Linux Driver Support @@ -9107,6 +9188,7 @@ F: drivers/usb/image/microtek.* MIPS M: Ralf Baechle +M: James Hogan L: linux-mips@linux-mips.org W: http://www.linux-mips.org/ T: git git://git.linux-mips.org/pub/scm/ralf/linux.git @@ -9115,6 +9197,7 @@ S: Supported F: Documentation/devicetree/bindings/mips/ F: Documentation/mips/ F: arch/mips/ +F: drivers/platform/mips/ MIPS BOSTON DEVELOPMENT BOARD M: Paul Burton @@ -9142,6 +9225,25 @@ F: arch/mips/include/asm/mach-loongson32/ F: drivers/*/*loongson1* F: drivers/*/*/*loongson1* +MIPS/LOONGSON2 ARCHITECTURE +M: Jiaxun Yang +L: linux-mips@linux-mips.org +S: Maintained +F: arch/mips/loongson64/*{2e/2f}* +F: arch/mips/include/asm/mach-loongson64/ +F: drivers/*/*loongson2* +F: drivers/*/*/*loongson2* + +MIPS/LOONGSON3 ARCHITECTURE +M: Huacai Chen +L: linux-mips@linux-mips.org +S: Maintained +F: arch/mips/loongson64/ +F: arch/mips/include/asm/mach-loongson64/ +F: drivers/platform/mips/cpu_hwmon.c +F: drivers/*/*loongson3* +F: drivers/*/*/*loongson3* + MIPS RINT INSTRUCTION EMULATION M: Aleksandar Markovic L: linux-mips@linux-mips.org @@ -9187,7 +9289,6 @@ F: drivers/media/dvb-frontends/mn88473* MODULE SUPPORT M: Jessica Yu -M: Rusty Russell T: git git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux.git modules-next S: Maintained F: include/linux/module.h @@ -9364,7 +9465,7 @@ L: linux-mtd@lists.infradead.org W: http://www.linux-mtd.infradead.org/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ T: git git://git.infradead.org/linux-mtd.git nand/fixes -T: git git://git.infradead.org/l2-mtd.git nand/next +T: git git://git.infradead.org/linux-mtd.git nand/next S: Maintained F: drivers/mtd/nand/ F: include/linux/mtd/*nand*.h @@ -9382,8 +9483,8 @@ F: drivers/net/ethernet/natsemi/natsemi.c NCP FILESYSTEM M: Petr Vandrovec -S: Odd Fixes -F: fs/ncpfs/ +S: Obsolete +F: drivers/staging/ncpfs/ NCR 5380 SCSI DRIVERS M: Finn Thain @@ -9619,6 +9720,11 @@ NETWORKING [WIRELESS] L: linux-wireless@vger.kernel.org Q: http://patchwork.kernel.org/project/linux-wireless/list/ +NETDEVSIM +M: Jakub Kicinski +S: Maintained +F: drivers/net/netdevsim/* + NETXEN (1/10) GbE SUPPORT M: Manish Chopra M: Rahul Verma @@ -9731,7 +9837,7 @@ F: drivers/ntb/hw/amd/ NTB DRIVER CORE M: Jon Mason M: Dave Jiang -M: Allen Hubbe +M: Allen Hubbe L: linux-ntb@googlegroups.com S: Supported W: https://github.com/jonmason/ntb/wiki @@ -9765,6 +9871,15 @@ S: Supported F: Documentation/filesystems/ntfs.txt F: fs/ntfs/ +NUBUS SUBSYSTEM +M: Finn Thain +L: linux-m68k@lists.linux-m68k.org +S: Maintained +F: arch/*/include/asm/nubus.h +F: drivers/nubus/ +F: include/linux/nubus.h +F: include/uapi/linux/nubus.h + NVIDIA (rivafb and nvidiafb) FRAMEBUFFER DRIVER M: Antonino Daplas L: linux-fbdev@vger.kernel.org @@ -9825,6 +9940,7 @@ NXP TFA9879 DRIVER M: Peter Rosin L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained +F: Documentation/devicetree/bindings/sound/tfa9879.txt F: sound/soc/codecs/tfa9879* NXP-NCI NFC DRIVER @@ -9839,6 +9955,18 @@ M: Josh Poimboeuf S: Supported F: tools/objtool/ +OCXL (Open Coherent Accelerator Processor Interface OpenCAPI) DRIVER +M: Frederic Barrat +M: Andrew Donnellan +L: linuxppc-dev@lists.ozlabs.org +S: Supported +F: arch/powerpc/platforms/powernv/ocxl.c +F: arch/powerpc/include/asm/pnv-ocxl.h +F: drivers/misc/ocxl/ +F: include/misc/ocxl* +F: include/uapi/misc/ocxl.h +F: Documentation/accelerators/ocxl.txt + OMAP AUDIO SUPPORT M: Peter Ujfalusi M: Jarkko Nikula @@ -10073,6 +10201,14 @@ S: Maintained F: drivers/media/i2c/ov7670.c F: Documentation/devicetree/bindings/media/i2c/ov7670.txt +OMNIVISION OV7740 SENSOR DRIVER +M: Wenyou Yang +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/i2c/ov7740.c +F: Documentation/devicetree/bindings/media/i2c/ov7740.txt + ONENAND FLASH DRIVER M: Kyungmin Park L: linux-mtd@lists.infradead.org @@ -10167,7 +10303,7 @@ F: include/uapi/linux/openvswitch.h OPERATING PERFORMANCE POINTS (OPP) M: Viresh Kumar M: Nishanth Menon -M: Stephen Boyd +M: Stephen Boyd L: linux-pm@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm.git @@ -10204,7 +10340,8 @@ F: fs/ocfs2/ ORANGEFS FILESYSTEM M: Mike Marshall -L: pvfs2-developers@beowulf-underground.org (subscribers-only) +R: Martin Brandenburg +L: devel@lists.orangefs.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux.git S: Supported F: fs/orangefs/ @@ -10302,7 +10439,6 @@ F: Documentation/parport*.txt PARAVIRT_OPS INTERFACE M: Juergen Gross M: Alok Kataria -M: Rusty Russell L: virtualization@lists.linux-foundation.org S: Supported F: Documentation/virtual/paravirt_ops.txt @@ -10421,6 +10557,13 @@ S: Maintained F: Documentation/devicetree/bindings/pci/pci-armada8k.txt F: drivers/pci/dwc/pcie-armada8k.c +PCI DRIVER FOR CADENCE PCIE IP +M: Alan Douglas +L: linux-pci@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/pci/cdns,*.txt +F: drivers/pci/cadence/pcie-cadence* + PCI DRIVER FOR FREESCALE LAYERSCAPE M: Minghuan Lian M: Mingkai Hu @@ -10571,8 +10714,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git S: Supported F: Documentation/devicetree/bindings/pci/ F: Documentation/PCI/ +F: drivers/acpi/pci* F: drivers/pci/ +F: include/asm-generic/pci* F: include/linux/pci* +F: include/uapi/linux/pci* +F: lib/pci* F: arch/x86/pci/ F: arch/x86/kernel/quirks.c @@ -10662,11 +10809,9 @@ S: Maintained F: drivers/pci/dwc/*spear* PCMCIA SUBSYSTEM -P: Linux PCMCIA Team -L: linux-pcmcia@lists.infradead.org -W: http://lists.infradead.org/mailman/listinfo/linux-pcmcia +M: Dominik Brodowski T: git git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia.git -S: Maintained +S: Odd Fixes F: Documentation/pcmcia/ F: tools/pcmcia/ F: drivers/pcmcia/ @@ -10793,6 +10938,16 @@ M: Heikki Krogerus S: Maintained F: drivers/pinctrl/intel/ +PIN CONTROLLER - MEDIATEK +M: Sean Wang +L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt +F: Documentation/devicetree/bindings/pinctrl/pinctrl-mt7622.txt +F: drivers/pinctrl/mediatek/pinctrl-mtk-common.* +F: drivers/pinctrl/mediatek/pinctrl-mt2701.c +F: drivers/pinctrl/mediatek/pinctrl-mt7622.c + PIN CONTROLLER - QUALCOMM M: Bjorn Andersson S: Maintained @@ -10911,6 +11066,7 @@ F: include/linux/pm.h F: include/linux/pm_* F: include/linux/powercap.h F: drivers/powercap/ +F: kernel/configs/nopm.config POWER STATE COORDINATION INTERFACE (PSCI) M: Mark Rutland @@ -11205,7 +11361,8 @@ S: Maintained F: drivers/firmware/qemu_fw_cfg.c QIB DRIVER -M: Mike Marciniszyn +M: Dennis Dalessandro +M: Mike Marciniszyn L: linux-rdma@vger.kernel.org S: Supported F: drivers/infiniband/hw/qib/ @@ -11232,7 +11389,6 @@ F: include/linux/qed/ F: drivers/net/ethernet/qlogic/qede/ QLOGIC QL4xxx RDMA DRIVER -M: Ram Amrani M: Michal Kalderon M: Ariel Elior L: linux-rdma@vger.kernel.org @@ -11456,6 +11612,13 @@ S: Maintained F: Documentation/blockdev/ramdisk.txt F: drivers/block/brd.c +RANCHU VIRTUAL BOARD FOR MIPS +M: Miodrag Dinic +L: linux-mips@linux-mips.org +S: Supported +F: arch/mips/generic/board-ranchu.c +F: arch/mips/configs/generic/board-ranchu.config + RANDOM NUMBER DRIVER M: "Theodore Ts'o" S: Maintained @@ -11472,15 +11635,6 @@ L: linux-wireless@vger.kernel.org S: Orphan F: drivers/net/wireless/ray* -RCUTORTURE MODULE -M: Josh Triplett -M: "Paul E. McKenney" -L: linux-kernel@vger.kernel.org -S: Supported -T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git -F: Documentation/RCU/torture.txt -F: kernel/rcu/rcutorture.c - RCUTORTURE TEST FRAMEWORK M: "Paul E. McKenney" M: Josh Triplett @@ -11504,6 +11658,7 @@ F: drivers/net/ethernet/rdc/r6040.c RDMAVT - RDMA verbs software M: Dennis Dalessandro +M: Mike Marciniszyn L: linux-rdma@vger.kernel.org S: Supported F: drivers/infiniband/sw/rdmavt @@ -11673,8 +11828,8 @@ F: drivers/mtd/nand/r852.h RISC-V ARCHITECTURE M: Palmer Dabbelt M: Albert Ou -L: patches@groups.riscv.org -T: git https://github.com/riscv/riscv-linux +L: linux-riscv@lists.infradead.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/palmer/riscv-linux.git S: Supported F: arch/riscv/ K: riscv @@ -11781,15 +11936,13 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.g S: Maintained F: drivers/net/wireless/realtek/rtl818x/rtl8187/ -RTL8192CE WIRELESS DRIVER -M: Larry Finger -M: Chaoming Li +REALTEK WIRELESS DRIVER (rtlwifi family) +M: Ping-Ke Shih L: linux-wireless@vger.kernel.org W: http://wireless.kernel.org/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git S: Maintained F: drivers/net/wireless/realtek/rtlwifi/ -F: drivers/net/wireless/realtek/rtlwifi/rtl8192ce/ RTL8XXXU WIRELESS DRIVER (rtl8xxxu) M: Jes Sorensen @@ -11882,6 +12035,7 @@ F: drivers/pci/hotplug/s390_pci_hpc.c S390 VFIO-CCW DRIVER M: Cornelia Huck M: Dong Jia Shi +M: Halil Pasic L: linux-s390@vger.kernel.org L: kvm@vger.kernel.org S: Supported @@ -11953,6 +12107,13 @@ S: Maintained F: drivers/crypto/exynos-rng.c F: Documentation/devicetree/bindings/crypto/samsung,exynos-rng4.txt +SAMSUNG EXYNOS TRUE RANDOM NUMBER GENERATOR (TRNG) DRIVER +M: Łukasz Stelmach +L: linux-samsung-soc@vger.kernel.org +S: Maintained +F: drivers/char/hw_random/exynos-trng.c +F: Documentation/devicetree/bindings/rng/samsung,exynos5250-trng.txt + SAMSUNG FRAMEBUFFER DRIVER M: Jingoo Han L: linux-fbdev@vger.kernel.org @@ -12015,6 +12176,7 @@ F: drivers/media/i2c/s5k5baf.c SAMSUNG S5P Security SubSystem (SSS) DRIVER M: Krzysztof Kozlowski M: Vladimir Zapolskiy +M: Kamil Konieczny L: linux-crypto@vger.kernel.org L: linux-samsung-soc@vger.kernel.org S: Maintained @@ -12255,7 +12417,7 @@ M: Security Officers S: Supported SECURITY SUBSYSTEM -M: James Morris +M: James Morris M: "Serge E. Hallyn" L: linux-security-module@vger.kernel.org (suggested Cc:) T: git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git @@ -12359,6 +12521,14 @@ T: git git://linuxtv.org/anttip/media_tree.git S: Maintained F: drivers/media/tuners/si2157* +SI2165 MEDIA DRIVER +M: Matthias Schwarzott +L: linux-media@vger.kernel.org +W: https://linuxtv.org +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +S: Maintained +F: drivers/media/dvb-frontends/si2165* + SI2168 MEDIA DRIVER M: Antti Palosaari L: linux-media@vger.kernel.org @@ -12482,6 +12652,13 @@ F: lib/siphash.c F: lib/test_siphash.c F: include/linux/siphash.h +SIOX +M: Gavin Schenk +M: Uwe Kleine-König +S: Supported +F: drivers/siox/* +F: include/trace/events/siox.h + SIS 190 ETHERNET DRIVER M: Francois Romieu L: netdev@vger.kernel.org @@ -12533,6 +12710,14 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git F: include/linux/srcu.h F: kernel/rcu/srcu.c +SERIAL LOW-POWER INTER-CHIP MEDIA BUS (SLIMbus) +M: Srinivas Kandagatla +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Maintained +F: drivers/slimbus/ +F: Documentation/devicetree/bindings/slimbus/ +F: include/linux/slimbus.h + SMACK SECURITY MODULE M: Casey Schaufler L: linux-security-module@vger.kernel.org @@ -12614,6 +12799,12 @@ F: include/media/soc* F: drivers/media/i2c/soc_camera/ F: drivers/media/platform/soc_camera/ +SOCIONEXT UNIPHIER SOUND DRIVER +M: Katsuhiro Suzuki +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Maintained +F: sound/soc/uniphier/ + SOEKRIS NET48XX LED SUPPORT M: Chris Boot S: Maintained @@ -12638,6 +12829,15 @@ L: linux-media@vger.kernel.org S: Supported F: drivers/media/pci/solo6x10/ +SOFTWARE DELEGATED EXCEPTION INTERFACE (SDEI) +M: James Morse +L: linux-arm-kernel@lists.infradead.org +S: Maintained +F: Documentation/devicetree/bindings/arm/firmware/sdei.txt +F: drivers/firmware/arm_sdei.c +F: include/linux/sdei.h +F: include/uapi/linux/sdei.h + SOFTWARE RAID (Multiple Disks) SUPPORT M: Shaohua Li L: linux-raid@vger.kernel.org @@ -12650,6 +12850,13 @@ F: drivers/md/raid* F: include/linux/raid/ F: include/uapi/linux/raid/ +SOCIONEXT (SNI) NETSEC NETWORK DRIVER +M: Jassi Brar +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/ethernet/socionext/netsec.c +F: Documentation/devicetree/bindings/net/socionext-netsec.txt + SONIC NETWORK DRIVER M: Thomas Bogendoerfer L: netdev@vger.kernel.org @@ -12736,6 +12943,16 @@ F: Documentation/sound/alsa/soc/ F: sound/soc/ F: include/sound/soc* +SOUNDWIRE SUBSYSTEM +M: Vinod Koul +M: Sanyog Kale +R: Pierre-Louis Bossart +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Supported +F: Documentation/driver-api/soundwire/ +F: drivers/soundwire/ +F: include/linux/soundwire/ + SP2 MEDIA DRIVER M: Olli Salonen L: linux-media@vger.kernel.org @@ -12802,7 +13019,7 @@ L: linux-mtd@lists.infradead.org W: http://www.linux-mtd.infradead.org/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ T: git git://git.infradead.org/linux-mtd.git spi-nor/fixes -T: git git://git.infradead.org/l2-mtd.git spi-nor/next +T: git git://git.infradead.org/linux-mtd.git spi-nor/next S: Maintained F: drivers/mtd/spi-nor/ F: include/linux/mtd/spi-nor.h @@ -12828,7 +13045,7 @@ F: Documentation/networking/spider_net.txt F: drivers/net/ethernet/toshiba/spider_net* SPMI SUBSYSTEM -R: Stephen Boyd +R: Stephen Boyd L: linux-arm-msm@vger.kernel.org F: Documentation/devicetree/bindings/spmi/ F: drivers/spmi/ @@ -12889,12 +13106,6 @@ S: Odd Fixes F: Documentation/devicetree/bindings/staging/iio/ F: drivers/staging/iio/ -STAGING - LIRC (LINUX INFRARED REMOTE CONTROL) DRIVERS -M: Jarod Wilson -W: http://www.lirc.org/ -S: Odd Fixes -F: drivers/staging/media/lirc/ - STAGING - LUSTRE PARALLEL FILESYSTEM M: Oleg Drokin M: Andreas Dilger @@ -13055,7 +13266,7 @@ F: arch/x86/boot/video* SWIOTLB SUBSYSTEM M: Konrad Rzeszutek Wilk -L: linux-kernel@vger.kernel.org +L: iommu@lists.linux-foundation.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/konrad/swiotlb.git S: Supported F: lib/swiotlb.c @@ -13120,6 +13331,11 @@ S: Supported F: drivers/reset/reset-axs10x.c F: Documentation/devicetree/bindings/reset/snps,axs10x-reset.txt +SYNOPSYS DESIGNWARE 8250 UART DRIVER +R: Andy Shevchenko +S: Maintained +F: drivers/tty/serial/8250/8250_dw.c + SYNOPSYS DESIGNWARE APB GPIO DRIVER M: Hoan Tran L: linux-gpio@vger.kernel.org @@ -13136,7 +13352,6 @@ F: include/linux/platform_data/dma-dw.h F: drivers/dma/dw/ SYNOPSYS DESIGNWARE ENTERPRISE ETHERNET DRIVER -M: Jie Deng M: Jose Abreu L: netdev@vger.kernel.org S: Supported @@ -13276,6 +13491,15 @@ T: git git://linuxtv.org/anttip/media_tree.git S: Maintained F: drivers/media/tuners/tda18218* +TDA18250 MEDIA DRIVER +M: Olli Salonen +L: linux-media@vger.kernel.org +W: https://linuxtv.org +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/tuners/tda18250* + TDA18271 MEDIA DRIVER M: Michael Krufky L: linux-media@vger.kernel.org @@ -13706,7 +13930,7 @@ F: include/linux/usb/tilegx.h TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER M: John Stultz M: Thomas Gleixner -R: Stephen Boyd +R: Stephen Boyd L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core S: Supported @@ -13789,6 +14013,18 @@ L: platform-driver-x86@vger.kernel.org S: Maintained F: drivers/platform/x86/topstar-laptop.c +TORTURE-TEST MODULES +M: Davidlohr Bueso +M: "Paul E. McKenney" +M: Josh Triplett +L: linux-kernel@vger.kernel.org +S: Supported +T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git +F: Documentation/RCU/torture.txt +F: kernel/torture.c +F: kernel/rcu/rcutorture.c +F: kernel/locking/locktorture.c + TOSHIBA ACPI EXTRAS DRIVER M: Azael Avalos L: platform-driver-x86@vger.kernel.org @@ -13831,9 +14067,10 @@ F: drivers/platform/x86/toshiba-wmi.c TPM DEVICE DRIVER M: Peter Huewe M: Jarkko Sakkinen -R: Jason Gunthorpe +R: Jason Gunthorpe L: linux-integrity@vger.kernel.org Q: https://patchwork.kernel.org/project/linux-integrity/list/ +W: https://kernsec.org/wiki/index.php/Linux_Kernel_Integrity T: git git://git.infradead.org/users/jjs/linux-tpmdd.git S: Maintained F: drivers/char/tpm/ @@ -13872,6 +14109,13 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial.git S: Maintained K: ^Subject:.*(?i)trivial +TEMPO SEMICONDUCTOR DRIVERS +M: Steven Eckhoff +S: Maintained +F: sound/soc/codecs/tscs*.c +F: sound/soc/codecs/tscs*.h +F: Documentation/devicetree/bindings/sound/tscs*.txt + TTY LAYER M: Greg Kroah-Hartman M: Jiri Slaby @@ -14033,6 +14277,8 @@ UNISYS S-PAR DRIVERS M: David Kershner L: sparmaintainer@unisys.com (Unisys internal) S: Supported +F: include/linux/visorbus.h +F: drivers/visorbus/ F: drivers/staging/unisys/ UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER @@ -14579,6 +14825,15 @@ S: Maintained F: drivers/virtio/virtio_input.c F: include/uapi/linux/virtio_input.h +VIRTUAL BOX GUEST DEVICE DRIVER +M: Hans de Goede +M: Arnd Bergmann +M: Greg Kroah-Hartman +S: Maintained +F: include/linux/vbox_utils.h +F: include/uapi/linux/vbox*.h +F: drivers/virt/vboxguest/ + VIRTUAL SERIO DEVICE DRIVER M: Stephen Chandler Paul S: Maintained @@ -14670,6 +14925,7 @@ W: http://www.slimlogic.co.uk/?p=48 T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git S: Supported F: Documentation/devicetree/bindings/regulator/ +F: Documentation/power/regulator/ F: drivers/regulator/ F: include/dt-bindings/regulator/ F: include/linux/regulator/ @@ -14742,8 +14998,8 @@ S: Maintained F: drivers/input/tablet/wacom_serial4.c WATCHDOG DEVICE DRIVERS -M: Wim Van Sebroeck -R: Guenter Roeck +M: Wim Van Sebroeck +M: Guenter Roeck L: linux-watchdog@vger.kernel.org W: http://www.linux-watchdog.org/ T: git git://www.linux-watchdog.org/linux-watchdog.git @@ -14767,9 +15023,9 @@ S: Maintained F: drivers/hid/hid-wiimote* WILOCITY WIL6210 WIRELESS DRIVER -M: Maya Erez +M: Maya Erez L: linux-wireless@vger.kernel.org -L: wil6210@qca.qualcomm.com +L: wil6210@qti.qualcomm.com S: Supported W: http://wireless.kernel.org/en/users/Drivers/wil6210 F: drivers/net/wireless/ath/wil6210/ @@ -14863,6 +15119,12 @@ F: include/linux/workqueue.h F: kernel/workqueue.c F: Documentation/core-api/workqueue.rst +X-POWERS AXP288 PMIC DRIVERS +M: Hans de Goede +S: Maintained +N: axp288 +F: drivers/acpi/pmic/intel_pmic_xpower.c + X-POWERS MULTIFUNCTION PMIC DEVICE DRIVERS M: Chen-Yu Tsai L: linux-kernel@vger.kernel.org @@ -14880,7 +15142,7 @@ F: net/x25/ X86 ARCHITECTURE (32-BIT AND 64-BIT) M: Thomas Gleixner M: Ingo Molnar -M: "H. Peter Anvin" +R: "H. Peter Anvin" M: x86@kernel.org L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/core @@ -14904,7 +15166,7 @@ X86 PLATFORM DRIVERS M: Darren Hart M: Andy Shevchenko L: platform-driver-x86@vger.kernel.org -T: git git://git.infradead.org/users/dvhart/linux-platform-drivers-x86.git +T: git git://git.infradead.org/linux-platform-drivers-x86.git S: Maintained F: drivers/platform/x86/ F: drivers/platform/olpc/ @@ -14990,6 +15252,7 @@ F: include/xen/interface/io/vscsiif.h XEN SWIOTLB SUBSYSTEM M: Konrad Rzeszutek Wilk L: xen-devel@lists.xenproject.org (moderated for non-subscribers) +L: iommu@lists.linux-foundation.org S: Supported F: arch/x86/xen/*swiotlb* F: drivers/xen/*swiotlb* diff --git a/Makefile b/Makefile index bf5b8cbb9469..79ad2bfa24b6 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 -PATCHLEVEL = 15 +PATCHLEVEL = 16 SUBLEVEL = 0 -EXTRAVERSION = -rc8 +EXTRAVERSION = -rc1 NAME = Fearless Coyote # *DOCUMENTATION* @@ -377,6 +377,8 @@ NM = $(CROSS_COMPILE)nm STRIP = $(CROSS_COMPILE)strip OBJCOPY = $(CROSS_COMPILE)objcopy OBJDUMP = $(CROSS_COMPILE)objdump +LEX = flex +YACC = bison AWK = awk GENKSYMS = scripts/genksyms/genksyms INSTALLKERNEL := installkernel @@ -428,11 +430,12 @@ GCC_PLUGINS_CFLAGS := export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC export CPP AR NM STRIP OBJCOPY OBJDUMP HOSTLDFLAGS HOST_LOADLIBES -export MAKE AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE +export MAKE LEX YACC AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS -export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_KASAN CFLAGS_UBSAN +export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE +export CFLAGS_KASAN CFLAGS_KASAN_NOSANITIZE CFLAGS_UBSAN export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL @@ -677,6 +680,10 @@ endif # This selects the stack protector compiler flag. Testing it is delayed # until after .config has been reprocessed, in the prepare-compiler-check # target. +ifdef CONFIG_CC_STACKPROTECTOR_AUTO + stackp-flag := $(call cc-option,-fstack-protector-strong,$(call cc-option,-fstack-protector)) + stackp-name := AUTO +else ifdef CONFIG_CC_STACKPROTECTOR_REGULAR stackp-flag := -fstack-protector stackp-name := REGULAR @@ -685,20 +692,43 @@ ifdef CONFIG_CC_STACKPROTECTOR_STRONG stackp-flag := -fstack-protector-strong stackp-name := STRONG else + # If either there is no stack protector for this architecture or + # CONFIG_CC_STACKPROTECTOR_NONE is selected, we're done, and $(stackp-name) + # is empty, skipping all remaining stack protector tests. + # # Force off for distro compilers that enable stack protector by default. - stackp-flag := $(call cc-option, -fno-stack-protector) + KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector) +endif endif endif # Find arch-specific stack protector compiler sanity-checking script. -ifdef CONFIG_CC_STACKPROTECTOR +ifdef stackp-name +ifneq ($(stackp-flag),) stackp-path := $(srctree)/scripts/gcc-$(SRCARCH)_$(BITS)-has-stack-protector.sh stackp-check := $(wildcard $(stackp-path)) + # If the wildcard test matches a test script, run it to check functionality. + ifdef stackp-check + ifneq ($(shell $(CONFIG_SHELL) $(stackp-check) $(CC) $(KBUILD_CPPFLAGS) $(biarch)),y) + stackp-broken := y + endif + endif + ifndef stackp-broken + # If the stack protector is functional, enable code that depends on it. + KBUILD_CPPFLAGS += -DCONFIG_CC_STACKPROTECTOR + # Either we've already detected the flag (for AUTO) or we'll fail the + # build in the prepare-compiler-check rule (for specific flag). + KBUILD_CFLAGS += $(stackp-flag) + else + # We have to make sure stack protector is unconditionally disabled if + # the compiler is broken (in case we're going to continue the build in + # AUTO mode). + KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector) + endif +endif endif -KBUILD_CFLAGS += $(stackp-flag) ifeq ($(cc-name),clang) KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,) -KBUILD_CFLAGS += $(call cc-disable-warning, unused-variable) KBUILD_CFLAGS += $(call cc-disable-warning, format-invalid-specifier) KBUILD_CFLAGS += $(call cc-disable-warning, gnu) KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member) @@ -716,9 +746,9 @@ else # These warnings generated too much noise in a regular build. # Use make W=1 to enable them (see scripts/Makefile.extrawarn) KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable) -KBUILD_CFLAGS += $(call cc-disable-warning, unused-const-variable) endif +KBUILD_CFLAGS += $(call cc-disable-warning, unused-const-variable) ifdef CONFIG_FRAME_POINTER KBUILD_CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls else @@ -1089,14 +1119,25 @@ PHONY += prepare-compiler-check prepare-compiler-check: FORCE # Make sure compiler supports requested stack protector flag. ifdef stackp-name + # Warn about CONFIG_CC_STACKPROTECTOR_AUTO having found no option. + ifeq ($(stackp-flag),) + @echo CONFIG_CC_STACKPROTECTOR_$(stackp-name): \ + Compiler does not support any known stack-protector >&2 + else + # Fail if specifically requested stack protector is missing. ifeq ($(call cc-option, $(stackp-flag)),) @echo Cannot use CONFIG_CC_STACKPROTECTOR_$(stackp-name): \ $(stackp-flag) not supported by compiler >&2 && exit 1 endif + endif endif -# Make sure compiler does not have buggy stack-protector support. -ifdef stackp-check - ifneq ($(shell $(CONFIG_SHELL) $(stackp-check) $(CC) $(KBUILD_CPPFLAGS) $(biarch)),y) +# Make sure compiler does not have buggy stack-protector support. If a +# specific stack-protector was requested, fail the build, otherwise warn. +ifdef stackp-broken + ifeq ($(stackp-name),AUTO) + @echo CONFIG_CC_STACKPROTECTOR_$(stackp-name): \ + $(stackp-flag) available but compiler is broken: disabling >&2 + else @echo Cannot use CONFIG_CC_STACKPROTECTOR_$(stackp-name): \ $(stackp-flag) available but compiler is broken >&2 && exit 1 endif diff --git a/arch/Kconfig b/arch/Kconfig index 400b9e1b2f27..76c0b54443b1 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -196,6 +196,9 @@ config HAVE_OPTPROBES config HAVE_KPROBES_ON_FTRACE bool +config HAVE_FUNCTION_ERROR_INJECTION + bool + config HAVE_NMI bool @@ -234,14 +237,25 @@ config ARCH_HAS_FORTIFY_SOURCE config ARCH_HAS_SET_MEMORY bool -# Select if arch init_task initializer is different to init/init_task.c -config ARCH_INIT_TASK +# Select if arch init_task must go in the __init_task_data section +config ARCH_TASK_STRUCT_ON_STACK bool # Select if arch has its private alloc_task_struct() function config ARCH_TASK_STRUCT_ALLOCATOR bool +config HAVE_ARCH_THREAD_STRUCT_WHITELIST + bool + depends on !ARCH_TASK_STRUCT_ALLOCATOR + help + An architecture should select this to provide hardened usercopy + knowledge about what region of the thread_struct should be + whitelisted for copying to userspace. Normally this is only the + FPU registers. Specifically, arch_thread_struct_whitelist() + should be implemented. Without this, the entire thread_struct + field in task_struct will be left whitelisted. + # Select if arch has its private alloc_thread_stack() function config ARCH_THREAD_STACK_ALLOCATOR bool @@ -524,16 +538,10 @@ config HAVE_CC_STACKPROTECTOR - its compiler supports the -fstack-protector option - it has implemented a stack canary (e.g. __stack_chk_guard) -config CC_STACKPROTECTOR - def_bool n - help - Set when a stack-protector mode is enabled, so that the build - can enable kernel-side support for the GCC feature. - choice prompt "Stack Protector buffer overflow detection" depends on HAVE_CC_STACKPROTECTOR - default CC_STACKPROTECTOR_NONE + default CC_STACKPROTECTOR_AUTO help This option turns on the "stack-protector" GCC feature. This feature puts, at the beginning of functions, a canary value on @@ -550,7 +558,6 @@ config CC_STACKPROTECTOR_NONE config CC_STACKPROTECTOR_REGULAR bool "Regular" - select CC_STACKPROTECTOR help Functions will have the stack-protector canary logic added if they have an 8-byte or larger character array on the stack. @@ -564,7 +571,6 @@ config CC_STACKPROTECTOR_REGULAR config CC_STACKPROTECTOR_STRONG bool "Strong" - select CC_STACKPROTECTOR help Functions will have the stack-protector canary logic added in any of the following conditions: @@ -582,6 +588,12 @@ config CC_STACKPROTECTOR_STRONG about 20% of all kernel functions, which increases the kernel code size by about 2%. +config CC_STACKPROTECTOR_AUTO + bool "Automatic" + help + If the compiler supports it, the best available stack-protector + option will be chosen. + endchoice config THIN_ARCHIVES @@ -938,6 +950,10 @@ config STRICT_MODULE_RWX and non-text memory will be made non-executable. This provides protection against certain security exploits (e.g. writing to text) +# select if the architecture provides an asm/dma-direct.h header +config ARCH_HAS_PHYS_TO_DMA + bool + config ARCH_HAS_REFCOUNT bool help diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index b31b974a03cb..e96adcbcab41 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -209,6 +209,7 @@ config ALPHA_EIGER config ALPHA_JENSEN bool "Jensen" + depends on BROKEN help DEC PC 150 AXP (aka Jensen): This is a very old Digital system - one of the first-generation Alpha systems. A number of these systems diff --git a/arch/alpha/include/asm/Kbuild b/arch/alpha/include/asm/Kbuild index 47f3fba3e41f..9b68790013e2 100644 --- a/arch/alpha/include/asm/Kbuild +++ b/arch/alpha/include/asm/Kbuild @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -generic-y += clkdev.h generic-y += exec.h generic-y += export.h generic-y += fb.h diff --git a/arch/alpha/include/asm/asm-prototypes.h b/arch/alpha/include/asm/asm-prototypes.h index d12c68ea340b..b34cc1f06720 100644 --- a/arch/alpha/include/asm/asm-prototypes.h +++ b/arch/alpha/include/asm/asm-prototypes.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include diff --git a/arch/alpha/include/asm/futex.h b/arch/alpha/include/asm/futex.h index d2e4da93e68c..ca3322536f72 100644 --- a/arch/alpha/include/asm/futex.h +++ b/arch/alpha/include/asm/futex.h @@ -20,8 +20,8 @@ "3: .subsection 2\n" \ "4: br 1b\n" \ " .previous\n" \ - EXC(1b,3b,%1,$31) \ - EXC(2b,3b,%1,$31) \ + EXC(1b,3b,$31,%1) \ + EXC(2b,3b,$31,%1) \ : "=&r" (oldval), "=&r"(ret) \ : "r" (uaddr), "r"(oparg) \ : "memory") @@ -82,8 +82,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, "3: .subsection 2\n" "4: br 1b\n" " .previous\n" - EXC(1b,3b,%0,$31) - EXC(2b,3b,%0,$31) + EXC(1b,3b,$31,%0) + EXC(2b,3b,$31,%0) : "+r"(ret), "=&r"(prev), "=&r"(cmp) : "r"(uaddr), "r"((long)(int)oldval), "r"(newval) : "memory"); diff --git a/arch/alpha/include/asm/processor.h b/arch/alpha/include/asm/processor.h index bfe784f2d4af..cb05d045efe3 100644 --- a/arch/alpha/include/asm/processor.h +++ b/arch/alpha/include/asm/processor.h @@ -40,15 +40,12 @@ typedef struct { struct thread_struct { }; #define INIT_THREAD { } -/* Return saved PC of a blocked thread. */ -struct task_struct; -extern unsigned long thread_saved_pc(struct task_struct *); - /* Do necessary setup to start up a newly executed thread. */ struct pt_regs; extern void start_thread(struct pt_regs *, unsigned long, unsigned long); /* Free all resources held by a thread. */ +struct task_struct; extern void release_thread(struct task_struct *); unsigned long get_wchan(struct task_struct *p); diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h index 8c20c5e35432..807d7b9a1860 100644 --- a/arch/alpha/include/asm/thread_info.h +++ b/arch/alpha/include/asm/thread_info.h @@ -39,9 +39,6 @@ struct thread_info { .preempt_count = INIT_PREEMPT_COUNT, \ } -#define init_thread_info (init_thread_union.thread_info) -#define init_stack (init_thread_union.stack) - /* How to get the thread information struct from C. */ register struct thread_info *__current_thread_info __asm__("$8"); #define current_thread_info() __current_thread_info diff --git a/arch/alpha/include/uapi/asm/Kbuild b/arch/alpha/include/uapi/asm/Kbuild index 14a2e9af97e9..9afaba5e5503 100644 --- a/arch/alpha/include/uapi/asm/Kbuild +++ b/arch/alpha/include/uapi/asm/Kbuild @@ -2,3 +2,4 @@ include include/uapi/asm-generic/Kbuild.asm generic-y += bpf_perf_event.h +generic-y += poll.h diff --git a/arch/alpha/include/uapi/asm/poll.h b/arch/alpha/include/uapi/asm/poll.h deleted file mode 100644 index b7132a305a47..000000000000 --- a/arch/alpha/include/uapi/asm/poll.h +++ /dev/null @@ -1,2 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#include diff --git a/arch/alpha/include/uapi/asm/termbits.h b/arch/alpha/include/uapi/asm/termbits.h index 05e0398a83a6..de6c8360fbe3 100644 --- a/arch/alpha/include/uapi/asm/termbits.h +++ b/arch/alpha/include/uapi/asm/termbits.h @@ -110,7 +110,11 @@ struct ktermios { #define VTDLY 00200000 #define VT0 00000000 #define VT1 00200000 -#define XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */ +/* + * Should be equivalent to TAB3, see description of TAB3 in + * POSIX.1-2008, Ch. 11.2.3 "Output Modes" + */ +#define XTABS TAB3 /* c_cflag bit meaning */ #define CBAUD 0000037 diff --git a/arch/alpha/kernel/console.c b/arch/alpha/kernel/console.c index 8e9a41966881..5476279329a6 100644 --- a/arch/alpha/kernel/console.c +++ b/arch/alpha/kernel/console.c @@ -21,6 +21,7 @@ struct pci_controller *pci_vga_hose; static struct resource alpha_vga = { .name = "alpha-vga+", + .flags = IORESOURCE_IO, .start = 0x3C0, .end = 0x3DF }; diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index ce3a675c0c4b..fa1a392ca9a2 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -950,22 +950,31 @@ struct itimerval32 }; static inline long -get_tv32(struct timeval *o, struct timeval32 __user *i) +get_tv32(struct timespec64 *o, struct timeval32 __user *i) { struct timeval32 tv; if (copy_from_user(&tv, i, sizeof(struct timeval32))) return -EFAULT; o->tv_sec = tv.tv_sec; - o->tv_usec = tv.tv_usec; + o->tv_nsec = tv.tv_usec * NSEC_PER_USEC; return 0; } static inline long -put_tv32(struct timeval32 __user *o, struct timeval *i) +put_tv32(struct timeval32 __user *o, struct timespec64 *i) { return copy_to_user(o, &(struct timeval32){ - .tv_sec = o->tv_sec, - .tv_usec = o->tv_usec}, + .tv_sec = i->tv_sec, + .tv_usec = i->tv_nsec / NSEC_PER_USEC}, + sizeof(struct timeval32)); +} + +static inline long +put_tv_to_tv32(struct timeval32 __user *o, struct timeval *i) +{ + return copy_to_user(o, &(struct timeval32){ + .tv_sec = i->tv_sec, + .tv_usec = i->tv_usec}, sizeof(struct timeval32)); } @@ -1004,9 +1013,10 @@ SYSCALL_DEFINE2(osf_gettimeofday, struct timeval32 __user *, tv, struct timezone __user *, tz) { if (tv) { - struct timeval ktv; - do_gettimeofday(&ktv); - if (put_tv32(tv, &ktv)) + struct timespec64 kts; + + ktime_get_real_ts64(&kts); + if (put_tv32(tv, &kts)) return -EFAULT; } if (tz) { @@ -1019,22 +1029,19 @@ SYSCALL_DEFINE2(osf_gettimeofday, struct timeval32 __user *, tv, SYSCALL_DEFINE2(osf_settimeofday, struct timeval32 __user *, tv, struct timezone __user *, tz) { - struct timespec64 kts64; - struct timespec kts; + struct timespec64 kts; struct timezone ktz; if (tv) { - if (get_tv32((struct timeval *)&kts, tv)) + if (get_tv32(&kts, tv)) return -EFAULT; - kts.tv_nsec *= 1000; - kts64 = timespec_to_timespec64(kts); } if (tz) { if (copy_from_user(&ktz, tz, sizeof(*tz))) return -EFAULT; } - return do_sys_settimeofday64(tv ? &kts64 : NULL, tz ? &ktz : NULL); + return do_sys_settimeofday64(tv ? &kts : NULL, tz ? &ktz : NULL); } asmlinkage long sys_ni_posix_timers(void); @@ -1083,22 +1090,16 @@ SYSCALL_DEFINE3(osf_setitimer, int, which, struct itimerval32 __user *, in, SYSCALL_DEFINE2(osf_utimes, const char __user *, filename, struct timeval32 __user *, tvs) { - struct timespec tv[2]; + struct timespec64 tv[2]; if (tvs) { - struct timeval ktvs[2]; - if (get_tv32(&ktvs[0], &tvs[0]) || - get_tv32(&ktvs[1], &tvs[1])) + if (get_tv32(&tv[0], &tvs[0]) || + get_tv32(&tv[1], &tvs[1])) return -EFAULT; - if (ktvs[0].tv_usec < 0 || ktvs[0].tv_usec >= 1000000 || - ktvs[1].tv_usec < 0 || ktvs[1].tv_usec >= 1000000) + if (tv[0].tv_nsec < 0 || tv[0].tv_nsec >= 1000000000 || + tv[1].tv_nsec < 0 || tv[1].tv_nsec >= 1000000000) return -EINVAL; - - tv[0].tv_sec = ktvs[0].tv_sec; - tv[0].tv_nsec = 1000 * ktvs[0].tv_usec; - tv[1].tv_sec = ktvs[1].tv_sec; - tv[1].tv_nsec = 1000 * ktvs[1].tv_usec; } return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL, 0); @@ -1107,19 +1108,18 @@ SYSCALL_DEFINE2(osf_utimes, const char __user *, filename, SYSCALL_DEFINE5(osf_select, int, n, fd_set __user *, inp, fd_set __user *, outp, fd_set __user *, exp, struct timeval32 __user *, tvp) { - struct timespec end_time, *to = NULL; + struct timespec64 end_time, *to = NULL; if (tvp) { - struct timeval tv; + struct timespec64 tv; to = &end_time; if (get_tv32(&tv, tvp)) return -EFAULT; - if (tv.tv_sec < 0 || tv.tv_usec < 0) + if (tv.tv_sec < 0 || tv.tv_nsec < 0) return -EINVAL; - if (poll_select_set_timeout(to, tv.tv_sec, - tv.tv_usec * NSEC_PER_USEC)) + if (poll_select_set_timeout(to, tv.tv_sec, tv.tv_nsec)) return -EINVAL; } @@ -1192,9 +1192,9 @@ SYSCALL_DEFINE4(osf_wait4, pid_t, pid, int __user *, ustatus, int, options, return -EFAULT; if (!ur) return err; - if (put_tv32(&ur->ru_utime, &r.ru_utime)) + if (put_tv_to_tv32(&ur->ru_utime, &r.ru_utime)) return -EFAULT; - if (put_tv32(&ur->ru_stime, &r.ru_stime)) + if (put_tv_to_tv32(&ur->ru_stime, &r.ru_stime)) return -EFAULT; if (copy_to_user(&ur->ru_maxrss, &r.ru_maxrss, sizeof(struct rusage32) - offsetof(struct rusage32, ru_maxrss))) @@ -1210,18 +1210,18 @@ SYSCALL_DEFINE4(osf_wait4, pid_t, pid, int __user *, ustatus, int, options, SYSCALL_DEFINE2(osf_usleep_thread, struct timeval32 __user *, sleep, struct timeval32 __user *, remain) { - struct timeval tmp; + struct timespec64 tmp; unsigned long ticks; if (get_tv32(&tmp, sleep)) goto fault; - ticks = timeval_to_jiffies(&tmp); + ticks = timespec64_to_jiffies(&tmp); ticks = schedule_timeout_interruptible(ticks); if (remain) { - jiffies_to_timeval(ticks, &tmp); + jiffies_to_timespec64(ticks, &tmp); if (put_tv32(remain, &tmp)) goto fault; } @@ -1280,7 +1280,7 @@ SYSCALL_DEFINE1(old_adjtimex, struct timex32 __user *, txc_p) if (copy_to_user(txc_p, &txc, offsetof(struct timex32, time)) || (copy_to_user(&txc_p->tick, &txc.tick, sizeof(struct timex32) - offsetof(struct timex32, tick))) || - (put_tv32(&txc_p->time, &txc.time))) + (put_tv_to_tv32(&txc_p->time, &txc.time))) return -EFAULT; return ret; diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index 87da00579946..2e86ebb680ae 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c @@ -425,7 +425,7 @@ sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn) if (bus == 0 && dfn == 0) { hose = pci_isa_hose; } else { - dev = pci_get_bus_and_slot(bus, dfn); + dev = pci_get_domain_bus_and_slot(0, bus, dfn); if (!dev) return -ENODEV; hose = dev->sysdata; diff --git a/arch/alpha/kernel/pci_impl.h b/arch/alpha/kernel/pci_impl.h index 2e4cb74fdc41..18043af45e2b 100644 --- a/arch/alpha/kernel/pci_impl.h +++ b/arch/alpha/kernel/pci_impl.h @@ -144,7 +144,8 @@ struct pci_iommu_arena }; #if defined(CONFIG_ALPHA_SRM) && \ - (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA)) + (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA) || \ + defined(CONFIG_ALPHA_AVANTI)) # define NEED_SRM_SAVE_RESTORE #else # undef NEED_SRM_SAVE_RESTORE diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 74bfb1f2d68e..48b81d015d8a 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -269,12 +269,13 @@ copy_thread(unsigned long clone_flags, unsigned long usp, application calling fork. */ if (clone_flags & CLONE_SETTLS) childti->pcb.unique = regs->r20; + else + regs->r20 = 0; /* OSF/1 has some strange fork() semantics. */ childti->pcb.usp = usp ?: rdusp(); *childregs = *regs; childregs->r0 = 0; childregs->r19 = 0; childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */ - regs->r20 = 0; stack = ((struct switch_stack *) regs) - 1; *childstack = *stack; childstack->r26 = (unsigned long) ret_from_fork; @@ -361,7 +362,7 @@ EXPORT_SYMBOL(dump_elf_task_fp); * all. -- r~ */ -unsigned long +static unsigned long thread_saved_pc(struct task_struct *t) { unsigned long base = (unsigned long)task_stack_page(t); diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c index 239dc0e601d5..ff4f54b86c7f 100644 --- a/arch/alpha/kernel/sys_nautilus.c +++ b/arch/alpha/kernel/sys_nautilus.c @@ -237,7 +237,7 @@ nautilus_init_pci(void) bus = hose->bus = bridge->bus; pcibios_claim_one_bus(bus); - irongate = pci_get_bus_and_slot(0, 0); + irongate = pci_get_domain_bus_and_slot(pci_domain_nr(bus), 0, 0); bus->self = irongate; bus->resource[0] = &irongate_io; bus->resource[1] = &irongate_mem; diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c index 37bd6d9b8eb9..a6bdc1da47ad 100644 --- a/arch/alpha/kernel/sys_sio.c +++ b/arch/alpha/kernel/sys_sio.c @@ -102,6 +102,15 @@ sio_pci_route(void) alpha_mv.sys.sio.route_tab); } +static bool sio_pci_dev_irq_needs_level(const struct pci_dev *dev) +{ + if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) && + (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA)) + return false; + + return true; +} + static unsigned int __init sio_collect_irq_levels(void) { @@ -110,8 +119,7 @@ sio_collect_irq_levels(void) /* Iterate through the devices, collecting IRQ levels. */ for_each_pci_dev(dev) { - if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) && - (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA)) + if (!sio_pci_dev_irq_needs_level(dev)) continue; if (dev->irq) @@ -120,8 +128,7 @@ sio_collect_irq_levels(void) return level_bits; } -static void __init -sio_fixup_irq_levels(unsigned int level_bits) +static void __sio_fixup_irq_levels(unsigned int level_bits, bool reset) { unsigned int old_level_bits; @@ -139,12 +146,21 @@ sio_fixup_irq_levels(unsigned int level_bits) */ old_level_bits = inb(0x4d0) | (inb(0x4d1) << 8); - level_bits |= (old_level_bits & 0x71ff); + if (reset) + old_level_bits &= 0x71ff; + + level_bits |= old_level_bits; outb((level_bits >> 0) & 0xff, 0x4d0); outb((level_bits >> 8) & 0xff, 0x4d1); } +static inline void +sio_fixup_irq_levels(unsigned int level_bits) +{ + __sio_fixup_irq_levels(level_bits, true); +} + static inline int noname_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { @@ -181,7 +197,14 @@ noname_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) const long min_idsel = 6, max_idsel = 14, irqs_per_slot = 5; int irq = COMMON_TABLE_LOOKUP, tmp; tmp = __kernel_extbl(alpha_mv.sys.sio.route_tab, irq); - return irq >= 0 ? tmp : -1; + + irq = irq >= 0 ? tmp : -1; + + /* Fixup IRQ level if an actual IRQ mapping is detected */ + if (sio_pci_dev_irq_needs_level(dev) && irq >= 0) + __sio_fixup_irq_levels(1 << irq, false); + + return irq; } static inline int diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index 4bd99a7b1c41..f43bd05dede2 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -160,11 +160,16 @@ void show_stack(struct task_struct *task, unsigned long *sp) for(i=0; i < kstack_depth_to_print; i++) { if (((long) stack & (THREAD_SIZE-1)) == 0) break; - if (i && ((i % 4) == 0)) - printk("\n "); - printk("%016lx ", *stack++); + if ((i % 4) == 0) { + if (i) + pr_cont("\n"); + printk(" "); + } else { + pr_cont(" "); + } + pr_cont("%016lx", *stack++); } - printk("\n"); + pr_cont("\n"); dik_show_trace(sp); } diff --git a/arch/alpha/lib/ev6-memset.S b/arch/alpha/lib/ev6-memset.S index 316a99aa9efe..1cfcfbbea6f0 100644 --- a/arch/alpha/lib/ev6-memset.S +++ b/arch/alpha/lib/ev6-memset.S @@ -18,7 +18,7 @@ * The algorithm for the leading and trailing quadwords remains the same, * however the loop has been unrolled to enable better memory throughput, * and the code has been replicated for each of the entry points: __memset - * and __memsetw to permit better scheduling to eliminate the stalling + * and __memset16 to permit better scheduling to eliminate the stalling * encountered during the mask replication. * A future enhancement might be to put in a byte store loop for really * small (say < 32 bytes) memset()s. Whether or not that change would be @@ -34,7 +34,7 @@ .globl memset .globl __memset .globl ___memset - .globl __memsetw + .globl __memset16 .globl __constant_c_memset .ent ___memset @@ -415,9 +415,9 @@ end: * to mask stalls. Note that entry point names also had to change */ .align 5 - .ent __memsetw + .ent __memset16 -__memsetw: +__memset16: .frame $30,0,$26,0 .prologue 0 @@ -596,8 +596,8 @@ end_w: nop ret $31,($26),1 # L0 : - .end __memsetw - EXPORT_SYMBOL(__memsetw) + .end __memset16 + EXPORT_SYMBOL(__memset16) memset = ___memset __memset = ___memset diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 9d5fd00d9e91..f3a80cf164cc 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -463,9 +463,6 @@ config ARCH_PHYS_ADDR_T_64BIT config ARCH_DMA_ADDR_T_64BIT bool -config ARC_PLAT_NEEDS_PHYS_TO_DMA - bool - config ARC_KVADDR_SIZE int "Kernel Virtual Address Space size (MB)" range 0 512 diff --git a/arch/arc/configs/axs101_defconfig b/arch/arc/configs/axs101_defconfig index ec7c849a5c8e..09f85154c5a4 100644 --- a/arch/arc/configs/axs101_defconfig +++ b/arch/arc/configs/axs101_defconfig @@ -44,7 +44,6 @@ CONFIG_IP_PNP_RARP=y CONFIG_DEVTMPFS=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_NETDEVICES=y diff --git a/arch/arc/configs/axs103_defconfig b/arch/arc/configs/axs103_defconfig index 63d3cf69e0b0..09fed3ef22b6 100644 --- a/arch/arc/configs/axs103_defconfig +++ b/arch/arc/configs/axs103_defconfig @@ -44,7 +44,6 @@ CONFIG_IP_PNP_RARP=y CONFIG_DEVTMPFS=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_BLK_DEV_LOOP=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y diff --git a/arch/arc/configs/axs103_smp_defconfig b/arch/arc/configs/axs103_smp_defconfig index f613ecac14a7..ea2f6d817d1a 100644 --- a/arch/arc/configs/axs103_smp_defconfig +++ b/arch/arc/configs/axs103_smp_defconfig @@ -45,7 +45,6 @@ CONFIG_IP_PNP_RARP=y CONFIG_DEVTMPFS=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_BLK_DEV_LOOP=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y diff --git a/arch/arc/configs/haps_hs_defconfig b/arch/arc/configs/haps_hs_defconfig index db04ea4dd2d9..ab231c040efe 100644 --- a/arch/arc/configs/haps_hs_defconfig +++ b/arch/arc/configs/haps_hs_defconfig @@ -40,7 +40,6 @@ CONFIG_INET=y CONFIG_DEVTMPFS=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FIRMWARE_IN_KERNEL is not set # CONFIG_BLK_DEV is not set CONFIG_NETDEVICES=y # CONFIG_NET_VENDOR_ARC is not set diff --git a/arch/arc/configs/haps_hs_smp_defconfig b/arch/arc/configs/haps_hs_smp_defconfig index 3507be2af6fe..cf449cbf440d 100644 --- a/arch/arc/configs/haps_hs_smp_defconfig +++ b/arch/arc/configs/haps_hs_smp_defconfig @@ -43,7 +43,6 @@ CONFIG_INET=y CONFIG_DEVTMPFS=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FIRMWARE_IN_KERNEL is not set # CONFIG_BLK_DEV is not set CONFIG_NETDEVICES=y # CONFIG_NET_VENDOR_ARC is not set diff --git a/arch/arc/configs/hsdk_defconfig b/arch/arc/configs/hsdk_defconfig index ac6b0ed8341e..1b54c72f4296 100644 --- a/arch/arc/configs/hsdk_defconfig +++ b/arch/arc/configs/hsdk_defconfig @@ -32,7 +32,6 @@ CONFIG_INET=y CONFIG_DEVTMPFS=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_NETDEVICES=y diff --git a/arch/arc/configs/nsim_700_defconfig b/arch/arc/configs/nsim_700_defconfig index 6dff83a238b8..31c2c70b34a1 100644 --- a/arch/arc/configs/nsim_700_defconfig +++ b/arch/arc/configs/nsim_700_defconfig @@ -36,7 +36,6 @@ CONFIG_INET=y CONFIG_DEVTMPFS=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FIRMWARE_IN_KERNEL is not set # CONFIG_BLK_DEV is not set CONFIG_NETDEVICES=y CONFIG_ARC_EMAC=y diff --git a/arch/arc/configs/nsim_hs_defconfig b/arch/arc/configs/nsim_hs_defconfig index 31ee51b987e7..a578c721d50f 100644 --- a/arch/arc/configs/nsim_hs_defconfig +++ b/arch/arc/configs/nsim_hs_defconfig @@ -40,7 +40,6 @@ CONFIG_INET=y CONFIG_DEVTMPFS=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FIRMWARE_IN_KERNEL is not set # CONFIG_BLK_DEV is not set # CONFIG_INPUT_MOUSEDEV_PSAUX is not set # CONFIG_INPUT_KEYBOARD is not set diff --git a/arch/arc/configs/nsim_hs_smp_defconfig b/arch/arc/configs/nsim_hs_smp_defconfig index 8d3b1f67cae4..37d7395f3272 100644 --- a/arch/arc/configs/nsim_hs_smp_defconfig +++ b/arch/arc/configs/nsim_hs_smp_defconfig @@ -39,7 +39,6 @@ CONFIG_INET=y CONFIG_DEVTMPFS=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FIRMWARE_IN_KERNEL is not set # CONFIG_BLK_DEV is not set # CONFIG_INPUT_MOUSEDEV_PSAUX is not set # CONFIG_INPUT_KEYBOARD is not set diff --git a/arch/arc/configs/nsimosci_defconfig b/arch/arc/configs/nsimosci_defconfig index 6168ce2ac2ef..1e1470e2a7f0 100644 --- a/arch/arc/configs/nsimosci_defconfig +++ b/arch/arc/configs/nsimosci_defconfig @@ -35,7 +35,6 @@ CONFIG_INET=y CONFIG_DEVTMPFS=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FIRMWARE_IN_KERNEL is not set # CONFIG_BLK_DEV is not set CONFIG_NETDEVICES=y CONFIG_EZCHIP_NPS_MANAGEMENT_ENET=y diff --git a/arch/arc/configs/nsimosci_hs_defconfig b/arch/arc/configs/nsimosci_hs_defconfig index a70bdeb2b3fd..084a6e42685b 100644 --- a/arch/arc/configs/nsimosci_hs_defconfig +++ b/arch/arc/configs/nsimosci_hs_defconfig @@ -36,7 +36,6 @@ CONFIG_INET=y CONFIG_DEVTMPFS=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FIRMWARE_IN_KERNEL is not set # CONFIG_BLK_DEV is not set CONFIG_NETDEVICES=y CONFIG_EZCHIP_NPS_MANAGEMENT_ENET=y diff --git a/arch/arc/configs/nsimosci_hs_smp_defconfig b/arch/arc/configs/nsimosci_hs_smp_defconfig index ef96406c446e..f36d47990415 100644 --- a/arch/arc/configs/nsimosci_hs_smp_defconfig +++ b/arch/arc/configs/nsimosci_hs_smp_defconfig @@ -39,7 +39,6 @@ CONFIG_INET=y CONFIG_DEVTMPFS=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FIRMWARE_IN_KERNEL is not set # CONFIG_BLK_DEV is not set CONFIG_NETDEVICES=y # CONFIG_NET_VENDOR_ARC is not set diff --git a/arch/arc/configs/tb10x_defconfig b/arch/arc/configs/tb10x_defconfig index f30182549395..1aca2e8fd1ba 100644 --- a/arch/arc/configs/tb10x_defconfig +++ b/arch/arc/configs/tb10x_defconfig @@ -42,7 +42,6 @@ CONFIG_IP_MULTICAST=y # CONFIG_IPV6 is not set # CONFIG_WIRELESS is not set CONFIG_DEVTMPFS=y -# CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_NETDEVICES=y # CONFIG_NET_CADENCE is not set # CONFIG_NET_VENDOR_BROADCOM is not set diff --git a/arch/arc/configs/vdk_hs38_defconfig b/arch/arc/configs/vdk_hs38_defconfig index 4fcf4f2503f6..f629493929ea 100644 --- a/arch/arc/configs/vdk_hs38_defconfig +++ b/arch/arc/configs/vdk_hs38_defconfig @@ -31,7 +31,6 @@ CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y diff --git a/arch/arc/configs/vdk_hs38_smp_defconfig b/arch/arc/configs/vdk_hs38_smp_defconfig index 7b71464f6c2f..21f0ca26a05d 100644 --- a/arch/arc/configs/vdk_hs38_smp_defconfig +++ b/arch/arc/configs/vdk_hs38_smp_defconfig @@ -34,7 +34,6 @@ CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y diff --git a/arch/arc/include/asm/Kbuild b/arch/arc/include/asm/Kbuild index cd8398daccee..4bd5d4369e05 100644 --- a/arch/arc/include/asm/Kbuild +++ b/arch/arc/include/asm/Kbuild @@ -1,6 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 generic-y += bugs.h -generic-y += clkdev.h generic-y += device.h generic-y += div64.h generic-y += emergency-restart.h diff --git a/arch/arc/include/asm/dma-mapping.h b/arch/arc/include/asm/dma-mapping.h index 94285031c4fb..7a16824bfe98 100644 --- a/arch/arc/include/asm/dma-mapping.h +++ b/arch/arc/include/asm/dma-mapping.h @@ -11,13 +11,6 @@ #ifndef ASM_ARC_DMA_MAPPING_H #define ASM_ARC_DMA_MAPPING_H -#ifndef CONFIG_ARC_PLAT_NEEDS_PHYS_TO_DMA -#define plat_dma_to_phys(dev, dma_handle) ((phys_addr_t)(dma_handle)) -#define plat_phys_to_dma(dev, paddr) ((dma_addr_t)(paddr)) -#else -#include -#endif - extern const struct dma_map_ops arc_dma_ops; static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus) diff --git a/arch/arc/include/asm/hugepage.h b/arch/arc/include/asm/hugepage.h index b18fcb606908..dc8ee011882f 100644 --- a/arch/arc/include/asm/hugepage.h +++ b/arch/arc/include/asm/hugepage.h @@ -74,4 +74,7 @@ extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp); extern void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); +/* We don't have hardware dirty/accessed bits, generic_pmdp_establish is fine.*/ +#define pmdp_establish generic_pmdp_establish + #endif diff --git a/arch/arc/include/asm/thread_info.h b/arch/arc/include/asm/thread_info.h index 2d79e527fa50..c85947bac5e5 100644 --- a/arch/arc/include/asm/thread_info.h +++ b/arch/arc/include/asm/thread_info.h @@ -62,9 +62,6 @@ struct thread_info { .addr_limit = KERNEL_DS, \ } -#define init_thread_info (init_thread_union.thread_info) -#define init_stack (init_thread_union.stack) - static inline __attribute_const__ struct thread_info *current_thread_info(void) { register unsigned long sp asm("sp"); diff --git a/arch/arc/kernel/traps.c b/arch/arc/kernel/traps.c index 133a4dae41fe..b123558bf0bb 100644 --- a/arch/arc/kernel/traps.c +++ b/arch/arc/kernel/traps.c @@ -65,12 +65,14 @@ unhandled_exception(const char *str, struct pt_regs *regs, siginfo_t *info) #define DO_ERROR_INFO(signr, str, name, sicode) \ int name(unsigned long address, struct pt_regs *regs) \ { \ - siginfo_t info = { \ - .si_signo = signr, \ - .si_errno = 0, \ - .si_code = sicode, \ - .si_addr = (void __user *)address, \ - }; \ + siginfo_t info; \ + \ + clear_siginfo(&info); \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void __user *)address; \ + \ return unhandled_exception(str, regs, &info);\ } diff --git a/arch/arc/mm/dma.c b/arch/arc/mm/dma.c index e9d93604ad0f..1dcc404b5aec 100644 --- a/arch/arc/mm/dma.c +++ b/arch/arc/mm/dma.c @@ -60,7 +60,7 @@ static void *arc_dma_alloc(struct device *dev, size_t size, /* This is linear addr (0x8000_0000 based) */ paddr = page_to_phys(page); - *dma_handle = plat_phys_to_dma(dev, paddr); + *dma_handle = paddr; /* This is kernel Virtual address (0x7000_0000 based) */ if (need_kvaddr) { @@ -92,7 +92,7 @@ static void *arc_dma_alloc(struct device *dev, size_t size, static void arc_dma_free(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle, unsigned long attrs) { - phys_addr_t paddr = plat_dma_to_phys(dev, dma_handle); + phys_addr_t paddr = dma_handle; struct page *page = virt_to_page(paddr); int is_non_coh = 1; @@ -111,7 +111,7 @@ static int arc_dma_mmap(struct device *dev, struct vm_area_struct *vma, { unsigned long user_count = vma_pages(vma); unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; - unsigned long pfn = __phys_to_pfn(plat_dma_to_phys(dev, dma_addr)); + unsigned long pfn = __phys_to_pfn(dma_addr); unsigned long off = vma->vm_pgoff; int ret = -ENXIO; @@ -175,7 +175,7 @@ static dma_addr_t arc_dma_map_page(struct device *dev, struct page *page, if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) _dma_cache_sync(paddr, size, dir); - return plat_phys_to_dma(dev, paddr); + return paddr; } /* @@ -190,7 +190,7 @@ static void arc_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir, unsigned long attrs) { - phys_addr_t paddr = plat_dma_to_phys(dev, handle); + phys_addr_t paddr = handle; if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) _dma_cache_sync(paddr, size, dir); @@ -224,13 +224,13 @@ static void arc_dma_unmap_sg(struct device *dev, struct scatterlist *sg, static void arc_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction dir) { - _dma_cache_sync(plat_dma_to_phys(dev, dma_handle), size, DMA_FROM_DEVICE); + _dma_cache_sync(dma_handle, size, DMA_FROM_DEVICE); } static void arc_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction dir) { - _dma_cache_sync(plat_dma_to_phys(dev, dma_handle), size, DMA_TO_DEVICE); + _dma_cache_sync(dma_handle, size, DMA_TO_DEVICE); } static void arc_dma_sync_sg_for_cpu(struct device *dev, diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 51c8df561077..7e3d53575486 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -3,11 +3,12 @@ config ARM bool default y select ARCH_CLOCKSOURCE_DATA - select ARCH_DISCARD_MEMBLOCK if !HAVE_ARCH_PFN_VALID - select ARCH_HAS_DEBUG_VIRTUAL + select ARCH_DISCARD_MEMBLOCK if !HAVE_ARCH_PFN_VALID && !KEXEC + select ARCH_HAS_DEBUG_VIRTUAL if MMU select ARCH_HAS_DEVMEM_IS_ALLOWED select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_SET_MEMORY + select ARCH_HAS_PHYS_TO_DMA select ARCH_HAS_STRICT_KERNEL_RWX if MMU && !XIP_KERNEL select ARCH_HAS_STRICT_MODULE_RWX if MMU select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST @@ -24,7 +25,7 @@ config ARM select CLONE_BACKWARDS select CPU_PM if (SUSPEND || CPU_IDLE) select DCACHE_WORD_ACCESS if HAVE_EFFICIENT_UNALIGNED_ACCESS - select DMA_NOOP_OPS if !MMU + select DMA_DIRECT_OPS if !MMU select EDAC_SUPPORT select EDAC_ATOMIC_SCRUB select GENERIC_ALLOCATOR @@ -50,6 +51,7 @@ config ARM select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && MMU select HAVE_ARCH_MMAP_RND_BITS if MMU select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT) + select HAVE_ARCH_THREAD_STRUCT_WHITELIST select HAVE_ARCH_TRACEHOOK select HAVE_ARM_SMCCC if CPU_V7 select HAVE_EBPF_JIT if !CPU_ENDIAN_BE32 @@ -99,6 +101,7 @@ config ARM select OLD_SIGACTION select OLD_SIGSUSPEND3 select PERF_USE_VMALLOC + select REFCOUNT_FULL select RTC_LIB select SYS_SUPPORTS_APM_EMULATION # Above selects are sorted alphabetically; please add new ones @@ -595,6 +598,7 @@ config ARCH_S3C24XX select MULTI_IRQ_HANDLER select NEED_MACH_IO_H select SAMSUNG_ATAGS + select USE_OF help Samsung S3C2410, S3C2412, S3C2413, S3C2416, S3C2440, S3C2442, S3C2443 and S3C2450 SoCs based systems, such as the Simtec Electronics BAST @@ -1524,12 +1528,10 @@ config THUMB2_KERNEL bool "Compile the kernel in Thumb-2 mode" if !CPU_THUMBONLY depends on (CPU_V7 || CPU_V7M) && !CPU_V6 && !CPU_V6K default y if CPU_THUMBONLY - select ARM_ASM_UNIFIED select ARM_UNWIND help By enabling this option, the kernel will be compiled in - Thumb-2 mode. A compiler/assembler that understand the unified - ARM-Thumb syntax is needed. + Thumb-2 mode. If unsure, say N. @@ -1564,9 +1566,6 @@ config THUMB2_AVOID_R_ARM_THM_JUMP11 Unless you are sure your tools don't have this problem, say Y. -config ARM_ASM_UNIFIED - bool - config ARM_PATCH_IDIV bool "Runtime patch udiv/sdiv instructions into __aeabi_{u}idiv()" depends on CPU_32v7 && !XIP_KERNEL diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 17685e19aed8..78a647080ebc 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -3,10 +3,14 @@ menu "Kernel hacking" source "lib/Kconfig.debug" -config ARM_PTDUMP +config ARM_PTDUMP_CORE + def_bool n + +config ARM_PTDUMP_DEBUGFS bool "Export kernel pagetable layout to userspace via debugfs" depends on DEBUG_KERNEL depends on MMU + select ARM_PTDUMP_CORE select DEBUG_FS ---help--- Say Y here if you want to show the kernel pagetable layout in a @@ -16,6 +20,33 @@ config ARM_PTDUMP kernel. If in doubt, say "N" +config DEBUG_WX + bool "Warn on W+X mappings at boot" + select ARM_PTDUMP_CORE + ---help--- + Generate a warning if any W+X mappings are found at boot. + + This is useful for discovering cases where the kernel is leaving + W+X mappings after applying NX, as such mappings are a security risk. + + Look for a message in dmesg output like this: + + arm/mm: Checked W+X mappings: passed, no W+X pages found. + + or like this, if the check failed: + + arm/mm: Checked W+X mappings: FAILED, W+X pages found. + + Note that even if the check fails, your kernel is possibly + still fine, as W+X mappings are not a security hole in + themselves, what they do is that they make the exploitation + of other unfixed kernel bugs easier. + + There is no runtime or memory usage effect of this option + once the kernel has booted up - it's a one time check. + + If in doubt, say "Y". + # RMK wants arm kernels compiled with frame pointers or stack unwinding. # If you know what you are doing and are willing to live without stack # traces, you can get a slightly smaller kernel by setting this option to diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 80351e505fd5..e83f5161fdd8 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -115,9 +115,11 @@ ifeq ($(CONFIG_ARM_UNWIND),y) CFLAGS_ABI +=-funwind-tables endif +# Accept old syntax despite ".syntax unified" +AFLAGS_NOWARN :=$(call as-option,-Wa$(comma)-mno-warn-deprecated,-Wa$(comma)-W) + ifeq ($(CONFIG_THUMB2_KERNEL),y) AFLAGS_AUTOIT :=$(call as-option,-Wa$(comma)-mimplicit-it=always,-Wa$(comma)-mauto-it) -AFLAGS_NOWARN :=$(call as-option,-Wa$(comma)-mno-warn-deprecated,-Wa$(comma)-W) CFLAGS_ISA :=-mthumb $(AFLAGS_AUTOIT) $(AFLAGS_NOWARN) AFLAGS_ISA :=$(CFLAGS_ISA) -Wa$(comma)-mthumb # Work around buggy relocation from gas if requested: @@ -125,7 +127,7 @@ ifeq ($(CONFIG_THUMB2_AVOID_R_ARM_THM_JUMP11),y) KBUILD_CFLAGS_MODULE +=-fno-optimize-sibling-calls endif else -CFLAGS_ISA :=$(call cc-option,-marm,) +CFLAGS_ISA :=$(call cc-option,-marm,) $(AFLAGS_NOWARN) AFLAGS_ISA :=$(CFLAGS_ISA) endif diff --git a/arch/arm/boot/compressed/string.c b/arch/arm/boot/compressed/string.c index 309e1bbad75d..13c90abc68d6 100644 --- a/arch/arm/boot/compressed/string.c +++ b/arch/arm/boot/compressed/string.c @@ -130,8 +130,3 @@ void *memset(void *s, int c, size_t count) *xs++ = c; return s; } - -void __memzero(void *s, size_t count) -{ - memset(s, 0, count); -} diff --git a/arch/arm/boot/compressed/vmlinux.lds.S b/arch/arm/boot/compressed/vmlinux.lds.S index e6bf6774c4bb..2b963d8e76dd 100644 --- a/arch/arm/boot/compressed/vmlinux.lds.S +++ b/arch/arm/boot/compressed/vmlinux.lds.S @@ -56,6 +56,7 @@ SECTIONS .rodata : { *(.rodata) *(.rodata.*) + *(.data.rel.ro) } .piggydata : { *(.piggydata) @@ -101,6 +102,12 @@ SECTIONS * this symbol allows further debug in the near future. */ .image_end (NOLOAD) : { + /* + * EFI requires that the image is aligned to 512 bytes, and appended + * DTB requires that we know where the end of the image is. Ensure + * that both are satisfied by ensuring that there are no additional + * sections emitted into the decompressor image. + */ _edata_real = .; } @@ -128,3 +135,4 @@ SECTIONS .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } } +ASSERT(_edata_real == _edata, "error: zImage file size is incorrect"); diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index d0381e9caf21..ade7a38543dc 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -1,6 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -ifeq ($(CONFIG_OF),y) - dtb-$(CONFIG_ARCH_ALPINE) += \ alpine-db.dtb dtb-$(CONFIG_MACH_ARTPEC6) += \ @@ -47,7 +45,9 @@ dtb-$(CONFIG_SOC_AT91SAM9) += \ at91sam9x35ek.dtb dtb-$(CONFIG_SOC_SAM_V7) += \ at91-kizbox2.dtb \ + at91-nattis-2-natte-2.dtb \ at91-sama5d27_som1_ek.dtb \ + at91-sama5d2_ptc_ek.dtb \ at91-sama5d2_xplained.dtb \ at91-sama5d3_xplained.dtb \ at91-tse850-3.dtb \ @@ -192,6 +192,7 @@ dtb-$(CONFIG_ARCH_EXYNOS5) += \ exynos5800-peach-pi.dtb dtb-$(CONFIG_ARCH_GEMINI) += \ gemini-dlink-dir-685.dtb \ + gemini-dlink-dns-313.dtb \ gemini-nas4220b.dtb \ gemini-rut1xx.dtb \ gemini-sq201.dtb \ @@ -372,6 +373,8 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6dl-aristainetos2_7.dtb \ imx6dl-colibri-eval-v3.dtb \ imx6dl-cubox-i.dtb \ + imx6dl-cubox-i-emmc-som-v15.dtb \ + imx6dl-cubox-i-som-v15.dtb \ imx6dl-dfi-fs700-m60.dtb \ imx6dl-gw51xx.dtb \ imx6dl-gw52xx.dtb \ @@ -384,6 +387,11 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6dl-gw5903.dtb \ imx6dl-gw5904.dtb \ imx6dl-hummingboard.dtb \ + imx6dl-hummingboard-emmc-som-v15.dtb \ + imx6dl-hummingboard-som-v15.dtb \ + imx6dl-hummingboard2.dtb \ + imx6dl-hummingboard2-emmc-som-v15.dtb \ + imx6dl-hummingboard2-som-v15.dtb \ imx6dl-icore.dtb \ imx6dl-icore-rqs.dtb \ imx6dl-nit6xlite.dtb \ @@ -396,6 +404,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6dl-sabresd.dtb \ imx6dl-savageboard.dtb \ imx6dl-ts4900.dtb \ + imx6dl-ts7970.dtb \ imx6dl-tx6dl-comtft.dtb \ imx6dl-tx6s-8034.dtb \ imx6dl-tx6s-8034-mb7.dtb \ @@ -421,6 +430,8 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6q-b850v3.dtb \ imx6q-cm-fx6.dtb \ imx6q-cubox-i.dtb \ + imx6q-cubox-i-emmc-som-v15.dtb \ + imx6q-cubox-i-som-v15.dtb \ imx6q-dfi-fs700-m60.dtb \ imx6q-display5-tianma-tm070-1280x768.dtb \ imx6q-dmo-edmqmx6.dtb \ @@ -439,6 +450,11 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6q-gw5904.dtb \ imx6q-h100.dtb \ imx6q-hummingboard.dtb \ + imx6q-hummingboard-emmc-som-v15.dtb \ + imx6q-hummingboard-som-v15.dtb \ + imx6q-hummingboard2.dtb \ + imx6q-hummingboard2-emmc-som-v15.dtb \ + imx6q-hummingboard2-som-v15.dtb \ imx6q-icore.dtb \ imx6q-icore-ofcap10.dtb \ imx6q-icore-ofcap12.dtb \ @@ -459,6 +475,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6q-sbc6x.dtb \ imx6q-tbs2910.dtb \ imx6q-ts4900.dtb \ + imx6q-ts7970.dtb \ imx6q-tx6q-1010.dtb \ imx6q-tx6q-1010-comtft.dtb \ imx6q-tx6q-1020.dtb \ @@ -470,6 +487,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6q-tx6q-11x0-mb7.dtb \ imx6q-udoo.dtb \ imx6q-utilite-pro.dtb \ + imx6q-var-dt6customboard.dtb \ imx6q-wandboard.dtb \ imx6q-wandboard-revb1.dtb \ imx6q-wandboard-revd1.dtb \ @@ -511,15 +529,17 @@ dtb-$(CONFIG_SOC_IMX6UL) += \ imx6ull-14x14-evk.dtb dtb-$(CONFIG_SOC_IMX7D) += \ imx7d-cl-som-imx7.dtb \ + imx7d-colibri-emmc-eval-v3.dtb \ imx7d-colibri-eval-v3.dtb \ imx7d-nitrogen7.dtb \ - imx7d-pico.dtb \ + imx7d-pico-pi.dtb \ imx7d-sbc-imx7.dtb \ imx7d-sdb.dtb \ imx7d-sdb-sht11.dtb \ imx7s-colibri-eval-v3.dtb \ imx7s-warp.dtb dtb-$(CONFIG_SOC_LS1021A) += \ + ls1021a-moxa-uc-8410a.dtb \ ls1021a-qds.dtb \ ls1021a-twr.dtb dtb-$(CONFIG_SOC_VF610) += \ @@ -558,6 +578,7 @@ dtb-$(CONFIG_ARCH_MXS) += \ imx28-m28cu3.dtb \ imx28-m28evk.dtb \ imx28-sps1.dtb \ + imx28-ts4600.dtb \ imx28-tx28.dtb dtb-$(CONFIG_ARCH_NOMADIK) += \ ste-nomadik-s8815.dtb \ @@ -689,6 +710,7 @@ dtb-$(CONFIG_SOC_DRA7XX) += \ am57xx-sbc-am57x.dtb \ am572x-idk.dtb \ am571x-idk.dtb \ + am574x-idk.dtb \ dra7-evm.dtb \ dra72-evm.dtb \ dra72-evm-revc.dtb \ @@ -707,12 +729,13 @@ dtb-$(CONFIG_ARCH_ORION5X) += \ orion5x-rd88f5182-nas.dtb dtb-$(CONFIG_ARCH_ACTIONS) += \ owl-s500-cubieboard6.dtb \ - owl-s500-guitar-bb-rev-b.dtb + owl-s500-guitar-bb-rev-b.dtb \ + owl-s500-sparky.dtb dtb-$(CONFIG_ARCH_PRIMA2) += \ prima2-evb.dtb dtb-$(CONFIG_ARCH_OXNAS) += \ - wd-mbwe.dtb \ - cloudengines-pogoplug-series-3.dtb + ox810se-wd-mbwe.dtb \ + ox820-cloudengines-pogoplug-series-3.dtb dtb-$(CONFIG_ARCH_QCOM) += \ qcom-apq8060-dragonboard.dtb \ qcom-apq8064-arrow-sd-600eval.dtb \ @@ -756,6 +779,7 @@ dtb-$(CONFIG_ARCH_RENESAS) += \ r8a7743-iwg20d-q7-dbcm-ca.dtb \ r8a7743-sk-rzg1m.dtb \ r8a7745-iwg22d-sodimm.dtb \ + r8a7745-iwg22d-sodimm-dbhd-ca.dtb \ r8a7745-sk-rzg1e.dtb \ r8a7778-bockw.dtb \ r8a7779-marzen.dtb \ @@ -949,9 +973,11 @@ dtb-$(CONFIG_MACH_SUN8I) += \ sun8i-a83t-bananapi-m3.dtb \ sun8i-a83t-cubietruck-plus.dtb \ sun8i-a83t-tbs-a711.dtb \ + sun8i-h2-plus-orangepi-r1.dtb \ sun8i-h2-plus-orangepi-zero.dtb \ sun8i-h3-bananapi-m2-plus.dtb \ sun8i-h3-beelink-x2.dtb \ + sun8i-h3-libretech-all-h3-cc.dtb \ sun8i-h3-nanopi-m1.dtb \ sun8i-h3-nanopi-m1-plus.dtb \ sun8i-h3-nanopi-neo.dtb \ @@ -1101,7 +1127,10 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ mt8127-moose.dtb \ mt8135-evbp1.dtb dtb-$(CONFIG_ARCH_ZX) += zx296702-ad1.dtb -dtb-$(CONFIG_ARCH_ASPEED) += aspeed-bmc-opp-palmetto.dtb \ +dtb-$(CONFIG_ARCH_ASPEED) += \ + aspeed-ast2500-evb.dtb \ + aspeed-bmc-opp-palmetto.dtb \ aspeed-bmc-opp-romulus.dtb \ - aspeed-ast2500-evb.dtb -endif + aspeed-bmc-opp-witherspoon.dtb \ + aspeed-bmc-opp-zaius.dtb \ + aspeed-bmc-quanta-q71l.dtb diff --git a/arch/arm/boot/dts/am335x-bone-common.dtsi b/arch/arm/boot/dts/am335x-bone-common.dtsi index 48a15fc641f2..e67b4d65c8d0 100644 --- a/arch/arm/boot/dts/am335x-bone-common.dtsi +++ b/arch/arm/boot/dts/am335x-bone-common.dtsi @@ -409,6 +409,6 @@ }; &rtc { - clocks = <&clk_32768_ck>, <&clkdiv32k_ick>; + clocks = <&clk_32768_ck>, <&l4_per_clkctrl AM3_CLKDIV32K_CLKCTRL 0>; clock-names = "ext-clk", "int-clk"; }; diff --git a/arch/arm/boot/dts/am335x-boneblue.dts b/arch/arm/boot/dts/am335x-boneblue.dts index cdc1b2be792f..3f2480d05a3b 100644 --- a/arch/arm/boot/dts/am335x-boneblue.dts +++ b/arch/arm/boot/dts/am335x-boneblue.dts @@ -159,6 +159,7 @@ >; }; + /* UT0 */ uart0_pins: pinmux_uart0_pins { pinctrl-single,pins = < AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0) /* (E15) uart0_rxd.uart0_rxd */ @@ -166,6 +167,37 @@ >; }; + /* UT1 */ + uart1_pins: pinmux_uart1_pins { + pinctrl-single,pins = < + AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0) /* (D16) uart1_rxd.uart1_rxd */ + AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* (D15) uart1_txd.uart1_txd */ + >; + }; + + /* GPS */ + uart2_pins: pinmux_uart2_pins { + pinctrl-single,pins = < + AM33XX_IOPAD(0x950, PIN_INPUT_PULLUP | MUX_MODE1) /* (A17) spi0_sclk.uart2_rxd */ + AM33XX_IOPAD(0x954, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* (B17) spi0_d0.uart2_txd */ + >; + }; + + /* DSM2 */ + uart4_pins: pinmux_uart4_pins { + pinctrl-single,pins = < + AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE6) /* (T17) gpmc_wait0.uart4_rxd */ + >; + }; + + /* UT5 */ + uart5_pins: pinmux_uart5_pins { + pinctrl-single,pins = < + AM33XX_IOPAD(0x8C4, PIN_INPUT_PULLUP | MUX_MODE4) /* (U2) lcd_data9.uart5_rxd */ + AM33XX_IOPAD(0x8C0, PIN_OUTPUT_PULLDOWN | MUX_MODE4) /* (U1) lcd_data8.uart5_txd */ + >; + }; + mmc1_pins: pinmux_mmc1_pins { pinctrl-single,pins = < AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE7) /* (C15) spi0_cs1.gpio0[6] */ @@ -216,10 +248,19 @@ wl18xx_pins: pinmux_wl18xx_pins { pinctrl-single,pins = < AM33XX_IOPAD(0x92c, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* (K18) gmii1_txclk.gpio3[9] - WL_EN */ - AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7) /* (H18) rmii1_refclk.gpio0[29] - WL_IRQ */ + AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7) /* (K16) gmii1_txd1.gpio0[21] - WL_IRQ */ AM33XX_IOPAD(0x930, PIN_OUTPUT_PULLUP | MUX_MODE7) /* (L18) gmii1_rxclk.gpio3[10] - LS_BUF_EN */ >; }; + + /* DCAN */ + dcan1_pins: pinmux_dcan1_pins { + pinctrl-single,pins = < + AM33XX_IOPAD(0x96c, PIN_INPUT | MUX_MODE2) /* (E17) uart0_rtsn.dcan1_rx */ + AM33XX_IOPAD(0x968, PIN_OUTPUT | MUX_MODE2) /* (E18) uart0_ctsn.dcan1_tx */ + AM33XX_IOPAD(0x940, PIN_OUTPUT | MUX_MODE7) /* (M16) gmii1_rxd0.gpio2[21] */ + >; + }; }; &uart0 { @@ -229,6 +270,34 @@ status = "okay"; }; +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; + + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; + + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&uart4_pins>; + + status = "okay"; +}; + +&uart5 { + pinctrl-names = "default"; + pinctrl-0 = <&uart5_pins>; + + status = "okay"; +}; + &usb { status = "okay"; }; @@ -414,7 +483,7 @@ compatible = "ti,wl1835"; reg = <2>; interrupt-parent = <&gpio0>; - interrupts = <29 IRQ_TYPE_EDGE_RISING>; + interrupts = <21 IRQ_TYPE_EDGE_RISING>; }; }; @@ -446,10 +515,16 @@ &rtc { system-power-controller; - clocks = <&clk_32768_ck>, <&clkdiv32k_ick>; + clocks = <&clk_32768_ck>, <&l4_per_clkctrl AM3_CLKDIV32K_CLKCTRL 0>; clock-names = "ext-clk", "int-clk"; }; +&dcan1 { + pinctrl-names = "default"; + pinctrl-0 = <&dcan1_pins>; + status = "okay"; +}; + &gpio3 { ls_buf_en { gpio-hog; diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts index ddd897556e03..fee6b3ee1741 100644 --- a/arch/arm/boot/dts/am335x-evm.dts +++ b/arch/arm/boot/dts/am335x-evm.dts @@ -790,6 +790,6 @@ }; &rtc { - clocks = <&clk_32768_ck>, <&clkdiv32k_ick>; + clocks = <&clk_32768_ck>, <&l4_per_clkctrl AM3_CLKDIV32K_CLKCTRL 0>; clock-names = "ext-clk", "int-clk"; }; diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts index 9ba4b18c0cb2..fa608cd5dc14 100644 --- a/arch/arm/boot/dts/am335x-evmsk.dts +++ b/arch/arm/boot/dts/am335x-evmsk.dts @@ -722,6 +722,6 @@ }; &rtc { - clocks = <&clk_32768_ck>, <&clkdiv32k_ick>; + clocks = <&clk_32768_ck>, <&l4_per_clkctrl AM3_CLKDIV32K_CLKCTRL 0>; clock-names = "ext-clk", "int-clk"; }; diff --git a/arch/arm/boot/dts/am335x-pepper.dts b/arch/arm/boot/dts/am335x-pepper.dts index 03c7d77023c6..9fb7426070ce 100644 --- a/arch/arm/boot/dts/am335x-pepper.dts +++ b/arch/arm/boot/dts/am335x-pepper.dts @@ -139,7 +139,7 @@ &audio_codec { status = "okay"; - gpio-reset = <&gpio1 16 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>; AVDD-supply = <&ldo3_reg>; IOVDD-supply = <&ldo3_reg>; DRVDD-supply = <&ldo3_reg>; diff --git a/arch/arm/boot/dts/am33xx-clocks.dtsi b/arch/arm/boot/dts/am33xx-clocks.dtsi index 8d8319590cde..95d5c9d136c5 100644 --- a/arch/arm/boot/dts/am33xx-clocks.dtsi +++ b/arch/arm/boot/dts/am33xx-clocks.dtsi @@ -292,14 +292,6 @@ clock-div = <4>; }; - cefuse_fck: cefuse_fck@a20 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_clkin_ck>; - ti,bit-shift = <1>; - reg = <0x0a20>; - }; - clk_24mhz: clk_24mhz { #clock-cells = <0>; compatible = "fixed-factor-clock"; @@ -316,14 +308,6 @@ clock-div = <732>; }; - clkdiv32k_ick: clkdiv32k_ick@14c { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&clkdiv32k_ck>; - ti,bit-shift = <1>; - reg = <0x014c>; - }; - l3_gclk: l3_gclk { #clock-cells = <0>; compatible = "fixed-factor-clock"; @@ -350,49 +334,49 @@ timer1_fck: timer1_fck@528 { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&sys_clkin_ck>, <&clkdiv32k_ick>, <&tclkin_ck>, <&clk_rc32k_ck>, <&clk_32768_ck>; + clocks = <&sys_clkin_ck>, <&l4_per_clkctrl AM3_CLKDIV32K_CLKCTRL 0>, <&tclkin_ck>, <&clk_rc32k_ck>, <&clk_32768_ck>; reg = <0x0528>; }; timer2_fck: timer2_fck@508 { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&l4_per_clkctrl AM3_CLKDIV32K_CLKCTRL 0>; reg = <0x0508>; }; timer3_fck: timer3_fck@50c { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&l4_per_clkctrl AM3_CLKDIV32K_CLKCTRL 0>; reg = <0x050c>; }; timer4_fck: timer4_fck@510 { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&l4_per_clkctrl AM3_CLKDIV32K_CLKCTRL 0>; reg = <0x0510>; }; timer5_fck: timer5_fck@518 { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&l4_per_clkctrl AM3_CLKDIV32K_CLKCTRL 0>; reg = <0x0518>; }; timer6_fck: timer6_fck@51c { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&l4_per_clkctrl AM3_CLKDIV32K_CLKCTRL 0>; reg = <0x051c>; }; timer7_fck: timer7_fck@504 { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>; + clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&l4_per_clkctrl AM3_CLKDIV32K_CLKCTRL 0>; reg = <0x0504>; }; @@ -423,7 +407,7 @@ wdt1_fck: wdt1_fck@538 { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&clk_rc32k_ck>, <&clkdiv32k_ick>; + clocks = <&clk_rc32k_ck>, <&l4_per_clkctrl AM3_CLKDIV32K_CLKCTRL 0>; reg = <0x0538>; }; @@ -493,42 +477,10 @@ gpio0_dbclk_mux_ck: gpio0_dbclk_mux_ck@53c { #clock-cells = <0>; compatible = "ti,mux-clock"; - clocks = <&clk_rc32k_ck>, <&clk_32768_ck>, <&clkdiv32k_ick>; + clocks = <&clk_rc32k_ck>, <&clk_32768_ck>, <&l4_per_clkctrl AM3_CLKDIV32K_CLKCTRL 0>; reg = <0x053c>; }; - gpio0_dbclk: gpio0_dbclk@408 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&gpio0_dbclk_mux_ck>; - ti,bit-shift = <18>; - reg = <0x0408>; - }; - - gpio1_dbclk: gpio1_dbclk@ac { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&clkdiv32k_ick>; - ti,bit-shift = <18>; - reg = <0x00ac>; - }; - - gpio2_dbclk: gpio2_dbclk@b0 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&clkdiv32k_ick>; - ti,bit-shift = <18>; - reg = <0x00b0>; - }; - - gpio3_dbclk: gpio3_dbclk@b4 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&clkdiv32k_ick>; - ti,bit-shift = <18>; - reg = <0x00b4>; - }; - lcd_gclk: lcd_gclk@534 { #clock-cells = <0>; compatible = "ti,mux-clock"; @@ -577,58 +529,6 @@ reg = <0x0700>; }; - dbg_sysclk_ck: dbg_sysclk_ck@414 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_clkin_ck>; - ti,bit-shift = <19>; - reg = <0x0414>; - }; - - dbg_clka_ck: dbg_clka_ck@414 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&dpll_core_m4_ck>; - ti,bit-shift = <30>; - reg = <0x0414>; - }; - - stm_pmd_clock_mux_ck: stm_pmd_clock_mux_ck@414 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&dbg_sysclk_ck>, <&dbg_clka_ck>; - ti,bit-shift = <22>; - reg = <0x0414>; - }; - - trace_pmd_clk_mux_ck: trace_pmd_clk_mux_ck@414 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&dbg_sysclk_ck>, <&dbg_clka_ck>; - ti,bit-shift = <20>; - reg = <0x0414>; - }; - - stm_clk_div_ck: stm_clk_div_ck@414 { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&stm_pmd_clock_mux_ck>; - ti,bit-shift = <27>; - ti,max-div = <64>; - reg = <0x0414>; - ti,index-power-of-two; - }; - - trace_clk_div_ck: trace_clk_div_ck@414 { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&trace_pmd_clk_mux_ck>; - ti,bit-shift = <24>; - ti,max-div = <64>; - reg = <0x0414>; - ti,index-power-of-two; - }; - clkout2_ck: clkout2_ck@700 { #clock-cells = <0>; compatible = "ti,gate-clock"; @@ -638,9 +538,88 @@ }; }; -&prcm_clockdomains { - clk_24mhz_clkdm: clk_24mhz_clkdm { - compatible = "ti,clockdomain"; - clocks = <&clkdiv32k_ick>; +&prcm { + l4_per_cm: l4_per_cm@0 { + compatible = "ti,omap4-cm"; + reg = <0x0 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x0 0x200>; + + l4_per_clkctrl: clk@14 { + compatible = "ti,clkctrl"; + reg = <0x14 0x13c>; + #clock-cells = <2>; + }; + }; + + l4_wkup_cm: l4_wkup_cm@400 { + compatible = "ti,omap4-cm"; + reg = <0x400 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x400 0x100>; + + l4_wkup_clkctrl: clk@4 { + compatible = "ti,clkctrl"; + reg = <0x4 0xd4>; + #clock-cells = <2>; + }; + }; + + mpu_cm: mpu_cm@600 { + compatible = "ti,omap4-cm"; + reg = <0x600 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x600 0x100>; + + mpu_clkctrl: clk@4 { + compatible = "ti,clkctrl"; + reg = <0x4 0x4>; + #clock-cells = <2>; + }; + }; + + l4_rtc_cm: l4_rtc_cm@800 { + compatible = "ti,omap4-cm"; + reg = <0x800 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x800 0x100>; + + l4_rtc_clkctrl: clk@0 { + compatible = "ti,clkctrl"; + reg = <0x0 0x4>; + #clock-cells = <2>; + }; + }; + + gfx_l3_cm: gfx_l3_cm@900 { + compatible = "ti,omap4-cm"; + reg = <0x900 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x900 0x100>; + + gfx_l3_clkctrl: clk@4 { + compatible = "ti,clkctrl"; + reg = <0x4 0x4>; + #clock-cells = <2>; + }; + }; + + l4_cefuse_cm: l4_cefuse_cm@a00 { + compatible = "ti,omap4-cm"; + reg = <0xa00 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xa00 0x100>; + + l4_cefuse_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; }; }; diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index d37f95025807..628c77b0b386 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -10,6 +10,7 @@ #include #include +#include / { compatible = "ti,am33xx"; @@ -179,8 +180,11 @@ }; prcm: prcm@200000 { - compatible = "ti,am3-prcm"; + compatible = "ti,am3-prcm", "simple-bus"; reg = <0x200000 0x4000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x200000 0x4000>; prcm_clocks: clocks { #address-cells = <1>; @@ -496,7 +500,7 @@ status = "disabled"; }; - mailbox: mailbox@480C8000 { + mailbox: mailbox@480c8000 { compatible = "ti,omap4-mailbox"; reg = <0x480C8000 0x200>; interrupts = <77>; @@ -517,6 +521,8 @@ interrupts = <67>; ti,hwmods = "timer1"; ti,timer-alwon; + clocks = <&timer1_fck>; + clock-names = "fck"; }; timer2: timer@48040000 { @@ -524,6 +530,8 @@ reg = <0x48040000 0x400>; interrupts = <68>; ti,hwmods = "timer2"; + clocks = <&timer2_fck>; + clock-names = "fck"; }; timer3: timer@48042000 { @@ -571,7 +579,7 @@ interrupts = <75 76>; ti,hwmods = "rtc"; - clocks = <&clkdiv32k_ick>; + clocks = <&l4_per_clkctrl AM3_CLKDIV32K_CLKCTRL 0>; clock-names = "int-clk"; }; @@ -991,7 +999,7 @@ dma-names = "tx", "rx"; }; - mcasp1: mcasp@4803C000 { + mcasp1: mcasp@4803c000 { compatible = "ti,am33xx-mcasp-audio"; ti,hwmods = "mcasp1"; reg = <0x4803C000 0x2000>, @@ -1014,4 +1022,4 @@ }; }; -/include/ "am33xx-clocks.dtsi" +#include "am33xx-clocks.dtsi" diff --git a/arch/arm/boot/dts/am3517.dtsi b/arch/arm/boot/dts/am3517.dtsi index 00da3f2c4072..ca294914bbb1 100644 --- a/arch/arm/boot/dts/am3517.dtsi +++ b/arch/arm/boot/dts/am3517.dtsi @@ -26,7 +26,7 @@ interrupt-names = "mc"; }; - davinci_emac: ethernet@0x5c000000 { + davinci_emac: ethernet@5c000000 { compatible = "ti,am3517-emac"; ti,hwmods = "davinci_emac"; status = "disabled"; @@ -41,7 +41,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; }; - davinci_mdio: ethernet@0x5c030000 { + davinci_mdio: ethernet@5c030000 { compatible = "ti,davinci_mdio"; ti,hwmods = "davinci_mdio"; status = "disabled"; @@ -99,9 +99,5 @@ status = "disabled"; }; -&smartreflex_mpu_iva { - status = "disabled"; -}; - /include/ "am35xx-clocks.dtsi" /include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi" diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index 4714a59fd86d..964f3ef79728 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -10,6 +10,7 @@ #include #include +#include / { compatible = "ti,am4372", "ti,am43"; @@ -163,9 +164,12 @@ }; prcm: prcm@1f0000 { - compatible = "ti,am4-prcm"; + compatible = "ti,am4-prcm", "simple-bus"; reg = <0x1f0000 0x11000>; interrupts = ; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1f0000 0x11000>; prcm_clocks: clocks { #address-cells = <1>; @@ -325,7 +329,7 @@ status = "disabled"; }; - mailbox: mailbox@480C8000 { + mailbox: mailbox@480c8000 { compatible = "ti,omap4-mailbox"; reg = <0x480C8000 0x200>; interrupts = ; @@ -346,6 +350,8 @@ interrupts = ; ti,timer-alwon; ti,hwmods = "timer1"; + clocks = <&timer1_fck>; + clock-names = "fck"; }; timer2: timer@48040000 { @@ -353,6 +359,8 @@ reg = <0x48040000 0x400>; interrupts = ; ti,hwmods = "timer2"; + clocks = <&timer2_fck>; + clock-names = "fck"; }; timer3: timer@48042000 { @@ -936,7 +944,7 @@ dma-names = "tx", "rx"; }; - mcasp1: mcasp@4803C000 { + mcasp1: mcasp@4803c000 { compatible = "ti,am33xx-mcasp-audio"; ti,hwmods = "mcasp1"; reg = <0x4803C000 0x2000>, @@ -993,7 +1001,7 @@ reg = <0x483a8000 0x8000>; syscon-phy-power = <&scm_conf 0x620>; clocks = <&usb_phy0_always_on_clk32k>, - <&usb_otg_ss0_refclk960m>; + <&l4_per_clkctrl AM4_USB_OTG_SS0_CLKCTRL 8>; clock-names = "wkupclk", "refclk"; #phy-cells = <0>; status = "disabled"; @@ -1012,7 +1020,7 @@ reg = <0x483e8000 0x8000>; syscon-phy-power = <&scm_conf 0x628>; clocks = <&usb_phy1_always_on_clk32k>, - <&usb_otg_ss1_refclk960m>; + <&l4_per_clkctrl AM4_USB_OTG_SS1_CLKCTRL 8>; clock-names = "wkupclk", "refclk"; #phy-cells = <0>; status = "disabled"; @@ -1175,4 +1183,4 @@ }; }; -/include/ "am43xx-clocks.dtsi" +#include "am43xx-clocks.dtsi" diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts index afb8eb0a0a16..c3b1a3fb5a2e 100644 --- a/arch/arm/boot/dts/am437x-gp-evm.dts +++ b/arch/arm/boot/dts/am437x-gp-evm.dts @@ -55,7 +55,7 @@ enable-active-high; }; - backlight { + lcd_bl: backlight { compatible = "pwm-backlight"; pwms = <&ecap0 0 50000 PWM_POLARITY_INVERTED>; brightness-levels = <0 51 53 56 62 75 101 152 255>; @@ -86,6 +86,8 @@ compatible = "osddisplays,osd057T0559-34ts", "panel-dpi"; label = "lcd"; + backlight = <&lcd_bl>; + panel-timing { clock-frequency = <33000000>; hactive = <800>; diff --git a/arch/arm/boot/dts/am437x-idk-evm.dts b/arch/arm/boot/dts/am437x-idk-evm.dts index 5e364473067f..20132477a871 100644 --- a/arch/arm/boot/dts/am437x-idk-evm.dts +++ b/arch/arm/boot/dts/am437x-idk-evm.dts @@ -519,3 +519,17 @@ &cpu { cpu0-supply = <&tps>; }; + +&cpu0_opp_table { + /* + * Supply voltage supervisor on board will not allow opp50 so + * disable it and set opp100 as suspend OPP. + */ + opp50@300000000 { + status = "disabled"; + }; + + opp100@600000000 { + opp-suspend; + }; +}; diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts index 2c6bf0684f50..3fa3b226995d 100644 --- a/arch/arm/boot/dts/am437x-sk-evm.dts +++ b/arch/arm/boot/dts/am437x-sk-evm.dts @@ -35,7 +35,7 @@ clock-frequency = <32768>; }; - backlight { + lcd_bl: backlight { compatible = "pwm-backlight"; pwms = <&ecap0 0 50000 PWM_POLARITY_INVERTED>; brightness-levels = <0 51 53 56 62 75 101 152 255>; @@ -132,6 +132,8 @@ pinctrl-names = "default"; pinctrl-0 = <&lcd_pins>; + backlight = <&lcd_bl>; + enable-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; panel-timing { diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts index a04d79ec212a..00c3d1de384f 100644 --- a/arch/arm/boot/dts/am43x-epos-evm.dts +++ b/arch/arm/boot/dts/am43x-epos-evm.dts @@ -48,6 +48,8 @@ compatible = "osddisplays,osd057T0559-34ts", "panel-dpi"; label = "lcd"; + backlight = <&lcd_bl>; + panel-timing { clock-frequency = <33000000>; hactive = <800>; @@ -107,7 +109,7 @@ 0x03030069>; /* LEFT */ }; - backlight { + lcd_bl: backlight { compatible = "pwm-backlight"; pwms = <&ecap0 0 50000 PWM_POLARITY_INVERTED>; brightness-levels = <0 51 53 56 62 75 101 152 255>; @@ -985,7 +987,11 @@ rx-num-evt = <32>; }; -&synctimer_32kclk { +&mux_synctimer32k_ck { assigned-clocks = <&mux_synctimer32k_ck>; assigned-clock-parents = <&clkdiv32k_ick>; }; + +&cpu { + cpu0-supply = <&dcdc2>; +}; diff --git a/arch/arm/boot/dts/am43xx-clocks.dtsi b/arch/arm/boot/dts/am43xx-clocks.dtsi index 430be5829f8f..a7037a4b4fd4 100644 --- a/arch/arm/boot/dts/am43xx-clocks.dtsi +++ b/arch/arm/boot/dts/am43xx-clocks.dtsi @@ -524,54 +524,6 @@ reg = <0x4240>; }; - gpio0_dbclk: gpio0_dbclk@2b68 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&gpio0_dbclk_mux_ck>; - ti,bit-shift = <8>; - reg = <0x2b68>; - }; - - gpio1_dbclk: gpio1_dbclk@8c78 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&clkdiv32k_ick>; - ti,bit-shift = <8>; - reg = <0x8c78>; - }; - - gpio2_dbclk: gpio2_dbclk@8c80 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&clkdiv32k_ick>; - ti,bit-shift = <8>; - reg = <0x8c80>; - }; - - gpio3_dbclk: gpio3_dbclk@8c88 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&clkdiv32k_ick>; - ti,bit-shift = <8>; - reg = <0x8c88>; - }; - - gpio4_dbclk: gpio4_dbclk@8c90 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&clkdiv32k_ick>; - ti,bit-shift = <8>; - reg = <0x8c90>; - }; - - gpio5_dbclk: gpio5_dbclk@8c98 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&clkdiv32k_ick>; - ti,bit-shift = <8>; - reg = <0x8c98>; - }; - mmc_clk: mmc_clk { #clock-cells = <0>; compatible = "fixed-factor-clock"; @@ -629,14 +581,6 @@ reg = <0x4230>; }; - synctimer_32kclk: synctimer_32kclk@2a30 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&mux_synctimer32k_ck>; - ti,bit-shift = <8>; - reg = <0x2a30>; - }; - timer8_fck: timer8_fck@421c { #clock-cells = <0>; compatible = "ti,mux-clock"; @@ -763,110 +707,76 @@ ti,bit-shift = <8>; reg = <0x2a48>; }; +}; - usb_otg_ss0_refclk960m: usb_otg_ss0_refclk960m@8a60 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&dpll_per_clkdcoldo>; - ti,bit-shift = <8>; - reg = <0x8a60>; +&prcm { + l4_wkup_cm: l4_wkup_cm@2800 { + compatible = "ti,omap4-cm"; + reg = <0x2800 0x400>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x2800 0x400>; + + l4_wkup_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x34c>; + #clock-cells = <2>; + }; }; - usb_otg_ss1_refclk960m: usb_otg_ss1_refclk960m@8a68 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&dpll_per_clkdcoldo>; - ti,bit-shift = <8>; - reg = <0x8a68>; + mpu_cm: mpu_cm@8300 { + compatible = "ti,omap4-cm"; + reg = <0x8300 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x8300 0x100>; + + mpu_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; }; - clkout1_osc_div_ck: clkout1_osc_div_ck { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&sys_clkin_ck>; - ti,bit-shift = <20>; - ti,max-div = <4>; - reg = <0x4100>; + gfx_l3_cm: gfx_l3_cm@8400 { + compatible = "ti,omap4-cm"; + reg = <0x8400 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x8400 0x100>; + + gfx_l3_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; }; - clkout1_src2_mux_ck: clkout1_src2_mux_ck { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&clk_rc32k_ck>, <&sysclk_div>, <&dpll_ddr_m2_ck>, - <&dpll_per_m2_ck>, <&dpll_disp_m2_ck>, - <&dpll_mpu_m2_ck>; - reg = <0x4100>; + l4_rtc_cm: l4_rtc_cm@8500 { + compatible = "ti,omap4-cm"; + reg = <0x8500 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x8500 0x100>; + + l4_rtc_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; }; - clkout1_src2_pre_div_ck: clkout1_src2_pre_div_ck { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&clkout1_src2_mux_ck>; - ti,bit-shift = <4>; - ti,max-div = <8>; - reg = <0x4100>; - }; + l4_per_cm: l4_per_cm@8800 { + compatible = "ti,omap4-cm"; + reg = <0x8800 0xc00>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x8800 0xc00>; - clkout1_src2_post_div_ck: clkout1_src2_post_div_ck { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&clkout1_src2_pre_div_ck>; - ti,bit-shift = <8>; - ti,max-div = <32>; - ti,index-power-of-two; - reg = <0x4100>; - }; - - clkout1_mux_ck: clkout1_mux_ck { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&clkout1_osc_div_ck>, <&clk_rc32k_ck>, - <&clkout1_src2_post_div_ck>, <&dpll_extdev_m2_ck>; - ti,bit-shift = <16>; - reg = <0x4100>; - }; - - clkout1_ck: clkout1_ck { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&clkout1_mux_ck>; - ti,bit-shift = <23>; - reg = <0x4100>; - }; - - clkout2_src_mux_ck: clkout2_src_mux_ck { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&clk_rc32k_ck>, <&sysclk_div>, <&dpll_ddr_m2_ck>, - <&dpll_per_m2_ck>, <&dpll_disp_m2_ck>, - <&dpll_mpu_m2_ck>, <&dpll_extdev_ck>; - reg = <0x4108>; - }; - - clkout2_pre_div_ck: clkout2_pre_div_ck { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&clkout2_src_mux_ck>; - ti,bit-shift = <4>; - ti,max-div = <8>; - reg = <0x4108>; - }; - - clkout2_post_div_ck: clkout2_post_div_ck { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&clkout2_pre_div_ck>; - ti,bit-shift = <8>; - ti,max-div = <32>; - ti,index-power-of-two; - reg = <0x4108>; - }; - - clkout2_ck: clkout2_ck { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&clkout2_post_div_ck>; - ti,bit-shift = <16>; - reg = <0x4108>; + l4_per_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0xb04>; + #clock-cells = <2>; + }; }; }; diff --git a/arch/arm/boot/dts/am571x-idk.dts b/arch/arm/boot/dts/am571x-idk.dts index debf9464403e..6d3c83743156 100644 --- a/arch/arm/boot/dts/am571x-idk.dts +++ b/arch/arm/boot/dts/am571x-idk.dts @@ -117,3 +117,7 @@ pinctrl-1 = <&mmc2_pins_hs>; pinctrl-2 = <&mmc2_pins_ddr_rev20 &mmc2_iodelay_ddr_conf>; }; + +&cpu0 { + vdd-supply = <&smps12_reg>; +}; diff --git a/arch/arm/boot/dts/am572x-idk-common.dtsi b/arch/arm/boot/dts/am572x-idk-common.dtsi new file mode 100644 index 000000000000..c6d858b31011 --- /dev/null +++ b/arch/arm/boot/dts/am572x-idk-common.dtsi @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ + */ + +#include +#include +#include "am57xx-idk-common.dtsi" + +/ { + memory@0 { + device_type = "memory"; + reg = <0x0 0x80000000 0x0 0x80000000>; + }; + + status-leds { + compatible = "gpio-leds"; + cpu0-led { + label = "status0:red:cpu0"; + gpios = <&gpio4 0 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "cpu0"; + }; + + usr0-led { + label = "status0:green:usr"; + gpios = <&gpio3 11 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + heartbeat-led { + label = "status0:blue:heartbeat"; + gpios = <&gpio3 12 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "heartbeat"; + }; + + cpu1-led { + label = "status1:red:cpu1"; + gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "cpu1"; + }; + + usr1-led { + label = "status1:green:usr"; + gpios = <&gpio7 23 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + mmc0-led { + label = "status1:blue:mmc0"; + gpios = <&gpio7 22 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "mmc0"; + }; + }; +}; + +&omap_dwc3_2 { + extcon = <&extcon_usb2>; +}; + +&extcon_usb2 { + id-gpio = <&gpio3 16 GPIO_ACTIVE_HIGH>; + vbus-gpio = <&gpio3 26 GPIO_ACTIVE_HIGH>; +}; + +&sn65hvs882 { + load-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>; +}; + +&pcie1_rc { + status = "okay"; + gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>; +}; + +&pcie1_ep { + gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>; +}; + +&mailbox5 { + status = "okay"; + mbox_ipu1_ipc3x: mbox_ipu1_ipc3x { + status = "okay"; + }; + mbox_dsp1_ipc3x: mbox_dsp1_ipc3x { + status = "okay"; + }; +}; + +&mailbox6 { + status = "okay"; + mbox_ipu2_ipc3x: mbox_ipu2_ipc3x { + status = "okay"; + }; + mbox_dsp2_ipc3x: mbox_dsp2_ipc3x { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/am572x-idk.dts b/arch/arm/boot/dts/am572x-idk.dts index a578fe97ba3b..9ab0af5017df 100644 --- a/arch/arm/boot/dts/am572x-idk.dts +++ b/arch/arm/boot/dts/am572x-idk.dts @@ -9,8 +9,7 @@ /dts-v1/; #include "dra74x.dtsi" -#include -#include +#include "am572x-idk-common.dtsi" #include "am57xx-idk-common.dtsi" #include "dra74x-mmc-iodelay.dtsi" @@ -18,54 +17,6 @@ model = "TI AM5728 IDK"; compatible = "ti,am5728-idk", "ti,am5728", "ti,dra742", "ti,dra74", "ti,dra7"; - - memory@0 { - device_type = "memory"; - reg = <0x0 0x80000000 0x0 0x80000000>; - }; - - status-leds { - compatible = "gpio-leds"; - cpu0-led { - label = "status0:red:cpu0"; - gpios = <&gpio4 0 GPIO_ACTIVE_HIGH>; - default-state = "off"; - linux,default-trigger = "cpu0"; - }; - - usr0-led { - label = "status0:green:usr"; - gpios = <&gpio3 11 GPIO_ACTIVE_HIGH>; - default-state = "off"; - }; - - heartbeat-led { - label = "status0:blue:heartbeat"; - gpios = <&gpio3 12 GPIO_ACTIVE_HIGH>; - default-state = "off"; - linux,default-trigger = "heartbeat"; - }; - - cpu1-led { - label = "status1:red:cpu1"; - gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>; - default-state = "off"; - linux,default-trigger = "cpu1"; - }; - - usr1-led { - label = "status1:green:usr"; - gpios = <&gpio7 23 GPIO_ACTIVE_HIGH>; - default-state = "off"; - }; - - mmc0-led { - label = "status1:blue:mmc0"; - gpios = <&gpio7 22 GPIO_ACTIVE_HIGH>; - default-state = "off"; - linux,default-trigger = "mmc0"; - }; - }; }; &mmc1 { @@ -86,44 +37,6 @@ pinctrl-2 = <&mmc2_pins_ddr_rev20>; }; -&omap_dwc3_2 { - extcon = <&extcon_usb2>; -}; - -&extcon_usb2 { - id-gpio = <&gpio3 16 GPIO_ACTIVE_HIGH>; - vbus-gpio = <&gpio3 26 GPIO_ACTIVE_HIGH>; -}; - -&sn65hvs882 { - load-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>; -}; - -&pcie1_rc { - status = "okay"; - gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>; -}; - -&pcie1_ep { - gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>; -}; - -&mailbox5 { - status = "okay"; - mbox_ipu1_ipc3x: mbox_ipu1_ipc3x { - status = "okay"; - }; - mbox_dsp1_ipc3x: mbox_dsp1_ipc3x { - status = "okay"; - }; -}; - -&mailbox6 { - status = "okay"; - mbox_ipu2_ipc3x: mbox_ipu2_ipc3x { - status = "okay"; - }; - mbox_dsp2_ipc3x: mbox_dsp2_ipc3x { - status = "okay"; - }; +&cpu0 { + vdd-supply = <&smps12_reg>; }; diff --git a/arch/arm/boot/dts/am574x-idk.dts b/arch/arm/boot/dts/am574x-idk.dts new file mode 100644 index 000000000000..41e12a382d2f --- /dev/null +++ b/arch/arm/boot/dts/am574x-idk.dts @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ + */ + + +/dts-v1/; + +#include "dra76x.dtsi" +#include "am572x-idk-common.dtsi" + +/ { + model = "TI AM5748 IDK"; + compatible = "ti,am5728-idk", "ti,dra762", "ti,dra7"; +}; + +&qspi { + spi-max-frequency = <96000000>; + m25p80@0 { + spi-max-frequency = <96000000>; + }; +}; diff --git a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi index 49aeecd312b4..ab60035bc50c 100644 --- a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi +++ b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi @@ -388,7 +388,7 @@ }; &cpu0 { - cpu0-supply = <&smps12_reg>; + vdd-supply = <&smps12_reg>; voltage-tolerance = <1>; }; @@ -554,7 +554,7 @@ &mcasp3 { #sound-dai-cells = <0>; - assigned-clocks = <&mcasp3_ahclkx_mux>; + assigned-clocks = <&l4per_clkctrl DRA7_MCASP3_CLKCTRL 24>; assigned-clock-parents = <&sys_clkin2>; status = "okay"; diff --git a/arch/arm/boot/dts/animeo_ip.dts b/arch/arm/boot/dts/animeo_ip.dts index 26ade8c0a960..b67a75179784 100644 --- a/arch/arm/boot/dts/animeo_ip.dts +++ b/arch/arm/boot/dts/animeo_ip.dts @@ -43,6 +43,18 @@ ahb { apb { + tcb0: timer@fffa0000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + usart0: serial@fffb0000 { pinctrl-0 = <&pinctrl_usart0 &pinctrl_usart0_rts>; linux,rs485-enabled-at-boot-time; diff --git a/arch/arm/boot/dts/arm-realview-eb-mp.dtsi b/arch/arm/boot/dts/arm-realview-eb-mp.dtsi index 7b8d90b7aeea..29b636fce23f 100644 --- a/arch/arm/boot/dts/arm-realview-eb-mp.dtsi +++ b/arch/arm/boot/dts/arm-realview-eb-mp.dtsi @@ -150,11 +150,6 @@ interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>; }; -&charlcd { - interrupt-parent = <&intc>; - interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; -}; - &serial0 { interrupt-parent = <&intc>; interrupts = <0 4 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm/boot/dts/armada-38x.dtsi b/arch/arm/boot/dts/armada-38x.dtsi index 00ff549d4e39..a6cc568f74f7 100644 --- a/arch/arm/boot/dts/armada-38x.dtsi +++ b/arch/arm/boot/dts/armada-38x.dtsi @@ -279,6 +279,11 @@ marvell,function = "dev"; }; + nand_rb: nand-rb { + marvell,pins = "mpp41"; + marvell,function = "nand"; + }; + uart0_pins: uart-pins-0 { marvell,pins = "mpp0", "mpp1"; marvell,function = "ua0"; diff --git a/arch/arm/boot/dts/aspeed-ast2500-evb.dts b/arch/arm/boot/dts/aspeed-ast2500-evb.dts index 602bc10fdaf4..91a36c1f029b 100644 --- a/arch/arm/boot/dts/aspeed-ast2500-evb.dts +++ b/arch/arm/boot/dts/aspeed-ast2500-evb.dts @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0+ /dts-v1/; #include "aspeed-g5.dtsi" @@ -16,7 +16,7 @@ bootargs = "console=ttyS4,115200 earlyprintk"; }; - memory { + memory@80000000 { reg = <0x80000000 0x20000000>; }; }; diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts index c786bc2f2919..4379d09a261f 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0+ /dts-v1/; #include "aspeed-g4.dtsi" @@ -12,7 +12,7 @@ bootargs = "console=ttyS4,115200 earlyprintk"; }; - memory { + memory@40000000 { reg = <0x40000000 0x20000000>; }; @@ -34,6 +34,7 @@ status = "okay"; m25p,fast-read; label = "bmc"; +#include "openbmc-flash-layout.dtsi" }; }; diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts b/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts index 8067793129ea..623b6ab42021 100644 --- a/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts +++ b/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts @@ -1,23 +1,19 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0+ /dts-v1/; - #include "aspeed-g5.dtsi" +#include / { model = "Romulus BMC"; compatible = "ibm,romulus-bmc", "aspeed,ast2500"; - aliases { - serial4 = &uart5; - }; - chosen { stdout-path = &uart5; bootargs = "console=ttyS4,115200 earlyprintk"; }; - memory { - reg = <0x80000000 0x40000000>; + memory@80000000 { + reg = <0x80000000 0x20000000>; }; reserved-memory { @@ -29,6 +25,49 @@ no-map; reg = <0xbf000000 0x01000000>; /* 16M */ }; + + flash_memory: region@98000000 { + no-map; + reg = <0x98000000 0x04000000>; /* 64M */ + }; + }; + + leds { + compatible = "gpio-leds"; + + fault { + gpios = <&gpio ASPEED_GPIO(N, 2) GPIO_ACTIVE_LOW>; + }; + + identify { + gpios = <&gpio ASPEED_GPIO(N, 4) GPIO_ACTIVE_HIGH>; + }; + + power { + gpios = <&gpio ASPEED_GPIO(R, 5) GPIO_ACTIVE_LOW>; + }; + }; + + fsi: gpio-fsi { + compatible = "fsi-master-gpio", "fsi-master"; + #address-cells = <2>; + #size-cells = <0>; + + clock-gpios = <&gpio ASPEED_GPIO(AA, 0) GPIO_ACTIVE_HIGH>; + data-gpios = <&gpio ASPEED_GPIO(AA, 2) GPIO_ACTIVE_HIGH>; + mux-gpios = <&gpio ASPEED_GPIO(A, 6) GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>; + trans-gpios = <&gpio ASPEED_GPIO(R, 2) GPIO_ACTIVE_HIGH>; + }; + + gpio-keys { + compatible = "gpio-keys"; + + checkstop { + label = "checkstop"; + gpios = <&gpio ASPEED_GPIO(J, 2) GPIO_ACTIVE_LOW>; + linux,code = ; + }; }; }; @@ -38,6 +77,7 @@ status = "okay"; m25p,fast-read; label = "bmc"; +#include "openbmc-flash-layout.dtsi" }; }; @@ -53,6 +93,12 @@ }; }; +&lpc_ctrl { + status = "okay"; + memory-region = <&flash_memory>; + flash = <&spi1>; +}; + &uart1 { /* Rear RS-232 connector */ status = "okay"; @@ -81,6 +127,10 @@ pinctrl-0 = <&pinctrl_rmii1_default>; }; +&i2c1 { + status = "okay"; +}; + &i2c2 { status = "okay"; }; @@ -133,8 +183,77 @@ &i2c12 { status = "okay"; + + max31785@52 { + compatible = "maxim,max31785"; + reg = <0x52>; + }; +}; + +&gpio { + nic_func_mode0 { + gpio-hog; + gpios = ; + output-low; + line-name = "nic_func_mode0"; + }; + nic_func_mode1 { + gpio-hog; + gpios = ; + output-low; + line-name = "nic_func_mode1"; + }; }; &vuart { status = "okay"; }; + +&gfx { + status = "okay"; +}; + +&pinctrl { + aspeed,external-nodes = <&gfx &lhc>; +}; + +&pwm_tacho { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default>; + + fan@0 { + reg = <0x00>; + aspeed,fan-tach-ch = /bits/ 8 <0x08>; + }; + + fan@1 { + reg = <0x00>; + aspeed,fan-tach-ch = /bits/ 8 <0x09>; + }; + + fan@2 { + reg = <0x01>; + aspeed,fan-tach-ch = /bits/ 8 <0x0a>; + }; + + fan@3 { + reg = <0x01>; + aspeed,fan-tach-ch = /bits/ 8 <0x0b>; + }; + + fan@4 { + reg = <0x00>; + aspeed,fan-tach-ch = /bits/ 8 <0x0c>; + }; + + fan@5 { + reg = <0x00>; + aspeed,fan-tach-ch = /bits/ 8 <0x0d>; + }; + + fan@6 { + reg = <0x01>; + aspeed,fan-tach-ch = /bits/ 8 <0x0e>; + }; +}; diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts b/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts new file mode 100644 index 000000000000..5f9049d2c4c3 --- /dev/null +++ b/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts @@ -0,0 +1,548 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; +#include "aspeed-g5.dtsi" +#include +#include + +/ { + model = "Witherspoon BMC"; + compatible = "ibm,witherspoon-bmc", "aspeed,ast2500"; + + chosen { + stdout-path = &uart5; + bootargs = "console=ttyS4,115200 earlyprintk"; + }; + + memory@80000000 { + reg = <0x80000000 0x20000000>; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + flash_memory: region@98000000 { + no-map; + reg = <0x98000000 0x04000000>; /* 64M */ + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <1000>; + + fan0-presence { + label = "fan0-presence"; + gpios = <&pca0 4 GPIO_ACTIVE_LOW>; + linux,code = <4>; + }; + + fan1-presence { + label = "fan1-presence"; + gpios = <&pca0 5 GPIO_ACTIVE_LOW>; + linux,code = <5>; + }; + + fan2-presence { + label = "fan2-presence"; + gpios = <&pca0 6 GPIO_ACTIVE_LOW>; + linux,code = <6>; + }; + + fan3-presence { + label = "fan3-presence"; + gpios = <&pca0 7 GPIO_ACTIVE_LOW>; + linux,code = <7>; + }; + }; + + leds { + compatible = "gpio-leds"; + + fan0 { + retain-state-shutdown; + default-state = "keep"; + gpios = <&pca0 0 GPIO_ACTIVE_LOW>; + }; + + fan1 { + retain-state-shutdown; + default-state = "keep"; + gpios = <&pca0 1 GPIO_ACTIVE_LOW>; + }; + + fan2 { + retain-state-shutdown; + default-state = "keep"; + gpios = <&pca0 2 GPIO_ACTIVE_LOW>; + }; + + fan3 { + retain-state-shutdown; + default-state = "keep"; + gpios = <&pca0 3 GPIO_ACTIVE_LOW>; + }; + + front-fault { + retain-state-shutdown; + default-state = "keep"; + gpios = <&pca0 13 GPIO_ACTIVE_LOW>; + }; + + front-power { + retain-state-shutdown; + default-state = "keep"; + gpios = <&pca0 14 GPIO_ACTIVE_LOW>; + }; + + front-id { + retain-state-shutdown; + default-state = "keep"; + gpios = <&pca0 15 GPIO_ACTIVE_LOW>; + }; + + rear-fault { + gpios = <&gpio ASPEED_GPIO(N, 2) GPIO_ACTIVE_LOW>; + }; + + rear-id { + gpios = <&gpio ASPEED_GPIO(N, 4) GPIO_ACTIVE_LOW>; + }; + + rear-power { + gpios = <&gpio ASPEED_GPIO(N, 3) GPIO_ACTIVE_LOW>; + }; + + power-button { + gpios = <&gpio ASPEED_GPIO(R, 5) GPIO_ACTIVE_LOW>; + }; + }; + + fsi: gpio-fsi { + compatible = "fsi-master-gpio", "fsi-master"; + #address-cells = <2>; + #size-cells = <0>; + + clock-gpios = <&gpio ASPEED_GPIO(AA, 0) GPIO_ACTIVE_HIGH>; + data-gpios = <&gpio ASPEED_GPIO(E, 0) GPIO_ACTIVE_HIGH>; + mux-gpios = <&gpio ASPEED_GPIO(A, 6) GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>; + trans-gpios = <&gpio ASPEED_GPIO(R, 2) GPIO_ACTIVE_HIGH>; + }; + + iio-hwmon-dps310 { + compatible = "iio-hwmon"; + io-channels = <&dps 0>; + }; + + iio-hwmon-bmp280 { + compatible = "iio-hwmon"; + io-channels = <&bmp 1>; + }; + +}; + +&fmc { + status = "okay"; + + flash@0 { + status = "okay"; + label = "bmc"; + m25p,fast-read; +#include "openbmc-flash-layout.dtsi" + }; + + flash@1 { + status = "okay"; + label = "alt"; + m25p,fast-read; + }; +}; + +&spi1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi1_default>; + + flash@0 { + status = "okay"; + label = "pnor"; + m25p,fast-read; + }; +}; + +&uart1 { + /* Rear RS-232 connector */ + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd1_default + &pinctrl_rxd1_default + &pinctrl_nrts1_default + &pinctrl_ndtr1_default + &pinctrl_ndsr1_default + &pinctrl_ncts1_default + &pinctrl_ndcd1_default + &pinctrl_nri1_default>; +}; + +&uart2 { + /* APSS */ + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd2_default &pinctrl_rxd2_default>; +}; + +&uart5 { + status = "okay"; +}; + +&lpc_ctrl { + status = "okay"; + memory-region = <&flash_memory>; + flash = <&spi1>; +}; + +&mac0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rmii1_default>; + use-ncsi; +}; + +&i2c2 { + status = "okay"; + + /* MUX -> + * Samtec 1 + * Samtec 2 + */ +}; + +&i2c3 { + status = "okay"; + + bmp: bmp280@77 { + compatible = "bosch,bmp280"; + reg = <0x77>; + #io-channel-cells = <1>; + }; + + max31785@52 { + compatible = "maxim,max31785a"; + reg = <0x52>; + #address-cells = <1>; + #size-cells = <0>; + }; + + dps: dps310@76 { + compatible = "infineon,dps310"; + reg = <0x76>; + #io-channel-cells = <0>; + }; + + pca0: pca9552@60 { + compatible = "nxp,pca9552"; + reg = <0x60>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + gpio@0 { + reg = <0>; + type = ; + }; + + gpio@1 { + reg = <1>; + type = ; + }; + + gpio@2 { + reg = <2>; + type = ; + }; + + gpio@3 { + reg = <3>; + type = ; + }; + + gpio@4 { + reg = <4>; + type = ; + }; + + gpio@5 { + reg = <5>; + type = ; + }; + + gpio@6 { + reg = <6>; + type = ; + }; + + gpio@7 { + reg = <7>; + type = ; + }; + + gpio@8 { + reg = <8>; + type = ; + }; + + gpio@9 { + reg = <9>; + type = ; + }; + + gpio@10 { + reg = <10>; + type = ; + }; + + gpio@11 { + reg = <11>; + type = ; + }; + + gpio@12 { + reg = <12>; + type = ; + }; + + gpio@13 { + reg = <13>; + type = ; + }; + + gpio@14 { + reg = <14>; + type = ; + }; + + gpio@15 { + reg = <15>; + type = ; + }; + }; + + power-supply@68 { + compatible = "ibm,cffps1"; + reg = <0x68>; + }; + + power-supply@69 { + compatible = "ibm,cffps1"; + reg = <0x69>; + }; +}; + +&i2c4 { + status = "okay"; + + tmp423a@4c { + compatible = "ti,tmp423"; + reg = <0x4c>; + }; + + ir35221@70 { + compatible = "infineon,ir35221"; + reg = <0x70>; + }; + + ir35221@71 { + compatible = "infineon,ir35221"; + reg = <0x71>; + }; +}; + + +&i2c5 { + status = "okay"; + + tmp423a@4c { + compatible = "ti,tmp423"; + reg = <0x4c>; + }; + + ir35221@70 { + compatible = "infineon,ir35221"; + reg = <0x70>; + }; + + ir35221@71 { + compatible = "infineon,ir35221"; + reg = <0x71>; + }; +}; + +&i2c9 { + status = "okay"; + + tmp275@4a { + compatible = "ti,tmp275"; + reg = <0x4a>; + }; +}; + +&i2c10 { + /* MUX + * -> PCIe Slot 3 + * -> PCIe Slot 4 + */ + status = "okay"; +}; + +&i2c11 { + status = "okay"; + + pca9552: pca9552@60 { + compatible = "nxp,pca9552"; + reg = <0x60>; + #address-cells = <1>; + #size-cells = <0>; + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = "PS_SMBUS_RESET_N", "APSS_RESET_N", + "GPU0_TH_OVERT_N_BUFF", "GPU1_TH_OVERT_N_BUFF", + "GPU2_TH_OVERT_N_BUFF", "GPU3_TH_OVERT_N_BUFF", + "GPU4_TH_OVERT_N_BUFF", "GPU5_TH_OVERT_N_BUFF", + "GPU0_PWR_GOOD_BUFF", "GPU1_PWR_GOOD_BUFF", + "GPU2_PWR_GOOD_BUFF", "GPU3_PWR_GOOD_BUFF", + "GPU4_PWR_GOOD_BUFF", "GPU5_PWR_GOOD_BUFF", + "12V_BREAKER_FLT_N", "THROTTLE_UNLATCHED_N"; + + gpio@0 { + reg = <0>; + type = ; + }; + + gpio@1 { + reg = <1>; + type = ; + }; + + gpio@2 { + reg = <2>; + type = ; + }; + + gpio@3 { + reg = <3>; + type = ; + }; + + gpio@4 { + reg = <4>; + type = ; + }; + + gpio@5 { + reg = <5>; + type = ; + }; + + gpio@6 { + reg = <6>; + type = ; + }; + + gpio@7 { + reg = <7>; + type = ; + }; + + gpio@8 { + reg = <8>; + type = ; + }; + + gpio@9 { + reg = <9>; + type = ; + }; + + gpio@10 { + reg = <10>; + type = ; + }; + + gpio@11 { + reg = <11>; + type = ; + }; + + gpio@12 { + reg = <12>; + type = ; + }; + + gpio@13 { + reg = <13>; + type = ; + }; + + gpio@14 { + reg = <14>; + type = ; + }; + + gpio@15 { + reg = <15>; + type = ; + }; + }; + + rtc@32 { + compatible = "epson,rx8900"; + reg = <0x32>; + }; + + eeprom@51 { + compatible = "atmel,24c64"; + reg = <0x51>; + }; + + ucd90160@64 { + compatible = "ti,ucd90160"; + reg = <0x64>; + }; +}; + +&i2c12 { + status = "okay"; +}; + +&i2c13 { + status = "okay"; +}; + +&vuart { + status = "okay"; +}; + +&gfx { + status = "okay"; +}; + +&pinctrl { + aspeed,external-nodes = <&gfx &lhc>; +}; + +&wdt1 { + aspeed,reset-type = "none"; + aspeed,external-signal; + aspeed,ext-push-pull; + aspeed,ext-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdtrst1_default>; +}; diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts b/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts new file mode 100644 index 000000000000..c881484a85cf --- /dev/null +++ b/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts @@ -0,0 +1,426 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +#include "aspeed-g5.dtsi" +#include + +/ { + model = "Zaius BMC"; + compatible = "ingrasys,zaius-bmc", "aspeed,ast2500"; + + chosen { + stdout-path = &uart5; + bootargs = "console=ttyS4,115200 earlyprintk"; + }; + + memory@80000000 { + reg = <0x80000000 0x40000000>; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + flash_memory: region@98000000 { + no-map; + reg = <0x98000000 0x04000000>; /* 64M */ + }; + }; + + onewire0 { + compatible = "w1-gpio"; + gpios = <&gpio ASPEED_GPIO(H, 0) GPIO_ACTIVE_HIGH>; + }; + + onewire1 { + compatible = "w1-gpio"; + gpios = <&gpio ASPEED_GPIO(H, 1) GPIO_ACTIVE_HIGH>; + }; + + onewire2 { + compatible = "w1-gpio"; + gpios = <&gpio ASPEED_GPIO(H, 2) GPIO_ACTIVE_HIGH>; + }; + + onewire3 { + compatible = "w1-gpio"; + gpios = <&gpio ASPEED_GPIO(H, 3) GPIO_ACTIVE_HIGH>; + }; + + gpio-keys { + compatible = "gpio-keys"; + + checkstop { + label = "checkstop"; + gpios = <&gpio ASPEED_GPIO(F, 7) GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + + sys_boot_status { + label = "System boot status"; + gpios = <&gpio ASPEED_GPIO(D, 5) GPIO_ACTIVE_LOW>; + }; + + attention { + label = "Attention"; + gpios = <&gpio ASPEED_GPIO(D, 6) GPIO_ACTIVE_LOW>; + }; + + plt_fault { + label = "Platform fault"; + gpios = <&gpio ASPEED_GPIO(D, 7) GPIO_ACTIVE_LOW>; + }; + + hdd_fault { + label = "Onboard drive fault"; + gpios = <&gpio ASPEED_GPIO(AA, 2) GPIO_ACTIVE_LOW>; + }; + }; + + fsi: gpio-fsi { + compatible = "fsi-master-gpio", "fsi-master"; + #address-cells = <2>; + #size-cells = <0>; + + trans-gpios = <&gpio ASPEED_GPIO(O, 6) GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>; + clock-gpios = <&gpio ASPEED_GPIO(G, 0) GPIO_ACTIVE_HIGH>; + data-gpios = <&gpio ASPEED_GPIO(G, 1) GPIO_ACTIVE_HIGH>; + mux-gpios = <&gpio ASPEED_GPIO(P, 6) GPIO_ACTIVE_HIGH>; + }; + + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>, + <&adc 4>, <&adc 5>, <&adc 6>, <&adc 7>, + <&adc 8>, <&adc 9>, <&adc 10>, <&adc 11>, + <&adc 13>, <&adc 14>, <&adc 15>; + }; + + iio-hwmon-battery { + compatible = "iio-hwmon"; + io-channels = <&adc 12>; + }; + +}; + +&fmc { + status = "okay"; + + flash@0 { + status = "okay"; + label = "bmc"; + m25p,fast-read; +#include "openbmc-flash-layout.dtsi" + }; +}; + +&spi1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi1_default>; + + flash@0 { + status = "okay"; + label = "pnor"; + m25p,fast-read; + }; +}; + +&spi2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi2ck_default + &pinctrl_spi2cs0_default + &pinctrl_spi2cs1_default + &pinctrl_spi2miso_default + &pinctrl_spi2mosi_default>; + + flash@0 { + status = "okay"; + }; +}; + +&uart1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_txd1_default + &pinctrl_rxd1_default>; +}; + +&lpc_ctrl { + status = "okay"; + memory-region = <&flash_memory>; + flash = <&spi1>; +}; + +&lpc_snoop { + status = "okay"; + snoop-ports = <0x80>; +}; + + +&uart5 { + status = "okay"; +}; + +&mac0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rmii1_default>; + use-ncsi; +}; + +&mac1 { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>; +}; + +&i2c0 { + status = "okay"; + + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + pagesize = <32>; + }; + + rtc@68 { + compatible = "nxp,pcf8523"; + reg = <0x68>; + }; + + ucd90160@64 { + compatible = "ti,ucd90160"; + reg = <0x64>; + }; + + /* Power sequencer UCD90160 PMBUS @64h + * FRU AT24C64D @50h + * RTC PCF8523 @68h + * Clock buffer 9DBL04 @6dh + */ +}; + +&i2c1 { + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9546"; + reg = <0x71>; + #address-cells = <1>; + #size-cells = <0>; + }; + + /* MUX1 PCA9546A @71h + * PCIe 0 + * PCIe 1 + * PCIe 2 + * TPM header + */ +}; + +&i2c2 { + status = "disabled"; + + /* OCP Mezz Connector A (OOB SMBUS) */ +}; + +&i2c3 { + status = "disabled"; + + /* OCP Mezz Connector A (PCIe slot SMBUS) */ +}; + +&i2c4 { + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9546"; + reg = <0x71>; + #address-cells = <1>; + #size-cells = <0>; + }; + + /* MUX1 PCA9546A @71h + * PCIe 3 + * PCIe 4 + */ +}; + + +&i2c5 { + status = "disabled"; + + /* CPU0 PRM 0.7V */ + /* CPU0 PRM 1.2V CH03 */ + /* CPU0 PRM 0.8V */ + /* CPU0 PRM 1.2V CH47 */ +}; + +&i2c6 { + status = "disabled"; + + /* CPU1 PRM 0.7V */ + /* CPU1 PRM 1.2V CH03 */ + /* CPU1 PRM 0.8V */ + /* CPU1 PRM 1.2V CH47 */ +}; + +&i2c7 { + status = "okay"; + + pca9541a@70 { + compatible = "nxp,pca9541"; + reg = <0x70>; + + i2c-arb { + #address-cells = <1>; + #size-cells = <0>; + + hotswap@54 { + compatible = "ti,lm5066i"; + reg = <0x54>; + }; + }; + }; + + /* Master selector PCA9541A @70h (other master: CPU0) + * LM5066I PMBUS @10h + */ + + /* 12V Quarter Brick DC/DC Converter Q54SJ12050 @61h */ + power-brick@61 { + compatible = "delta,dps800"; + reg = <0x61>; + }; + + /* CPU0 VR ISL68137 0.7V, 0.96V PMBUS @64h */ + /* CPU0 VR ISL68137 1.2V CH03 PMBUS @40h */ + /* CPU0 VR ISL68137 0.8V PMBUS @60h */ + /* CPU0 VR 1.0V IR38064 I2C @11h, PMBUS @41h */ + /* CPU0 VR ISL68137 1.2V CH47 PMBUS @41h */ +}; + +&i2c8 { + status = "okay"; + + /* CPU1 VR ISL68137 0.7V, 0.96V PMBUS @65h */ + /* CPU1 VR ISL68137 1.2V CH03 PMBUS @44h */ + /* CPU1 VR ISL68137 0.8V PMBUS @61h */ + /* CPU1 VR 1.0V IR38064 I2C @12h, PMBUS @42h */ + /* CPU0 VR ISL68137 1.2V CH47 PMBUS @45h */ +}; + + +&i2c9 { + status = "disabled"; + + /* Fan board */ +}; + +&i2c10 { + status = "disabled"; +}; + +&i2c11 { + status = "disabled"; + + /* GPU sideband */ +}; + +&i2c12 { + status = "disabled"; +}; + +&i2c13 { + status = "disabled"; + + /* MUX PI3USB102 + * CPU0 debug + * CPU1 debug + */ +}; + +&pinctrl { + aspeed,external-nodes = <&gfx &lhc>; + + pinctrl_gpioh_unbiased: gpioi_unbiased { + pins = "A8", "C7", "B7", "A7", "D7", "B6", "A6", "E7"; + bias-disable; + }; +}; + +&gpio { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpioh_unbiased>; + + line_iso_u146_en { + gpio-hog; + gpios = ; + output-high; + line-name = "iso_u164_en"; + }; + + ncsi_mux_en_n { + gpio-hog; + gpios = ; + output-low; + line-name = "ncsi_mux_en_n"; + }; + + line_bmc_i2c2_sw_rst_n { + gpio-hog; + gpios = ; + output-high; + line-name = "bmc_i2c2_sw_rst_n"; + }; + + line_bmc_i2c5_sw_rst_n { + gpio-hog; + gpios = ; + output-high; + line-name = "bmc_i2c5_sw_rst_n"; + }; +}; + +&vuart { + status = "okay"; +}; + +&gfx { + status = "okay"; +}; + +&pwm_tacho { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default + &pinctrl_pwm2_default &pinctrl_pwm3_default>; + + fan@0 { + reg = <0x00>; + aspeed,fan-tach-ch = /bits/ 8 <0x00>; + }; + + fan@1 { + reg = <0x01>; + aspeed,fan-tach-ch = /bits/ 8 <0x01>; + }; + + fan@2 { + reg = <0x02>; + aspeed,fan-tach-ch = /bits/ 8 <0x02>; + }; + + fan@3 { + reg = <0x03>; + aspeed,fan-tach-ch = /bits/ 8 <0x03>; + }; +}; diff --git a/arch/arm/boot/dts/aspeed-bmc-quanta-q71l.dts b/arch/arm/boot/dts/aspeed-bmc-quanta-q71l.dts new file mode 100644 index 000000000000..76aa6ea1f988 --- /dev/null +++ b/arch/arm/boot/dts/aspeed-bmc-quanta-q71l.dts @@ -0,0 +1,458 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +#include "aspeed-g4.dtsi" +#include + +/ { + model = "Quanta Q71L BMC"; + compatible = "quanta,q71l-bmc", "aspeed,ast2400"; + + chosen { + stdout-path = &uart5; + bootargs = "console=ttyS4,115200 earlyprintk"; + }; + + memory@40000000 { + reg = <0x40000000 0x8000000>; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + vga_memory: framebuffer@47800000 { + no-map; + reg = <0x47800000 0x00800000>; /* 8MB */ + }; + }; + + leds { + compatible = "gpio-leds"; + + heartbeat { + gpios = <&gpio ASPEED_GPIO(B, 0) GPIO_ACTIVE_LOW>; + }; + + power { + gpios = <&gpio ASPEED_GPIO(B, 2) GPIO_ACTIVE_LOW>; + }; + + identify { + gpios = <&gpio ASPEED_GPIO(B, 3) GPIO_ACTIVE_LOW>; + }; + }; + + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>, + <&adc 4>, <&adc 5>, <&adc 6>, <&adc 7>, + <&adc 8>, <&adc 9>, <&adc 10>; + }; + + iio-hwmon-battery { + compatible = "iio-hwmon"; + io-channels = <&adc 11>; + }; + + i2c1mux: i2cmux { + compatible = "i2c-mux-gpio"; + #address-cells = <1>; + #size-cells = <0>; + + /* mux-gpios = <&sgpio 10 GPIO_ACTIVE_HIGH> */ + i2c-parent = <&i2c1>; + }; +}; + +&fmc { + status = "okay"; + flash@0 { + status = "okay"; + label = "bmc"; + m25p,fast-read; +#include "openbmc-flash-layout.dtsi" + }; +}; + +&spi { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi1_default>; + + flash@0 { + status = "okay"; + m25p,fast-read; + label = "pnor"; + }; +}; + +&pinctrl { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_vgahs_default &pinctrl_vgavs_default + &pinctrl_ddcclk_default &pinctrl_ddcdat_default>; +}; + +&lpc_snoop { + status = "okay"; + snoop-ports = <0x80>; +}; + +&mac0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rmii1_default>; + use-ncsi; +}; + +&mac1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>; +}; + +&uart5 { + status = "okay"; +}; + +&i2c0 { + status = "okay"; +}; + +&i2c1 { + status = "okay"; + + /* temp2 inlet */ + tmp75@4c { + compatible = "ti,tmp75"; + reg = <0x4c>; + }; + + /* temp3 */ + tmp75@4e { + compatible = "ti,tmp75"; + reg = <0x4e>; + }; + + /* temp1 */ + tmp75@4f { + compatible = "ti,tmp75"; + reg = <0x4f>; + }; + + /* Baseboard FRU */ + eeprom@54 { + compatible = "atmel,24c64"; + reg = <0x54>; + }; + + /* FP FRU */ + eeprom@57 { + compatible = "atmel,24c64"; + reg = <0x57>; + }; +}; + +&i2c2 { + status = "okay"; + + /* 0: PCIe Slot 2, + * Slot 3, + * Slot 6, + * Slot 7 + */ + i2c-switch@74 { + compatible = "nxp,pca9546"; + reg = <0x74>; + #address-cells = <1>; + #size-cells = <0>; + i2c-mux-idle-disconnect; /* may use mux@77 next. */ + + i2c_pcie2: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c_pcie3: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + i2c_pcie6: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c_pcie7: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; + + /* 0: PCIe Slot 1, + * Slot 4, + * Slot 5, + * Slot 8, + * Slot 9, + * Slot 10, + * SSD 1, + * SSD 2 + */ + i2c-switch@77 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x77>; + i2c-mux-idle-disconnect; /* may use mux@74 next. */ + + i2c_pcie1: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c_pcie4: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + i2c_pcie5: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c_pcie8: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + + i2c_pcie9: i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + }; + + i2c_pcie10: i2c@5 { + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; + }; + + i2c_ssd1: i2c@6 { + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; + }; + + i2c_ssd2: i2c@7 { + #address-cells = <1>; + #size-cells = <0>; + reg = <7>; + }; + }; +}; + +&i2c3 { + status = "okay"; + + /* BIOS FRU */ + eeprom@56 { + compatible = "atmel,24c64"; + reg = <0x56>; + }; +}; + +&i2c4 { + status = "okay"; +}; + +&i2c5 { + status = "okay"; +}; + +&i2c6 { + status = "okay"; +}; + +&i2c7 { + status = "okay"; + + /* 0: PSU4 + * PSU1 + * PSU3 + * PSU2 + */ + i2c-switch@70 { + compatible = "nxp,pca9546"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + + i2c_psu4: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + i2c_psu1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + i2c_psu3: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + i2c_psu2: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; + + /* PDB FRU */ + eeprom@52 { + compatible = "atmel,24c64"; + reg = <0x52>; + }; +}; + +&i2c8 { + status = "okay"; + + /* BMC FRU */ + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; +}; + +&vuart { + status = "okay"; +}; + +&wdt2 { + status = "okay"; +}; + +&pwm_tacho { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm0_default + &pinctrl_pwm1_default + &pinctrl_pwm2_default + &pinctrl_pwm3_default>; + + fan@0 { + reg = <0x00>; + aspeed,fan-tach-ch = /bits/ 8 <0x00>; + }; + + fan@1 { + reg = <0x01>; + aspeed,fan-tach-ch = /bits/ 8 <0x01>; + }; + + fan@2 { + reg = <0x02>; + aspeed,fan-tach-ch = /bits/ 8 <0x02>; + }; + + fan@3 { + reg = <0x03>; + aspeed,fan-tach-ch = /bits/ 8 <0x03>; + }; + + fan@4 { + reg = <0x00>; + aspeed,fan-tach-ch = /bits/ 8 <0x04>; + }; + + fan@5 { + reg = <0x01>; + aspeed,fan-tach-ch = /bits/ 8 <0x05>; + }; + + fan@6 { + reg = <0x02>; + aspeed,fan-tach-ch = /bits/ 8 <0x06>; + }; + + fan@7 { + reg = <0x03>; + aspeed,fan-tach-ch = /bits/ 8 <0x07>; + }; +}; + +&i2c1mux { + i2c@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + /* Memory Riser 1 FRU */ + eeprom@50 { + compatible = "atmel,24c02"; + reg = <0x50>; + }; + + /* Memory Riser 2 FRU */ + eeprom@51 { + compatible = "atmel,24c02"; + reg = <0x51>; + }; + + /* Memory Riser 3 FRU */ + eeprom@52 { + compatible = "atmel,24c02"; + reg = <0x52>; + }; + + /* Memory Riser 4 FRU */ + eeprom@53 { + compatible = "atmel,24c02"; + reg = <0x53>; + }; + }; + + i2c@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + /* Memory Riser 5 FRU */ + eeprom@50 { + compatible = "atmel,24c02"; + reg = <0x50>; + }; + + /* Memory Riser 6 FRU */ + eeprom@51 { + compatible = "atmel,24c02"; + reg = <0x51>; + }; + + /* Memory Riser 7 FRU */ + eeprom@52 { + compatible = "atmel,24c02"; + reg = <0x52>; + }; + + /* Memory Riser 8 FRU */ + eeprom@53 { + compatible = "atmel,24c02"; + reg = <0x53>; + }; + }; +}; diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi index de08d9045cb8..b0d8431a3700 100644 --- a/arch/arm/boot/dts/aspeed-g4.dtsi +++ b/arch/arm/boot/dts/aspeed-g4.dtsi @@ -1,5 +1,5 @@ -// SPDX-License-Identifier: GPL-2.0 -#include "skeleton.dtsi" +// SPDX-License-Identifier: GPL-2.0+ +#include / { model = "Aspeed BMC"; @@ -54,6 +54,7 @@ #address-cells = <1>; #size-cells = <0>; compatible = "aspeed,ast2400-fmc"; + clocks = <&syscon ASPEED_CLK_AHB>; status = "disabled"; interrupts = <19>; flash@0 { @@ -69,6 +70,7 @@ #address-cells = <1>; #size-cells = <0>; compatible = "aspeed,ast2400-spi"; + clocks = <&syscon ASPEED_CLK_AHB>; status = "disabled"; flash@0 { reg = < 0 >; @@ -89,6 +91,7 @@ compatible = "aspeed,ast2400-mac", "faraday,ftgmac100"; reg = <0x1e660000 0x180>; interrupts = <2>; + clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>; status = "disabled"; }; @@ -96,6 +99,7 @@ compatible = "aspeed,ast2400-mac", "faraday,ftgmac100"; reg = <0x1e680000 0x180>; interrupts = <3>; + clocks = <&syscon ASPEED_CLK_GATE_MAC2CLK>; status = "disabled"; }; @@ -106,47 +110,12 @@ ranges; syscon: syscon@1e6e2000 { - compatible = "aspeed,g4-scu", "syscon", "simple-mfd"; + compatible = "aspeed,ast2400-scu", "syscon", "simple-mfd"; reg = <0x1e6e2000 0x1a8>; #address-cells = <1>; #size-cells = <0>; - - clk_clkin: clk_clkin { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <48000000>; - }; - - clk_hpll: clk_hpll@70 { - #clock-cells = <0>; - compatible = "aspeed,g4-hpll-clock", "fixed-clock"; - reg = <0x70>; - clocks = <&clk_clkin>; - clock-frequency = <384000000>; - }; - - clk_ahb: clk_ahb@70 { - #clock-cells = <0>; - compatible = "aspeed,g4-ahb-clock", "fixed-clock"; - reg = <0x70>; - clocks = <&clk_hpll>; - clock-frequency = <192000000>; - }; - - clk_apb: clk_apb@8 { - #clock-cells = <0>; - compatible = "aspeed,g4-apb-clock", "fixed-clock"; - reg = <0x08>; - clocks = <&clk_hpll>; - clock-frequency = <48000000>; - }; - - clk_uart: clk_uart@2c{ - #clock-cells = <0>; - compatible = "aspeed,g4-uart-clock", "fixed-clock"; - reg = <0x2c>; - clock-frequency = <24000000>; - }; + #clock-cells = <1>; + #reset-cells = <1>; pinctrl: pinctrl { compatible = "aspeed,g4-pinctrl"; @@ -156,7 +125,8 @@ adc: adc@1e6e9000 { compatible = "aspeed,ast2400-adc"; reg = <0x1e6e9000 0xb0>; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_ADC>; #io-channel-cells = <1>; status = "disabled"; }; @@ -173,6 +143,7 @@ reg = <0x1e780000 0x1000>; interrupts = <20>; gpio-ranges = <&pinctrl 0 0 220>; + clocks = <&syscon ASPEED_CLK_APB>; interrupt-controller; }; @@ -181,7 +152,7 @@ compatible = "aspeed,ast2400-timer"; reg = <0x1e782000 0x90>; interrupts = <16 17 18 35 36 37 38 39>; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; clock-names = "PCLK"; }; @@ -190,7 +161,7 @@ reg = <0x1e783000 0x20>; reg-shift = <2>; interrupts = <9>; - clocks = <&clk_uart>; + clocks = <&syscon ASPEED_CLK_GATE_UART1CLK>; no-loopback-test; status = "disabled"; }; @@ -200,7 +171,7 @@ reg = <0x1e784000 0x20>; reg-shift = <2>; interrupts = <10>; - clocks = <&clk_uart>; + clocks = <&syscon ASPEED_CLK_GATE_UART5CLK>; no-loopback-test; status = "disabled"; }; @@ -208,11 +179,23 @@ wdt1: watchdog@1e785000 { compatible = "aspeed,ast2400-wdt"; reg = <0x1e785000 0x1c>; + clocks = <&syscon ASPEED_CLK_APB>; }; wdt2: watchdog@1e785020 { compatible = "aspeed,ast2400-wdt"; reg = <0x1e785020 0x1c>; + clocks = <&syscon ASPEED_CLK_APB>; + }; + + pwm_tacho: pwm-tacho-controller@1e786000 { + compatible = "aspeed,ast2400-pwm-tacho"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x1e786000 0x1000>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_PWM>; + status = "disabled"; }; vuart: serial@1e787000 { @@ -220,17 +203,59 @@ reg = <0x1e787000 0x40>; reg-shift = <2>; interrupts = <8>; - clocks = <&clk_uart>; + clocks = <&syscon ASPEED_CLK_APB>; no-loopback-test; status = "disabled"; }; + lpc: lpc@1e789000 { + compatible = "aspeed,ast2400-lpc", "simple-mfd"; + reg = <0x1e789000 0x1000>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x1e789000 0x1000>; + + lpc_bmc: lpc-bmc@0 { + compatible = "aspeed,ast2400-lpc-bmc"; + reg = <0x0 0x80>; + }; + + lpc_host: lpc-host@80 { + compatible = "aspeed,ast2400-lpc-host", "simple-mfd", "syscon"; + reg = <0x80 0x1e0>; + reg-io-width = <4>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x80 0x1e0>; + + lpc_ctrl: lpc-ctrl@0 { + compatible = "aspeed,ast2400-lpc-ctrl"; + reg = <0x0 0x80>; + status = "disabled"; + }; + + lpc_snoop: lpc-snoop@0 { + compatible = "aspeed,ast2400-lpc-snoop"; + reg = <0x0 0x80>; + interrupts = <8>; + status = "disabled"; + }; + + lhc: lhc@20 { + compatible = "aspeed,ast2400-lhc"; + reg = <0x20 0x24 0x48 0x8>; + }; + }; + }; + uart2: serial@1e78d000 { compatible = "ns16550a"; reg = <0x1e78d000 0x20>; reg-shift = <2>; interrupts = <32>; - clocks = <&clk_uart>; + clocks = <&syscon ASPEED_CLK_GATE_UART2CLK>; no-loopback-test; status = "disabled"; }; @@ -240,7 +265,7 @@ reg = <0x1e78e000 0x20>; reg-shift = <2>; interrupts = <33>; - clocks = <&clk_uart>; + clocks = <&syscon ASPEED_CLK_GATE_UART3CLK>; no-loopback-test; status = "disabled"; }; @@ -250,7 +275,7 @@ reg = <0x1e78f000 0x20>; reg-shift = <2>; interrupts = <34>; - clocks = <&clk_uart>; + clocks = <&syscon ASPEED_CLK_GATE_UART4CLK>; no-loopback-test; status = "disabled"; }; @@ -281,7 +306,8 @@ reg = <0x40 0x40>; compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <0>; interrupt-parent = <&i2c_ic>; @@ -296,7 +322,8 @@ reg = <0x80 0x40>; compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <1>; interrupt-parent = <&i2c_ic>; @@ -311,7 +338,8 @@ reg = <0xc0 0x40>; compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <2>; interrupt-parent = <&i2c_ic>; @@ -327,7 +355,8 @@ reg = <0x100 0x40>; compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <3>; interrupt-parent = <&i2c_ic>; @@ -343,7 +372,8 @@ reg = <0x140 0x40>; compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <4>; interrupt-parent = <&i2c_ic>; @@ -359,7 +389,8 @@ reg = <0x180 0x40>; compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <5>; interrupt-parent = <&i2c_ic>; @@ -375,7 +406,8 @@ reg = <0x1c0 0x40>; compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <6>; interrupt-parent = <&i2c_ic>; @@ -391,7 +423,8 @@ reg = <0x300 0x40>; compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <7>; interrupt-parent = <&i2c_ic>; @@ -407,7 +440,8 @@ reg = <0x340 0x40>; compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <8>; interrupt-parent = <&i2c_ic>; @@ -423,7 +457,8 @@ reg = <0x380 0x40>; compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <9>; interrupt-parent = <&i2c_ic>; @@ -439,7 +474,8 @@ reg = <0x3c0 0x40>; compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <10>; interrupt-parent = <&i2c_ic>; @@ -455,7 +491,8 @@ reg = <0x400 0x40>; compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <11>; interrupt-parent = <&i2c_ic>; @@ -471,7 +508,8 @@ reg = <0x440 0x40>; compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <12>; interrupt-parent = <&i2c_ic>; @@ -487,7 +525,8 @@ reg = <0x480 0x40>; compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <13>; interrupt-parent = <&i2c_ic>; diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi index 5c4ecdba3a6b..40de3b66c33f 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi @@ -1,5 +1,5 @@ -// SPDX-License-Identifier: GPL-2.0 -#include "skeleton.dtsi" +// SPDX-License-Identifier: GPL-2.0+ +#include / { model = "Aspeed BMC"; @@ -54,6 +54,7 @@ #address-cells = <1>; #size-cells = <0>; compatible = "aspeed,ast2500-fmc"; + clocks = <&syscon ASPEED_CLK_AHB>; status = "disabled"; interrupts = <19>; flash@0 { @@ -79,6 +80,7 @@ #address-cells = <1>; #size-cells = <0>; compatible = "aspeed,ast2500-spi"; + clocks = <&syscon ASPEED_CLK_AHB>; status = "disabled"; flash@0 { reg = < 0 >; @@ -98,6 +100,7 @@ #address-cells = <1>; #size-cells = <0>; compatible = "aspeed,ast2500-spi"; + clocks = <&syscon ASPEED_CLK_AHB>; status = "disabled"; flash@0 { reg = < 0 >; @@ -123,6 +126,7 @@ compatible = "aspeed,ast2500-mac", "faraday,ftgmac100"; reg = <0x1e660000 0x180>; interrupts = <2>; + clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>; status = "disabled"; }; @@ -130,6 +134,7 @@ compatible = "aspeed,ast2500-mac", "faraday,ftgmac100"; reg = <0x1e680000 0x180>; interrupts = <3>; + clocks = <&syscon ASPEED_CLK_GATE_MAC2CLK>; status = "disabled"; }; @@ -140,55 +145,18 @@ ranges; syscon: syscon@1e6e2000 { - compatible = "aspeed,g5-scu", "syscon", "simple-mfd"; + compatible = "aspeed,ast2500-scu", "syscon", "simple-mfd"; reg = <0x1e6e2000 0x1a8>; #address-cells = <1>; #size-cells = <0>; - - clk_clkin: clk_clkin@70 { - #clock-cells = <0>; - compatible = "aspeed,g5-clkin-clock", "fixed-clock"; - reg = <0x70>; - clock-frequency = <24000000>; - }; - - clk_hpll: clk_hpll@24 { - #clock-cells = <0>; - compatible = "aspeed,g5-hpll-clock", "fixed-clock"; - reg = <0x24>; - clocks = <&clk_clkin>; - clock-frequency = <792000000>; - }; - - clk_ahb: clk_ahb@70 { - #clock-cells = <0>; - compatible = "aspeed,g5-ahb-clock", "fixed-clock"; - reg = <0x70>; - clocks = <&clk_hpll>; - clock-frequency = <198000000>; - }; - - clk_apb: clk_apb@8 { - #clock-cells = <0>; - compatible = "aspeed,g5-apb-clock", "fixed-clock"; - reg = <0x08>; - clocks = <&clk_hpll>; - clock-frequency = <24750000>; - }; - - clk_uart: clk_uart@2c { - #clock-cells = <0>; - compatible = "aspeed,uart-clock", "fixed-clock"; - reg = <0x2c>; - clock-frequency = <24000000>; - }; + #clock-cells = <1>; + #reset-cells = <1>; pinctrl: pinctrl { compatible = "aspeed,g5-pinctrl"; aspeed,external-nodes = <&gfx &lhc>; }; - }; gfx: display@1e6e6000 { @@ -200,7 +168,8 @@ adc: adc@1e6e9000 { compatible = "aspeed,ast2500-adc"; reg = <0x1e6e9000 0xb0>; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_ADC>; #io-channel-cells = <1>; status = "disabled"; }; @@ -217,6 +186,7 @@ reg = <0x1e780000 0x1000>; interrupts = <20>; gpio-ranges = <&pinctrl 0 0 220>; + clocks = <&syscon ASPEED_CLK_APB>; interrupt-controller; }; @@ -225,7 +195,7 @@ compatible = "aspeed,ast2400-timer"; reg = <0x1e782000 0x90>; interrupts = <16 17 18 35 36 37 38 39>; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; clock-names = "PCLK"; }; @@ -234,7 +204,7 @@ reg = <0x1e783000 0x20>; reg-shift = <2>; interrupts = <9>; - clocks = <&clk_uart>; + clocks = <&syscon ASPEED_CLK_GATE_UART1CLK>; no-loopback-test; status = "disabled"; }; @@ -244,7 +214,7 @@ reg = <0x1e784000 0x20>; reg-shift = <2>; interrupts = <10>; - clocks = <&clk_uart>; + clocks = <&syscon ASPEED_CLK_GATE_UART5CLK>; no-loopback-test; status = "disabled"; }; @@ -252,16 +222,39 @@ wdt1: watchdog@1e785000 { compatible = "aspeed,ast2500-wdt"; reg = <0x1e785000 0x20>; + clocks = <&syscon ASPEED_CLK_APB>; }; wdt2: watchdog@1e785020 { compatible = "aspeed,ast2500-wdt"; reg = <0x1e785020 0x20>; + clocks = <&syscon ASPEED_CLK_APB>; }; wdt3: watchdog@1e785040 { compatible = "aspeed,ast2500-wdt"; reg = <0x1e785040 0x20>; + clocks = <&syscon ASPEED_CLK_APB>; + status = "disabled"; + }; + + pwm_tacho: pwm-tacho-controller@1e786000 { + compatible = "aspeed,ast2500-pwm-tacho"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x1e786000 0x1000>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_PWM>; + status = "disabled"; + }; + + vuart: serial@1e787000 { + compatible = "aspeed,ast2500-vuart"; + reg = <0x1e787000 0x40>; + reg-shift = <2>; + interrupts = <8>; + clocks = <&syscon ASPEED_CLK_APB>; + no-loopback-test; status = "disabled"; }; @@ -288,6 +281,19 @@ reg-io-width = <4>; + lpc_ctrl: lpc-ctrl@0 { + compatible = "aspeed,ast2500-lpc-ctrl"; + reg = <0x0 0x80>; + status = "disabled"; + }; + + lpc_snoop: lpc-snoop@0 { + compatible = "aspeed,ast2500-lpc-snoop"; + reg = <0x0 0x80>; + interrupts = <8>; + status = "disabled"; + }; + lhc: lhc@20 { compatible = "aspeed,ast2500-lhc"; reg = <0x20 0x24 0x48 0x8>; @@ -295,22 +301,12 @@ }; }; - vuart: serial@1e787000 { - compatible = "aspeed,ast2500-vuart"; - reg = <0x1e787000 0x40>; - reg-shift = <2>; - interrupts = <10>; - clocks = <&clk_uart>; - no-loopback-test; - status = "disabled"; - }; - uart2: serial@1e78d000 { compatible = "ns16550a"; reg = <0x1e78d000 0x20>; reg-shift = <2>; interrupts = <32>; - clocks = <&clk_uart>; + clocks = <&syscon ASPEED_CLK_GATE_UART2CLK>; no-loopback-test; status = "disabled"; }; @@ -320,7 +316,7 @@ reg = <0x1e78e000 0x20>; reg-shift = <2>; interrupts = <33>; - clocks = <&clk_uart>; + clocks = <&syscon ASPEED_CLK_GATE_UART3CLK>; no-loopback-test; status = "disabled"; }; @@ -330,7 +326,7 @@ reg = <0x1e78f000 0x20>; reg-shift = <2>; interrupts = <34>; - clocks = <&clk_uart>; + clocks = <&syscon ASPEED_CLK_GATE_UART4CLK>; no-loopback-test; status = "disabled"; }; @@ -361,7 +357,8 @@ reg = <0x40 0x40>; compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <0>; interrupt-parent = <&i2c_ic>; @@ -376,7 +373,8 @@ reg = <0x80 0x40>; compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <1>; interrupt-parent = <&i2c_ic>; @@ -391,7 +389,8 @@ reg = <0xc0 0x40>; compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <2>; interrupt-parent = <&i2c_ic>; @@ -407,7 +406,8 @@ reg = <0x100 0x40>; compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <3>; interrupt-parent = <&i2c_ic>; @@ -423,7 +423,8 @@ reg = <0x140 0x40>; compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <4>; interrupt-parent = <&i2c_ic>; @@ -439,7 +440,8 @@ reg = <0x180 0x40>; compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <5>; interrupt-parent = <&i2c_ic>; @@ -455,7 +457,8 @@ reg = <0x1c0 0x40>; compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <6>; interrupt-parent = <&i2c_ic>; @@ -471,7 +474,8 @@ reg = <0x300 0x40>; compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <7>; interrupt-parent = <&i2c_ic>; @@ -487,7 +491,8 @@ reg = <0x340 0x40>; compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <8>; interrupt-parent = <&i2c_ic>; @@ -503,7 +508,8 @@ reg = <0x380 0x40>; compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <9>; interrupt-parent = <&i2c_ic>; @@ -519,7 +525,8 @@ reg = <0x3c0 0x40>; compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <10>; interrupt-parent = <&i2c_ic>; @@ -535,7 +542,8 @@ reg = <0x400 0x40>; compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <11>; interrupt-parent = <&i2c_ic>; @@ -551,7 +559,8 @@ reg = <0x440 0x40>; compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <12>; interrupt-parent = <&i2c_ic>; @@ -567,7 +576,8 @@ reg = <0x480 0x40>; compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&clk_apb>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; bus-frequency = <100000>; interrupts = <13>; interrupt-parent = <&i2c_ic>; diff --git a/arch/arm/boot/dts/at91-ariag25.dts b/arch/arm/boot/dts/at91-ariag25.dts index 1c86537a42a0..e3e14b7e25aa 100644 --- a/arch/arm/boot/dts/at91-ariag25.dts +++ b/arch/arm/boot/dts/at91-ariag25.dts @@ -58,6 +58,18 @@ }; }; + tcb0: timer@f8008000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; + }; + i2c0: i2c@f8010000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/at91-ariettag25.dts b/arch/arm/boot/dts/at91-ariettag25.dts index f877f3430bcc..7a34c4dc05d2 100644 --- a/arch/arm/boot/dts/at91-ariettag25.dts +++ b/arch/arm/boot/dts/at91-ariettag25.dts @@ -46,6 +46,18 @@ }; }; + tcb0: timer@f8008000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; + }; + usb2: gadget@f803c000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/at91-cosino.dtsi b/arch/arm/boot/dts/at91-cosino.dtsi index 89cde175154e..295a5a43fe01 100644 --- a/arch/arm/boot/dts/at91-cosino.dtsi +++ b/arch/arm/boot/dts/at91-cosino.dtsi @@ -37,6 +37,18 @@ ahb { apb { + tcb0: timer@f8008000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; + }; + mmc0: mmc@f0008000 { pinctrl-0 = < &pinctrl_board_mmc0 diff --git a/arch/arm/boot/dts/at91-foxg20.dts b/arch/arm/boot/dts/at91-foxg20.dts index 50d5e719b451..d413e2d9abdf 100644 --- a/arch/arm/boot/dts/at91-foxg20.dts +++ b/arch/arm/boot/dts/at91-foxg20.dts @@ -34,6 +34,18 @@ ahb { apb { + tcb0: timer@fffa0000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + usb1: gadget@fffa4000 { atmel,vbus-gpio = <&pioC 6 GPIO_ACTIVE_HIGH>; status = "okay"; diff --git a/arch/arm/boot/dts/at91-kizbox.dts b/arch/arm/boot/dts/at91-kizbox.dts index 1f31df846d61..1003846679c1 100644 --- a/arch/arm/boot/dts/at91-kizbox.dts +++ b/arch/arm/boot/dts/at91-kizbox.dts @@ -31,6 +31,18 @@ ahb { apb { + tcb0: timer@fffa0000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + macb0: ethernet@fffc4000 { phy-mode = "mii"; pinctrl-0 = <&pinctrl_macb_rmii diff --git a/arch/arm/boot/dts/at91-kizbox2.dts b/arch/arm/boot/dts/at91-kizbox2.dts index ec6c28c521a5..30041e8f12d5 100644 --- a/arch/arm/boot/dts/at91-kizbox2.dts +++ b/arch/arm/boot/dts/at91-kizbox2.dts @@ -94,6 +94,18 @@ }; }; + tcb0: timer@f0010000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; + }; + usart0: serial@f001c000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/at91-kizboxmini.dts b/arch/arm/boot/dts/at91-kizboxmini.dts index fe1bc0a59a98..15b0746e44e2 100644 --- a/arch/arm/boot/dts/at91-kizboxmini.dts +++ b/arch/arm/boot/dts/at91-kizboxmini.dts @@ -34,6 +34,18 @@ ahb { apb { + tcb0: timer@f8008000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; + }; + usart0: serial@f801c000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/at91-linea.dtsi b/arch/arm/boot/dts/at91-linea.dtsi index 87e5090fb4c4..c7b964e25321 100644 --- a/arch/arm/boot/dts/at91-linea.dtsi +++ b/arch/arm/boot/dts/at91-linea.dtsi @@ -27,6 +27,18 @@ clock-frequency = <12000000>; }; +&tcb0 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; +}; + &i2c0 { status = "okay"; diff --git a/arch/arm/boot/dts/at91-natte.dtsi b/arch/arm/boot/dts/at91-natte.dtsi new file mode 100644 index 000000000000..49f0a0c46cde --- /dev/null +++ b/arch/arm/boot/dts/at91-natte.dtsi @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * at91-natte.dts - Device Tree include file for the Natte board + * + * Copyright (C) 2017 Axentia Technologies AB + * + * Author: Peter Rosin + */ + +/ { + mux: mux-controller { + compatible = "gpio-mux"; + #mux-control-cells = <0>; + + mux-gpios = <&ioexp 0 GPIO_ACTIVE_HIGH>, + <&ioexp 1 GPIO_ACTIVE_HIGH>, + <&ioexp 2 GPIO_ACTIVE_HIGH>; + }; + + batntc-mux { + compatible = "io-channel-mux"; + io-channels = <&adc 5>; + io-channel-names = "parent"; + mux-controls = <&mux>; + + channels = + "batntc0", "batntc1", "batntc2", "batntc3", + "batntc4", "batntc5", "batntc6", "batntc7"; + }; + + batv-mux { + compatible = "io-channel-mux"; + io-channels = <&adc 6>; + io-channel-names = "parent"; + mux-controls = <&mux>; + + channels = + "batv0", "batv1", "batv2", "batv3", + "batv4", "batv5", "batv6", "batv7"; + }; + + iout-mux { + compatible = "io-channel-mux"; + io-channels = <&adc 7>; + io-channel-names = "parent"; + mux-controls = <&mux>; + + channels = + "iout0", "iout1", "iout2", "iout3", + "iout4", "iout5", "iout6", "iout7"; + }; + + i2c-mux { + compatible = "i2c-mux"; + mux-locked; + i2c-parent = <&i2c0>; + mux-controls = <&mux>; + + #address-cells = <1>; + #size-cells = <0>; + + i2c@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + charger@9 { + compatible = "ti,bq24735"; + reg = <0x9>; + + ti,charge-current = <2000>; + ti,charge-voltage = <16800>; + + poll-interval = <20000>; + }; + }; + + i2c@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + charger@9 { + compatible = "ti,bq24735"; + reg = <0x9>; + + ti,charge-current = <2000>; + ti,charge-voltage = <16800>; + + poll-interval = <20000>; + }; + }; + + i2c@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + + charger@9 { + compatible = "ti,bq24735"; + reg = <0x9>; + + ti,charge-current = <2000>; + ti,charge-voltage = <16800>; + + poll-interval = <20000>; + }; + }; + + i2c@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + + charger@9 { + compatible = "ti,bq24735"; + reg = <0x9>; + + ti,charge-current = <2000>; + ti,charge-voltage = <16800>; + + poll-interval = <20000>; + }; + }; + + i2c@4 { + reg = <4>; + #address-cells = <1>; + #size-cells = <0>; + + charger@9 { + compatible = "ti,bq24735"; + reg = <0x9>; + + ti,charge-current = <2000>; + ti,charge-voltage = <16800>; + + poll-interval = <20000>; + }; + }; + + i2c@5 { + reg = <5>; + #address-cells = <1>; + #size-cells = <0>; + + charger@9 { + compatible = "ti,bq24735"; + reg = <0x9>; + + ti,charge-current = <2000>; + ti,charge-voltage = <16800>; + + poll-interval = <20000>; + }; + }; + + i2c@6 { + reg = <6>; + #address-cells = <1>; + #size-cells = <0>; + + charger@9 { + compatible = "ti,bq24735"; + reg = <0x9>; + + ti,charge-current = <2000>; + ti,charge-voltage = <16800>; + + poll-interval = <20000>; + }; + }; + + i2c@7 { + reg = <7>; + #address-cells = <1>; + #size-cells = <0>; + + charger@9 { + compatible = "ti,bq24735"; + reg = <0x9>; + + ti,charge-current = <2000>; + ti,charge-voltage = <16800>; + + poll-interval = <20000>; + }; + }; + }; +}; + +&i2c0 { + status = "okay"; + + ioexp: ioexp@20 { + #gpio-cells = <2>; + compatible = "semtech,sx1502q"; + reg = <0x20>; + + gpio-controller; + ngpios = <8>; + + pinctrl-names = "default"; + pinctrl-0 = <&gpio3_cfg_pins>; + + gpio3_cfg_pins: gpio3_cfg { + pins = "gpio3"; + bias-pull-up; + }; + }; + + adc: adc@48 { + compatible = "ti,ads1015"; + reg = <0x48>; + #io-channel-cells = <1>; + + #address-cells = <1>; + #size-cells = <0>; + + channel@4 { + reg = <4>; + ti,gain = <2>; + ti,datarate = <4>; + }; + + channel@5 { + reg = <5>; + ti,gain = <2>; + ti,datarate = <4>; + }; + + channel@6 { + reg = <6>; + ti,gain = <1>; + ti,datarate = <4>; + }; + + channel@7 { + reg = <7>; + ti,gain = <3>; + ti,datarate = <4>; + }; + }; +}; diff --git a/arch/arm/boot/dts/at91-nattis-2-natte-2.dts b/arch/arm/boot/dts/at91-nattis-2-natte-2.dts new file mode 100644 index 000000000000..3ea1d26e1c68 --- /dev/null +++ b/arch/arm/boot/dts/at91-nattis-2-natte-2.dts @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * at91-nattis-2-natte-2.dts - Device Tree file for the Linea/Nattis board + * + * Copyright (C) 2017 Axentia Technologies AB + * + * Author: Peter Rosin + */ +/dts-v1/; +#include "at91-linea.dtsi" +#include "sama5d3_lcd.dtsi" +#include "at91-natte.dtsi" + +/ { + model = "Axentia Linea-Nattis v2 Natte v2"; + compatible = "axentia,nattis-2", "axentia,natte-2", "axentia,linea", + "atmel,sama5d31", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + pinctrl@fffff200 { + nattis { + pinctrl_usba_vbus: usba_vbus { + atmel,pins = + ; + }; + + pinctrl_mmc0_cd: mmc0_cd { + atmel,pins = + ; + }; + + pinctrl_lcd_prlud0: lcd_prlud0 { + atmel,pins = + ; + }; + + pinctrl_lcd_hipow0: lcd_hipow0 { + atmel,pins = + ; + }; + }; + }; + + watchdog@fffffe40 { + status = "okay"; + }; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + wakeup { + label = "Wakeup"; + linux,code = <10>; + gpio-key,wakeup; + gpios = <&pioB 27 GPIO_ACTIVE_LOW>; + }; + }; + + panel_reg: panel-regulator { + compatible = "regulator-fixed"; + regulator-name = "panel-VCC"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + bl_reg: backlight-regulator { + compatible = "regulator-fixed"; + regulator-name = "panel-VDD"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + }; + + panel_bl: backlight { + compatible = "pwm-backlight"; + pwms = <&hlcdc_pwm 0 100000 0>; + + brightness-levels = < 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 33 34 35 36 37 38 39 + 40 41 42 43 44 45 46 47 48 49 + 50 51 52 53 54 55 56 57 58 59 + 60 61 62 63 64 65 66 67 68 69 + 70 71 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 88 89 + 90 91 92 93 94 95 96 97 98 99 + 100>; + default-brightness-level = <40>; + + power-supply = <&bl_reg>; + enable-gpios = <&pioA 20 GPIO_ACTIVE_HIGH>; + }; + + panel: panel { + compatible = "sharp,lq150x1lg11"; + backlight = <&panel_bl>; + power-supply = <&panel_reg>; + + port { + panel_input: endpoint { + remote-endpoint = <&hlcdc_panel_output>; + }; + }; + }; + + sound { + compatible = "simple-audio-card"; + + simple-audio-card,name = "nattis-tfa9879"; + simple-audio-card,format = "i2s"; + simple-audio-card,bitclock-master = <&cpu_dai>; + simple-audio-card,frame-master = <&cpu_dai>; + simple-audio-card,widgets = "Line", "Line Out Jack"; + simple-audio-card,routing = "Line Out Jack", "LINEOUT"; + + cpu_dai: simple-audio-card,cpu { + sound-dai = <&ssc0>; + }; + + simple-audio-card,codec { + sound-dai = <&>; + }; + }; +}; + +&i2c0 { + status = "okay"; + + clock-frequency = <100000>; + + temp@18 { + compatible = "nxp,se97b", "jedec,jc-42.4-temp"; + reg = <0x18>; + smbus-timeout-disable; + }; + + eeprom@50 { + compatible = "nxp,24c02"; + reg = <0x50>; + pagesize = <16>; + }; + + amp: amplifier@6c { + compatible = "nxp,tfa9879"; + reg = <0x6c>; + #sound-dai-cells = <0>; + }; +}; + +&ssc0 { + status = "okay"; + + atmel,clk-from-rk-pin; + #sound-dai-cells = <0>; +}; + +&hlcdc { + status = "okay"; + + hlcdc-display-controller { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base + &pinctrl_lcd_rgb565 + &pinctrl_lcd_prlud0 + &pinctrl_lcd_hipow0>; + + port@0 { + hlcdc_panel_output: endpoint { + remote-endpoint = <&panel_input>; + }; + }; + }; +}; + +&mmc0 { + status = "okay"; + + pinctrl-0 = <&pinctrl_mmc0_clk_cmd_dat0 + &pinctrl_mmc0_dat1_3 + &pinctrl_mmc0_cd>; + + slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioD 5 GPIO_ACTIVE_HIGH>; + }; +}; + +&usart0 { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usart0>; + atmel,use-dma-rx; +}; + +&nand { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + at91bootstrap@0 { + label = "at91bootstrap"; + reg = <0x0 0x40000>; + }; + + bootloader@40000 { + label = "bootloader"; + reg = <0x40000 0x80000>; + }; + + bootloaderenv@c0000 { + label = "bootloader env"; + reg = <0xc0000 0xc0000>; + }; + + dtb@180000 { + label = "device tree"; + reg = <0x180000 0x80000>; + }; + + kernel@200000 { + label = "kernel"; + reg = <0x200000 0x600000>; + }; + + rootfs@800000 { + label = "rootfs"; + reg = <0x800000 0x0f800000>; + }; + }; +}; + +&dbgu { + status = "okay"; + + atmel,use-dma-rx; +}; + +&usb0 { + status = "okay"; + + atmel,vbus-gpio = <&pioD 28 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usba_vbus>; +}; diff --git a/arch/arm/boot/dts/at91-qil_a9260.dts b/arch/arm/boot/dts/at91-qil_a9260.dts index f46352790a41..72e9148ca096 100644 --- a/arch/arm/boot/dts/at91-qil_a9260.dts +++ b/arch/arm/boot/dts/at91-qil_a9260.dts @@ -31,6 +31,18 @@ ahb { apb { + tcb0: timer@fffa0000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + usb1: gadget@fffa4000 { atmel,vbus-gpio = <&pioC 5 GPIO_ACTIVE_HIGH>; status = "okay"; diff --git a/arch/arm/boot/dts/at91-sam9_l9260.dts b/arch/arm/boot/dts/at91-sam9_l9260.dts index 171243ca4f2f..70cb36f7a9d7 100644 --- a/arch/arm/boot/dts/at91-sam9_l9260.dts +++ b/arch/arm/boot/dts/at91-sam9_l9260.dts @@ -32,6 +32,18 @@ ahb { apb { + tcb0: timer@fffa0000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + mmc0: mmc@fffa8000 { pinctrl-0 = < &pinctrl_board_mmc0 diff --git a/arch/arm/boot/dts/at91-sama5d27_som1_ek.dts b/arch/arm/boot/dts/at91-sama5d27_som1_ek.dts index 6d87b4eb6c41..e86e0c00eb6b 100644 --- a/arch/arm/boot/dts/at91-sama5d27_som1_ek.dts +++ b/arch/arm/boot/dts/at91-sama5d27_som1_ek.dts @@ -119,6 +119,18 @@ status = "okay"; }; + tcb0: timer@f800c000 { + timer0: timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer1: timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; + }; + uart1: serial@f8020000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart1_default>; diff --git a/arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts b/arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts new file mode 100644 index 000000000000..e603a267bdf1 --- /dev/null +++ b/arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts @@ -0,0 +1,413 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR X11) +/* + * at91-sama5d2_ptc_ek.dts - Device Tree file for SAMA5D2 PTC EK board + * + * Copyright (C) 2017 Microchip/Atmel, + * 2017 Wenyou Yang + * 2017 Ludovic Desroches + */ +/dts-v1/; +#include "sama5d2.dtsi" +#include "sama5d2-pinfunc.h" +#include +#include + +/ { + model = "Atmel SAMA5D2 PTC EK"; + compatible = "atmel,sama5d2-ptc_ek", "atmel,sama5d2", "atmel,sama5"; + + aliases { + serial0 = &uart0; + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + clocks { + slow_xtal { + clock-frequency = <32768>; + }; + + main_xtal { + clock-frequency = <24000000>; + }; + }; + + ahb { + usb0: gadget@300000 { + atmel,vbus-gpio = <&pioA PIN_PA27 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usba_vbus>; + status = "okay"; + }; + + usb1: ohci@400000 { + num-ports = <3>; + atmel,vbus-gpio = <0 + &pioA PIN_PB12 GPIO_ACTIVE_HIGH + 0 + >; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb_default>; + status = "okay"; + }; + + usb2: ehci@500000 { + status = "okay"; + }; + + ebi: ebi@10000000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_nand_default>; + status = "okay"; /* conflicts with sdmmc1 and qspi0 */ + + nand_controller: nand-controller { + status = "okay"; + + nand@3 { + reg = <0x3 0x0 0x2>; + atmel,rb = <0>; + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + nand-on-flash-bbt; + label = "atmel_nand"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + at91bootstrap@0 { + label = "bootstrap"; + reg = <0x0 0x40000>; + }; + + bootloader@40000 { + label = "bootloader"; + reg = <0x40000 0xc0000>; + }; + + bootloaderenv@0x100000 { + label = "bootloader env"; + reg = <0x100000 0x40000>; + }; + + bootloaderenvred@0x140000 { + label = "bootloader env redundant"; + reg = <0x140000 0x40000>; + }; + + dtb@180000 { + label = "device tree"; + reg = <0x180000 0x80000>; + }; + + kernel@200000 { + label = "kernel"; + reg = <0x200000 0x600000>; + }; + + rootfs@800000 { + label = "rootfs"; + reg = <0x800000 0x1f800000>; + }; + }; + }; + }; + }; + + sdmmc0: sdio-host@a0000000 { + bus-width = <8>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sdmmc0_default>; + non-removable; + mmc-ddr-1_8v; + status = "okay"; + }; + + apb { + spi0: spi@f8000000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi0_default>; + status = "okay"; + }; + + macb0: ethernet@f8008000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_macb0_default &pinctrl_macb0_phy_irq>; + phy-mode = "rmii"; + status = "okay"; + + ethernet-phy@1 { + reg = <0x1>; + interrupt-parent = <&pioA>; + interrupts = <56 IRQ_TYPE_LEVEL_LOW>; + }; + }; + + tcb0: timer@f800c000 { + timer0: timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer1: timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; + }; + + uart0: serial@f801c000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart0_default>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "okay"; + }; + + uart2: serial@f8024000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2_default>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "okay"; + }; + + i2c0: i2c@f8028000 { + dmas = <0>, <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c0_default>; + status = "okay"; + }; + + flx0: flexcom@f8034000 { + atmel,flexcom-mode = ; + status = "okay"; + + i2c2: i2c@600 { + compatible = "atmel,sama5d2-i2c"; + reg = <0x600 0x200>; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <0>, <0>; + dma-names = "tx", "rx"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&flx0_clk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flx0_default>; + atmel,fifo-size = <16>; + status = "okay"; + }; + }; + + shdwc@f8048010 { + atmel,shdwc-debouncer = <976>; + + input@0 { + reg = <0>; + atmel,wakeup-type = "low"; + }; + }; + + watchdog@f8048040 { + status = "okay"; + }; + + spi1: spi@fc000000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi1_default>; + status = "okay"; + }; + + i2c1: i2c@fc028000 { + dmas = <0>, <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1_default>; + status = "okay"; + + at24@50 { + compatible = "24c02"; + reg = <0x50>; + pagesize = <8>; + }; + }; + + pinctrl@fc038000 { + pinctrl_flx0_default: flx0_default { + pinmux = , + ; + bias-disable; + }; + + pinctrl_i2c0_default: i2c0_default { + pinmux = , + ; + bias-disable; + }; + + pinctrl_i2c1_default: i2c1_default { + pinmux = , + ; + bias-disable; + }; + + pinctrl_key_gpio_default: key_gpio_default { + pinmux = ; + bias-pull-up; + }; + + pinctrl_led_gpio_default: led_gpio_default { + pinmux = , + , + ; + bias-pull-up; + }; + + pinctrl_macb0_default: macb0_default { + pinmux = , + , + , + , + , + , + , + , + , + ; + bias-disable; + }; + + pinctrl_macb0_phy_irq: macb0_phy_irq { + pinmux = ; + bias-disable; + }; + + pinctrl_nand_default: nand_default { + re_we_data { + pinmux = , + , + , + , + , + , + , + , + , + ; + bias-pull-up; + }; + + ale_cle_rdy_cs { + pinmux = , + , + , + ; + bias-pull-up; + }; + }; + + pinctrl_sdmmc0_default: sdmmc0_default { + cmd_data { + pinmux = , + , + , + , + , + , + , + , + ; + bias-pull-up; + }; + + ck_cd_vddsel { + pinmux = , + , + ; + bias-disable; + }; + }; + + pinctrl_spi0_default: spi0_default { + pinmux = , + , + , + ; + bias-disable; + }; + + pinctrl_spi1_default: spi1_default { + pinmux = , + , + , + ; + bias-disable; + }; + + pinctrl_uart0_default: uart0_default { + pinmux = , + ; + bias-disable; + }; + + pinctrl_uart2_default: uart2_default { + pinmux = , + ; + bias-disable; + }; + + pinctrl_usb_default: usb_default { + pinmux = ; + bias-disable; + }; + + pinctrl_usba_vbus: usba_vbus { + pinmux = ; + bias-disable; + }; + + }; + + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_key_gpio_default>; + + bp1 { + label = "PB_USER"; + gpios = <&pioA PIN_PA10 GPIO_ACTIVE_LOW>; + linux,code = <0x104>; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_led_gpio_default>; + status = "okay"; + + red { + label = "red"; + gpios = <&pioA PIN_PB10 GPIO_ACTIVE_HIGH>; + }; + + green { + label = "green"; + gpios = <&pioA PIN_PB8 GPIO_ACTIVE_HIGH>; + }; + + blue { + label = "blue"; + gpios = <&pioA PIN_PB6 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + }; +}; diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 56de21de2779..e4bbb7e0f793 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -133,6 +133,18 @@ }; }; + tcb0: timer@f800c000 { + timer0: timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer1: timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; + }; + pdmic@f8018000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pdmic_default>; diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts index 40879aded680..02c1d2958d78 100644 --- a/arch/arm/boot/dts/at91-sama5d3_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts @@ -65,6 +65,18 @@ status = "okay"; }; + tcb0: timer@f0010000 { + timer0: timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer1: timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; + }; + i2c0: i2c@f0014000 { pinctrl-0 = <&pinctrl_i2c0_pu>; status = "okay"; diff --git a/arch/arm/boot/dts/at91-sama5d4_ma5d4.dtsi b/arch/arm/boot/dts/at91-sama5d4_ma5d4.dtsi index b813fdfa2842..d3e79fbf1944 100644 --- a/arch/arm/boot/dts/at91-sama5d4_ma5d4.dtsi +++ b/arch/arm/boot/dts/at91-sama5d4_ma5d4.dtsi @@ -89,6 +89,18 @@ }; }; + tcb2: timer@fc024000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; + }; + adc0: adc@fc034000 { pinctrl-names = "default"; pinctrl-0 = < diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained.dts b/arch/arm/boot/dts/at91-sama5d4_xplained.dts index 29ab17a97f9a..4b7c762d5f22 100644 --- a/arch/arm/boot/dts/at91-sama5d4_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d4_xplained.dts @@ -130,6 +130,18 @@ status = "okay"; }; + tcb2: timer@fc024000 { + timer0: timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer1: timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; + }; + adc0: adc@fc034000 { pinctrl-names = "default"; pinctrl-0 = < diff --git a/arch/arm/boot/dts/at91-sama5d4ek.dts b/arch/arm/boot/dts/at91-sama5d4ek.dts index 5b7ee92e32a7..7887a7160a54 100644 --- a/arch/arm/boot/dts/at91-sama5d4ek.dts +++ b/arch/arm/boot/dts/at91-sama5d4ek.dts @@ -174,6 +174,18 @@ status = "okay"; }; + tcb2: timer@fc024000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; + }; + watchdog@fc068640 { status = "okay"; }; diff --git a/arch/arm/boot/dts/at91-vinco.dts b/arch/arm/boot/dts/at91-vinco.dts index 9f6005708ea8..1be9889a2b3a 100644 --- a/arch/arm/boot/dts/at91-vinco.dts +++ b/arch/arm/boot/dts/at91-vinco.dts @@ -151,6 +151,18 @@ status = "okay"; }; + tcb2: timer@fc024000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; + }; + macb1: ethernet@fc028000 { phy-mode = "rmii"; status = "okay"; diff --git a/arch/arm/boot/dts/at91rm9200.dtsi b/arch/arm/boot/dts/at91rm9200.dtsi index da622bf45b4a..ba61893a02a0 100644 --- a/arch/arm/boot/dts/at91rm9200.dtsi +++ b/arch/arm/boot/dts/at91rm9200.dtsi @@ -375,7 +375,9 @@ }; tcb0: timer@fffa0000 { - compatible = "atmel,at91rm9200-tcb"; + compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xfffa0000 0x100>; interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0 18 IRQ_TYPE_LEVEL_HIGH 0 @@ -385,7 +387,9 @@ }; tcb1: timer@fffa4000 { - compatible = "atmel,at91rm9200-tcb"; + compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xfffa4000 0x100>; interrupts = <20 IRQ_TYPE_LEVEL_HIGH 0 21 IRQ_TYPE_LEVEL_HIGH 0 diff --git a/arch/arm/boot/dts/at91rm9200ek.dts b/arch/arm/boot/dts/at91rm9200ek.dts index 33192d0cefee..81aaf8151c76 100644 --- a/arch/arm/boot/dts/at91rm9200ek.dts +++ b/arch/arm/boot/dts/at91rm9200ek.dts @@ -32,6 +32,18 @@ ahb { apb { + tcb0: timer@fffa0000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + usb1: gadget@fffb0000 { atmel,vbus-gpio = <&pioD 4 GPIO_ACTIVE_HIGH>; atmel,pullup-gpio = <&pioD 5 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi index bc655e7332d6..655f06cd716a 100644 --- a/arch/arm/boot/dts/at91sam9260.dtsi +++ b/arch/arm/boot/dts/at91sam9260.dtsi @@ -386,7 +386,9 @@ }; tcb0: timer@fffa0000 { - compatible = "atmel,at91rm9200-tcb"; + compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xfffa0000 0x100>; interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0 18 IRQ_TYPE_LEVEL_HIGH 0 @@ -396,7 +398,9 @@ }; tcb1: timer@fffdc000 { - compatible = "atmel,at91rm9200-tcb"; + compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xfffdc000 0x100>; interrupts = <26 IRQ_TYPE_LEVEL_HIGH 0 27 IRQ_TYPE_LEVEL_HIGH 0 diff --git a/arch/arm/boot/dts/at91sam9260ek.dts b/arch/arm/boot/dts/at91sam9260ek.dts index b2578feceb08..e16c706d91ef 100644 --- a/arch/arm/boot/dts/at91sam9260ek.dts +++ b/arch/arm/boot/dts/at91sam9260ek.dts @@ -69,6 +69,18 @@ ahb { apb { + tcb0: timer@fffa0000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + usb1: gadget@fffa4000 { atmel,vbus-gpio = <&pioC 5 GPIO_ACTIVE_HIGH>; status = "okay"; diff --git a/arch/arm/boot/dts/at91sam9261.dtsi b/arch/arm/boot/dts/at91sam9261.dtsi index 66876019101d..ddfc63b8fd4e 100644 --- a/arch/arm/boot/dts/at91sam9261.dtsi +++ b/arch/arm/boot/dts/at91sam9261.dtsi @@ -80,7 +80,7 @@ status = "disabled"; }; - fb0: fb@0x00600000 { + fb0: fb@600000 { compatible = "atmel,at91sam9261-lcdc"; reg = <0x00600000 0x1000>; interrupts = <21 IRQ_TYPE_LEVEL_HIGH 3>; @@ -125,7 +125,9 @@ ranges; tcb0: timer@fffa0000 { - compatible = "atmel,at91rm9200-tcb"; + compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xfffa0000 0x100>; interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0>, <18 IRQ_TYPE_LEVEL_HIGH 0>, diff --git a/arch/arm/boot/dts/at91sam9261ek.dts b/arch/arm/boot/dts/at91sam9261ek.dts index 960d6940ebf6..a29fc0494076 100644 --- a/arch/arm/boot/dts/at91sam9261ek.dts +++ b/arch/arm/boot/dts/at91sam9261ek.dts @@ -15,6 +15,14 @@ chosen { bootargs = "rootfstype=ubifs ubi.mtd=5 root=ubi0:rootfs rw"; stdout-path = "serial0:115200n8"; + + clocksource { + timer = <&timer0>; + }; + + clockevent { + timer = <&timer1>; + }; }; memory { @@ -36,7 +44,7 @@ status = "okay"; }; - fb0: fb@0x00600000 { + fb0: fb@600000 { display = <&display0>; atmel,power-control-gpio = <&pioA 12 GPIO_ACTIVE_LOW>; status = "okay"; @@ -125,6 +133,18 @@ }; apb { + tcb0: timer@fffa0000 { + timer0: timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer1: timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + usb1: gadget@fffa4000 { atmel,vbus-gpio = <&pioB 29 GPIO_ACTIVE_HIGH>; status = "okay"; diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi index e54f14d36b6f..f2405671e3bd 100644 --- a/arch/arm/boot/dts/at91sam9263.dtsi +++ b/arch/arm/boot/dts/at91sam9263.dtsi @@ -389,7 +389,9 @@ }; tcb0: timer@fff7c000 { - compatible = "atmel,at91rm9200-tcb"; + compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xfff7c000 0x100>; interrupts = <19 IRQ_TYPE_LEVEL_HIGH 0>; clocks = <&tcb_clk>, <&slow_xtal>; @@ -999,7 +1001,7 @@ }; }; - fb0: fb@0x00700000 { + fb0: fb@700000 { compatible = "atmel,at91sam9263-lcdc"; reg = <0x00700000 0x1000>; interrupts = <26 IRQ_TYPE_LEVEL_HIGH 3>; diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts index 5a2e1af793f5..e9a7c70830a8 100644 --- a/arch/arm/boot/dts/at91sam9263ek.dts +++ b/arch/arm/boot/dts/at91sam9263ek.dts @@ -37,6 +37,18 @@ status = "okay"; }; + tcb0: timer@fff7c000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + usart0: serial@fff8c000 { pinctrl-0 = < &pinctrl_usart0 @@ -95,7 +107,7 @@ }; }; - fb0: fb@0x00700000 { + fb0: fb@700000 { display = <&display0>; status = "okay"; diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi index ac9a1511e239..50561b7b7939 100644 --- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi +++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi @@ -51,6 +51,18 @@ status = "okay"; }; + tcb0: timer@fffa0000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + usart0: serial@fffb0000 { pinctrl-0 = <&pinctrl_usart0 diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts index 91a71774472e..31fecc2cdaf9 100644 --- a/arch/arm/boot/dts/at91sam9g25ek.dts +++ b/arch/arm/boot/dts/at91sam9g25ek.dts @@ -25,7 +25,7 @@ }; i2c0: i2c@f8010000 { - ov2640: camera@0x30 { + ov2640: camera@30 { compatible = "ovti,ov2640"; reg = <0x30>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index 2b127ca7aaa0..3a30eec7f508 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi @@ -415,7 +415,9 @@ }; tcb0: timer@fff7c000 { - compatible = "atmel,at91rm9200-tcb"; + compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xfff7c000 0x100>; interrupts = <18 IRQ_TYPE_LEVEL_HIGH 0>; clocks = <&tcb0_clk>, <&tcb0_clk>, <&tcb0_clk>, <&clk32k>; @@ -423,7 +425,9 @@ }; tcb1: timer@fffd4000 { - compatible = "atmel,at91rm9200-tcb"; + compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xfffd4000 0x100>; interrupts = <18 IRQ_TYPE_LEVEL_HIGH 0>; clocks = <&tcb0_clk>, <&tcb0_clk>, <&tcb0_clk>, <&clk32k>; @@ -1302,7 +1306,7 @@ }; }; - fb0: fb@0x00500000 { + fb0: fb@500000 { compatible = "atmel,at91sam9g45-lcdc"; reg = <0x00500000 0x1000>; interrupts = <23 IRQ_TYPE_LEVEL_HIGH 3>; diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts index e922552a04cb..25888339d8de 100644 --- a/arch/arm/boot/dts/at91sam9m10g45ek.dts +++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts @@ -39,6 +39,18 @@ status = "okay"; }; + tcb0: timer@fff7c000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + usart1: serial@fff90000 { pinctrl-0 = <&pinctrl_usart1 @@ -220,7 +232,7 @@ }; }; - fb0: fb@0x00500000 { + fb0: fb@500000 { display = <&display0>; status = "okay"; diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi index e0ac824e0785..4b62f4f963f6 100644 --- a/arch/arm/boot/dts/at91sam9n12.dtsi +++ b/arch/arm/boot/dts/at91sam9n12.dtsi @@ -446,7 +446,9 @@ }; tcb0: timer@f8008000 { - compatible = "atmel,at91sam9x5-tcb"; + compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xf8008000 0x100>; interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0>; clocks = <&tcb_clk>, <&clk32k>; @@ -454,7 +456,9 @@ }; tcb1: timer@f800c000 { - compatible = "atmel,at91sam9x5-tcb"; + compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xf800c000 0x100>; interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0>; clocks = <&tcb_clk>, <&clk32k>; diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts index 212562aedf5e..c43095c5cb5c 100644 --- a/arch/arm/boot/dts/at91sam9n12ek.dts +++ b/arch/arm/boot/dts/at91sam9n12ek.dts @@ -42,6 +42,18 @@ status = "okay"; }; + tcb0: timer@f8008000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; + }; + i2c0: i2c@f8010000 { status = "okay"; diff --git a/arch/arm/boot/dts/at91sam9rl.dtsi b/arch/arm/boot/dts/at91sam9rl.dtsi index 52f0e9ef8f67..3cae687dccbd 100644 --- a/arch/arm/boot/dts/at91sam9rl.dtsi +++ b/arch/arm/boot/dts/at91sam9rl.dtsi @@ -124,7 +124,9 @@ ranges; tcb0: timer@fffa0000 { - compatible = "atmel,at91rm9200-tcb"; + compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xfffa0000 0x100>; interrupts = <16 IRQ_TYPE_LEVEL_HIGH 0>, <17 IRQ_TYPE_LEVEL_HIGH 0>, diff --git a/arch/arm/boot/dts/at91sam9rlek.dts b/arch/arm/boot/dts/at91sam9rlek.dts index ea6ed98960c9..4bde9f245e61 100644 --- a/arch/arm/boot/dts/at91sam9rlek.dts +++ b/arch/arm/boot/dts/at91sam9rlek.dts @@ -124,6 +124,18 @@ }; apb { + tcb0: timer@fffa0000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + mmc0: mmc@fffa4000 { pinctrl-0 = < &pinctrl_board_mmc0 diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index ad779a7dfefd..fee4fe51a97e 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi @@ -433,7 +433,9 @@ }; tcb0: timer@f8008000 { - compatible = "atmel,at91sam9x5-tcb"; + compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xf8008000 0x100>; interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0>; clocks = <&tcb0_clk>, <&clk32k>; @@ -441,7 +443,9 @@ }; tcb1: timer@f800c000 { - compatible = "atmel,at91sam9x5-tcb"; + compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xf800c000 0x100>; interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0>; clocks = <&tcb0_clk>, <&clk32k>; diff --git a/arch/arm/boot/dts/at91sam9x5cm.dtsi b/arch/arm/boot/dts/at91sam9x5cm.dtsi index bdeaa0b64a5b..4908ee07e628 100644 --- a/arch/arm/boot/dts/at91sam9x5cm.dtsi +++ b/arch/arm/boot/dts/at91sam9x5cm.dtsi @@ -24,6 +24,18 @@ ahb { apb { + tcb0: timer@f8008000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; + }; + pinctrl@fffff400 { 1wire_cm { pinctrl_1wire_cm: 1wire_cm-0 { diff --git a/arch/arm/boot/dts/axp81x.dtsi b/arch/arm/boot/dts/axp81x.dtsi index 73b761f850c5..fd55b896afa1 100644 --- a/arch/arm/boot/dts/axp81x.dtsi +++ b/arch/arm/boot/dts/axp81x.dtsi @@ -48,6 +48,22 @@ interrupt-controller; #interrupt-cells = <1>; + axp_gpio: axp-gpio { + compatible = "x-powers,axp813-gpio"; + gpio-controller; + #gpio-cells = <2>; + + gpio0_ldo: gpio0-ldo { + pins = "GPIO0"; + function = "ldo"; + }; + + gpio1_ldo: gpio1-ldo { + pins = "GPIO1"; + function = "ldo"; + }; + }; + regulators { /* Default work frequency for buck regulators */ x-powers,dcdc-freq = <3000>; @@ -113,11 +129,15 @@ }; reg_ldo_io0: ldo-io0 { + pinctrl-names = "default"; + pinctrl-0 = <&gpio0_ldo>; /* Disable by default to avoid conflicts with GPIO */ status = "disabled"; }; reg_ldo_io1: ldo-io1 { + pinctrl-names = "default"; + pinctrl-0 = <&gpio1_ldo>; /* Disable by default to avoid conflicts with GPIO */ status = "disabled"; }; diff --git a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts index f81ae0a10310..aa1fc7babfea 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts @@ -10,12 +10,12 @@ leds { act { - gpios = <&gpio 47 0>; + gpios = <&gpio 47 GPIO_ACTIVE_HIGH>; }; pwr { label = "PWR"; - gpios = <&gpio 35 0>; + gpios = <&gpio 35 GPIO_ACTIVE_HIGH>; default-state = "keep"; linux,default-trigger = "default-on"; }; diff --git a/arch/arm/boot/dts/bcm2835-rpi-a.dts b/arch/arm/boot/dts/bcm2835-rpi-a.dts index 7a960a048204..425f6b0a5ef8 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-a.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts @@ -10,7 +10,7 @@ leds { act { - gpios = <&gpio 16 1>; + gpios = <&gpio 16 GPIO_ACTIVE_LOW>; }; }; }; diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts index 0161a8483e39..effa195e7895 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts @@ -11,12 +11,12 @@ leds { act { - gpios = <&gpio 47 0>; + gpios = <&gpio 47 GPIO_ACTIVE_HIGH>; }; pwr { label = "PWR"; - gpios = <&gpio 35 0>; + gpios = <&gpio 35 GPIO_ACTIVE_HIGH>; default-state = "keep"; linux,default-trigger = "default-on"; }; diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts index 4bc70efe43d6..772ec3b48231 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts @@ -11,7 +11,7 @@ leds { act { - gpios = <&gpio 16 1>; + gpios = <&gpio 16 GPIO_ACTIVE_LOW>; }; }; }; diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts b/arch/arm/boot/dts/bcm2835-rpi-b.dts index cca4a75a5651..434483d6fc14 100644 --- a/arch/arm/boot/dts/bcm2835-rpi-b.dts +++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts @@ -11,7 +11,7 @@ leds { act { - gpios = <&gpio 16 1>; + gpios = <&gpio 16 GPIO_ACTIVE_LOW>; }; }; }; diff --git a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts index 6669355fd655..5c339adabdf0 100644 --- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts +++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts @@ -15,12 +15,12 @@ leds { act { - gpios = <&gpio 47 0>; + gpios = <&gpio 47 GPIO_ACTIVE_HIGH>; }; pwr { label = "PWR"; - gpios = <&gpio 35 0>; + gpios = <&gpio 35 GPIO_ACTIVE_HIGH>; default-state = "keep"; linux,default-trigger = "default-on"; }; diff --git a/arch/arm/boot/dts/bcm2836.dtsi b/arch/arm/boot/dts/bcm2836.dtsi index 61e158003509..1dfd76442777 100644 --- a/arch/arm/boot/dts/bcm2836.dtsi +++ b/arch/arm/boot/dts/bcm2836.dtsi @@ -13,24 +13,24 @@ compatible = "brcm,bcm2836-l1-intc"; reg = <0x40000000 0x100>; interrupt-controller; - #interrupt-cells = <1>; + #interrupt-cells = <2>; interrupt-parent = <&local_intc>; }; arm-pmu { compatible = "arm,cortex-a7-pmu"; interrupt-parent = <&local_intc>; - interrupts = <9>; + interrupts = <9 IRQ_TYPE_LEVEL_HIGH>; }; }; timer { compatible = "arm,armv7-timer"; interrupt-parent = <&local_intc>; - interrupts = <0>, // PHYS_SECURE_PPI - <1>, // PHYS_NONSECURE_PPI - <3>, // VIRT_PPI - <2>; // HYP_PPI + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>, // PHYS_SECURE_PPI + <1 IRQ_TYPE_LEVEL_HIGH>, // PHYS_NONSECURE_PPI + <3 IRQ_TYPE_LEVEL_HIGH>, // VIRT_PPI + <2 IRQ_TYPE_LEVEL_HIGH>; // HYP_PPI always-on; }; @@ -76,7 +76,7 @@ compatible = "brcm,bcm2836-armctrl-ic"; reg = <0x7e00b200 0x200>; interrupt-parent = <&local_intc>; - interrupts = <8>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH>; }; &cpu_thermal { diff --git a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts index a8844d033b3f..3e4ed7c5b0b3 100644 --- a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts +++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts @@ -20,7 +20,7 @@ leds { act { - gpios = <&gpio 47 0>; + gpios = <&gpio 47 GPIO_ACTIVE_HIGH>; }; }; }; diff --git a/arch/arm/boot/dts/bcm2837.dtsi b/arch/arm/boot/dts/bcm2837.dtsi index bc1cca5cf43c..efa7d3387ab2 100644 --- a/arch/arm/boot/dts/bcm2837.dtsi +++ b/arch/arm/boot/dts/bcm2837.dtsi @@ -12,7 +12,7 @@ compatible = "brcm,bcm2836-l1-intc"; reg = <0x40000000 0x100>; interrupt-controller; - #interrupt-cells = <1>; + #interrupt-cells = <2>; interrupt-parent = <&local_intc>; }; }; @@ -20,10 +20,10 @@ timer { compatible = "arm,armv7-timer"; interrupt-parent = <&local_intc>; - interrupts = <0>, // PHYS_SECURE_PPI - <1>, // PHYS_NONSECURE_PPI - <3>, // VIRT_PPI - <2>; // HYP_PPI + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>, // PHYS_SECURE_PPI + <1 IRQ_TYPE_LEVEL_HIGH>, // PHYS_NONSECURE_PPI + <3 IRQ_TYPE_LEVEL_HIGH>, // VIRT_PPI + <2 IRQ_TYPE_LEVEL_HIGH>; // HYP_PPI always-on; }; @@ -73,7 +73,7 @@ compatible = "brcm,bcm2836-armctrl-ic"; reg = <0x7e00b200 0x200>; interrupt-parent = <&local_intc>; - interrupts = <8>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH>; }; &cpu_thermal { diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi index dcde93c85c2d..18db25a5a66e 100644 --- a/arch/arm/boot/dts/bcm283x.dtsi +++ b/arch/arm/boot/dts/bcm283x.dtsi @@ -2,6 +2,7 @@ #include #include #include +#include /* firmware-provided startup stubs live here, where the secondary CPUs are * spinning. diff --git a/arch/arm/boot/dts/da850-lcdk.dts b/arch/arm/boot/dts/da850-lcdk.dts index eed89e659143..a1f4d6d5a569 100644 --- a/arch/arm/boot/dts/da850-lcdk.dts +++ b/arch/arm/boot/dts/da850-lcdk.dts @@ -293,12 +293,12 @@ label = "u-boot env"; reg = <0 0x020000>; }; - partition@0x020000 { + partition@20000 { /* The LCDK defaults to booting from this partition */ label = "u-boot"; reg = <0x020000 0x080000>; }; - partition@0x0a0000 { + partition@a0000 { label = "free space"; reg = <0x0a0000 0>; }; diff --git a/arch/arm/boot/dts/dm814x-clocks.dtsi b/arch/arm/boot/dts/dm814x-clocks.dtsi index c4671af0a28d..f80525a290bb 100644 --- a/arch/arm/boot/dts/dm814x-clocks.dtsi +++ b/arch/arm/boot/dts/dm814x-clocks.dtsi @@ -337,3 +337,33 @@ clock-frequency = <20000000>; }; }; + +&prcm { + default_cm: default_cm@500 { + compatible = "ti,omap4-cm"; + reg = <0x500 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x500 0x100>; + + default_clkctrl: clk@0 { + compatible = "ti,clkctrl"; + reg = <0x0 0x5c>; + #clock-cells = <2>; + }; + }; + + alwon_cm: alwon_cm@1400 { + compatible = "ti,omap4-cm"; + reg = <0x1400 0x300>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1400 0x300>; + + alwon_clkctrl: clk@0 { + compatible = "ti,clkctrl"; + reg = <0x0 0x228>; + #clock-cells = <2>; + }; + }; +}; diff --git a/arch/arm/boot/dts/dm814x.dtsi b/arch/arm/boot/dts/dm814x.dtsi index 681f5487406e..601c57afd4fe 100644 --- a/arch/arm/boot/dts/dm814x.dtsi +++ b/arch/arm/boot/dts/dm814x.dtsi @@ -250,6 +250,8 @@ interrupts = <67>; ti,hwmods = "timer1"; ti,timer-alwon; + clocks = <&timer1_fck>; + clock-names = "fck"; }; uart1: uart@20000 { @@ -287,6 +289,8 @@ reg = <0x40000 0x2000>; interrupts = <68>; ti,hwmods = "timer2"; + clocks = <&timer2_fck>; + clock-names = "fck"; }; timer3: timer@42000 { diff --git a/arch/arm/boot/dts/dm816x-clocks.dtsi b/arch/arm/boot/dts/dm816x-clocks.dtsi index 51865eb84a80..1efd4e23e50d 100644 --- a/arch/arm/boot/dts/dm816x-clocks.dtsi +++ b/arch/arm/boot/dts/dm816x-clocks.dtsi @@ -248,3 +248,33 @@ reg = <0x03a8>; }; }; + +&prcm { + default_cm: default_cm@500 { + compatible = "ti,omap4-cm"; + reg = <0x500 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x500 0x100>; + + default_clkctrl: clk@0 { + compatible = "ti,clkctrl"; + reg = <0x0 0x5c>; + #clock-cells = <2>; + }; + }; + + alwon_cm: alwon_cm@1400 { + compatible = "ti,omap4-cm"; + reg = <0x1400 0x300>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1400 0x300>; + + alwon_clkctrl: clk@0 { + compatible = "ti,clkctrl"; + reg = <0x0 0x208>; + #clock-cells = <2>; + }; + }; +}; diff --git a/arch/arm/boot/dts/dm816x.dtsi b/arch/arm/boot/dts/dm816x.dtsi index 566b2a8c8b96..1edc2b48b254 100644 --- a/arch/arm/boot/dts/dm816x.dtsi +++ b/arch/arm/boot/dts/dm816x.dtsi @@ -67,8 +67,11 @@ ranges; prcm: prcm@48180000 { - compatible = "ti,dm816-prcm"; + compatible = "ti,dm816-prcm", "simple-bus"; reg = <0x48180000 0x4000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x48180000 0x4000>; prcm_clocks: clocks { #address-cells = <1>; @@ -331,6 +334,8 @@ interrupts = <67>; ti,hwmods = "timer1"; ti,timer-alwon; + clocks = <&timer1_fck>; + clock-names = "fck"; }; timer2: timer@48040000 { @@ -338,6 +343,8 @@ reg = <0x48040000 0x2000>; interrupts = <68>; ti,hwmods = "timer2"; + clocks = <&timer2_fck>; + clock-names = "fck"; }; timer3: timer@48042000 { diff --git a/arch/arm/boot/dts/dra62x-j5eco-evm.dts b/arch/arm/boot/dts/dra62x-j5eco-evm.dts index 155eb32ee213..fee0547f7302 100644 --- a/arch/arm/boot/dts/dra62x-j5eco-evm.dts +++ b/arch/arm/boot/dts/dra62x-j5eco-evm.dts @@ -74,19 +74,19 @@ label = "X-Loader"; reg = <0 0x80000>; }; - partition@0x80000 { + partition@80000 { label = "U-Boot"; reg = <0x80000 0x1c0000>; }; - partition@0x1c0000 { + partition@1c0000 { label = "Environment"; reg = <0x240000 0x40000>; }; - partition@0x280000 { + partition@280000 { label = "Kernel"; reg = <0x280000 0x500000>; }; - partition@0x780000 { + partition@780000 { label = "Filesystem"; reg = <0x780000 0xf880000>; }; diff --git a/arch/arm/boot/dts/dra7-evm-common.dtsi b/arch/arm/boot/dts/dra7-evm-common.dtsi index e088bb93636a..05a7b1a01bc3 100644 --- a/arch/arm/boot/dts/dra7-evm-common.dtsi +++ b/arch/arm/boot/dts/dra7-evm-common.dtsi @@ -204,7 +204,7 @@ &atl { assigned-clocks = <&abe_dpll_sys_clk_mux>, - <&atl_gfclk_mux>, + <&atl_clkctrl DRA7_ATL_CLKCTRL 26>, <&dpll_abe_ck>, <&dpll_abe_m2x2_ck>, <&atl_clkin2_ck>; @@ -222,7 +222,7 @@ &mcasp3 { #sound-dai-cells = <0>; - assigned-clocks = <&mcasp3_ahclkx_mux>; + assigned-clocks = <&l4per_clkctrl DRA7_MCASP3_CLKCTRL 24>; assigned-clock-parents = <&atl_clkin2_ck>; status = "okay"; diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts index ef9c90daa74b..a7385c338ee9 100644 --- a/arch/arm/boot/dts/dra7-evm.dts +++ b/arch/arm/boot/dts/dra7-evm.dts @@ -361,7 +361,7 @@ }; &cpu0 { - cpu0-supply = <&smps123_reg>; + vdd-supply = <&smps123_reg>; }; &omap_dwc3_2 { diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index ac9216293b7c..e4a420f16800 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -7,8 +7,11 @@ * Based on "omap4.dtsi" */ +#include +#include #include #include +#include #define MAX_SOURCES 400 @@ -92,6 +95,8 @@ cooling-min-level = <0>; cooling-max-level = <2>; #cooling-cells = <2>; /* min followed by max */ + + vbb-supply = <&abb_mpu>; }; }; @@ -101,16 +106,26 @@ opp_nom-1000000000 { opp-hz = /bits/ 64 <1000000000>; - opp-microvolt = <1060000 850000 1150000>; + opp-microvolt = <1060000 850000 1150000>, + <1060000 850000 1150000>; opp-supported-hw = <0xFF 0x01>; opp-suspend; }; opp_od-1176000000 { opp-hz = /bits/ 64 <1176000000>; - opp-microvolt = <1160000 885000 1160000>; + opp-microvolt = <1160000 885000 1160000>, + <1160000 885000 1160000>; + opp-supported-hw = <0xFF 0x02>; }; + + opp_high@1500000000 { + opp-hz = /bits/ 64 <1500000000>; + opp-microvolt = <1210000 950000 1250000>, + <1210000 950000 1250000>; + opp-supported-hw = <0xFF 0x04>; + }; }; /* @@ -224,8 +239,12 @@ }; cm_core_aon: cm_core_aon@5000 { - compatible = "ti,dra7-cm-core-aon"; + compatible = "ti,dra7-cm-core-aon", + "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; reg = <0x5000 0x2000>; + ranges = <0 0x5000 0x2000>; cm_core_aon_clocks: clocks { #address-cells = <1>; @@ -237,8 +256,11 @@ }; cm_core: cm_core@8000 { - compatible = "ti,dra7-cm-core"; + compatible = "ti,dra7-cm-core", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; reg = <0x8000 0x3000>; + ranges = <0 0x8000 0x3000>; cm_core_clocks: clocks { #address-cells = <1>; @@ -263,9 +285,12 @@ }; prm: prm@6000 { - compatible = "ti,dra7-prm"; + compatible = "ti,dra7-prm", "simple-bus"; reg = <0x6000 0x3000>; interrupts = ; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x6000 0x3000>; prm_clocks: clocks { #address-cells = <1>; @@ -293,7 +318,6 @@ * node and enable pcie1_ep mode. */ pcie1_rc: pcie@51000000 { - compatible = "ti,dra7-pcie"; reg = <0x51000000 0x2000>, <0x51002000 0x14c>, <0x1000 0x2000>; reg-names = "rc_dbics", "ti_conf", "config"; interrupts = <0 232 0x4>, <0 233 0x4>; @@ -323,7 +347,6 @@ }; pcie1_ep: pcie_ep@51000000 { - compatible = "ti,dra7-pcie-ep"; reg = <0x51000000 0x28>, <0x51002000 0x14c>, <0x51001000 0x28>, <0x1000 0x10000000>; reg-names = "ep_dbics", "ti_conf", "ep_dbics2", "addr_space"; interrupts = <0 232 0x4>; @@ -345,8 +368,7 @@ ranges = <0x51800000 0x51800000 0x3000 0x0 0x30000000 0x10000000>; status = "disabled"; - pcie@51800000 { - compatible = "ti,dra7-pcie"; + pcie2_rc: pcie@51800000 { reg = <0x51800000 0x2000>, <0x51802000 0x14c>, <0x1000 0x2000>; reg-names = "rc_dbics", "ti_conf", "config"; interrupts = <0 355 0x4>, <0 356 0x4>; @@ -876,6 +898,8 @@ interrupts = ; ti,hwmods = "timer1"; ti,timer-alwon; + clock-names = "fck"; + clocks = <&wkupaon_clkctrl DRA7_TIMER1_CLKCTRL 24>; }; timer2: timer@48032000 { @@ -1358,7 +1382,7 @@ #address-cells = <1>; #size-cells = <0>; ti,hwmods = "qspi"; - clocks = <&qspi_gfclk_div>; + clocks = <&l4per_clkctrl DRA7_QSPI_CLKCTRL 25>; clock-names = "fck"; num-cs = <4>; interrupts = ; @@ -1373,14 +1397,15 @@ ranges; reg = <0x4a090000 0x20>; ti,hwmods = "ocp2scp3"; - sata_phy: phy@4A096000 { + sata_phy: phy@4a096000 { compatible = "ti,phy-pipe3-sata"; reg = <0x4A096000 0x80>, /* phy_rx */ <0x4A096400 0x64>, /* phy_tx */ <0x4A096800 0x40>; /* pll_ctrl */ reg-names = "phy_rx", "phy_tx", "pll_ctrl"; syscon-phy-power = <&scm_conf 0x374>; - clocks = <&sys_clkin1>, <&sata_ref_clk>; + clocks = <&sys_clkin1>, + <&l3init_clkctrl DRA7_SATA_CLKCTRL 8>; clock-names = "sysclk", "refclk"; syscon-pllreset = <&scm_conf 0x3fc>; #phy-cells = <0>; @@ -1395,9 +1420,9 @@ syscon-pcs = <&scm_conf_pcie 0x10>; clocks = <&dpll_pcie_ref_ck>, <&dpll_pcie_ref_m2ldo_ck>, - <&optfclk_pciephy1_32khz>, - <&optfclk_pciephy1_clk>, - <&optfclk_pciephy1_div_clk>, + <&l3init_clkctrl DRA7_PCIE1_CLKCTRL 8>, + <&l3init_clkctrl DRA7_PCIE1_CLKCTRL 9>, + <&l3init_clkctrl DRA7_PCIE1_CLKCTRL 10>, <&optfclk_pciephy_div>, <&sys_clkin1>; clock-names = "dpll_ref", "dpll_ref_m2", @@ -1415,9 +1440,9 @@ syscon-pcs = <&scm_conf_pcie 0x10>; clocks = <&dpll_pcie_ref_ck>, <&dpll_pcie_ref_m2ldo_ck>, - <&optfclk_pciephy2_32khz>, - <&optfclk_pciephy2_clk>, - <&optfclk_pciephy2_div_clk>, + <&l3init_clkctrl DRA7_PCIE2_CLKCTRL 8>, + <&l3init_clkctrl DRA7_PCIE2_CLKCTRL 9>, + <&l3init_clkctrl DRA7_PCIE2_CLKCTRL 10>, <&optfclk_pciephy_div>, <&sys_clkin1>; clock-names = "dpll_ref", "dpll_ref_m2", @@ -1434,7 +1459,7 @@ interrupts = ; phys = <&sata_phy>; phy-names = "sata-phy"; - clocks = <&sata_ref_clk>; + clocks = <&l3init_clkctrl DRA7_SATA_CLKCTRL 8>; ti,hwmods = "sata"; ports-implemented = <0x1>; }; @@ -1462,7 +1487,7 @@ reg = <0x4a084000 0x400>; syscon-phy-power = <&scm_conf 0x300>; clocks = <&usb_phy1_always_on_clk32k>, - <&usb_otg_ss1_refclk960m>; + <&l3init_clkctrl DRA7_USB_OTG_SS1_CLKCTRL 8>; clock-names = "wkupclk", "refclk"; #phy-cells = <0>; @@ -1474,7 +1499,7 @@ reg = <0x4a085000 0x400>; syscon-phy-power = <&scm_conf 0xe74>; clocks = <&usb_phy2_always_on_clk32k>, - <&usb_otg_ss2_refclk960m>; + <&l3init_clkctrl DRA7_USB_OTG_SS2_CLKCTRL 8>; clock-names = "wkupclk", "refclk"; #phy-cells = <0>; @@ -1489,7 +1514,7 @@ syscon-phy-power = <&scm_conf 0x370>; clocks = <&usb_phy3_always_on_clk32k>, <&sys_clkin1>, - <&usb_otg_ss1_refclk960m>; + <&l3init_clkctrl DRA7_USB_OTG_SS1_CLKCTRL 8>; clock-names = "wkupclk", "sysclk", "refclk"; @@ -1498,11 +1523,17 @@ }; target-module@4a0dd000 { - compatible = "ti,sysc-omap4-sr"; + compatible = "ti,sysc-omap4-sr", "ti,sysc"; ti,hwmods = "smartreflex_core"; - reg = <0x4a0dd000 0x4>, - <0x4a0dd008 0x4>; - reg-names = "rev", "sysc"; + reg = <0x4a0dd038 0x4>; + reg-names = "sysc"; + ti,sysc-mask = ; + ti,sysc-sidle = , + , + , + ; + clocks = <&coreaon_clkctrl DRA7_SMARTREFLEX_CORE_CLKCTRL 0>; + clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x4a0dd000 0x001000>; @@ -1511,11 +1542,17 @@ }; target-module@4a0d9000 { - compatible = "ti,sysc-omap4-sr"; + compatible = "ti,sysc-omap4-sr", "ti,sysc"; ti,hwmods = "smartreflex_mpu"; - reg = <0x4a0d9000 0x4>, - <0x4a0d9008 0x4>; - reg-names = "rev", "sysc"; + reg = <0x4a0d9038 0x4>; + reg-names = "sysc"; + ti,sysc-mask = ; + ti,sysc-sidle = , + , + , + ; + clocks = <&coreaon_clkctrl DRA7_SMARTREFLEX_MPU_CLKCTRL 0>; + clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x4a0d9000 0x001000>; @@ -1547,6 +1584,7 @@ dr_mode = "otg"; snps,dis_u3_susphy_quirk; snps,dis_u2_susphy_quirk; + snps,dis_metastability_quirk; }; }; @@ -1636,7 +1674,7 @@ ti,hwmods = "atl"; ti,provided-clocks = <&atl_clkin0_ck>, <&atl_clkin1_ck>, <&atl_clkin2_ck>, <&atl_clkin3_ck>; - clocks = <&atl_gfclk_mux>; + clocks = <&atl_clkctrl DRA7_ATL_CLKCTRL 26>; clock-names = "fck"; status = "disabled"; }; @@ -1652,8 +1690,8 @@ interrupt-names = "tx", "rx"; dmas = <&edma_xbar 129 1>, <&edma_xbar 128 1>; dma-names = "tx", "rx"; - clocks = <&mcasp1_aux_gfclk_mux>, <&mcasp1_ahclkx_mux>, - <&mcasp1_ahclkr_mux>; + clocks = <&ipu_clkctrl DRA7_MCASP1_CLKCTRL 22>, <&ipu_clkctrl DRA7_MCASP1_CLKCTRL 24>, + <&ipu_clkctrl DRA7_MCASP1_CLKCTRL 28>; clock-names = "fck", "ahclkx", "ahclkr"; status = "disabled"; }; @@ -1669,8 +1707,9 @@ interrupt-names = "tx", "rx"; dmas = <&edma_xbar 131 1>, <&edma_xbar 130 1>; dma-names = "tx", "rx"; - clocks = <&mcasp2_aux_gfclk_mux>, <&mcasp2_ahclkx_mux>, - <&mcasp2_ahclkr_mux>; + clocks = <&l4per_clkctrl DRA7_MCASP2_CLKCTRL 22>, + <&l4per_clkctrl DRA7_MCASP2_CLKCTRL 24>, + <&l4per_clkctrl DRA7_MCASP2_CLKCTRL 28>; clock-names = "fck", "ahclkx", "ahclkr"; status = "disabled"; }; @@ -1686,7 +1725,8 @@ interrupt-names = "tx", "rx"; dmas = <&edma_xbar 133 1>, <&edma_xbar 132 1>; dma-names = "tx", "rx"; - clocks = <&mcasp3_aux_gfclk_mux>, <&mcasp3_ahclkx_mux>; + clocks = <&l4per_clkctrl DRA7_MCASP3_CLKCTRL 22>, + <&l4per_clkctrl DRA7_MCASP3_CLKCTRL 24>; clock-names = "fck", "ahclkx"; status = "disabled"; }; @@ -1702,7 +1742,8 @@ interrupt-names = "tx", "rx"; dmas = <&edma_xbar 135 1>, <&edma_xbar 134 1>; dma-names = "tx", "rx"; - clocks = <&mcasp4_aux_gfclk_mux>, <&mcasp4_ahclkx_mux>; + clocks = <&l4per_clkctrl DRA7_MCASP4_CLKCTRL 22>, + <&l4per_clkctrl DRA7_MCASP4_CLKCTRL 24>; clock-names = "fck", "ahclkx"; status = "disabled"; }; @@ -1718,7 +1759,8 @@ interrupt-names = "tx", "rx"; dmas = <&edma_xbar 137 1>, <&edma_xbar 136 1>; dma-names = "tx", "rx"; - clocks = <&mcasp5_aux_gfclk_mux>, <&mcasp5_ahclkx_mux>; + clocks = <&l4per_clkctrl DRA7_MCASP5_CLKCTRL 22>, + <&l4per_clkctrl DRA7_MCASP5_CLKCTRL 24>; clock-names = "fck", "ahclkx"; status = "disabled"; }; @@ -1734,7 +1776,8 @@ interrupt-names = "tx", "rx"; dmas = <&edma_xbar 139 1>, <&edma_xbar 138 1>; dma-names = "tx", "rx"; - clocks = <&mcasp6_aux_gfclk_mux>, <&mcasp6_ahclkx_mux>; + clocks = <&l4per_clkctrl DRA7_MCASP6_CLKCTRL 22>, + <&l4per_clkctrl DRA7_MCASP6_CLKCTRL 24>; clock-names = "fck", "ahclkx"; status = "disabled"; }; @@ -1750,7 +1793,8 @@ interrupt-names = "tx", "rx"; dmas = <&edma_xbar 141 1>, <&edma_xbar 140 1>; dma-names = "tx", "rx"; - clocks = <&mcasp7_aux_gfclk_mux>, <&mcasp7_ahclkx_mux>; + clocks = <&l4per_clkctrl DRA7_MCASP7_CLKCTRL 22>, + <&l4per_clkctrl DRA7_MCASP7_CLKCTRL 24>; clock-names = "fck", "ahclkx"; status = "disabled"; }; @@ -1766,7 +1810,8 @@ interrupt-names = "tx", "rx"; dmas = <&edma_xbar 143 1>, <&edma_xbar 142 1>; dma-names = "tx", "rx"; - clocks = <&mcasp8_aux_gfclk_mux>, <&mcasp8_ahclkx_mux>; + clocks = <&l4per_clkctrl DRA7_MCASP8_CLKCTRL 22>, + <&l4per_clkctrl DRA7_MCASP8_CLKCTRL 24>; clock-names = "fck", "ahclkx"; status = "disabled"; }; @@ -1788,7 +1833,7 @@ mac: ethernet@48484000 { compatible = "ti,dra7-cpsw","ti,cpsw"; ti,hwmods = "gmac"; - clocks = <&gmac_main_clk>, <&gmac_rft_clk_mux>; + clocks = <&gmac_main_clk>, <&l3init_clkctrl DRA7_GMAC_CLKCTRL 25>; clock-names = "fck", "cpts"; cpdma_channels = <8>; ale_entries = <1024>; @@ -1858,7 +1903,7 @@ reg = <0x4ae3c000 0x2000>; syscon-raminit = <&scm_conf 0x558 0>; interrupts = ; - clocks = <&dcan1_sys_clk_mux>; + clocks = <&wkupaon_clkctrl DRA7_DCAN1_CLKCTRL 24>; status = "disabled"; }; @@ -1889,7 +1934,7 @@ reg = <0x58001000 0x1000>; interrupts = ; ti,hwmods = "dss_dispc"; - clocks = <&dss_dss_clk>; + clocks = <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 8>; clock-names = "fck"; /* CTRL_CORE_SMA_SW_1 */ syscon-pol = <&scm_conf 0x534>; @@ -1905,8 +1950,11 @@ interrupts = ; status = "disabled"; ti,hwmods = "dss_hdmi"; - clocks = <&dss_48mhz_clk>, <&dss_hdmi_clk>; + clocks = <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 9>, + <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 10>; clock-names = "fck", "sys_clk"; + dmas = <&sdma_xbar 76>; + dma-names = "audio_tx"; }; }; @@ -2052,6 +2100,19 @@ clocks = <&l3_iclk_div>; clock-names = "fck"; }; + + opp_supply_mpu: opp-supply@4a003b20 { + compatible = "ti,omap5-opp-supply"; + reg = <0x4a003b20 0xc>; + ti,efuse-settings = < + /* uV offset */ + 1060000 0x0 + 1160000 0x4 + 1210000 0x8 + >; + ti,absolute-max-voltage-uv = <1500000>; + }; + }; thermal_zones: thermal-zones { @@ -2089,4 +2150,20 @@ temperature = <120000>; /* milli Celsius */ }; -/include/ "dra7xx-clocks.dtsi" +#include "dra7xx-clocks.dtsi" + +&core_crit { + temperature = <120000>; /* milli Celsius */ +}; + +&gpu_crit { + temperature = <120000>; /* milli Celsius */ +}; + +&dspeve_crit { + temperature = <120000>; /* milli Celsius */ +}; + +&iva_crit { + temperature = <120000>; /* milli Celsius */ +}; diff --git a/arch/arm/boot/dts/dra72-evm-common.dtsi b/arch/arm/boot/dts/dra72-evm-common.dtsi index 2e485a13dfd7..e85f560a2f78 100644 --- a/arch/arm/boot/dts/dra72-evm-common.dtsi +++ b/arch/arm/boot/dts/dra72-evm-common.dtsi @@ -514,7 +514,7 @@ &atl { assigned-clocks = <&abe_dpll_sys_clk_mux>, - <&atl_gfclk_mux>, + <&atl_clkctrl DRA7_ATL_CLKCTRL 26>, <&dpll_abe_ck>, <&dpll_abe_m2x2_ck>, <&atl_clkin2_ck>; @@ -532,7 +532,7 @@ &mcasp3 { #sound-dai-cells = <0>; - assigned-clocks = <&mcasp3_ahclkx_mux>; + assigned-clocks = <&l4per_clkctrl DRA7_MCASP3_CLKCTRL 24>; assigned-clock-parents = <&atl_clkin2_ck>; status = "okay"; diff --git a/arch/arm/boot/dts/dra72-evm-tps65917.dtsi b/arch/arm/boot/dts/dra72-evm-tps65917.dtsi index 57bfe5caf5e4..47bb90f41f3f 100644 --- a/arch/arm/boot/dts/dra72-evm-tps65917.dtsi +++ b/arch/arm/boot/dts/dra72-evm-tps65917.dtsi @@ -148,3 +148,7 @@ &mmc1 { vqmmc-supply = <&ldo1_reg>; }; + +&cpu0 { + vdd-supply = <&smps1_reg>; +}; diff --git a/arch/arm/boot/dts/dra72x.dtsi b/arch/arm/boot/dts/dra72x.dtsi index 67107605fb4c..c011d2e64fef 100644 --- a/arch/arm/boot/dts/dra72x.dtsi +++ b/arch/arm/boot/dts/dra72x.dtsi @@ -25,8 +25,8 @@ <0x58004300 0x20>; reg-names = "dss", "pll1_clkctrl", "pll1"; - clocks = <&dss_dss_clk>, - <&dss_video1_clk>; + clocks = <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 8>, + <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 12>; clock-names = "fck", "video1_clk"; }; @@ -50,3 +50,15 @@ status = "disabled"; }; }; + +&pcie1_rc { + compatible = "ti,dra726-pcie-rc", "ti,dra7-pcie"; +}; + +&pcie1_ep { + compatible = "ti,dra726-pcie-ep", "ti,dra7-pcie-ep"; +}; + +&pcie2_rc { + compatible = "ti,dra726-pcie-rc", "ti,dra7-pcie"; +}; diff --git a/arch/arm/boot/dts/dra74x.dtsi b/arch/arm/boot/dts/dra74x.dtsi index 24e6746c5b26..91e93ab588ca 100644 --- a/arch/arm/boot/dts/dra74x.dtsi +++ b/arch/arm/boot/dts/dra74x.dtsi @@ -93,9 +93,9 @@ reg-names = "dss", "pll1_clkctrl", "pll1", "pll2_clkctrl", "pll2"; - clocks = <&dss_dss_clk>, - <&dss_video1_clk>, - <&dss_video2_clk>; + clocks = <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 8>, + <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 12>, + <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 13>; clock-names = "fck", "video1_clk", "video2_clk"; }; @@ -124,3 +124,15 @@ status = "disabled"; }; }; + +&pcie1_rc { + compatible = "ti,dra746-pcie-rc", "ti,dra7-pcie"; +}; + +&pcie1_ep { + compatible = "ti,dra746-pcie-ep", "ti,dra7-pcie-ep"; +}; + +&pcie2_rc { + compatible = "ti,dra746-pcie-rc", "ti,dra7-pcie"; +}; diff --git a/arch/arm/boot/dts/dra76-evm.dts b/arch/arm/boot/dts/dra76-evm.dts index b024a65c6e27..c4fe7f8ef72a 100644 --- a/arch/arm/boot/dts/dra76-evm.dts +++ b/arch/arm/boot/dts/dra76-evm.dts @@ -148,6 +148,7 @@ compatible = "ti,tps65917"; reg = <0x58>; ti,system-power-controller; + ti,palmas-override-powerhold; interrupt-controller; #interrupt-cells = <2>; @@ -421,3 +422,19 @@ spi-max-frequency = <96000000>; }; }; + +&pcie2_phy { + status = "okay"; +}; + +&pcie1_rc { + num-lanes = <2>; + phys = <&pcie1_phy>, <&pcie2_phy>; + phy-names = "pcie-phy0", "pcie-phy1"; +}; + +&pcie1_ep { + num-lanes = <2>; + phys = <&pcie1_phy>, <&pcie2_phy>; + phy-names = "pcie-phy0", "pcie-phy1"; +}; diff --git a/arch/arm/boot/dts/dra7xx-clocks.dtsi b/arch/arm/boot/dts/dra7xx-clocks.dtsi index e62b62875cba..69562cdbeada 100644 --- a/arch/arm/boot/dts/dra7xx-clocks.dtsi +++ b/arch/arm/boot/dts/dra7xx-clocks.dtsi @@ -11,25 +11,25 @@ atl_clkin0_ck: atl_clkin0_ck { #clock-cells = <0>; compatible = "ti,dra7-atl-clock"; - clocks = <&atl_gfclk_mux>; + clocks = <&atl_clkctrl DRA7_ATL_CLKCTRL 26>; }; atl_clkin1_ck: atl_clkin1_ck { #clock-cells = <0>; compatible = "ti,dra7-atl-clock"; - clocks = <&atl_gfclk_mux>; + clocks = <&atl_clkctrl DRA7_ATL_CLKCTRL 26>; }; atl_clkin2_ck: atl_clkin2_ck { #clock-cells = <0>; compatible = "ti,dra7-atl-clock"; - clocks = <&atl_gfclk_mux>; + clocks = <&atl_clkctrl DRA7_ATL_CLKCTRL 26>; }; atl_clkin3_ck: atl_clkin3_ck { #clock-cells = <0>; compatible = "ti,dra7-atl-clock"; - clocks = <&atl_gfclk_mux>; + clocks = <&atl_clkctrl DRA7_ATL_CLKCTRL 26>; }; hdmi_clkin_ck: hdmi_clkin_ck { @@ -809,70 +809,6 @@ assigned-clock-parents = <&dpll_core_h22x2_ck>; }; - mcasp1_ahclkr_mux: mcasp1_ahclkr_mux@550 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; - ti,bit-shift = <28>; - reg = <0x0550>; - }; - - mcasp1_ahclkx_mux: mcasp1_ahclkx_mux@550 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; - ti,bit-shift = <24>; - reg = <0x0550>; - }; - - mcasp1_aux_gfclk_mux: mcasp1_aux_gfclk_mux@550 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; - ti,bit-shift = <22>; - reg = <0x0550>; - }; - - timer5_gfclk_mux: timer5_gfclk_mux@558 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>, <&clkoutmux0_clk_mux>; - ti,bit-shift = <24>; - reg = <0x0558>; - }; - - timer6_gfclk_mux: timer6_gfclk_mux@560 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>, <&clkoutmux0_clk_mux>; - ti,bit-shift = <24>; - reg = <0x0560>; - }; - - timer7_gfclk_mux: timer7_gfclk_mux@568 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>, <&clkoutmux0_clk_mux>; - ti,bit-shift = <24>; - reg = <0x0568>; - }; - - timer8_gfclk_mux: timer8_gfclk_mux@570 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>, <&clkoutmux0_clk_mux>; - ti,bit-shift = <24>; - reg = <0x0570>; - }; - - uart6_gfclk_mux: uart6_gfclk_mux@580 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; - ti,bit-shift = <24>; - reg = <0x0580>; - }; - dummy_ck: dummy_ck { #clock-cells = <0>; compatible = "fixed-clock"; @@ -1188,39 +1124,8 @@ clocks = <&sys_clkin1>, <&abe_lp_clk_div>; reg = <0x0108>; }; - - gpio1_dbclk: gpio1_dbclk@1838 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1838>; - }; - - dcan1_sys_clk_mux: dcan1_sys_clk_mux@1888 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin1>, <&sys_clkin2>; - ti,bit-shift = <24>; - reg = <0x1888>; - }; - - timer1_gfclk_mux: timer1_gfclk_mux@1840 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; - ti,bit-shift = <24>; - reg = <0x1840>; - }; - - uart10_gfclk_mux: uart10_gfclk_mux@1880 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; - ti,bit-shift = <24>; - reg = <0x1880>; - }; }; + &cm_core_clocks { dpll_pcie_ref_ck: dpll_pcie_ref_ck@200 { #clock-cells = <0>; @@ -1255,22 +1160,6 @@ reg = <0x021c>, <0x0220>; }; - optfclk_pciephy1_32khz: optfclk_pciephy1_32khz@4a0093b0 { - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - #clock-cells = <0>; - reg = <0x13b0>; - ti,bit-shift = <8>; - }; - - optfclk_pciephy2_32khz: optfclk_pciephy2_32khz@4a0093b8 { - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - #clock-cells = <0>; - reg = <0x13b8>; - ti,bit-shift = <8>; - }; - optfclk_pciephy_div: optfclk_pciephy_div@4a00821c { compatible = "ti,divider-clock"; clocks = <&apll_pcie_ck>; @@ -1281,38 +1170,6 @@ ti,max-div = <2>; }; - optfclk_pciephy1_clk: optfclk_pciephy1_clk@4a0093b0 { - compatible = "ti,gate-clock"; - clocks = <&apll_pcie_ck>; - #clock-cells = <0>; - reg = <0x13b0>; - ti,bit-shift = <9>; - }; - - optfclk_pciephy2_clk: optfclk_pciephy2_clk@4a0093b8 { - compatible = "ti,gate-clock"; - clocks = <&apll_pcie_ck>; - #clock-cells = <0>; - reg = <0x13b8>; - ti,bit-shift = <9>; - }; - - optfclk_pciephy1_div_clk: optfclk_pciephy1_div_clk@4a0093b0 { - compatible = "ti,gate-clock"; - clocks = <&optfclk_pciephy_div>; - #clock-cells = <0>; - reg = <0x13b0>; - ti,bit-shift = <10>; - }; - - optfclk_pciephy2_div_clk: optfclk_pciephy2_div_clk@4a0093b8 { - compatible = "ti,gate-clock"; - clocks = <&optfclk_pciephy_div>; - #clock-cells = <0>; - reg = <0x13b8>; - ti,bit-shift = <10>; - }; - apll_pcie_clkvcoldo: apll_pcie_clkvcoldo { #clock-cells = <0>; compatible = "fixed-factor-clock"; @@ -1541,167 +1398,6 @@ reg = <0x06c0>; }; - dss_32khz_clk: dss_32khz_clk@1120 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <11>; - reg = <0x1120>; - }; - - dss_48mhz_clk: dss_48mhz_clk@1120 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&func_48m_fclk>; - ti,bit-shift = <9>; - reg = <0x1120>; - }; - - dss_dss_clk: dss_dss_clk@1120 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&dpll_per_h12x2_ck>; - ti,bit-shift = <8>; - reg = <0x1120>; - ti,set-rate-parent; - }; - - dss_hdmi_clk: dss_hdmi_clk@1120 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&hdmi_dpll_clk_mux>; - ti,bit-shift = <10>; - reg = <0x1120>; - }; - - dss_video1_clk: dss_video1_clk@1120 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&video1_dpll_clk_mux>; - ti,bit-shift = <12>; - reg = <0x1120>; - }; - - dss_video2_clk: dss_video2_clk@1120 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&video2_dpll_clk_mux>; - ti,bit-shift = <13>; - reg = <0x1120>; - }; - - gpio2_dbclk: gpio2_dbclk@1760 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1760>; - }; - - gpio3_dbclk: gpio3_dbclk@1768 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1768>; - }; - - gpio4_dbclk: gpio4_dbclk@1770 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1770>; - }; - - gpio5_dbclk: gpio5_dbclk@1778 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1778>; - }; - - gpio6_dbclk: gpio6_dbclk@1780 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1780>; - }; - - gpio7_dbclk: gpio7_dbclk@1810 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1810>; - }; - - gpio8_dbclk: gpio8_dbclk@1818 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1818>; - }; - - mmc1_clk32k: mmc1_clk32k@1328 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1328>; - }; - - mmc2_clk32k: mmc2_clk32k@1330 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1330>; - }; - - mmc3_clk32k: mmc3_clk32k@1820 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1820>; - }; - - mmc4_clk32k: mmc4_clk32k@1828 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1828>; - }; - - sata_ref_clk: sata_ref_clk@1388 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_clkin1>; - ti,bit-shift = <8>; - reg = <0x1388>; - }; - - usb_otg_ss1_refclk960m: usb_otg_ss1_refclk960m@13f0 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&l3init_960m_gfclk>; - ti,bit-shift = <8>; - reg = <0x13f0>; - }; - - usb_otg_ss2_refclk960m: usb_otg_ss2_refclk960m@1340 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&l3init_960m_gfclk>; - ti,bit-shift = <8>; - reg = <0x1340>; - }; - usb_phy1_always_on_clk32k: usb_phy1_always_on_clk32k@640 { #clock-cells = <0>; compatible = "ti,gate-clock"; @@ -1726,38 +1422,6 @@ reg = <0x0698>; }; - atl_dpll_clk_mux: atl_dpll_clk_mux@c00 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_32k_ck>, <&video1_clkin_ck>, <&video2_clkin_ck>, <&hdmi_clkin_ck>; - ti,bit-shift = <24>; - reg = <0x0c00>; - }; - - atl_gfclk_mux: atl_gfclk_mux@c00 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&l3_iclk_div>, <&dpll_abe_m2_ck>, <&atl_dpll_clk_mux>; - ti,bit-shift = <26>; - reg = <0x0c00>; - }; - - rmii_50mhz_clk_mux: rmii_50mhz_clk_mux@13d0 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&dpll_gmac_h11x2_ck>, <&rmii_clk_ck>; - ti,bit-shift = <24>; - reg = <0x13d0>; - }; - - gmac_rft_clk_mux: gmac_rft_clk_mux@13d0 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&video1_clkin_ck>, <&video2_clkin_ck>, <&dpll_abe_m2_ck>, <&hdmi_clkin_ck>, <&l3_iclk_div>; - ti,bit-shift = <25>; - reg = <0x13d0>; - }; - gpu_core_gclk_mux: gpu_core_gclk_mux@1220 { #clock-cells = <0>; compatible = "ti,mux-clock"; @@ -1787,362 +1451,6 @@ ti,dividers = <8>, <16>, <32>; }; - mcasp2_ahclkr_mux: mcasp2_ahclkr_mux@1860 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; - ti,bit-shift = <28>; - reg = <0x1860>; - }; - - mcasp2_ahclkx_mux: mcasp2_ahclkx_mux@1860 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; - ti,bit-shift = <24>; - reg = <0x1860>; - }; - - mcasp2_aux_gfclk_mux: mcasp2_aux_gfclk_mux@1860 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; - ti,bit-shift = <22>; - reg = <0x1860>; - }; - - mcasp3_ahclkx_mux: mcasp3_ahclkx_mux@1868 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; - ti,bit-shift = <24>; - reg = <0x1868>; - assigned-clocks = <&mcasp3_ahclkx_mux>; - assigned-clock-parents = <&abe_24m_fclk>; - }; - - mcasp3_aux_gfclk_mux: mcasp3_aux_gfclk_mux@1868 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; - ti,bit-shift = <22>; - reg = <0x1868>; - }; - - mcasp4_ahclkx_mux: mcasp4_ahclkx_mux@1898 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; - ti,bit-shift = <24>; - reg = <0x1898>; - }; - - mcasp4_aux_gfclk_mux: mcasp4_aux_gfclk_mux@1898 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; - ti,bit-shift = <22>; - reg = <0x1898>; - }; - - mcasp5_ahclkx_mux: mcasp5_ahclkx_mux@1878 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; - ti,bit-shift = <24>; - reg = <0x1878>; - }; - - mcasp5_aux_gfclk_mux: mcasp5_aux_gfclk_mux@1878 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; - ti,bit-shift = <22>; - reg = <0x1878>; - }; - - mcasp6_ahclkx_mux: mcasp6_ahclkx_mux@1904 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; - ti,bit-shift = <24>; - reg = <0x1904>; - }; - - mcasp6_aux_gfclk_mux: mcasp6_aux_gfclk_mux@1904 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; - ti,bit-shift = <22>; - reg = <0x1904>; - }; - - mcasp7_ahclkx_mux: mcasp7_ahclkx_mux@1908 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; - ti,bit-shift = <24>; - reg = <0x1908>; - }; - - mcasp7_aux_gfclk_mux: mcasp7_aux_gfclk_mux@1908 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; - ti,bit-shift = <22>; - reg = <0x1908>; - }; - - mcasp8_ahclkx_mux: mcasp8_ahclkx_mux@1890 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atl_clkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>; - ti,bit-shift = <22>; - reg = <0x1890>; - }; - - mcasp8_aux_gfclk_mux: mcasp8_aux_gfclk_mux@1890 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>; - ti,bit-shift = <24>; - reg = <0x1890>; - }; - - mmc1_fclk_mux: mmc1_fclk_mux@1328 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_128m_clk>, <&dpll_per_m2x2_ck>; - ti,bit-shift = <24>; - reg = <0x1328>; - }; - - mmc1_fclk_div: mmc1_fclk_div@1328 { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&mmc1_fclk_mux>; - ti,bit-shift = <25>; - ti,max-div = <4>; - reg = <0x1328>; - ti,index-power-of-two; - }; - - mmc2_fclk_mux: mmc2_fclk_mux@1330 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_128m_clk>, <&dpll_per_m2x2_ck>; - ti,bit-shift = <24>; - reg = <0x1330>; - }; - - mmc2_fclk_div: mmc2_fclk_div@1330 { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&mmc2_fclk_mux>; - ti,bit-shift = <25>; - ti,max-div = <4>; - reg = <0x1330>; - ti,index-power-of-two; - }; - - mmc3_gfclk_mux: mmc3_gfclk_mux@1820 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; - ti,bit-shift = <24>; - reg = <0x1820>; - }; - - mmc3_gfclk_div: mmc3_gfclk_div@1820 { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&mmc3_gfclk_mux>; - ti,bit-shift = <25>; - ti,max-div = <4>; - reg = <0x1820>; - ti,index-power-of-two; - }; - - mmc4_gfclk_mux: mmc4_gfclk_mux@1828 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; - ti,bit-shift = <24>; - reg = <0x1828>; - }; - - mmc4_gfclk_div: mmc4_gfclk_div@1828 { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&mmc4_gfclk_mux>; - ti,bit-shift = <25>; - ti,max-div = <4>; - reg = <0x1828>; - ti,index-power-of-two; - }; - - qspi_gfclk_mux: qspi_gfclk_mux@1838 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_128m_clk>, <&dpll_per_h13x2_ck>; - ti,bit-shift = <24>; - reg = <0x1838>; - }; - - qspi_gfclk_div: qspi_gfclk_div@1838 { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&qspi_gfclk_mux>; - ti,bit-shift = <25>; - ti,max-div = <4>; - reg = <0x1838>; - ti,index-power-of-two; - }; - - timer10_gfclk_mux: timer10_gfclk_mux@1728 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; - ti,bit-shift = <24>; - reg = <0x1728>; - }; - - timer11_gfclk_mux: timer11_gfclk_mux@1730 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; - ti,bit-shift = <24>; - reg = <0x1730>; - }; - - timer13_gfclk_mux: timer13_gfclk_mux@17c8 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; - ti,bit-shift = <24>; - reg = <0x17c8>; - }; - - timer14_gfclk_mux: timer14_gfclk_mux@17d0 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; - ti,bit-shift = <24>; - reg = <0x17d0>; - }; - - timer15_gfclk_mux: timer15_gfclk_mux@17d8 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; - ti,bit-shift = <24>; - reg = <0x17d8>; - }; - - timer16_gfclk_mux: timer16_gfclk_mux@1830 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; - ti,bit-shift = <24>; - reg = <0x1830>; - }; - - timer2_gfclk_mux: timer2_gfclk_mux@1738 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; - ti,bit-shift = <24>; - reg = <0x1738>; - }; - - timer3_gfclk_mux: timer3_gfclk_mux@1740 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; - ti,bit-shift = <24>; - reg = <0x1740>; - }; - - timer4_gfclk_mux: timer4_gfclk_mux@1748 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; - ti,bit-shift = <24>; - reg = <0x1748>; - }; - - timer9_gfclk_mux: timer9_gfclk_mux@1750 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>; - ti,bit-shift = <24>; - reg = <0x1750>; - }; - - uart1_gfclk_mux: uart1_gfclk_mux@1840 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; - ti,bit-shift = <24>; - reg = <0x1840>; - }; - - uart2_gfclk_mux: uart2_gfclk_mux@1848 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; - ti,bit-shift = <24>; - reg = <0x1848>; - }; - - uart3_gfclk_mux: uart3_gfclk_mux@1850 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; - ti,bit-shift = <24>; - reg = <0x1850>; - }; - - uart4_gfclk_mux: uart4_gfclk_mux@1858 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; - ti,bit-shift = <24>; - reg = <0x1858>; - }; - - uart5_gfclk_mux: uart5_gfclk_mux@1870 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; - ti,bit-shift = <24>; - reg = <0x1870>; - }; - - uart7_gfclk_mux: uart7_gfclk_mux@18d0 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; - ti,bit-shift = <24>; - reg = <0x18d0>; - }; - - uart8_gfclk_mux: uart8_gfclk_mux@18e0 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; - ti,bit-shift = <24>; - reg = <0x18e0>; - }; - - uart9_gfclk_mux: uart9_gfclk_mux@18e8 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>; - ti,bit-shift = <24>; - reg = <0x18e8>; - }; - vip1_gclk_mux: vip1_gclk_mux@1020 { #clock-cells = <0>; compatible = "ti,mux-clock"; @@ -2216,3 +1524,210 @@ reg = <0x6c4>; }; }; + +&cm_core_aon { + mpu_cm: mpu_cm@300 { + compatible = "ti,omap4-cm"; + reg = <0x300 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x300 0x100>; + + mpu_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + ipu_cm: ipu_cm@500 { + compatible = "ti,omap4-cm"; + reg = <0x500 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x500 0x100>; + + ipu_clkctrl: clk@40 { + compatible = "ti,clkctrl"; + reg = <0x40 0x44>; + #clock-cells = <2>; + }; + }; + + rtc_cm: rtc_cm@700 { + compatible = "ti,omap4-cm"; + reg = <0x700 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x700 0x100>; + + rtc_clkctrl: clk@40 { + compatible = "ti,clkctrl"; + reg = <0x40 0x8>; + #clock-cells = <2>; + }; + }; + +}; + +&cm_core { + coreaon_cm: coreaon_cm@600 { + compatible = "ti,omap4-cm"; + reg = <0x600 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x600 0x100>; + + coreaon_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x1c>; + #clock-cells = <2>; + }; + }; + + l3main1_cm: l3main1_cm@700 { + compatible = "ti,omap4-cm"; + reg = <0x700 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x700 0x100>; + + l3main1_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x74>; + #clock-cells = <2>; + }; + }; + + dma_cm: dma_cm@a00 { + compatible = "ti,omap4-cm"; + reg = <0xa00 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xa00 0x100>; + + dma_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + emif_cm: emif_cm@b00 { + compatible = "ti,omap4-cm"; + reg = <0xb00 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xb00 0x100>; + + emif_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + atl_cm: atl_cm@c00 { + compatible = "ti,omap4-cm"; + reg = <0xc00 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xc00 0x100>; + + atl_clkctrl: clk@0 { + compatible = "ti,clkctrl"; + reg = <0x0 0x4>; + #clock-cells = <2>; + }; + }; + + l4cfg_cm: l4cfg_cm@d00 { + compatible = "ti,omap4-cm"; + reg = <0xd00 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xd00 0x100>; + + l4cfg_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x84>; + #clock-cells = <2>; + }; + }; + + l3instr_cm: l3instr_cm@e00 { + compatible = "ti,omap4-cm"; + reg = <0xe00 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xe00 0x100>; + + l3instr_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0xc>; + #clock-cells = <2>; + }; + }; + + dss_cm: dss_cm@1100 { + compatible = "ti,omap4-cm"; + reg = <0x1100 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1100 0x100>; + + dss_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x14>; + #clock-cells = <2>; + }; + }; + + l3init_cm: l3init_cm@1300 { + compatible = "ti,omap4-cm"; + reg = <0x1300 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1300 0x100>; + + l3init_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0xd4>; + #clock-cells = <2>; + }; + }; + + l4per_cm: l4per_cm@1700 { + compatible = "ti,omap4-cm"; + reg = <0x1700 0x300>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1700 0x300>; + + l4per_clkctrl: clk@0 { + compatible = "ti,clkctrl"; + reg = <0x0 0x20c>; + #clock-cells = <2>; + + assigned-clocks = <&l4per_clkctrl DRA7_MCASP3_CLKCTRL 24>; + assigned-clock-parents = <&abe_24m_fclk>; + }; + }; + +}; + +&prm { + wkupaon_cm: wkupaon_cm@1800 { + compatible = "ti,omap4-cm"; + reg = <0x1800 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1800 0x100>; + + wkupaon_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x6c>; + #clock-cells = <2>; + }; + }; +}; diff --git a/arch/arm/boot/dts/efm32gg-dk3750.dts b/arch/arm/boot/dts/efm32gg-dk3750.dts index c9f3ea29cf9e..adfa559a488b 100644 --- a/arch/arm/boot/dts/efm32gg-dk3750.dts +++ b/arch/arm/boot/dts/efm32gg-dk3750.dts @@ -37,7 +37,7 @@ }; eeprom@50 { - compatible = "microchip,24c02"; + compatible = "microchip,24c02", "atmel,24c02"; reg = <0x50>; pagesize = <16>; }; diff --git a/arch/arm/boot/dts/ethernut5.dts b/arch/arm/boot/dts/ethernut5.dts index 123b203be06c..b554f85add41 100644 --- a/arch/arm/boot/dts/ethernut5.dts +++ b/arch/arm/boot/dts/ethernut5.dts @@ -36,6 +36,18 @@ status = "okay"; }; + tcb0: timer@fffa0000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + usart0: serial@fffb0000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/exynos3250-artik5-eval.dts b/arch/arm/boot/dts/exynos3250-artik5-eval.dts index 4cbfa09c6c4e..20446a846a98 100644 --- a/arch/arm/boot/dts/exynos3250-artik5-eval.dts +++ b/arch/arm/boot/dts/exynos3250-artik5-eval.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos3250 based ARTIK5 evaluation board device tree source * @@ -6,10 +7,6 @@ * * Device tree source file for Samsung's ARTIK5 evaluation board * which is based on Samsung Exynos3250 SoC. - * - * 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. */ /dts-v1/; diff --git a/arch/arm/boot/dts/exynos3250-artik5.dtsi b/arch/arm/boot/dts/exynos3250-artik5.dtsi index 152e0291d0da..0aa577fe9f95 100644 --- a/arch/arm/boot/dts/exynos3250-artik5.dtsi +++ b/arch/arm/boot/dts/exynos3250-artik5.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos3250 based ARTIK5 module device tree source * @@ -6,10 +7,6 @@ * * Device tree source file for Samsung's ARTIK5 module which is based on * Samsung Exynos3250 SoC. - * - * 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. */ #include "exynos3250.dtsi" diff --git a/arch/arm/boot/dts/exynos3250-monk.dts b/arch/arm/boot/dts/exynos3250-monk.dts index 029eb18590cf..6ffedf4ed9f2 100644 --- a/arch/arm/boot/dts/exynos3250-monk.dts +++ b/arch/arm/boot/dts/exynos3250-monk.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos3250 based Monk board device tree source * @@ -6,10 +7,6 @@ * * Device tree source file for Samsung's Monk board which is based on * Samsung Exynos3250 SoC. - * - * 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. */ /dts-v1/; diff --git a/arch/arm/boot/dts/exynos3250-pinctrl.dtsi b/arch/arm/boot/dts/exynos3250-pinctrl.dtsi index a149f148e659..dff3c6e3aa1f 100644 --- a/arch/arm/boot/dts/exynos3250-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos3250-pinctrl.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos3250 SoCs pin-mux and pin-config device tree source * @@ -6,11 +7,7 @@ * * Samsung's Exynos3250 SoCs pin-mux and pin-config optiosn are listed as device * tree nodes are listed in this file. - * - * 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. -*/ + */ #include diff --git a/arch/arm/boot/dts/exynos3250-rinato.dts b/arch/arm/boot/dts/exynos3250-rinato.dts index 3743df4de390..2c3460781cc6 100644 --- a/arch/arm/boot/dts/exynos3250-rinato.dts +++ b/arch/arm/boot/dts/exynos3250-rinato.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos3250 based Rinato board device tree source * @@ -6,10 +7,6 @@ * * Device tree source file for Samsung's Rinato board which is based on * Samsung Exynos3250 SoC. - * - * 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. */ /dts-v1/; diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi index 2bd3872221a1..b8fb94f5daa8 100644 --- a/arch/arm/boot/dts/exynos3250.dtsi +++ b/arch/arm/boot/dts/exynos3250.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos3250 SoC device tree source * @@ -11,10 +12,6 @@ * Note: This file does not include device nodes for all the controllers in * Exynos3250 SoC. As device tree coverage for Exynos3250 increases, additional * nodes can be added to this file. - * - * 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. */ #include "exynos4-cpu-thermal.dtsi" @@ -164,31 +161,31 @@ syscon = <&pmu_system_controller>; }; - pd_cam: cam-power-domain@10023C00 { + pd_cam: cam-power-domain@10023c00 { compatible = "samsung,exynos4210-pd"; reg = <0x10023C00 0x20>; #power-domain-cells = <0>; }; - pd_mfc: mfc-power-domain@10023C40 { + pd_mfc: mfc-power-domain@10023c40 { compatible = "samsung,exynos4210-pd"; reg = <0x10023C40 0x20>; #power-domain-cells = <0>; }; - pd_g3d: g3d-power-domain@10023C60 { + pd_g3d: g3d-power-domain@10023c60 { compatible = "samsung,exynos4210-pd"; reg = <0x10023C60 0x20>; #power-domain-cells = <0>; }; - pd_lcd0: lcd0-power-domain@10023C80 { + pd_lcd0: lcd0-power-domain@10023c80 { compatible = "samsung,exynos4210-pd"; reg = <0x10023C80 0x20>; #power-domain-cells = <0>; }; - pd_isp: isp-power-domain@10023CA0 { + pd_isp: isp-power-domain@10023ca0 { compatible = "samsung,exynos4210-pd"; reg = <0x10023CA0 0x20>; #power-domain-cells = <0>; @@ -204,7 +201,7 @@ <&cmu CLK_FIN_PLL>; }; - cmu_dmc: clock-controller@105C0000 { + cmu_dmc: clock-controller@105c0000 { compatible = "samsung,exynos3250-cmu-dmc"; reg = <0x105C0000 0x2000>; #clock-cells = <1>; @@ -219,7 +216,7 @@ status = "disabled"; }; - tmu: tmu@100C0000 { + tmu: tmu@100c0000 { compatible = "samsung,exynos3250-tmu"; reg = <0x100C0000 0x100>; interrupts = ; @@ -287,7 +284,7 @@ status = "disabled"; }; - sysmmu_jpeg: sysmmu@11A60000 { + sysmmu_jpeg: sysmmu@11a60000 { compatible = "samsung,exynos-sysmmu"; reg = <0x11a60000 0x1000>; interrupts = , @@ -313,7 +310,7 @@ status = "disabled"; }; - dsi_0: dsi@11C80000 { + dsi_0: dsi@11c80000 { compatible = "samsung,exynos3250-mipi-dsi"; reg = <0x11C80000 0x10000>; interrupts = ; @@ -328,7 +325,7 @@ status = "disabled"; }; - sysmmu_fimd0: sysmmu@11E20000 { + sysmmu_fimd0: sysmmu@11e20000 { compatible = "samsung,exynos-sysmmu"; reg = <0x11e20000 0x1000>; interrupts = , @@ -386,7 +383,7 @@ status = "disabled"; }; - exynos_usbphy: exynos-usbphy@125B0000 { + exynos_usbphy: exynos-usbphy@125b0000 { compatible = "samsung,exynos3250-usb2-phy"; reg = <0x125B0000 0x100>; samsung,pmureg-phandle = <&pmu_system_controller>; @@ -425,7 +422,7 @@ }; }; - adc: adc@126C0000 { + adc: adc@126c0000 { compatible = "samsung,exynos3250-adc", "samsung,exynos-adc-v2"; reg = <0x126C0000 0x100>; @@ -544,7 +541,7 @@ status = "disabled"; }; - i2c_4: i2c@138A0000 { + i2c_4: i2c@138a0000 { #address-cells = <1>; #size-cells = <0>; compatible = "samsung,s3c2440-i2c"; @@ -557,7 +554,7 @@ status = "disabled"; }; - i2c_5: i2c@138B0000 { + i2c_5: i2c@138b0000 { #address-cells = <1>; #size-cells = <0>; compatible = "samsung,s3c2440-i2c"; @@ -570,7 +567,7 @@ status = "disabled"; }; - i2c_6: i2c@138C0000 { + i2c_6: i2c@138c0000 { #address-cells = <1>; #size-cells = <0>; compatible = "samsung,s3c2440-i2c"; @@ -583,7 +580,7 @@ status = "disabled"; }; - i2c_7: i2c@138D0000 { + i2c_7: i2c@138d0000 { #address-cells = <1>; #size-cells = <0>; compatible = "samsung,s3c2440-i2c"; @@ -641,7 +638,7 @@ status = "disabled"; }; - pwm: pwm@139D0000 { + pwm: pwm@139d0000 { compatible = "samsung,exynos4210-pwm"; reg = <0x139D0000 0x1000>; interrupts = , diff --git a/arch/arm/boot/dts/exynos4-cpu-thermal.dtsi b/arch/arm/boot/dts/exynos4-cpu-thermal.dtsi index 735cb2f10817..021d9fc1b492 100644 --- a/arch/arm/boot/dts/exynos4-cpu-thermal.dtsi +++ b/arch/arm/boot/dts/exynos4-cpu-thermal.dtsi @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Device tree sources for Exynos4 thermal zone * * Copyright (c) 2014 Lukasz Majewski - * - * 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. - * */ #include diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi index 4768b086ed67..6d59cc827649 100644 --- a/arch/arm/boot/dts/exynos4.dtsi +++ b/arch/arm/boot/dts/exynos4.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos4 SoC series common device tree source * @@ -13,10 +14,6 @@ * Note: This file does not include device nodes for all the controllers in * Exynos4 SoCs. As device tree coverage for Exynos4 increases, additional * nodes can be added to this file. - * - * 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. */ #include @@ -101,28 +98,28 @@ syscon = <&pmu_system_controller>; }; - pd_mfc: mfc-power-domain@10023C40 { + pd_mfc: mfc-power-domain@10023c40 { compatible = "samsung,exynos4210-pd"; reg = <0x10023C40 0x20>; #power-domain-cells = <0>; label = "MFC"; }; - pd_g3d: g3d-power-domain@10023C60 { + pd_g3d: g3d-power-domain@10023c60 { compatible = "samsung,exynos4210-pd"; reg = <0x10023C60 0x20>; #power-domain-cells = <0>; label = "G3D"; }; - pd_lcd0: lcd0-power-domain@10023C80 { + pd_lcd0: lcd0-power-domain@10023c80 { compatible = "samsung,exynos4210-pd"; reg = <0x10023C80 0x20>; #power-domain-cells = <0>; label = "LCD0"; }; - pd_tv: tv-power-domain@10023C20 { + pd_tv: tv-power-domain@10023c20 { compatible = "samsung,exynos4210-pd"; reg = <0x10023C20 0x20>; #power-domain-cells = <0>; @@ -130,21 +127,21 @@ label = "TV"; }; - pd_cam: cam-power-domain@10023C00 { + pd_cam: cam-power-domain@10023c00 { compatible = "samsung,exynos4210-pd"; reg = <0x10023C00 0x20>; #power-domain-cells = <0>; label = "CAM"; }; - pd_gps: gps-power-domain@10023CE0 { + pd_gps: gps-power-domain@10023ce0 { compatible = "samsung,exynos4210-pd"; reg = <0x10023CE0 0x20>; #power-domain-cells = <0>; label = "GPS"; }; - pd_gps_alive: gps-alive-power-domain@10023D00 { + pd_gps_alive: gps-alive-power-domain@10023d00 { compatible = "samsung,exynos4210-pd"; reg = <0x10023D00 0x20>; #power-domain-cells = <0>; @@ -184,7 +181,7 @@ interrupt-parent = <&gic>; }; - dsi_0: dsi@11C80000 { + dsi_0: dsi@11c80000 { compatible = "samsung,exynos4210-mipi-dsi"; reg = <0x11C80000 0x10000>; interrupts = ; @@ -297,7 +294,7 @@ status = "disabled"; }; - keypad: keypad@100A0000 { + keypad: keypad@100a0000 { compatible = "samsung,s5pv210-keypad"; reg = <0x100A0000 0x100>; interrupts = ; @@ -342,7 +339,7 @@ status = "disabled"; }; - exynos_usbphy: exynos-usbphy@125B0000 { + exynos_usbphy: exynos-usbphy@125b0000 { compatible = "samsung,exynos4210-usb2-phy"; reg = <0x125B0000 0x100>; samsung,pmureg-phandle = <&pmu_system_controller>; @@ -538,7 +535,7 @@ status = "disabled"; }; - i2c_4: i2c@138A0000 { + i2c_4: i2c@138a0000 { #address-cells = <1>; #size-cells = <0>; compatible = "samsung,s3c2440-i2c"; @@ -551,7 +548,7 @@ status = "disabled"; }; - i2c_5: i2c@138B0000 { + i2c_5: i2c@138b0000 { #address-cells = <1>; #size-cells = <0>; compatible = "samsung,s3c2440-i2c"; @@ -564,7 +561,7 @@ status = "disabled"; }; - i2c_6: i2c@138C0000 { + i2c_6: i2c@138c0000 { #address-cells = <1>; #size-cells = <0>; compatible = "samsung,s3c2440-i2c"; @@ -577,7 +574,7 @@ status = "disabled"; }; - i2c_7: i2c@138D0000 { + i2c_7: i2c@138d0000 { #address-cells = <1>; #size-cells = <0>; compatible = "samsung,s3c2440-i2c"; @@ -590,7 +587,7 @@ status = "disabled"; }; - i2c_8: i2c@138E0000 { + i2c_8: i2c@138e0000 { #address-cells = <1>; #size-cells = <0>; compatible = "samsung,s3c2440-hdmiphy-i2c"; @@ -651,7 +648,7 @@ status = "disabled"; }; - pwm: pwm@139D0000 { + pwm: pwm@139d0000 { compatible = "samsung,exynos4210-pwm"; reg = <0x139D0000 0x1000>; interrupts = , @@ -720,7 +717,7 @@ status = "disabled"; }; - tmu: tmu@100C0000 { + tmu: tmu@100c0000 { #include "exynos4412-tmu-sensor-conf.dtsi" }; @@ -743,7 +740,7 @@ iommus = <&sysmmu_rotator>; }; - hdmi: hdmi@12D00000 { + hdmi: hdmi@12d00000 { compatible = "samsung,exynos4210-hdmi"; reg = <0x12D00000 0x70000>; interrupts = ; @@ -755,10 +752,11 @@ phy = <&hdmi_i2c_phy>; power-domains = <&pd_tv>; samsung,syscon-phandle = <&pmu_system_controller>; + #sound-dai-cells = <0>; status = "disabled"; }; - hdmicec: cec@100B0000 { + hdmicec: cec@100b0000 { compatible = "samsung,s5p-cec"; reg = <0x100B0000 0x200>; interrupts = ; @@ -771,7 +769,7 @@ status = "disabled"; }; - mixer: mixer@12C10000 { + mixer: mixer@12c10000 { compatible = "samsung,exynos4210-mixer"; interrupts = ; reg = <0x12C10000 0x2100>, <0x12c00000 0x300>; @@ -910,7 +908,7 @@ #iommu-cells = <0>; }; - sysmmu_tv: sysmmu@12E20000 { + sysmmu_tv: sysmmu@12e20000 { compatible = "samsung,exynos-sysmmu"; reg = <0x12E20000 0x1000>; interrupt-parent = <&combiner>; @@ -921,7 +919,7 @@ #iommu-cells = <0>; }; - sysmmu_fimc0: sysmmu@11A20000 { + sysmmu_fimc0: sysmmu@11a20000 { compatible = "samsung,exynos-sysmmu"; reg = <0x11A20000 0x1000>; interrupt-parent = <&combiner>; @@ -932,7 +930,7 @@ #iommu-cells = <0>; }; - sysmmu_fimc1: sysmmu@11A30000 { + sysmmu_fimc1: sysmmu@11a30000 { compatible = "samsung,exynos-sysmmu"; reg = <0x11A30000 0x1000>; interrupt-parent = <&combiner>; @@ -943,7 +941,7 @@ #iommu-cells = <0>; }; - sysmmu_fimc2: sysmmu@11A40000 { + sysmmu_fimc2: sysmmu@11a40000 { compatible = "samsung,exynos-sysmmu"; reg = <0x11A40000 0x1000>; interrupt-parent = <&combiner>; @@ -954,7 +952,7 @@ #iommu-cells = <0>; }; - sysmmu_fimc3: sysmmu@11A50000 { + sysmmu_fimc3: sysmmu@11a50000 { compatible = "samsung,exynos-sysmmu"; reg = <0x11A50000 0x1000>; interrupt-parent = <&combiner>; @@ -965,7 +963,7 @@ #iommu-cells = <0>; }; - sysmmu_jpeg: sysmmu@11A60000 { + sysmmu_jpeg: sysmmu@11a60000 { compatible = "samsung,exynos-sysmmu"; reg = <0x11A60000 0x1000>; interrupt-parent = <&combiner>; @@ -976,7 +974,7 @@ #iommu-cells = <0>; }; - sysmmu_rotator: sysmmu@12A30000 { + sysmmu_rotator: sysmmu@12a30000 { compatible = "samsung,exynos-sysmmu"; reg = <0x12A30000 0x1000>; interrupt-parent = <&combiner>; @@ -986,7 +984,7 @@ #iommu-cells = <0>; }; - sysmmu_fimd0: sysmmu@11E20000 { + sysmmu_fimd0: sysmmu@11e20000 { compatible = "samsung,exynos-sysmmu"; reg = <0x11E20000 0x1000>; interrupt-parent = <&combiner>; diff --git a/arch/arm/boot/dts/exynos4210-origen.dts b/arch/arm/boot/dts/exynos4210-origen.dts index 084fcc5574ef..9a310e841d5d 100644 --- a/arch/arm/boot/dts/exynos4210-origen.dts +++ b/arch/arm/boot/dts/exynos4210-origen.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos4210 based Origen board device tree source * @@ -8,11 +9,7 @@ * * Device tree source file for Insignal's Origen board which is based on * Samsung's Exynos4210 SoC. - * - * 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. -*/ + */ /dts-v1/; #include "exynos4210.dtsi" diff --git a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi index 82c32d4d83d8..dbe6c052d8c1 100644 --- a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos4210 SoC pin-mux and pin-config device tree source * @@ -8,11 +9,7 @@ * * Samsung's Exynos4210 SoC pin-mux and pin-config optiosn are listed as device * tree nodes are listed in this file. - * - * 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. -*/ + */ #include diff --git a/arch/arm/boot/dts/exynos4210-smdkv310.dts b/arch/arm/boot/dts/exynos4210-smdkv310.dts index 9c98a3724396..7a3e621edede 100644 --- a/arch/arm/boot/dts/exynos4210-smdkv310.dts +++ b/arch/arm/boot/dts/exynos4210-smdkv310.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos4210 based SMDKV310 board device tree source * @@ -8,11 +9,7 @@ * * Device tree source file for Samsung's SMDKV310 board which is based on * Samsung's Exynos4210 SoC. - * - * 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. -*/ + */ /dts-v1/; #include "exynos4210.dtsi" diff --git a/arch/arm/boot/dts/exynos4210-trats.dts b/arch/arm/boot/dts/exynos4210-trats.dts index 7b6ab7265110..aaade17b140e 100644 --- a/arch/arm/boot/dts/exynos4210-trats.dts +++ b/arch/arm/boot/dts/exynos4210-trats.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos4210 based Trats board device tree source * @@ -6,11 +7,7 @@ * * Device tree source file for Samsung's Trats board which is based on * Samsung's Exynos4210 SoC. - * - * 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. -*/ + */ /dts-v1/; #include "exynos4210.dtsi" diff --git a/arch/arm/boot/dts/exynos4210-universal_c210.dts b/arch/arm/boot/dts/exynos4210-universal_c210.dts index acd2b2286ccb..21fff7cd3aa4 100644 --- a/arch/arm/boot/dts/exynos4210-universal_c210.dts +++ b/arch/arm/boot/dts/exynos4210-universal_c210.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos4210 based Universal C210 board device tree source * @@ -6,11 +7,7 @@ * * Device tree source file for Samsung's Universal C210 board which is based on * Samsung's Exynos4210 rev0 SoC. - * - * 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. -*/ + */ /dts-v1/; #include "exynos4210.dtsi" diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi index 03dd61f64809..cc978cf28267 100644 --- a/arch/arm/boot/dts/exynos4210.dtsi +++ b/arch/arm/boot/dts/exynos4210.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos4210 SoC device tree source * @@ -13,11 +14,7 @@ * Note: This file does not include device nodes for all the controllers in * Exynos4210 SoC. As device tree coverage for Exynos4210 increases, additional * nodes can be added to this file. - * - * 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. -*/ + */ #include "exynos4.dtsi" #include "exynos4210-pinctrl.dtsi" @@ -82,7 +79,7 @@ }; }; - pd_lcd1: lcd1-power-domain@10023CA0 { + pd_lcd1: lcd1-power-domain@10023ca0 { compatible = "samsung,exynos4210-pd"; reg = <0x10023CA0 0x20>; #power-domain-cells = <0>; @@ -156,7 +153,7 @@ reg = <0x03860000 0x1000>; }; - tmu: tmu@100C0000 { + tmu: tmu@100c0000 { compatible = "samsung,exynos4210-tmu"; interrupt-parent = <&combiner>; reg = <0x100C0000 0x100>; @@ -229,7 +226,7 @@ }; }; - mixer: mixer@12C10000 { + mixer: mixer@12c10000 { clock-names = "mixer", "hdmi", "sclk_hdmi", "vp", "mout_mixer", "sclk_mixer"; clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>, @@ -245,7 +242,7 @@ status = "disabled"; }; - sysmmu_g2d: sysmmu@12A20000 { + sysmmu_g2d: sysmmu@12a20000 { compatible = "samsung,exynos-sysmmu"; reg = <0x12A20000 0x1000>; interrupt-parent = <&combiner>; diff --git a/arch/arm/boot/dts/exynos4412-itop-elite.dts b/arch/arm/boot/dts/exynos4412-itop-elite.dts index d66093084dbb..a4cd4939fe9a 100644 --- a/arch/arm/boot/dts/exynos4412-itop-elite.dts +++ b/arch/arm/boot/dts/exynos4412-itop-elite.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * TOPEET's Exynos4412 based itop board device tree source * @@ -7,10 +8,6 @@ * * Device tree source file for TOPEET iTop Exynos 4412 core board * which is based on Samsung's Exynos4412 SoC. - * - * 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. */ /dts-v1/; diff --git a/arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi b/arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi index bda49b232f7b..ab7affab7f1c 100644 --- a/arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi +++ b/arch/arm/boot/dts/exynos4412-itop-scp-core.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * TOPEET's Exynos4412 based itop board device tree source * @@ -7,10 +8,6 @@ * * Device tree source file for TOPEET iTop Exynos 4412 SCP package core * board which is based on Samsung's Exynos4412 SoC. - * - * 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. */ #include diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi index a21be71000c1..556ea78b8e32 100644 --- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Common definition for Hardkernel's Exynos4412 based ODROID-X/X2/U2/U3 boards * device tree source - * - * 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. */ #include diff --git a/arch/arm/boot/dts/exynos4412-odroidu3.dts b/arch/arm/boot/dts/exynos4412-odroidu3.dts index 44a4de08466b..bdcd4523cc1c 100644 --- a/arch/arm/boot/dts/exynos4412-odroidu3.dts +++ b/arch/arm/boot/dts/exynos4412-odroidu3.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Hardkernel's Exynos4412 based ODROID-U3 board device tree source * @@ -5,11 +6,7 @@ * * Device tree source file for Hardkernel's ODROID-U3 board which is based * on Samsung's Exynos4412 SoC. - * - * 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. -*/ + */ /dts-v1/; #include "exynos4412-odroid-common.dtsi" diff --git a/arch/arm/boot/dts/exynos4412-odroidx.dts b/arch/arm/boot/dts/exynos4412-odroidx.dts index acf48a018e5e..2dff129bc2ad 100644 --- a/arch/arm/boot/dts/exynos4412-odroidx.dts +++ b/arch/arm/boot/dts/exynos4412-odroidx.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Hardkernel's Exynos4412 based ODROID-X board device tree source * @@ -5,11 +6,7 @@ * * Device tree source file for Hardkernel's ODROID-X board which is based * on Samsung's Exynos4412 SoC. - * - * 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. -*/ + */ /dts-v1/; #include "exynos4412-odroid-common.dtsi" diff --git a/arch/arm/boot/dts/exynos4412-odroidx2.dts b/arch/arm/boot/dts/exynos4412-odroidx2.dts index d867b2ee95ca..f4b68c75c962 100644 --- a/arch/arm/boot/dts/exynos4412-odroidx2.dts +++ b/arch/arm/boot/dts/exynos4412-odroidx2.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Hardkernel's Exynos4412 based ODROID-X2 board device tree source * @@ -5,11 +6,7 @@ * * Device tree source file for Hardkernel's ODROID-X2 board which is based * on Samsung's Exynos4412 SoC. - * - * 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. -*/ + */ #include "exynos4412-odroidx.dts" #include "exynos4412-prime.dtsi" diff --git a/arch/arm/boot/dts/exynos4412-origen.dts b/arch/arm/boot/dts/exynos4412-origen.dts index b0b5ec7903a5..1514f0dbaff8 100644 --- a/arch/arm/boot/dts/exynos4412-origen.dts +++ b/arch/arm/boot/dts/exynos4412-origen.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Insignal's Exynos4412 based Origen board device tree source * @@ -6,11 +7,7 @@ * * Device tree source file for Insignal's Origen board which is based on * Samsung's Exynos4412 SoC. - * - * 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. -*/ + */ /dts-v1/; #include "exynos4412.dtsi" diff --git a/arch/arm/boot/dts/exynos4412-pinctrl.dtsi b/arch/arm/boot/dts/exynos4412-pinctrl.dtsi index 4eebd4721a5f..e8dd5f2d976f 100644 --- a/arch/arm/boot/dts/exynos4412-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos4412-pinctrl.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos4412 SoCs pin-mux and pin-config device tree source * @@ -6,11 +7,7 @@ * * Samsung's Exynos4412 SoCs pin-mux and pin-config optiosn are listed as device * tree nodes are listed in this file. - * - * 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. -*/ + */ #include @@ -925,7 +922,7 @@ }; }; - pinctrl_3: pinctrl@106E0000 { + pinctrl_3: pinctrl@106e0000 { gpv0: gpv0 { gpio-controller; #gpio-cells = <2>; diff --git a/arch/arm/boot/dts/exynos4412-ppmu-common.dtsi b/arch/arm/boot/dts/exynos4412-ppmu-common.dtsi index 16e4b77d8cb1..3a3b2fafefdd 100644 --- a/arch/arm/boot/dts/exynos4412-ppmu-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-ppmu-common.dtsi @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Device tree sources for Exynos4412 PPMU common device tree * * Copyright (C) 2015 Samsung Electronics * Author: Chanwoo Choi - * - * 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. */ &ppmu_dmc0 { diff --git a/arch/arm/boot/dts/exynos4412-prime.dtsi b/arch/arm/boot/dts/exynos4412-prime.dtsi index a67bd953d754..8e7a7fb98124 100644 --- a/arch/arm/boot/dts/exynos4412-prime.dtsi +++ b/arch/arm/boot/dts/exynos4412-prime.dtsi @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos4412 Prime SoC device tree source * * Copyright (c) 2016 Samsung Electronics Co., Ltd. * http://www.samsung.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. */ /* diff --git a/arch/arm/boot/dts/exynos4412-smdk4412.dts b/arch/arm/boot/dts/exynos4412-smdk4412.dts index 7fcb43431b59..5c5c2887c14f 100644 --- a/arch/arm/boot/dts/exynos4412-smdk4412.dts +++ b/arch/arm/boot/dts/exynos4412-smdk4412.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos4412 based SMDK board device tree source * @@ -6,11 +7,7 @@ * * Device tree source file for Samsung's SMDK4412 board which is based on * Samsung's Exynos4412 SoC. - * - * 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. -*/ + */ /dts-v1/; #include "exynos4412.dtsi" diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts index 220cdf109405..f285790e8e04 100644 --- a/arch/arm/boot/dts/exynos4412-trats2.dts +++ b/arch/arm/boot/dts/exynos4412-trats2.dts @@ -300,6 +300,13 @@ }; + wlan_pwrseq: sdhci3-pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpj0 0 GPIO_ACTIVE_LOW>; + clocks = <&max77686 MAX77686_CLK_PMIC>; + clock-names = "ext_clock"; + }; + sound { compatible = "samsung,trats2-audio"; samsung,i2s-controller = <&i2s0>; @@ -454,7 +461,7 @@ reg = <0>; vdd3-supply = <&lcd_vdd3_reg>; vci-supply = <&ldo25_reg>; - reset-gpios = <&gpy4 5 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpf2 1 GPIO_ACTIVE_HIGH>; power-on-delay= <50>; reset-delay = <100>; init-delay = <100>; @@ -1350,6 +1357,26 @@ status = "okay"; }; +&sdhci_3 { + #address-cells = <1>; + #size-cells = <0>; + non-removable; + bus-width = <4>; + + mmc-pwrseq = <&wlan_pwrseq>; + pinctrl-names = "default"; + pinctrl-0 = <&sd3_clk &sd3_cmd &sd3_bus4>; + status = "okay"; + + brcmf: wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + interrupt-parent = <&gpx2>; + interrupts = <5 IRQ_TYPE_NONE>; + interrupt-names = "host-wake"; + }; +}; + &serial_0 { status = "okay"; }; diff --git a/arch/arm/boot/dts/exynos4412.dtsi b/arch/arm/boot/dts/exynos4412.dtsi index b255ac55b1c1..e4ad2fc0329e 100644 --- a/arch/arm/boot/dts/exynos4412.dtsi +++ b/arch/arm/boot/dts/exynos4412.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos4412 SoC device tree source * @@ -11,11 +12,7 @@ * Note: This file does not include device nodes for all the controllers in * Exynos4412 SoC. As device tree coverage for Exynos4412 increases, additional * nodes can be added to this file. - * - * 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. -*/ + */ #include "exynos4.dtsi" #include "exynos4412-pinctrl.dtsi" @@ -38,7 +35,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu0: cpu@A00 { + cpu0: cpu@a00 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <0xA00>; @@ -50,21 +47,21 @@ #cooling-cells = <2>; /* min followed by max */ }; - cpu@A01 { + cpu@a01 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <0xA01>; operating-points-v2 = <&cpu0_opp_table>; }; - cpu@A02 { + cpu@a02 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <0xA02>; operating-points-v2 = <&cpu0_opp_table>; }; - cpu@A03 { + cpu@a03 { device_type = "cpu"; compatible = "arm,cortex-a9"; reg = <0xA03>; @@ -168,7 +165,7 @@ }; }; - pd_isp: isp-power-domain@10023CA0 { + pd_isp: isp-power-domain@10023ca0 { compatible = "samsung,exynos4210-pd"; reg = <0x10023CA0 0x20>; #power-domain-cells = <0>; @@ -191,10 +188,19 @@ clock: clock-controller@10030000 { compatible = "samsung,exynos4412-clock"; - reg = <0x10030000 0x20000>; + reg = <0x10030000 0x18000>; #clock-cells = <1>; }; + isp_clock: clock-controller@10048000 { + compatible = "samsung,exynos4412-isp-clock"; + reg = <0x10048000 0x1000>; + #clock-cells = <1>; + power-domains = <&pd_isp>; + clocks = <&clock CLK_ACLK200>, <&clock CLK_ACLK400_MCUISP>; + clock-names = "aclk200", "aclk400_mcuisp"; + }; + mct@10050000 { compatible = "samsung,exynos4412-mct"; reg = <0x10050000 0x800>; @@ -224,7 +230,7 @@ samsung,syscon-phandle = <&pmu_system_controller>; }; - adc: adc@126C0000 { + adc: adc@126c0000 { compatible = "samsung,exynos-adc-v1"; reg = <0x126C0000 0x100>; interrupt-parent = <&combiner>; @@ -257,18 +263,18 @@ reg = <0x12390000 0x1000>; interrupts = ; power-domains = <&pd_isp>; - clocks = <&clock CLK_FIMC_LITE0>; + clocks = <&isp_clock CLK_ISP_FIMC_LITE0>; clock-names = "flite"; iommus = <&sysmmu_fimc_lite0>; status = "disabled"; }; - fimc_lite_1: fimc-lite@123A0000 { + fimc_lite_1: fimc-lite@123a0000 { compatible = "samsung,exynos4212-fimc-lite"; reg = <0x123A0000 0x1000>; interrupts = ; power-domains = <&pd_isp>; - clocks = <&clock CLK_FIMC_LITE1>; + clocks = <&isp_clock CLK_ISP_FIMC_LITE1>; clock-names = "flite"; iommus = <&sysmmu_fimc_lite1>; status = "disabled"; @@ -280,29 +286,35 @@ interrupts = , ; power-domains = <&pd_isp>; - clocks = <&clock CLK_FIMC_LITE0>, - <&clock CLK_FIMC_LITE1>, <&clock CLK_PPMUISPX>, - <&clock CLK_PPMUISPMX>, + clocks = <&isp_clock CLK_ISP_FIMC_LITE0>, + <&isp_clock CLK_ISP_FIMC_LITE1>, + <&isp_clock CLK_ISP_PPMUISPX>, + <&isp_clock CLK_ISP_PPMUISPMX>, + <&isp_clock CLK_ISP_FIMC_ISP>, + <&isp_clock CLK_ISP_FIMC_DRC>, + <&isp_clock CLK_ISP_FIMC_FD>, + <&isp_clock CLK_ISP_MCUISP>, + <&isp_clock CLK_ISP_GICISP>, + <&isp_clock CLK_ISP_MCUCTL_ISP>, + <&isp_clock CLK_ISP_PWM_ISP>, + <&isp_clock CLK_ISP_DIV_ISP0>, + <&isp_clock CLK_ISP_DIV_ISP1>, + <&isp_clock CLK_ISP_DIV_MCUISP0>, + <&isp_clock CLK_ISP_DIV_MCUISP1>, <&clock CLK_MOUT_MPLL_USER_T>, - <&clock CLK_FIMC_ISP>, <&clock CLK_FIMC_DRC>, - <&clock CLK_FIMC_FD>, <&clock CLK_MCUISP>, - <&clock CLK_GICISP>, <&clock CLK_MCUCTL_ISP>, - <&clock CLK_PWM_ISP>, - <&clock CLK_DIV_ISP0>, <&clock CLK_DIV_ISP1>, - <&clock CLK_DIV_MCUISP0>, - <&clock CLK_DIV_MCUISP1>, - <&clock CLK_UART_ISP_SCLK>, - <&clock CLK_ACLK200>, <&clock CLK_DIV_ACLK200>, + <&clock CLK_ACLK200>, <&clock CLK_ACLK400_MCUISP>, - <&clock CLK_DIV_ACLK400_MCUISP>; + <&clock CLK_DIV_ACLK200>, + <&clock CLK_DIV_ACLK400_MCUISP>, + <&clock CLK_UART_ISP_SCLK>; clock-names = "lite0", "lite1", "ppmuispx", - "ppmuispmx", "mpll", "isp", + "ppmuispmx", "isp", "drc", "fd", "mcuisp", "gicisp", "mcuctl_isp", "pwm_isp", "ispdiv0", "ispdiv1", "mcuispdiv0", - "mcuispdiv1", "uart", "aclk200", - "div_aclk200", "aclk400mcuisp", - "div_aclk400mcuisp"; + "mcuispdiv1", "mpll", "aclk200", + "aclk400mcuisp", "div_aclk200", + "div_aclk400mcuisp", "uart"; iommus = <&sysmmu_fimc_isp>, <&sysmmu_fimc_drc>, <&sysmmu_fimc_fd>, <&sysmmu_fimc_mcuctl>; iommu-names = "isp", "drc", "fd", "mcuctl"; @@ -318,7 +330,7 @@ i2c1_isp: i2c-isp@12140000 { compatible = "samsung,exynos4212-i2c-isp"; reg = <0x12140000 0x100>; - clocks = <&clock CLK_I2C1_ISP>; + clocks = <&isp_clock CLK_ISP_I2C1_ISP>; clock-names = "i2c_isp"; #address-cells = <1>; #size-cells = <0>; @@ -355,7 +367,7 @@ interrupts = <16 2>; power-domains = <&pd_isp>; clock-names = "sysmmu"; - clocks = <&clock CLK_SMMU_ISP>; + clocks = <&isp_clock CLK_ISP_SMMU_ISP>; #iommu-cells = <0>; }; @@ -366,51 +378,53 @@ interrupts = <16 3>; power-domains = <&pd_isp>; clock-names = "sysmmu"; - clocks = <&clock CLK_SMMU_DRC>; + clocks = <&isp_clock CLK_ISP_SMMU_DRC>; #iommu-cells = <0>; }; - sysmmu_fimc_fd: sysmmu@122A0000 { + sysmmu_fimc_fd: sysmmu@122a0000 { compatible = "samsung,exynos-sysmmu"; reg = <0x122A0000 0x1000>; interrupt-parent = <&combiner>; interrupts = <16 4>; power-domains = <&pd_isp>; clock-names = "sysmmu"; - clocks = <&clock CLK_SMMU_FD>; + clocks = <&isp_clock CLK_ISP_SMMU_FD>; #iommu-cells = <0>; }; - sysmmu_fimc_mcuctl: sysmmu@122B0000 { + sysmmu_fimc_mcuctl: sysmmu@122b0000 { compatible = "samsung,exynos-sysmmu"; reg = <0x122B0000 0x1000>; interrupt-parent = <&combiner>; interrupts = <16 5>; power-domains = <&pd_isp>; clock-names = "sysmmu"; - clocks = <&clock CLK_SMMU_ISPCX>; + clocks = <&isp_clock CLK_ISP_SMMU_ISPCX>; #iommu-cells = <0>; }; - sysmmu_fimc_lite0: sysmmu@123B0000 { + sysmmu_fimc_lite0: sysmmu@123b0000 { compatible = "samsung,exynos-sysmmu"; reg = <0x123B0000 0x1000>; interrupt-parent = <&combiner>; interrupts = <16 0>; power-domains = <&pd_isp>; clock-names = "sysmmu", "master"; - clocks = <&clock CLK_SMMU_LITE0>, <&clock CLK_FIMC_LITE0>; + clocks = <&isp_clock CLK_ISP_SMMU_LITE0>, + <&isp_clock CLK_ISP_FIMC_LITE0>; #iommu-cells = <0>; }; - sysmmu_fimc_lite1: sysmmu@123C0000 { + sysmmu_fimc_lite1: sysmmu@123c0000 { compatible = "samsung,exynos-sysmmu"; reg = <0x123C0000 0x1000>; interrupt-parent = <&combiner>; interrupts = <16 1>; power-domains = <&pd_isp>; clock-names = "sysmmu", "master"; - clocks = <&clock CLK_SMMU_LITE1>, <&clock CLK_FIMC_LITE1>; + clocks = <&isp_clock CLK_ISP_SMMU_LITE1>, + <&isp_clock CLK_ISP_FIMC_LITE1>; #iommu-cells = <0>; }; diff --git a/arch/arm/boot/dts/exynos5.dtsi b/arch/arm/boot/dts/exynos5.dtsi index 66d22521c976..f8d7de1144f1 100644 --- a/arch/arm/boot/dts/exynos5.dtsi +++ b/arch/arm/boot/dts/exynos5.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos5 SoC series common device tree source * @@ -7,10 +8,6 @@ * Samsung's Exynos5 SoC series device nodes are listed in this file. Particular * SoCs from Exynos5 series can include this file and provide values for SoCs * specfic bindings. - * - * 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. */ #include @@ -106,31 +103,31 @@ reg = <0x10050000 0x5000>; }; - serial_0: serial@12C00000 { + serial_0: serial@12c00000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C00000 0x100>; interrupts = ; }; - serial_1: serial@12C10000 { + serial_1: serial@12c10000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C10000 0x100>; interrupts = ; }; - serial_2: serial@12C20000 { + serial_2: serial@12c20000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C20000 0x100>; interrupts = ; }; - serial_3: serial@12C30000 { + serial_3: serial@12c30000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C30000 0x100>; interrupts = ; }; - i2c_0: i2c@12C60000 { + i2c_0: i2c@12c60000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12C60000 0x100>; interrupts = ; @@ -140,7 +137,7 @@ status = "disabled"; }; - i2c_1: i2c@12C70000 { + i2c_1: i2c@12c70000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12C70000 0x100>; interrupts = ; @@ -150,7 +147,7 @@ status = "disabled"; }; - i2c_2: i2c@12C80000 { + i2c_2: i2c@12c80000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12C80000 0x100>; interrupts = ; @@ -160,7 +157,7 @@ status = "disabled"; }; - i2c_3: i2c@12C90000 { + i2c_3: i2c@12c90000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12C90000 0x100>; interrupts = ; @@ -170,14 +167,14 @@ status = "disabled"; }; - pwm: pwm@12DD0000 { + pwm: pwm@12dd0000 { compatible = "samsung,exynos4210-pwm"; reg = <0x12DD0000 0x100>; samsung,pwm-outputs = <0>, <1>, <2>, <3>; #pwm-cells = <3>; }; - rtc: rtc@101E0000 { + rtc: rtc@101e0000 { compatible = "samsung,s3c6410-rtc"; reg = <0x101E0000 0x100>; interrupts = , @@ -195,7 +192,7 @@ status = "disabled"; }; - dp: dp-controller@145B0000 { + dp: dp-controller@145b0000 { compatible = "samsung,exynos5-dp"; reg = <0x145B0000 0x1000>; interrupts = <10 3>; @@ -204,5 +201,28 @@ #size-cells = <0>; status = "disabled"; }; + + sss: sss@10830000 { + compatible = "samsung,exynos4210-secss"; + reg = <0x10830000 0x300>; + interrupts = ; + }; + + prng: rng@10830400 { + compatible = "samsung,exynos5250-prng"; + reg = <0x10830400 0x200>; + }; + + trng: rng@10830600 { + compatible = "samsung,exynos5250-trng"; + reg = <0x10830600 0x100>; + }; + + g2d: g2d@10850000 { + compatible = "samsung,exynos5250-g2d"; + reg = <0x10850000 0x1000>; + interrupts = ; + status = "disabled"; + }; }; }; diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts index 0efd678b8251..7a8a5c55701a 100644 --- a/arch/arm/boot/dts/exynos5250-arndale.dts +++ b/arch/arm/boot/dts/exynos5250-arndale.dts @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos5250 based Arndale board device tree source * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.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. */ /dts-v1/; diff --git a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi index 1fd122db18e6..6ff6dea29d44 100644 --- a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos5250 SoC pin-mux and pin-config device tree source * @@ -6,11 +7,7 @@ * * Samsung's Exynos5250 SoC pin-mux and pin-config optiosn are listed as device * tree nodes are listed in this file. - * - * 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. -*/ + */ #include diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts index 1e3f9627766c..d5e66189ed2a 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SAMSUNG SMDK5250 board device tree source * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.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. */ /dts-v1/; diff --git a/arch/arm/boot/dts/exynos5250-snow-common.dtsi b/arch/arm/boot/dts/exynos5250-snow-common.dtsi index 2e7175d2b1b8..59cf1b202849 100644 --- a/arch/arm/boot/dts/exynos5250-snow-common.dtsi +++ b/arch/arm/boot/dts/exynos5250-snow-common.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Google Snow board device tree source * * Copyright (c) 2012 Google, Inc - * - * 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. */ #include diff --git a/arch/arm/boot/dts/exynos5250-snow-rev5.dts b/arch/arm/boot/dts/exynos5250-snow-rev5.dts index 90560c316f64..0348b1c49a69 100644 --- a/arch/arm/boot/dts/exynos5250-snow-rev5.dts +++ b/arch/arm/boot/dts/exynos5250-snow-rev5.dts @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Google Snow Rev 5+ board device tree source * * Copyright (c) 2012 Google, Inc * Copyright (c) 2015 Samsung Electronics Co., Ltd. * http://www.samsung.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. */ /dts-v1/; diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts index df48f2cc96f7..4827cb506fa3 100644 --- a/arch/arm/boot/dts/exynos5250-snow.dts +++ b/arch/arm/boot/dts/exynos5250-snow.dts @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Google Snow board device tree source * * Copyright (c) 2012 Google, Inc - * - * 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. */ /dts-v1/; diff --git a/arch/arm/boot/dts/exynos5250-spring.dts b/arch/arm/boot/dts/exynos5250-spring.dts index 47dbc50546c1..3d501926c227 100644 --- a/arch/arm/boot/dts/exynos5250-spring.dts +++ b/arch/arm/boot/dts/exynos5250-spring.dts @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Google Spring board device tree source * * Copyright (c) 2013 Google, Inc * Copyright (c) 2014 SUSE LINUX Products GmbH - * - * 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. */ /dts-v1/; diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index 5286084e1032..56626d1a4235 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SAMSUNG EXYNOS5250 SoC device tree source * @@ -11,11 +12,7 @@ * Note: This file does not include device nodes for all the controllers in * EXYNOS5250 SoC. As device tree coverage for EXYNOS5250 increases, * additional nodes can be added to this file. - * - * 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. -*/ + */ #include #include "exynos5.dtsi" @@ -111,21 +108,28 @@ }; }; - pd_gsc: gsc-power-domain@10044000 { + pd_gsc: power-domain@10044000 { compatible = "samsung,exynos4210-pd"; reg = <0x10044000 0x20>; #power-domain-cells = <0>; label = "GSC"; }; - pd_mfc: mfc-power-domain@10044040 { + pd_mfc: power-domain@10044040 { compatible = "samsung,exynos4210-pd"; reg = <0x10044040 0x20>; #power-domain-cells = <0>; label = "MFC"; }; - pd_disp1: disp1-power-domain@100440A0 { + pd_g3d: power-domain@10044060 { + compatible = "samsung,exynos4210-pd"; + reg = <0x10044060 0x20>; + #power-domain-cells = <0>; + label = "G3D"; + }; + + pd_disp1: power-domain@100440a0 { compatible = "samsung,exynos4210-pd"; reg = <0x100440A0 0x20>; #power-domain-cells = <0>; @@ -136,6 +140,13 @@ clock-names = "oscclk", "clk0", "clk1"; }; + pd_mau: power-domain@100440c0 { + compatible = "samsung,exynos4210-pd"; + reg = <0x100440C0 0x20>; + #power-domain-cells = <0>; + label = "MAU"; + }; + clock: clock-controller@10010000 { compatible = "samsung,exynos5250-clock"; reg = <0x10010000 0x30000>; @@ -149,6 +160,7 @@ clocks = <&clock CLK_FIN_PLL>, <&clock CLK_FOUT_EPLL>, <&clock CLK_SCLK_AUDIO0>, <&clock CLK_DIV_PCM0>; clock-names = "pll_ref", "pll_in", "sclk_audio", "sclk_pcm_in"; + power-domains = <&pd_mau>; }; timer { @@ -165,7 +177,7 @@ clock-frequency = <24000000>; }; - mct@101C0000 { + mct@101c0000 { compatible = "samsung,exynos4210-mct"; reg = <0x101C0000 0x800>; interrupt-controller; @@ -223,6 +235,7 @@ compatible = "samsung,exynos5250-pinctrl"; reg = <0x03860000 0x1000>; interrupts = ; + power-domains = <&pd_mau>; }; pmu_system_controller: system-controller@10040000 { @@ -236,7 +249,7 @@ interrupt-parent = <&gic>; }; - watchdog@101D0000 { + watchdog@101d0000 { compatible = "samsung,exynos5250-wdt"; reg = <0x101D0000 0x100>; interrupts = ; @@ -245,15 +258,6 @@ samsung,syscon-phandle = <&pmu_system_controller>; }; - g2d@10850000 { - compatible = "samsung,exynos5250-g2d"; - reg = <0x10850000 0x1000>; - interrupts = ; - clocks = <&clock CLK_G2D>; - clock-names = "fimg2d"; - iommus = <&sysmmu_g2d>; - }; - mfc: codec@11000000 { compatible = "samsung,mfc-v6"; reg = <0x11000000 0x10000>; @@ -265,7 +269,7 @@ iommu-names = "left", "right"; }; - rotator: rotator@11C00000 { + rotator: rotator@11c00000 { compatible = "samsung,exynos5250-rotator"; reg = <0x11C00000 0x64>; interrupts = ; @@ -283,7 +287,7 @@ #include "exynos4412-tmu-sensor-conf.dtsi" }; - sata: sata@122F0000 { + sata: sata@122f0000 { compatible = "snps,dwc-ahci"; samsung,sata-freq = <66>; reg = <0x122F0000 0x1ff>; @@ -306,7 +310,7 @@ }; /* i2c_0-3 are defined in exynos5.dtsi */ - i2c_4: i2c@12CA0000 { + i2c_4: i2c@12ca0000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12CA0000 0x100>; interrupts = ; @@ -319,7 +323,7 @@ status = "disabled"; }; - i2c_5: i2c@12CB0000 { + i2c_5: i2c@12cb0000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12CB0000 0x100>; interrupts = ; @@ -332,7 +336,7 @@ status = "disabled"; }; - i2c_6: i2c@12CC0000 { + i2c_6: i2c@12cc0000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12CC0000 0x100>; interrupts = ; @@ -345,7 +349,7 @@ status = "disabled"; }; - i2c_7: i2c@12CD0000 { + i2c_7: i2c@12cd0000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12CD0000 0x100>; interrupts = ; @@ -358,7 +362,7 @@ status = "disabled"; }; - i2c_8: i2c@12CE0000 { + i2c_8: i2c@12ce0000 { compatible = "samsung,s3c2440-hdmiphy-i2c"; reg = <0x12CE0000 0x1000>; interrupts = ; @@ -374,7 +378,7 @@ }; }; - i2c_9: i2c@121D0000 { + i2c_9: i2c@121d0000 { compatible = "samsung,exynos5-sata-phy-i2c"; reg = <0x121D0000 0x100>; #address-cells = <1>; @@ -495,9 +499,10 @@ samsung,idma-addr = <0x03000000>; pinctrl-names = "default"; pinctrl-0 = <&i2s0_bus>; + power-domains = <&pd_mau>; }; - i2s1: i2s@12D60000 { + i2s1: i2s@12d60000 { compatible = "samsung,s3c6410-i2s"; status = "disabled"; reg = <0x12D60000 0x100>; @@ -508,9 +513,10 @@ clock-names = "iis", "i2s_opclk0"; pinctrl-names = "default"; pinctrl-0 = <&i2s1_bus>; + power-domains = <&pd_mau>; }; - i2s2: i2s@12D70000 { + i2s2: i2s@12d70000 { compatible = "samsung,s3c6410-i2s"; status = "disabled"; reg = <0x12D70000 0x100>; @@ -521,6 +527,7 @@ clock-names = "iis", "i2s_opclk0"; pinctrl-names = "default"; pinctrl-0 = <&i2s2_bus>; + power-domains = <&pd_mau>; }; usb_dwc3 { @@ -596,7 +603,7 @@ interrupt-parent = <&gic>; ranges; - pdma0: pdma@121A0000 { + pdma0: pdma@121a0000 { compatible = "arm,pl330", "arm,primecell"; reg = <0x121A0000 0x1000>; interrupts = ; @@ -607,7 +614,7 @@ #dma-requests = <32>; }; - pdma1: pdma@121B0000 { + pdma1: pdma@121b0000 { compatible = "arm,pl330", "arm,primecell"; reg = <0x121B0000 0x1000>; interrupts = ; @@ -629,7 +636,7 @@ #dma-requests = <1>; }; - mdma1: mdma@11C10000 { + mdma1: mdma@11c10000 { compatible = "arm,pl330", "arm,primecell"; reg = <0x11C10000 0x1000>; interrupts = ; @@ -696,7 +703,7 @@ status = "disabled"; }; - hdmicec: cec@101B0000 { + hdmicec: cec@101b0000 { compatible = "samsung,s5p-cec"; reg = <0x101B0000 0x200>; interrupts = ; @@ -727,7 +734,7 @@ #phy-cells = <0>; }; - adc: adc@12D10000 { + adc: adc@12d10000 { compatible = "samsung,exynos-adc-v1"; reg = <0x12D10000 0x100>; interrupts = ; @@ -739,15 +746,7 @@ status = "disabled"; }; - sss@10830000 { - compatible = "samsung,exynos4210-secss"; - reg = <0x10830000 0x300>; - interrupts = ; - clocks = <&clock CLK_SSS>; - clock-names = "secss"; - }; - - sysmmu_g2d: sysmmu@10A60000 { + sysmmu_g2d: sysmmu@10a60000 { compatible = "samsung,exynos-sysmmu"; reg = <0x10A60000 0x1000>; interrupt-parent = <&combiner>; @@ -779,7 +778,7 @@ #iommu-cells = <0>; }; - sysmmu_rotator: sysmmu@11D40000 { + sysmmu_rotator: sysmmu@11d40000 { compatible = "samsung,exynos-sysmmu"; reg = <0x11D40000 0x1000>; interrupt-parent = <&combiner>; @@ -789,7 +788,7 @@ #iommu-cells = <0>; }; - sysmmu_jpeg: sysmmu@11F20000 { + sysmmu_jpeg: sysmmu@11f20000 { compatible = "samsung,exynos-sysmmu"; reg = <0x11F20000 0x1000>; interrupt-parent = <&combiner>; @@ -820,7 +819,7 @@ #iommu-cells = <0>; }; - sysmmu_fimc_fd: sysmmu@132A0000 { + sysmmu_fimc_fd: sysmmu@132a0000 { compatible = "samsung,exynos-sysmmu"; reg = <0x132A0000 0x1000>; interrupt-parent = <&combiner>; @@ -850,7 +849,7 @@ #iommu-cells = <0>; }; - sysmmu_fimc_mcuctl: sysmmu@132B0000 { + sysmmu_fimc_mcuctl: sysmmu@132b0000 { compatible = "samsung,exynos-sysmmu"; reg = <0x132B0000 0x1000>; interrupt-parent = <&combiner>; @@ -860,7 +859,7 @@ #iommu-cells = <0>; }; - sysmmu_fimc_odc: sysmmu@132C0000 { + sysmmu_fimc_odc: sysmmu@132c0000 { compatible = "samsung,exynos-sysmmu"; reg = <0x132C0000 0x1000>; interrupt-parent = <&combiner>; @@ -870,7 +869,7 @@ #iommu-cells = <0>; }; - sysmmu_fimc_dis0: sysmmu@132D0000 { + sysmmu_fimc_dis0: sysmmu@132d0000 { compatible = "samsung,exynos-sysmmu"; reg = <0x132D0000 0x1000>; interrupt-parent = <&combiner>; @@ -890,7 +889,7 @@ #iommu-cells = <0>; }; - sysmmu_fimc_3dnr: sysmmu@132F0000 { + sysmmu_fimc_3dnr: sysmmu@132f0000 { compatible = "samsung,exynos-sysmmu"; reg = <0x132F0000 0x1000>; interrupt-parent = <&combiner>; @@ -900,7 +899,7 @@ #iommu-cells = <0>; }; - sysmmu_fimc_lite0: sysmmu@13C40000 { + sysmmu_fimc_lite0: sysmmu@13c40000 { compatible = "samsung,exynos-sysmmu"; reg = <0x13C40000 0x1000>; interrupt-parent = <&combiner>; @@ -911,7 +910,7 @@ #iommu-cells = <0>; }; - sysmmu_fimc_lite1: sysmmu@13C50000 { + sysmmu_fimc_lite1: sysmmu@13c50000 { compatible = "samsung,exynos-sysmmu"; reg = <0x13C50000 0x1000>; interrupt-parent = <&combiner>; @@ -922,7 +921,7 @@ #iommu-cells = <0>; }; - sysmmu_gsc0: sysmmu@13E80000 { + sysmmu_gsc0: sysmmu@13e80000 { compatible = "samsung,exynos-sysmmu"; reg = <0x13E80000 0x1000>; interrupt-parent = <&combiner>; @@ -933,7 +932,7 @@ #iommu-cells = <0>; }; - sysmmu_gsc1: sysmmu@13E90000 { + sysmmu_gsc1: sysmmu@13e90000 { compatible = "samsung,exynos-sysmmu"; reg = <0x13E90000 0x1000>; interrupt-parent = <&combiner>; @@ -944,7 +943,7 @@ #iommu-cells = <0>; }; - sysmmu_gsc2: sysmmu@13EA0000 { + sysmmu_gsc2: sysmmu@13ea0000 { compatible = "samsung,exynos-sysmmu"; reg = <0x13EA0000 0x1000>; interrupt-parent = <&combiner>; @@ -955,7 +954,7 @@ #iommu-cells = <0>; }; - sysmmu_gsc3: sysmmu@13EB0000 { + sysmmu_gsc3: sysmmu@13eb0000 { compatible = "samsung,exynos-sysmmu"; reg = <0x13EB0000 0x1000>; interrupt-parent = <&combiner>; @@ -1024,6 +1023,13 @@ iommus = <&sysmmu_fimd1>; }; +&g2d { + iommus = <&sysmmu_g2d>; + clocks = <&clock CLK_G2D>; + clock-names = "fimg2d"; + status = "okay"; +}; + &i2c_0 { clocks = <&clock CLK_I2C0>; clock-names = "i2c"; @@ -1052,6 +1058,11 @@ pinctrl-0 = <&i2c3_bus>; }; +&prng { + clocks = <&clock CLK_SSS>; + clock-names = "secss"; +}; + &pwm { clocks = <&clock CLK_PWM>; clock-names = "timers"; @@ -1092,4 +1103,14 @@ dma-names = "rx", "tx"; }; +&sss { + clocks = <&clock CLK_SSS>; + clock-names = "secss"; +}; + +&trng { + clocks = <&clock CLK_SSS>; + clock-names = "secss"; +}; + #include "exynos5250-pinctrl.dtsi" diff --git a/arch/arm/boot/dts/exynos5260-pinctrl.dtsi b/arch/arm/boot/dts/exynos5260-pinctrl.dtsi index 1b911a219a27..b1edb20b789e 100644 --- a/arch/arm/boot/dts/exynos5260-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos5260-pinctrl.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos5260 SoC pin-mux and pin-config device tree source * @@ -6,11 +7,7 @@ * * Samsung's Exynos5260 SoC pin-mux and pin-config options are listed as device * tree nodes are listed in this file. - * - * 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. -*/ + */ #include diff --git a/arch/arm/boot/dts/exynos5260-xyref5260.dts b/arch/arm/boot/dts/exynos5260-xyref5260.dts index 73b7cdd5f522..442eb0353f29 100644 --- a/arch/arm/boot/dts/exynos5260-xyref5260.dts +++ b/arch/arm/boot/dts/exynos5260-xyref5260.dts @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SAMSUNG XYREF5260 board device tree source * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.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. -*/ + */ /dts-v1/; #include "exynos5260.dtsi" diff --git a/arch/arm/boot/dts/exynos5260.dtsi b/arch/arm/boot/dts/exynos5260.dtsi index 5e88c9645975..55167850619c 100644 --- a/arch/arm/boot/dts/exynos5260.dtsi +++ b/arch/arm/boot/dts/exynos5260.dtsi @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SAMSUNG EXYNOS5260 SoC device tree source * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.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. -*/ + */ #include #include @@ -106,13 +103,13 @@ #clock-cells = <1>; }; - clock_g2d: clock-controller@10A00000 { + clock_g2d: clock-controller@10a00000 { compatible = "samsung,exynos5260-clock-g2d"; reg = <0x10A00000 0x10000>; #clock-cells = <1>; }; - clock_mif: clock-controller@10CE0000 { + clock_mif: clock-controller@10ce0000 { compatible = "samsung,exynos5260-clock-mif"; reg = <0x10CE0000 0x10000>; #clock-cells = <1>; @@ -130,25 +127,25 @@ #clock-cells = <1>; }; - clock_fsys: clock-controller@122E0000 { + clock_fsys: clock-controller@122e0000 { compatible = "samsung,exynos5260-clock-fsys"; reg = <0x122E0000 0x10000>; #clock-cells = <1>; }; - clock_aud: clock-controller@128C0000 { + clock_aud: clock-controller@128c0000 { compatible = "samsung,exynos5260-clock-aud"; reg = <0x128C0000 0x10000>; #clock-cells = <1>; }; - clock_isp: clock-controller@133C0000 { + clock_isp: clock-controller@133c0000 { compatible = "samsung,exynos5260-clock-isp"; reg = <0x133C0000 0x10000>; #clock-cells = <1>; }; - clock_gscl: clock-controller@13F00000 { + clock_gscl: clock-controller@13f00000 { compatible = "samsung,exynos5260-clock-gscl"; reg = <0x13F00000 0x10000>; #clock-cells = <1>; @@ -179,7 +176,7 @@ reg = <0x10000000 0x100>; }; - mct: mct@100B0000 { + mct: mct@100b0000 { compatible = "samsung,exynos4210-mct"; reg = <0x100B0000 0x1000>; clocks = <&fin_pll>, <&clock_peri PERI_CLK_MCT>; @@ -198,7 +195,7 @@ ; }; - cci: cci@10F00000 { + cci: cci@10f00000 { compatible = "arm,cci-400"; #address-cells = <1>; #size-cells = <1>; @@ -236,18 +233,18 @@ interrupts = ; }; - pinctrl_2: pinctrl@128B0000 { + pinctrl_2: pinctrl@128b0000 { compatible = "samsung,exynos5260-pinctrl"; reg = <0x128B0000 0x1000>; interrupts = ; }; - pmu_system_controller: system-controller@10D50000 { + pmu_system_controller: system-controller@10d50000 { compatible = "samsung,exynos5260-pmu", "syscon"; reg = <0x10D50000 0x10000>; }; - uart0: serial@12C00000 { + uart0: serial@12c00000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C00000 0x100>; interrupts = ; @@ -256,7 +253,7 @@ status = "disabled"; }; - uart1: serial@12C10000 { + uart1: serial@12c10000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C10000 0x100>; interrupts = ; @@ -265,7 +262,7 @@ status = "disabled"; }; - uart2: serial@12C20000 { + uart2: serial@12c20000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C20000 0x100>; interrupts = ; diff --git a/arch/arm/boot/dts/exynos5410-odroidxu.dts b/arch/arm/boot/dts/exynos5410-odroidxu.dts index a45eaae33f8f..a2046f5f998c 100644 --- a/arch/arm/boot/dts/exynos5410-odroidxu.dts +++ b/arch/arm/boot/dts/exynos5410-odroidxu.dts @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Hardkernel Odroid XU board device tree source * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * Copyright (c) 2016 Krzysztof Kozlowski - * - * 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. */ /dts-v1/; diff --git a/arch/arm/boot/dts/exynos5410-pinctrl.dtsi b/arch/arm/boot/dts/exynos5410-pinctrl.dtsi index ff46a1c27182..369a8a7f2105 100644 --- a/arch/arm/boot/dts/exynos5410-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos5410-pinctrl.dtsi @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Exynos5410 SoC pin-mux and pin-config device tree source * * Copyright (c) 2013 Hardkernel Co., Ltd. * http://www.hardkernel.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. */ #include diff --git a/arch/arm/boot/dts/exynos5410-smdk5410.dts b/arch/arm/boot/dts/exynos5410-smdk5410.dts index 25f21e9e7d58..8fc8c841d34b 100644 --- a/arch/arm/boot/dts/exynos5410-smdk5410.dts +++ b/arch/arm/boot/dts/exynos5410-smdk5410.dts @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SAMSUNG SMDK5410 board device tree source * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.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. -*/ + */ /dts-v1/; #include "exynos5410.dtsi" diff --git a/arch/arm/boot/dts/exynos5410.dtsi b/arch/arm/boot/dts/exynos5410.dtsi index 06713ec86f0d..1886aa00b2db 100644 --- a/arch/arm/boot/dts/exynos5410.dtsi +++ b/arch/arm/boot/dts/exynos5410.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SAMSUNG EXYNOS5410 SoC device tree source * @@ -7,10 +8,6 @@ * SAMSUNG EXYNOS5410 SoC device nodes are listed in this file. * EXYNOS5410 based board files can include this file and provide * values for board specfic bindings. - * - * 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. */ #include "exynos54xx.dtsi" @@ -264,6 +261,11 @@ }; }; +&arm_a15_pmu { + interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; + status = "okay"; +}; + &i2c_0 { clocks = <&clock CLK_I2C0>; clock-names = "i2c"; @@ -325,6 +327,11 @@ clock-names = "fin_pll", "mct"; }; +&prng { + clocks = <&clock CLK_SSS>; + clock-names = "secss"; +}; + &pwm { clocks = <&clock CLK_PWM>; clock-names = "timers"; @@ -333,7 +340,6 @@ &rtc { clocks = <&clock CLK_RTC>; clock-names = "rtc"; - interrupt-parent = <&pmu_system_controller>; status = "disabled"; }; @@ -379,6 +385,11 @@ 3 0 0x07000000 0x20000>; }; +&trng { + clocks = <&clock CLK_SSS>; + clock-names = "secss"; +}; + &usbdrd3_0 { clocks = <&clock CLK_USBD300>; clock-names = "usbdrd30"; diff --git a/arch/arm/boot/dts/exynos5420-arndale-octa.dts b/arch/arm/boot/dts/exynos5420-arndale-octa.dts index bc78575d8a4d..cdda614e417e 100644 --- a/arch/arm/boot/dts/exynos5420-arndale-octa.dts +++ b/arch/arm/boot/dts/exynos5420-arndale-octa.dts @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos5420 based Arndale Octa board device tree source * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.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. -*/ + */ /dts-v1/; #include "exynos5420.dtsi" diff --git a/arch/arm/boot/dts/exynos5420-cpus.dtsi b/arch/arm/boot/dts/exynos5420-cpus.dtsi index d7d703aa1699..123f0cef658d 100644 --- a/arch/arm/boot/dts/exynos5420-cpus.dtsi +++ b/arch/arm/boot/dts/exynos5420-cpus.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SAMSUNG EXYNOS5420 SoC cpu device tree source * @@ -14,10 +15,6 @@ * booting cluster (big or LITTLE) is chosen by IROM code by reading * the gpg2-1 GPIO. By default all Exynos5422 based boards choose booting * from the LITTLE: Cortex-A7. - * - * 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. */ / { @@ -132,3 +129,13 @@ }; }; }; + +&arm_a7_pmu { + interrupt-affinity = <&cpu4>, <&cpu5>, <&cpu6>, <&cpu7>; + status = "okay"; +}; + +&arm_a15_pmu { + interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts index 38af8769711c..5a76ed77dda1 100644 --- a/arch/arm/boot/dts/exynos5420-peach-pit.dts +++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Google Peach Pit Rev 6+ board device tree source * * Copyright (c) 2014 Google, Inc - * - * 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. */ /dts-v1/; diff --git a/arch/arm/boot/dts/exynos5420-pinctrl.dtsi b/arch/arm/boot/dts/exynos5420-pinctrl.dtsi index 65aa0e300c23..dda8ca2d2324 100644 --- a/arch/arm/boot/dts/exynos5420-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos5420-pinctrl.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos5420 SoC pin-mux and pin-config device tree source * @@ -6,11 +7,7 @@ * * Samsung's Exynos5420 SoC pin-mux and pin-config options are listed as device * tree nodes are listed in this file. - * - * 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. -*/ + */ #include diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts index 310d8637ce9f..831c7336f237 100644 --- a/arch/arm/boot/dts/exynos5420-smdk5420.dts +++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SAMSUNG SMDK5420 board device tree source * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.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. -*/ + */ /dts-v1/; #include "exynos5420.dtsi" diff --git a/arch/arm/boot/dts/exynos5420-tmu-sensor-conf.dtsi b/arch/arm/boot/dts/exynos5420-tmu-sensor-conf.dtsi index c8771c660550..fbc77cb58473 100644 --- a/arch/arm/boot/dts/exynos5420-tmu-sensor-conf.dtsi +++ b/arch/arm/boot/dts/exynos5420-tmu-sensor-conf.dtsi @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Device tree sources for Exynos5420 TMU sensor configuration * * Copyright (c) 2014 Lukasz Majewski * Copyright (c) 2017 Krzysztof Kozlowski - * - * 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. - * */ #include diff --git a/arch/arm/boot/dts/exynos5420-trip-points.dtsi b/arch/arm/boot/dts/exynos5420-trip-points.dtsi index 2180a0152c9b..a67a380717ec 100644 --- a/arch/arm/boot/dts/exynos5420-trip-points.dtsi +++ b/arch/arm/boot/dts/exynos5420-trip-points.dtsi @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Device tree sources for default Exynos5420 thermal zone definition * * Copyright (c) 2014 Lukasz Majewski - * - * 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. - * */ polling-delay-passive = <0>; diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index 8aa2cc7aa125..2f3cb2a97f71 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SAMSUNG EXYNOS5420 SoC device tree source * @@ -7,10 +8,6 @@ * SAMSUNG EXYNOS54200 SoC device nodes are listed in this file. * EXYNOS5420 based board files can include this file and provide * values for board specfic bindings. - * - * 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. */ #include "exynos54xx.dtsi" @@ -188,6 +185,7 @@ clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MAU_EPLL>, <&clock CLK_SCLK_MAUDIO0>, <&clock CLK_SCLK_MAUPCM0>; clock-names = "pll_ref", "pll_in", "sclk_audio", "sclk_pcm_in"; + power-domains = <&mau_pd>; }; mfc: codec@11000000 { @@ -237,37 +235,37 @@ status = "disabled"; }; - nocp_mem0_0: nocp@10CA1000 { + nocp_mem0_0: nocp@10ca1000 { compatible = "samsung,exynos5420-nocp"; reg = <0x10CA1000 0x200>; status = "disabled"; }; - nocp_mem0_1: nocp@10CA1400 { + nocp_mem0_1: nocp@10ca1400 { compatible = "samsung,exynos5420-nocp"; reg = <0x10CA1400 0x200>; status = "disabled"; }; - nocp_mem1_0: nocp@10CA1800 { + nocp_mem1_0: nocp@10ca1800 { compatible = "samsung,exynos5420-nocp"; reg = <0x10CA1800 0x200>; status = "disabled"; }; - nocp_mem1_1: nocp@10CA1C00 { + nocp_mem1_1: nocp@10ca1c00 { compatible = "samsung,exynos5420-nocp"; reg = <0x10CA1C00 0x200>; status = "disabled"; }; - nocp_g3d_0: nocp@11A51000 { + nocp_g3d_0: nocp@11a51000 { compatible = "samsung,exynos5420-nocp"; reg = <0x11A51000 0x200>; status = "disabled"; }; - nocp_g3d_1: nocp@11A51400 { + nocp_g3d_1: nocp@11a51400 { compatible = "samsung,exynos5420-nocp"; reg = <0x11A51400 0x200>; status = "disabled"; @@ -309,7 +307,7 @@ label = "MSC"; }; - disp_pd: power-domain@100440C0 { + disp_pd: power-domain@100440c0 { compatible = "samsung,exynos4210-pd"; reg = <0x100440C0 0x20>; #power-domain-cells = <0>; @@ -322,6 +320,13 @@ clock-names = "oscclk", "clk0", "clk1", "clk2", "asb0", "asb1"; }; + mau_pd: power-domain@100440e0 { + compatible = "samsung,exynos4210-pd"; + reg = <0x100440E0 0x20>; + #power-domain-cells = <0>; + label = "MAU"; + }; + pinctrl_0: pinctrl@13400000 { compatible = "samsung,exynos5420-pinctrl"; reg = <0x13400000 0x1000>; @@ -356,6 +361,7 @@ compatible = "samsung,exynos5420-pinctrl"; reg = <0x03860000 0x1000>; interrupts = ; + power-domains = <&mau_pd>; }; amba { @@ -374,9 +380,10 @@ #dma-cells = <1>; #dma-channels = <6>; #dma-requests = <16>; + power-domains = <&mau_pd>; }; - pdma0: pdma@121A0000 { + pdma0: pdma@121a0000 { compatible = "arm,pl330", "arm,primecell"; reg = <0x121A0000 0x1000>; interrupts = ; @@ -387,7 +394,7 @@ #dma-requests = <32>; }; - pdma1: pdma@121B0000 { + pdma1: pdma@121b0000 { compatible = "arm,pl330", "arm,primecell"; reg = <0x121B0000 0x1000>; interrupts = ; @@ -409,7 +416,7 @@ #dma-requests = <1>; }; - mdma1: mdma@11C10000 { + mdma1: mdma@11c10000 { compatible = "arm,pl330", "arm,primecell"; reg = <0x11C10000 0x1000>; interrupts = ; @@ -446,10 +453,11 @@ samsung,idma-addr = <0x03000000>; pinctrl-names = "default"; pinctrl-0 = <&i2s0_bus>; + power-domains = <&mau_pd>; status = "disabled"; }; - i2s1: i2s@12D60000 { + i2s1: i2s@12d60000 { compatible = "samsung,exynos5420-i2s"; reg = <0x12D60000 0x100>; dmas = <&pdma1 12 @@ -465,7 +473,7 @@ status = "disabled"; }; - i2s2: i2s@12D70000 { + i2s2: i2s@12d70000 { compatible = "samsung,exynos5420-i2s"; reg = <0x12D70000 0x100>; dmas = <&pdma0 12 @@ -554,7 +562,7 @@ status = "disabled"; }; - adc: adc@12D10000 { + adc: adc@12d10000 { compatible = "samsung,exynos-adc-v2"; reg = <0x12D10000 0x100>; interrupts = ; @@ -566,7 +574,7 @@ status = "disabled"; }; - hsi2c_8: i2c@12E00000 { + hsi2c_8: i2c@12e00000 { compatible = "samsung,exynos5250-hsi2c"; reg = <0x12E00000 0x1000>; interrupts = ; @@ -579,7 +587,7 @@ status = "disabled"; }; - hsi2c_9: i2c@12E10000 { + hsi2c_9: i2c@12e10000 { compatible = "samsung,exynos5250-hsi2c"; reg = <0x12E10000 0x1000>; interrupts = ; @@ -592,7 +600,7 @@ status = "disabled"; }; - hsi2c_10: i2c@12E20000 { + hsi2c_10: i2c@12e20000 { compatible = "samsung,exynos5250-hsi2c"; reg = <0x12E20000 0x1000>; interrupts = ; @@ -618,13 +626,14 @@ samsung,syscon-phandle = <&pmu_system_controller>; status = "disabled"; power-domains = <&disp_pd>; + #sound-dai-cells = <0>; }; - hdmiphy: hdmiphy@145D0000 { + hdmiphy: hdmiphy@145d0000 { reg = <0x145D0000 0x20>; }; - hdmicec: cec@101B0000 { + hdmicec: cec@101b0000 { compatible = "samsung,s5p-cec"; reg = <0x101B0000 0x200>; interrupts = ; @@ -649,7 +658,7 @@ status = "disabled"; }; - rotator: rotator@11C00000 { + rotator: rotator@11c00000 { compatible = "samsung,exynos5250-rotator"; reg = <0x11C00000 0x64>; interrupts = ; @@ -678,7 +687,7 @@ iommus = <&sysmmu_gscl1>; }; - jpeg_0: jpeg@11F50000 { + jpeg_0: jpeg@11f50000 { compatible = "samsung,exynos5420-jpeg"; reg = <0x11F50000 0x1000>; interrupts = ; @@ -687,7 +696,7 @@ iommus = <&sysmmu_jpeg0>; }; - jpeg_1: jpeg@11F60000 { + jpeg_1: jpeg@11f60000 { compatible = "samsung,exynos5420-jpeg"; reg = <0x11F60000 0x1000>; interrupts = ; @@ -1349,6 +1358,13 @@ iommu-names = "m0", "m1"; }; +&g2d { + iommus = <&sysmmu_g2dr>, <&sysmmu_g2dw>; + clocks = <&clock CLK_G2D>; + clock-names = "fimg2d"; + status = "okay"; +}; + &i2c_0 { clocks = <&clock CLK_I2C0>; clock-names = "i2c"; @@ -1410,6 +1426,11 @@ clock-names = "fin_pll", "mct"; }; +&prng { + clocks = <&clock CLK_SSS>; + clock-names = "secss"; +}; + &pwm { clocks = <&clock CLK_PWM>; clock-names = "timers"; @@ -1455,6 +1476,11 @@ clock-names = "secss"; }; +&trng { + clocks = <&clock CLK_SSS>; + clock-names = "secss"; +}; + &usbdrd3_0 { clocks = <&clock CLK_USBD300>; clock-names = "usbdrd30"; diff --git a/arch/arm/boot/dts/exynos5422-cpus.dtsi b/arch/arm/boot/dts/exynos5422-cpus.dtsi index ec01d8020c2d..c593809c7f08 100644 --- a/arch/arm/boot/dts/exynos5422-cpus.dtsi +++ b/arch/arm/boot/dts/exynos5422-cpus.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SAMSUNG EXYNOS5422 SoC cpu device tree source * @@ -13,10 +14,6 @@ * booting cluster (big or LITTLE) is chosen by IROM code by reading * the gpg2-1 GPIO. By default all Exynos5422 based boards choose booting * from the LITTLE: Cortex-A7. - * - * 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. */ / { @@ -131,3 +128,13 @@ }; }; }; + +&arm_a7_pmu { + interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; + status = "okay"; +}; + +&arm_a15_pmu { + interrupt-affinity = <&cpu4>, <&cpu5>, <&cpu6>, <&cpu7>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/exynos5422-odroid-core.dtsi b/arch/arm/boot/dts/exynos5422-odroid-core.dtsi index a5b8d0f0877e..d31249f25ccf 100644 --- a/arch/arm/boot/dts/exynos5422-odroid-core.dtsi +++ b/arch/arm/boot/dts/exynos5422-odroid-core.dtsi @@ -1,14 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Hardkernel Odroid XU3/XU4/HC1 boards core device tree source * * Copyright (c) 2017 Marek Szyprowski * Copyright (c) 2013-2017 Samsung Electronics Co., Ltd. * http://www.samsung.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. -*/ + */ #include #include @@ -233,8 +230,8 @@ ldo15_reg: LDO15 { regulator-name = "vdd_ldo15"; - regulator-min-microvolt = <3100000>; - regulator-max-microvolt = <3100000>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; regulator-always-on; }; @@ -246,7 +243,7 @@ }; ldo17_reg: LDO17 { - regulator-name = "tsp_avdd"; + regulator-name = "vdd_ldo17"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; diff --git a/arch/arm/boot/dts/exynos5422-odroidhc1.dts b/arch/arm/boot/dts/exynos5422-odroidhc1.dts index fb8e8ae776e9..8f332be143f7 100644 --- a/arch/arm/boot/dts/exynos5422-odroidhc1.dts +++ b/arch/arm/boot/dts/exynos5422-odroidhc1.dts @@ -1,14 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Hardkernel Odroid HC1 board device tree source * * Copyright (c) 2017 Marek Szyprowski * Copyright (c) 2017 Samsung Electronics Co., Ltd. * http://www.samsung.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. -*/ + */ /dts-v1/; #include "exynos5422-odroid-core.dtsi" diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi b/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi index da3141a307d5..03611d50c5a9 100644 --- a/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi +++ b/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi @@ -1,27 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Hardkernel Odroid XU3 Audio Codec device tree source + * Hardkernel Odroid XU3 audio subsystem device tree source * * Copyright (c) 2015 Krzysztof Kozlowski * Copyright (c) 2014 Collabora Ltd. * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.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. -*/ + */ #include / { sound: sound { - compatible = "simple-audio-card"; + compatible = "samsung,odroid-xu3-audio"; + model = "Odroid-XU3"; - simple-audio-card,name = "Odroid-XU3"; - simple-audio-card,widgets = + samsung,audio-widgets = "Headphone", "Headphone Jack", "Speakers", "Speakers"; - simple-audio-card,routing = + samsung,audio-routing = "Headphone Jack", "HPL", "Headphone Jack", "HPR", "Headphone Jack", "MICBIAS", @@ -29,31 +26,47 @@ "Speakers", "SPKL", "Speakers", "SPKR"; - simple-audio-card,format = "i2s"; - simple-audio-card,bitclock-master = <&link0_codec>; - simple-audio-card,frame-master = <&link0_codec>; + assigned-clocks = <&i2s0 CLK_I2S_RCLK_SRC>, + <&clock CLK_MOUT_EPLL>, + <&clock CLK_MOUT_MAU_EPLL>, + <&clock CLK_MOUT_USER_MAU_EPLL>, + <&clock_audss EXYNOS_MOUT_AUDSS>, + <&clock_audss EXYNOS_MOUT_I2S>, + <&clock_audss EXYNOS_DOUT_SRP>, + <&clock_audss EXYNOS_DOUT_AUD_BUS>, + <&clock_audss EXYNOS_DOUT_I2S>; - simple-audio-card,cpu { + assigned-clock-parents = <&clock_audss EXYNOS_SCLK_I2S>, + <&clock CLK_FOUT_EPLL>, + <&clock CLK_MOUT_EPLL>, + <&clock CLK_MOUT_MAU_EPLL>, + <&clock CLK_MAU_EPLL>, + <&clock_audss EXYNOS_MOUT_AUDSS>; + + assigned-clock-rates = <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <196608001>, + <(196608002 / 2)>, + <196608000>; + + cpu { sound-dai = <&i2s0 0>; - system-clock-frequency = <19200000>; }; - - link0_codec: simple-audio-card,codec { - sound-dai = <&max98090>; - clocks = <&i2s0 CLK_I2S_CDCLK>; + codec { + sound-dai = <&hdmi>, <&max98090>; }; }; }; &clock_audss { - assigned-clocks = <&clock_audss EXYNOS_MOUT_AUDSS>, - <&clock_audss EXYNOS_MOUT_I2S>, - <&clock_audss EXYNOS_DOUT_AUD_BUS>; - assigned-clock-parents = <&clock CLK_FIN_PLL>, - <&clock_audss EXYNOS_MOUT_AUDSS>; - assigned-clock-rates = <0>, - <0>, - <19200000>; + assigned-clocks = <&clock_audss EXYNOS_DOUT_SRP>, + <&clock CLK_FOUT_EPLL>; + assigned-clock-rates = <(196608000 / 256)>, + <196608000>; }; &hsi2c_5 { diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi index 445c6c5a1300..96e281c0a118 100644 --- a/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi +++ b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Hardkernel Odroid XU3 board device tree source * @@ -6,11 +7,7 @@ * Copyright (c) 2014 Collabora Ltd. * Copyright (c) 2015 Lukasz Majewski * Anand Moon - * - * 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. -*/ + */ #include #include "exynos5422-odroid-core.dtsi" diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts b/arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts index 03fa88c45426..0db935f2b836 100644 --- a/arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts +++ b/arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Hardkernel Odroid XU3-Lite board device tree source * @@ -5,11 +6,7 @@ * Copyright (c) 2014 Collabora Ltd. * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.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. -*/ + */ /dts-v1/; #include "exynos5422-odroidxu3-common.dtsi" diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3.dts b/arch/arm/boot/dts/exynos5422-odroidxu3.dts index 9ed6564acfb0..0322f281912c 100644 --- a/arch/arm/boot/dts/exynos5422-odroidxu3.dts +++ b/arch/arm/boot/dts/exynos5422-odroidxu3.dts @@ -1,14 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Hardkernel Odroid XU3 board device tree source * * Copyright (c) 2014 Collabora Ltd. * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.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. -*/ + */ /dts-v1/; #include "exynos5422-odroidxu3-common.dtsi" diff --git a/arch/arm/boot/dts/exynos5422-odroidxu4.dts b/arch/arm/boot/dts/exynos5422-odroidxu4.dts index 2faf88627a48..4a30cc849b00 100644 --- a/arch/arm/boot/dts/exynos5422-odroidxu4.dts +++ b/arch/arm/boot/dts/exynos5422-odroidxu4.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Hardkernel Odroid XU4 board device tree source * @@ -5,13 +6,10 @@ * Copyright (c) 2014 Collabora Ltd. * Copyright (c) 2013-2015 Samsung Electronics Co., Ltd. * http://www.samsung.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. -*/ + */ /dts-v1/; +#include #include "exynos5422-odroidxu3-common.dtsi" / { @@ -30,6 +28,57 @@ linux,default-trigger = "heartbeat"; }; }; + + sound: sound { + compatible = "samsung,odroid-xu3-audio"; + model = "Odroid-XU4"; + + assigned-clocks = <&i2s0 CLK_I2S_RCLK_SRC>, + <&clock CLK_MOUT_EPLL>, + <&clock CLK_MOUT_MAU_EPLL>, + <&clock CLK_MOUT_USER_MAU_EPLL>, + <&clock_audss EXYNOS_MOUT_AUDSS>, + <&clock_audss EXYNOS_MOUT_I2S>, + <&clock_audss EXYNOS_DOUT_SRP>, + <&clock_audss EXYNOS_DOUT_AUD_BUS>, + <&clock_audss EXYNOS_DOUT_I2S>; + + assigned-clock-parents = <&clock_audss EXYNOS_SCLK_I2S>, + <&clock CLK_FOUT_EPLL>, + <&clock CLK_MOUT_EPLL>, + <&clock CLK_MOUT_MAU_EPLL>, + <&clock CLK_MAU_EPLL>, + <&clock_audss EXYNOS_MOUT_AUDSS>; + + assigned-clock-rates = <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <196608001>, + <(196608002 / 2)>, + <196608000>; + + cpu { + sound-dai = <&i2s0 0>; + }; + + codec { + sound-dai = <&hdmi>; + }; + }; +}; + +&clock_audss { + assigned-clocks = <&clock_audss EXYNOS_DOUT_SRP>, + <&clock CLK_FOUT_EPLL>; + assigned-clock-rates = <(196608000 / 256)>, + <196608000>; +}; + +&i2s0 { + status = "okay"; }; &pwm { diff --git a/arch/arm/boot/dts/exynos5440-sd5v1.dts b/arch/arm/boot/dts/exynos5440-sd5v1.dts index ad6f533b3f40..c4b8392d1ae1 100644 --- a/arch/arm/boot/dts/exynos5440-sd5v1.dts +++ b/arch/arm/boot/dts/exynos5440-sd5v1.dts @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SAMSUNG SD5v1 board device tree source * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.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. -*/ + */ /dts-v1/; #include "exynos5440.dtsi" diff --git a/arch/arm/boot/dts/exynos5440-ssdk5440.dts b/arch/arm/boot/dts/exynos5440-ssdk5440.dts index 7eafad333bdb..a33c4fc29ae5 100644 --- a/arch/arm/boot/dts/exynos5440-ssdk5440.dts +++ b/arch/arm/boot/dts/exynos5440-ssdk5440.dts @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SAMSUNG SSDK5440 board device tree source * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.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. -*/ + */ /dts-v1/; #include "exynos5440.dtsi" diff --git a/arch/arm/boot/dts/exynos5440-tmu-sensor-conf.dtsi b/arch/arm/boot/dts/exynos5440-tmu-sensor-conf.dtsi index 7b2fba0ae92b..0421c3d42905 100644 --- a/arch/arm/boot/dts/exynos5440-tmu-sensor-conf.dtsi +++ b/arch/arm/boot/dts/exynos5440-tmu-sensor-conf.dtsi @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Device tree sources for Exynos5440 TMU sensor configuration * * Copyright (c) 2014 Lukasz Majewski - * - * 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. - * */ #include diff --git a/arch/arm/boot/dts/exynos5440-trip-points.dtsi b/arch/arm/boot/dts/exynos5440-trip-points.dtsi index 356e963edf11..a2b04fed7d0b 100644 --- a/arch/arm/boot/dts/exynos5440-trip-points.dtsi +++ b/arch/arm/boot/dts/exynos5440-trip-points.dtsi @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Device tree sources for default Exynos5440 thermal zone definition * * Copyright (c) 2014 Lukasz Majewski - * - * 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. - * */ polling-delay-passive = <0>; diff --git a/arch/arm/boot/dts/exynos5440.dtsi b/arch/arm/boot/dts/exynos5440.dtsi index 9c3c75ae5e48..fce9e26b5930 100644 --- a/arch/arm/boot/dts/exynos5440.dtsi +++ b/arch/arm/boot/dts/exynos5440.dtsi @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SAMSUNG EXYNOS5440 SoC device tree source * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.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. -*/ + */ #include #include @@ -35,7 +32,7 @@ #clock-cells = <1>; }; - gic: interrupt-controller@2E0000 { + gic: interrupt-controller@2e0000 { compatible = "arm,cortex-a15-gic"; #interrupt-cells = <3>; interrupt-controller; @@ -108,7 +105,7 @@ >; }; - serial_0: serial@B0000 { + serial_0: serial@b0000 { compatible = "samsung,exynos4210-uart"; reg = <0xB0000 0x1000>; interrupts = ; @@ -116,7 +113,7 @@ clock-names = "uart", "clk_uart_baud0"; }; - serial_1: serial@C0000 { + serial_1: serial@c0000 { compatible = "samsung,exynos4210-uart"; reg = <0xC0000 0x1000>; interrupts = ; @@ -124,7 +121,7 @@ clock-names = "uart", "clk_uart_baud0"; }; - spi_0: spi@D0000 { + spi_0: spi@d0000 { compatible = "samsung,exynos5440-spi"; reg = <0xD0000 0x100>; interrupts = ; @@ -136,7 +133,7 @@ clock-names = "spi", "spi_busclk0"; }; - pin_ctrl: pinctrl@E0000 { + pin_ctrl: pinctrl@e0000 { compatible = "samsung,exynos5440-pinctrl"; reg = <0xE0000 0x1000>; interrupts = , @@ -168,7 +165,7 @@ }; }; - i2c@F0000 { + i2c@f0000 { compatible = "samsung,exynos5440-i2c"; reg = <0xF0000 0x1000>; interrupts = ; @@ -233,7 +230,7 @@ #include "exynos5440-tmu-sensor-conf.dtsi" }; - tmuctrl_1: tmuctrl@16011C { + tmuctrl_1: tmuctrl@16011c { compatible = "samsung,exynos5440-tmu"; reg = <0x16011C 0x230>, <0x160368 0x10>; interrupts = ; diff --git a/arch/arm/boot/dts/exynos54xx-odroidxu-leds.dtsi b/arch/arm/boot/dts/exynos54xx-odroidxu-leds.dtsi index 0ed30206625c..56acd832f0b3 100644 --- a/arch/arm/boot/dts/exynos54xx-odroidxu-leds.dtsi +++ b/arch/arm/boot/dts/exynos54xx-odroidxu-leds.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Hardkernel Odroid XU/XU3 LED device tree source * @@ -5,11 +6,7 @@ * Copyright (c) 2014 Collabora Ltd. * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.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. -*/ + */ #include diff --git a/arch/arm/boot/dts/exynos54xx.dtsi b/arch/arm/boot/dts/exynos54xx.dtsi index a5007f182bc4..de26e5ee0d2d 100644 --- a/arch/arm/boot/dts/exynos54xx.dtsi +++ b/arch/arm/boot/dts/exynos54xx.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's Exynos54xx SoC series common device tree source * @@ -8,10 +9,6 @@ * Device nodes common for Samsung Exynos5410/5420/5422/5800. Specific * Exynos 54xx SoCs should include this file and customize it further * (e.g. with clocks). - * - * 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. */ #include "exynos5.dtsi" @@ -29,6 +26,26 @@ }; soc: soc { + arm_a7_pmu: arm-a7-pmu { + compatible = "arm,cortex-a7-pmu"; + interrupt-parent = <&gic>; + interrupts = , + , + , + ; + status = "disabled"; + }; + + arm_a15_pmu: arm-a15-pmu { + compatible = "arm,cortex-a15-pmu"; + interrupt-parent = <&combiner>; + interrupts = <1 2>, + <7 0>, + <16 6>, + <19 2>; + status = "disabled"; + }; + sysram@2020000 { compatible = "mmio-sram"; reg = <0x02020000 0x54000>; @@ -79,12 +96,6 @@ interrupts = ; }; - sss: sss@10830000 { - compatible = "samsung,exynos4210-secss"; - reg = <0x10830000 0x300>; - interrupts = ; - }; - /* i2c_0-3 are defined in exynos5.dtsi */ hsi2c_4: i2c@12ca0000 { compatible = "samsung,exynos5250-hsi2c"; diff --git a/arch/arm/boot/dts/ge863-pro3.dtsi b/arch/arm/boot/dts/ge863-pro3.dtsi index 6a9fdc0760f0..a7adbdc2f0c0 100644 --- a/arch/arm/boot/dts/ge863-pro3.dtsi +++ b/arch/arm/boot/dts/ge863-pro3.dtsi @@ -18,6 +18,18 @@ ahb { apb { + tcb0: timer@fffa0000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + dbgu: serial@fffff200 { status = "okay"; }; diff --git a/arch/arm/boot/dts/gemini-dlink-dir-685.dts b/arch/arm/boot/dts/gemini-dlink-dir-685.dts index e75e2d44371c..cadde92bc6b5 100644 --- a/arch/arm/boot/dts/gemini-dlink-dir-685.dts +++ b/arch/arm/boot/dts/gemini-dlink-dir-685.dts @@ -45,6 +45,47 @@ }; }; + vdisp: regulator { + compatible = "regulator-fixed"; + regulator-name = "display-power"; + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + /* Collides with LCD E */ + gpio = <&gpio0 16 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + spi { + compatible = "spi-gpio"; + #address-cells = <1>; + #size-cells = <0>; + + /* Collides with IDE pins, that's cool (we do not use them) */ + gpio-sck = <&gpio1 5 GPIO_ACTIVE_HIGH>; + gpio-miso = <&gpio1 8 GPIO_ACTIVE_HIGH>; + gpio-mosi = <&gpio1 7 GPIO_ACTIVE_HIGH>; + /* Collides with pflash CE1, not so cool */ + cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>; + num-chipselects = <1>; + + panel: display@0 { + compatible = "dlink,dir-685-panel", "ilitek,ili9322"; + reg = <0>; + /* 50 ns min period = 20 MHz */ + spi-max-frequency = <20000000>; + spi-cpol; /* Clock active low */ + vcc-supply = <&vdisp>; + iovcc-supply = <&vdisp>; + vci-supply = <&vdisp>; + + port { + panel_in: endpoint { + remote-endpoint = <&display_out>; + }; + }; + }; + }; + leds { compatible = "gpio-leds"; led-wps { @@ -99,8 +140,8 @@ gpio-i2c { compatible = "i2c-gpio"; /* Collides with ICE */ - gpios = <&gpio0 5 0>, /* SDA */ - <&gpio0 6 0>; /* SCL */ + sda-gpios = <&gpio0 5 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + scl-gpios = <&gpio0 6 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; #address-cells = <1>; #size-cells = <0>; @@ -115,7 +156,16 @@ soc { flash@30000000 { - status = "okay"; + /* + * Flash access is by default disabled, because it + * collides with the Chip Enable signal for the display + * panel, that reuse the parallel flash Chip Select 1 + * (CS1). Enabling flash makes graphics stop working. + * + * We might be able to hack around this by letting + * GPIO poke around in the flash controller registers. + */ + /* status = "okay"; */ /* 32MB of flash */ reg = <0x30000000 0x02000000>; @@ -242,5 +292,16 @@ ata@63000000 { status = "okay"; }; + + display-controller@6a000000 { + status = "okay"; + + port@0 { + reg = <0>; + display_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; }; }; diff --git a/arch/arm/boot/dts/gemini-dlink-dns-313.dts b/arch/arm/boot/dts/gemini-dlink-dns-313.dts new file mode 100644 index 000000000000..08568ce24d06 --- /dev/null +++ b/arch/arm/boot/dts/gemini-dlink-dns-313.dts @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree file for D-Link DNS-313 1-Bay Network Storage Enclosure + */ + +/dts-v1/; + +#include "gemini.dtsi" +#include +#include + +/ { + model = "D-Link DNS-313 1-Bay Network Storage Enclosure"; + compatible = "dlink,dir-313", "cortina,gemini"; + #address-cells = <1>; + #size-cells = <1>; + + memory { + /* 64 MB SDRAM in a Nanya NT5DS32M16BS-6K package */ + device_type = "memory"; + reg = <0x00000000 0x4000000>; + }; + + aliases { + mdio-gpio0 = &mdio0; + }; + + chosen { + stdout-path = "uart0:19200n8"; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + button-esc { + debounce_interval = <50>; + wakeup-source; + linux,code = ; + label = "reset"; + gpios = <&gpio1 31 GPIO_ACTIVE_LOW>; + }; + }; + + leds { + compatible = "gpio-leds"; + led-power { + label = "dns313:blue:power"; + gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + led-disk-blue { + label = "dns313:blue:disk"; + gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + led-disk-green { + label = "dns313:green:disk"; + gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "ide-disk"; + /* Ideally should activate while reading */ + }; + led-disk-red { + label = "dns313:red:disk"; + gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; + default-state = "off"; + /* Ideally should activate while writing */ + }; + }; + + /* + * This is a ADDA AD0405GB-G73 fan @3000 and 6000 RPM. + */ + fan0: gpio-fan { + compatible = "gpio-fan"; + gpios = <&gpio0 11 GPIO_ACTIVE_HIGH>, + <&gpio0 12 GPIO_ACTIVE_HIGH>; + gpio-fan,speed-map = <0 0>, <3000 1>, <6000 2>; + cooling-min-level = <0>; + cooling-max-level = <2>; + #cooling-cells = <2>; + }; + + + /* Global Mixed-Mode Technology G751 mounted on GPIO I2C */ + gpio-i2c { + compatible = "i2c-gpio"; + sda-gpios = <&gpio0 15 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + scl-gpios = <&gpio0 16 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + #address-cells = <1>; + #size-cells = <0>; + + g751: temperature-sensor@48 { + compatible = "gmt,g751"; + reg = <0x48>; + #thermal-sensor-cells = <0>; + }; + }; + + thermal-zones { + chassis-thermal { + /* Poll every 20 seconds */ + polling-delay = <20000>; + /* Poll every 2nd second when cooling */ + polling-delay-passive = <2000>; + + thermal-sensors = <&g751>; + + /* Tripping points from the fan.script in the rootfs */ + trips { + chassis_alert0: chassis-alert0 { + /* At 43 degrees turn on low speed */ + temperature = <43000>; + hysteresis = <3000>; + type = "active"; + }; + chassis_alert1: chassis-alert1 { + /* At 47 degrees turn on high speed */ + temperature = <47000>; + hysteresis = <3000>; + type = "active"; + }; + chassis_crit: chassis-crit { + /* Just shut down at 60 degrees */ + temperature = <60000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&chassis_alert0>; + cooling-device = <&fan0 1 1>; + }; + map1 { + trip = <&chassis_alert1>; + cooling-device = <&fan0 2 2>; + }; + }; + }; + }; + + mdio0: ethernet-phy { + compatible = "virtual,mdio-gpio"; + /* Uses MDC and MDIO */ + gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>, /* MDC */ + <&gpio0 21 GPIO_ACTIVE_HIGH>; /* MDIO */ + #address-cells = <1>; + #size-cells = <0>; + + /* This is a Realtek RTL8211B Gigabit ethernet transceiver */ + phy0: ethernet-phy@1 { + reg = <1>; + device_type = "ethernet-phy"; + }; + }; + + soc { + flash@30000000 { + status = "okay"; + /* 512KB of flash */ + reg = <0x30000000 0x00080000>; + + /* + * This "RedBoot" is the Storlink derivative. + */ + partition@0 { + label = "RedBoot"; + reg = <0x00000000 0x00040000>; + read-only; + }; + partition@40000 { + label = "MTD1"; + reg = <0x00040000 0x00020000>; + read-only; + }; + partition@60000 { + label = "MTD2"; + reg = <0x00060000 0x00020000>; + read-only; + }; + }; + + syscon: syscon@40000000 { + pinctrl { + /* + */ + gpio0_default_pins: pinctrl-gpio0 { + mux { + function = "gpio0"; + groups = + /* Used by LEDs conflicts ICE */ + "gpio0bgrp", + /* Used by ? conflicts ICE */ + "gpio0cgrp", + /* + * Used by fan & G751, conflicts LPC, + * UART modem lines, SSP + */ + "gpio0egrp", + /* Used by G751 */ + "gpio0fgrp", + /* Used by MDIO */ + "gpio0igrp"; + }; + }; + gpio1_default_pins: pinctrl-gpio1 { + mux { + function = "gpio1"; + /* Used by "reset" button */ + groups = "gpio1dgrp"; + }; + }; + pinctrl-gmii { + mux { + function = "gmii"; + groups = "gmii_gmac0_grp"; + }; + /* + * In the vendor Linux tree, these values are set for the C3 + * version of the SL3512 ASIC with the comment "benson suggest" + */ + conf0 { + pins = "R8 GMAC0 RXDV", "U11 GMAC1 RXDV"; + skew-delay = <0>; + }; + conf1 { + pins = "T8 GMAC0 RXC"; + skew-delay = <10>; + }; + conf2 { + pins = "T11 GMAC1 RXC"; + skew-delay = <15>; + }; + conf3 { + pins = "P8 GMAC0 TXEN", "V11 GMAC1 TXEN"; + skew-delay = <7>; + }; + conf4 { + pins = "V7 GMAC0 TXC", "P10 GMAC1 TXC"; + skew-delay = <10>; + }; + conf5 { + /* The data lines all have default skew */ + pins = "U8 GMAC0 RXD0", "V8 GMAC0 RXD1", + "P9 GMAC0 RXD2", "R9 GMAC0 RXD3", + "R11 GMAC1 RXD0", "P11 GMAC1 RXD1", + "V12 GMAC1 RXD2", "U12 GMAC1 RXD3", + "R10 GMAC1 TXD0", "T10 GMAC1 TXD1", + "U10 GMAC1 TXD2", "V10 GMAC1 TXD3"; + skew-delay = <7>; + }; + conf6 { + pins = "U7 GMAC0 TXD0", "T7 GMAC0 TXD1", + "R7 GMAC0 TXD2", "P7 GMAC0 TXD3"; + skew-delay = <5>; + }; + /* Set up drive strength on GMAC0 to 16 mA */ + conf7 { + groups = "gmii_gmac0_grp"; + drive-strength = <16>; + }; + }; + }; + }; + + sata: sata@46000000 { + /* The ROM uses this muxmode */ + cortina,gemini-ata-muxmode = <3>; + cortina,gemini-enable-sata-bridge; + status = "okay"; + }; + + gpio0: gpio@4d000000 { + pinctrl-names = "default"; + pinctrl-0 = <&gpio0_default_pins>; + }; + + gpio1: gpio@4e000000 { + pinctrl-names = "default"; + pinctrl-0 = <&gpio1_default_pins>; + }; + + ethernet@60000000 { + status = "okay"; + + ethernet-port@0 { + phy-mode = "rgmii"; + phy-handle = <&phy0>; + }; + ethernet-port@1 { + /* Not used in this platform */ + }; + }; + + ata@63000000 { + status = "okay"; + }; + }; +}; diff --git a/arch/arm/boot/dts/gemini-nas4220b.dts b/arch/arm/boot/dts/gemini-nas4220b.dts index d6a22e677c7a..8bbb6f85d161 100644 --- a/arch/arm/boot/dts/gemini-nas4220b.dts +++ b/arch/arm/boot/dts/gemini-nas4220b.dts @@ -64,6 +64,19 @@ }; }; + mdio0: ethernet-phy { + compatible = "virtual,mdio-gpio"; + gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>, /* MDC */ + <&gpio0 21 GPIO_ACTIVE_HIGH>; /* MDIO */ + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@1 { + reg = <1>; + device_type = "ethernet-phy"; + }; + }; + soc { flash@30000000 { status = "okay"; @@ -116,6 +129,50 @@ groups = "gpio1dgrp"; }; }; + pinctrl-gmii { + mux { + function = "gmii"; + groups = "gmii_gmac0_grp"; + }; + /* Settings come from OpenWRT */ + conf0 { + pins = "R8 GMAC0 RXDV", "U11 GMAC1 RXDV"; + skew-delay = <0>; + }; + conf1 { + pins = "T8 GMAC0 RXC", "T11 GMAC1 RXC"; + skew-delay = <15>; + }; + conf2 { + pins = "P8 GMAC0 TXEN", "V11 GMAC1 TXEN"; + skew-delay = <7>; + }; + conf3 { + pins = "V7 GMAC0 TXC"; + skew-delay = <11>; + }; + conf4 { + pins = "P10 GMAC1 TXC"; + skew-delay = <10>; + }; + conf5 { + /* The data lines all have default skew */ + pins = "U8 GMAC0 RXD0", "V8 GMAC0 RXD1", + "P9 GMAC0 RXD2", "R9 GMAC0 RXD3", + "U7 GMAC0 TXD0", "T7 GMAC0 TXD1", + "R7 GMAC0 TXD2", "P7 GMAC0 TXD3", + "R11 GMAC1 RXD0", "P11 GMAC1 RXD1", + "V12 GMAC1 RXD2", "U12 GMAC1 RXD3", + "R10 GMAC1 TXD0", "T10 GMAC1 TXD1", + "U10 GMAC1 TXD2", "V10 GMAC1 TXD3"; + skew-delay = <7>; + }; + /* Set up drive strength on GMAC0 to 16 mA */ + conf6 { + groups = "gmii_gmac0_grp"; + drive-strength = <16>; + }; + }; }; }; @@ -130,6 +187,18 @@ pinctrl-0 = <&gpio1_default_pins>; }; + ethernet@60000000 { + status = "okay"; + + ethernet-port@0 { + phy-mode = "rgmii"; + phy-handle = <&phy0>; + }; + ethernet-port@1 { + /* Not used in this platform */ + }; + }; + ata@63000000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/gemini-rut1xx.dts b/arch/arm/boot/dts/gemini-rut1xx.dts index 500057b6570e..15f20178642c 100644 --- a/arch/arm/boot/dts/gemini-rut1xx.dts +++ b/arch/arm/boot/dts/gemini-rut1xx.dts @@ -58,6 +58,19 @@ }; }; + mdio0: ethernet-phy { + compatible = "virtual,mdio-gpio"; + gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>, /* MDC */ + <&gpio0 21 GPIO_ACTIVE_HIGH>; /* MDIO */ + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@1 { + reg = <1>; + device_type = "ethernet-phy"; + }; + }; + soc { flash@30000000 { status = "okay"; @@ -101,5 +114,17 @@ pinctrl-names = "default"; pinctrl-0 = <&gpio1_default_pins>; }; + + ethernet@60000000 { + status = "okay"; + + ethernet-port@0 { + phy-mode = "rgmii"; + phy-handle = <&phy0>; + }; + ethernet-port@1 { + /* Not used in this platform */ + }; + }; }; }; diff --git a/arch/arm/boot/dts/gemini-wbd111.dts b/arch/arm/boot/dts/gemini-wbd111.dts index b413fd12c5ba..b4ec9ad85d72 100644 --- a/arch/arm/boot/dts/gemini-wbd111.dts +++ b/arch/arm/boot/dts/gemini-wbd111.dts @@ -69,6 +69,19 @@ }; }; + mdio0: ethernet-phy { + compatible = "virtual,mdio-gpio"; + gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>, /* MDC */ + <&gpio0 21 GPIO_ACTIVE_HIGH>; /* MDIO */ + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@1 { + reg = <1>; + device_type = "ethernet-phy"; + }; + }; + soc { flash@30000000 { status = "okay"; @@ -125,5 +138,39 @@ pinctrl-names = "default"; pinctrl-0 = <&gpio0_default_pins>; }; + + pci@50000000 { + status = "okay"; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = + <0x4800 0 0 1 &pci_intc 0>, /* Slot 9 */ + <0x4800 0 0 2 &pci_intc 1>, + <0x4800 0 0 3 &pci_intc 2>, + <0x4800 0 0 4 &pci_intc 3>, + <0x5000 0 0 1 &pci_intc 1>, /* Slot 10 */ + <0x5000 0 0 2 &pci_intc 2>, + <0x5000 0 0 3 &pci_intc 3>, + <0x5000 0 0 4 &pci_intc 0>, + <0x5800 0 0 1 &pci_intc 2>, /* Slot 11 */ + <0x5800 0 0 2 &pci_intc 3>, + <0x5800 0 0 3 &pci_intc 0>, + <0x5800 0 0 4 &pci_intc 1>, + <0x6000 0 0 1 &pci_intc 3>, /* Slot 12 */ + <0x6000 0 0 2 &pci_intc 0>, + <0x6000 0 0 3 &pci_intc 1>, + <0x6000 0 0 4 &pci_intc 2>; + }; + + ethernet@60000000 { + status = "okay"; + + ethernet-port@0 { + phy-mode = "rgmii"; + phy-handle = <&phy0>; + }; + ethernet-port@1 { + /* Not used in this platform */ + }; + }; }; }; diff --git a/arch/arm/boot/dts/gemini-wbd222.dts b/arch/arm/boot/dts/gemini-wbd222.dts index 3ba710538662..6d25bcc046e7 100644 --- a/arch/arm/boot/dts/gemini-wbd222.dts +++ b/arch/arm/boot/dts/gemini-wbd222.dts @@ -69,6 +69,24 @@ }; }; + mdio0: ethernet-phy { + compatible = "virtual,mdio-gpio"; + gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>, /* MDC */ + <&gpio0 21 GPIO_ACTIVE_HIGH>; /* MDIO */ + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@1 { + reg = <1>; + device_type = "ethernet-phy"; + }; + + phy1: ethernet-phy@3 { + reg = <3>; + device_type = "ethernet-phy"; + }; + }; + soc { flash@30000000 { status = "okay"; @@ -118,6 +136,13 @@ "gpio0bgrp"; }; }; + pinctrl-gmii { + /* This platform use both the ethernet ports */ + mux { + function = "gmii"; + groups = "gmii_gmac0_grp", "gmii_gmac1_grp"; + }; + }; }; }; @@ -125,5 +150,40 @@ pinctrl-names = "default"; pinctrl-0 = <&gpio0_default_pins>; }; + + pci@50000000 { + status = "okay"; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = + <0x4800 0 0 1 &pci_intc 0>, /* Slot 9 */ + <0x4800 0 0 2 &pci_intc 1>, + <0x4800 0 0 3 &pci_intc 2>, + <0x4800 0 0 4 &pci_intc 3>, + <0x5000 0 0 1 &pci_intc 1>, /* Slot 10 */ + <0x5000 0 0 2 &pci_intc 2>, + <0x5000 0 0 3 &pci_intc 3>, + <0x5000 0 0 4 &pci_intc 0>, + <0x5800 0 0 1 &pci_intc 2>, /* Slot 11 */ + <0x5800 0 0 2 &pci_intc 3>, + <0x5800 0 0 3 &pci_intc 0>, + <0x5800 0 0 4 &pci_intc 1>, + <0x6000 0 0 1 &pci_intc 3>, /* Slot 12 */ + <0x6000 0 0 2 &pci_intc 0>, + <0x6000 0 0 3 &pci_intc 1>, + <0x6000 0 0 4 &pci_intc 2>; + }; + + ethernet@60000000 { + status = "okay"; + + ethernet-port@0 { + phy-mode = "rgmii"; + phy-handle = <&phy0>; + }; + ethernet-port@1 { + phy-mode = "rgmii"; + phy-handle = <&phy1>; + }; + }; }; }; diff --git a/arch/arm/boot/dts/gemini.dtsi b/arch/arm/boot/dts/gemini.dtsi index cb5c925bd597..0568baca500a 100644 --- a/arch/arm/boot/dts/gemini.dtsi +++ b/arch/arm/boot/dts/gemini.dtsi @@ -114,9 +114,16 @@ }; }; gmii_default_pins: pinctrl-gmii { + /* + * Only activate GMAC0 by default since + * GMAC1 will overlap with 8 GPIO lines + * gpio2a, gpio2b. Overlay groups with + * "gmii_gmac0_grp", "gmii_gmac1_grp" for + * both ethernet interfaces. + */ mux { function = "gmii"; - groups = "gmiigrp"; + groups = "gmii_gmac0_grp"; }; }; pci_default_pins: pinctrl-pci { @@ -316,6 +323,41 @@ }; }; + ethernet@60000000 { + compatible = "cortina,gemini-ethernet"; + reg = <0x60000000 0x4000>, /* Global registers, queue */ + <0x60004000 0x2000>, /* V-bit */ + <0x60006000 0x2000>; /* A-bit */ + pinctrl-names = "default"; + pinctrl-0 = <&gmii_default_pins>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + gmac0: ethernet-port@0 { + compatible = "cortina,gemini-ethernet-port"; + reg = <0x60008000 0x2000>, /* Port 0 DMA/TOE */ + <0x6000a000 0x2000>; /* Port 0 GMAC */ + interrupt-parent = <&intcon>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; + resets = <&syscon GEMINI_RESET_GMAC0>; + clocks = <&syscon GEMINI_CLK_GATE_GMAC0>; + clock-names = "PCLK"; + }; + + gmac1: ethernet-port@1 { + compatible = "cortina,gemini-ethernet-port"; + reg = <0x6000c000 0x2000>, /* Port 1 DMA/TOE */ + <0x6000e000 0x2000>; /* Port 1 GMAC */ + interrupt-parent = <&intcon>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + resets = <&syscon GEMINI_RESET_GMAC1>; + clocks = <&syscon GEMINI_CLK_GATE_GMAC1>; + clock-names = "PCLK"; + }; + }; + ata@63000000 { compatible = "cortina,gemini-pata", "faraday,ftide010"; reg = <0x63000000 0x1000>; diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi index 09ce8b81fafa..9445f8e1473c 100644 --- a/arch/arm/boot/dts/imx25.dtsi +++ b/arch/arm/boot/dts/imx25.dtsi @@ -122,7 +122,7 @@ }; can1: can@43f88000 { - compatible = "fsl,imx25-flexcan", "fsl,p1010-flexcan"; + compatible = "fsl,imx25-flexcan"; reg = <0x43f88000 0x4000>; interrupts = <43>; clocks = <&clks 75>, <&clks 75>; @@ -131,7 +131,7 @@ }; can2: can@43f8c000 { - compatible = "fsl,imx25-flexcan", "fsl,p1010-flexcan"; + compatible = "fsl,imx25-flexcan"; reg = <0x43f8c000 0x4000>; interrupts = <44>; clocks = <&clks 76>, <&clks 76>; @@ -628,11 +628,13 @@ usbphy0: usb-phy@0 { reg = <0>; compatible = "usb-nop-xceiv"; + #phy-cells = <0>; }; usbphy1: usb-phy@1 { reg = <1>; compatible = "usb-nop-xceiv"; + #phy-cells = <0>; }; }; }; diff --git a/arch/arm/boot/dts/imx27-pdk.dts b/arch/arm/boot/dts/imx27-pdk.dts index 96f442ba6d22..2a140c8ae6d2 100644 --- a/arch/arm/boot/dts/imx27-pdk.dts +++ b/arch/arm/boot/dts/imx27-pdk.dts @@ -30,6 +30,7 @@ reg = <0>; clocks = <&clks IMX27_CLK_DUMMY>; clock-names = "main_clk"; + #phy-cells = <0>; }; }; }; diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts index 2a9198f99a8d..2ed2d73b087e 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore-rdk.dts @@ -63,6 +63,7 @@ vcc-supply = <®_5v0>; clocks = <&clks IMX27_CLK_DUMMY>; clock-names = "main_clk"; + #phy-cells = <0>; }; }; }; diff --git a/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi b/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi index c973c5d91875..c9095b7654c6 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi +++ b/arch/arm/boot/dts/imx27-phytec-phycore-som.dtsi @@ -53,6 +53,7 @@ vcc-supply = <&sw3_reg>; clocks = <&clks IMX27_CLK_DUMMY>; clock-names = "main_clk"; + #phy-cells = <0>; }; }; }; diff --git a/arch/arm/boot/dts/imx28-ts4600.dts b/arch/arm/boot/dts/imx28-ts4600.dts new file mode 100644 index 000000000000..1e391c9f1b7a --- /dev/null +++ b/arch/arm/boot/dts/imx28-ts4600.dts @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016 Savoir-Faire Linux + * Author: Sebastien Bourdelin + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +#include "imx28.dtsi" +#include "dt-bindings/gpio/gpio.h" + +/ { + + model = "Technologic Systems i.MX28 TS-4600"; + compatible = "technologic,imx28-ts4600", "fsl,imx28"; + + memory { + reg = <0x40000000 0x10000000>; /* 256MB */ + }; + + apb@80000000 { + apbh@80000000 { + ssp0: ssp@80010000 { + compatible = "fsl,imx28-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_4bit_pins_a + &mmc0_sck_cfg + &en_sd_pwr>; + broken-cd = <1>; + bus-width = <4>; + vmmc-supply = <®_vddio_sd0>; + status = "okay"; + }; + + pinctrl@80018000 { + + en_sd_pwr: en-sd-pwr@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_PWM3__GPIO_3_28 + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; + + }; + }; + + apbx@80040000 { + pwm: pwm@80064000 { + pinctrl-names = "default"; + pinctrl-0 = <&pwm2_pins_a>; + status = "okay"; + }; + + duart: serial@80074000 { + pinctrl-names = "default"; + pinctrl-0 = <&duart_pins_a>; + status = "okay"; + }; + }; + }; + + reg_vddio_sd0: regulator-vddio-sd0 { + compatible = "regulator-fixed"; + regulator-name = "vddio-sd0"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + gpio = <&gpio3 28 GPIO_ACTIVE_LOW>; + }; + +}; diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 2f4ebe0318d3..e52e05c0fe56 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -1038,7 +1038,7 @@ }; can0: can@80032000 { - compatible = "fsl,imx28-flexcan", "fsl,p1010-flexcan"; + compatible = "fsl,imx28-flexcan"; reg = <0x80032000 0x2000>; interrupts = <8>; clocks = <&clks 58>, <&clks 58>; @@ -1047,7 +1047,7 @@ }; can1: can@80034000 { - compatible = "fsl,imx28-flexcan", "fsl,p1010-flexcan"; + compatible = "fsl,imx28-flexcan"; reg = <0x80034000 0x2000>; interrupts = <9>; clocks = <&clks 59>, <&clks 59>; diff --git a/arch/arm/boot/dts/imx35.dtsi b/arch/arm/boot/dts/imx35.dtsi index 6d5e6a60bee7..e08c0c193767 100644 --- a/arch/arm/boot/dts/imx35.dtsi +++ b/arch/arm/boot/dts/imx35.dtsi @@ -303,7 +303,7 @@ }; can1: can@53fe4000 { - compatible = "fsl,imx35-flexcan", "fsl,p1010-flexcan"; + compatible = "fsl,imx35-flexcan"; reg = <0x53fe4000 0x1000>; clocks = <&clks 33>, <&clks 33>; clock-names = "ipg", "per"; @@ -312,7 +312,7 @@ }; can2: can@53fe8000 { - compatible = "fsl,imx35-flexcan", "fsl,p1010-flexcan"; + compatible = "fsl,imx35-flexcan"; reg = <0x53fe8000 0x1000>; clocks = <&clks 34>, <&clks 34>; clock-names = "ipg", "per"; @@ -402,11 +402,13 @@ usbphy0: usb-phy@0 { reg = <0>; compatible = "usb-nop-xceiv"; + #phy-cells = <0>; }; usbphy1: usb-phy@1 { reg = <1>; compatible = "usb-nop-xceiv"; + #phy-cells = <0>; }; }; }; diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts index 2a694c5cc8ae..4ac5ab614a7f 100644 --- a/arch/arm/boot/dts/imx51-babbage.dts +++ b/arch/arm/boot/dts/imx51-babbage.dts @@ -25,18 +25,41 @@ reg = <0x90000000 0x20000000>; }; - clocks { - ckih1 { - clock-frequency = <22579200>; - }; + ckih1 { + clock-frequency = <22579200>; + }; - clk_26M: codec_clock { - compatible = "fixed-clock"; - reg=<0>; - #clock-cells = <0>; - clock-frequency = <26000000>; - gpios = <&gpio4 26 GPIO_ACTIVE_LOW>; - }; + clk_osc: clk-osc { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <26000000>; + }; + + clk_osc_gate: clk-osc-gate { + compatible = "gpio-gate-clock"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_clk26mhz_osc>; + clocks = <&clk_osc>; + #clock-cells = <0>; + enable-gpios = <&gpio3 1 GPIO_ACTIVE_HIGH>; + }; + + clk_audio: clk-audio { + compatible = "gpio-gate-clock"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_clk26mhz_audio>; + clocks = <&clk_osc_gate>; + #clock-cells = <0>; + enable-gpios = <&gpio4 26 GPIO_ACTIVE_LOW>; + }; + + clk_usb: clk-usb { + compatible = "gpio-gate-clock"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_clk26mhz_usb>; + clocks = <&clk_osc_gate>; + #clock-cells = <0>; + enable-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>; }; display1: disp1 { @@ -162,9 +185,11 @@ usbh1phy: usbh1phy@0 { compatible = "usb-nop-xceiv"; reg = <0>; - clocks = <&clks IMX5_CLK_DUMMY>; + clocks = <&clk_usb>; clock-names = "main_clk"; reset-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; + vcc-supply = <&vusb_reg>; + #phy-cells = <0>; }; }; }; @@ -240,6 +265,10 @@ regulator-max-microvolt = <3150000>; }; + vusb_reg: vusb { + regulator-boot-on; + }; + vusb2_reg: vusb2 { regulator-min-microvolt = <2400000>; regulator-max-microvolt = <2775000>; @@ -339,10 +368,8 @@ sgtl5000: codec@a { compatible = "fsl,sgtl5000"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_clkcodec>; reg = <0x0a>; - clocks = <&clk_26M>; + clocks = <&clk_audio>; VDDA-supply = <&vdig_reg>; VDDIO-supply = <&vvideo_reg>; }; @@ -413,6 +440,10 @@ status = "okay"; }; +&usbphy0 { + vcc-supply = <&vusb_reg>; +}; + &usbotg { dr_mode = "otg"; disable-over-current; @@ -431,9 +462,21 @@ >; }; - pinctrl_clkcodec: clkcodecgrp { + pinctrl_clk26mhz_audio: clk26mhzaudiocgrp { fsl,pins = < - MX51_PAD_CSPI1_RDY__GPIO4_26 0x80000000 + MX51_PAD_CSPI1_RDY__GPIO4_26 0x85 + >; + }; + + pinctrl_clk26mhz_osc: clk26mhzoscgrp { + fsl,pins = < + MX51_PAD_DI1_PIN12__GPIO3_1 0x85 + >; + }; + + pinctrl_clk26mhz_usb: clk26mhzusbgrp { + fsl,pins = < + MX51_PAD_EIM_D17__GPIO2_1 0x85 >; }; diff --git a/arch/arm/boot/dts/imx51-eukrea-mbimxsd51-baseboard.dts b/arch/arm/boot/dts/imx51-eukrea-mbimxsd51-baseboard.dts index 1305b05c7ed9..b3d952f37cdc 100644 --- a/arch/arm/boot/dts/imx51-eukrea-mbimxsd51-baseboard.dts +++ b/arch/arm/boot/dts/imx51-eukrea-mbimxsd51-baseboard.dts @@ -94,6 +94,7 @@ clocks = <&clks IMX5_CLK_USB_PHY_GATE>; clock-names = "main_clk"; clock-frequency = <19200000>; + #phy-cells = <0>; }; }; }; diff --git a/arch/arm/boot/dts/imx51-ts4800.dts b/arch/arm/boot/dts/imx51-ts4800.dts index 564233e97412..f59b02bae68d 100644 --- a/arch/arm/boot/dts/imx51-ts4800.dts +++ b/arch/arm/boot/dts/imx51-ts4800.dts @@ -149,18 +149,18 @@ #size-cells = <1>; ranges = <0 0 0 0x1d000>; - syscon: syscon@b0010000 { + syscon: syscon@10000 { compatible = "syscon", "simple-mfd"; reg = <0x10000 0x3d>; reg-io-width = <2>; - wdt@e { + wdt { compatible = "technologic,ts4800-wdt"; syscon = <&syscon 0xe>; }; }; - touchscreen { + touchscreen@12000 { compatible = "technologic,ts4800-ts"; reg = <0x12000 0x1000>; syscon = <&syscon 0x10 6>; diff --git a/arch/arm/boot/dts/imx51-zii-rdu1.dts b/arch/arm/boot/dts/imx51-zii-rdu1.dts index 49be0e1c812d..5306b78de0ca 100644 --- a/arch/arm/boot/dts/imx51-zii-rdu1.dts +++ b/arch/arm/boot/dts/imx51-zii-rdu1.dts @@ -242,7 +242,7 @@ sound { compatible = "simple-audio-card"; - simple-audio-card,name = "RDU1 audio"; + simple-audio-card,name = "Front"; simple-audio-card,format = "i2s"; simple-audio-card,bitclock-master = <&sound_codec>; simple-audio-card,frame-master = <&sound_codec>; @@ -251,7 +251,7 @@ simple-audio-card,routing = "Headphone Jack", "HPLEFT", "Headphone Jack", "HPRIGHT"; - simple-audio-card,aux-devs = <&tpa6130a2>; + simple-audio-card,aux-devs = <&hpa1>; sound_cpu: simple-audio-card,cpu { sound-dai = <&ssi2>; @@ -271,6 +271,7 @@ clock-names = "main_clk"; reset-gpios = <&gpio4 8 GPIO_ACTIVE_LOW>; vcc-supply = <&vusb_reg>; + #phy-cells = <0>; }; usbh2phy: usbphy2 { @@ -281,6 +282,7 @@ clock-names = "main_clk"; reset-gpios = <&gpio4 7 GPIO_ACTIVE_LOW>; vcc-supply = <&vusb_reg>; + #phy-cells = <0>; }; }; @@ -428,13 +430,13 @@ #size-cells = <0>; led-control = <0x0 0x0 0x3f83f8 0x0>; - sysled0 { + sysled0@3 { reg = <3>; label = "system:green:status"; linux,default-trigger = "default-on"; }; - sysled1 { + sysled1@4 { reg = <4>; label = "system:green:act"; linux,default-trigger = "heartbeat"; @@ -479,7 +481,7 @@ reg = <0x50>; }; - tpa6130a2: amp@60 { + hpa1: amp@60 { compatible = "ti,tpa6130a2"; reg = <0x60>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index 378be720b3c7..00d30bd70068 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -113,6 +113,7 @@ reg = <0>; clocks = <&clks IMX5_CLK_USB_PHY_GATE>; clock-names = "main_clk"; + #phy-cells = <0>; }; }; diff --git a/arch/arm/boot/dts/imx53-cx9020.dts b/arch/arm/boot/dts/imx53-cx9020.dts index 4f54fd4418a3..5e67e43004e7 100644 --- a/arch/arm/boot/dts/imx53-cx9020.dts +++ b/arch/arm/boot/dts/imx53-cx9020.dts @@ -152,7 +152,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_fec>; phy-mode = "rmii"; - phy-reset-gpios = <&gpio7 6 GPIO_ACTIVE_HIGH>; + phy-reset-gpios = <&gpio7 6 GPIO_ACTIVE_LOW>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx53-m53.dtsi b/arch/arm/boot/dts/imx53-m53.dtsi index ec390aa562c3..7ce69c63510c 100644 --- a/arch/arm/boot/dts/imx53-m53.dtsi +++ b/arch/arm/boot/dts/imx53-m53.dtsi @@ -64,7 +64,6 @@ stmpe_touchscreen { compatible = "st,stmpe-ts"; - reg = <0>; st,sample-time = <4>; st,mod-12b = <1>; st,ref-sel = <0>; diff --git a/arch/arm/boot/dts/imx53-tx53-x03x.dts b/arch/arm/boot/dts/imx53-tx53-x03x.dts index 7eb53e48c2f4..fe15c9555d6e 100644 --- a/arch/arm/boot/dts/imx53-tx53-x03x.dts +++ b/arch/arm/boot/dts/imx53-tx53-x03x.dts @@ -53,132 +53,130 @@ display = &display; }; - soc { - display: disp0 { - compatible = "fsl,imx-parallel-display"; - interface-pix-fmt = "rgb24"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_rgb24_vga1>; - status = "okay"; + display: disp0 { + compatible = "fsl,imx-parallel-display"; + interface-pix-fmt = "rgb24"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rgb24_vga1>; + status = "okay"; - port { - display0_in: endpoint { - remote-endpoint = <&ipu_di0_disp0>; - }; + port { + display0_in: endpoint { + remote-endpoint = <&ipu_di0_disp0>; + }; + }; + + display-timings { + VGA { + clock-frequency = <25200000>; + hactive = <640>; + vactive = <480>; + hback-porch = <48>; + hsync-len = <96>; + hfront-porch = <16>; + vback-porch = <31>; + vsync-len = <2>; + vfront-porch = <12>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; }; - display-timings { - VGA { - clock-frequency = <25200000>; - hactive = <640>; - vactive = <480>; - hback-porch = <48>; - hsync-len = <96>; - hfront-porch = <16>; - vback-porch = <31>; - vsync-len = <2>; - vfront-porch = <12>; - hsync-active = <0>; - vsync-active = <0>; - de-active = <1>; - pixelclk-active = <0>; - }; + ETV570 { + clock-frequency = <25200000>; + hactive = <640>; + vactive = <480>; + hback-porch = <114>; + hsync-len = <30>; + hfront-porch = <16>; + vback-porch = <32>; + vsync-len = <3>; + vfront-porch = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; - ETV570 { - clock-frequency = <25200000>; - hactive = <640>; - vactive = <480>; - hback-porch = <114>; - hsync-len = <30>; - hfront-porch = <16>; - vback-porch = <32>; - vsync-len = <3>; - vfront-porch = <10>; - hsync-active = <0>; - vsync-active = <0>; - de-active = <1>; - pixelclk-active = <0>; - }; + ET0350 { + clock-frequency = <6413760>; + hactive = <320>; + vactive = <240>; + hback-porch = <34>; + hsync-len = <34>; + hfront-porch = <20>; + vback-porch = <15>; + vsync-len = <3>; + vfront-porch = <4>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; - ET0350 { - clock-frequency = <6413760>; - hactive = <320>; - vactive = <240>; - hback-porch = <34>; - hsync-len = <34>; - hfront-porch = <20>; - vback-porch = <15>; - vsync-len = <3>; - vfront-porch = <4>; - hsync-active = <0>; - vsync-active = <0>; - de-active = <1>; - pixelclk-active = <0>; - }; + ET0430 { + clock-frequency = <9009000>; + hactive = <480>; + vactive = <272>; + hback-porch = <2>; + hsync-len = <41>; + hfront-porch = <2>; + vback-porch = <2>; + vsync-len = <10>; + vfront-porch = <2>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <1>; + }; - ET0430 { - clock-frequency = <9009000>; - hactive = <480>; - vactive = <272>; - hback-porch = <2>; - hsync-len = <41>; - hfront-porch = <2>; - vback-porch = <2>; - vsync-len = <10>; - vfront-porch = <2>; - hsync-active = <0>; - vsync-active = <0>; - de-active = <1>; - pixelclk-active = <1>; - }; + ET0500 { + clock-frequency = <33264000>; + hactive = <800>; + vactive = <480>; + hback-porch = <88>; + hsync-len = <128>; + hfront-porch = <40>; + vback-porch = <33>; + vsync-len = <2>; + vfront-porch = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; - ET0500 { - clock-frequency = <33264000>; - hactive = <800>; - vactive = <480>; - hback-porch = <88>; - hsync-len = <128>; - hfront-porch = <40>; - vback-porch = <33>; - vsync-len = <2>; - vfront-porch = <10>; - hsync-active = <0>; - vsync-active = <0>; - de-active = <1>; - pixelclk-active = <0>; - }; + ET0700 { /* same as ET0500 */ + clock-frequency = <33264000>; + hactive = <800>; + vactive = <480>; + hback-porch = <88>; + hsync-len = <128>; + hfront-porch = <40>; + vback-porch = <33>; + vsync-len = <2>; + vfront-porch = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; - ET0700 { /* same as ET0500 */ - clock-frequency = <33264000>; - hactive = <800>; - vactive = <480>; - hback-porch = <88>; - hsync-len = <128>; - hfront-porch = <40>; - vback-porch = <33>; - vsync-len = <2>; - vfront-porch = <10>; - hsync-active = <0>; - vsync-active = <0>; - de-active = <1>; - pixelclk-active = <0>; - }; - - ETQ570 { - clock-frequency = <6596040>; - hactive = <320>; - vactive = <240>; - hback-porch = <38>; - hsync-len = <30>; - hfront-porch = <30>; - vback-porch = <16>; - vsync-len = <3>; - vfront-porch = <4>; - hsync-active = <0>; - vsync-active = <0>; - de-active = <1>; - pixelclk-active = <0>; - }; + ETQ570 { + clock-frequency = <6596040>; + hactive = <320>; + vactive = <240>; + hback-porch = <38>; + hsync-len = <30>; + hfront-porch = <30>; + vback-porch = <16>; + vsync-len = <3>; + vfront-porch = <4>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; }; }; }; diff --git a/arch/arm/boot/dts/imx53-tx53.dtsi b/arch/arm/boot/dts/imx53-tx53.dtsi index 71b58b6933e1..a22e461fc168 100644 --- a/arch/arm/boot/dts/imx53-tx53.dtsi +++ b/arch/arm/boot/dts/imx53-tx53.dtsi @@ -225,10 +225,16 @@ mac-address = [000000000000]; /* placeholder; will be overwritten by bootloader */ status = "okay"; - phy0: ethernet-phy@0 { - interrupt-parent = <&gpio2>; - interrupts = <4 IRQ_TYPE_EDGE_FALLING>; - device_type = "ethernet-phy"; + mdio { + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@0 { + reg = <0>; + interrupt-parent = <&gpio2>; + interrupts = <4 IRQ_TYPE_EDGE_FALLING>; + device_type = "ethernet-phy"; + }; }; }; diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index 84f17f7abb71..1040251f2951 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -116,6 +116,28 @@ }; }; + pmu { + compatible = "arm,cortex-a8-pmu"; + interrupt-parent = <&tzic>; + interrupts = <77>; + }; + + usbphy0: usbphy-0 { + compatible = "usb-nop-xceiv"; + clocks = <&clks IMX5_CLK_USB_PHY1_GATE>; + clock-names = "main_clk"; + #phy-cells = <0>; + status = "okay"; + }; + + usbphy1: usbphy-1 { + compatible = "usb-nop-xceiv"; + clocks = <&clks IMX5_CLK_USB_PHY2_GATE>; + clock-names = "main_clk"; + #phy-cells = <0>; + status = "okay"; + }; + soc { #address-cells = <1>; #size-cells = <1>; @@ -299,20 +321,6 @@ reg = <0x53f00000 0x60>; }; - usbphy0: usbphy-0 { - compatible = "usb-nop-xceiv"; - clocks = <&clks IMX5_CLK_USB_PHY1_GATE>; - clock-names = "main_clk"; - status = "okay"; - }; - - usbphy1: usbphy-1 { - compatible = "usb-nop-xceiv"; - clocks = <&clks IMX5_CLK_USB_PHY2_GATE>; - clock-names = "main_clk"; - status = "okay"; - }; - usbotg: usb@53f80000 { compatible = "fsl,imx53-usb", "fsl,imx27-usb"; reg = <0x53f80000 0x0200>; @@ -433,6 +441,13 @@ clock-names = "ipg", "per"; }; + srtc: rtc@53fa4000 { + compatible = "fsl,imx53-rtc"; + reg = <0x53fa4000 0x4000>; + interrupts = <24>; + clocks = <&clks IMX5_CLK_SRTC_GATE>; + }; + iomuxc: iomuxc@53fa8000 { compatible = "fsl,imx53-iomuxc"; reg = <0x53fa8000 0x4000>; @@ -536,7 +551,7 @@ }; can1: can@53fc8000 { - compatible = "fsl,imx53-flexcan", "fsl,p1010-flexcan"; + compatible = "fsl,imx53-flexcan"; reg = <0x53fc8000 0x4000>; interrupts = <82>; clocks = <&clks IMX5_CLK_CAN1_IPG_GATE>, @@ -546,7 +561,7 @@ }; can2: can@53fcc000 { - compatible = "fsl,imx53-flexcan", "fsl,p1010-flexcan"; + compatible = "fsl,imx53-flexcan"; reg = <0x53fcc000 0x4000>; interrupts = <83>; clocks = <&clks IMX5_CLK_CAN2_IPG_GATE>, @@ -813,10 +828,5 @@ reg = <0xf8000000 0x20000>; clocks = <&clks IMX5_CLK_OCRAM>; }; - - pmu { - compatible = "arm,cortex-a8-pmu"; - interrupts = <77>; - }; }; }; diff --git a/arch/arm/boot/dts/imx6dl-aristainetos_4.dts b/arch/arm/boot/dts/imx6dl-aristainetos_4.dts index cc418cecabdb..3c9f4af9e9ff 100644 --- a/arch/arm/boot/dts/imx6dl-aristainetos_4.dts +++ b/arch/arm/boot/dts/imx6dl-aristainetos_4.dts @@ -31,35 +31,33 @@ reg = <0x10000000 0x40000000>; }; - soc { - display0: disp0 { - compatible = "fsl,imx-parallel-display"; - interface-pix-fmt = "rgb24"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ipu_disp>; - status = "okay"; + display0: disp0 { + compatible = "fsl,imx-parallel-display"; + interface-pix-fmt = "rgb24"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ipu_disp>; + status = "okay"; - display-timings { - 480x800p60 { - native-mode; - clock-frequency = <30000000>; - hactive = <480>; - vactive = <800>; - hfront-porch = <59>; - hback-porch = <10>; - hsync-len = <10>; - vback-porch = <15>; - vfront-porch = <15>; - vsync-len = <15>; - hsync-active = <1>; - vsync-active = <1>; - }; + display-timings { + 480x800p60 { + native-mode; + clock-frequency = <30000000>; + hactive = <480>; + vactive = <800>; + hfront-porch = <59>; + hback-porch = <10>; + hsync-len = <10>; + vback-porch = <15>; + vfront-porch = <15>; + vsync-len = <15>; + hsync-active = <1>; + vsync-active = <1>; }; + }; - port { - display0_in: endpoint { - remote-endpoint = <&ipu1_di0_disp0>; - }; + port { + display0_in: endpoint { + remote-endpoint = <&ipu1_di0_disp0>; }; }; }; diff --git a/arch/arm/boot/dts/imx6dl-aristainetos_7.dts b/arch/arm/boot/dts/imx6dl-aristainetos_7.dts index 126ff964eded..96cd835ccbf6 100644 --- a/arch/arm/boot/dts/imx6dl-aristainetos_7.dts +++ b/arch/arm/boot/dts/imx6dl-aristainetos_7.dts @@ -20,34 +20,32 @@ reg = <0x10000000 0x40000000>; }; - soc { - display0: disp0 { - compatible = "fsl,imx-parallel-display"; - interface-pix-fmt = "rgb24"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ipu_disp>; - status = "okay"; + display0: disp0 { + compatible = "fsl,imx-parallel-display"; + interface-pix-fmt = "rgb24"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ipu_disp>; + status = "okay"; - display-timings { - 800x480p60 { - native-mode; - clock-frequency = <33246000>; - hactive = <800>; - vactive = <480>; - hfront-porch = <88>; - hback-porch = <88>; - hsync-len = <80>; - vback-porch = <10>; - vfront-porch = <10>; - vsync-len = <25>; - vsync-active = <1>; - }; + display-timings { + 800x480p60 { + native-mode; + clock-frequency = <33246000>; + hactive = <800>; + vactive = <480>; + hfront-porch = <88>; + hback-porch = <88>; + hsync-len = <80>; + vback-porch = <10>; + vfront-porch = <10>; + vsync-len = <25>; + vsync-active = <1>; }; + }; - port { - display0_in: endpoint { - remote-endpoint = <&ipu1_di0_disp0>; - }; + port { + display0_in: endpoint { + remote-endpoint = <&ipu1_di0_disp0>; }; }; }; diff --git a/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts b/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts index 5705ebee0595..dcf9206f3e0d 100644 --- a/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts +++ b/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts @@ -163,7 +163,7 @@ /* M41T0M6 real time clock on carrier board */ rtc_i2c: rtc@68 { - compatible = "st,m41t00"; + compatible = "st,m41t0"; reg = <0x68>; }; }; diff --git a/arch/arm/boot/dts/imx6dl-cubox-i-emmc-som-v15.dts b/arch/arm/boot/dts/imx6dl-cubox-i-emmc-som-v15.dts new file mode 100644 index 000000000000..2b2fc360b865 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-cubox-i-emmc-som-v15.dts @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014 Russell King + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; + +#include "imx6dl.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-ti.dtsi" +#include "imx6qdl-sr-som-emmc.dtsi" +#include "imx6qdl-cubox-i.dtsi" + +/ { + model = "SolidRun Cubox-i Solo/DualLite (1.5som+emmc)"; + compatible = "solidrun,cubox-i/dl", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6dl-cubox-i-som-v15.dts b/arch/arm/boot/dts/imx6dl-cubox-i-som-v15.dts new file mode 100644 index 000000000000..e09c565d1d1f --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-cubox-i-som-v15.dts @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014 Russell King + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; + +#include "imx6dl.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-ti.dtsi" +#include "imx6qdl-cubox-i.dtsi" + +/ { + model = "SolidRun Cubox-i Solo/DualLite (1.5som)"; + compatible = "solidrun,cubox-i/dl", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6dl-cubox-i.dts b/arch/arm/boot/dts/imx6dl-cubox-i.dts index f10a36b8647d..2b1b3e193f53 100644 --- a/arch/arm/boot/dts/imx6dl-cubox-i.dts +++ b/arch/arm/boot/dts/imx6dl-cubox-i.dts @@ -41,6 +41,8 @@ /dts-v1/; #include "imx6dl.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-brcm.dtsi" #include "imx6qdl-cubox-i.dtsi" / { diff --git a/arch/arm/boot/dts/imx6dl-hummingboard-emmc-som-v15.dts b/arch/arm/boot/dts/imx6dl-hummingboard-emmc-som-v15.dts new file mode 100644 index 000000000000..a63f742f20d9 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-hummingboard-emmc-som-v15.dts @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014 Rabeeh Khoury (rabeeh@solid-run.com) + * Based on dt work by Russell King + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; + +#include "imx6dl.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-ti.dtsi" +#include "imx6qdl-sr-som-emmc.dtsi" +#include "imx6qdl-hummingboard.dtsi" + +/ { + model = "SolidRun HummingBoard Solo/DualLite (1.5som+emmc)"; + compatible = "solidrun,hummingboard/dl", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6dl-hummingboard-som-v15.dts b/arch/arm/boot/dts/imx6dl-hummingboard-som-v15.dts new file mode 100644 index 000000000000..66a06cf3cdf3 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-hummingboard-som-v15.dts @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014 Rabeeh Khoury (rabeeh@solid-run.com) + * Based on dt work by Russell King + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; + +#include "imx6dl.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-ti.dtsi" +#include "imx6qdl-hummingboard.dtsi" + +/ { + model = "SolidRun HummingBoard Solo/DualLite (1.5som)"; + compatible = "solidrun,hummingboard/dl", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6dl-hummingboard.dts b/arch/arm/boot/dts/imx6dl-hummingboard.dts index 39c2602fa87c..cbd02eb486e1 100644 --- a/arch/arm/boot/dts/imx6dl-hummingboard.dts +++ b/arch/arm/boot/dts/imx6dl-hummingboard.dts @@ -42,6 +42,8 @@ /dts-v1/; #include "imx6dl.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-brcm.dtsi" #include "imx6qdl-hummingboard.dtsi" / { diff --git a/arch/arm/boot/dts/imx6dl-hummingboard2-emmc-som-v15.dts b/arch/arm/boot/dts/imx6dl-hummingboard2-emmc-som-v15.dts new file mode 100644 index 000000000000..80313c13bcdb --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-hummingboard2-emmc-som-v15.dts @@ -0,0 +1,55 @@ +/* + * Device Tree file for SolidRun HummingBoard2 + * Copyright (C) 2015 Rabeeh Khoury + * Based on work by Russell King + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License. + * + * This file 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. + * + * Or, alternatively + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; + +#include "imx6dl.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-emmc.dtsi" +#include "imx6qdl-sr-som-ti.dtsi" +#include "imx6qdl-hummingboard2.dtsi" + +/ { + model = "SolidRun HummingBoard2 Solo/DualLite (1.5som+emmc)"; + compatible = "solidrun,hummingboard2/dl", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6dl-hummingboard2-som-v15.dts b/arch/arm/boot/dts/imx6dl-hummingboard2-som-v15.dts new file mode 100644 index 000000000000..e61ef1156f8b --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-hummingboard2-som-v15.dts @@ -0,0 +1,54 @@ +/* + * Device Tree file for SolidRun HummingBoard2 + * Copyright (C) 2015 Rabeeh Khoury + * Based on work by Russell King + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License. + * + * This file 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. + * + * Or, alternatively + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; + +#include "imx6dl.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-ti.dtsi" +#include "imx6qdl-hummingboard2.dtsi" + +/ { + model = "SolidRun HummingBoard2 Solo/DualLite (1.5som)"; + compatible = "solidrun,hummingboard2/dl", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6dl-hummingboard2.dts b/arch/arm/boot/dts/imx6dl-hummingboard2.dts new file mode 100644 index 000000000000..b12cd87f3f94 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-hummingboard2.dts @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 Rabeeh Khoury + * Based on dt work by Russell King + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; + +#include "imx6dl.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-brcm.dtsi" +#include "imx6qdl-hummingboard2.dtsi" +#include "imx6qdl-hummingboard2-emmc.dtsi" + +/ { + model = "SolidRun HummingBoard2 Solo/DualLite"; + compatible = "solidrun,hummingboard2/dl", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6dl-pinfunc.h b/arch/arm/boot/dts/imx6dl-pinfunc.h index 0ead323fdbd2..37e430a261de 100644 --- a/arch/arm/boot/dts/imx6dl-pinfunc.h +++ b/arch/arm/boot/dts/imx6dl-pinfunc.h @@ -668,6 +668,7 @@ #define MX6QDL_PAD_ENET_RX_ER__SPDIF_IN 0x1f4 0x5c4 0x8f0 0x3 0x1 #define MX6QDL_PAD_ENET_RX_ER__ENET_1588_EVENT2_OUT 0x1f4 0x5c4 0x000 0x4 0x0 #define MX6QDL_PAD_ENET_RX_ER__GPIO1_IO24 0x1f4 0x5c4 0x000 0x5 0x0 +#define MX6QDL_PAD_ENET_RXD0__OSC32K_32K_OUT 0x1f8 0x5c8 0x000 0x0 0x0 #define MX6QDL_PAD_ENET_RXD0__ENET_RX_DATA0 0x1f8 0x5c8 0x818 0x1 0x0 #define MX6QDL_PAD_ENET_RXD0__ESAI_TX_HF_CLK 0x1f8 0x5c8 0x838 0x2 0x0 #define MX6QDL_PAD_ENET_RXD0__SPDIF_OUT 0x1f8 0x5c8 0x000 0x3 0x0 diff --git a/arch/arm/boot/dts/imx6dl-ts7970.dts b/arch/arm/boot/dts/imx6dl-ts7970.dts new file mode 100644 index 000000000000..d104daf305d9 --- /dev/null +++ b/arch/arm/boot/dts/imx6dl-ts7970.dts @@ -0,0 +1,50 @@ +/* + * Copyright 2015 Technologic Systems + * Copyright 2017 Savoir-faire Linux + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "imx6dl.dtsi" +#include "imx6qdl-ts7970.dtsi" + +/ { + model = "Technologic Systems i.MX6 Solo/DualLite TS-7970 (Default Device Tree)"; + compatible = "technologic,imx6dl-ts7970", "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi index 4d693a75ce98..c01674fa098a 100644 --- a/arch/arm/boot/dts/imx6dl.dtsi +++ b/arch/arm/boot/dts/imx6dl.dtsi @@ -170,7 +170,7 @@ }; &gpr { - ipu1_csi0_mux: ipu1_csi0_mux@34 { + ipu1_csi0_mux { compatible = "video-mux"; mux-controls = <&mux 0>; #address-cells = <1>; @@ -224,7 +224,7 @@ }; }; - ipu1_csi1_mux: ipu1_csi1_mux@34 { + ipu1_csi1_mux { compatible = "video-mux"; mux-controls = <&mux 1>; #address-cells = <1>; @@ -309,10 +309,12 @@ #size-cells = <0>; mipi_vc0_to_ipu1_csi0_mux: endpoint@0 { + reg = <0>; remote-endpoint = <&ipu1_csi0_mux_from_mipi_vc0>; }; mipi_vc0_to_ipu1_csi1_mux: endpoint@1 { + reg = <1>; remote-endpoint = <&ipu1_csi1_mux_from_mipi_vc0>; }; }; @@ -323,10 +325,12 @@ #size-cells = <0>; mipi_vc1_to_ipu1_csi0_mux: endpoint@0 { + reg = <0>; remote-endpoint = <&ipu1_csi0_mux_from_mipi_vc1>; }; mipi_vc1_to_ipu1_csi1_mux: endpoint@1 { + reg = <1>; remote-endpoint = <&ipu1_csi1_mux_from_mipi_vc1>; }; }; @@ -337,10 +341,12 @@ #size-cells = <0>; mipi_vc2_to_ipu1_csi0_mux: endpoint@0 { + reg = <0>; remote-endpoint = <&ipu1_csi0_mux_from_mipi_vc2>; }; mipi_vc2_to_ipu1_csi1_mux: endpoint@1 { + reg = <1>; remote-endpoint = <&ipu1_csi1_mux_from_mipi_vc2>; }; }; @@ -351,10 +357,12 @@ #size-cells = <0>; mipi_vc3_to_ipu1_csi0_mux: endpoint@0 { + reg = <0>; remote-endpoint = <&ipu1_csi0_mux_from_mipi_vc3>; }; mipi_vc3_to_ipu1_csi1_mux: endpoint@1 { + reg = <1>; remote-endpoint = <&ipu1_csi1_mux_from_mipi_vc3>; }; }; diff --git a/arch/arm/boot/dts/imx6q-apalis-eval.dts b/arch/arm/boot/dts/imx6q-apalis-eval.dts index 8b56656e53da..aa0e631f3c0a 100644 --- a/arch/arm/boot/dts/imx6q-apalis-eval.dts +++ b/arch/arm/boot/dts/imx6q-apalis-eval.dts @@ -158,7 +158,7 @@ /* M41T0M6 real time clock on carrier board */ rtc_i2c: rtc@68 { - compatible = "st,m41t00"; + compatible = "st,m41t0"; reg = <0x68>; }; }; diff --git a/arch/arm/boot/dts/imx6q-apalis-ixora-v1.1.dts b/arch/arm/boot/dts/imx6q-apalis-ixora-v1.1.dts index 27dc0fc686a9..e8dccf552122 100644 --- a/arch/arm/boot/dts/imx6q-apalis-ixora-v1.1.dts +++ b/arch/arm/boot/dts/imx6q-apalis-ixora-v1.1.dts @@ -170,7 +170,7 @@ /* M41T0M6 real time clock on carrier board */ rtc_i2c: rtc@68 { - compatible = "st,m41t00"; + compatible = "st,m41t0"; reg = <0x68>; }; }; diff --git a/arch/arm/boot/dts/imx6q-apalis-ixora.dts b/arch/arm/boot/dts/imx6q-apalis-ixora.dts index 40b2c67fe7af..6831dfd24cc1 100644 --- a/arch/arm/boot/dts/imx6q-apalis-ixora.dts +++ b/arch/arm/boot/dts/imx6q-apalis-ixora.dts @@ -174,7 +174,7 @@ /* M41T0M6 real time clock on carrier board */ rtc_i2c: rtc@68 { - compatible = "st,m41t00"; + compatible = "st,m41t0"; reg = <0x68>; }; }; diff --git a/arch/arm/boot/dts/imx6q-b450v3.dts b/arch/arm/boot/dts/imx6q-b450v3.dts index 404a93d9596b..3ec58500e9c2 100644 --- a/arch/arm/boot/dts/imx6q-b450v3.dts +++ b/arch/arm/boot/dts/imx6q-b450v3.dts @@ -112,3 +112,55 @@ line-name = "PCA9539-P07"; }; }; + +&pci_root { + /* Intel Corporation I210 Gigabit Network Connection */ + switch_nic: ethernet@3,0 { + compatible = "pci8086,1533"; + reg = <0x00010000 0 0 0 0>; + }; +}; + +&switch_ports { + port@0 { + reg = <0>; + label = "enacq"; + phy-handle = <&switchphy0>; + }; + + port@1 { + reg = <1>; + label = "eneport1"; + phy-handle = <&switchphy1>; + }; + + port@2 { + reg = <2>; + label = "enix"; + phy-handle = <&switchphy2>; + }; + + port@3 { + reg = <3>; + label = "enid"; + phy-handle = <&switchphy3>; + }; + + port@4 { + reg = <4>; + label = "cpu"; + ethernet = <&switch_nic>; + phy-handle = <&switchphy4>; + }; + + port@5 { + reg = <5>; + label = "enembc"; + + /* connected to Ethernet MAC of AT91RM9200 in MII mode */ + fixed-link { + speed = <100>; + full-duplex; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx6q-b650v3.dts b/arch/arm/boot/dts/imx6q-b650v3.dts index 7f9f176901d4..5650a9b11091 100644 --- a/arch/arm/boot/dts/imx6q-b650v3.dts +++ b/arch/arm/boot/dts/imx6q-b650v3.dts @@ -111,3 +111,55 @@ fsl,tx-cal-45-dp-ohms = <55>; fsl,tx-d-cal = <100>; }; + +&pci_root { + /* Intel Corporation I210 Gigabit Network Connection */ + switch_nic: ethernet@3,0 { + compatible = "pci8086,1533"; + reg = <0x00010000 0 0 0 0>; + }; +}; + +&switch_ports { + port@0 { + reg = <0>; + label = "enacq"; + phy-handle = <&switchphy0>; + }; + + port@1 { + reg = <1>; + label = "eneport1"; + phy-handle = <&switchphy1>; + }; + + port@2 { + reg = <2>; + label = "enix"; + phy-handle = <&switchphy2>; + }; + + port@3 { + reg = <3>; + label = "enid"; + phy-handle = <&switchphy3>; + }; + + port@4 { + reg = <4>; + label = "cpu"; + ethernet = <&switch_nic>; + phy-handle = <&switchphy4>; + }; + + port@5 { + reg = <5>; + label = "enembc"; + + /* connected to Ethernet MAC of AT91RM9200 in MII mode */ + fixed-link { + speed = <100>; + full-duplex; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx6q-b850v3.dts b/arch/arm/boot/dts/imx6q-b850v3.dts index 46bdc6722715..35edbdc7bcd1 100644 --- a/arch/arm/boot/dts/imx6q-b850v3.dts +++ b/arch/arm/boot/dts/imx6q-b850v3.dts @@ -212,3 +212,78 @@ }; }; }; + +&pci_root { + /* PLX Technology, Inc. PEX 8605 PCI Express 4-port Gen2 Switch */ + bridge@1,0 { + compatible = "pci10b5,8605"; + reg = <0x00010000 0 0 0 0>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + bridge@2,1 { + compatible = "pci10b5,8605"; + reg = <0x00020800 0 0 0 0>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + /* Intel Corporation I210 Gigabit Network Connection */ + ethernet@3,0 { + compatible = "pci8086,1533"; + reg = <0x00030000 0 0 0 0>; + }; + }; + + bridge@2,2 { + compatible = "pci10b5,8605"; + reg = <0x00021000 0 0 0 0>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + /* Intel Corporation I210 Gigabit Network Connection */ + switch_nic: ethernet@4,0 { + compatible = "pci8086,1533"; + reg = <0x00040000 0 0 0 0>; + }; + }; + }; +}; + +&switch_ports { + port@0 { + reg = <0>; + label = "eneport1"; + phy-handle = <&switchphy0>; + }; + + port@1 { + reg = <1>; + label = "eneport2"; + phy-handle = <&switchphy1>; + }; + + port@2 { + reg = <2>; + label = "enix"; + phy-handle = <&switchphy2>; + }; + + port@3 { + reg = <3>; + label = "enid"; + phy-handle = <&switchphy3>; + }; + + port@4 { + reg = <4>; + label = "cpu"; + ethernet = <&switch_nic>; + phy-handle = <&switchphy4>; + }; +}; diff --git a/arch/arm/boot/dts/imx6q-bx50v3.dtsi b/arch/arm/boot/dts/imx6q-bx50v3.dtsi index b915837bbb5f..916ea94d75ca 100644 --- a/arch/arm/boot/dts/imx6q-bx50v3.dtsi +++ b/arch/arm/boot/dts/imx6q-bx50v3.dtsi @@ -92,6 +92,56 @@ mux-int-port = <1>; mux-ext-port = <4>; }; + + aliases { + mdio-gpio0 = &mdio0; + }; + + mdio0: mdio-gpio { + compatible = "virtual,mdio-gpio"; + gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>, /* mdc */ + <&gpio2 7 GPIO_ACTIVE_HIGH>; /* mdio */ + + #address-cells = <1>; + #size-cells = <0>; + + switch@0 { + compatible = "marvell,mv88e6085"; /* 88e6240*/ + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + switch_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + }; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + switchphy0: switchphy@0 { + reg = <0>; + }; + + switchphy1: switchphy@1 { + reg = <1>; + }; + + switchphy2: switchphy@2 { + reg = <2>; + }; + + switchphy3: switchphy@3 { + reg = <3>; + }; + + switchphy4: switchphy@4 { + reg = <4>; + }; + }; + }; + }; }; &ecspi5 { @@ -326,3 +376,15 @@ tcxo-clock-frequency = <26000000>; }; }; + +&pcie { + /* Synopsys, Inc. Device */ + pci_root: root@0,0 { + compatible = "pci16c3,abcd"; + reg = <0x00000000 0 0 0 0>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + }; +}; diff --git a/arch/arm/boot/dts/imx6q-cubox-i-emmc-som-v15.dts b/arch/arm/boot/dts/imx6q-cubox-i-emmc-som-v15.dts new file mode 100644 index 000000000000..3e59ebbb3608 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-cubox-i-emmc-som-v15.dts @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014 Russell King + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; + +#include "imx6q.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-ti.dtsi" +#include "imx6qdl-sr-som-emmc.dtsi" +#include "imx6qdl-cubox-i.dtsi" + +/ { + model = "SolidRun Cubox-i Dual/Quad (1.5som+emmc)"; + compatible = "solidrun,cubox-i/q", "fsl,imx6q"; +}; + +&sata { + status = "okay"; + fsl,transmit-level-mV = <1104>; + fsl,transmit-boost-mdB = <0>; + fsl,transmit-atten-16ths = <9>; + fsl,no-spread-spectrum; +}; diff --git a/arch/arm/boot/dts/imx6q-cubox-i-som-v15.dts b/arch/arm/boot/dts/imx6q-cubox-i-som-v15.dts new file mode 100644 index 000000000000..dab70d1230a2 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-cubox-i-som-v15.dts @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2014 Russell King + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; + +#include "imx6q.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-ti.dtsi" +#include "imx6qdl-cubox-i.dtsi" + +/ { + model = "SolidRun Cubox-i Dual/Quad (1.5som)"; + compatible = "solidrun,cubox-i/q", "fsl,imx6q"; +}; + +&sata { + status = "okay"; + fsl,transmit-level-mV = <1104>; + fsl,transmit-boost-mdB = <0>; + fsl,transmit-atten-16ths = <9>; + fsl,no-spread-spectrum; +}; diff --git a/arch/arm/boot/dts/imx6q-cubox-i.dts b/arch/arm/boot/dts/imx6q-cubox-i.dts index b68aa0e57f20..1c7b262e3709 100644 --- a/arch/arm/boot/dts/imx6q-cubox-i.dts +++ b/arch/arm/boot/dts/imx6q-cubox-i.dts @@ -41,6 +41,8 @@ /dts-v1/; #include "imx6q.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-brcm.dtsi" #include "imx6qdl-cubox-i.dtsi" / { diff --git a/arch/arm/boot/dts/imx6q-display5.dtsi b/arch/arm/boot/dts/imx6q-display5.dtsi index 4084de43d4d9..09085fde3341 100644 --- a/arch/arm/boot/dts/imx6q-display5.dtsi +++ b/arch/arm/boot/dts/imx6q-display5.dtsi @@ -255,7 +255,7 @@ pinctrl-0 = <&pinctrl_i2c1>; status = "okay"; - codec: tfa9879@6C { + codec: tfa9879@6c { #sound-dai-cells = <0>; compatible = "nxp,tfa9879"; reg = <0x6C>; diff --git a/arch/arm/boot/dts/imx6q-h100.dts b/arch/arm/boot/dts/imx6q-h100.dts index a3269f57df2b..8a2ea6c58902 100644 --- a/arch/arm/boot/dts/imx6q-h100.dts +++ b/arch/arm/boot/dts/imx6q-h100.dts @@ -42,8 +42,8 @@ /dts-v1/; #include "imx6q.dtsi" -#include "imx6qdl-microsom.dtsi" -#include "imx6qdl-microsom-ar8035.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-brcm.dtsi" / { model = "Auvidea H100"; @@ -108,21 +108,6 @@ regulator-always-on; }; - reg_nvcc_sd2: regulator-nvcc-sd2 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_h100_reg_nvcc_sd2>; - compatible = "regulator-gpio"; - regulator-name = "NVCC_SD2"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3300000>; - regulator-type = "voltage"; - regulator-boot-on; - regulator-always-on; - gpios = <&gpio4 9 GPIO_ACTIVE_HIGH>; - states = <1800000 0x1 - 3300000 0x0>; - }; - reg_usbh1_vbus: regulator-usb-h1-vbus { compatible = "regulator-fixed"; enable-active-high; @@ -205,7 +190,7 @@ reset-gpios = <&gpio6 15 GPIO_ACTIVE_LOW>; /* IRQ has a wrong pull resistor which renders it useless */ - port@0 { + port { tc358743_out: endpoint { remote-endpoint = <&mipi_csi2_in>; data-lanes = <1 2 3 4>; @@ -260,12 +245,6 @@ >; }; - pinctrl_h100_reg_nvcc_sd2: h100-reg-nvcc-sd2 { - fsl,pins = < - MX6QDL_PAD_KEY_ROW1__GPIO4_IO09 0x1b0b0 - >; - }; - pinctrl_h100_sgtl5000: h100-sgtl5000 { fsl,pins = < MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 @@ -316,6 +295,7 @@ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 + MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b0b0 >; }; @@ -328,6 +308,7 @@ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x170b9 + MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b0b0 >; }; @@ -340,6 +321,7 @@ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x170f9 + MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b0b0 >; }; }; @@ -348,7 +330,7 @@ &mipi_csi { status = "okay"; - port@0 { + port { mipi_csi2_in: endpoint { remote-endpoint = <&tc358743_out>; data-lanes = <1 2 3 4>; @@ -389,7 +371,6 @@ pinctrl-1 = <&pinctrl_h100_usdhc2_100mhz>; pinctrl-2 = <&pinctrl_h100_usdhc2_200mhz>; vmmc-supply = <®_3p3v>; - vqmmc-supply = <®_nvcc_sd2>; cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6q-hummingboard-emmc-som-v15.dts b/arch/arm/boot/dts/imx6q-hummingboard-emmc-som-v15.dts new file mode 100644 index 000000000000..c51b4e4fd71e --- /dev/null +++ b/arch/arm/boot/dts/imx6q-hummingboard-emmc-som-v15.dts @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2014 Rabeeh Khoury (rabeeh@solid-run.com) + * Based on dt work by Russell King + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; + +#include "imx6q.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-ti.dtsi" +#include "imx6qdl-sr-som-emmc.dtsi" +#include "imx6qdl-hummingboard.dtsi" + +/ { + model = "SolidRun HummingBoard Dual/Quad (1.5som+emmc)"; + compatible = "solidrun,hummingboard/q", "fsl,imx6q"; +}; + +&sata { + status = "okay"; + fsl,transmit-level-mV = <1025>; + fsl,transmit-boost-mdB = <3330>; + fsl,transmit-atten-16ths = <9>; + fsl,receive-eq-mdB = <3000>; +}; diff --git a/arch/arm/boot/dts/imx6q-hummingboard-som-v15.dts b/arch/arm/boot/dts/imx6q-hummingboard-som-v15.dts new file mode 100644 index 000000000000..e4132d62ffa2 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-hummingboard-som-v15.dts @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014 Rabeeh Khoury (rabeeh@solid-run.com) + * Based on dt work by Russell King + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; + +#include "imx6q.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-ti.dtsi" +#include "imx6qdl-hummingboard.dtsi" + +/ { + model = "SolidRun HummingBoard Dual/Quad (1.5som)"; + compatible = "solidrun,hummingboard/q", "fsl,imx6q"; +}; + +&sata { + status = "okay"; + fsl,transmit-level-mV = <1025>; + fsl,transmit-boost-mdB = <3330>; + fsl,transmit-atten-16ths = <9>; + fsl,receive-eq-mdB = <3000>; +}; diff --git a/arch/arm/boot/dts/imx6q-hummingboard.dts b/arch/arm/boot/dts/imx6q-hummingboard.dts index 69a7a0a1cb21..8c9e94e648a7 100644 --- a/arch/arm/boot/dts/imx6q-hummingboard.dts +++ b/arch/arm/boot/dts/imx6q-hummingboard.dts @@ -42,6 +42,8 @@ /dts-v1/; #include "imx6q.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-brcm.dtsi" #include "imx6qdl-hummingboard.dtsi" / { diff --git a/arch/arm/boot/dts/imx6q-hummingboard2-emmc-som-v15.dts b/arch/arm/boot/dts/imx6q-hummingboard2-emmc-som-v15.dts new file mode 100644 index 000000000000..1998ebfa0fe0 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-hummingboard2-emmc-som-v15.dts @@ -0,0 +1,63 @@ +/* + * Device Tree file for SolidRun HummingBoard2 + * Copyright (C) 2015 Rabeeh Khoury + * Based on work by Russell King + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License. + * + * This file 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. + * + * Or, alternatively + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; + +#include "imx6q.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-emmc.dtsi" +#include "imx6qdl-sr-som-ti.dtsi" +#include "imx6qdl-hummingboard2.dtsi" + +/ { + model = "SolidRun HummingBoard2 Dual/Quad (1.5som+emmc)"; + compatible = "solidrun,hummingboard2/q", "fsl,imx6q"; +}; + +&sata { + status = "okay"; + fsl,transmit-level-mV = <1104>; + fsl,transmit-boost-mdB = <0>; + fsl,transmit-atten-16ths = <9>; + fsl,no-spread-spectrum; +}; diff --git a/arch/arm/boot/dts/imx6q-hummingboard2-som-v15.dts b/arch/arm/boot/dts/imx6q-hummingboard2-som-v15.dts new file mode 100644 index 000000000000..d3ad7329cd6d --- /dev/null +++ b/arch/arm/boot/dts/imx6q-hummingboard2-som-v15.dts @@ -0,0 +1,62 @@ +/* + * Device Tree file for SolidRun HummingBoard2 + * Copyright (C) 2015 Rabeeh Khoury + * Based on work by Russell King + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License. + * + * This file 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. + * + * Or, alternatively + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; + +#include "imx6q.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-ti.dtsi" +#include "imx6qdl-hummingboard2.dtsi" + +/ { + model = "SolidRun HummingBoard2 Dual/Quad (1.5som)"; + compatible = "solidrun,hummingboard2/q", "fsl,imx6q"; +}; + +&sata { + status = "okay"; + fsl,transmit-level-mV = <1104>; + fsl,transmit-boost-mdB = <0>; + fsl,transmit-atten-16ths = <9>; + fsl,no-spread-spectrum; +}; diff --git a/arch/arm/boot/dts/imx6q-hummingboard2.dts b/arch/arm/boot/dts/imx6q-hummingboard2.dts new file mode 100644 index 000000000000..5249f53dcdbc --- /dev/null +++ b/arch/arm/boot/dts/imx6q-hummingboard2.dts @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2015 Rabeeh Khoury + * Based on dt work by Russell King + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; + +#include "imx6q.dtsi" +#include "imx6qdl-sr-som.dtsi" +#include "imx6qdl-sr-som-brcm.dtsi" +#include "imx6qdl-hummingboard2.dtsi" +#include "imx6qdl-hummingboard2-emmc.dtsi" + +/ { + model = "SolidRun HummingBoard2 Dual/Quad"; + compatible = "solidrun,hummingboard2/q", "fsl,imx6q"; +}; + +&sata { + status = "okay"; + fsl,transmit-level-mV = <1104>; + fsl,transmit-boost-mdB = <0>; + fsl,transmit-atten-16ths = <9>; + fsl,no-spread-spectrum; +}; diff --git a/arch/arm/boot/dts/imx6q-pinfunc.h b/arch/arm/boot/dts/imx6q-pinfunc.h index 9fc6120a1853..cfb11d3e739c 100644 --- a/arch/arm/boot/dts/imx6q-pinfunc.h +++ b/arch/arm/boot/dts/imx6q-pinfunc.h @@ -551,6 +551,7 @@ #define MX6QDL_PAD_ENET_RXD1__ESAI_TX_FS 0x1e0 0x4f4 0x860 0x2 0x0 #define MX6QDL_PAD_ENET_RXD1__ENET_1588_EVENT3_OUT 0x1e0 0x4f4 0x000 0x4 0x0 #define MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x1e0 0x4f4 0x000 0x5 0x0 +#define MX6QDL_PAD_ENET_RXD0__OSC32K_32K_OUT 0x1e4 0x4f8 0x000 0x0 0x0 #define MX6QDL_PAD_ENET_RXD0__ENET_RX_DATA0 0x1e4 0x4f8 0x848 0x1 0x1 #define MX6QDL_PAD_ENET_RXD0__ESAI_TX_HF_CLK 0x1e4 0x4f8 0x868 0x2 0x0 #define MX6QDL_PAD_ENET_RXD0__SPDIF_OUT 0x1e4 0x4f8 0x000 0x3 0x0 diff --git a/arch/arm/boot/dts/imx6q-ts7970.dts b/arch/arm/boot/dts/imx6q-ts7970.dts new file mode 100644 index 000000000000..f19e18995e68 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-ts7970.dts @@ -0,0 +1,54 @@ +/* + * Copyright 2015 Technologic Systems + * Copyright 2017 Savoir-faire Linux + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/dts-v1/; +#include "imx6q.dtsi" +#include "imx6qdl-ts7970.dtsi" + +/ { + model = "Technologic Systems i.MX6 Quad TS-7970 (Default Device Tree)"; + compatible = "technologic,imx6q-ts7970", "fsl,imx6q"; +}; + +&sata { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6q-var-dt6customboard.dts b/arch/arm/boot/dts/imx6q-var-dt6customboard.dts new file mode 100644 index 000000000000..e0728d475f6f --- /dev/null +++ b/arch/arm/boot/dts/imx6q-var-dt6customboard.dts @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Support for Variscite DART-MX6 Carrier-board + * + * Copyright 2017 BayLibre, SAS + * Author: Neil Armstrong + */ + +/dts-v1/; + +#include "imx6q.dtsi" +#include "imx6qdl-var-dart.dtsi" +#include + +/ { + model = "Variscite DART-MX6 Carrier-board"; + compatible = "variscite,dt6customboard", "fsl,imx6q"; + + backlight_lvds: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm2 0 50000>; + brightness-levels = <0 4 8 16 32 64 128 248>; + default-brightness-level = <7>; + status = "okay"; + }; + + gpio-keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + autorepeat; + + back { + gpios = <&gpio4 26 GPIO_ACTIVE_LOW>; + linux,code = ; + label = "Key Back"; + linux,input-type = <1>; + debounce-interval = <100>; + wakeup-source; + }; + + home { + gpios = <&gpio5 11 GPIO_ACTIVE_LOW>; + linux,code = ; + label = "Key Home"; + linux,input-type = <1>; + debounce-interval = <100>; + wakeup-source; + }; + + menu { + gpios = <&gpio4 25 GPIO_ACTIVE_LOW>; + linux,code = ; + label = "Key Menu"; + linux,input-type = <1>; + debounce-interval = <100>; + wakeup-source; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + + led1 { + gpios = <&gpio4 27 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + + led2 { + gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "default-on"; + }; + }; + + panel1: lvds-panel { + compatible = "sgd,gktw70sdae4se", "panel-lvds"; + backlight = <&backlight_lvds>; + width-mm = <153>; + height-mm = <86>; + label = "gktw70sdae4se"; + data-mapping = "jeida-18"; + + panel-timing { + clock-frequency = <32000000>; + hactive = <800>; + vactive = <480>; + hback-porch = <39>; + hfront-porch = <39>; + vback-porch = <29>; + vfront-porch = <13>; + hsync-len = <47>; + vsync-len = <2>; + }; + + port { + panel_in: endpoint { + remote-endpoint = <&lvds1_out>; + }; + }; + }; + + reg_usb_h1_vbus: regulator-usbh1vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_h1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 28 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_usb_otg_vbus: regulator-usbotgvbus { + compatible = "regulator-fixed"; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio4 15 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "dt6-customboard-audio"; + simple-audio-card,format = "i2s"; + simple-audio-card,bitclock-master = <&sound_codec>; + simple-audio-card,frame-master = <&sound_codec>; + simple-audio-card,widgets = "Headphone", "Headphone Jack", + "Line", "Line In"; + simple-audio-card,routing = "Headphone Jack", "HPLOUT", + "Headphone Jack", "HPROUT", + "LINE1L", "Line In", + "LINE1R", "Line In"; + + sound_cpu: simple-audio-card,cpu { + sound-dai = <&ssi2>; + }; + + sound_codec: simple-audio-card,codec { + sound-dai = <&tlv320aic3106>; + clocks = <&clks IMX6QDL_CLK_CKO>; + }; + }; +}; + +&can1 { + status = "okay"; +}; + +&ecspi1 { + cs-gpios = <&gpio4 9 GPIO_ACTIVE_HIGH>, + <&gpio4 10 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&fec { + status = "okay"; + phy-mode = "rgmii"; + phy-reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>; +}; + +&hdmi { + status = "okay"; +}; + +&i2c1 { + clock-frequency = <100000>; + status = "okay"; +}; + +&i2c3 { + clock-frequency = <100000>; + status = "okay"; + + touchscreen@38 { + compatible = "edt,edt-ft5x06"; + reg = <0x38>; + interrupt-parent = <&gpio1>; + interrupts = <4 IRQ_TYPE_EDGE_FALLING>; + touchscreen-size-x = <800>; + touchscreen-size-y = <480>; + touchscreen-inverted-x; + touchscreen-inverted-y; + }; + + rtc@68 { + compatible = "isil,isl12057"; + reg = <0x68>; + }; +}; + +&ldb { + status = "okay"; + + lvds-channel@1 { + status = "okay"; + + port@4 { + reg = <4>; + + lvds1_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; +}; + +&pwm2 { + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; + +&uart3 { + status = "okay"; +}; + +&usbh1 { + vbus-supply = <®_usb_h1_vbus>; + status = "okay"; +}; + +&usbotg { + vbus-supply = <®_usb_otg_vbus>; + dr_mode = "otg"; + srp-disable; + hnp-disable; + adp-disable; + status = "okay"; +}; + +&usdhc2 { + cd-gpios = <&gpio1 6 GPIO_ACTIVE_LOW>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-apalis.dtsi b/arch/arm/boot/dts/imx6qdl-apalis.dtsi index e80fdca585f8..4e776e036cbc 100644 --- a/arch/arm/boot/dts/imx6qdl-apalis.dtsi +++ b/arch/arm/boot/dts/imx6qdl-apalis.dtsi @@ -338,7 +338,6 @@ stmpe_touchscreen { compatible = "st,stmpe-ts"; - reg = <0>; /* 3.25 MHz ADC clock speed */ st,adc-freq = <1>; /* 8 sample average control */ diff --git a/arch/arm/boot/dts/imx6qdl-apf6dev.dtsi b/arch/arm/boot/dts/imx6qdl-apf6dev.dtsi index 829a47938179..9fc1fa449f64 100644 --- a/arch/arm/boot/dts/imx6qdl-apf6dev.dtsi +++ b/arch/arm/boot/dts/imx6qdl-apf6dev.dtsi @@ -111,32 +111,28 @@ }; }; - regulators { - compatible = "simple-bus"; + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; - reg_3p3v: 3p3v { - compatible = "regulator-fixed"; - regulator-name = "3P3V"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; + reg_usbh1_vbus: regulator-usb-h1-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_h1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; - reg_usbh1_vbus: usb-h1-vbus { - compatible = "regulator-fixed"; - regulator-name = "usb_h1_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - regulator-always-on; - }; - - reg_usb_otg_vbus: usb-otg-vbus { - compatible = "regulator-fixed"; - regulator-name = "usb_otg_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - regulator-always-on; - }; + reg_usb_otg_vbus: regulator-usb-otg-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; }; sound { diff --git a/arch/arm/boot/dts/imx6qdl-aristainetos.dtsi b/arch/arm/boot/dts/imx6qdl-aristainetos.dtsi index 7d64075204ae..ee4d0f84eeb2 100644 --- a/arch/arm/boot/dts/imx6qdl-aristainetos.dtsi +++ b/arch/arm/boot/dts/imx6qdl-aristainetos.dtsi @@ -12,48 +12,43 @@ #include / { - regulators { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - reg_2p5v: regulator@0 { - compatible = "regulator-fixed"; - regulator-name = "2P5V"; - regulator-min-microvolt = <2500000>; - regulator-max-microvolt = <2500000>; - regulator-always-on; - }; + reg_2p5v: regulator-2p5v { + compatible = "regulator-fixed"; + regulator-name = "2P5V"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + }; - reg_3p3v: regulator@1 { - compatible = "regulator-fixed"; - regulator-name = "3P3V"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; - reg_usbh1_vbus: regulator@2 { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio3 31 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_aristainetos_usbh1_vbus>; - regulator-name = "usb_h1_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - }; + reg_usbh1_vbus: regulator-usbh1-vbus { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio3 31 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_aristainetos_usbh1_vbus>; + regulator-name = "usb_h1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; - reg_usbotg_vbus: regulator@3 { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio4 15 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_aristainetos_usbotg_vbus>; - regulator-name = "usb_otg_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - }; + reg_usbotg_vbus: regulator-usbotg-vbus { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio4 15 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_aristainetos_usbotg_vbus>; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; }; }; diff --git a/arch/arm/boot/dts/imx6qdl-aristainetos2.dtsi b/arch/arm/boot/dts/imx6qdl-aristainetos2.dtsi index 1b1872873207..376750882ed3 100644 --- a/arch/arm/boot/dts/imx6qdl-aristainetos2.dtsi +++ b/arch/arm/boot/dts/imx6qdl-aristainetos2.dtsi @@ -52,46 +52,42 @@ enable-gpios = <&gpio6 31 GPIO_ACTIVE_HIGH>; }; - regulators { - compatible = "simple-bus"; + reg_2p5v: regulator-2p5v { + compatible = "regulator-fixed"; + regulator-name = "2P5V"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + }; - reg_2p5v: 2p5v { - compatible = "regulator-fixed"; - regulator-name = "2P5V"; - regulator-min-microvolt = <2500000>; - regulator-max-microvolt = <2500000>; - regulator-always-on; - }; + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; - reg_3p3v: 3p3v { - compatible = "regulator-fixed"; - regulator-name = "3P3V"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; + reg_usbh1_vbus: regulator-usbh1-vbus { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio1 0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_aristainetos2_usbh1_vbus>; + regulator-name = "usb_h1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; - reg_usbh1_vbus: usb-h1-vbus { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio1 0 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_aristainetos2_usbh1_vbus>; - regulator-name = "usb_h1_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - }; - - reg_usbotg_vbus: usb-otg-vbus { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio4 15 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_aristainetos2_usbotg_vbus>; - regulator-name = "usb_otg_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - }; + reg_usbotg_vbus: regulator-usbotg-vbus { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio4 15 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_aristainetos2_usbotg_vbus>; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; }; }; diff --git a/arch/arm/boot/dts/imx6qdl-colibri.dtsi b/arch/arm/boot/dts/imx6qdl-colibri.dtsi index fc66bbfd6796..e4eb300549d4 100644 --- a/arch/arm/boot/dts/imx6qdl-colibri.dtsi +++ b/arch/arm/boot/dts/imx6qdl-colibri.dtsi @@ -274,7 +274,6 @@ stmpe_touchscreen { compatible = "st,stmpe-ts"; - reg = <0>; /* 3.25 MHz ADC clock speed */ st,adc-freq = <1>; /* 8 sample average control */ diff --git a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi index 14fff4ee6516..d1cfdc264126 100644 --- a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi +++ b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi @@ -38,8 +38,6 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ -#include "imx6qdl-microsom.dtsi" -#include "imx6qdl-microsom-ar8035.dtsi" #include #include @@ -64,38 +62,36 @@ }; }; - regulators { - compatible = "simple-bus"; + v_5v0: regulator-v-5v0 { + compatible = "regulator-fixed"; + regulator-always-on; + regulator-max-microvolt = <5000000>; + regulator-min-microvolt = <5000000>; + regulator-name = "v_5v0"; + }; - reg_3p3v: 3p3v { - compatible = "regulator-fixed"; - regulator-name = "3P3V"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; + v_usb2: regulator-v-usb2 { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio1 0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cubox_i_usbh1_vbus>; + regulator-max-microvolt = <5000000>; + regulator-min-microvolt = <5000000>; + regulator-name = "v_usb2"; + vin-supply = <&v_5v0>; + }; - reg_usbh1_vbus: usb-h1-vbus { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio1 0 0>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_cubox_i_usbh1_vbus>; - regulator-name = "usb_h1_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - }; - - reg_usbotg_vbus: usb-otg-vbus { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio3 22 0>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_cubox_i_usbotg_vbus>; - regulator-name = "usb_otg_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - }; + v_usb1: regulator-v-usb1 { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cubox_i_usbotg_vbus>; + regulator-max-microvolt = <5000000>; + regulator-min-microvolt = <5000000>; + regulator-name = "v_usb1"; + vin-supply = <&v_5v0>; }; sound-spdif { @@ -139,7 +135,7 @@ status = "okay"; - rtc: pcf8523@68 { + rtc@68 { compatible = "nxp,pcf8523"; reg = <0x68>; }; @@ -243,21 +239,25 @@ &usbh1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_cubox_i_usbh1>; - vbus-supply = <®_usbh1_vbus>; + vbus-supply = <&v_usb2>; status = "okay"; }; &usbotg { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_cubox_i_usbotg>; - vbus-supply = <®_usbotg_vbus>; + vbus-supply = <&v_usb1>; status = "okay"; }; &usdhc2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2>; - vmmc-supply = <®_3p3v>; + vmmc-supply = <&vcc_3v3>; cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; status = "okay"; }; + +&vcc_3v3 { + vin-supply = <&v_5v0>; +}; diff --git a/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi b/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi index 37c07c0748aa..92583238ca4a 100644 --- a/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi +++ b/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi @@ -38,8 +38,6 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ -#include "imx6qdl-microsom.dtsi" -#include "imx6qdl-microsom-ar8035.dtsi" / { chosen { @@ -53,38 +51,58 @@ pinctrl-0 = <&pinctrl_hummingboard_gpio3_5>; }; - regulators { - compatible = "simple-bus"; + v_3v2: regulator-v-3v2 { + compatible = "regulator-fixed"; + regulator-always-on; + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3300000>; + regulator-name = "v_3v2"; + vin-supply = <&v_5v0>; + }; - reg_3p3v: 3p3v { - compatible = "regulator-fixed"; - regulator-name = "3P3V"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; + v_5v0: regulator-v-5v0 { + compatible = "regulator-fixed"; + regulator-always-on; + regulator-max-microvolt = <5000000>; + regulator-min-microvolt = <5000000>; + regulator-name = "v_5v0"; + }; - reg_usbh1_vbus: usb-h1-vbus { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio1 0 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_hummingboard_usbh1_vbus>; - regulator-name = "usb_h1_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - }; + v_sd: regulator-v-sd { + compatible = "regulator-fixed"; + gpio = <&gpio4 30 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard_vmmc>; + regulator-boot-on; + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3300000>; + regulator-name = "v_sd"; + startup-delay-us = <1000>; + vin-supply = <&v_3v2>; + }; - reg_usbotg_vbus: usb-otg-vbus { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_hummingboard_usbotg_vbus>; - regulator-name = "usb_otg_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - }; + v_usb2: regulator-v-usb2 { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio1 0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard_usbh1_vbus>; + regulator-max-microvolt = <5000000>; + regulator-min-microvolt = <5000000>; + regulator-name = "v_usb2"; + vin-supply = <&v_5v0>; + }; + + v_usb1: regulator-v-usb1 { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard_usbotg_vbus>; + regulator-max-microvolt = <5000000>; + regulator-min-microvolt = <5000000>; + regulator-name = "v_usb1"; + vin-supply = <&v_5v0>; }; sound-sgtl5000 { @@ -132,20 +150,20 @@ status = "okay"; /* Pro baseboard model */ - rtc: pcf8523@68 { + rtc@68 { compatible = "nxp,pcf8523"; reg = <0x68>; }; /* Pro baseboard model */ - sgtl5000: sgtl5000@a { + sgtl5000: codec@a { clocks = <&clks IMX6QDL_CLK_CKO>; compatible = "fsl,sgtl5000"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hummingboard_sgtl5000>; reg = <0x0a>; - VDDA-supply = <®_3p3v>; - VDDIO-supply = <®_3p3v>; + VDDA-supply = <&v_3v2>; + VDDIO-supply = <&v_3v2>; }; }; @@ -247,6 +265,11 @@ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 >; }; + pinctrl_hummingboard_vmmc: hummingboard-vmmc { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT9__GPIO4_IO30 0x1b0b0 + >; + }; }; }; @@ -280,7 +303,7 @@ &usbh1 { disable-over-current; - vbus-supply = <®_usbh1_vbus>; + vbus-supply = <&v_usb2>; status = "okay"; }; @@ -288,7 +311,7 @@ disable-over-current; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hummingboard_usbotg_id>; - vbus-supply = <®_usbotg_vbus>; + vbus-supply = <&v_usb1>; status = "okay"; }; @@ -298,7 +321,11 @@ &pinctrl_hummingboard_usdhc2_aux &pinctrl_hummingboard_usdhc2 >; - vmmc-supply = <®_3p3v>; + vmmc-supply = <&v_sd>; cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; status = "okay"; }; + +&vcc_3v3 { + vin-supply = <&v_3v2>; +}; diff --git a/arch/arm/boot/dts/imx6qdl-hummingboard2-emmc.dtsi b/arch/arm/boot/dts/imx6qdl-hummingboard2-emmc.dtsi new file mode 100644 index 000000000000..f400405381a7 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-hummingboard2-emmc.dtsi @@ -0,0 +1,72 @@ +/* + * Device Tree file for SolidRun HummingBoard2 + * Copyright (C) 2015 Rabeeh Khoury + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +&iomuxc { + hummingboard2 { + pinctrl_hummingboard2_usdhc3: hummingboard2-usdhc3 { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 + MX6QDL_PAD_SD3_RST__SD3_RESET 0x17059 + >; + }; + }; +}; + +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_usdhc3>; + vmmc-supply = <&v_3v2>; + vqmmc-supply = <&v_3v2>; + bus-width = <8>; + non-removable; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-hummingboard2.dtsi b/arch/arm/boot/dts/imx6qdl-hummingboard2.dtsi new file mode 100644 index 000000000000..dffbc92e0023 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-hummingboard2.dtsi @@ -0,0 +1,540 @@ +/* + * Copyright (C) 2015 Rabeeh Khoury + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/ { + chosen { + stdout-path = &uart1; + }; + + ir_recv: ir-receiver { + compatible = "gpio-ir-receiver"; + gpios = <&gpio7 9 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_gpio7_9>; + linux,rc-map-name = "rc-rc6-mce"; + }; + + v_3v2: regulator-v-3v2 { + compatible = "regulator-fixed"; + regulator-always-on; + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3300000>; + regulator-name = "v_3v2"; + }; + + v_5v0: regulator-v-5v0 { + compatible = "regulator-fixed"; + regulator-always-on; + regulator-max-microvolt = <5000000>; + regulator-min-microvolt = <5000000>; + regulator-name = "v_5v0"; + }; + + vcc_1p8: regulator-vcc-1p8 { + compatible = "regulator-fixed"; + regulator-always-on; + regulator-max-microvolt = <1800000>; + regulator-min-microvolt = <1800000>; + regulator-name = "vcc_1p8"; + vin-supply = <&v_3v2>; + }; + + v_sd: regulator-v-sd { + compatible = "regulator-fixed"; + gpio = <&gpio4 30 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_vmmc>; + regulator-boot-on; + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3300000>; + regulator-name = "v_sd"; + startup-delay-us = <1000>; + vin-supply = <&v_3v2>; + }; + + v_usb1: regulator-v-usb1 { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_usbotg_vbus>; + regulator-always-on; + regulator-max-microvolt = <5000000>; + regulator-min-microvolt = <5000000>; + regulator-name = "v_usb1"; + vin-supply = <&v_5v0>; + }; + + v_usb2: regulator-v-usb2 { + /* USB hub port 1 */ + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio1 0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_usbh1_vbus>; + regulator-always-on; + regulator-max-microvolt = <5000000>; + regulator-min-microvolt = <5000000>; + regulator-name = "v_usb2"; + vin-supply = <&v_5v0>; + }; + + v_usb3: regulator-v-usb3 { + /* USB hub port 3 */ + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio2 13 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_usbh2_vbus>; + regulator-always-on; + regulator-max-microvolt = <5000000>; + regulator-min-microvolt = <5000000>; + regulator-name = "v_usb3"; + vin-supply = <&v_5v0>; + }; + + v_usb4: regulator-v-usb4 { + /* USB hub port 4 */ + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio7 10 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_usbh3_vbus>; + regulator-always-on; + regulator-max-microvolt = <5000000>; + regulator-min-microvolt = <5000000>; + regulator-name = "v_usb4"; + vin-supply = <&v_5v0>; + }; + + sound-sgtl5000 { + audio-codec = <&sgtl5000>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; + compatible = "fsl,imx-audio-sgtl5000"; + model = "On-board Codec"; + mux-ext-port = <5>; + mux-int-port = <1>; + ssi-controller = <&ssi1>; + }; +}; + +&audmux { + status = "okay"; +}; + +&ecspi2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_ecspi2>; + cs-gpios = <&gpio2 26 0>; + status = "okay"; +}; + +&hdmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_hdmi>; + ddc-i2c-bus = <&i2c2>; + status = "okay"; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_i2c1>; + status = "okay"; + + pcf8523: rtc@68 { + compatible = "nxp,pcf8523"; + reg = <0x68>; + }; + + sgtl5000: codec@a { + clocks = <&clks IMX6QDL_CLK_CKO>; + compatible = "fsl,sgtl5000"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_sgtl5000>; + reg = <0x0a>; + VDDA-supply = <&v_3v2>; + VDDD-supply = <&vcc_1p8>; + VDDIO-supply = <&v_3v2>; + }; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_i2c2>; + status = "okay"; +}; + +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_i2c3>; + status = "okay"; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + hummingboard2 { + pinctrl_hog: hoggrp { + fsl,pins = < + /* + * 36 pin headers GPIO description. The pins + * numbering as following - + * + * 3.2v 5v 74 75 + * 73 72 71 70 + * 69 68 67 66 + * + * 77 78 79 76 + * 65 64 61 60 + * 53 52 51 50 + * 49 48 166 132 + * 95 94 90 91 + * GND 54 24 204 + * + * The GPIO numbers can be extracted using + * signal name from below. + * Example - + * MX6QDL_PAD_EIM_DA10__GPIO3_IO10 is + * GPIO(3,10) which is (3-1)*32+10 = gpio 74 + * + * i.e. The mapping of GPIO(X,Y) to Linux gpio + * number is : gpio number = (X-1) * 32 + Y + */ + /* DI1_PIN15 */ + MX6QDL_PAD_EIM_DA10__GPIO3_IO10 0x400130b1 + /* DI1_PIN02 */ + MX6QDL_PAD_EIM_DA11__GPIO3_IO11 0x400130b1 + /* DISP1_DATA00 */ + MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x400130b1 + /* DISP1_DATA01 */ + MX6QDL_PAD_EIM_DA8__GPIO3_IO08 0x400130b1 + /* DISP1_DATA02 */ + MX6QDL_PAD_EIM_DA7__GPIO3_IO07 0x400130b1 + /* DISP1_DATA03 */ + MX6QDL_PAD_EIM_DA6__GPIO3_IO06 0x400130b1 + /* DISP1_DATA04 */ + MX6QDL_PAD_EIM_DA5__GPIO3_IO05 0x400130b1 + /* DISP1_DATA05 */ + MX6QDL_PAD_EIM_DA4__GPIO3_IO04 0x400130b1 + /* DISP1_DATA06 */ + MX6QDL_PAD_EIM_DA3__GPIO3_IO03 0x400130b1 + /* DISP1_DATA07 */ + MX6QDL_PAD_EIM_DA2__GPIO3_IO02 0x400130b1 + /* DI1_D0_CS */ + MX6QDL_PAD_EIM_DA13__GPIO3_IO13 0x400130b1 + /* DI1_D1_CS */ + MX6QDL_PAD_EIM_DA14__GPIO3_IO14 0x400130b1 + /* DI1_PIN01 */ + MX6QDL_PAD_EIM_DA15__GPIO3_IO15 0x400130b1 + /* DI1_PIN03 */ + MX6QDL_PAD_EIM_DA12__GPIO3_IO12 0x400130b1 + /* DISP1_DATA08 */ + MX6QDL_PAD_EIM_DA1__GPIO3_IO01 0x400130b1 + /* DISP1_DATA09 */ + MX6QDL_PAD_EIM_DA0__GPIO3_IO00 0x400130b1 + /* DISP1_DATA10 */ + MX6QDL_PAD_EIM_EB1__GPIO2_IO29 0x400130b1 + /* DISP1_DATA11 */ + MX6QDL_PAD_EIM_EB0__GPIO2_IO28 0x400130b1 + /* DISP1_DATA12 */ + MX6QDL_PAD_EIM_A17__GPIO2_IO21 0x400130b1 + /* DISP1_DATA13 */ + MX6QDL_PAD_EIM_A18__GPIO2_IO20 0x400130b1 + /* DISP1_DATA14 */ + MX6QDL_PAD_EIM_A19__GPIO2_IO19 0x400130b1 + /* DISP1_DATA15 */ + MX6QDL_PAD_EIM_A20__GPIO2_IO18 0x400130b1 + /* DISP1_DATA16 */ + MX6QDL_PAD_EIM_A21__GPIO2_IO17 0x400130b1 + /* DISP1_DATA17 */ + MX6QDL_PAD_EIM_A22__GPIO2_IO16 0x400130b1 + /* DISP1_DATA18 */ + MX6QDL_PAD_EIM_A23__GPIO6_IO06 0x400130b1 + /* DISP1_DATA19 */ + MX6QDL_PAD_EIM_A24__GPIO5_IO04 0x400130b1 + /* DISP1_DATA20 */ + MX6QDL_PAD_EIM_D31__GPIO3_IO31 0x400130b1 + /* DISP1_DATA21 */ + MX6QDL_PAD_EIM_D30__GPIO3_IO30 0x400130b1 + /* DISP1_DATA22 */ + MX6QDL_PAD_EIM_D26__GPIO3_IO26 0x400130b1 + /* DISP1_DATA23 */ + MX6QDL_PAD_EIM_D27__GPIO3_IO27 0x400130b1 + /* DI1_DISP_CLK */ + MX6QDL_PAD_EIM_A16__GPIO2_IO22 0x400130b1 + /* SPDIF_IN */ + MX6QDL_PAD_ENET_RX_ER__GPIO1_IO24 0x400130b1 + /* SPDIF_OUT */ + MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x400130b1 + + /* MikroBUS GPIO pin number 10 */ + MX6QDL_PAD_EIM_LBA__GPIO2_IO27 0x400130b1 + >; + }; + + pinctrl_hummingboard2_ecspi2: hummingboard2-ecspi2grp { + fsl,pins = < + MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x100b1 + MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x100b1 + MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x100b1 + MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x000b1 /* CS */ + >; + }; + + pinctrl_hummingboard2_gpio7_9: hummingboard2-gpio7_9 { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__GPIO7_IO09 0x80000000 + >; + }; + + pinctrl_hummingboard2_hdmi: hummingboard2-hdmi { + fsl,pins = < + MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 + >; + }; + + pinctrl_hummingboard2_i2c1: hummingboard2-i2c1 { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; + + pinctrl_hummingboard2_i2c2: hummingboard2-i2c2 { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_hummingboard2_i2c3: hummingboard2-i2c3 { + fsl,pins = < + MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 + >; + }; + + pinctrl_hummingboard2_mipi: hummingboard2_mipi { + fsl,pins = < + MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 0x4001b8b1 + MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x4001b8b1 + MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x130b0 + >; + }; + + pinctrl_hummingboard2_pcie_reset: hummingboard2-pcie-reset { + fsl,pins = < + MX6QDL_PAD_SD4_DAT3__GPIO2_IO11 0x1b0b1 + >; + }; + + pinctrl_hummingboard2_pwm1: pwm1grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT8__PWM1_OUT 0x1b0b1 + >; + }; + + pinctrl_hummingboard2_pwm3: pwm3grp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1 + >; + }; + + pinctrl_hummingboard2_sgtl5000: hummingboard2-sgtl5000 { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 + MX6QDL_PAD_KEY_COL0__AUD5_TXC 0x130b0 + MX6QDL_PAD_KEY_ROW0__AUD5_TXD 0x110b0 + MX6QDL_PAD_KEY_COL1__AUD5_TXFS 0x130b0 + MX6QDL_PAD_GPIO_5__CCM_CLKO1 0x130b0 + >; + }; + + pinctrl_hummingboard2_usbh1_vbus: hummingboard2-usbh1-vbus { + fsl,pins = ; + }; + + pinctrl_hummingboard2_usbh2_vbus: hummingboard2-usbh2-vbus { + fsl,pins = ; + }; + + pinctrl_hummingboard2_usbh3_vbus: hummingboard2-usbh3-vbus { + fsl,pins = ; + }; + + pinctrl_hummingboard2_usbotg_id: hummingboard2-usbotg-id { + /* + * Similar to pinctrl_usbotg_2, but we want it + * pulled down for a fixed host connection. + */ + fsl,pins = ; + }; + + pinctrl_hummingboard2_usbotg_vbus: hummingboard2-usbotg-vbus { + fsl,pins = ; + }; + + pinctrl_hummingboard2_usdhc2_aux: hummingboard2-usdhc2-aux { + fsl,pins = < + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 + MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b071 + >; + }; + + pinctrl_hummingboard2_usdhc2: hummingboard2-usdhc2 { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 + >; + }; + + pinctrl_hummingboard2_usdhc2_100mhz: hummingboard2-usdhc2-100mhz { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170b9 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100b9 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170b9 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130b9 + >; + }; + + pinctrl_hummingboard2_usdhc2_200mhz: hummingboard2-usdhc2-200mhz { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170f9 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100f9 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170f9 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130f9 + >; + }; + + pinctrl_hummingboard2_vmmc: hummingboard2-vmmc { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT9__GPIO4_IO30 0x1b0b0 + >; + }; + + pinctrl_hummingboard2_uart3: hummingboard2-uart3 { + fsl,pins = < + MX6QDL_PAD_EIM_D25__UART3_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D24__UART3_RX_DATA 0x40013000 + >; + }; + }; +}; + +&pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_pcie_reset>; + reset-gpio = <&gpio2 11 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_pwm1>; + status = "okay"; +}; + +&pwm3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_pwm3>; + status = "okay"; +}; + +&ssi1 { + status = "okay"; +}; + +&usbh1 { + disable-over-current; + status = "okay"; +}; + +&usbotg { + disable-over-current; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_usbotg_id>; + vbus-supply = <&v_usb1>; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = < + &pinctrl_hummingboard2_usdhc2_aux + &pinctrl_hummingboard2_usdhc2 + >; + pinctrl-1 = < + &pinctrl_hummingboard2_usdhc2_aux + &pinctrl_hummingboard2_usdhc2_100mhz + >; + pinctrl-2 = < + &pinctrl_hummingboard2_usdhc2_aux + &pinctrl_hummingboard2_usdhc2_200mhz + >; + vmmc-supply = <&v_sd>; + cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hummingboard2_uart3>; + status = "okay"; +}; + +&vcc_3v3 { + vin-supply = <&v_3v2>; +}; diff --git a/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi b/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi index 3a77f0fedfce..fd05f7caa472 100644 --- a/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi +++ b/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi @@ -172,7 +172,7 @@ }; }; - i2cmux@2 { + i2c2mux { compatible = "i2c-mux-gpio"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c2mux>; @@ -183,20 +183,20 @@ i2c-parent = <&i2c2>; idle-state = <0>; - i2c2@1 { + i2c2mux@1 { reg = <1>; #address-cells = <1>; #size-cells = <0>; }; - i2c2@2 { + i2c2mux@2 { reg = <2>; #address-cells = <1>; #size-cells = <0>; }; }; - i2cmux@3 { + i2c3mux { compatible = "i2c-mux-gpio"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c3mux>; @@ -206,7 +206,7 @@ i2c-parent = <&i2c3>; idle-state = <0>; - i2c3@1 { + i2c3mux@1 { reg = <1>; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi index 4bdf29169d2a..919b6b7619a4 100644 --- a/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi +++ b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi @@ -276,6 +276,23 @@ compatible = "sst,sst25vf016b", "jedec,spi-nor"; spi-max-frequency = <20000000>; reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bootloader"; + reg = <0x0 0xc0000>; + }; + + partition@c0000 { + label = "env"; + reg = <0xc0000 0x2000>; + }; + + partition@c2000 { + label = "splash"; + reg = <0xc2000 0x13e000>; + }; }; }; diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi index 4fa2fac3877b..82d6ccb46982 100644 --- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi @@ -235,6 +235,9 @@ }; &hdmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hdmi_cec>; + ddc-i2c-bus = <&i2c2>; status = "okay"; }; @@ -453,6 +456,12 @@ >; }; + pinctrl_hdmi_cec: hdmicecgrp { + fsl,pins = < + MX6QDL_PAD_EIM_A25__HDMI_TX_CEC_LINE 0x1f8b0 + >; + }; + pinctrl_i2c2: i2c2grp { fsl,pins = < MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 diff --git a/arch/arm/boot/dts/imx6qdl-microsom.dtsi b/arch/arm/boot/dts/imx6qdl-sr-som-brcm.dtsi similarity index 85% rename from arch/arm/boot/dts/imx6qdl-microsom.dtsi rename to arch/arm/boot/dts/imx6qdl-sr-som-brcm.dtsi index 6a410160c9ee..b55af61dfeca 100644 --- a/arch/arm/boot/dts/imx6qdl-microsom.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sr-som-brcm.dtsi @@ -40,7 +40,7 @@ */ #include / { - clk_sdio: sdio-clock { + clk_brcm: brcm-clock { compatible = "gpio-gate-clock"; #clock-cells = <0>; pinctrl-names = "default"; @@ -48,27 +48,23 @@ enable-gpios = <&gpio5 5 GPIO_ACTIVE_HIGH>; }; - regulators { - compatible = "simple-bus"; - - reg_brcm: brcm-reg { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio3 19 0>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_microsom_brcm_reg>; - regulator-name = "brcm_reg"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - startup-delay-us = <200000>; - }; + reg_brcm: brcm-reg { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio3 19 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_microsom_brcm_reg>; + regulator-name = "brcm_reg"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + startup-delay-us = <200000>; }; usdhc1_pwrseq: usdhc1_pwrseq { compatible = "mmc-pwrseq-simple"; reset-gpios = <&gpio5 26 GPIO_ACTIVE_LOW>, <&gpio6 0 GPIO_ACTIVE_LOW>; - clocks = <&clk_sdio>; + clocks = <&clk_brcm>; clock-names = "ext_clock"; }; }; @@ -104,13 +100,6 @@ >; }; - pinctrl_microsom_uart1: microsom-uart1 { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 - MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 - >; - }; - pinctrl_microsom_uart4: microsom-uart4 { fsl,pins = < MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1 @@ -133,12 +122,6 @@ }; }; -&uart1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_microsom_uart1>; - status = "okay"; -}; - /* UART4 - Connected to optional BRCM Wifi/BT/FM */ &uart4 { pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/imx6qdl-sr-som-emmc.dtsi b/arch/arm/boot/dts/imx6qdl-sr-som-emmc.dtsi new file mode 100644 index 000000000000..5f3b8baab20f --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-sr-som-emmc.dtsi @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2013,2014 Russell King + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +&iomuxc { + microsom { + pinctrl_microsom_usdhc3: microsom-usdhc3 { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 + MX6QDL_PAD_SD3_RST__SD3_RESET 0x17059 + >; + }; + }; +}; + +/* USDHC3 - eMMC */ +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_microsom_usdhc3>; + bus-width = <8>; + non-removable; + vmmc-supply = <&vcc_3v3>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-sr-som-ti.dtsi b/arch/arm/boot/dts/imx6qdl-sr-som-ti.dtsi new file mode 100644 index 000000000000..44a97ba93a95 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-sr-som-ti.dtsi @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2013,2014 Russell King + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include + +/ { + nvcc_sd1: regulator-nvcc-sd1 { + compatible = "regulator-fixed"; + regulator-always-on; + regulator-name = "nvcc_sd1"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vcc_3v3>; + }; + + clk_ti_wifi: ti-wifi-clock { + /* This is a hack around the kernel - using "fixed clock" + * results in the "pinctrl" properties being ignored, and + * the clock not being output. Instead, use a gated clock + * and the unrouted WL_XTAL_PU gpio. + */ + compatible = "gpio-gate-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_microsom_ti_clk>; + enable-gpios = <&gpio5 5 GPIO_ACTIVE_HIGH>; + }; + + pwrseq_ti_wifi: ti-wifi-pwrseq { + compatible = "mmc-pwrseq-simple"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_microsom_ti_wifi_en>; + reset-gpios = <&gpio5 26 GPIO_ACTIVE_LOW>; + post-power-on-delay-ms = <200>; + clocks = <&clk_ti_wifi>; + clock-names = "ext_clock"; + }; +}; + +&iomuxc { + microsom { + pinctrl_microsom_ti_bt: microsom-ti-bt { + fsl,pins = < + /* BT_EN_SOC */ + MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00 0x40013070 + >; + }; + + pinctrl_microsom_ti_clk: microsom-ti-clk { + fsl,pins = < + /* EXT_32K */ + MX6QDL_PAD_GPIO_8__XTALOSC_REF_CLK_32K 0x1b0b0 + /* WL_XTAL_PU (unrouted) */ + MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x40013070 + >; + }; + + pinctrl_microsom_ti_wifi_en: microsom-ti-wifi-en { + fsl,pins = < + /* WLAN_EN_SOC */ + MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 0x40013070 + >; + }; + + pinctrl_microsom_ti_wifi_irq: microsom-ti-wifi-irq { + fsl,pins = < + /* WLAN_IRQ */ + MX6QDL_PAD_CSI0_DAT18__GPIO6_IO04 0x40013070 + >; + }; + + pinctrl_microsom_uart4: microsom-uart4 { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x1b0b1 + MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x1b0b1 + >; + }; + + pinctrl_microsom_usdhc1: microsom-usdhc1 { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 + MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 + MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 + MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 + MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 + MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 + >; + }; + }; +}; + +/* UART4 - Connected to optional TI Wi-Fi/BT/FM */ +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_microsom_uart4>; + uart-has-rtscts; + status = "okay"; + + bluetooth { + compatible = "ti,wl1837-st"; + clocks = <&clk_ti_wifi>; + clock-names = "ext_clock"; + enable-gpios = <&gpio6 0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_microsom_ti_bt>; + }; +}; + +/* USDHC1 - Connected to optional TI Wi-Fi/BT/FM */ +&usdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_microsom_usdhc1>; + bus-width = <4>; + keep-power-in-suspend; + mmc-pwrseq = <&pwrseq_ti_wifi>; + non-removable; + vmmc-supply = <&vcc_3v3>; + /* vqmmc-supply = <&nvcc_sd1>; - MMC layer doesn't like it! */ + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + wlcore@2 { + compatible = "ti,wl1837"; + reg = <2>; + interrupts-extended = <&gpio6 4 IRQ_TYPE_LEVEL_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_microsom_ti_wifi_irq>; + }; +}; diff --git a/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi b/arch/arm/boot/dts/imx6qdl-sr-som.dtsi similarity index 84% rename from arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi rename to arch/arm/boot/dts/imx6qdl-sr-som.dtsi index 900e8c781f91..4ccb7afc4b35 100644 --- a/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sr-som.dtsi @@ -1,9 +1,6 @@ /* * Copyright (C) 2013,2014 Russell King * - * This describes the hookup for an AR8035 to the iMX6 on the SolidRun - * MicroSOM. - * * This file is dual-licensed: you can use it either under the terms * of the GPL or the X11 license, at your option. Note that this dual * licensing only applies to this file, and not this project as a @@ -41,6 +38,18 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ +#include + +/ { + vcc_3v3: regulator-vcc-3v3 { + compatible = "regulator-fixed"; + regulator-always-on; + regulator-name = "vcc_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; +}; + &fec { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_microsom_enet_ar8035>; @@ -51,7 +60,7 @@ }; &iomuxc { - enet { + microsom { pinctrl_microsom_enet_ar8035: microsom-enet-ar8035 { fsl,pins = < MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b8b0 @@ -59,10 +68,10 @@ /* AR8035 reset */ MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x130b0 /* AR8035 interrupt */ - MX6QDL_PAD_DI0_PIN2__GPIO4_IO18 0x80000000 + MX6QDL_PAD_DI0_PIN2__GPIO4_IO18 0x1b0b0 /* GPIO16 -> AR8035 25MHz */ - MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0xc0000000 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x80000000 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x13030 MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 @@ -95,5 +104,18 @@ MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x03000 >; }; + + pinctrl_microsom_uart1: microsom-uart1 { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + >; + }; }; }; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_microsom_uart1>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-ts7970.dtsi b/arch/arm/boot/dts/imx6qdl-ts7970.dtsi new file mode 100644 index 000000000000..f0be516dc28e --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-ts7970.dtsi @@ -0,0 +1,594 @@ +/* + * Copyright 2015 Technologic Systems + * Copyright 2017 Savoir-Faire Linux + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +/ { + leds { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_leds1>; + compatible = "gpio-leds"; + + green-led { + label = "green-led"; + gpios = <&gpio3 27 GPIO_ACTIVE_LOW>; + default-state = "on"; + }; + + red-led { + label = "red-led"; + gpios = <&gpio1 2 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + yel-led { + label = "yellow-led"; + gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + blue-led { + label = "blue-led"; + gpios = <&gpio4 25 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + en-usb-5v { + label = "en-usb-5v"; + gpios = <&gpio2 22 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + + sel_dc_usb { + label = "sel_dc_usb"; + gpios = <&gpio5 17 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "3p3v"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_can1_3v3: reg_can1_3v3 { + compatible = "regulator-fixed"; + regulator-name = "reg_can1_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio4 21 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_can2_3v3: en-reg_can2_3v3 { + compatible = "regulator-fixed"; + regulator-name = "reg_can2_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio6 31 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_usb_otg_vbus: regulator-usb-otg-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_wlan_vmmc: regulator_wlan_vmmc { + compatible = "regulator-fixed"; + regulator-name = "wlan_vmmc"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + gpio = <&gpio8 14 GPIO_ACTIVE_HIGH>; + startup-delay-us = <70000>; + enable-active-high; + }; + + sound-sgtl5000 { + audio-codec = <&sgtl5000>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; + compatible = "fsl,imx-audio-sgtl5000"; + model = "On-board Codec"; + mux-ext-port = <3>; + mux-int-port = <1>; + ssi-controller = <&ssi1>; + }; +}; + +&audmux { + status = "okay"; +}; + +&can1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan1>; + xceiver-supply = <®_can1_3v3>; + status = "okay"; +}; + +&can2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan2>; + xceiver-supply = <®_can2_3v3>; + status = "okay"; +}; + +&ecspi1 { + cs-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi1>; + status = "okay"; + + n25q064: flash@0 { + compatible = "micron,n25q064", "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <20000000>; + }; +}; + +&ecspi2 { + cs-gpios = < + &gpio5 31 GPIO_ACTIVE_HIGH + &gpio7 12 GPIO_ACTIVE_HIGH + &gpio5 18 GPIO_ACTIVE_HIGH + >; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi2>; + status = "okay"; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>, + <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>; + fsl,err006687-workaround-present; + status = "okay"; +}; + +&hdmi { + status = "okay"; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c1>; + pinctrl-1 = <&pinctrl_i2c1_gpio>; + scl-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + sda-gpios = <&gpio3 28 GPIO_ACTIVE_HIGH>; + status = "okay"; + + m41t00s: rtc@68 { + compatible = "m41t00"; + reg = <0x68>; + }; + + isl12022: rtc@6f { + compatible = "isl,isl12022"; + reg = <0x6f>; + }; + + gpio8: gpio@28 { + compatible = "technologic,ts7970-gpio"; + reg = <0x28>; + #gpio-cells = <2>; + gpio-controller; + ngpio = <32>; + }; + + sgtl5000: codec@a { + compatible = "fsl,sgtl5000"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sgtl5000>; + reg = <0x0a>; + clocks = <&clks IMX6QDL_CLK_CKO>; + VDDA-supply = <®_3p3v>; + VDDIO-supply = <®_3p3v>; + }; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c2>; + pinctrl-1 = <&pinctrl_i2c2_gpio>; + scl-gpios = <&gpio4 12 GPIO_ACTIVE_HIGH>; + sda-gpios = <&gpio4 13 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x100b1 /* Onboard Flash CS */ + >; + }; + + pinctrl_ecspi2: ecspi2 { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT8__ECSPI2_SCLK 0x100b1 + MX6QDL_PAD_CSI0_DAT9__ECSPI2_MOSI 0x100b1 + MX6QDL_PAD_CSI0_DAT10__ECSPI2_MISO 0x100b1 + MX6QDL_PAD_CSI0_DAT13__GPIO5_IO31 0x100b1 /* FPGA_SPI_CS0 */ + MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x100b1 /* FPGA_SPI_CS1 */ + MX6QDL_PAD_CSI0_PIXCLK__GPIO5_IO18 0x100b1 /* HD1_SPI_CS */ + MX6QDL_PAD_CSI0_VSYNC__GPIO5_IO21 0x1b088 /* FPGA_RESET */ + MX6QDL_PAD_GPIO_3__XTALOSC_REF_CLK_24M 0x10 /* FPGA 24MHZ */ + MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20 0x1b088 /* FPGA_IRQ_0 */ + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b088 /* FPGA_IRQ_1 */ + >; + }; + + pinctrl_enet: enet { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x1b088 + MX6QDL_PAD_DI0_PIN4__GPIO4_IO20 0x1b088 /* ETH_PHY_RESET */ + MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 + >; + }; + + pinctrl_flexcan1: flexcan1grp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b088 + MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b088 + MX6QDL_PAD_DISP0_DAT0__GPIO4_IO21 0x1b088 /* EN_CAN_1 */ + >; + }; + + pinctrl_flexcan2: flexcan2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x1b088 + MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x1b088 + MX6QDL_PAD_EIM_BCLK__GPIO6_IO31 0x1b088 /* EN_CAN_2 */ + >; + }; + + pinctrl_hog: hoggrp { + fsl,pins = < + /* Onboard */ + MX6QDL_PAD_SD4_DAT3__GPIO2_IO11 0x1b088 /* USB_HUB_RESET */ + MX6QDL_PAD_DISP0_DAT23__GPIO5_IO17 0x1b088 /* SEL_DC_USB */ + MX6QDL_PAD_EIM_A16__GPIO2_IO22 0x1b088 /* EN_USB_5V */ + MX6QDL_PAD_DISP0_DAT14__GPIO5_IO08 0x1b088 /* JTAG_FPGA_TMS */ + MX6QDL_PAD_DISP0_DAT17__GPIO5_IO11 0x1b088 /* JTAG_FPGA_TCK */ + MX6QDL_PAD_DISP0_DAT18__GPIO5_IO12 0x1b088 /* JTAG_FPGA_TDO */ + MX6QDL_PAD_DISP0_DAT22__GPIO5_IO16 0x1b088 /* JTAG_FPGA_TDI */ + MX6QDL_PAD_DISP0_DAT20__GPIO5_IO14 0x1b088 /* GYRO_INT */ + MX6QDL_PAD_EIM_OE__GPIO2_IO25 0x1b088 /* MODBUS_FAULT */ + MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x1b088 /* BUS_DIR/JP_SD_BOOT */ + MX6QDL_PAD_EIM_A19__GPIO2_IO19 0x1b088 /* EN_MODBUS_24V */ + MX6QDL_PAD_DISP0_DAT5__GPIO4_IO26 0x1b088 /* EN_MODBUS_3V */ + MX6QDL_PAD_EIM_A17__GPIO2_IO21 0x1b088 /* I210_RESET */ + MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x1b088 /* EN_RTC_PWR */ + MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x1b088 /* REVSTRAP1 */ + + /* Offboard */ + MX6QDL_PAD_DISP0_DAT7__GPIO4_IO28 0x1b088 /* LCD_D09 */ + MX6QDL_PAD_DISP0_DAT9__GPIO4_IO30 0x1b088 /* HD1_IRQ */ + MX6QDL_PAD_DISP0_DAT10__GPIO4_IO31 0x1b088 /* LCD_D10 */ + MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x1b088 /* LCD_D11 */ + MX6QDL_PAD_EIM_EB1__GPIO2_IO29 0x1b088 /* BUS_BHE */ + MX6QDL_PAD_EIM_LBA__GPIO2_IO27 0x1b088 /* BUS_ALE */ + MX6QDL_PAD_EIM_CS0__GPIO2_IO23 0x1b088 /* BUS_CS */ + MX6QDL_PAD_EIM_A24__GPIO5_IO04 0x1b088 /* DIO_20 */ + MX6QDL_PAD_EIM_WAIT__GPIO5_IO00 0x1b088 /* BUS_WAIT */ + MX6QDL_PAD_EIM_DA0__GPIO3_IO00 0x1b088 /* MUX_AD_00 */ + MX6QDL_PAD_EIM_DA1__GPIO3_IO01 0x1b088 /* MUX_AD_01 */ + MX6QDL_PAD_EIM_DA2__GPIO3_IO02 0x1b088 /* MUX_AD_02 */ + MX6QDL_PAD_EIM_DA3__GPIO3_IO03 0x1b088 /* MUX_AD_03 */ + MX6QDL_PAD_EIM_DA4__GPIO3_IO04 0x1b088 /* MUX_AD_04 */ + MX6QDL_PAD_EIM_DA5__GPIO3_IO05 0x1b088 /* MUX_AD_05 */ + MX6QDL_PAD_EIM_DA6__GPIO3_IO06 0x1b088 /* MUX_AD_06 */ + MX6QDL_PAD_EIM_DA7__GPIO3_IO07 0x1b088 /* MUX_AD_07 */ + MX6QDL_PAD_EIM_DA8__GPIO3_IO08 0x1b088 /* MUX_AD_08 */ + MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x1b088 /* MUX_AD_09 */ + MX6QDL_PAD_EIM_DA10__GPIO3_IO10 0x1b088 /* MUX_AD_10 */ + MX6QDL_PAD_EIM_DA11__GPIO3_IO11 0x1b088 /* MUX_AD_11 */ + MX6QDL_PAD_EIM_DA12__GPIO3_IO12 0x1b088 /* MUX_AD_12 */ + MX6QDL_PAD_EIM_DA13__GPIO3_IO13 0x1b088 /* MUX_AD_13 */ + MX6QDL_PAD_EIM_DA14__GPIO3_IO14 0x1b088 /* MUX_AD_14 */ + MX6QDL_PAD_EIM_DA15__GPIO3_IO15 0x1b088 /* MUX_AD_15 */ + + /* Strapping only */ + MX6QDL_PAD_EIM_A18__GPIO2_IO20 0x1b088 + MX6QDL_PAD_EIM_A21__GPIO2_IO17 0x1b088 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c1_gpio: i2c1gpiogrp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__GPIO3_IO21 0x4001b8b1 + MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x4001b8b1 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c2_gpio: i2c2gpiogrp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__GPIO4_IO12 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__GPIO4_IO13 0x4001b8b1 + >; + }; + + pinctrl_leds1: leds1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D27__GPIO3_IO27 0x1b088 /* GREEN_LED */ + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1b088 /* RED_LED */ + MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b088 /* YEL_LED */ + MX6QDL_PAD_DISP0_DAT4__GPIO4_IO25 0x1b088 /* IMX6_BLUE_LED */ + >; + }; + + pinctrl_sgtl5000: sgtl5000grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 + MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 + MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 + MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 /* Audio CLK */ + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b088 + MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b088 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_GPIO_7__UART2_TX_DATA 0x1b088 + MX6QDL_PAD_GPIO_8__UART2_RX_DATA 0x1b088 + MX6QDL_PAD_SD4_DAT6__UART2_CTS_B 0x1b088 + MX6QDL_PAD_SD4_DAT5__UART2_RTS_B 0x1b088 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b088 + MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b088 + MX6QDL_PAD_EIM_D30__UART3_RTS_B 0x1b088 + MX6QDL_PAD_EIM_D31__UART3_CTS_B 0x1b088 + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b088 + MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b088 + >; + }; + + pinctrl_uart5: uart5grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b088 + MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b088 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 + MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 + MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 + MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 + MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 + MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 + MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x17059 /* WIFI IRQ */ + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + MX6QDL_PAD_EIM_EB0__GPIO2_IO28 0x1b088 /* EN_SD_POWER */ + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; +}; + +&pcie { + status = "okay"; +}; + +&snvs_rtc { + status = "disabled"; +}; + +&ssi1 { + fsl,mode = "i2s-slave"; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + uart-has-rtscts; + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; + status = "okay"; +}; + +&uart5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart5>; + status = "okay"; +}; + +&usbh1 { + status = "okay"; +}; + +&usbotg { + vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + status = "okay"; +}; + +/* WIFI */ +&usdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc1>; + vmmc-supply = <®_wlan_vmmc>; + bus-width = <4>; + non-removable; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + wlcore: wlcore@2 { + compatible = "ti,wl1271"; + reg = <2>; + interrupt-parent = <&gpio1>; + interrupts = <26 IRQ_TYPE_LEVEL_HIGH>; + ref-clock-frequency = <38400000>; + }; +}; + +/* SD */ +&usdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2>; + vmmc-supply = <®_3p3v>; + bus-width = <4>; + fsl,wp-controller; + status = "okay"; +}; + +/* eMMC */ +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3>; + vmmc-supply = <®_3p3v>; + bus-width = <4>; + non-removable; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-udoo.dtsi b/arch/arm/boot/dts/imx6qdl-udoo.dtsi index c96c91d83678..4161b7d4323a 100644 --- a/arch/arm/boot/dts/imx6qdl-udoo.dtsi +++ b/arch/arm/boot/dts/imx6qdl-udoo.dtsi @@ -28,6 +28,13 @@ status = "disabled"; }; + gpio-poweroff { + compatible = "gpio-poweroff"; + gpios = <&gpio2 4 0>; + pinctrl-0 = <&pinctrl_power_off>; + pinctrl-names = "default"; + }; + memory { reg = <0x10000000 0x40000000>; }; @@ -172,6 +179,12 @@ >; }; + pinctrl_power_off: poweroffgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x30 + >; + }; + pinctrl_touchscreenp7: touchscreenp7grp { fsl,pins = < MX6QDL_PAD_SD2_DAT0__GPIO1_IO15 0x70 @@ -208,8 +221,8 @@ fsl,pins = < MX6QDL_PAD_DI0_PIN2__AUD6_TXD 0x1b0b0 MX6QDL_PAD_DI0_PIN3__AUD6_TXFS 0x1b0b0 - MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x1b0b0 - MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x1b0b0 + MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x13080 + MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x13080 MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x1b0b0 >; }; @@ -218,8 +231,8 @@ fsl,pins = < MX6QDL_PAD_DI0_PIN2__AUD6_TXD 0x1b0b0 MX6QDL_PAD_DI0_PIN3__GPIO4_IO19 0x1b0b0 - MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x1b0b0 - MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x1b0b0 + MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x13080 + MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x13080 MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x1b0b0 >; }; @@ -228,8 +241,8 @@ fsl,pins = < MX6QDL_PAD_DI0_PIN2__GPIO4_IO18 0x1b0b0 MX6QDL_PAD_DI0_PIN3__GPIO4_IO19 0x1b0b0 - MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x1b0b0 - MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x1b0b0 + MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x13080 + MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x13080 MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x1b0b0 >; }; diff --git a/arch/arm/boot/dts/imx6qdl-var-dart.dtsi b/arch/arm/boot/dts/imx6qdl-var-dart.dtsi new file mode 100644 index 000000000000..421d6f527609 --- /dev/null +++ b/arch/arm/boot/dts/imx6qdl-var-dart.dtsi @@ -0,0 +1,503 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Support for Variscite DART-MX6 Module + * + * Copyright 2017 BayLibre, SAS + * Author: Neil Armstrong + */ + +#include +#include + +/ { + memory { + reg = <0x10000000 0x40000000>; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + reg_wl18xx_vmmc: regulator-wl18xx { + compatible = "regulator-fixed"; + regulator-name = "vwl1807"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + gpio = <&gpio7 8 GPIO_ACTIVE_HIGH>; + enable-active-high; + startup-delay-us = <70000>; + }; +}; + +&audmux { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; + + ssi2 { + fsl,audmux-port = <1>; + fsl,port-config = < + (IMX_AUDMUX_V2_PTCR_SYN | + IMX_AUDMUX_V2_PTCR_TFSDIR | + IMX_AUDMUX_V2_PTCR_TFSEL(2) | + IMX_AUDMUX_V2_PTCR_TCLKDIR | + IMX_AUDMUX_V2_PTCR_TCSEL(2)) + IMX_AUDMUX_V2_PDCR_RXDSEL(2) + >; + }; + + aud3 { + fsl,audmux-port = <2>; + fsl,port-config = < + IMX_AUDMUX_V2_PTCR_SYN + IMX_AUDMUX_V2_PDCR_RXDSEL(1) + >; + }; +}; + +&can1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan1>; + status = "disabled"; +}; + +&can2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan2>; + status = "disabled"; +}; + +&ecspi1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi1>; + status = "disabled"; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + status = "disabled"; +}; + +&hdmi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hdmicec>; + ddc-i2c-bus = <&i2c1>; + status = "disabled"; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "disabled"; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + pmic@8 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pmic>; + compatible = "fsl,pfuze100"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw1c_reg: sw1c { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3a { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3950000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3b_reg: sw3b { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3950000>; + regulator-boot-on; + regulator-always-on; + }; + + sw4_reg: sw4 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3950000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen6_reg: vgen6 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + regulator-boot-on; + }; + }; + }; + + tlv320aic3106: codec@1b { + compatible = "ti,tlv320aic3106"; + reg = <0x1b>; + #sound-dai-cells = <0>; + DRVDD-supply = <®_3p3v>; + AVDD-supply = <®_3p3v>; + IOVDD-supply = <®_3p3v>; + DVDD-supply = <®_3p3v>; + ai3x-ocmv = <0>; + gpio-reset = <&gpio5 5 GPIO_ACTIVE_LOW>; + }; +}; + +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "disabled"; +}; + +&iomuxc { + pinctrl_audmux: audmux { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 + MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 + MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 + MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 + /* Audio Clock */ + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 + >; + }; + + pinctrl_bt: bt { + fsl,pins = < + /* Bluetooth enable */ + MX6QDL_PAD_SD3_DAT6__GPIO6_IO18 0x1b0b1 + /* Bluetooth Slow Clock */ + MX6QDL_PAD_ENET_RXD0__OSC32K_32K_OUT 0x000b0 + >; + }; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_KEY_ROW0__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_KEY_COL0__ECSPI1_SCLK 0x100b1 + /* SPI1 CS0 */ + MX6QDL_PAD_KEY_ROW1__GPIO4_IO09 0x1b0b0 + /* SPI1 CS1 */ + MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x1b0b0 + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x10030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x10030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x10030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x10030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x10030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x10030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + >; + }; + + pinctrl_flexcan1: flexcan1grp { + fsl,pins = < + MX6QDL_PAD_GPIO_7__FLEXCAN1_TX 0x1b0b0 + MX6QDL_PAD_GPIO_8__FLEXCAN1_RX 0x1b0b0 + >; + }; + + pinctrl_flexcan2: flexcan2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x1b0b0 + MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x1b0b0 + >; + }; + + pinctrl_hdmicec: hdmicecgrp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1 + MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1 + >; + }; + + pinctrl_pmic: pmicgrp { + fsl,pins = < + /* PMIC INT */ + MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x1b0b1 + >; + }; + + pinctrl_pwm2: pwm2grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT9__PWM2_OUT 0x1b0b1 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_SD3_DAT4__UART2_RX_DATA 0x1b0b1 + MX6QDL_PAD_SD3_DAT5__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD4_DAT6__UART2_CTS_B 0x1b0b1 + MX6QDL_PAD_SD4_DAT5__UART2_RTS_B 0x1b0b1 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D23__UART3_CTS_B 0x1b0b1 + MX6QDL_PAD_EIM_EB3__UART3_RTS_B 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 + MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 + MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 + MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 + MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 + MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 + /* WL_EN */ + MX6QDL_PAD_SD3_DAT7__GPIO6_IO17 0x17071 + /* WL_IRQ */ + MX6QDL_PAD_SD3_RST__GPIO7_IO08 0x17071 + >; + }; + + pinctrl_usdhc1_100mhz: usdhc1grp100mhz { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__SD1_CMD 0x170B9 + MX6QDL_PAD_SD1_CLK__SD1_CLK 0x100B9 + MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x170B9 + MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x170B9 + MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x170B9 + MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x170B9 + >; + }; + + pinctrl_usdhc1_200mhz: usdhc1grp200mhz { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__SD1_CMD 0x170F9 + MX6QDL_PAD_SD1_CLK__SD1_CLK 0x100F9 + MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x170F9 + MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x170F9 + MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x170F9 + MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x170F9 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; +}; + +&pcie { + fsl,tx-swing-full = <103>; + fsl,tx-swing-low = <103>; + reset-gpio = <&gpio4 11 GPIO_ACTIVE_LOW>; + status = "disabled"; +}; + +&pwm2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm2>; + status = "disabled"; +}; + +®_arm { + vin-supply = <&sw1a_reg>; +}; + +®_pu { + vin-supply = <&sw1c_reg>; +}; + +®_soc { + vin-supply = <&sw1c_reg>; +}; + +&snvs_poweroff { + status = "okay"; +}; + +&ssi2 { + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "disabled"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2 &pinctrl_bt>; + uart-has-rtscts; + status = "okay"; + + bluetooth { + compatible = "ti,wl1835-st"; + enable-gpios = <&gpio6 18 GPIO_ACTIVE_HIGH>; + }; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + uart-has-rtscts; + status = "disabled"; +}; + +&usbh1 { + status = "disabled"; +}; + +&usbotg { + vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + status = "disabled"; +}; + +&usdhc1 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc1>; + pinctrl-1 = <&pinctrl_usdhc1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>; + bus-width = <4>; + vmmc-supply = <®_wl18xx_vmmc>; + non-removable; + wakeup-source; + keep-power-in-suspend; + cap-power-off-card; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + wlcore: wlcore@2 { + compatible = "ti,wl1835"; + reg = <2>; + interrupt-parent = <&gpio6>; + interrupts = <17 IRQ_TYPE_LEVEL_HIGH>; + ref-clock-frequency = <38400000>; + }; +}; + +&usdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2>; + no-1-8-v; + keep-power-in-suspend; + wakeup-source; + status = "disabled"; +}; + +&usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3>; + non-removable; + keep-power-in-suspend; + wakeup-source; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx6qdl-wandboard-revd1.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard-revd1.dtsi index 6d8d9ca96646..3a8a4952d45e 100644 --- a/arch/arm/boot/dts/imx6qdl-wandboard-revd1.dtsi +++ b/arch/arm/boot/dts/imx6qdl-wandboard-revd1.dtsi @@ -21,6 +21,11 @@ }; }; +&hdmi { + ddc-i2c-bus = <&i2c2>; + status = "okay"; +}; + &i2c3 { clock-frequency = <100000>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi b/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi index 7812fbac963c..72f52fcecee1 100644 --- a/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi +++ b/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi @@ -49,6 +49,7 @@ aliases { mdio-gpio0 = &mdio1; + rtc0 = &ds1341; }; mdio1: mdio { @@ -501,7 +502,7 @@ reg = <0x54>; }; - rtc@68 { + ds1341: rtc@68 { compatible = "dallas,ds1341"; reg = <0x68>; }; @@ -580,6 +581,17 @@ pinctrl-0 = <&pinctrl_pcie>; reset-gpio = <&gpio7 12 GPIO_ACTIVE_LOW>; status = "okay"; + + host@0 { + reg = <0 0 0 0 0>; + + #address-cells = <3>; + #size-cells = <2>; + + i210: i210@0 { + reg = <0 0 0 0 0>; + }; + }; }; &usdhc2 { diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 1ce4eabf0590..59ff86695a14 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -80,6 +80,75 @@ }; }; + tempmon: tempmon { + compatible = "fsl,imx6q-tempmon"; + interrupt-parent = <&gpc>; + interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>; + fsl,tempmon = <&anatop>; + fsl,tempmon-data = <&ocotp>; + clocks = <&clks IMX6QDL_CLK_PLL3_USB_OTG>; + }; + + ldb: ldb { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx6q-ldb", "fsl,imx53-ldb"; + gpr = <&gpr>; + status = "disabled"; + + lvds-channel@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + status = "disabled"; + + port@0 { + reg = <0>; + + lvds0_mux_0: endpoint { + remote-endpoint = <&ipu1_di0_lvds0>; + }; + }; + + port@1 { + reg = <1>; + + lvds0_mux_1: endpoint { + remote-endpoint = <&ipu1_di1_lvds0>; + }; + }; + }; + + lvds-channel@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + status = "disabled"; + + port@0 { + reg = <0>; + + lvds1_mux_0: endpoint { + remote-endpoint = <&ipu1_di0_lvds1>; + }; + }; + + port@1 { + reg = <1>; + + lvds1_mux_1: endpoint { + remote-endpoint = <&ipu1_di1_lvds1>; + }; + }; + }; + }; + + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&gpc>; + interrupts = <0 94 IRQ_TYPE_LEVEL_HIGH>; + }; + soc { #address-cells = <1>; #size-cells = <1>; @@ -224,11 +293,6 @@ status = "disabled"; }; - pmu { - compatible = "arm,cortex-a9-pmu"; - interrupts = <0 94 IRQ_TYPE_LEVEL_HIGH>; - }; - aips-bus@2000000 { /* AIPS1 */ compatible = "fsl,aips-bus", "simple-bus"; #address-cells = <1>; @@ -631,8 +695,11 @@ interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>, <0 54 IRQ_TYPE_LEVEL_HIGH>, <0 127 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; - regulator-1p1 { + regulator-1p1@20c8110 { + reg = <0x20c8110>; compatible = "fsl,anatop-regulator"; regulator-name = "vdd1p1"; regulator-min-microvolt = <1000000>; @@ -647,7 +714,8 @@ anatop-enable-bit = <0>; }; - regulator-3p0 { + regulator-3p0@20c8120 { + reg = <0x20c8120>; compatible = "fsl,anatop-regulator"; regulator-name = "vdd3p0"; regulator-min-microvolt = <2800000>; @@ -662,7 +730,8 @@ anatop-enable-bit = <0>; }; - regulator-2p5 { + regulator-2p5@20c8130 { + reg = <0x20c8130>; compatible = "fsl,anatop-regulator"; regulator-name = "vdd2p5"; regulator-min-microvolt = <2250000>; @@ -677,7 +746,8 @@ anatop-enable-bit = <0>; }; - reg_arm: regulator-vddcore { + reg_arm: regulator-vddcore@20c8140 { + reg = <0x20c8140>; compatible = "fsl,anatop-regulator"; regulator-name = "vddarm"; regulator-min-microvolt = <725000>; @@ -694,7 +764,8 @@ anatop-max-voltage = <1450000>; }; - reg_pu: regulator-vddpu { + reg_pu: regulator-vddpu@20c8140 { + reg = <0x20c8140>; compatible = "fsl,anatop-regulator"; regulator-name = "vddpu"; regulator-min-microvolt = <725000>; @@ -711,7 +782,8 @@ anatop-max-voltage = <1450000>; }; - reg_soc: regulator-vddsoc { + reg_soc: regulator-vddsoc@20c8140 { + reg = <0x20c8140>; compatible = "fsl,anatop-regulator"; regulator-name = "vddsoc"; regulator-min-microvolt = <725000>; @@ -729,14 +801,6 @@ }; }; - tempmon: tempmon { - compatible = "fsl,imx6q-tempmon"; - interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>; - fsl,tempmon = <&anatop>; - fsl,tempmon-data = <&ocotp>; - clocks = <&clks IMX6QDL_CLK_PLL3_USB_OTG>; - }; - usbphy1: usbphy@20c9000 { compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy"; reg = <0x020c9000 0x1000>; @@ -773,6 +837,10 @@ mask = <0x60>; status = "disabled"; }; + + snvs_lpgpr: snvs-lpgpr { + compatible = "fsl,imx6q-snvs-lpgpr"; + }; }; epit1: epit@20d0000 { /* EPIT1 */ @@ -841,60 +909,6 @@ reg = <0x20e0000 0x4000>; }; - ldb: ldb { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,imx6q-ldb", "fsl,imx53-ldb"; - gpr = <&gpr>; - status = "disabled"; - - lvds-channel@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - status = "disabled"; - - port@0 { - reg = <0>; - - lvds0_mux_0: endpoint { - remote-endpoint = <&ipu1_di0_lvds0>; - }; - }; - - port@1 { - reg = <1>; - - lvds0_mux_1: endpoint { - remote-endpoint = <&ipu1_di1_lvds0>; - }; - }; - }; - - lvds-channel@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - status = "disabled"; - - port@0 { - reg = <0>; - - lvds1_mux_0: endpoint { - remote-endpoint = <&ipu1_di0_lvds1>; - }; - }; - - port@1 { - reg = <1>; - - lvds1_mux_1: endpoint { - remote-endpoint = <&ipu1_di1_lvds1>; - }; - }; - }; - }; - dcic1: dcic@20e4000 { reg = <0x020e4000 0x4000>; interrupts = <0 124 IRQ_TYPE_LEVEL_HIGH>; @@ -1017,6 +1031,7 @@ fec: ethernet@2188000 { compatible = "fsl,imx6q-fec"; reg = <0x02188000 0x4000>; + interrupt-names = "int0", "pps"; interrupts-extended = <&intc 0 118 IRQ_TYPE_LEVEL_HIGH>, <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts index 60600b4cf5fe..2844ab541759 100644 --- a/arch/arm/boot/dts/imx6sl-evk.dts +++ b/arch/arm/boot/dts/imx6sl-evk.dts @@ -20,7 +20,7 @@ reg = <0x80000000 0x40000000>; }; - backlight { + backlight_display: backlight_display { compatible = "pwm-backlight"; pwms = <&pwm1 0 5000000>; brightness-levels = <0 4 8 16 32 64 128 255>; @@ -39,58 +39,54 @@ }; }; - regulators { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; + reg_usb_otg1_vbus: regulator-usb-otg1-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_otg1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio4 0 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <&swbst_reg>; + }; - reg_usb_otg1_vbus: regulator@0 { - compatible = "regulator-fixed"; - reg = <0>; - regulator-name = "usb_otg1_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - gpio = <&gpio4 0 0>; - enable-active-high; - vin-supply = <&swbst_reg>; - }; + reg_usb_otg2_vbus: regulator-usb-otg2-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_otg2_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio4 2 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <&swbst_reg>; + }; - reg_usb_otg2_vbus: regulator@1 { - compatible = "regulator-fixed"; - reg = <1>; - regulator-name = "usb_otg2_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - gpio = <&gpio4 2 0>; - enable-active-high; - vin-supply = <&swbst_reg>; - }; + reg_aud3v: regulator-aud3v { + compatible = "regulator-fixed"; + regulator-name = "wm8962-supply-3v15"; + regulator-min-microvolt = <3150000>; + regulator-max-microvolt = <3150000>; + regulator-boot-on; + }; - reg_aud3v: regulator@2 { - compatible = "regulator-fixed"; - reg = <2>; - regulator-name = "wm8962-supply-3v15"; - regulator-min-microvolt = <3150000>; - regulator-max-microvolt = <3150000>; - regulator-boot-on; - }; + reg_aud4v: regulator-aud4v { + compatible = "regulator-fixed"; + regulator-name = "wm8962-supply-4v2"; + regulator-min-microvolt = <4325000>; + regulator-max-microvolt = <4325000>; + regulator-boot-on; + }; - reg_aud4v: regulator@3 { - compatible = "regulator-fixed"; - reg = <3>; - regulator-name = "wm8962-supply-4v2"; - regulator-min-microvolt = <4325000>; - regulator-max-microvolt = <4325000>; - regulator-boot-on; - }; + reg_lcd_3v3: regulator-lcd-3v3 { + compatible = "regulator-fixed"; + regulator-name = "lcd-3v3"; + gpio = <&gpio4 3 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; - reg_lcd_3v3: regulator@4 { - compatible = "regulator-fixed"; - reg = <4>; - regulator-name = "lcd-3v3"; - gpio = <&gpio4 3 0>; - enable-active-high; - }; + reg_lcd_5v: regulator-lcd-5v { + compatible = "regulator-fixed"; + regulator-name = "lcd-5v0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; }; sound { @@ -108,6 +104,19 @@ mux-int-port = <2>; mux-ext-port = <3>; }; + + panel { + compatible = "sii,43wvf1g"; + backlight = <&backlight_display>; + dvdd-supply = <®_lcd_3v3>; + avdd-supply = <®_lcd_5v>; + + port { + panel_in: endpoint { + remote-endpoint = <&display_out>; + }; + }; + }; }; &audmux { @@ -546,31 +555,11 @@ &lcdif { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lcd>; - lcd-supply = <®_lcd_3v3>; - display = <&display0>; status = "okay"; - display0: display0 { - bits-per-pixel = <32>; - bus-width = <24>; - - display-timings { - native-mode = <&timing0>; - timing0: timing0 { - clock-frequency = <33500000>; - hactive = <800>; - vactive = <480>; - hback-porch = <89>; - hfront-porch = <164>; - vback-porch = <23>; - vfront-porch = <10>; - hsync-len = <10>; - vsync-len = <10>; - hsync-active = <0>; - vsync-active = <0>; - de-active = <1>; - pixelclk-active = <0>; - }; + port { + display_out: endpoint { + remote-endpoint = <&panel_in>; }; }; }; diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi index 3ea1a41893c8..ae8df3cf687e 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi @@ -102,6 +102,21 @@ }; }; + tempmon: tempmon { + compatible = "fsl,imx6q-tempmon"; + interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&gpc>; + fsl,tempmon = <&anatop>; + fsl,tempmon-data = <&ocotp>; + clocks = <&clks IMX6SL_CLK_PLL3_USB_OTG>; + }; + + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&gpc>; + interrupts = <0 94 IRQ_TYPE_LEVEL_HIGH>; + }; + soc { #address-cells = <1>; #size-cells = <1>; @@ -125,11 +140,6 @@ arm,data-latency = <4 2 3>; }; - pmu { - compatible = "arm,cortex-a9-pmu"; - interrupts = <0 94 IRQ_TYPE_LEVEL_HIGH>; - }; - aips1: aips-bus@2000000 { compatible = "fsl,aips-bus", "simple-bus"; #address-cells = <1>; @@ -517,8 +527,11 @@ interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>, <0 54 IRQ_TYPE_LEVEL_HIGH>, <0 127 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; - regulator-1p1 { + regulator-1p1@20c8110 { + reg = <0x20c8110>; compatible = "fsl,anatop-regulator"; regulator-name = "vdd1p1"; regulator-min-microvolt = <800000>; @@ -533,7 +546,8 @@ anatop-enable-bit = <0>; }; - regulator-3p0 { + regulator-3p0@20c8120 { + reg = <0x20c8120>; compatible = "fsl,anatop-regulator"; regulator-name = "vdd3p0"; regulator-min-microvolt = <2800000>; @@ -548,7 +562,8 @@ anatop-enable-bit = <0>; }; - regulator-2p5 { + regulator-2p5@20c8130 { + reg = <0x20c8130>; compatible = "fsl,anatop-regulator"; regulator-name = "vdd2p5"; regulator-min-microvolt = <2100000>; @@ -563,7 +578,8 @@ anatop-enable-bit = <0>; }; - reg_arm: regulator-vddcore { + reg_arm: regulator-vddcore@20c8140 { + reg = <0x20c8140>; compatible = "fsl,anatop-regulator"; regulator-name = "vddarm"; regulator-min-microvolt = <725000>; @@ -580,7 +596,8 @@ anatop-max-voltage = <1450000>; }; - reg_pu: regulator-vddpu { + reg_pu: regulator-vddpu@20c8140 { + reg = <0x20c8140>; compatible = "fsl,anatop-regulator"; regulator-name = "vddpu"; regulator-min-microvolt = <725000>; @@ -597,7 +614,8 @@ anatop-max-voltage = <1450000>; }; - reg_soc: regulator-vddsoc { + reg_soc: regulator-vddsoc@20c8140 { + reg = <0x20c8140>; compatible = "fsl,anatop-regulator"; regulator-name = "vddsoc"; regulator-min-microvolt = <725000>; @@ -615,14 +633,6 @@ }; }; - tempmon: tempmon { - compatible = "fsl,imx6q-tempmon"; - interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>; - fsl,tempmon = <&anatop>; - fsl,tempmon-data = <&ocotp>; - clocks = <&clks IMX6SL_CLK_PLL3_USB_OTG>; - }; - usbphy1: usbphy@20c9000 { compatible = "fsl,imx6sl-usbphy", "fsl,imx23-usbphy"; reg = <0x020c9000 0x1000>; diff --git a/arch/arm/boot/dts/imx6sx-sdb.dtsi b/arch/arm/boot/dts/imx6sx-sdb.dtsi index da815527a7f8..d35aa858f9db 100644 --- a/arch/arm/boot/dts/imx6sx-sdb.dtsi +++ b/arch/arm/boot/dts/imx6sx-sdb.dtsi @@ -24,7 +24,7 @@ reg = <0x80000000 0x40000000>; }; - backlight { + backlight_display: backlight-display { compatible = "pwm-backlight"; pwms = <&pwm3 0 5000000>; brightness-levels = <0 4 8 16 32 64 128 255>; @@ -49,86 +49,91 @@ }; }; - regulators { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; + vcc_sd3: regulator-vcc-sd3 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_vcc_sd3>; + regulator-name = "VCC_SD3"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + gpio = <&gpio2 11 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; - vcc_sd3: regulator@0 { - compatible = "regulator-fixed"; - reg = <0>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_vcc_sd3>; - regulator-name = "VCC_SD3"; - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3000000>; - gpio = <&gpio2 11 GPIO_ACTIVE_HIGH>; - enable-active-high; - }; + reg_usb_otg1_vbus: regulator-usb-otg1-vbus { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb_otg1>; + regulator-name = "usb_otg1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; - reg_usb_otg1_vbus: regulator@1 { - compatible = "regulator-fixed"; - reg = <1>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usb_otg1>; - regulator-name = "usb_otg1_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; - enable-active-high; - }; + reg_usb_otg2_vbus: regulator-usb-otg2-vbus { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb_otg2>; + regulator-name = "usb_otg2_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 12 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; - reg_usb_otg2_vbus: regulator@2 { - compatible = "regulator-fixed"; - reg = <2>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usb_otg2>; - regulator-name = "usb_otg2_vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - gpio = <&gpio1 12 GPIO_ACTIVE_HIGH>; - enable-active-high; - }; + reg_psu_5v: regulator-psu-5v { + compatible = "regulator-fixed"; + regulator-name = "PSU-5V0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; - reg_psu_5v: regulator@3 { - compatible = "regulator-fixed"; - reg = <3>; - regulator-name = "PSU-5V0"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - }; + reg_lcd_3v3: regulator-lcd-3v3 { + compatible = "regulator-fixed"; + regulator-name = "lcd-3v3"; + gpio = <&gpio3 27 0>; + enable-active-high; + }; - reg_lcd_3v3: regulator@4 { - compatible = "regulator-fixed"; - reg = <4>; - regulator-name = "lcd-3v3"; - gpio = <&gpio3 27 0>; - enable-active-high; - }; + reg_peri_3v3: regulator-peri-3v3 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_peri_3v3>; + regulator-name = "peri_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio4 16 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-always-on; + }; - reg_peri_3v3: regulator@5 { - compatible = "regulator-fixed"; - reg = <5>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_peri_3v3>; - regulator-name = "peri_3v3"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - gpio = <&gpio4 16 GPIO_ACTIVE_HIGH>; - enable-active-high; - regulator-always-on; - }; + reg_enet_3v3: regulator-enet-3v3 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet_3v3>; + regulator-name = "enet_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpios = <&gpio2 6 GPIO_ACTIVE_LOW>; + }; - reg_enet_3v3: regulator@6 { - compatible = "regulator-fixed"; - reg = <6>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_enet_3v3>; - regulator-name = "enet_3v3"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - gpios = <&gpio2 6 GPIO_ACTIVE_LOW>; - }; + reg_pcie_gpio: regulator-pcie-gpio { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pcie_reg>; + regulator-name = "MPCIE_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio2 1 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_lcd_5v: regulator-lcd-5v { + compatible = "regulator-fixed"; + regulator-name = "lcd-5v0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; }; sound { @@ -146,6 +151,19 @@ mux-int-port = <2>; mux-ext-port = <6>; }; + + panel { + compatible = "sii,43wvf1g"; + backlight = <&backlight_display>; + dvdd-supply = <®_lcd_3v3>; + avdd-supply = <®_lcd_5v>; + + port { + panel_in: endpoint { + remote-endpoint = <&display_out>; + }; + }; + }; }; &audmux { @@ -212,34 +230,22 @@ }; }; +&pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pcie>; + reset-gpio = <&gpio2 0 GPIO_ACTIVE_LOW>; + vpcie-supply = <®_pcie_gpio>; + status = "okay"; +}; + &lcdif1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lcd>; - lcd-supply = <®_lcd_3v3>; - display = <&display0>; status = "okay"; - display0: display0 { - bits-per-pixel = <16>; - bus-width = <24>; - - display-timings { - native-mode = <&timing0>; - timing0: timing0 { - clock-frequency = <33500000>; - hactive = <800>; - vactive = <480>; - hback-porch = <89>; - hfront-porch = <164>; - vback-porch = <23>; - vfront-porch = <10>; - hsync-len = <10>; - vsync-len = <10>; - hsync-active = <0>; - vsync-active = <0>; - de-active = <1>; - pixelclk-active = <0>; - }; + port { + display_out: endpoint { + remote-endpoint = <&panel_in>; }; }; }; @@ -453,6 +459,18 @@ >; }; + pinctrl_pcie: pciegrp { + fsl,pins = < + MX6SX_PAD_ENET1_COL__GPIO2_IO_0 0x10b0 + >; + }; + + pinctrl_pcie_reg: pciereggrp { + fsl,pins = < + MX6SX_PAD_ENET1_CRS__GPIO2_IO_1 0x10b0 + >; + }; + pinctrl_peri_3v3: peri3v3grp { fsl,pins = < MX6SX_PAD_QSPI1A_DATA0__GPIO4_IO_16 0x80000000 diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi index 5b03ba3beda9..fd7879342d0d 100644 --- a/arch/arm/boot/dts/imx6sx.dtsi +++ b/arch/arm/boot/dts/imx6sx.dtsi @@ -141,6 +141,22 @@ }; }; + tempmon: tempmon { + compatible = "fsl,imx6sx-tempmon", "fsl,imx6q-tempmon"; + interrupt-parent = <&gpc>; + interrupts = ; + fsl,tempmon = <&anatop>; + nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>; + nvmem-cell-names = "calib", "temp_grade"; + clocks = <&clks IMX6SX_CLK_PLL3_USB_OTG>; + }; + + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&gpc>; + interrupts = ; + }; + soc { #address-cells = <1>; #size-cells = <1>; @@ -148,11 +164,6 @@ interrupt-parent = <&gpc>; ranges; - pmu { - compatible = "arm,cortex-a9-pmu"; - interrupts = ; - }; - ocram: sram@900000 { compatible = "mmio-sram"; reg = <0x00900000 0x20000>; @@ -574,8 +585,11 @@ interrupts = , , ; + #address-cells = <1>; + #size-cells = <0>; - regulator-1p1 { + regulator-1p1@20c8110 { + reg = <0x20c8110>; compatible = "fsl,anatop-regulator"; regulator-name = "vdd1p1"; regulator-min-microvolt = <800000>; @@ -590,7 +604,8 @@ anatop-enable-bit = <0>; }; - regulator-3p0 { + regulator-3p0@20c8120 { + reg = <0x20c8120>; compatible = "fsl,anatop-regulator"; regulator-name = "vdd3p0"; regulator-min-microvolt = <2800000>; @@ -605,7 +620,8 @@ anatop-enable-bit = <0>; }; - regulator-2p5 { + regulator-2p5@20c8130 { + reg = <0x20c8130>; compatible = "fsl,anatop-regulator"; regulator-name = "vdd2p5"; regulator-min-microvolt = <2100000>; @@ -620,7 +636,8 @@ anatop-enable-bit = <0>; }; - reg_arm: regulator-vddcore { + reg_arm: regulator-vddcore@20c8140 { + reg = <0x20c8140>; compatible = "fsl,anatop-regulator"; regulator-name = "vddarm"; regulator-min-microvolt = <725000>; @@ -637,7 +654,8 @@ anatop-max-voltage = <1450000>; }; - reg_pcie: regulator-vddpcie { + reg_pcie: regulator-vddpcie@20c8140 { + reg = <0x20c8140>; compatible = "fsl,anatop-regulator"; regulator-name = "vddpcie"; regulator-min-microvolt = <725000>; @@ -653,7 +671,8 @@ anatop-max-voltage = <1450000>; }; - reg_soc: regulator-vddsoc { + reg_soc: regulator-vddsoc@20c8140 { + reg = <0x20c8140>; compatible = "fsl,anatop-regulator"; regulator-name = "vddsoc"; regulator-min-microvolt = <725000>; @@ -671,15 +690,6 @@ }; }; - tempmon: tempmon { - compatible = "fsl,imx6sx-tempmon", "fsl,imx6q-tempmon"; - interrupts = ; - fsl,tempmon = <&anatop>; - nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>; - nvmem-cell-names = "calib", "temp_grade"; - clocks = <&clks IMX6SX_CLK_PLL3_USB_OTG>; - }; - usbphy1: usbphy@20c9000 { compatible = "fsl,imx6sx-usbphy", "fsl,imx23-usbphy"; reg = <0x020c9000 0x1000>; @@ -750,6 +760,19 @@ #interrupt-cells = <3>; interrupts = ; interrupt-parent = <&intc>; + clocks = <&clks IMX6SX_CLK_IPG>; + clock-names = "ipg"; + + pgc { + #address-cells = <1>; + #size-cells = <0>; + + pd_pci: power-domain@3 { + reg = <3>; + #power-domain-cells = <0>; + power-supply = <®_pcie>; + }; + }; }; iomuxc: iomuxc@20e0000 { @@ -862,6 +885,7 @@ fec1: ethernet@2188000 { compatible = "fsl,imx6sx-fec", "fsl,imx6q-fec"; reg = <0x02188000 0x4000>; + interrupt-names = "int0", "pps"; interrupts = , ; clocks = <&clks IMX6SX_CLK_ENET>, @@ -971,6 +995,7 @@ fec2: ethernet@21b4000 { compatible = "fsl,imx6sx-fec", "fsl,imx6q-fec"; reg = <0x021b4000 0x4000>; + interrupt-names = "int0", "pps"; interrupts = , ; clocks = <&clks IMX6SX_CLK_ENET>, @@ -1138,7 +1163,7 @@ reg = <0x02200000 0x100000>; ranges; - spba-bus@2200000 { + spba-bus@2240000 { compatible = "fsl,spba-bus", "simple-bus"; #address-cells = <1>; #size-cells = <1>; @@ -1304,25 +1329,29 @@ pcie: pcie@8ffc000 { compatible = "fsl,imx6sx-pcie", "snps,dw-pcie"; - reg = <0x08ffc000 0x4000>; /* DBI */ + reg = <0x08ffc000 0x04000>, <0x08f00000 0x80000>; + reg-names = "dbi", "config"; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; - /* configuration space */ - ranges = <0x00000800 0 0x08f00000 0x08f00000 0 0x00080000 - /* downstream I/O */ - 0x81000000 0 0 0x08f80000 0 0x00010000 - /* non-prefetchable memory */ - 0x82000000 0 0x08000000 0x08000000 0 0x00f00000>; bus-range = <0x00 0xff>; + ranges = <0x81000000 0 0 0x08f80000 0 0x00010000 /* downstream I/O */ + 0x82000000 0 0x08000000 0x08000000 0 0x00f00000>; /* non-prefetchable memory */ num-lanes = <1>; interrupts = ; - clocks = <&clks IMX6SX_CLK_PCIE_REF_125M>, - <&clks IMX6SX_CLK_PCIE_AXI>, + interrupt-names = "msi"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &gpc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &gpc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &gpc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &gpc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SX_CLK_PCIE_AXI>, <&clks IMX6SX_CLK_LVDS1_OUT>, + <&clks IMX6SX_CLK_PCIE_REF_125M>, <&clks IMX6SX_CLK_DISPLAY_AXI>; - clock-names = "pcie_ref_125m", "pcie_axi", - "lvds_gate", "display_axi"; + clock-names = "pcie", "pcie_bus", "pcie_phy", "pcie_inbound_axi"; + power-domains = <&pd_pci>; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk.dts b/arch/arm/boot/dts/imx6ul-14x14-evk.dts index e5d3ef88be60..18fdb088ba1e 100644 --- a/arch/arm/boot/dts/imx6ul-14x14-evk.dts +++ b/arch/arm/boot/dts/imx6ul-14x14-evk.dts @@ -30,19 +30,14 @@ status = "okay"; }; - regulators { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - reg_sd1_vmmc: sd1_regulator { - compatible = "regulator-fixed"; - regulator-name = "VSD_3V3"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; - enable-active-high; - }; + reg_sd1_vmmc: regulator-sd1-vmmc { + compatible = "regulator-fixed"; + regulator-name = "VSD_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; + enable-active-high; }; sound { diff --git a/arch/arm/boot/dts/imx6ul.dtsi b/arch/arm/boot/dts/imx6ul.dtsi index d5181f85ca9c..5d6c3ba36cd1 100644 --- a/arch/arm/boot/dts/imx6ul.dtsi +++ b/arch/arm/boot/dts/imx6ul.dtsi @@ -68,12 +68,14 @@ clock-latency = <61036>; /* two CLK32 periods */ operating-points = < /* kHz uV */ + 696000 1275000 528000 1175000 396000 1025000 198000 950000 >; fsl,soc-operating-points = < /* KHz uV */ + 696000 1275000 528000 1175000 396000 1175000 198000 1175000 @@ -136,6 +138,23 @@ clock-output-names = "ipp_di1"; }; + tempmon: tempmon { + compatible = "fsl,imx6ul-tempmon", "fsl,imx6sx-tempmon"; + interrupt-parent = <&gpc>; + interrupts = ; + fsl,tempmon = <&anatop>; + nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>; + nvmem-cell-names = "calib", "temp_grade"; + clocks = <&clks IMX6UL_CLK_PLL3_USB_OTG>; + }; + + pmu { + compatible = "arm,cortex-a7-pmu"; + interrupt-parent = <&gpc>; + interrupts = ; + status = "disabled"; + }; + soc { #address-cells = <1>; #size-cells = <1>; @@ -143,12 +162,6 @@ interrupt-parent = <&gpc>; ranges; - pmu { - compatible = "arm,cortex-a7-pmu"; - interrupts = ; - status = "disabled"; - }; - ocram: sram@900000 { compatible = "mmio-sram"; reg = <0x00900000 0x20000>; @@ -476,6 +489,7 @@ fec2: ethernet@20b4000 { compatible = "fsl,imx6ul-fec", "fsl,imx6q-fec"; reg = <0x020b4000 0x4000>; + interrupt-names = "int0", "pps"; interrupts = , ; clocks = <&clks IMX6UL_CLK_ENET>, @@ -530,8 +544,11 @@ interrupts = , , ; + #address-cells = <1>; + #size-cells = <0>; - reg_3p0: regulator-3p0 { + reg_3p0: regulator-3p0@20c8110 { + reg = <0x20c8110>; compatible = "fsl,anatop-regulator"; regulator-name = "vdd3p0"; regulator-min-microvolt = <2625000>; @@ -545,7 +562,8 @@ anatop-enable-bit = <0>; }; - reg_arm: regulator-vddcore { + reg_arm: regulator-vddcore@20c8140 { + reg = <0x20c8140>; compatible = "fsl,anatop-regulator"; regulator-name = "cpu"; regulator-min-microvolt = <725000>; @@ -562,7 +580,8 @@ anatop-max-voltage = <1450000>; }; - reg_soc: regulator-vddsoc { + reg_soc: regulator-vddsoc@20c8140 { + reg = <0x20c8140>; compatible = "fsl,anatop-regulator"; regulator-name = "vddsoc"; regulator-min-microvolt = <725000>; @@ -598,15 +617,6 @@ fsl,anatop = <&anatop>; }; - tempmon: tempmon { - compatible = "fsl,imx6ul-tempmon", "fsl,imx6sx-tempmon"; - interrupts = ; - fsl,tempmon = <&anatop>; - nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>; - nvmem-cell-names = "calib", "temp_grade"; - clocks = <&clks IMX6UL_CLK_PLL3_USB_OTG>; - }; - snvs: snvs@20cc000 { compatible = "fsl,sec-v4.0-mon", "syscon", "simple-mfd"; reg = <0x020cc000 0x4000>; @@ -635,6 +645,10 @@ linux,keycode = ; wakeup-source; }; + + snvs_lpgpr: snvs-lpgpr { + compatible = "fsl,imx6ul-snvs-lpgpr"; + }; }; epit1: epit@20d0000 { @@ -784,6 +798,7 @@ fec1: ethernet@2188000 { compatible = "fsl,imx6ul-fec", "fsl,imx6q-fec"; reg = <0x02188000 0x4000>; + interrupt-names = "int0", "pps"; interrupts = , ; clocks = <&clks IMX6UL_CLK_ENET>, diff --git a/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi b/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi index 18bebd6d8d47..3f2746169181 100644 --- a/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi +++ b/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi @@ -45,6 +45,13 @@ stdout-path = "serial0:115200n8"; }; + /* fixed crystal dedicated to mpc258x */ + clk16m: clk16m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <16000000>; + }; + panel: panel { compatible = "edt,et057090dhu"; backlight = <&bl>; @@ -70,6 +77,17 @@ regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; }; + + reg_usbh_vbus: regulator-usbh-vbus { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbh_reg>; + regulator-name = "VCC_USB[1-4]"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio4 7 GPIO_ACTIVE_LOW>; + vin-supply = <®_5v0>; + }; }; &bl { @@ -88,6 +106,24 @@ status = "okay"; }; +&ecspi3 { + status = "okay"; + + mcp2515: can@0 { + compatible = "microchip,mcp2515"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_can_int>; + reg = <0>; + clocks = <&clk16m>; + interrupt-parent = <&gpio5>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + spi-max-frequency = <10000000>; + vdd-supply = <®_3v3>; + xceiver-supply = <®_5v0>; + status = "okay"; + }; +}; + &fec1 { status = "okay"; }; @@ -97,7 +133,7 @@ /* M41T0M6 real time clock on carrier board */ rtc: m41t0m6@68 { - compatible = "st,m41t00"; + compatible = "st,m41t0"; reg = <0x68>; }; }; @@ -147,5 +183,6 @@ &usdhc1 { keep-power-in-suspend; wakeup-source; + vmmc-supply = <®_3v3>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx7-colibri.dtsi b/arch/arm/boot/dts/imx7-colibri.dtsi index bb5bf94f1a32..895fbde4d433 100644 --- a/arch/arm/boot/dts/imx7-colibri.dtsi +++ b/arch/arm/boot/dts/imx7-colibri.dtsi @@ -43,7 +43,10 @@ / { bl: backlight { compatible = "pwm-backlight"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_bl_on>; pwms = <&pwm1 0 5000000 0>; + enable-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>; }; reg_module_3v3: regulator-module-3v3 { @@ -86,7 +89,13 @@ }; &cpu0 { - arm-supply = <®_DCDC2>; + cpu-supply = <®_DCDC2>; +}; + +&ecspi3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi3 &pinctrl_ecspi3_cs>; + cs-gpios = <&gpio4 11 GPIO_ACTIVE_HIGH>; }; &fec1 { @@ -112,7 +121,6 @@ fsl,use-minimum-ecc; nand-on-flash-bbt; nand-ecc-mode = "hw"; - status = "okay"; }; &i2c1 { @@ -299,6 +307,22 @@ no-1-8-v; cd-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>; disable-wp; + vqmmc-supply = <®_LDO2>; +}; + +&usdhc3 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc3>; + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; + assigned-clocks = <&clks IMX7D_USDHC3_ROOT_CLK>; + assigned-clock-rates = <400000000>; + bus-width = <8>; + fsl,tuning-step = <2>; + max-frequency = <100000000>; + vmmc-supply = <®_module_3v3>; + vqmmc-supply = <®_DCDC3>; + non-removable; }; &iomuxc { @@ -307,17 +331,16 @@ pinctrl_gpio1: gpio1-grp { fsl,pins = < - MX7D_PAD_ENET1_RGMII_RD3__GPIO7_IO3 0x14 /* SODIMM 55 */ - MX7D_PAD_ENET1_RGMII_RD2__GPIO7_IO2 0x14 /* SODIMM 63 */ - MX7D_PAD_SD1_RESET_B__GPIO5_IO2 0X14 /* SODIMM 73 */ - MX7D_PAD_SAI1_RX_SYNC__GPIO6_IO16 0X14 /* SODIMM 77 */ + MX7D_PAD_ENET1_RGMII_RD3__GPIO7_IO3 0x74 /* SODIMM 55 */ + MX7D_PAD_ENET1_RGMII_RD2__GPIO7_IO2 0x74 /* SODIMM 63 */ + MX7D_PAD_SAI1_RX_SYNC__GPIO6_IO16 0x14 /* SODIMM 77 */ MX7D_PAD_EPDC_DATA09__GPIO2_IO9 0x14 /* SODIMM 89 */ - MX7D_PAD_EPDC_DATA08__GPIO2_IO8 0x14 /* SODIMM 91 */ + MX7D_PAD_EPDC_DATA08__GPIO2_IO8 0x74 /* SODIMM 91 */ MX7D_PAD_LCD_RESET__GPIO3_IO4 0x14 /* SODIMM 93 */ MX7D_PAD_EPDC_DATA13__GPIO2_IO13 0x14 /* SODIMM 95 */ MX7D_PAD_ENET1_RGMII_TXC__GPIO7_IO11 0x14 /* SODIMM 99 */ - MX7D_PAD_EPDC_DATA10__GPIO2_IO10 0x14 /* SODIMM 105 */ - MX7D_PAD_EPDC_DATA15__GPIO2_IO15 0x14 /* SODIMM 107 */ + MX7D_PAD_EPDC_DATA10__GPIO2_IO10 0x74 /* SODIMM 105 */ + MX7D_PAD_EPDC_DATA15__GPIO2_IO15 0x74 /* SODIMM 107 */ MX7D_PAD_EPDC_DATA00__GPIO2_IO0 0x14 /* SODIMM 111 */ MX7D_PAD_EPDC_DATA01__GPIO2_IO1 0x14 /* SODIMM 113 */ MX7D_PAD_EPDC_DATA02__GPIO2_IO2 0x14 /* SODIMM 115 */ @@ -329,11 +352,12 @@ MX7D_PAD_EPDC_SDCE2__GPIO2_IO22 0x14 /* SODIMM 127 */ MX7D_PAD_UART3_RTS_B__GPIO4_IO6 0x14 /* SODIMM 131 */ MX7D_PAD_EPDC_GDRL__GPIO2_IO26 0x14 /* SODIMM 133 */ + MX7D_PAD_SAI1_RX_DATA__GPIO6_IO12 0x14 /* SODIMM 169 */ MX7D_PAD_SAI1_RX_BCLK__GPIO6_IO17 0x14 /* SODIMM 24 */ MX7D_PAD_SD2_DATA2__GPIO5_IO16 0x14 /* SODIMM 100 */ MX7D_PAD_SD2_DATA3__GPIO5_IO17 0x14 /* SODIMM 102 */ MX7D_PAD_EPDC_GDSP__GPIO2_IO27 0x14 /* SODIMM 104 */ - MX7D_PAD_EPDC_BDR0__GPIO2_IO28 0x14 /* SODIMM 106 */ + MX7D_PAD_EPDC_BDR0__GPIO2_IO28 0x74 /* SODIMM 106 */ MX7D_PAD_EPDC_BDR1__GPIO2_IO29 0x14 /* SODIMM 110 */ MX7D_PAD_EPDC_PWR_COM__GPIO2_IO30 0x14 /* SODIMM 112 */ MX7D_PAD_EPDC_SDCLK__GPIO2_IO16 0x14 /* SODIMM 114 */ @@ -357,8 +381,7 @@ pinctrl_gpio2: gpio2-grp { /* On X22 Camera interface */ fsl,pins = < MX7D_PAD_ECSPI2_SS0__GPIO4_IO23 0x14 /* SODIMM 65 */ - MX7D_PAD_SD1_CD_B__GPIO5_IO0 0x14 /* SODIMM 69 */ - MX7D_PAD_SD1_WP__GPIO5_IO1 0x14 /* SODIMM 71 */ + MX7D_PAD_SD1_CD_B__GPIO5_IO0 0x74 /* SODIMM 69 */ MX7D_PAD_I2C4_SDA__GPIO4_IO15 0x14 /* SODIMM 75 */ MX7D_PAD_ECSPI1_MISO__GPIO4_IO18 0x14 /* SODIMM 79 */ MX7D_PAD_I2C3_SCL__GPIO4_IO12 0x14 /* SODIMM 81 */ @@ -378,8 +401,8 @@ MX7D_PAD_LCD_DATA19__GPIO3_IO24 0x14 /* SODIMM 138 */ MX7D_PAD_LCD_DATA20__GPIO3_IO25 0x14 /* SODIMM 140 */ MX7D_PAD_LCD_DATA21__GPIO3_IO26 0x14 /* SODIMM 142 */ - MX7D_PAD_LCD_DATA22__GPIO3_IO27 0x14 /* SODIMM 146 */ - MX7D_PAD_LCD_DATA23__GPIO3_IO28 0x14 /* SODIMM 148 */ + MX7D_PAD_LCD_DATA22__GPIO3_IO27 0x74 /* SODIMM 144 */ + MX7D_PAD_LCD_DATA23__GPIO3_IO28 0x74 /* SODIMM 146 */ >; }; @@ -396,6 +419,12 @@ >; }; + pinctrl_can_int: can-int-grp { + fsl,pins = < + MX7D_PAD_SD1_RESET_B__GPIO5_IO2 0X14 /* SODIMM 73 */ + >; + }; + pinctrl_enet1: enet1grp { fsl,pins = < MX7D_PAD_ENET1_CRS__GPIO7_IO14 0x14 @@ -434,12 +463,17 @@ >; }; + pinctrl_gpio_bl_on: gpio-bl-on { + fsl,pins = < + MX7D_PAD_SD1_WP__GPIO5_IO1 0x14 /* SODIMM 71 */ + >; + }; + pinctrl_gpmi_nand: gpmi-nand-grp { fsl,pins = < MX7D_PAD_SD3_CLK__NAND_CLE 0x71 MX7D_PAD_SD3_CMD__NAND_ALE 0x71 MX7D_PAD_SAI1_TX_BCLK__NAND_CE0_B 0x71 - MX7D_PAD_SAI1_RX_DATA__NAND_CE1_B 0x71 MX7D_PAD_SAI1_TX_DATA__NAND_READY_B 0x74 MX7D_PAD_SD3_STROBE__NAND_RE_B 0x71 MX7D_PAD_SD3_RESET_B__NAND_WE_B 0x71 @@ -507,6 +541,7 @@ pinctrl_pwm1: pwm1-grp { fsl,pins = < MX7D_PAD_GPIO1_IO08__PWM1_OUT 0x79 + MX7D_PAD_ECSPI2_MOSI__GPIO4_IO21 0x4 >; }; @@ -525,6 +560,7 @@ pinctrl_pwm4: pwm4-grp { fsl,pins = < MX7D_PAD_GPIO1_IO11__PWM4_OUT 0x79 + MX7D_PAD_ECSPI2_SCLK__GPIO4_IO20 0x4 >; }; @@ -559,7 +595,7 @@ >; }; - pinctrl_usbotg2_reg: gpio-usbotg2-vbus { + pinctrl_usbh_reg: gpio-usbh-vbus { fsl,pins = < MX7D_PAD_UART3_CTS_B__GPIO4_IO7 0x14 /* SODIMM 129 USBH PEN */ >; @@ -576,6 +612,54 @@ >; }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX7D_PAD_SD3_CMD__SD3_CMD 0x59 + MX7D_PAD_SD3_CLK__SD3_CLK 0x19 + MX7D_PAD_SD3_DATA0__SD3_DATA0 0x59 + MX7D_PAD_SD3_DATA1__SD3_DATA1 0x59 + MX7D_PAD_SD3_DATA2__SD3_DATA2 0x59 + MX7D_PAD_SD3_DATA3__SD3_DATA3 0x59 + MX7D_PAD_SD3_DATA4__SD3_DATA4 0x59 + MX7D_PAD_SD3_DATA5__SD3_DATA5 0x59 + MX7D_PAD_SD3_DATA6__SD3_DATA6 0x59 + MX7D_PAD_SD3_DATA7__SD3_DATA7 0x59 + MX7D_PAD_SD3_STROBE__SD3_STROBE 0x19 + >; + }; + + pinctrl_usdhc3_100mhz: usdhc3grp_100mhz { + fsl,pins = < + MX7D_PAD_SD3_CMD__SD3_CMD 0x5a + MX7D_PAD_SD3_CLK__SD3_CLK 0x1a + MX7D_PAD_SD3_DATA0__SD3_DATA0 0x5a + MX7D_PAD_SD3_DATA1__SD3_DATA1 0x5a + MX7D_PAD_SD3_DATA2__SD3_DATA2 0x5a + MX7D_PAD_SD3_DATA3__SD3_DATA3 0x5a + MX7D_PAD_SD3_DATA4__SD3_DATA4 0x5a + MX7D_PAD_SD3_DATA5__SD3_DATA5 0x5a + MX7D_PAD_SD3_DATA6__SD3_DATA6 0x5a + MX7D_PAD_SD3_DATA7__SD3_DATA7 0x5a + MX7D_PAD_SD3_STROBE__SD3_STROBE 0x1a + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3grp_200mhz { + fsl,pins = < + MX7D_PAD_SD3_CMD__SD3_CMD 0x5b + MX7D_PAD_SD3_CLK__SD3_CLK 0x1b + MX7D_PAD_SD3_DATA0__SD3_DATA0 0x5b + MX7D_PAD_SD3_DATA1__SD3_DATA1 0x5b + MX7D_PAD_SD3_DATA2__SD3_DATA2 0x5b + MX7D_PAD_SD3_DATA3__SD3_DATA3 0x5b + MX7D_PAD_SD3_DATA4__SD3_DATA4 0x5b + MX7D_PAD_SD3_DATA5__SD3_DATA5 0x5b + MX7D_PAD_SD3_DATA6__SD3_DATA6 0x5b + MX7D_PAD_SD3_DATA7__SD3_DATA7 0x5b + MX7D_PAD_SD3_STROBE__SD3_STROBE 0x1b + >; + }; + pinctrl_sai1: sai1-grp { fsl,pins = < MX7D_PAD_ENET1_RX_CLK__SAI1_TX_BCLK 0x1f diff --git a/arch/arm/boot/dts/imx7d-colibri-emmc-eval-v3.dts b/arch/arm/boot/dts/imx7d-colibri-emmc-eval-v3.dts new file mode 100644 index 000000000000..8ee73c870b12 --- /dev/null +++ b/arch/arm/boot/dts/imx7d-colibri-emmc-eval-v3.dts @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2017 Toradex AG + */ + +/dts-v1/; +#include "imx7d-colibri-emmc.dtsi" +#include "imx7-colibri-eval-v3.dtsi" + +/ { + model = "Toradex Colibri iMX7D 1GB (eMMC) on Colibri Evaluation Board V3"; + compatible = "toradex,colibri-imx7d-emmc-eval-v3", + "toradex,colibri-imx7d-emmc", "fsl,imx7d"; +}; + +&usbotg2 { + vbus-supply = <®_usbh_vbus>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx7d-colibri-emmc.dtsi b/arch/arm/boot/dts/imx7d-colibri-emmc.dtsi new file mode 100644 index 000000000000..9b63b9c89e4b --- /dev/null +++ b/arch/arm/boot/dts/imx7d-colibri-emmc.dtsi @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2017 Toradex AG + */ + +#include "imx7d.dtsi" +#include "imx7-colibri.dtsi" + +/ { + memory { + reg = <0x80000000 0x40000000>; + }; +}; + +&usbotg2 { + dr_mode = "host"; +}; + +&usdhc3 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/imx7d-colibri-eval-v3.dts b/arch/arm/boot/dts/imx7d-colibri-eval-v3.dts index a608a14d8c85..136e11ab4893 100644 --- a/arch/arm/boot/dts/imx7d-colibri-eval-v3.dts +++ b/arch/arm/boot/dts/imx7d-colibri-eval-v3.dts @@ -48,20 +48,9 @@ model = "Toradex Colibri iMX7D on Colibri Evaluation Board V3"; compatible = "toradex,colibri-imx7d-eval-v3", "toradex,colibri-imx7d", "fsl,imx7d"; - - reg_usb_otg2_vbus: regulator-usb-otg2-vbus { - compatible = "regulator-fixed"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usbotg2_reg>; - regulator-name = "VCC_USB[1-4]"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - gpio = <&gpio4 7 GPIO_ACTIVE_LOW>; - vin-supply = <®_5v0>; - }; }; &usbotg2 { - vbus-supply = <®_usb_otg2_vbus>; + vbus-supply = <®_usbh_vbus>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx7d-colibri.dtsi b/arch/arm/boot/dts/imx7d-colibri.dtsi index 3c2cb502b388..6f2bb70c1fbd 100644 --- a/arch/arm/boot/dts/imx7d-colibri.dtsi +++ b/arch/arm/boot/dts/imx7d-colibri.dtsi @@ -49,6 +49,10 @@ }; }; +&gpmi { + status = "okay"; +}; + &usbotg2 { dr_mode = "host"; }; diff --git a/arch/arm/boot/dts/imx7d-pico-pi.dts b/arch/arm/boot/dts/imx7d-pico-pi.dts new file mode 100644 index 000000000000..ee02d931cf49 --- /dev/null +++ b/arch/arm/boot/dts/imx7d-pico-pi.dts @@ -0,0 +1,181 @@ +/* + * Copyright 2017 NXP + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "imx7d-pico.dtsi" + +/ { + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "imx7-sgtl5000"; + simple-audio-card,format = "i2s"; + simple-audio-card,bitclock-master = <&dailink_master>; + simple-audio-card,frame-master = <&dailink_master>; + simple-audio-card,cpu { + sound-dai = <&sai1>; + }; + + dailink_master: simple-audio-card,codec { + sound-dai = <&codec>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; + }; + }; +}; + +&fec1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet1>; + assigned-clocks = <&clks IMX7D_ENET1_TIME_ROOT_SRC>, + <&clks IMX7D_ENET1_TIME_ROOT_CLK>; + assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>; + assigned-clock-rates = <0>, <100000000>; + phy-mode = "rgmii"; + phy-handle = <ðphy0>; + fsl,magic-packet; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + status = "okay"; + }; + }; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + codec: sgtl5000@a { + #sound-dai-cells = <0>; + reg = <0x0a>; + compatible = "fsl,sgtl5000"; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; + VDDA-supply = <®_2p5v>; + VDDIO-supply = <®_vref_1v8>; + }; +}; + + +&sai1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai1>; + assigned-clocks = <&clks IMX7D_SAI1_ROOT_SRC>, + <&clks IMX7D_SAI1_ROOT_CLK>; + assigned-clock-parents = <&clks IMX7D_PLL_AUDIO_POST_DIV>; + assigned-clock-rates = <0>, <24576000>; + status = "okay"; +}; + +&uart5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart5>; + assigned-clocks = <&clks IMX7D_UART5_ROOT_SRC>; + assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>; + status = "okay"; +}; + +&usbotg1 { + vbus-supply = <®_usb_otg1_vbus>; + status = "okay"; +}; + +&usbotg2 { + vbus-supply = <®_usb_otg2_vbus>; + dr_mode = "host"; + status = "okay"; +}; + +&iomuxc { + pinctrl_enet1: enet1grp { + fsl,pins = < + MX7D_PAD_SD2_CD_B__ENET1_MDIO 0x3 + MX7D_PAD_SD2_WP__ENET1_MDC 0x3 + MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC 0x1 + MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0 0x1 + MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1 0x1 + MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2 0x1 + MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3 0x1 + MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL 0x1 + MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC 0x1 + MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0 0x1 + MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1 0x1 + MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2 0x1 + MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3 0x1 + MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL 0x1 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX7D_PAD_UART1_TX_DATA__I2C1_SDA 0x4000007f + MX7D_PAD_UART1_RX_DATA__I2C1_SCL 0x4000007f + >; + }; + + pinctrl_sai1: sai1grp { + fsl,pins = < + MX7D_PAD_ENET1_RX_CLK__SAI1_TX_BCLK 0x1f + MX7D_PAD_ENET1_CRS__SAI1_TX_SYNC 0x1f + MX7D_PAD_ENET1_COL__SAI1_TX_DATA0 0x30 + MX7D_PAD_ENET1_TX_CLK__SAI1_RX_DATA0 0x1f + >; + }; + + pinctrl_uart5: uart5grp { + fsl,pins = < + MX7D_PAD_I2C4_SDA__UART5_DCE_TX 0x79 + MX7D_PAD_I2C4_SCL__UART5_DCE_RX 0x79 + >; + }; + + pinctrl_usbotg1_pwr: usbotg_pwr { + fsl,pins = < + MX7D_PAD_UART3_TX_DATA__GPIO4_IO5 0x14 + >; + }; +}; diff --git a/arch/arm/boot/dts/imx7d-pico.dts b/arch/arm/boot/dts/imx7d-pico.dtsi similarity index 71% rename from arch/arm/boot/dts/imx7d-pico.dts rename to arch/arm/boot/dts/imx7d-pico.dtsi index 508328b2a6bf..e307462a48ec 100644 --- a/arch/arm/boot/dts/imx7d-pico.dts +++ b/arch/arm/boot/dts/imx7d-pico.dtsi @@ -100,62 +100,6 @@ regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; - - sound { - compatible = "simple-audio-card"; - simple-audio-card,name = "imx7-sgtl5000"; - simple-audio-card,format = "i2s"; - simple-audio-card,bitclock-master = <&dailink_master>; - simple-audio-card,frame-master = <&dailink_master>; - simple-audio-card,cpu { - sound-dai = <&sai1>; - }; - - dailink_master: simple-audio-card,codec { - sound-dai = <&codec>; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; - }; - }; -}; - -&fec1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_enet1>; - assigned-clocks = <&clks IMX7D_ENET1_TIME_ROOT_SRC>, - <&clks IMX7D_ENET1_TIME_ROOT_CLK>; - assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>; - assigned-clock-rates = <0>, <100000000>; - phy-mode = "rgmii"; - phy-handle = <ðphy0>; - fsl,magic-packet; - status = "okay"; - - mdio { - #address-cells = <1>; - #size-cells = <0>; - - ethphy0: ethernet-phy@1 { - compatible = "ethernet-phy-ieee802.3-c22"; - reg = <1>; - status = "okay"; - }; - }; -}; - -&i2c1 { - clock-frequency = <100000>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2c1>; - status = "okay"; - - codec: sgtl5000@a { - #sound-dai-cells = <0>; - reg = <0x0a>; - compatible = "fsl,sgtl5000"; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; - VDDA-supply = <®_2p5v>; - VDDIO-supply = <®_vref_1v8>; - }; }; &i2c4 { @@ -253,35 +197,6 @@ }; }; -&sai1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_sai1>; - assigned-clocks = <&clks IMX7D_SAI1_ROOT_SRC>, - <&clks IMX7D_SAI1_ROOT_CLK>; - assigned-clock-parents = <&clks IMX7D_PLL_AUDIO_POST_DIV>; - assigned-clock-rates = <0>, <24576000>; - status = "okay"; -}; - -&uart5 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_uart5>; - assigned-clocks = <&clks IMX7D_UART5_ROOT_SRC>; - assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>; - status = "okay"; -}; - -&usbotg1 { - vbus-supply = <®_usb_otg1_vbus>; - status = "okay"; -}; - -&usbotg2 { - vbus-supply = <®_usb_otg2_vbus>; - dr_mode = "host"; - status = "okay"; -}; - &usdhc2 { /* Wifi SDIO */ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usdhc2>; @@ -315,32 +230,6 @@ }; &iomuxc { - pinctrl_enet1: enet1grp { - fsl,pins = < - MX7D_PAD_SD2_CD_B__ENET1_MDIO 0x3 - MX7D_PAD_SD2_WP__ENET1_MDC 0x3 - MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC 0x1 - MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0 0x1 - MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1 0x1 - MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2 0x1 - MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3 0x1 - MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL 0x1 - MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC 0x1 - MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0 0x1 - MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1 0x1 - MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2 0x1 - MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3 0x1 - MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL 0x1 - >; - }; - - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX7D_PAD_UART1_TX_DATA__I2C1_SDA 0x4000007f - MX7D_PAD_UART1_RX_DATA__I2C1_SCL 0x4000007f - >; - }; - pinctrl_i2c4: i2c4grp { fsl,pins = < MX7D_PAD_SAI1_RX_BCLK__I2C4_SDA 0x4000007f @@ -354,28 +243,6 @@ >; }; - pinctrl_sai1: sai1grp { - fsl,pins = < - MX7D_PAD_ENET1_RX_CLK__SAI1_TX_BCLK 0x1f - MX7D_PAD_ENET1_CRS__SAI1_TX_SYNC 0x1f - MX7D_PAD_ENET1_COL__SAI1_TX_DATA0 0x30 - MX7D_PAD_ENET1_TX_CLK__SAI1_RX_DATA0 0x1f - >; - }; - - pinctrl_uart5: uart5grp { - fsl,pins = < - MX7D_PAD_I2C4_SDA__UART5_DCE_TX 0x79 - MX7D_PAD_I2C4_SCL__UART5_DCE_RX 0x79 - >; - }; - - pinctrl_usbotg1_pwr: usbotg_pwr { - fsl,pins = < - MX7D_PAD_UART3_TX_DATA__GPIO4_IO5 0x14 - >; - }; - pinctrl_usdhc2: usdhc2grp { fsl,pins = < MX7D_PAD_SD2_CMD__SD2_CMD 0x59 diff --git a/arch/arm/boot/dts/imx7d.dtsi b/arch/arm/boot/dts/imx7d.dtsi index 4d308d17f040..200714e3feea 100644 --- a/arch/arm/boot/dts/imx7d.dtsi +++ b/arch/arm/boot/dts/imx7d.dtsi @@ -63,6 +63,13 @@ }; }; + usbphynop2: usbphynop2 { + compatible = "usb-nop-xceiv"; + clocks = <&clks IMX7D_USB_PHY2_CLK>; + clock-names = "main_clk"; + #phy-cells = <0>; + }; + soc { etm@3007d000 { compatible = "arm,coresight-etm3x", "arm,primecell"; @@ -105,18 +112,14 @@ reg = <0x30b20200 0x200>; }; - usbphynop2: usbphynop2 { - compatible = "usb-nop-xceiv"; - clocks = <&clks IMX7D_USB_PHY2_CLK>; - clock-names = "main_clk"; - }; - fec2: ethernet@30bf0000 { compatible = "fsl,imx7d-fec", "fsl,imx6sx-fec"; reg = <0x30bf0000 0x10000>; - interrupts = , + interrupt-names = "int0", "int1", "int2", "pps"; + interrupts = , + , , - ; + ; clocks = <&clks IMX7D_ENET_AXI_ROOT_CLK>, <&clks IMX7D_ENET_AXI_ROOT_CLK>, <&clks IMX7D_ENET2_TIME_ROOT_CLK>, @@ -129,7 +132,7 @@ status = "disabled"; }; - pcie: pcie@0x33800000 { + pcie: pcie@33800000 { compatible = "fsl,imx7d-pcie", "snps,dw-pcie"; reg = <0x33800000 0x4000>, <0x4ff00000 0x80000>; @@ -137,6 +140,7 @@ #address-cells = <3>; #size-cells = <2>; device_type = "pci"; + bus-range = <0x00 0xff>; ranges = <0x81000000 0 0 0x4ff80000 0 0x00010000 /* downstream I/O */ 0x82000000 0 0x40000000 0x40000000 0 0x0ff00000>; /* non-prefetchable memory */ num-lanes = <1>; diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi index 82ad26e766eb..9aa2bb998552 100644 --- a/arch/arm/boot/dts/imx7s.dtsi +++ b/arch/arm/boot/dts/imx7s.dtsi @@ -116,6 +116,66 @@ clock-output-names = "osc"; }; + usbphynop1: usbphynop1 { + compatible = "usb-nop-xceiv"; + clocks = <&clks IMX7D_USB_PHY1_CLK>; + clock-names = "main_clk"; + #phy-cells = <0>; + }; + + usbphynop3: usbphynop3 { + compatible = "usb-nop-xceiv"; + clocks = <&clks IMX7D_USB_HSIC_ROOT_CLK>; + clock-names = "main_clk"; + #phy-cells = <0>; + }; + + + replicator { + /* + * non-configurable replicators don't show up on the + * AMBA bus. As such no need to add "arm,primecell" + */ + compatible = "arm,coresight-replicator"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + /* replicator output ports */ + port@0 { + reg = <0>; + replicator_out_port0: endpoint { + remote-endpoint = <&tpiu_in_port>; + }; + }; + + port@1 { + reg = <1>; + replicator_out_port1: endpoint { + remote-endpoint = <&etr_in_port>; + }; + }; + + /* replicator input port */ + port@2 { + reg = <0>; + replicator_in_port0: endpoint { + slave-mode; + remote-endpoint = <&etf_out_port>; + }; + }; + }; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupt-parent = <&intc>; + interrupts = , + , + , + ; + }; + soc { #address-cells = <1>; #size-cells = <1>; @@ -260,43 +320,6 @@ }; }; - replicator { - /* - * non-configurable replicators don't show up on the - * AMBA bus. As such no need to add "arm,primecell" - */ - compatible = "arm,coresight-replicator"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - /* replicator output ports */ - port@0 { - reg = <0>; - replicator_out_port0: endpoint { - remote-endpoint = <&tpiu_in_port>; - }; - }; - - port@1 { - reg = <1>; - replicator_out_port1: endpoint { - remote-endpoint = <&etr_in_port>; - }; - }; - - /* replicator input port */ - port@2 { - reg = <0>; - replicator_in_port0: endpoint { - slave-mode; - remote-endpoint = <&etf_out_port>; - }; - }; - }; - }; - intc: interrupt-controller@31001000 { compatible = "arm,cortex-a7-gic"; interrupts = ; @@ -309,15 +332,6 @@ <0x31006000 0x2000>; }; - timer { - compatible = "arm,armv7-timer"; - interrupt-parent = <&intc>; - interrupts = , - , - , - ; - }; - aips1: aips-bus@30000000 { compatible = "fsl,aips-bus", "simple-bus"; #address-cells = <1>; @@ -508,8 +522,11 @@ reg = <0x30360000 0x10000>; interrupts = , ; + #address-cells = <1>; + #size-cells = <0>; - reg_1p0d: regulator-vdd1p0d { + reg_1p0d: regulator-vdd1p0d@30360210 { + reg = <0x30360210>; compatible = "fsl,anatop-regulator"; regulator-name = "vdd1p0d"; regulator-min-microvolt = <800000>; @@ -583,9 +600,9 @@ #address-cells = <1>; #size-cells = <0>; - pgc_pcie_phy: pgc-power-domain@IMX7_POWER_DOMAIN_PCIE_PHY { + pgc_pcie_phy: pgc-power-domain@1 { #power-domain-cells = <0>; - reg = ; + reg = <1>; power-supply = <®_1p0d>; }; }; @@ -945,18 +962,6 @@ reg = <0x30b30200 0x200>; }; - usbphynop1: usbphynop1 { - compatible = "usb-nop-xceiv"; - clocks = <&clks IMX7D_USB_PHY1_CLK>; - clock-names = "main_clk"; - }; - - usbphynop3: usbphynop3 { - compatible = "usb-nop-xceiv"; - clocks = <&clks IMX7D_USB_HSIC_ROOT_CLK>; - clock-names = "main_clk"; - }; - usdhc1: usdhc@30b40000 { compatible = "fsl,imx7d-usdhc", "fsl,imx6sl-usdhc"; reg = <0x30b40000 0x10000>; @@ -1007,9 +1012,11 @@ fec1: ethernet@30be0000 { compatible = "fsl,imx7d-fec", "fsl,imx6sx-fec"; reg = <0x30be0000 0x10000>; - interrupts = , + interrupt-names = "int0", "int1", "int2", "pps"; + interrupts = , + , , - ; + ; clocks = <&clks IMX7D_ENET_AXI_ROOT_CLK>, <&clks IMX7D_ENET_AXI_ROOT_CLK>, <&clks IMX7D_ENET1_TIME_ROOT_CLK>, diff --git a/arch/arm/boot/dts/iwg20d-q7-common.dtsi b/arch/arm/boot/dts/iwg20d-q7-common.dtsi index efd8af9242d1..66954aaf2c47 100644 --- a/arch/arm/boot/dts/iwg20d-q7-common.dtsi +++ b/arch/arm/boot/dts/iwg20d-q7-common.dtsi @@ -8,9 +8,33 @@ * kind, whether express or implied. */ +/* + * SSI-SGTL5000 + * + * This command is required when Playback/Capture + * + * amixer set "DVC Out" 100% + * amixer set "DVC In" 100% + * + * You can use Mute + * + * amixer set "DVC Out Mute" on + * amixer set "DVC In Mute" on + * + * You can use Volume Ramp + * + * amixer set "DVC Out Ramp Up Rate" "0.125 dB/64 steps" + * amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps" + * amixer set "DVC Out Ramp" on + * aplay xxx.wav & + * amixer set "DVC Out" 80% // Volume Down + * amixer set "DVC Out" 100% // Volume Up + */ + / { aliases { serial0 = &scif0; + serial3 = &scifb1; ethernet0 = &avb; }; @@ -19,6 +43,36 @@ stdout-path = "serial0:115200n8"; }; + audio_clock: audio_clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <26000000>; + }; + + reg_1p5v: 1p5v { + compatible = "regulator-fixed"; + regulator-name = "1P5V"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + }; + + rsnd_sgtl5000: sound { + compatible = "simple-audio-card"; + + simple-audio-card,format = "i2s"; + simple-audio-card,bitclock-master = <&sndcodec>; + simple-audio-card,frame-master = <&sndcodec>; + + sndcpu: simple-audio-card,cpu { + sound-dai = <&rcar_sound>; + }; + + sndcodec: simple-audio-card,codec { + sound-dai = <&sgtl5000>; + }; + }; + vcc_sdhi1: regulator-vcc-sdhi1 { compatible = "regulator-fixed"; @@ -58,6 +112,13 @@ }; }; +&can0 { + pinctrl-0 = <&can0_pins>; + pinctrl-names = "default"; + + status = "okay"; +}; + &hsusb { status = "okay"; pinctrl-0 = <&usb0_pins>; @@ -75,6 +136,16 @@ compatible = "ti,bq32000"; reg = <0x68>; }; + + sgtl5000: codec@a { + compatible = "fsl,sgtl5000"; + #sound-dai-cells = <0>; + reg = <0x0a>; + clocks = <&audio_clock>; + VDDA-supply = <®_3p3v>; + VDDIO-supply = <®_3p3v>; + VDDD-supply = <®_1p5v>; + }; }; &pci0 { @@ -88,7 +159,20 @@ pinctrl-names = "default"; }; +&pcie_bus_clk { + clock-frequency = <100000000>; +}; + +&pciec { + status = "okay"; +}; + &pfc { + can0_pins: can0 { + groups = "can0_data_d"; + function = "can0"; + }; + avb_pins: avb { groups = "avb_mdio", "avb_gmii"; function = "avb"; @@ -104,6 +188,11 @@ function = "scif0"; }; + scifb1_pins: scifb1 { + groups = "scifb1_data_d", "scifb1_ctrl"; + function = "scifb1"; + }; + sdhi1_pins: sd1 { groups = "sdhi1_data4", "sdhi1_ctrl"; function = "sdhi1"; @@ -116,6 +205,11 @@ power-source = <1800>; }; + sound_pins: sound { + groups = "ssi0129_ctrl", "ssi0_data", "ssi1_data"; + function = "ssi"; + }; + usb0_pins: usb0 { groups = "usb0"; function = "usb0"; @@ -127,6 +221,22 @@ }; }; +&rcar_sound { + pinctrl-0 = <&sound_pins>; + pinctrl-names = "default"; + status = "okay"; + + /* Single DAI */ + #sound-dai-cells = <0>; + + rcar_sound,dai { + dai0 { + playback = <&ssi1 &src3 &dvc1>; + capture = <&ssi0 &src2 &dvc0>; + }; + }; +}; + &scif0 { pinctrl-0 = <&scif0_pins>; pinctrl-names = "default"; @@ -134,6 +244,14 @@ status = "okay"; }; +&scifb1 { + pinctrl-0 = <&scifb1_pins>; + pinctrl-names = "default"; + + uart-has-rtscts; + status = "okay"; +}; + &sdhi1 { pinctrl-0 = <&sdhi1_pins>; pinctrl-1 = <&sdhi1_pins_uhs>; @@ -147,6 +265,10 @@ status = "okay"; }; +&ssi1 { + shared-pin; +}; + &usbphy { status = "okay"; }; diff --git a/arch/arm/boot/dts/iwg20d-q7-dbcm-ca.dtsi b/arch/arm/boot/dts/iwg20d-q7-dbcm-ca.dtsi index 31fab5f183a9..476273b3f994 100644 --- a/arch/arm/boot/dts/iwg20d-q7-dbcm-ca.dtsi +++ b/arch/arm/boot/dts/iwg20d-q7-dbcm-ca.dtsi @@ -13,6 +13,44 @@ serial1 = &scif1; serial4 = &hscif1; }; + + cec_clock: cec-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; + + hdmi-out { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_out: endpoint { + remote-endpoint = <&adv7511_out>; + }; + }; + }; +}; + +&can1 { + pinctrl-0 = <&can1_pins>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&du { + pinctrl-0 = <&du_pins>; + pinctrl-names = "default"; + status = "okay"; + + ports { + port@0 { + endpoint { + remote-endpoint = <&adv7511_in>; + }; + }; + }; }; &hscif1 { @@ -23,7 +61,56 @@ status = "okay"; }; +&i2c5 { + status = "okay"; + clock-frequency = <400000>; + + hdmi@39 { + compatible = "adi,adv7511w"; + reg = <0x39>; + interrupt-parent = <&gpio0>; + interrupts = <13 IRQ_TYPE_LEVEL_LOW>; + clocks = <&cec_clock>; + clock-names = "cec"; + + adi,input-depth = <8>; + adi,input-colorspace = "rgb"; + adi,input-clock = "1x"; + adi,input-style = <1>; + adi,input-justification = "evenly"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + adv7511_in: endpoint { + remote-endpoint = <&du_out_rgb>; + }; + }; + + port@1 { + reg = <1>; + adv7511_out: endpoint { + remote-endpoint = <&hdmi_con_out>; + }; + }; + }; + }; +}; + &pfc { + can1_pins: can1 { + groups = "can1_data_d"; + function = "can1"; + }; + + du_pins: du { + groups = "du_rgb888", "du_sync", "du_oddf", "du_clk_out_0"; + function = "du"; + }; + hscif1_pins: hscif1 { groups = "hscif1_data_c", "hscif1_ctrl_c"; function = "hscif1"; diff --git a/arch/arm/boot/dts/keystone-clocks.dtsi b/arch/arm/boot/dts/keystone-clocks.dtsi index 0c334b25781e..457515b0736a 100644 --- a/arch/arm/boot/dts/keystone-clocks.dtsi +++ b/arch/arm/boot/dts/keystone-clocks.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Device Tree Source for Keystone 2 clock tree * - * Copyright (C) 2013 Texas Instruments, Inc. - * - * 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. + * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/ */ clocks { @@ -51,7 +48,7 @@ clocks { clock-output-names = "gemtraceclk"; }; - chipstmxptclk: chipstmxptclk { + chipstmxptclk: chipstmxptclk@2310164 { #clock-cells = <0>; compatible = "ti,keystone,pll-divider-clock"; clocks = <&mainmuxclk>; @@ -160,7 +157,7 @@ clocks { clock-output-names = "chipclk1rstiso112"; }; - clkmodrst0: clkmodrst0 { + clkmodrst0: clkmodrst0@2350000 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk16>; @@ -171,7 +168,7 @@ clocks { }; - clkusb: clkusb { + clkusb: clkusb@2350008 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk16>; @@ -181,7 +178,7 @@ clocks { domain-id = <0>; }; - clkaemifspi: clkaemifspi { + clkaemifspi: clkaemifspi@235000c { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk16>; @@ -192,7 +189,7 @@ clocks { }; - clkdebugsstrc: clkdebugsstrc { + clkdebugsstrc: clkdebugsstrc@2350014 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -202,7 +199,7 @@ clocks { domain-id = <1>; }; - clktetbtrc: clktetbtrc { + clktetbtrc: clktetbtrc@2350018 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -212,7 +209,7 @@ clocks { domain-id = <1>; }; - clkpa: clkpa { + clkpa: clkpa@235001c { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&paclk13>; @@ -222,7 +219,7 @@ clocks { domain-id = <2>; }; - clkcpgmac: clkcpgmac { + clkcpgmac: clkcpgmac@2350020 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&clkpa>; @@ -232,7 +229,7 @@ clocks { domain-id = <2>; }; - clksa: clksa { + clksa: clksa@2350024 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&clkpa>; @@ -242,7 +239,7 @@ clocks { domain-id = <2>; }; - clkpcie: clkpcie { + clkpcie: clkpcie@2350028 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk12>; @@ -252,7 +249,7 @@ clocks { domain-id = <3>; }; - clksr: clksr { + clksr: clksr@2350034 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk1rstiso112>; @@ -262,7 +259,7 @@ clocks { domain-id = <6>; }; - clkgem0: clkgem0 { + clkgem0: clkgem0@235003c { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk1>; @@ -272,7 +269,7 @@ clocks { domain-id = <8>; }; - clkddr30: clkddr30 { + clkddr30: clkddr30@235005c { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk12>; @@ -282,7 +279,7 @@ clocks { domain-id = <16>; }; - clkwdtimer0: clkwdtimer0 { + clkwdtimer0: clkwdtimer0@2350000 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&clkmodrst0>; @@ -292,7 +289,7 @@ clocks { domain-id = <0>; }; - clkwdtimer1: clkwdtimer1 { + clkwdtimer1: clkwdtimer1@2350000 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&clkmodrst0>; @@ -302,7 +299,7 @@ clocks { domain-id = <0>; }; - clkwdtimer2: clkwdtimer2 { + clkwdtimer2: clkwdtimer2@2350000 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&clkmodrst0>; @@ -312,7 +309,7 @@ clocks { domain-id = <0>; }; - clkwdtimer3: clkwdtimer3 { + clkwdtimer3: clkwdtimer3@2350000 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&clkmodrst0>; @@ -322,7 +319,7 @@ clocks { domain-id = <0>; }; - clktimer15: clktimer15 { + clktimer15: clktimer15@2350000 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&clkmodrst0>; @@ -332,7 +329,7 @@ clocks { domain-id = <0>; }; - clkuart0: clkuart0 { + clkuart0: clkuart0@2350000 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&clkmodrst0>; @@ -342,7 +339,7 @@ clocks { domain-id = <0>; }; - clkuart1: clkuart1 { + clkuart1: clkuart1@2350000 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&clkmodrst0>; @@ -352,7 +349,7 @@ clocks { domain-id = <0>; }; - clkaemif: clkaemif { + clkaemif: clkaemif@2350000 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&clkaemifspi>; @@ -362,7 +359,7 @@ clocks { domain-id = <0>; }; - clkusim: clkusim { + clkusim: clkusim@2350000 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&clkmodrst0>; @@ -372,7 +369,7 @@ clocks { domain-id = <0>; }; - clki2c: clki2c { + clki2c: clki2c@2350000 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&clkmodrst0>; @@ -382,7 +379,7 @@ clocks { domain-id = <0>; }; - clkspi: clkspi { + clkspi: clkspi@2350000 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&clkaemifspi>; @@ -392,7 +389,7 @@ clocks { domain-id = <0>; }; - clkgpio: clkgpio { + clkgpio: clkgpio@2350000 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&clkmodrst0>; @@ -402,7 +399,7 @@ clocks { domain-id = <0>; }; - clkkeymgr: clkkeymgr { + clkkeymgr: clkkeymgr@2350000 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&clkmodrst0>; diff --git a/arch/arm/boot/dts/keystone-k2e-clocks.dtsi b/arch/arm/boot/dts/keystone-k2e-clocks.dtsi index d56d68fe7ffc..5e0e7d232161 100644 --- a/arch/arm/boot/dts/keystone-k2e-clocks.dtsi +++ b/arch/arm/boot/dts/keystone-k2e-clocks.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2014 Texas Instruments, Inc. - * * Keystone 2 Edison SoC specific device tree * - * 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. + * Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/ */ clocks { @@ -35,7 +32,7 @@ clocks { reg-names = "control"; }; - clkusb1: clkusb1 { + clkusb1: clkusb1@2350004 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk16>; @@ -45,7 +42,7 @@ clocks { domain-id = <0>; }; - clkhyperlink0: clkhyperlink0 { + clkhyperlink0: clkhyperlink02350030 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk12>; @@ -55,7 +52,7 @@ clocks { domain-id = <5>; }; - clkpcie1: clkpcie1 { + clkpcie1: clkpcie1@235006c { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk12>; @@ -65,7 +62,7 @@ clocks { domain-id = <18>; }; - clkxge: clkxge { + clkxge: clkxge@23500c8 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; diff --git a/arch/arm/boot/dts/keystone-k2e-evm.dts b/arch/arm/boot/dts/keystone-k2e-evm.dts index f1f32c54e72f..66fec5f5d081 100644 --- a/arch/arm/boot/dts/keystone-k2e-evm.dts +++ b/arch/arm/boot/dts/keystone-k2e-evm.dts @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2013-2014 Texas Instruments, Inc. - * * Keystone 2 Edison EVM device tree * - * 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. + * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/ */ /dts-v1/; @@ -28,8 +25,9 @@ status = "okay"; }; }; +}; - soc { +&soc0 { clocks { refclksys: refclksys { @@ -53,7 +51,6 @@ clock-output-names = "refclk-ddr3a"; }; }; - }; }; &usb_phy { @@ -82,7 +79,7 @@ &i2c0 { dtt@50 { - compatible = "at,24c1024"; + compatible = "atmel,24c1024"; reg = <0x50>; }; }; diff --git a/arch/arm/boot/dts/keystone-k2e-netcp.dtsi b/arch/arm/boot/dts/keystone-k2e-netcp.dtsi index ba828cb59587..a17311c602aa 100644 --- a/arch/arm/boot/dts/keystone-k2e-netcp.dtsi +++ b/arch/arm/boot/dts/keystone-k2e-netcp.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Device Tree Source for Keystone 2 Edison Netcp driver * - * Copyright 2015 Texas Instruments, Inc. - * - * 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. + * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/ */ qmss: qmss@2a40000 { diff --git a/arch/arm/boot/dts/keystone-k2e.dtsi b/arch/arm/boot/dts/keystone-k2e.dtsi index 6b796b52ff4f..0bcd3f8a9c45 100644 --- a/arch/arm/boot/dts/keystone-k2e.dtsi +++ b/arch/arm/boot/dts/keystone-k2e.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2013-2014 Texas Instruments, Inc. - * * Keystone 2 Edison soc device tree * - * 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. + * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/ */ #include @@ -48,8 +45,9 @@ aliases { rproc0 = &dsp0; }; +}; - soc { +&soc0 { /include/ "keystone-k2e-clocks.dtsi" usb: usb@2680000 { @@ -194,5 +192,4 @@ bus_freq = <2500000>; }; /include/ "keystone-k2e-netcp.dtsi" - }; }; diff --git a/arch/arm/boot/dts/keystone-k2g-evm.dts b/arch/arm/boot/dts/keystone-k2g-evm.dts index 656af194a518..6a4657799b99 100644 --- a/arch/arm/boot/dts/keystone-k2g-evm.dts +++ b/arch/arm/boot/dts/keystone-k2g-evm.dts @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Device Tree Source for K2G EVM * - * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.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 "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/ */ /dts-v1/; @@ -45,22 +37,6 @@ regulator-max-microvolt = <3300000>; regulator-always-on; }; - - ecap0_pins: ecap0_pins { - pinctrl-single,pins = < - K2G_CORE_IOPAD(0x1374) (BUFFER_CLASS_B | MUX_MODE4) /* pr1_mdio_data.ecap0_in_apwm0_out */ - >; - }; - - spi1_pins: pinmux_spi1_pins { - pinctrl-single,pins = < - K2G_CORE_IOPAD(0x11a4) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* spi1_scs0.spi1_scs0 */ - K2G_CORE_IOPAD(0x11ac) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* spi1_clk.spi1_clk */ - K2G_CORE_IOPAD(0x11b0) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* spi1_miso.spi1_miso */ - K2G_CORE_IOPAD(0x11b4) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* spi1_mosi.spi1_mosi */ - >; - }; - }; &k2g_pinctrl { @@ -105,6 +81,39 @@ >; }; + ecap0_pins: ecap0_pins { + pinctrl-single,pins = < + K2G_CORE_IOPAD(0x1374) (BUFFER_CLASS_B | MUX_MODE4) /* pr1_mdio_data.ecap0_in_apwm0_out */ + >; + }; + + spi1_pins: pinmux_spi1_pins { + pinctrl-single,pins = < + K2G_CORE_IOPAD(0x11a4) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* spi1_scs0.spi1_scs0 */ + K2G_CORE_IOPAD(0x11ac) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* spi1_clk.spi1_clk */ + K2G_CORE_IOPAD(0x11b0) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* spi1_miso.spi1_miso */ + K2G_CORE_IOPAD(0x11b4) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* spi1_mosi.spi1_mosi */ + >; + }; + + qspi_pins: pinmux_qspi_pins { + pinctrl-single,pins = < + K2G_CORE_IOPAD(0x1204) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* qspi_clk.qspi_clk */ + K2G_CORE_IOPAD(0x1208) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* qspi_rclk.qspi_rclk */ + K2G_CORE_IOPAD(0x120c) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* qspi_d0.qspi_d0 */ + K2G_CORE_IOPAD(0x1210) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* qspi_d1.qspi_d1 */ + K2G_CORE_IOPAD(0x1214) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* qspi_d2.qspi_d2 */ + K2G_CORE_IOPAD(0x1218) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* qspi_d3.qspi_d3 */ + K2G_CORE_IOPAD(0x121c) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* qspi_csn0.qspi_csn0 */ + >; + }; + + uart2_pins: pinmux_uart2_pins { + pinctrl-single,pins = < + K2G_CORE_IOPAD(0x11ec) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* uart2_rxd.uart2_rxd */ + K2G_CORE_IOPAD(0x11f0) (BUFFER_CLASS_B | PIN_PULLDOWN | MUX_MODE0) /* uart2_txd.uart2_txd */ + >; + }; }; &uart0 { @@ -129,6 +138,7 @@ pinctrl-names = "default"; pinctrl-0 = <&mmc1_pins>; vmmc-supply = <&vcc3v3_dcin_reg>; /* VCC3V3_EMMC is connected to VCC3V3_DCIN */ + ti,non-removable; status = "okay"; }; @@ -205,3 +215,56 @@ }; }; }; + +&qspi { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&qspi_pins>; + cdns,rclk-en; + + flash0: m25p80@0 { + compatible = "s25fl512s", "jedec,spi-nor"; + reg = <0>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <4>; + spi-max-frequency = <96000000>; + #address-cells = <1>; + #size-cells = <1>; + cdns,read-delay = <5>; + cdns,tshsl-ns = <500>; + cdns,tsd2d-ns = <500>; + cdns,tchsh-ns = <119>; + cdns,tslch-ns = <119>; + + partition@0 { + label = "QSPI.u-boot-spl-os"; + reg = <0x00000000 0x00100000>; + }; + partition@1 { + label = "QSPI.u-boot-env"; + reg = <0x00100000 0x00040000>; + }; + partition@2 { + label = "QSPI.skern"; + reg = <0x00140000 0x0040000>; + }; + partition@3 { + label = "QSPI.pmmc-firmware"; + reg = <0x00180000 0x0040000>; + }; + partition@4 { + label = "QSPI.kernel"; + reg = <0x001C0000 0x0800000>; + }; + partition@5 { + label = "QSPI.file-system"; + reg = <0x009C0000 0x3640000>; + }; + }; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/keystone-k2g-ice.dts b/arch/arm/boot/dts/keystone-k2g-ice.dts index 78692745e0af..d820ed2474bb 100644 --- a/arch/arm/boot/dts/keystone-k2g-ice.dts +++ b/arch/arm/boot/dts/keystone-k2g-ice.dts @@ -1,9 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Device Tree Source for K2G Industrial Communication Engine EVM * * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ - * - * SPDX-License-Identifier: GPL-2.0 */ /dts-v1/; @@ -30,6 +29,191 @@ status = "okay"; }; }; + + vmain: fixedregulator-vmain { + compatible = "regulator-fixed"; + regulator-name = "vmain_fixed"; + regulator-min-microvolt = <24000000>; + regulator-max-microvolt = <24000000>; + regulator-always-on; + }; + + v5_0: fixedregulator-v5_0 { + /* TPS54531 */ + compatible = "regulator-fixed"; + regulator-name = "v5_0_fixed"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vmain>; + regulator-always-on; + }; + + vdd_3v3: fixedregulator-vdd_3v3 { + /* TLV62084 */ + compatible = "regulator-fixed"; + regulator-name = "vdd_3v3_fixed"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&v5_0>; + regulator-always-on; + }; + + vdd_1v8: fixedregulator-vdd_1v8 { + /* TLV62084 */ + compatible = "regulator-fixed"; + regulator-name = "vdd_1v8_fixed"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&v5_0>; + regulator-always-on; + }; + + vdds_ddr: fixedregulator-vdds_ddr { + /* TLV62080 */ + compatible = "regulator-fixed"; + regulator-name = "vdds_ddr_fixed"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + vin-supply = <&v5_0>; + regulator-always-on; + }; + + vref_ddr: fixedregulator-vref_ddr { + /* LP2996A */ + compatible = "regulator-fixed"; + regulator-name = "vref_ddr_fixed"; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <675000>; + vin-supply = <&vdd_3v3>; + regulator-always-on; + }; + + vtt_ddr: fixedregulator-vtt_ddr { + /* LP2996A */ + compatible = "regulator-fixed"; + regulator-name = "vtt_ddr_fixed"; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <675000>; + vin-supply = <&vdd_3v3>; + regulator-always-on; + }; + + vdd_0v9: fixedregulator-vdd_0v9 { + /* TPS62180 */ + compatible = "regulator-fixed"; + regulator-name = "vdd_0v9_fixed"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + vin-supply = <&v5_0>; + regulator-always-on; + }; + + vddb: fixedregulator-vddb { + /* TPS22945 */ + compatible = "regulator-fixed"; + regulator-name = "vddb_fixed"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&gpio1 53 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + gpio-decoder { + compatible = "gpio-decoder"; + gpios = <&pca9536 3 GPIO_ACTIVE_HIGH>, + <&pca9536 2 GPIO_ACTIVE_HIGH>, + <&pca9536 1 GPIO_ACTIVE_HIGH>, + <&pca9536 0 GPIO_ACTIVE_HIGH>; + linux,axis = <0>; /* ABS_X */ + decoder-max-value = <9>; + }; + + leds1 { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&user_leds>; + + led0 { + label = "status0:red:cpu0"; + gpios = <&gpio0 11 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "cpu0"; + }; + + led1 { + label = "status0:green:usr"; + gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led2 { + label = "status0:yellow:usr"; + gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led3 { + label = "status1:red:mmc0"; + gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "mmc0"; + }; + + led4 { + label = "status1:green:usr"; + gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led5 { + label = "status1:yellow:usr"; + gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led6 { + label = "status2:red:usr"; + gpios = <&gpio0 44 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led7 { + label = "status2:green:usr"; + gpios = <&gpio0 43 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led8 { + label = "status2:yellow:usr"; + gpios = <&gpio0 42 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led9 { + label = "status3:red:usr"; + gpios = <&gpio0 41 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led10 { + label = "status3:green:usr"; + gpios = <&gpio0 101 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led11 { + label = "status3:yellow:usr"; + gpios = <&gpio0 102 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led12 { + label = "status4:green:heartbeat"; + gpios = <&gpio0 19 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + }; }; &k2g_pinctrl { @@ -39,6 +223,64 @@ K2G_CORE_IOPAD(0x11d0) (BUFFER_CLASS_B | PIN_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */ >; }; + + qspi_pins: pinmux_qspi_pins { + pinctrl-single,pins = < + K2G_CORE_IOPAD(0x1204) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* qspi_clk.qspi_clk */ + K2G_CORE_IOPAD(0x1208) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* qspi_rclk.qspi_rclk */ + K2G_CORE_IOPAD(0x120c) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* qspi_d0.qspi_d0 */ + K2G_CORE_IOPAD(0x1210) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* qspi_d1.qspi_d1 */ + K2G_CORE_IOPAD(0x1214) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* qspi_d2.qspi_d2 */ + K2G_CORE_IOPAD(0x1218) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* qspi_d3.qspi_d3 */ + K2G_CORE_IOPAD(0x121c) (BUFFER_CLASS_B | PULL_DISABLE | MUX_MODE0) /* qspi_csn0.qspi_csn0 */ + >; + }; + + mmc1_pins: pinmux_mmc1_pins { + pinctrl-single,pins = < + K2G_CORE_IOPAD(0x10FC) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE0) /* mmc1_dat3.mmc1_dat3 */ + K2G_CORE_IOPAD(0x1100) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE0) /* mmc1_dat2.mmc1_dat2 */ + K2G_CORE_IOPAD(0x1104) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE0) /* mmc1_dat1.mmc1_dat1 */ + K2G_CORE_IOPAD(0x1108) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE0) /* mmc1_dat0.mmc1_dat0 */ + K2G_CORE_IOPAD(0x110C) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE0) /* mmc1_clk.mmc1_clk */ + K2G_CORE_IOPAD(0x1110) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE0) /* mmc1_cmd.mmc1_cmd */ + K2G_CORE_IOPAD(0x1114) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE3) /* mmc1_sdcd.gpio0_69 */ + K2G_CORE_IOPAD(0x1118) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE0) /* mmc1_sdwp.mmc1_sdwp */ + K2G_CORE_IOPAD(0x111C) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE0) /* mmc1_pow.mmc1_pow */ + >; + }; + + i2c0_pins: pinmux_i2c0_pins { + pinctrl-single,pins = < + K2G_CORE_IOPAD(0x137c) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE0) /* i2c0_scl.i2c0_scl */ + K2G_CORE_IOPAD(0x1380) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE0) /* i2c0_sda.i2c0_sda */ + >; + }; + + i2c1_pins: pinmux_i2c1_pins { + pinctrl-single,pins = < + K2G_CORE_IOPAD(0x1384) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE0) /* i2c1_scl.i2c1_scl */ + K2G_CORE_IOPAD(0x1388) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE0) /* i2c1_sda.i2c1_sda */ + >; + }; + + user_leds: pinmux_user_leds { + pinctrl-single,pins = < + K2G_CORE_IOPAD(0x102c) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE3) /* gpmc_ad11.gpio0_11 */ + K2G_CORE_IOPAD(0x1030) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE3) /* gpmc_ad12.gpio0_12 */ + K2G_CORE_IOPAD(0x1034) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE3) /* gpmc_ad13.gpio0_13 */ + K2G_CORE_IOPAD(0x1038) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE3) /* gpmc_ad14.gpio0_14 */ + K2G_CORE_IOPAD(0x103c) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE3) /* gpmc_ad15.gpio0_15 */ + K2G_CORE_IOPAD(0x1040) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE3) /* gpmc_clk.gpio0_16 */ + K2G_CORE_IOPAD(0x104c) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE3) /* gpmc_wen.gpio0_19 */ + K2G_CORE_IOPAD(0x10b0) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE3) /* dss_data9.gpio0_44 */ + K2G_CORE_IOPAD(0x10ac) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE3) /* dss_data10.gpio0_43 */ + K2G_CORE_IOPAD(0x10a8) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE3) /* dss_data11.gpio0_42 */ + K2G_CORE_IOPAD(0x10a4) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE3) /* dss_data12.gpio0_41 */ + K2G_CORE_IOPAD(0x11b8) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE3) /* spi2_scsn0.gpio0_101 */ + K2G_CORE_IOPAD(0x11bc) (BUFFER_CLASS_B | PIN_PULLUP | MUX_MODE3) /* spi2_scsn1.gpio0_102 */ + >; + }; }; &uart0 { @@ -51,3 +293,96 @@ memory-region = <&dsp_common_memory>; status = "okay"; }; + +&qspi { + pinctrl-names = "default"; + pinctrl-0 = <&qspi_pins>; + cdns,rclk-en; + status = "okay"; + + flash0: m25p80@0 { + compatible = "s25fl256s1", "jedec,spi-nor"; + reg = <0>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <4>; + spi-max-frequency = <96000000>; + #address-cells = <1>; + #size-cells = <1>; + cdns,read-delay = <5>; + cdns,tshsl-ns = <500>; + cdns,tsd2d-ns = <500>; + cdns,tchsh-ns = <119>; + cdns,tslch-ns = <119>; + + partition@0 { + label = "QSPI.u-boot"; + reg = <0x00000000 0x00100000>; + }; + partition@1 { + label = "QSPI.u-boot-env"; + reg = <0x00100000 0x00040000>; + }; + partition@2 { + label = "QSPI.skern"; + reg = <0x00140000 0x0040000>; + }; + partition@3 { + label = "QSPI.pmmc-firmware"; + reg = <0x00180000 0x0040000>; + }; + partition@4 { + label = "QSPI.kernel"; + reg = <0x001c0000 0x0800000>; + }; + partition@5 { + label = "QSPI.u-boot-spl-os"; + reg = <0x009c0000 0x0040000>; + }; + partition@6 { + label = "QSPI.file-system"; + reg = <0x00a00000 0x1600000>; + }; + }; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&mmc1 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc1_pins>; + vmmc-supply = <&vdd_3v3>; + cd-gpios = <&gpio0 69 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + status = "okay"; + + eeprom@50 { + compatible = "atmel,24c256"; + reg = <0x50>; + }; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + status = "okay"; + clock-frequency = <400000>; + + pca9536: gpio@41 { + compatible = "ti,pca9536"; + reg = <0x41>; + gpio-controller; + #gpio-cells = <2>; + vcc-supply = <&vdd_3v3>; + }; +}; diff --git a/arch/arm/boot/dts/keystone-k2g.dtsi b/arch/arm/boot/dts/keystone-k2g.dtsi index 8f313ff406b9..fd061718dc0a 100644 --- a/arch/arm/boot/dts/keystone-k2g.dtsi +++ b/arch/arm/boot/dts/keystone-k2g.dtsi @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Device Tree Source for K2G SOC * - * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.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 "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/ */ #include @@ -28,6 +20,8 @@ aliases { serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; @@ -75,7 +69,7 @@ interrupts = ; }; - soc { + soc0: soc@0 { #address-cells = <1>; #size-cells = <1>; #pinctrl-cells = <1>; @@ -114,7 +108,32 @@ reg-io-width = <4>; reg = <0x02530c00 0x100>; interrupts = ; - clock-frequency = <200000000>; + clocks = <&k2g_clks 0x2c 0>; + power-domains = <&k2g_pds 0x2c>; + status = "disabled"; + }; + + uart1: serial@02531000 { + compatible = "ti,da830-uart", "ns16550a"; + current-speed = <115200>; + reg-shift = <2>; + reg-io-width = <4>; + reg = <0x02531000 0x100>; + interrupts = ; + clocks = <&k2g_clks 0x2d 0>; + power-domains = <&k2g_pds 0x2d>; + status = "disabled"; + }; + + uart2: serial@02531400 { + compatible = "ti,da830-uart", "ns16550a"; + current-speed = <115200>; + reg-shift = <2>; + reg-io-width = <4>; + reg = <0x02531400 0x100>; + interrupts = ; + clocks = <&k2g_clks 0x2e 0>; + power-domains = <&k2g_pds 0x2e>; status = "disabled"; }; @@ -372,11 +391,24 @@ dma-names = "tx", "rx"; bus-width = <8>; ti,needs-special-reset; - ti,non-removable; max-frequency = <96000000>; power-domains = <&k2g_pds 0xc>; clocks = <&k2g_clks 0xc 1>, <&k2g_clks 0xc 2>; clock-names = "fck", "mmchsdb_fck"; + }; + + qspi: qspi@2940000 { + compatible = "ti,k2g-qspi", "cdns,qspi-nor"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x02940000 0x1000>, + <0x24000000 0x4000000>; + interrupts = ; + cdns,fifo-depth = <256>; + cdns,fifo-width = <4>; + cdns,trigger-address = <0x24000000>; + clocks = <&k2g_clks 0x43 0x0>; + power-domains = <&k2g_pds 0x43>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/keystone-k2hk-clocks.dtsi b/arch/arm/boot/dts/keystone-k2hk-clocks.dtsi index af9b7190533a..4ba6912176ef 100644 --- a/arch/arm/boot/dts/keystone-k2hk-clocks.dtsi +++ b/arch/arm/boot/dts/keystone-k2hk-clocks.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2013-2014 Texas Instruments, Inc. - * * Keystone 2 Kepler/Hawking SoC clock nodes * - * 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. + * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/ */ clocks { @@ -53,7 +50,7 @@ clocks { reg-names = "control"; }; - clktsip: clktsip { + clktsip: clktsip@2350000 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk16>; @@ -63,7 +60,7 @@ clocks { domain-id = <0>; }; - clksrio: clksrio { + clksrio: clksrio@235002c { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk1rstiso13>; @@ -73,7 +70,7 @@ clocks { domain-id = <4>; }; - clkhyperlink0: clkhyperlink0 { + clkhyperlink0: clkhyperlink0@2350030 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk12>; @@ -83,7 +80,7 @@ clocks { domain-id = <5>; }; - clkgem1: clkgem1 { + clkgem1: clkgem1@2350040 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk1>; @@ -93,7 +90,7 @@ clocks { domain-id = <9>; }; - clkgem2: clkgem2 { + clkgem2: clkgem2@2350044 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk1>; @@ -103,7 +100,7 @@ clocks { domain-id = <10>; }; - clkgem3: clkgem3 { + clkgem3: clkgem3@2350048 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk1>; @@ -113,7 +110,7 @@ clocks { domain-id = <11>; }; - clkgem4: clkgem4 { + clkgem4: clkgem4@235004c { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk1>; @@ -123,7 +120,7 @@ clocks { domain-id = <12>; }; - clkgem5: clkgem5 { + clkgem5: clkgem5@2350050 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk1>; @@ -133,7 +130,7 @@ clocks { domain-id = <13>; }; - clkgem6: clkgem6 { + clkgem6: clkgem6@2350054 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk1>; @@ -143,7 +140,7 @@ clocks { domain-id = <14>; }; - clkgem7: clkgem7 { + clkgem7: clkgem7@2350058 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk1>; @@ -153,7 +150,7 @@ clocks { domain-id = <15>; }; - clkddr31: clkddr31 { + clkddr31: clkddr31@2350060 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -163,7 +160,7 @@ clocks { domain-id = <16>; }; - clktac: clktac { + clktac: clktac@2350064 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -173,7 +170,7 @@ clocks { domain-id = <17>; }; - clkrac01: clkrac01 { + clkrac01: clkrac01@2350068 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -183,7 +180,7 @@ clocks { domain-id = <17>; }; - clkrac23: clkrac23 { + clkrac23: clkrac23@235006c { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -193,7 +190,7 @@ clocks { domain-id = <18>; }; - clkfftc0: clkfftc0 { + clkfftc0: clkfftc0@2350070 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -203,7 +200,7 @@ clocks { domain-id = <19>; }; - clkfftc1: clkfftc1 { + clkfftc1: clkfftc1@2350074 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -213,7 +210,7 @@ clocks { domain-id = <19>; }; - clkfftc2: clkfftc2 { + clkfftc2: clkfftc2@2350078 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -223,7 +220,7 @@ clocks { domain-id = <20>; }; - clkfftc3: clkfftc3 { + clkfftc3: clkfftc3@235007c { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -233,7 +230,7 @@ clocks { domain-id = <20>; }; - clkfftc4: clkfftc4 { + clkfftc4: clkfftc4@2350080 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -243,7 +240,7 @@ clocks { domain-id = <20>; }; - clkfftc5: clkfftc5 { + clkfftc5: clkfftc5@2350084 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -253,7 +250,7 @@ clocks { domain-id = <20>; }; - clkaif: clkaif { + clkaif: clkaif@2350088 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -263,7 +260,7 @@ clocks { domain-id = <21>; }; - clktcp3d0: clktcp3d0 { + clktcp3d0: clktcp3d0@235008c { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -273,7 +270,7 @@ clocks { domain-id = <22>; }; - clktcp3d1: clktcp3d1 { + clktcp3d1: clktcp3d1@2350090 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -283,7 +280,7 @@ clocks { domain-id = <22>; }; - clktcp3d2: clktcp3d2 { + clktcp3d2: clktcp3d2@2350094 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -293,7 +290,7 @@ clocks { domain-id = <23>; }; - clktcp3d3: clktcp3d3 { + clktcp3d3: clktcp3d3@2350098 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -303,7 +300,7 @@ clocks { domain-id = <23>; }; - clkvcp0: clkvcp0 { + clkvcp0: clkvcp0@235009c { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -313,7 +310,7 @@ clocks { domain-id = <24>; }; - clkvcp1: clkvcp1 { + clkvcp1: clkvcp1@23500a0 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -323,7 +320,7 @@ clocks { domain-id = <24>; }; - clkvcp2: clkvcp2 { + clkvcp2: clkvcp2@23500a4 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -333,7 +330,7 @@ clocks { domain-id = <24>; }; - clkvcp3: clkvcp3 { + clkvcp3: clkvcp3@23500a8 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -343,7 +340,7 @@ clocks { domain-id = <24>; }; - clkvcp4: clkvcp4 { + clkvcp4: clkvcp4@23500ac { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -353,7 +350,7 @@ clocks { domain-id = <25>; }; - clkvcp5: clkvcp5 { + clkvcp5: clkvcp5@23500b0 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -363,7 +360,7 @@ clocks { domain-id = <25>; }; - clkvcp6: clkvcp6 { + clkvcp6: clkvcp6@23500b4 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -373,7 +370,7 @@ clocks { domain-id = <25>; }; - clkvcp7: clkvcp7 { + clkvcp7: clkvcp7@23500b8 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -383,7 +380,7 @@ clocks { domain-id = <25>; }; - clkbcp: clkbcp { + clkbcp: clkbcp@23500bc { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -393,7 +390,7 @@ clocks { domain-id = <26>; }; - clkdxb: clkdxb { + clkdxb: clkdxb@23500c0 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -403,7 +400,7 @@ clocks { domain-id = <27>; }; - clkhyperlink1: clkhyperlink1 { + clkhyperlink1: clkhyperlink1@23500c4 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk12>; @@ -413,7 +410,7 @@ clocks { domain-id = <28>; }; - clkxge: clkxge { + clkxge: clkxge@23500c8 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; diff --git a/arch/arm/boot/dts/keystone-k2hk-evm.dts b/arch/arm/boot/dts/keystone-k2hk-evm.dts index 6dd13b98aaba..ad4e22afe133 100644 --- a/arch/arm/boot/dts/keystone-k2hk-evm.dts +++ b/arch/arm/boot/dts/keystone-k2hk-evm.dts @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2013-2014 Texas Instruments, Inc. - * * Keystone 2 Kepler/Hawking EVM device tree * - * 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. + * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/ */ /dts-v1/; @@ -29,7 +26,31 @@ }; }; - soc { + leds { + compatible = "gpio-leds"; + debug1_1 { + label = "keystone:green:debug1"; + gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; /* 12 */ + }; + + debug1_2 { + label = "keystone:red:debug1"; + gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>; /* 13 */ + }; + + debug2 { + label = "keystone:blue:debug2"; + gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; /* 14 */ + }; + + debug3 { + label = "keystone:blue:debug3"; + gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; /* 15 */ + }; + }; +}; + +&soc0 { clocks { refclksys: refclksys { #clock-cells = <0>; @@ -66,30 +87,6 @@ clock-output-names = "refclk-ddr3b"; }; }; - }; - - leds { - compatible = "gpio-leds"; - debug1_1 { - label = "keystone:green:debug1"; - gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; /* 12 */ - }; - - debug1_2 { - label = "keystone:red:debug1"; - gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>; /* 13 */ - }; - - debug2 { - label = "keystone:blue:debug2"; - gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; /* 14 */ - }; - - debug3 { - label = "keystone:blue:debug3"; - gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; /* 15 */ - }; - }; }; &usb_phy { @@ -158,7 +155,7 @@ &i2c0 { dtt@50 { - compatible = "at,24c1024"; + compatible = "atmel,24c1024"; reg = <0x50>; }; }; diff --git a/arch/arm/boot/dts/keystone-k2hk-netcp.dtsi b/arch/arm/boot/dts/keystone-k2hk-netcp.dtsi index a5ac845464bf..b88c0689c285 100644 --- a/arch/arm/boot/dts/keystone-k2hk-netcp.dtsi +++ b/arch/arm/boot/dts/keystone-k2hk-netcp.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Device Tree Source for Keystone 2 Hawking Netcp driver * - * Copyright 2015 Texas Instruments, Inc. - * - * 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. + * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/ */ qmss: qmss@2a40000 { diff --git a/arch/arm/boot/dts/keystone-k2hk.dtsi b/arch/arm/boot/dts/keystone-k2hk.dtsi index 7c486d9dc90e..ed59474522cb 100644 --- a/arch/arm/boot/dts/keystone-k2hk.dtsi +++ b/arch/arm/boot/dts/keystone-k2hk.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2013-2014 Texas Instruments, Inc. - * * Keystone 2 Kepler/Hawking soc specific device tree * - * 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. + * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/ */ #include @@ -55,8 +52,9 @@ rproc6 = &dsp6; rproc7 = &dsp7; }; +}; - soc { +&soc0 { /include/ "keystone-k2hk-clocks.dtsi" msm_ram: msmram@c000000 { @@ -284,5 +282,4 @@ bus_freq = <2500000>; }; /include/ "keystone-k2hk-netcp.dtsi" - }; }; diff --git a/arch/arm/boot/dts/keystone-k2l-clocks.dtsi b/arch/arm/boot/dts/keystone-k2l-clocks.dtsi index ef8464bb11ff..635528064dea 100644 --- a/arch/arm/boot/dts/keystone-k2l-clocks.dtsi +++ b/arch/arm/boot/dts/keystone-k2l-clocks.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2013-2014 Texas Instruments, Inc. - * * Keystone 2 lamarr SoC clock nodes * - * 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. + * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/ */ clocks { @@ -44,7 +41,7 @@ clocks { reg-names = "control"; }; - clkdfeiqnsys: clkdfeiqnsys { + clkdfeiqnsys: clkdfeiqnsys@2350004 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk12>; @@ -54,7 +51,7 @@ clocks { domain-id = <0>; }; - clkpcie1: clkpcie1 { + clkpcie1: clkpcie1@235002c { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk12>; @@ -64,7 +61,7 @@ clocks { domain-id = <4>; }; - clkgem1: clkgem1 { + clkgem1: clkgem1@2350040 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk1>; @@ -74,7 +71,7 @@ clocks { domain-id = <9>; }; - clkgem2: clkgem2 { + clkgem2: clkgem2@2350044 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk1>; @@ -84,7 +81,7 @@ clocks { domain-id = <10>; }; - clkgem3: clkgem3 { + clkgem3: clkgem3@2350048 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk1>; @@ -94,7 +91,7 @@ clocks { domain-id = <11>; }; - clktac: clktac { + clktac: clktac@2350064 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -104,7 +101,7 @@ clocks { domain-id = <17>; }; - clkrac: clkrac { + clkrac: clkrac@2350068 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -114,7 +111,7 @@ clocks { domain-id = <17>; }; - clkdfepd0: clkdfepd0 { + clkdfepd0: clkdfepd0@235006c { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -124,7 +121,7 @@ clocks { domain-id = <18>; }; - clkfftc0: clkfftc0 { + clkfftc0: clkfftc0@2350070 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -134,7 +131,7 @@ clocks { domain-id = <19>; }; - clkosr: clkosr { + clkosr: clkosr@2350088 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -144,7 +141,7 @@ clocks { domain-id = <21>; }; - clktcp3d0: clktcp3d0 { + clktcp3d0: clktcp3d0@235008c { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -154,7 +151,7 @@ clocks { domain-id = <22>; }; - clktcp3d1: clktcp3d1 { + clktcp3d1: clktcp3d1@2350094 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -164,7 +161,7 @@ clocks { domain-id = <23>; }; - clkvcp0: clkvcp0 { + clkvcp0: clkvcp0@235009c { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -174,7 +171,7 @@ clocks { domain-id = <24>; }; - clkvcp1: clkvcp1 { + clkvcp1: clkvcp1@23500a0 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -184,7 +181,7 @@ clocks { domain-id = <24>; }; - clkvcp2: clkvcp2 { + clkvcp2: clkvcp2@23500a4 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -194,7 +191,7 @@ clocks { domain-id = <24>; }; - clkvcp3: clkvcp3 { + clkvcp3: clkvcp3@23500a8 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -204,7 +201,7 @@ clocks { domain-id = <24>; }; - clkbcp: clkbcp { + clkbcp: clkbcp@23500bc { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -214,7 +211,7 @@ clocks { domain-id = <26>; }; - clkdfepd1: clkdfepd1 { + clkdfepd1: clkdfepd1@23500c0 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -224,7 +221,7 @@ clocks { domain-id = <27>; }; - clkfftc1: clkfftc1 { + clkfftc1: clkfftc1@23500c4 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -234,7 +231,7 @@ clocks { domain-id = <28>; }; - clkiqnail: clkiqnail { + clkiqnail: clkiqnail@23500c8 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk13>; @@ -244,7 +241,7 @@ clocks { domain-id = <29>; }; - clkuart2: clkuart2 { + clkuart2: clkuart2@2350000 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&clkmodrst0>; @@ -254,7 +251,7 @@ clocks { domain-id = <0>; }; - clkuart3: clkuart3 { + clkuart3: clkuart3@2350000 { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&clkmodrst0>; diff --git a/arch/arm/boot/dts/keystone-k2l-evm.dts b/arch/arm/boot/dts/keystone-k2l-evm.dts index 528667618db4..e200533d26a4 100644 --- a/arch/arm/boot/dts/keystone-k2l-evm.dts +++ b/arch/arm/boot/dts/keystone-k2l-evm.dts @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2014 Texas Instruments, Inc. - * * Keystone 2 Lamarr EVM device tree * - * 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. + * Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/ */ /dts-v1/; @@ -28,8 +25,9 @@ status = "okay"; }; }; +}; - soc { +&soc0 { clocks { refclksys: refclksys { #clock-cells = <0>; @@ -38,7 +36,6 @@ clock-output-names = "refclk-sys"; }; }; - }; }; &usb_phy { @@ -55,7 +52,7 @@ &i2c0 { dtt@50 { - compatible = "at,24c1024"; + compatible = "atmel,24c1024"; reg = <0x50>; }; }; diff --git a/arch/arm/boot/dts/keystone-k2l-netcp.dtsi b/arch/arm/boot/dts/keystone-k2l-netcp.dtsi index 66f615a74118..9ec84228bc16 100644 --- a/arch/arm/boot/dts/keystone-k2l-netcp.dtsi +++ b/arch/arm/boot/dts/keystone-k2l-netcp.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Device Tree Source for Keystone 2 Lamarr Netcp driver * - * Copyright 2015 Texas Instruments, Inc. - * - * 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. + * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/ */ qmss: qmss@2a40000 { diff --git a/arch/arm/boot/dts/keystone-k2l.dtsi b/arch/arm/boot/dts/keystone-k2l.dtsi index 4370e6513aa4..b61a830f4a4d 100644 --- a/arch/arm/boot/dts/keystone-k2l.dtsi +++ b/arch/arm/boot/dts/keystone-k2l.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2014 Texas Instruments, Inc. - * * Keystone 2 Lamarr SoC specific device tree * - * 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. + * Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/ */ #include @@ -39,8 +36,9 @@ rproc2 = &dsp2; rproc3 = &dsp3; }; +}; - soc { +&soc0 { /include/ "keystone-k2l-clocks.dtsi" uart2: serial@2348400 { @@ -63,6 +61,50 @@ interrupts = ; }; + gpio1: gpio@2348000 { + compatible = "ti,keystone-gpio"; + reg = <0x02348000 0x100>; + gpio-controller; + #gpio-cells = <2>; + /* HW Interrupts mapped to GPIO pins */ + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + clocks = <&clkgpio>; + clock-names = "gpio"; + ti,ngpio = <32>; + ti,davinci-gpio-unbanked = <32>; + }; + k2l_pmx: pinmux@2620690 { compatible = "pinctrl-single"; reg = <0x02620690 0xc>; @@ -350,7 +392,6 @@ bus_freq = <2500000>; }; /include/ "keystone-k2l-netcp.dtsi" - }; }; &spi0 { diff --git a/arch/arm/boot/dts/keystone.dtsi b/arch/arm/boot/dts/keystone.dtsi index 06e10544f9b1..93ea5c69ea77 100644 --- a/arch/arm/boot/dts/keystone.dtsi +++ b/arch/arm/boot/dts/keystone.dtsi @@ -1,16 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2013 Texas Instruments, Inc. - * - * 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. + * Copyright (C) 2013-2017 Texas Instruments Incorporated - http://www.ti.com/ */ #include #include -#include "skeleton.dtsi" - / { compatible = "ti,keystone"; model = "Texas Instruments Keystone 2 SoC"; @@ -25,11 +20,14 @@ spi2 = &spi2; }; - memory { + chosen { }; + + memory: memory@80000000 { + device_type = "memory"; reg = <0x00000000 0x80000000 0x00000000 0x40000000>; }; - gic: interrupt-controller { + gic: interrupt-controller@2561000 { compatible = "arm,gic-400", "arm,cortex-a15-gic"; #interrupt-cells = <3>; interrupt-controller; @@ -70,7 +68,7 @@ cpu_on = <0x84000003>; }; - soc { + soc0: soc@0 { #address-cells = <1>; #size-cells = <1>; compatible = "ti,keystone","simple-bus"; diff --git a/arch/arm/boot/dts/kirkwood-linksys-viper.dts b/arch/arm/boot/dts/kirkwood-linksys-viper.dts index df7851820507..f21a50dd9869 100644 --- a/arch/arm/boot/dts/kirkwood-linksys-viper.dts +++ b/arch/arm/boot/dts/kirkwood-linksys-viper.dts @@ -157,7 +157,7 @@ reg = <0x80000 0x20000>; }; - partition@A0000 { + partition@a0000 { label = "s_env"; reg = <0xA0000 0x20000>; }; @@ -167,17 +167,17 @@ reg = <0x200000 0x2A0000>; }; - partition@4A0000 { + partition@4a0000 { label = "rootfs"; reg = <0x4A0000 0x1760000>; }; - partition@1C00000 { + partition@1c00000 { label = "alt_kernel"; reg = <0x1C00000 0x2A0000>; }; - partition@1EA0000 { + partition@1ea0000 { label = "alt_rootfs"; reg = <0x1EA0000 0x1760000>; }; @@ -187,7 +187,7 @@ reg = <0x3600000 0x4A00000>; }; - partition@C0000 { + partition@c0000 { label = "unused"; reg = <0xC0000 0x140000>; }; diff --git a/arch/arm/boot/dts/kirkwood-openblocks_a7.dts b/arch/arm/boot/dts/kirkwood-openblocks_a7.dts index cf2f5240e176..27cc913ca0f5 100644 --- a/arch/arm/boot/dts/kirkwood-openblocks_a7.dts +++ b/arch/arm/boot/dts/kirkwood-openblocks_a7.dts @@ -53,7 +53,8 @@ }; pinctrl: pin-controller@10000 { - pinctrl-0 = <&pmx_dip_switches &pmx_gpio_header>; + pinctrl-0 = <&pmx_dip_switches &pmx_gpio_header + &pmx_gpio_header_gpo>; pinctrl-names = "default"; pmx_uart0: pmx-uart0 { @@ -85,11 +86,16 @@ * ground. */ pmx_gpio_header: pmx-gpio-header { - marvell,pins = "mpp17", "mpp7", "mpp29", "mpp28", + marvell,pins = "mpp17", "mpp29", "mpp28", "mpp35", "mpp34", "mpp40"; marvell,function = "gpio"; }; + pmx_gpio_header_gpo: pxm-gpio-header-gpo { + marvell,pins = "mpp7"; + marvell,function = "gpo"; + }; + pmx_gpio_init: pmx-init { marvell,pins = "mpp38"; marvell,function = "gpio"; diff --git a/arch/arm/boot/dts/logicpd-som-lv-35xx-devkit.dts b/arch/arm/boot/dts/logicpd-som-lv-35xx-devkit.dts new file mode 100644 index 000000000000..32d0dc371fc3 --- /dev/null +++ b/arch/arm/boot/dts/logicpd-som-lv-35xx-devkit.dts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +/dts-v1/; + +#include "omap34xx.dtsi" +#include "logicpd-som-lv.dtsi" +#include "logicpd-som-lv-baseboard.dtsi" +#include "omap-gpmc-smsc9221.dtsi" + +/ { + model = "LogicPD Zoom OMAP35xx SOM-LV Development Kit"; + compatible = "logicpd,dm3730-som-lv-devkit", "ti,omap3"; +}; diff --git a/arch/arm/boot/dts/logicpd-som-lv-37xx-devkit.dts b/arch/arm/boot/dts/logicpd-som-lv-37xx-devkit.dts index 2fa5eb4bd402..24283739526c 100644 --- a/arch/arm/boot/dts/logicpd-som-lv-37xx-devkit.dts +++ b/arch/arm/boot/dts/logicpd-som-lv-37xx-devkit.dts @@ -8,257 +8,10 @@ #include "omap36xx.dtsi" #include "logicpd-som-lv.dtsi" +#include "logicpd-som-lv-baseboard.dtsi" #include "omap-gpmc-smsc9221.dtsi" / { model = "LogicPD Zoom DM3730 SOM-LV Development Kit"; compatible = "logicpd,dm3730-som-lv-devkit", "ti,omap3630", "ti,omap3"; - - gpio_keys { - compatible = "gpio-keys"; - pinctrl-names = "default"; - pinctrl-0 = <&gpio_key_pins>; - - sysboot2 { - label = "gpio3"; - gpios = <&gpio4 15 GPIO_ACTIVE_LOW>; /* gpio_111 / uP_GPIO_3 */ - linux,code = ; - wakeup-source; - }; - }; - - sound { - compatible = "ti,omap-twl4030"; - ti,model = "omap3logic"; - ti,mcbsp = <&mcbsp2>; - }; - - leds { - compatible = "gpio-leds"; - pinctrl-names = "default"; - pinctrl-0 = <&led_pins &led_pins_wkup>; - - led1 { - label = "led1"; - gpios = <&gpio5 5 GPIO_ACTIVE_LOW>; /* gpio133 */ - linux,default-trigger = "cpu0"; - }; - - led2 { - label = "led2"; - gpios = <&gpio1 11 GPIO_ACTIVE_LOW>; /* gpio11 */ - linux,default-trigger = "none"; - }; - }; -}; - -&vaux1 { - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3000000>; -}; - -&vaux4 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; -}; - -&mcbsp2 { - status = "okay"; -}; - -&charger { - ti,bb-uvolt = <3200000>; - ti,bb-uamp = <150>; -}; - -&gpmc { - ranges = <0 0 0x30000000 0x1000000 /* CS0: 16MB for NAND */ - 1 0 0x2c000000 0x1000000>; /* CS1: 16MB for LAN9221 */ - - ethernet@gpmc { - pinctrl-names = "default"; - pinctrl-0 = <&lan9221_pins>; - interrupt-parent = <&gpio5>; - interrupts = <24 IRQ_TYPE_LEVEL_LOW>; /* gpio_152 */ - reg = <1 0 0xff>; - }; -}; - -&vpll2 { - regulator-always-on; -}; - -&dss { - status = "ok"; - vdds_dsi-supply = <&vpll2>; - vdda_video-supply = <&video_reg>; - pinctrl-names = "default"; - pinctrl-0 = <&dss_dpi_pins1>; - port { - dpi_out: endpoint { - remote-endpoint = <&lcd_in>; - data-lines = <16>; - }; - }; -}; - -/ { - aliases { - display0 = &lcd0; - }; - - video_reg: video_reg { - compatible = "regulator-fixed"; - regulator-name = "fixed-supply"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - }; - - lcd0: display@0 { - compatible = "panel-dpi"; - label = "28"; - status = "okay"; - /* default-on; */ - pinctrl-names = "default"; - pinctrl-0 = <&lcd_enable_pin>; - enable-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>; /* gpio155, lcd INI */ - port { - lcd_in: endpoint { - remote-endpoint = <&dpi_out>; - }; - }; - - panel-timing { - clock-frequency = <9000000>; - hactive = <480>; - vactive = <272>; - hfront-porch = <3>; - hback-porch = <2>; - hsync-len = <42>; - vback-porch = <3>; - vfront-porch = <2>; - vsync-len = <11>; - hsync-active = <1>; - vsync-active = <1>; - de-active = <1>; - pixelclk-active = <0>; - }; - }; - - bl: backlight { - compatible = "pwm-backlight"; - pinctrl-names = "default"; - pinctrl-0 = <&backlight_pins>; - pwms = <&twl_pwm 0 5000000>; - brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>; - default-brightness-level = <7>; - enable-gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>; /* gpio_8 */ - }; -}; - -&mmc1 { - interrupts-extended = <&intc 83 &omap3_pmx_core 0x11a>; - pinctrl-names = "default"; - pinctrl-0 = <&mmc1_pins>; - wp-gpios = <&gpio4 30 GPIO_ACTIVE_HIGH>; /* gpio_126 */ - cd-gpios = <&gpio4 14 IRQ_TYPE_LEVEL_LOW>; /* gpio_110 */ - vmmc-supply = <&vmmc1>; - bus-width = <4>; - cap-power-off-card; -}; - -&omap3_pmx_core { - gpio_key_pins: pinmux_gpio_key_pins { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x212e, PIN_INPUT_PULLUP | MUX_MODE4) /* cam_xclkb.gpio_111 / uP_GPIO_3*/ - >; - }; - - led_pins: pinmux_led_pins { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x215e, PIN_OUTPUT_PULLUP | MUX_MODE4) /* sdmmc2_dat1.gpio_133 / uP_GPIO_0 */ - >; - }; - - lan9221_pins: pinmux_lan9221_pins { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x2184, PIN_INPUT_PULLUP | MUX_MODE4) /* mcbsp4_clkx.gpio_152 */ - >; - }; - - mmc1_pins: pinmux_mmc1_pins { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x2144, PIN_OUTPUT | MUX_MODE0) /* sdmmc1_clk.sdmmc1_clk */ - OMAP3_CORE1_IOPAD(0x2146, PIN_INPUT | MUX_MODE0) /* sdmmc1_cmd.sdmmc1_cmd */ - OMAP3_CORE1_IOPAD(0x2148, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat0.sdmmc1_dat0 */ - OMAP3_CORE1_IOPAD(0x214a, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat1.sdmmc1_dat1 */ - OMAP3_CORE1_IOPAD(0x214c, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat2.sdmmc1_dat2 */ - OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */ - OMAP3_CORE1_IOPAD(0x2132, PIN_INPUT_PULLUP | MUX_MODE4) /* cam_strobe.gpio_126 */ - OMAP3_CORE1_IOPAD(0x212c, PIN_INPUT_PULLUP | MUX_MODE4) /* cam_d11.gpio_110 */ - >; - }; - - lcd_enable_pin: pinmux_lcd_enable_pin { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x218a, PIN_OUTPUT | PIN_OFF_OUTPUT_LOW | MUX_MODE4) /* mcbsp4_fs.gpio_155 */ - >; - }; - - dss_dpi_pins1: pinmux_dss_dpi_pins1 { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x20d4, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_pclk.dss_pclk */ - OMAP3_CORE1_IOPAD(0x20d6, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_hsync.dss_hsync */ - OMAP3_CORE1_IOPAD(0x20d8, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_vsync.dss_vsync */ - OMAP3_CORE1_IOPAD(0x20da, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_acbias.dss_acbias */ - - OMAP3_CORE1_IOPAD(0x20dc, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data0.dss_data0 */ - OMAP3_CORE1_IOPAD(0x20de, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data1.dss_data1 */ - OMAP3_CORE1_IOPAD(0x20e0, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data2.dss_data2 */ - OMAP3_CORE1_IOPAD(0x20e2, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data3.dss_data3 */ - OMAP3_CORE1_IOPAD(0x20e4, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data4.dss_data4 */ - OMAP3_CORE1_IOPAD(0x20e6, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data5.dss_data5 */ - OMAP3_CORE1_IOPAD(0x20e8, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data6.dss_data6 */ - OMAP3_CORE1_IOPAD(0x20ea, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data7.dss_data7 */ - OMAP3_CORE1_IOPAD(0x20ec, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data8.dss_data8 */ - OMAP3_CORE1_IOPAD(0x20ee, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data9.dss_data9 */ - OMAP3_CORE1_IOPAD(0x20f0, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data10.dss_data10 */ - OMAP3_CORE1_IOPAD(0x20f2, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data11.dss_data11 */ - OMAP3_CORE1_IOPAD(0x20f4, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data12.dss_data12 */ - OMAP3_CORE1_IOPAD(0x20f6, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data13.dss_data13 */ - OMAP3_CORE1_IOPAD(0x20f8, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data14.dss_data14 */ - OMAP3_CORE1_IOPAD(0x20fa, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data15.dss_data15 */ - >; - }; -}; - -&omap3_pmx_wkup { - led_pins_wkup: pinmux_led_pins_wkup { - pinctrl-single,pins = < - OMAP3_WKUP_IOPAD(0x2a24, PIN_OUTPUT_PULLUP | MUX_MODE4) /* jtag_emu0.gpio_11 / uP_GPIO_1 */ - >; - }; - - backlight_pins: pinmux_backlight_pins { - pinctrl-single,pins = < - OMAP3_WKUP_IOPAD(0x2a16, PIN_OUTPUT | PIN_OFF_OUTPUT_LOW | MUX_MODE4) /* sys_boot6.gpio_8 */ - >; - }; -}; - - -&uart1 { - interrupts-extended = <&intc 72 &omap3_pmx_core OMAP3_UART1_RX>; -}; - -/* Wired to the tps65950 on the SOM, only the USB connector is on the devkit */ -&usb_otg_hs { - pinctrl-names = "default"; - pinctrl-0 = <&hsusb_otg_pins>; - interface-type = <0>; - usb-phy = <&usb2_phy>; - phys = <&usb2_phy>; - phy-names = "usb2-phy"; - mode = <3>; - power = <50>; }; diff --git a/arch/arm/boot/dts/logicpd-som-lv-baseboard.dtsi b/arch/arm/boot/dts/logicpd-som-lv-baseboard.dtsi new file mode 100644 index 000000000000..4990ed90dcea --- /dev/null +++ b/arch/arm/boot/dts/logicpd-som-lv-baseboard.dtsi @@ -0,0 +1,256 @@ +/* + * 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. + */ + +/ { + gpio_keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&gpio_key_pins>; + + sysboot2 { + label = "gpio3"; + gpios = <&gpio4 15 GPIO_ACTIVE_LOW>; /* gpio_111 / uP_GPIO_3 */ + linux,code = ; + wakeup-source; + }; + }; + + sound { + compatible = "ti,omap-twl4030"; + ti,model = "omap3logic"; + ti,mcbsp = <&mcbsp2>; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pins &led_pins_wkup>; + + led1 { + label = "led1"; + gpios = <&gpio5 5 GPIO_ACTIVE_LOW>; /* gpio133 */ + linux,default-trigger = "cpu0"; + }; + + led2 { + label = "led2"; + gpios = <&gpio1 11 GPIO_ACTIVE_LOW>; /* gpio11 */ + linux,default-trigger = "none"; + }; + }; +}; + +&vaux1 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; +}; + +&vaux4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; +}; + +&mcbsp2 { + status = "okay"; +}; + +&charger { + ti,bb-uvolt = <3200000>; + ti,bb-uamp = <150>; +}; + +&gpmc { + ranges = <0 0 0x30000000 0x1000000 /* CS0: 16MB for NAND */ + 1 0 0x2c000000 0x1000000 /* CS1: 16MB for LAN9221 */ + 2 0 0x10000000 0x2000000>; /* CS2: 32MB for NOR */ + + ethernet@gpmc { + pinctrl-names = "default"; + pinctrl-0 = <&lan9221_pins>; + interrupt-parent = <&gpio5>; + interrupts = <24 IRQ_TYPE_LEVEL_LOW>; /* gpio_152 */ + reg = <1 0 0xff>; + }; +}; + +&vpll2 { + regulator-always-on; +}; + +&dss { + status = "ok"; + vdds_dsi-supply = <&vpll2>; + vdda_video-supply = <&video_reg>; + pinctrl-names = "default"; + pinctrl-0 = <&dss_dpi_pins1>; + port { + dpi_out: endpoint { + remote-endpoint = <&lcd_in>; + data-lines = <16>; + }; + }; +}; + +/ { + aliases { + display0 = &lcd0; + }; + + video_reg: video_reg { + compatible = "regulator-fixed"; + regulator-name = "fixed-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + lcd0: display@0 { + compatible = "panel-dpi"; + label = "28"; + status = "okay"; + /* default-on; */ + pinctrl-names = "default"; + pinctrl-0 = <&lcd_enable_pin>; + enable-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>; /* gpio155, lcd INI */ + port { + lcd_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + + panel-timing { + clock-frequency = <9000000>; + hactive = <480>; + vactive = <272>; + hfront-porch = <3>; + hback-porch = <2>; + hsync-len = <42>; + vback-porch = <3>; + vfront-porch = <2>; + vsync-len = <11>; + hsync-active = <1>; + vsync-active = <1>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; + + bl: backlight { + compatible = "pwm-backlight"; + pinctrl-names = "default"; + pinctrl-0 = <&backlight_pins>; + pwms = <&twl_pwm 0 5000000>; + brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>; + default-brightness-level = <7>; + enable-gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>; /* gpio_8 */ + }; +}; + +&mmc1 { + interrupts-extended = <&intc 83 &omap3_pmx_core 0x11a>; + pinctrl-names = "default"; + pinctrl-0 = <&mmc1_pins>; + wp-gpios = <&gpio4 30 GPIO_ACTIVE_HIGH>; /* gpio_126 */ + cd-gpios = <&gpio4 14 IRQ_TYPE_LEVEL_LOW>; /* gpio_110 */ + vmmc-supply = <&vmmc1>; + bus-width = <4>; + cap-power-off-card; +}; + +&omap3_pmx_core { + gpio_key_pins: pinmux_gpio_key_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x212e, PIN_INPUT_PULLUP | MUX_MODE4) /* cam_xclkb.gpio_111 / uP_GPIO_3*/ + >; + }; + + led_pins: pinmux_led_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x215e, PIN_OUTPUT_PULLUP | MUX_MODE4) /* sdmmc2_dat1.gpio_133 / uP_GPIO_0 */ + >; + }; + + lan9221_pins: pinmux_lan9221_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x2184, PIN_INPUT_PULLUP | MUX_MODE4) /* mcbsp4_clkx.gpio_152 */ + >; + }; + + mmc1_pins: pinmux_mmc1_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x2144, PIN_OUTPUT | MUX_MODE0) /* sdmmc1_clk.sdmmc1_clk */ + OMAP3_CORE1_IOPAD(0x2146, PIN_INPUT | MUX_MODE0) /* sdmmc1_cmd.sdmmc1_cmd */ + OMAP3_CORE1_IOPAD(0x2148, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat0.sdmmc1_dat0 */ + OMAP3_CORE1_IOPAD(0x214a, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat1.sdmmc1_dat1 */ + OMAP3_CORE1_IOPAD(0x214c, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat2.sdmmc1_dat2 */ + OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */ + OMAP3_CORE1_IOPAD(0x2132, PIN_INPUT_PULLUP | MUX_MODE4) /* cam_strobe.gpio_126 */ + OMAP3_CORE1_IOPAD(0x212c, PIN_INPUT_PULLUP | MUX_MODE4) /* cam_d11.gpio_110 */ + >; + }; + + lcd_enable_pin: pinmux_lcd_enable_pin { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x218a, PIN_OUTPUT | PIN_OFF_OUTPUT_LOW | MUX_MODE4) /* mcbsp4_fs.gpio_155 */ + >; + }; + + dss_dpi_pins1: pinmux_dss_dpi_pins1 { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x20d4, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_pclk.dss_pclk */ + OMAP3_CORE1_IOPAD(0x20d6, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_hsync.dss_hsync */ + OMAP3_CORE1_IOPAD(0x20d8, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_vsync.dss_vsync */ + OMAP3_CORE1_IOPAD(0x20da, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_acbias.dss_acbias */ + + OMAP3_CORE1_IOPAD(0x20dc, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data0.dss_data0 */ + OMAP3_CORE1_IOPAD(0x20de, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data1.dss_data1 */ + OMAP3_CORE1_IOPAD(0x20e0, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data2.dss_data2 */ + OMAP3_CORE1_IOPAD(0x20e2, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data3.dss_data3 */ + OMAP3_CORE1_IOPAD(0x20e4, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data4.dss_data4 */ + OMAP3_CORE1_IOPAD(0x20e6, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data5.dss_data5 */ + OMAP3_CORE1_IOPAD(0x20e8, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data6.dss_data6 */ + OMAP3_CORE1_IOPAD(0x20ea, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data7.dss_data7 */ + OMAP3_CORE1_IOPAD(0x20ec, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data8.dss_data8 */ + OMAP3_CORE1_IOPAD(0x20ee, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data9.dss_data9 */ + OMAP3_CORE1_IOPAD(0x20f0, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data10.dss_data10 */ + OMAP3_CORE1_IOPAD(0x20f2, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data11.dss_data11 */ + OMAP3_CORE1_IOPAD(0x20f4, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data12.dss_data12 */ + OMAP3_CORE1_IOPAD(0x20f6, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data13.dss_data13 */ + OMAP3_CORE1_IOPAD(0x20f8, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data14.dss_data14 */ + OMAP3_CORE1_IOPAD(0x20fa, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data15.dss_data15 */ + >; + }; +}; + +&omap3_pmx_wkup { + led_pins_wkup: pinmux_led_pins_wkup { + pinctrl-single,pins = < + OMAP3_WKUP_IOPAD(0x2a24, PIN_OUTPUT_PULLUP | MUX_MODE4) /* jtag_emu0.gpio_11 / uP_GPIO_1 */ + >; + }; + + backlight_pins: pinmux_backlight_pins { + pinctrl-single,pins = < + OMAP3_WKUP_IOPAD(0x2a16, PIN_OUTPUT | PIN_OFF_OUTPUT_LOW | MUX_MODE4) /* sys_boot6.gpio_8 */ + >; + }; +}; + + +&uart1 { + interrupts-extended = <&intc 72 &omap3_pmx_core OMAP3_UART1_RX>; +}; + +/* Wired to the tps65950 on the SOM, only the USB connector is on the devkit */ +&usb_otg_hs { + pinctrl-names = "default"; + pinctrl-0 = <&hsusb_otg_pins>; + interface-type = <0>; + usb-phy = <&usb2_phy>; + phys = <&usb2_phy>; + phy-names = "usb2-phy"; + mode = <3>; + power = <50>; +}; diff --git a/arch/arm/boot/dts/logicpd-som-lv.dtsi b/arch/arm/boot/dts/logicpd-som-lv.dtsi index 29cb804d10cc..c1aa7a4518fb 100644 --- a/arch/arm/boot/dts/logicpd-som-lv.dtsi +++ b/arch/arm/boot/dts/logicpd-som-lv.dtsi @@ -67,33 +67,6 @@ gpmc,device-width = <2>; #address-cells = <1>; #size-cells = <1>; - - /* u-boot uses mtdparts=omap2-nand.0:512k(x-loader),1920k(u-boot),128k(u-boot-env),4m(kernel),-(fs) */ - - x-loader@0 { - label = "x-loader"; - reg = <0 0x80000>; - }; - - bootloaders@80000 { - label = "u-boot"; - reg = <0x80000 0x1e0000>; - }; - - bootloaders_env@260000 { - label = "u-boot-env"; - reg = <0x260000 0x20000>; - }; - - kernel@280000 { - label = "kernel"; - reg = <0x280000 0x400000>; - }; - - filesystem@680000 { - label = "fs"; - reg = <0x680000 0>; /* 0 = MTDPART_SIZ_FULL */ - }; }; }; diff --git a/arch/arm/boot/dts/logicpd-torpedo-35xx-devkit.dts b/arch/arm/boot/dts/logicpd-torpedo-35xx-devkit.dts new file mode 100644 index 000000000000..d7cb659656ce --- /dev/null +++ b/arch/arm/boot/dts/logicpd-torpedo-35xx-devkit.dts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +/dts-v1/; + +#include "omap34xx.dtsi" +#include "logicpd-torpedo-som.dtsi" +#include "logicpd-torpedo-baseboard.dtsi" +#include "omap-gpmc-smsc9221.dtsi" + +/ { + model = "LogicPD Zoom OMAP35xx Torpedo Development Kit"; + compatible = "logicpd,dm3730-torpedo-devkit", "ti,omap3"; +}; diff --git a/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts b/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts index b4575bbaf085..234afd6d60ec 100644 --- a/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts +++ b/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts @@ -9,396 +9,69 @@ #include "omap36xx.dtsi" #include "logicpd-torpedo-som.dtsi" #include "omap-gpmc-smsc9221.dtsi" +#include "logicpd-torpedo-baseboard.dtsi" / { model = "LogicPD Zoom DM3730 Torpedo + Wireless Development Kit"; compatible = "logicpd,dm3730-torpedo-devkit", "ti,omap3630", "ti,omap3"; - gpio_keys { - compatible = "gpio-keys"; - pinctrl-names = "default"; - pinctrl-0 = <&gpio_key_pins &gpio_key_pins_wkup>; - - sysboot2 { - label = "sysboot2"; - gpios = <&gpio1 2 GPIO_ACTIVE_LOW>; /* gpio2 */ - linux,code = ; - wakeup-source; - }; - - sysboot5 { - label = "sysboot5"; - gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; /* gpio7 */ - linux,code = ; - wakeup-source; - }; - - gpio1 { - label = "gpio1"; - gpios = <&gpio6 21 GPIO_ACTIVE_LOW>; /* gpio181 */ - linux,code = ; - wakeup-source; - }; - - gpio2 { - label = "gpio2"; - gpios = <&gpio6 18 GPIO_ACTIVE_LOW>; /* gpio178 */ - linux,code = ; - wakeup-source; - }; - }; - - sound { - compatible = "ti,omap-twl4030"; - ti,model = "omap3logic"; - ti,mcbsp = <&mcbsp2>; - }; - - leds { - compatible = "gpio-leds"; - pinctrl-names = "default"; - pinctrl-0 = <&led_pins>; - - led1 { - label = "led1"; - gpios = <&gpio6 20 GPIO_ACTIVE_HIGH>; /* gpio180 */ - linux,default-trigger = "cpu0"; - }; - - led2 { - label = "led2"; - gpios = <&gpio6 19 GPIO_ACTIVE_HIGH>; /* gpio179 */ - linux,default-trigger = "none"; - }; - }; - - pwm10: dmtimer-pwm { - compatible = "ti,omap-dmtimer-pwm"; - pinctrl-names = "default"; - pinctrl-0 = <&pwm_pins>; - ti,timers = <&timer10>; - #pwm-cells = <3>; - }; - -}; - -&vaux1 { - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3000000>; -}; - -&vaux4 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; -}; - -&mcbsp2 { - status = "okay"; -}; - -&charger { - ti,bb-uvolt = <3200000>; - ti,bb-uamp = <150>; -}; - -&gpmc { - ranges = <0 0 0x30000000 0x1000000 /* CS0: 16MB for NAND */ - 1 0 0x2c000000 0x1000000>; /* CS1: 16MB for LAN9221 */ - - ethernet@gpmc { - pinctrl-names = "default"; - pinctrl-0 = <&lan9221_pins>; - interrupt-parent = <&gpio5>; - interrupts = <1 IRQ_TYPE_LEVEL_LOW>; /* gpio129 */ - reg = <1 0 0xff>; - }; -}; - -&vpll2 { - regulator-always-on; -}; - -&dss { - status = "ok"; - vdds_dsi-supply = <&vpll2>; - vdda_video-supply = <&video_reg>; - pinctrl-names = "default"; - pinctrl-0 = <&dss_dpi_pins1>; - port { - dpi_out: endpoint { - remote-endpoint = <&lcd_in>; - data-lines = <16>; - }; - }; -}; - -/ { - aliases { - display0 = &lcd0; - }; - - video_reg: video_reg { - pinctrl-names = "default"; - pinctrl-0 = <&panel_pwr_pins>; + wl12xx_vmmc: wl12xx_vmmc { compatible = "regulator-fixed"; - regulator-name = "fixed-supply"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - gpio = <&gpio5 27 GPIO_ACTIVE_HIGH>; /* gpio155, lcd INI */ - }; - - lcd0: display { - compatible = "panel-dpi"; - label = "15"; - status = "okay"; - /* default-on; */ - pinctrl-names = "default"; - - port { - lcd_in: endpoint { - remote-endpoint = <&dpi_out>; - }; - }; - - panel-timing { - clock-frequency = <9000000>; - hactive = <480>; - vactive = <272>; - hfront-porch = <3>; - hback-porch = <2>; - hsync-len = <42>; - vback-porch = <3>; - vfront-porch = <4>; - vsync-len = <11>; - hsync-active = <0>; - vsync-active = <0>; - de-active = <1>; - pixelclk-active = <1>; - }; - }; - - bl: backlight { - compatible = "pwm-backlight"; - pinctrl-names = "default"; - pinctrl-0 = <&backlight_pins>; - pwms = <&pwm10 0 5000000 0>; - brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>; - default-brightness-level = <7>; - enable-gpios = <&gpio5 26 GPIO_ACTIVE_HIGH>; /* gpio_154 */ + regulator-name = "vwl1271"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + gpio = <&gpio5 29 0>; /* gpio157 */ + startup-delay-us = <70000>; + enable-active-high; + vin-supply = <&vmmc2>; }; }; -&mmc1 { - interrupts-extended = <&intc 83 &omap3_pmx_core 0x11a>; +/* + * Only found on the wireless SOM. For the SOM without wireless, the pins for + * MMC3 can be routed with jumpers to the second MMC slot on the devkit and + * gpio157 is not connected. So this should be OK to keep common for now, + * probably device tree overlays is the way to go with the various SOM and + * jumpering combinations for the long run. + */ +&mmc3 { + interrupts-extended = <&intc 94 &omap3_pmx_core2 0x46>; + pinctrl-0 = <&mmc3_pins &mmc3_core2_pins>; pinctrl-names = "default"; - pinctrl-0 = <&mmc1_pins &mmc1_cd>; - cd-gpios = <&gpio4 31 GPIO_ACTIVE_LOW>; /* gpio127 */ - vmmc-supply = <&vmmc1>; + vmmc-supply = <&wl12xx_vmmc>; + non-removable; bus-width = <4>; cap-power-off-card; + #address-cells = <1>; + #size-cells = <0>; + wlcore: wlcore@2 { + compatible = "ti,wl1283"; + reg = <2>; + interrupt-parent = <&gpio5>; + interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; /* gpio 152 */ + ref-clock-frequency = <26000000>; + tcxo-clock-frequency = <26000000>; + }; }; &omap3_pmx_core { - gpio_key_pins: pinmux_gpio_key_pins { + mmc3_pins: pinmux_mm3_pins { pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x21d6, PIN_INPUT_PULLUP | MUX_MODE4) /* mcspi2_clk.gpio_178 */ - OMAP3_CORE1_IOPAD(0x21dc, PIN_INPUT_PULLUP | MUX_MODE4) /* mcspi2_cs0.gpio_181 */ - >; - }; - - pwm_pins: pinmux_pwm_pins { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x20B8, PIN_OUTPUT | PIN_OFF_OUTPUT_LOW | MUX_MODE3) /* gpmc_ncs5.gpt_10_pwm_evt */ - >; - }; - - led_pins: pinmux_led_pins { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x21d8, PIN_OUTPUT | MUX_MODE4) /* gpio_179 */ - OMAP3_CORE1_IOPAD(0x21da, PIN_OUTPUT | MUX_MODE4) /* gpio_180 */ - >; - }; - - mmc1_pins: pinmux_mmc1_pins { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x2144, PIN_OUTPUT | MUX_MODE0) /* sdmmc1_clk.sdmmc1_clk */ - OMAP3_CORE1_IOPAD(0x2146, PIN_INPUT | MUX_MODE0) /* sdmmc1_cmd.sdmmc1_cmd */ - OMAP3_CORE1_IOPAD(0x2148, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat0.sdmmc1_dat0 */ - OMAP3_CORE1_IOPAD(0x214a, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat1.sdmmc1_dat1 */ - OMAP3_CORE1_IOPAD(0x214c, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat2.sdmmc1_dat2 */ - OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */ - >; - }; - - tsc2004_pins: pinmux_tsc2004_pins { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x2186, PIN_INPUT | MUX_MODE4) /* mcbsp4_dr.gpio_153 */ - >; - }; - - backlight_pins: pinmux_backlight_pins { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x2188, PIN_OUTPUT | PIN_OFF_OUTPUT_LOW | MUX_MODE4) /* mcbsp4_dx.gpio_154 */ - >; - }; - - isp_pins: pinmux_isp_pins { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x210c, PIN_INPUT | MUX_MODE0) /* cam_hs.cam_hs */ - OMAP3_CORE1_IOPAD(0x210e, PIN_INPUT | MUX_MODE0) /* cam_vs.cam_vs */ - OMAP3_CORE1_IOPAD(0x2110, PIN_INPUT | MUX_MODE0) /* cam_xclka.cam_xclka */ - OMAP3_CORE1_IOPAD(0x2112, PIN_INPUT | MUX_MODE0) /* cam_pclk.cam_pclk */ - - OMAP3_CORE1_IOPAD(0x2116, PIN_INPUT | MUX_MODE0) /* cam_d0.cam_d0 */ - OMAP3_CORE1_IOPAD(0x2118, PIN_INPUT | MUX_MODE0) /* cam_d1.cam_d1 */ - OMAP3_CORE1_IOPAD(0x211a, PIN_INPUT | MUX_MODE0) /* cam_d2.cam_d2 */ - OMAP3_CORE1_IOPAD(0x211c, PIN_INPUT | MUX_MODE0) /* cam_d3.cam_d3 */ - OMAP3_CORE1_IOPAD(0x211e, PIN_INPUT | MUX_MODE0) /* cam_d4.cam_d4 */ - OMAP3_CORE1_IOPAD(0x2120, PIN_INPUT | MUX_MODE0) /* cam_d5.cam_d5 */ - OMAP3_CORE1_IOPAD(0x2122, PIN_INPUT | MUX_MODE0) /* cam_d6.cam_d6 */ - OMAP3_CORE1_IOPAD(0x2124, PIN_INPUT | MUX_MODE0) /* cam_d7.cam_d7 */ - >; - }; - - panel_pwr_pins: pinmux_panel_pwr_pins { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x218a, PIN_OUTPUT | PIN_OFF_OUTPUT_LOW | MUX_MODE4) /* mcbsp4_fs.gpio_155 */ - >; - }; - - dss_dpi_pins1: pinmux_dss_dpi_pins1 { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x20d4, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_pclk.dss_pclk */ - OMAP3_CORE1_IOPAD(0x20d6, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_hsync.dss_hsync */ - OMAP3_CORE1_IOPAD(0x20d8, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_vsync.dss_vsync */ - OMAP3_CORE1_IOPAD(0x20da, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_acbias.dss_acbias */ - - OMAP3_CORE1_IOPAD(0x20e8, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data6.dss_data6 */ - OMAP3_CORE1_IOPAD(0x20ea, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data7.dss_data7 */ - OMAP3_CORE1_IOPAD(0x20ec, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data8.dss_data8 */ - OMAP3_CORE1_IOPAD(0x20ee, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data9.dss_data9 */ - OMAP3_CORE1_IOPAD(0x20f0, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data10.dss_data10 */ - OMAP3_CORE1_IOPAD(0x20f2, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data11.dss_data11 */ - OMAP3_CORE1_IOPAD(0x20f4, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data12.dss_data12 */ - OMAP3_CORE1_IOPAD(0x20f6, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data13.dss_data13 */ - OMAP3_CORE1_IOPAD(0x20f8, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data14.dss_data14 */ - OMAP3_CORE1_IOPAD(0x20fa, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data15.dss_data15 */ - OMAP3_CORE1_IOPAD(0x20fc, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data16.dss_data16 */ - OMAP3_CORE1_IOPAD(0x20fe, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data17.dss_data17 */ - - OMAP3_CORE1_IOPAD(0x2100, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE3) /* dss_data18.dss_data0 */ - OMAP3_CORE1_IOPAD(0x2102, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE3) /* dss_data19.dss_data1 */ - OMAP3_CORE1_IOPAD(0x2104, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE3) /* dss_data20.dss_data2 */ - OMAP3_CORE1_IOPAD(0x2106, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE3) /* dss_data21.dss_data3 */ - OMAP3_CORE1_IOPAD(0x2108, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE3) /* dss_data22.dss_data4 */ - OMAP3_CORE1_IOPAD(0x210a, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE3) /* dss_data23.dss_data5 */ + OMAP3_CORE1_IOPAD(0x2164, PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc2_dat4.sdmmc3_dat0 */ + OMAP3_CORE1_IOPAD(0x2166, PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc2_dat5.sdmmc3_dat1 */ + OMAP3_CORE1_IOPAD(0x2168, PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc2_dat6.sdmmc3_dat2 */ + OMAP3_CORE1_IOPAD(0x216a, PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc2_dat6.sdmmc3_dat3 */ + OMAP3_CORE1_IOPAD(0x2184, PIN_INPUT_PULLUP | MUX_MODE4) /* mcbsp4_clkx.gpio_152 */ + OMAP3_CORE1_IOPAD(0x218e, PIN_OUTPUT | MUX_MODE4) /* mcbsp1_fsr.gpio_157 */ >; }; }; -&omap3_pmx_wkup { - gpio_key_pins_wkup: pinmux_gpio_key_pins_wkup { +&omap3_pmx_core2 { + mmc3_core2_pins: pinmux_mmc3_core2_pins { pinctrl-single,pins = < - OMAP3_WKUP_IOPAD(0x2a0a, PIN_INPUT_PULLUP | MUX_MODE4) /* sys_boot0.gpio_2 */ - OMAP3_WKUP_IOPAD(0x2a14, PIN_INPUT_PULLUP | MUX_MODE4) /* sys_boot5.gpio_7 */ - >; - }; - - lan9221_pins: pinmux_lan9221_pins { - pinctrl-single,pins = < - OMAP3_WKUP_IOPAD(0x2a5a, PIN_INPUT | MUX_MODE4) /* reserved.gpio_129 */ - >; - }; - - mmc1_cd: pinmux_mmc1_cd { - pinctrl-single,pins = < - OMAP3_WKUP_IOPAD(0x2a54, PIN_INPUT_PULLUP | MUX_MODE4) /* reserved.gpio_127 */ + OMAP3630_CORE2_IOPAD(0x25d8, PIN_INPUT_PULLUP | MUX_MODE2) /* etk_clk.sdmmc3_clk */ + OMAP3630_CORE2_IOPAD(0x25da, PIN_INPUT_PULLUP | MUX_MODE2) /* etk_ctl.sdmmc3_cmd */ >; }; }; - -&i2c2 { - mt9p031@48 { - compatible = "aptina,mt9p031"; - reg = <0x48>; - clocks = <&isp 0>; - vaa-supply = <&vaux4>; - vdd-supply = <&vaux4>; - vdd_io-supply = <&vaux4>; - port { - mt9p031_out: endpoint { - input-clock-frequency = <24000000>; - pixel-clock-frequency = <72000000>; - remote-endpoint = <&ccdc_ep>; - }; - }; - }; -}; - -&i2c3 { - touchscreen: tsc2004@48 { - compatible = "ti,tsc2004"; - reg = <0x48>; - vio-supply = <&vaux1>; - pinctrl-names = "default"; - pinctrl-0 = <&tsc2004_pins>; - interrupts-extended = <&gpio5 25 IRQ_TYPE_EDGE_RISING>; /* gpio 153 */ - - touchscreen-fuzz-x = <4>; - touchscreen-fuzz-y = <7>; - touchscreen-fuzz-pressure = <2>; - touchscreen-size-x = <4096>; - touchscreen-size-y = <4096>; - touchscreen-max-pressure = <2048>; - - ti,x-plate-ohms = <280>; - ti,esd-recovery-timeout-ms = <8000>; - }; -}; - -&mcspi1 { - at25@0 { - compatible = "atmel,at25"; - reg = <0>; - spi-max-frequency = <5000000>; - spi-cpha; - spi-cpol; - - pagesize = <64>; - size = <32768>; - address-width = <16>; - }; -}; - -&isp { - pinctrl-names = "default"; - pinctrl-0 = <&isp_pins>; - ports { - port@0 { - reg = <0>; - ccdc_ep: endpoint { - remote-endpoint = <&mt9p031_out>; - bus-width = <8>; - hsync-active = <1>; - vsync-active = <1>; - pclk-sample = <0>; - }; - }; - }; -}; - -&uart1 { - interrupts-extended = <&intc 72 &omap3_pmx_core OMAP3_UART1_RX>; -}; - -/* Wired to the tps65950 on the SOM, only the USB connector is on the devkit */ -&usb_otg_hs { - pinctrl-names = "default"; - pinctrl-0 = <&hsusb_otg_pins>; - interface-type = <0>; - usb-phy = <&usb2_phy>; - phys = <&usb2_phy>; - phy-names = "usb2-phy"; - mode = <3>; - power = <50>; -}; diff --git a/arch/arm/boot/dts/logicpd-torpedo-baseboard.dtsi b/arch/arm/boot/dts/logicpd-torpedo-baseboard.dtsi new file mode 100644 index 000000000000..86c5644f558c --- /dev/null +++ b/arch/arm/boot/dts/logicpd-torpedo-baseboard.dtsi @@ -0,0 +1,395 @@ +/* + * 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. + */ + +/ { + gpio_keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&gpio_key_pins &gpio_key_pins_wkup>; + + sysboot2 { + label = "sysboot2"; + gpios = <&gpio1 2 GPIO_ACTIVE_LOW>; /* gpio2 */ + linux,code = ; + wakeup-source; + }; + + sysboot5 { + label = "sysboot5"; + gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; /* gpio7 */ + linux,code = ; + wakeup-source; + }; + + gpio1 { + label = "gpio1"; + gpios = <&gpio6 21 GPIO_ACTIVE_LOW>; /* gpio181 */ + linux,code = ; + wakeup-source; + }; + + gpio2 { + label = "gpio2"; + gpios = <&gpio6 18 GPIO_ACTIVE_LOW>; /* gpio178 */ + linux,code = ; + wakeup-source; + }; + }; + + sound { + compatible = "ti,omap-twl4030"; + ti,model = "omap3logic"; + ti,mcbsp = <&mcbsp2>; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pins>; + + led1 { + label = "led1"; + gpios = <&gpio6 20 GPIO_ACTIVE_HIGH>; /* gpio180 */ + linux,default-trigger = "cpu0"; + }; + + led2 { + label = "led2"; + gpios = <&gpio6 19 GPIO_ACTIVE_HIGH>; /* gpio179 */ + linux,default-trigger = "none"; + }; + }; + + pwm10: dmtimer-pwm { + compatible = "ti,omap-dmtimer-pwm"; + pinctrl-names = "default"; + pinctrl-0 = <&pwm_pins>; + ti,timers = <&timer10>; + #pwm-cells = <3>; + }; + +}; + +&vaux1 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; +}; + +&vaux4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; +}; + +&mcbsp2 { + status = "okay"; +}; + +&charger { + ti,bb-uvolt = <3200000>; + ti,bb-uamp = <150>; +}; + +&gpmc { + ranges = <0 0 0x30000000 0x1000000 /* CS0: 16MB for NAND */ + 1 0 0x2c000000 0x1000000>; /* CS1: 16MB for LAN9221 */ + + ethernet@gpmc { + pinctrl-names = "default"; + pinctrl-0 = <&lan9221_pins>; + interrupt-parent = <&gpio5>; + interrupts = <1 IRQ_TYPE_LEVEL_LOW>; /* gpio129 */ + reg = <1 0 0xff>; + }; +}; + +&vpll2 { + regulator-always-on; +}; + +&dss { + status = "ok"; + vdds_dsi-supply = <&vpll2>; + vdda_video-supply = <&video_reg>; + pinctrl-names = "default"; + pinctrl-0 = <&dss_dpi_pins1>; + port { + dpi_out: endpoint { + remote-endpoint = <&lcd_in>; + data-lines = <16>; + }; + }; +}; + +/ { + aliases { + display0 = &lcd0; + }; + + video_reg: video_reg { + pinctrl-names = "default"; + pinctrl-0 = <&panel_pwr_pins>; + compatible = "regulator-fixed"; + regulator-name = "fixed-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio5 27 GPIO_ACTIVE_HIGH>; /* gpio155, lcd INI */ + }; + + lcd0: display { + compatible = "panel-dpi"; + label = "15"; + status = "okay"; + /* default-on; */ + pinctrl-names = "default"; + + port { + lcd_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + + panel-timing { + clock-frequency = <9000000>; + hactive = <480>; + vactive = <272>; + hfront-porch = <3>; + hback-porch = <2>; + hsync-len = <42>; + vback-porch = <3>; + vfront-porch = <4>; + vsync-len = <11>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <1>; + }; + }; + + bl: backlight { + compatible = "pwm-backlight"; + pinctrl-names = "default"; + pinctrl-0 = <&backlight_pins>; + pwms = <&pwm10 0 5000000 0>; + brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>; + default-brightness-level = <7>; + enable-gpios = <&gpio5 26 GPIO_ACTIVE_HIGH>; /* gpio_154 */ + }; +}; + +&mmc1 { + interrupts-extended = <&intc 83 &omap3_pmx_core 0x11a>; + pinctrl-names = "default"; + pinctrl-0 = <&mmc1_pins &mmc1_cd>; + cd-gpios = <&gpio4 31 GPIO_ACTIVE_LOW>; /* gpio127 */ + vmmc-supply = <&vmmc1>; + bus-width = <4>; + cap-power-off-card; +}; + +&omap3_pmx_core { + gpio_key_pins: pinmux_gpio_key_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x21d6, PIN_INPUT_PULLUP | MUX_MODE4) /* mcspi2_clk.gpio_178 */ + OMAP3_CORE1_IOPAD(0x21dc, PIN_INPUT_PULLUP | MUX_MODE4) /* mcspi2_cs0.gpio_181 */ + >; + }; + + pwm_pins: pinmux_pwm_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x20B8, PIN_OUTPUT | PIN_OFF_OUTPUT_LOW | MUX_MODE3) /* gpmc_ncs5.gpt_10_pwm_evt */ + >; + }; + + led_pins: pinmux_led_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x21d8, PIN_OUTPUT | MUX_MODE4) /* gpio_179 */ + OMAP3_CORE1_IOPAD(0x21da, PIN_OUTPUT | MUX_MODE4) /* gpio_180 */ + >; + }; + + mmc1_pins: pinmux_mmc1_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x2144, PIN_OUTPUT | MUX_MODE0) /* sdmmc1_clk.sdmmc1_clk */ + OMAP3_CORE1_IOPAD(0x2146, PIN_INPUT | MUX_MODE0) /* sdmmc1_cmd.sdmmc1_cmd */ + OMAP3_CORE1_IOPAD(0x2148, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat0.sdmmc1_dat0 */ + OMAP3_CORE1_IOPAD(0x214a, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat1.sdmmc1_dat1 */ + OMAP3_CORE1_IOPAD(0x214c, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat2.sdmmc1_dat2 */ + OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */ + >; + }; + + tsc2004_pins: pinmux_tsc2004_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x2186, PIN_INPUT | MUX_MODE4) /* mcbsp4_dr.gpio_153 */ + >; + }; + + backlight_pins: pinmux_backlight_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x2188, PIN_OUTPUT | PIN_OFF_OUTPUT_LOW | MUX_MODE4) /* mcbsp4_dx.gpio_154 */ + >; + }; + + isp_pins: pinmux_isp_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x210c, PIN_INPUT | MUX_MODE0) /* cam_hs.cam_hs */ + OMAP3_CORE1_IOPAD(0x210e, PIN_INPUT | MUX_MODE0) /* cam_vs.cam_vs */ + OMAP3_CORE1_IOPAD(0x2110, PIN_INPUT | MUX_MODE0) /* cam_xclka.cam_xclka */ + OMAP3_CORE1_IOPAD(0x2112, PIN_INPUT | MUX_MODE0) /* cam_pclk.cam_pclk */ + + OMAP3_CORE1_IOPAD(0x2116, PIN_INPUT | MUX_MODE0) /* cam_d0.cam_d0 */ + OMAP3_CORE1_IOPAD(0x2118, PIN_INPUT | MUX_MODE0) /* cam_d1.cam_d1 */ + OMAP3_CORE1_IOPAD(0x211a, PIN_INPUT | MUX_MODE0) /* cam_d2.cam_d2 */ + OMAP3_CORE1_IOPAD(0x211c, PIN_INPUT | MUX_MODE0) /* cam_d3.cam_d3 */ + OMAP3_CORE1_IOPAD(0x211e, PIN_INPUT | MUX_MODE0) /* cam_d4.cam_d4 */ + OMAP3_CORE1_IOPAD(0x2120, PIN_INPUT | MUX_MODE0) /* cam_d5.cam_d5 */ + OMAP3_CORE1_IOPAD(0x2122, PIN_INPUT | MUX_MODE0) /* cam_d6.cam_d6 */ + OMAP3_CORE1_IOPAD(0x2124, PIN_INPUT | MUX_MODE0) /* cam_d7.cam_d7 */ + >; + }; + + panel_pwr_pins: pinmux_panel_pwr_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x218a, PIN_OUTPUT | PIN_OFF_OUTPUT_LOW | MUX_MODE4) /* mcbsp4_fs.gpio_155 */ + >; + }; + + dss_dpi_pins1: pinmux_dss_dpi_pins1 { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x20d4, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_pclk.dss_pclk */ + OMAP3_CORE1_IOPAD(0x20d6, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_hsync.dss_hsync */ + OMAP3_CORE1_IOPAD(0x20d8, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_vsync.dss_vsync */ + OMAP3_CORE1_IOPAD(0x20da, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_acbias.dss_acbias */ + + OMAP3_CORE1_IOPAD(0x20e8, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data6.dss_data6 */ + OMAP3_CORE1_IOPAD(0x20ea, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data7.dss_data7 */ + OMAP3_CORE1_IOPAD(0x20ec, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data8.dss_data8 */ + OMAP3_CORE1_IOPAD(0x20ee, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data9.dss_data9 */ + OMAP3_CORE1_IOPAD(0x20f0, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data10.dss_data10 */ + OMAP3_CORE1_IOPAD(0x20f2, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data11.dss_data11 */ + OMAP3_CORE1_IOPAD(0x20f4, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data12.dss_data12 */ + OMAP3_CORE1_IOPAD(0x20f6, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data13.dss_data13 */ + OMAP3_CORE1_IOPAD(0x20f8, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data14.dss_data14 */ + OMAP3_CORE1_IOPAD(0x20fa, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data15.dss_data15 */ + OMAP3_CORE1_IOPAD(0x20fc, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data16.dss_data16 */ + OMAP3_CORE1_IOPAD(0x20fe, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE0) /* dss_data17.dss_data17 */ + + OMAP3_CORE1_IOPAD(0x2100, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE3) /* dss_data18.dss_data0 */ + OMAP3_CORE1_IOPAD(0x2102, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE3) /* dss_data19.dss_data1 */ + OMAP3_CORE1_IOPAD(0x2104, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE3) /* dss_data20.dss_data2 */ + OMAP3_CORE1_IOPAD(0x2106, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE3) /* dss_data21.dss_data3 */ + OMAP3_CORE1_IOPAD(0x2108, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE3) /* dss_data22.dss_data4 */ + OMAP3_CORE1_IOPAD(0x210a, PIN_OUTPUT_PULLDOWN | PIN_OFF_OUTPUT_LOW | MUX_MODE3) /* dss_data23.dss_data5 */ + >; + }; +}; + +&omap3_pmx_wkup { + gpio_key_pins_wkup: pinmux_gpio_key_pins_wkup { + pinctrl-single,pins = < + OMAP3_WKUP_IOPAD(0x2a0a, PIN_INPUT_PULLUP | MUX_MODE4) /* sys_boot0.gpio_2 */ + OMAP3_WKUP_IOPAD(0x2a14, PIN_INPUT_PULLUP | MUX_MODE4) /* sys_boot5.gpio_7 */ + >; + }; + + lan9221_pins: pinmux_lan9221_pins { + pinctrl-single,pins = < + OMAP3_WKUP_IOPAD(0x2a5a, PIN_INPUT | MUX_MODE4) /* reserved.gpio_129 */ + >; + }; + + mmc1_cd: pinmux_mmc1_cd { + pinctrl-single,pins = < + OMAP3_WKUP_IOPAD(0x2a54, PIN_INPUT_PULLUP | MUX_MODE4) /* reserved.gpio_127 */ + >; + }; +}; + +&i2c2 { + mt9p031@48 { + compatible = "aptina,mt9p031"; + reg = <0x48>; + clocks = <&isp 0>; + vaa-supply = <&vaux4>; + vdd-supply = <&vaux4>; + vdd_io-supply = <&vaux4>; + port { + mt9p031_out: endpoint { + input-clock-frequency = <24000000>; + pixel-clock-frequency = <72000000>; + remote-endpoint = <&ccdc_ep>; + }; + }; + }; +}; + +&i2c3 { + touchscreen: tsc2004@48 { + compatible = "ti,tsc2004"; + reg = <0x48>; + vio-supply = <&vaux1>; + pinctrl-names = "default"; + pinctrl-0 = <&tsc2004_pins>; + interrupts-extended = <&gpio5 25 IRQ_TYPE_EDGE_RISING>; /* gpio 153 */ + + touchscreen-fuzz-x = <4>; + touchscreen-fuzz-y = <7>; + touchscreen-fuzz-pressure = <2>; + touchscreen-size-x = <4096>; + touchscreen-size-y = <4096>; + touchscreen-max-pressure = <2048>; + + ti,x-plate-ohms = <280>; + ti,esd-recovery-timeout-ms = <8000>; + }; +}; + +&mcspi1 { + at25@0 { + compatible = "atmel,at25"; + reg = <0>; + spi-max-frequency = <5000000>; + spi-cpha; + spi-cpol; + + pagesize = <64>; + size = <32768>; + address-width = <16>; + }; +}; + +&isp { + pinctrl-names = "default"; + pinctrl-0 = <&isp_pins>; + ports { + port@0 { + reg = <0>; + ccdc_ep: endpoint { + remote-endpoint = <&mt9p031_out>; + bus-width = <8>; + hsync-active = <1>; + vsync-active = <1>; + pclk-sample = <0>; + }; + }; + }; +}; + +&uart1 { + interrupts-extended = <&intc 72 &omap3_pmx_core OMAP3_UART1_RX>; +}; + +/* Wired to the tps65950 on the SOM, only the USB connector is on the devkit */ +&usb_otg_hs { + pinctrl-names = "default"; + pinctrl-0 = <&hsusb_otg_pins>; + interface-type = <0>; + usb-phy = <&usb2_phy>; + phys = <&usb2_phy>; + phy-names = "usb2-phy"; + mode = <3>; + power = <50>; +}; diff --git a/arch/arm/boot/dts/logicpd-torpedo-som.dtsi b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi index 6d89736c7b44..b50b796e15c7 100644 --- a/arch/arm/boot/dts/logicpd-torpedo-som.dtsi +++ b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi @@ -30,17 +30,6 @@ linux,default-trigger = "none"; }; }; - - wl12xx_vmmc: wl12xx_vmmc { - compatible = "regulator-fixed"; - regulator-name = "vwl1271"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - gpio = <&gpio5 29 0>; /* gpio157 */ - startup-delay-us = <70000>; - enable-active-high; - vin-supply = <&vmmc2>; - }; }; &gpmc { @@ -73,33 +62,6 @@ gpmc,device-width = <2>; #address-cells = <1>; #size-cells = <1>; - - /* u-boot uses mtdparts=omap2-nand.0:512k(x-loader),1920k(u-boot),128k(u-boot-env),4m(kernel),-(fs) */ - - x-loader@0 { - label = "x-loader"; - reg = <0 0x80000>; - }; - - bootloaders@80000 { - label = "u-boot"; - reg = <0x80000 0x1e0000>; - }; - - bootloaders_env@260000 { - label = "u-boot-env"; - reg = <0x260000 0x20000>; - }; - - kernel@280000 { - label = "kernel"; - reg = <0x280000 0x400000>; - }; - - filesystem@680000 { - label = "fs"; - reg = <0x680000 0>; /* 0 = MTDPART_SIZ_FULL */ - }; }; }; @@ -131,44 +93,7 @@ }; }; -/* - * Only found on the wireless SOM. For the SOM without wireless, the pins for - * MMC3 can be routed with jumpers to the second MMC slot on the devkit and - * gpio157 is not connected. So this should be OK to keep common for now, - * probably device tree overlays is the way to go with the various SOM and - * jumpering combinations for the long run. - */ -&mmc3 { - interrupts-extended = <&intc 94 &omap3_pmx_core2 0x46>; - pinctrl-0 = <&mmc3_pins &mmc3_core2_pins>; - pinctrl-names = "default"; - vmmc-supply = <&wl12xx_vmmc>; - non-removable; - bus-width = <4>; - cap-power-off-card; - #address-cells = <1>; - #size-cells = <0>; - wlcore: wlcore@2 { - compatible = "ti,wl1283"; - reg = <2>; - interrupt-parent = <&gpio5>; - interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; /* gpio 152 */ - ref-clock-frequency = <26000000>; - tcxo-clock-frequency = <26000000>; - }; -}; - &omap3_pmx_core { - mmc3_pins: pinmux_mm3_pins { - pinctrl-single,pins = < - OMAP3_CORE1_IOPAD(0x2164, PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc2_dat4.sdmmc3_dat0 */ - OMAP3_CORE1_IOPAD(0x2166, PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc2_dat5.sdmmc3_dat1 */ - OMAP3_CORE1_IOPAD(0x2168, PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc2_dat6.sdmmc3_dat2 */ - OMAP3_CORE1_IOPAD(0x216a, PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc2_dat6.sdmmc3_dat3 */ - OMAP3_CORE1_IOPAD(0x2184, PIN_INPUT_PULLUP | MUX_MODE4) /* mcbsp4_clkx.gpio_152 */ - OMAP3_CORE1_IOPAD(0x218e, PIN_OUTPUT | MUX_MODE4) /* mcbsp1_fsr.gpio_157 */ - >; - }; mcbsp2_pins: pinmux_mcbsp2_pins { pinctrl-single,pins = < OMAP3_CORE1_IOPAD(0x213c, PIN_INPUT | MUX_MODE0) /* mcbsp2_fsx */ @@ -224,15 +149,6 @@ pinctrl-0 = <&mcspi1_pins>; }; -&omap3_pmx_core2 { - mmc3_core2_pins: pinmux_mmc3_core2_pins { - pinctrl-single,pins = < - OMAP3630_CORE2_IOPAD(0x25d8, PIN_INPUT_PULLUP | MUX_MODE2) /* etk_clk.sdmmc3_clk */ - OMAP3630_CORE2_IOPAD(0x25da, PIN_INPUT_PULLUP | MUX_MODE2) /* etk_ctl.sdmmc3_cmd */ - >; - }; -}; - #include "twl4030.dtsi" #include "twl4030_omap3.dtsi" diff --git a/arch/arm/boot/dts/lpc3250-ea3250.dts b/arch/arm/boot/dts/lpc3250-ea3250.dts index c43adb7b4d7c..58ea0a4e7afa 100644 --- a/arch/arm/boot/dts/lpc3250-ea3250.dts +++ b/arch/arm/boot/dts/lpc3250-ea3250.dts @@ -156,8 +156,8 @@ uda1380: uda1380@18 { compatible = "nxp,uda1380"; reg = <0x18>; - power-gpio = <&gpio 0x59 0>; - reset-gpio = <&gpio 0x51 0>; + power-gpio = <&gpio 3 10 0>; + reset-gpio = <&gpio 3 2 0>; dac-clk = "wspll"; }; diff --git a/arch/arm/boot/dts/lpc3250-phy3250.dts b/arch/arm/boot/dts/lpc3250-phy3250.dts index c72eb9845603..1e1c2f517a82 100644 --- a/arch/arm/boot/dts/lpc3250-phy3250.dts +++ b/arch/arm/boot/dts/lpc3250-phy3250.dts @@ -81,8 +81,8 @@ uda1380: uda1380@18 { compatible = "nxp,uda1380"; reg = <0x18>; - power-gpio = <&gpio 0x59 0>; - reset-gpio = <&gpio 0x51 0>; + power-gpio = <&gpio 3 10 0>; + reset-gpio = <&gpio 3 2 0>; dac-clk = "wspll"; }; diff --git a/arch/arm/boot/dts/lpc4337-ciaa.dts b/arch/arm/boot/dts/lpc4337-ciaa.dts index 7c16d639a1b4..beddaba85393 100644 --- a/arch/arm/boot/dts/lpc4337-ciaa.dts +++ b/arch/arm/boot/dts/lpc4337-ciaa.dts @@ -174,17 +174,17 @@ clock-frequency = <400000>; eeprom@50 { - compatible = "microchip,24c512"; + compatible = "microchip,24c512", "atmel,24c512"; reg = <0x50>; }; eeprom@51 { - compatible = "microchip,24c02"; + compatible = "microchip,24c02", "atmel,24c02"; reg = <0x51>; }; eeprom@54 { - compatible = "microchip,24c512"; + compatible = "microchip,24c512", "atmel,24c512"; reg = <0x54>; }; }; diff --git a/arch/arm/boot/dts/lpc4350-hitex-eval.dts b/arch/arm/boot/dts/lpc4350-hitex-eval.dts index 874c75d44013..8b973f537d3a 100644 --- a/arch/arm/boot/dts/lpc4350-hitex-eval.dts +++ b/arch/arm/boot/dts/lpc4350-hitex-eval.dts @@ -429,7 +429,7 @@ }; eeprom@50 { - compatible = "nxp,24c02"; + compatible = "nxp,24c02", "atmel,24c02"; reg = <0x50>; }; diff --git a/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts b/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts index 9b5fad622522..02b23fa29d75 100644 --- a/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts +++ b/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts @@ -490,7 +490,7 @@ }; eeprom@57 { - compatible = "microchip,24c64"; + compatible = "microchip,24c64", "atmel,24c64"; reg = <0x57>; }; }; diff --git a/arch/arm/boot/dts/ls1021a-moxa-uc-8410a.dts b/arch/arm/boot/dts/ls1021a-moxa-uc-8410a.dts new file mode 100644 index 000000000000..d01f64b252b1 --- /dev/null +++ b/arch/arm/boot/dts/ls1021a-moxa-uc-8410a.dts @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2017 Moxa Inc. - https://www.moxa.com/ + * + * Author: Harry YJ Jhou (周亞諄) + * Jimmy Chen (陳永達) + * SZ Lin (林上智) + * + * 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. + */ + +/dts-v1/; + +#include +#include +#include "ls1021a.dtsi" + +/ { + model = "Moxa UC-8410A"; + + aliases { + enet0_rgmii_phy = &rgmii_phy0; + enet1_rgmii_phy = &rgmii_phy1; + enet2_rgmii_phy = &rgmii_phy2; + }; + + sys_mclk: clock-mclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24576000>; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + leds { + compatible = "gpio-leds"; + + cel-pwr { + label = "UC8410A:CEL-PWR"; + gpios = <&gpio3 27 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + cel-reset { + label = "UC8410A:CEL-RESET"; + gpios = <&gpio3 28 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + str-led { + label = "UC8410A:RED:PROG"; + gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc0"; + }; + + sw-ready { + label = "UC8410A:GREEN:SWRDY"; + gpios = <&gpio0 18 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + + beeper { + label = "UC8410A:BEEP"; + gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + prog-led0 { + label = "UC8410A:GREEN:PROG2"; + gpios = <&gpio3 14 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + prog-led1 { + label = "UC8410A:GREEN:PROG1"; + gpios = <&gpio3 15 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + prog-led2 { + label = "UC8410A:GREEN:PROG0"; + gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + wifi-signal0 { + label = "UC8410A:GREEN:CEL2"; + gpios = <&gpio3 17 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + wifi-signal1 { + label = "UC8410A:GREEN:CEL1"; + gpios = <&gpio3 18 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + wifi-signal2 { + label = "UC8410A:GREEN:CEL0"; + gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + cpu-diag-red { + label = "UC8410A:RED:DIA"; + gpios = <&gpio3 20 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + cpu-diag-green { + label = "UC8410A:GREEN:DIA"; + gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + cpu-diag-yellow { + label = "UC8410A:YELLOW:DIA"; + gpios = <&gpio3 22 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + pushbtn-key { + label = "push button key"; + gpios = <&gpio1 21 GPIO_ACTIVE_LOW>; + linux,code = ; + default-state = "on"; + }; + }; +}; + +&enet0 { + phy-handle = <&rgmii_phy0>; + phy-connection-type = "rgmii-id"; + status = "okay"; +}; + +&enet1 { + phy-handle = <&rgmii_phy1>; + phy-connection-type = "rgmii-id"; + status = "okay"; +}; + +&enet2 { + phy-handle = <&rgmii_phy2>; + phy-connection-type = "rgmii-id"; + status = "okay"; +}; + +&i2c0 { + clock-frequency = <100000>; + status = "okay"; + + tpm@20 { + compatible = "infineon,slb9635tt"; + reg = <0x20>; + }; + + rtc@68 { + compatible = "dallas,ds1374"; + reg = <0x68>; + }; +}; + +&lpuart0 { + status = "okay"; +}; + +&mdio0 { + rgmii_phy0: ethernet-phy@0 { + compatible = "marvell,88e1118"; + reg = <0x0>; + marvell,reg-init = + <3 0x11 0 0x4415>, /* Reg 3,17 */ + <3 0x10 0 0x77>; /* Reg 3,16 */ + }; + + rgmii_phy1: ethernet-phy@1 { + compatible = "marvell,88e1118"; + reg = <0x1>; + marvell,reg-init = + <3 0x11 0 0x4415>, /* Reg 3,17 */ + <3 0x10 0 0x77>; /* Reg 3,16 */ + }; + + rgmii_phy2: ethernet-phy@2 { + compatible = "marvell,88e1118"; + reg = <0x2>; + marvell,reg-init = + <3 0x11 0 0x4415>, /* Reg 3,17 */ + <3 0x10 0 0x77>; /* Reg 3,16 */ + }; +}; + +&qspi { + bus-num = <0>; + fsl,spi-num-chipselects = <2>; + fsl,spi-flash-chipselects = <0>; + fsl,qspi-has-second-chip; + status = "okay"; + + flash: flash@0 { + compatible = "spansion,s25fl064l", "spansion,s25fl164k"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <20000000>; + reg = <0>; + + partitions@0 { + label = "U-Boot"; + reg = <0x0 0x180000>; + }; + + partitions@180000 { + label = "U-Boot Env"; + reg = <0x180000 0x680000>; + }; + }; +}; + +&sata { + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/ls1021a-qds.dts b/arch/arm/boot/dts/ls1021a-qds.dts index 67b4de0e3439..499f41a2c6f0 100644 --- a/arch/arm/boot/dts/ls1021a-qds.dts +++ b/arch/arm/boot/dts/ls1021a-qds.dts @@ -239,6 +239,11 @@ device-width = <1>; }; + nand@2,0 { + compatible = "fsl,ifc-nand"; + reg = <0x2 0x0 0x10000>; + }; + fpga: board-control@3,0 { #address-cells = <1>; #size-cells = <1>; @@ -331,3 +336,19 @@ &uart1 { status = "okay"; }; + +&can0 { + status = "okay"; +}; + +&can1 { + status = "okay"; +}; + +&can2 { + status = "disabled"; +}; + +&can3 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/ls1021a-twr.dts b/arch/arm/boot/dts/ls1021a-twr.dts index 44715c8ef756..f0c949d74833 100644 --- a/arch/arm/boot/dts/ls1021a-twr.dts +++ b/arch/arm/boot/dts/ls1021a-twr.dts @@ -228,6 +228,10 @@ }; }; +&esdhc { + status = "okay"; +}; + &sai1 { status = "okay"; }; @@ -243,3 +247,19 @@ &uart1 { status = "okay"; }; + +&can0 { + status = "okay"; +}; + +&can1 { + status = "okay"; +}; + +&can2 { + status = "disabled"; +}; + +&can3 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi index 9319e1f0f1d8..c31dad98f989 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -106,6 +106,14 @@ compatible = "arm,cortex-a7-pmu"; interrupts = , ; + interrupt-affinity = <&cpu0>, <&cpu1>; + }; + + reboot { + compatible = "syscon-reboot"; + regmap = <&dcfg>; + offset = <0xb0>; + mask = <0x02>; }; soc { @@ -154,8 +162,22 @@ big-endian; }; + qspi: quadspi@1550000 { + compatible = "fsl,ls1021a-qspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x1550000 0x0 0x10000>, + <0x0 0x40000000 0x0 0x40000000>; + reg-names = "QuadSPI", "QuadSPI-memory"; + interrupts = ; + clock-names = "qspi_en", "qspi"; + clocks = <&clockgen 4 1>, <&clockgen 4 1>; + big-endian; + status = "disabled"; + }; + esdhc: esdhc@1560000 { - compatible = "fsl,esdhc"; + compatible = "fsl,ls1021a-esdhc", "fsl,esdhc"; reg = <0x0 0x1560000 0x0 0x10000>; interrupts = ; clock-frequency = <0>; @@ -575,7 +597,7 @@ fsl,tclk-period = <5>; fsl,tmr-prsc = <2>; fsl,tmr-add = <0xaaaaaaab>; - fsl,tmr-fiper1 = <999999990>; + fsl,tmr-fiper1 = <999999995>; fsl,tmr-fiper2 = <99990>; fsl,max-adj = <499999999>; }; @@ -668,7 +690,7 @@ }; }; - usb@8600000 { + usb2: usb@8600000 { compatible = "fsl-usb2-dr-v2.5", "fsl-usb2-dr"; reg = <0x0 0x8600000 0x0 0x1000>; interrupts = ; @@ -676,7 +698,7 @@ phy_type = "ulpi"; }; - usb3@3100000 { + usb3: usb3@3100000 { compatible = "snps,dwc3"; reg = <0x0 0x3100000 0x0 0x10000>; interrupts = ; @@ -730,5 +752,41 @@ <0000 0 0 3 &gic GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>, <0000 0 0 4 &gic GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>; }; + + can0: can@2a70000 { + compatible = "fsl,ls1021ar2-flexcan"; + reg = <0x0 0x2a70000 0x0 0x1000>; + interrupts = ; + clocks = <&clockgen 4 1>, <&clockgen 4 1>; + clock-names = "ipg", "per"; + big-endian; + }; + + can1: can@2a80000 { + compatible = "fsl,ls1021ar2-flexcan"; + reg = <0x0 0x2a80000 0x0 0x1000>; + interrupts = ; + clocks = <&clockgen 4 1>, <&clockgen 4 1>; + clock-names = "ipg", "per"; + big-endian; + }; + + can2: can@2a90000 { + compatible = "fsl,ls1021ar2-flexcan"; + reg = <0x0 0x2a90000 0x0 0x1000>; + interrupts = ; + clocks = <&clockgen 4 1>, <&clockgen 4 1>; + clock-names = "ipg", "per"; + big-endian; + }; + + can3: can@2aa0000 { + compatible = "fsl,ls1021ar2-flexcan"; + reg = <0x0 0x2aa0000 0x0 0x1000>; + interrupts = ; + clocks = <&clockgen 4 1>, <&clockgen 4 1>; + clock-names = "ipg", "per"; + big-endian; + }; }; }; diff --git a/arch/arm/boot/dts/meson8.dtsi b/arch/arm/boot/dts/meson8.dtsi index 2d7a0752a460..d2e3eeaa1a5f 100644 --- a/arch/arm/boot/dts/meson8.dtsi +++ b/arch/arm/boot/dts/meson8.dtsi @@ -286,6 +286,11 @@ clock-names = "stmmaceth"; }; +&gpio_intc { + compatible = "amlogic,meson8-gpio-intc", "amlogic,meson-gpio-intc"; + status = "okay"; +}; + &hwrng { compatible = "amlogic,meson8-rng", "amlogic,meson-rng"; clocks = <&clkc CLKID_RNG0>; @@ -308,6 +313,9 @@ arm,data-latency = <3 3 3>; arm,tag-latency = <2 2 2>; arm,filter-ranges = <0x100000 0xc0000000>; + prefetch-data = <1>; + prefetch-instr = <1>; + arm,shared-override; }; &pwm_ab { @@ -321,9 +329,8 @@ &saradc { compatible = "amlogic,meson8-saradc", "amlogic,meson-saradc"; clocks = <&clkc CLKID_XTAL>, - <&clkc CLKID_SAR_ADC>, - <&clkc CLKID_SANA>; - clock-names = "clkin", "core", "sana"; + <&clkc CLKID_SAR_ADC>; + clock-names = "clkin", "core"; }; &sdio { @@ -337,19 +344,27 @@ }; &uart_AO { - clocks = <&clkc CLKID_CLK81>; + compatible = "amlogic,meson8-uart", "amlogic,meson-uart"; + clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_XTAL>, <&clkc CLKID_CLK81>; + clock-names = "baud", "xtal", "pclk"; }; &uart_A { - clocks = <&clkc CLKID_CLK81>; + compatible = "amlogic,meson8-uart", "amlogic,meson-uart"; + clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_XTAL>, <&clkc CLKID_UART0>; + clock-names = "baud", "xtal", "pclk"; }; &uart_B { - clocks = <&clkc CLKID_CLK81>; + compatible = "amlogic,meson8-uart", "amlogic,meson-uart"; + clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_XTAL>, <&clkc CLKID_UART1>; + clock-names = "baud", "xtal", "pclk"; }; &uart_C { - clocks = <&clkc CLKID_CLK81>; + compatible = "amlogic,meson8-uart", "amlogic,meson-uart"; + clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_XTAL>, <&clkc CLKID_UART2>; + clock-names = "baud", "xtal", "pclk"; }; &usb0 { diff --git a/arch/arm/boot/dts/meson8b.dtsi b/arch/arm/boot/dts/meson8b.dtsi index d75e0ceda8bb..7cd03ed3742e 100644 --- a/arch/arm/boot/dts/meson8b.dtsi +++ b/arch/arm/boot/dts/meson8b.dtsi @@ -223,6 +223,9 @@ arm,data-latency = <3 3 3>; arm,tag-latency = <2 2 2>; arm,filter-ranges = <0x100000 0xc0000000>; + prefetch-data = <1>; + prefetch-instr = <1>; + arm,shared-override; }; &pwm_ab { @@ -236,9 +239,8 @@ &saradc { compatible = "amlogic,meson8b-saradc", "amlogic,meson-saradc"; clocks = <&clkc CLKID_XTAL>, - <&clkc CLKID_SAR_ADC>, - <&clkc CLKID_SANA>; - clock-names = "clkin", "core", "sana"; + <&clkc CLKID_SAR_ADC>; + clock-names = "clkin", "core"; }; &sdio { @@ -248,19 +250,27 @@ }; &uart_AO { - clocks = <&clkc CLKID_CLK81>; + compatible = "amlogic,meson8b-uart", "amlogic,meson-uart"; + clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_XTAL>, <&clkc CLKID_CLK81>; + clock-names = "baud", "xtal", "pclk"; }; &uart_A { - clocks = <&clkc CLKID_CLK81>; + compatible = "amlogic,meson8b-uart", "amlogic,meson-uart"; + clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_XTAL>, <&clkc CLKID_UART0>; + clock-names = "baud", "xtal", "pclk"; }; &uart_B { - clocks = <&clkc CLKID_CLK81>; + compatible = "amlogic,meson8b-uart", "amlogic,meson-uart"; + clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_XTAL>, <&clkc CLKID_UART1>; + clock-names = "baud", "xtal", "pclk"; }; &uart_C { - clocks = <&clkc CLKID_CLK81>; + compatible = "amlogic,meson8b-uart", "amlogic,meson-uart"; + clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_XTAL>, <&clkc CLKID_UART2>; + clock-names = "baud", "xtal", "pclk"; }; &usb0 { diff --git a/arch/arm/boot/dts/mpa1600.dts b/arch/arm/boot/dts/mpa1600.dts index 36cfa215620d..43aaa67fcd87 100644 --- a/arch/arm/boot/dts/mpa1600.dts +++ b/arch/arm/boot/dts/mpa1600.dts @@ -32,6 +32,18 @@ status = "okay"; }; + tcb0: timer@fffa0000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + macb0: ethernet@fffbc000 { phy-mode = "rmii"; status = "okay"; diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi index 965ddfbc9953..05557fce0f1d 100644 --- a/arch/arm/boot/dts/mt2701.dtsi +++ b/arch/arm/boot/dts/mt2701.dtsi @@ -604,6 +604,7 @@ compatible = "mediatek,mt2701-hifsys", "syscon"; reg = <0 0x1a000000 0 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; usb0: usb@1a1c0000 { @@ -688,6 +689,7 @@ compatible = "mediatek,mt2701-ethsys", "syscon"; reg = <0 0x1b000000 0 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; eth: ethernet@1b100000 { diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi index 0640fb75bf59..b750da5362f7 100644 --- a/arch/arm/boot/dts/mt7623.dtsi +++ b/arch/arm/boot/dts/mt7623.dtsi @@ -641,7 +641,7 @@ mmc0: mmc@11230000 { compatible = "mediatek,mt7623-mmc", - "mediatek,mt8135-mmc"; + "mediatek,mt2701-mmc"; reg = <0 0x11230000 0 0x1000>; interrupts = ; clocks = <&pericfg CLK_PERI_MSDC30_0>, @@ -652,7 +652,7 @@ mmc1: mmc@11240000 { compatible = "mediatek,mt7623-mmc", - "mediatek,mt8135-mmc"; + "mediatek,mt2701-mmc"; reg = <0 0x11240000 0 0x1000>; interrupts = ; clocks = <&pericfg CLK_PERI_MSDC30_1>, @@ -758,6 +758,7 @@ "syscon"; reg = <0 0x1b000000 0 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; eth: ethernet@1b100000 { diff --git a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts index 688a86378cee..7bf5aa2237c9 100644 --- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts @@ -204,7 +204,7 @@ bus-width = <4>; max-frequency = <50000000>; cap-sd-highspeed; - cd-gpios = <&pio 261 0>; + cd-gpios = <&pio 261 GPIO_ACTIVE_LOW>; vmmc-supply = <&mt6323_vmch_reg>; vqmmc-supply = <&mt6323_vio18_reg>; }; diff --git a/arch/arm/boot/dts/mt7623n-rfb-nand.dts b/arch/arm/boot/dts/mt7623n-rfb-nand.dts index 17c578f0d261..e66de8611650 100644 --- a/arch/arm/boot/dts/mt7623n-rfb-nand.dts +++ b/arch/arm/boot/dts/mt7623n-rfb-nand.dts @@ -51,7 +51,7 @@ reg = <0x40000 0x80000>; }; - partition@C0000 { + partition@c0000 { label = "uboot-env"; reg = <0xC0000 0x40000>; }; diff --git a/arch/arm/boot/dts/omap2420-n8x0-common.dtsi b/arch/arm/boot/dts/omap2420-n8x0-common.dtsi index 1df3ace3af92..63b0b4921e4e 100644 --- a/arch/arm/boot/dts/omap2420-n8x0-common.dtsi +++ b/arch/arm/boot/dts/omap2420-n8x0-common.dtsi @@ -52,6 +52,7 @@ onenand@0,0 { #address-cells = <1>; #size-cells = <1>; + compatible = "ti,omap2-onenand"; reg = <0 0 0x20000>; /* CS0, offset 0, IO size 128K */ gpmc,sync-read; diff --git a/arch/arm/boot/dts/omap3-cm-t3x.dtsi b/arch/arm/boot/dts/omap3-cm-t3x.dtsi index ab6003fe5a43..9dcb18d22cde 100644 --- a/arch/arm/boot/dts/omap3-cm-t3x.dtsi +++ b/arch/arm/boot/dts/omap3-cm-t3x.dtsi @@ -306,19 +306,19 @@ label = "xloader"; reg = <0 0x80000>; }; - partition@0x80000 { + partition@80000 { label = "uboot"; reg = <0x80000 0x1e0000>; }; - partition@0x260000 { + partition@260000 { label = "uboot environment"; reg = <0x260000 0x40000>; }; - partition@0x2a0000 { + partition@2a0000 { label = "linux"; reg = <0x2a0000 0x400000>; }; - partition@0x6a0000 { + partition@6a0000 { label = "rootfs"; reg = <0x6a0000 0x1f880000>; }; diff --git a/arch/arm/boot/dts/omap3-evm-37xx.dts b/arch/arm/boot/dts/omap3-evm-37xx.dts index 5a4ba0aea447..a14303b09ae2 100644 --- a/arch/arm/boot/dts/omap3-evm-37xx.dts +++ b/arch/arm/boot/dts/omap3-evm-37xx.dts @@ -90,19 +90,19 @@ label = "X-Loader"; reg = <0 0x80000>; }; - partition@0x80000 { + partition@80000 { label = "U-Boot"; reg = <0x80000 0x1c0000>; }; - partition@0x1c0000 { + partition@1c0000 { label = "Environment"; reg = <0x240000 0x40000>; }; - partition@0x280000 { + partition@280000 { label = "Kernel"; reg = <0x280000 0x500000>; }; - partition@0x780000 { + partition@780000 { label = "Filesystem"; reg = <0x780000 0x1f880000>; }; diff --git a/arch/arm/boot/dts/omap3-gta04.dtsi b/arch/arm/boot/dts/omap3-gta04.dtsi index 3dc56fb156b7..4170be70460e 100644 --- a/arch/arm/boot/dts/omap3-gta04.dtsi +++ b/arch/arm/boot/dts/omap3-gta04.dtsi @@ -86,7 +86,7 @@ /* lcd panel */ lcd: td028ttec1@0 { - compatible = "toppoly,td028ttec1"; + compatible = "tpo,td028ttec1"; reg = <0>; spi-max-frequency = <100000>; spi-cpol; diff --git a/arch/arm/boot/dts/omap3-igep.dtsi b/arch/arm/boot/dts/omap3-igep.dtsi index 4ad7d5565906..f33cc80c9dbc 100644 --- a/arch/arm/boot/dts/omap3-igep.dtsi +++ b/arch/arm/boot/dts/omap3-igep.dtsi @@ -147,32 +147,32 @@ gpmc,sync-read; gpmc,sync-write; gpmc,burst-length = <16>; - gpmc,burst-read; gpmc,burst-wrap; + gpmc,burst-read; gpmc,burst-write; gpmc,device-width = <2>; /* GPMC_DEVWIDTH_16BIT */ gpmc,mux-add-data = <2>; /* GPMC_MUX_AD */ gpmc,cs-on-ns = <0>; - gpmc,cs-rd-off-ns = <87>; - gpmc,cs-wr-off-ns = <87>; + gpmc,cs-rd-off-ns = <96>; + gpmc,cs-wr-off-ns = <96>; gpmc,adv-on-ns = <0>; - gpmc,adv-rd-off-ns = <10>; - gpmc,adv-wr-off-ns = <10>; - gpmc,oe-on-ns = <15>; - gpmc,oe-off-ns = <87>; + gpmc,adv-rd-off-ns = <12>; + gpmc,adv-wr-off-ns = <12>; + gpmc,oe-on-ns = <18>; + gpmc,oe-off-ns = <96>; gpmc,we-on-ns = <0>; - gpmc,we-off-ns = <87>; - gpmc,rd-cycle-ns = <112>; - gpmc,wr-cycle-ns = <112>; - gpmc,access-ns = <81>; - gpmc,page-burst-access-ns = <15>; + gpmc,we-off-ns = <96>; + gpmc,rd-cycle-ns = <114>; + gpmc,wr-cycle-ns = <114>; + gpmc,access-ns = <90>; + gpmc,page-burst-access-ns = <12>; gpmc,bus-turnaround-ns = <0>; gpmc,cycle2cycle-delay-ns = <0>; gpmc,wait-monitoring-ns = <0>; - gpmc,clk-activation-ns = <5>; + gpmc,clk-activation-ns = <6>; gpmc,wr-data-mux-bus-ns = <30>; - gpmc,wr-access-ns = <81>; - gpmc,sync-clk-ps = <15000>; + gpmc,wr-access-ns = <90>; + gpmc,sync-clk-ps = <12000>; #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi index 7ada1e93e166..cf7a2a72348d 100644 --- a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi +++ b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi @@ -405,22 +405,22 @@ reg = <0 0x80000>; }; - partition@0x80000 { + partition@80000 { label = "u-boot"; reg = <0x80000 0x1e0000>; }; - partition@0x260000 { + partition@260000 { label = "u-boot-environment"; reg = <0x260000 0x20000>; }; - partition@0x280000 { + partition@280000 { label = "kernel"; reg = <0x280000 0x500000>; }; - partition@0x780000 { + partition@780000 { label = "filesystem"; reg = <0x780000 0xf880000>; }; diff --git a/arch/arm/boot/dts/omap3-n9.dts b/arch/arm/boot/dts/omap3-n9.dts index 39e35f8b8206..e44d93fc644c 100644 --- a/arch/arm/boot/dts/omap3-n9.dts +++ b/arch/arm/boot/dts/omap3-n9.dts @@ -11,6 +11,7 @@ /dts-v1/; #include "omap3-n950-n9.dtsi" +#include / { model = "Nokia N9"; @@ -72,3 +73,9 @@ st,max-limit-y = <46>; st,max-limit-z = <46>; }; + +&twl_keypad { + linux,keymap = < MATRIX_KEY(6, 8, KEY_VOLUMEUP) + MATRIX_KEY(7, 8, KEY_VOLUMEDOWN) + >; +}; diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts index 669c51c00c00..ab930581fc7a 100644 --- a/arch/arm/boot/dts/omap3-n900.dts +++ b/arch/arm/boot/dts/omap3-n900.dts @@ -35,6 +35,8 @@ i2c1 = &i2c1; i2c2 = &i2c2; i2c3 = &i2c3; + display0 = &lcd; + display1 = &tv; }; cpus { @@ -558,7 +560,7 @@ tlv320aic3x: tlv320aic3x@18 { compatible = "ti,tlv320aic3x"; reg = <0x18>; - gpio-reset = <&gpio2 28 GPIO_ACTIVE_HIGH>; /* 60 */ + reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; /* 60 */ ai3x-gpio-func = < 0 /* AIC3X_GPIO1_FUNC_DISABLED */ 5 /* AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT */ @@ -575,7 +577,7 @@ tlv320aic3x_aux: tlv320aic3x@19 { compatible = "ti,tlv320aic3x"; reg = <0x19>; - gpio-reset = <&gpio2 28 GPIO_ACTIVE_HIGH>; /* 60 */ + reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; /* 60 */ AVDD-supply = <&vmmc2>; DRVDD-supply = <&vmmc2>; @@ -778,6 +780,8 @@ reset-gpio = <&gpio4 6 GPIO_ACTIVE_HIGH>; /* 102 */ + lens-focus = <&ad5820>; + port { csi_cam1: endpoint { bus-type = <3>; /* CCP2 */ @@ -838,6 +842,7 @@ onenand@0,0 { #address-cells = <1>; #size-cells = <1>; + compatible = "ti,omap2-onenand"; reg = <0 0 0x20000>; /* CS0, offset 0, IO size 128K */ gpmc,sync-read; @@ -965,7 +970,7 @@ ti,esd-recovery-timeout-ms = <8000>; }; - acx565akm@2 { + lcd: acx565akm@2 { compatible = "sony,acx565akm"; spi-max-frequency = <6000000>; reg = <2>; diff --git a/arch/arm/boot/dts/omap3-n950-n9.dtsi b/arch/arm/boot/dts/omap3-n950-n9.dtsi index 12fbb3da5fce..0d9b85317529 100644 --- a/arch/arm/boot/dts/omap3-n950-n9.dtsi +++ b/arch/arm/boot/dts/omap3-n950-n9.dtsi @@ -367,6 +367,7 @@ onenand@0,0 { #address-cells = <1>; #size-cells = <1>; + compatible = "ti,omap2-onenand"; reg = <0 0 0x20000>; /* CS0, offset 0, IO size 128K */ gpmc,sync-read; diff --git a/arch/arm/boot/dts/omap3-n950.dts b/arch/arm/boot/dts/omap3-n950.dts index c354a1ed1e70..2354e09343f3 100644 --- a/arch/arm/boot/dts/omap3-n950.dts +++ b/arch/arm/boot/dts/omap3-n950.dts @@ -51,6 +51,26 @@ }; }; +&omap3_pmx_core { + dsi_pins: pinmux_dsi_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x20dc, PIN_OUTPUT | MUX_MODE1) /* dsi_dx0 - data0+ */ + OMAP3_CORE1_IOPAD(0x20de, PIN_OUTPUT | MUX_MODE1) /* dsi_dy0 - data0- */ + OMAP3_CORE1_IOPAD(0x20e0, PIN_OUTPUT | MUX_MODE1) /* dsi_dx1 - clk+ */ + OMAP3_CORE1_IOPAD(0x20e2, PIN_OUTPUT | MUX_MODE1) /* dsi_dy1 - clk- */ + OMAP3_CORE1_IOPAD(0x20e4, PIN_OUTPUT | MUX_MODE1) /* dsi_dx2 - data1+ */ + OMAP3_CORE1_IOPAD(0x20e6, PIN_OUTPUT | MUX_MODE1) /* dsi_dy2 - data1- */ + >; + }; + + display_pins: pinmux_display_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x20ca, PIN_INPUT | MUX_MODE4) /* gpio 62 - display te */ + OMAP3_CORE1_IOPAD(0x20fe, PIN_OUTPUT | MUX_MODE4) /* gpio 87 - display reset */ + >; + }; +}; + &i2c2 { smia_1: camera@10 { compatible = "nokia,smia"; @@ -186,3 +206,71 @@ st,max-limit-y = <32>; st,max-limit-z = <32>; }; + +&dss { + status = "ok"; + + vdda_video-supply = <&vdac>; +}; + +&dsi { + status = "ok"; + + pinctrl-names = "default"; + pinctrl-0 = <&dsi_pins>; + + vdd-supply = <&vpll2>; + + port { + dsi_out_ep: endpoint { + remote-endpoint = <&lcd0_in>; + lanes = <2 3 0 1 4 5>; + }; + }; + + lcd0: display { + compatible = "nokia,himalaya", "panel-dsi-cm"; + label = "lcd0"; + + pinctrl-names = "default"; + pinctrl-0 = <&display_pins>; + + vpnl-supply = <&vmmc2>; + vddi-supply = <&vio>; + + reset-gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>; /* 87 */ + te-gpios = <&gpio2 30 GPIO_ACTIVE_HIGH>; /* 62 */ + + width-mm = <49>; /* 48.960 mm */ + height-mm = <88>; /* 88.128 mm */ + + /* TODO: + * - panel is upside-down + * - top + bottom 5px are not visible + */ + panel-timing { + clock-frequency = <0>; /* Calculated by dsi */ + + hback-porch = <2>; + hactive = <480>; + hfront-porch = <0>; + hsync-len = <2>; + + vback-porch = <1>; + vactive = <864>; + vfront-porch = <0>; + vsync-len = <1>; + + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <1>; + }; + + port { + lcd0_in: endpoint { + remote-endpoint = <&dsi_out_ep>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/omap3-pandora-common.dtsi b/arch/arm/boot/dts/omap3-pandora-common.dtsi index cd53dc6c0051..f83b1029b3b7 100644 --- a/arch/arm/boot/dts/omap3-pandora-common.dtsi +++ b/arch/arm/boot/dts/omap3-pandora-common.dtsi @@ -627,7 +627,7 @@ lcd: lcd@1 { reg = <1>; /* CS1 */ - compatible = "omapdss,tpo,td043mtea1"; + compatible = "tpo,td043mtea1"; spi-max-frequency = <100000>; spi-cpol; spi-cpha; diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index bb33935df7b0..a005802cd52b 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -587,20 +587,6 @@ dma-names = "rx"; }; - smartreflex_core: smartreflex@480cb000 { - compatible = "ti,omap3-smartreflex-core"; - ti,hwmods = "smartreflex_core"; - reg = <0x480cb000 0x400>; - interrupts = <19>; - }; - - smartreflex_mpu_iva: smartreflex@480c9000 { - compatible = "ti,omap3-smartreflex-iva"; - ti,hwmods = "smartreflex_mpu_iva"; - reg = <0x480c9000 0x400>; - interrupts = <18>; - }; - timer1: timer@48318000 { compatible = "ti,omap3430-timer"; reg = <0x48318000 0x400>; diff --git a/arch/arm/boot/dts/omap3430-sdp.dts b/arch/arm/boot/dts/omap3430-sdp.dts index 908951eb5943..d652708f6bef 100644 --- a/arch/arm/boot/dts/omap3430-sdp.dts +++ b/arch/arm/boot/dts/omap3430-sdp.dts @@ -154,6 +154,7 @@ linux,mtd-name= "samsung,kfm2g16q2m-deb8"; #address-cells = <1>; #size-cells = <1>; + compatible = "ti,omap2-onenand"; reg = <2 0 0x20000>; /* CS2, offset 0, IO size 4 */ gpmc,device-width = <2>; diff --git a/arch/arm/boot/dts/omap34xx.dtsi b/arch/arm/boot/dts/omap34xx.dtsi index ac4f8795b756..f572a477f74c 100644 --- a/arch/arm/boot/dts/omap34xx.dtsi +++ b/arch/arm/boot/dts/omap34xx.dtsi @@ -8,6 +8,7 @@ * kind, whether express or implied. */ +#include #include #include "omap3.dtsi" @@ -61,6 +62,44 @@ compatible = "ti,omap34xx-bandgap"; #thermal-sensor-cells = <0>; }; + + target-module@480cb000 { + compatible = "ti,sysc-omap3430-sr", "ti,sysc"; + ti,hwmods = "smartreflex_core"; + reg = <0x480cb024 0x4>; + reg-names = "sysc"; + ti,sysc-mask = ; + clocks = <&sr2_fck>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x480cb000 0x001000>; + + smartreflex_core: smartreflex@0 { + compatible = "ti,omap3-smartreflex-core"; + reg = <0 0x400>; + interrupts = <19>; + }; + }; + + target-module@480c9000 { + compatible = "ti,sysc-omap3430-sr", "ti,sysc"; + ti,hwmods = "smartreflex_mpu_iva"; + reg = <0x480c9024 0x4>; + reg-names = "sysc"; + ti,sysc-mask = ; + clocks = <&sr1_fck>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x480c9000 0x001000>; + + smartreflex_mpu_iva: smartreflex@480c9000 { + compatible = "ti,omap3-smartreflex-mpu-iva"; + reg = <0 0x400>; + interrupts = <18>; + }; + }; }; thermal_zones: thermal-zones { diff --git a/arch/arm/boot/dts/omap36xx.dtsi b/arch/arm/boot/dts/omap36xx.dtsi index ade31d74c70c..6fb23ada1f64 100644 --- a/arch/arm/boot/dts/omap36xx.dtsi +++ b/arch/arm/boot/dts/omap36xx.dtsi @@ -8,6 +8,7 @@ * kind, whether express or implied. */ +#include #include #include "omap3.dtsi" @@ -93,6 +94,51 @@ compatible = "ti,omap36xx-bandgap"; #thermal-sensor-cells = <0>; }; + + target-module@480cb000 { + compatible = "ti,sysc-omap3630-sr", "ti,sysc"; + ti,hwmods = "smartreflex_core"; + reg = <0x480cb038 0x4>; + reg-names = "sysc"; + ti,sysc-mask = ; + ti,sysc-sidle = , + , + ; + clocks = <&sr2_fck>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x480cb000 0x001000>; + + smartreflex_core: smartreflex@0 { + compatible = "ti,omap3-smartreflex-core"; + reg = <0 0x400>; + interrupts = <19>; + }; + }; + + target-module@480c9000 { + compatible = "ti,sysc-omap3630-sr", "ti,sysc"; + ti,hwmods = "smartreflex_mpu_iva"; + reg = <0x480c9038 0x4>; + reg-names = "sysc"; + ti,sysc-mask = ; + ti,sysc-sidle = , + , + ; + clocks = <&sr1_fck>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x480c9000 0x001000>; + + + smartreflex_mpu_iva: smartreflex@480c9000 { + compatible = "ti,omap3-smartreflex-mpu-iva"; + reg = <0 0x400>; + interrupts = <18>; + }; + }; }; thermal_zones: thermal-zones { diff --git a/arch/arm/boot/dts/omap4-droid4-xt894.dts b/arch/arm/boot/dts/omap4-droid4-xt894.dts index 24a463f8641f..b21084da490b 100644 --- a/arch/arm/boot/dts/omap4-droid4-xt894.dts +++ b/arch/arm/boot/dts/omap4-droid4-xt894.dts @@ -177,6 +177,10 @@ vddi-supply = <&lcd_regulator>; reset-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>; /* gpio101 */ + width-mm = <50>; + height-mm = <89>; + backlight = <&lcd_backlight>; + panel-timing { clock-frequency = <0>; /* Calculated by dsi */ @@ -346,7 +350,7 @@ enable-gpios = <&gpio6 12 GPIO_ACTIVE_HIGH>; - backlight { + lcd_backlight: backlight { compatible = "ti,lm3532-backlight"; lcd { diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index cc1a07a3620f..475904894b86 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -6,9 +6,12 @@ * published by the Free Software Foundation. */ +#include +#include #include #include #include +#include / { compatible = "ti,omap4430", "ti,omap4"; @@ -143,8 +146,11 @@ ranges = <0 0x4a000000 0x1000000>; cm1: cm1@4000 { - compatible = "ti,omap4-cm1"; + compatible = "ti,omap4-cm1", "simple-bus"; reg = <0x4000 0x2000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x4000 0x2000>; cm1_clocks: clocks { #address-cells = <1>; @@ -156,8 +162,11 @@ }; cm2: cm2@8000 { - compatible = "ti,omap4-cm2"; + compatible = "ti,omap4-cm2", "simple-bus"; reg = <0x8000 0x3000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x8000 0x3000>; cm2_clocks: clocks { #address-cells = <1>; @@ -243,6 +252,9 @@ compatible = "ti,omap4-prm"; reg = <0x6000 0x3000>; interrupts = ; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x6000 0x3000>; prm_clocks: clocks { #address-cells = <1>; @@ -383,11 +395,18 @@ }; target-module@48076000 { - compatible = "ti,sysc-omap4"; + compatible = "ti,sysc-omap4", "ti,sysc"; ti,hwmods = "slimbus2"; reg = <0x48076000 0x4>, <0x48076010 0x4>; reg-names = "rev", "sysc"; + ti,sysc-mask = ; + ti,sysc-sidle = , + , + , + ; + clocks = <&l4_per_clkctrl OMAP4_SLIMBUS2_CLKCTRL 0>; + clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x48076000 0x001000>; @@ -456,11 +475,17 @@ }; target-module@4a0db000 { - compatible = "ti,sysc-sr"; + compatible = "ti,sysc-omap4-sr", "ti,sysc"; ti,hwmods = "smartreflex_iva"; - reg = <0x4a0db000 0x4>, - <0x4a0db008 0x4>; - reg-names = "rev", "sysc"; + reg = <0x4a0db038 0x4>; + reg-names = "sysc"; + ti,sysc-mask = ; + ti,sysc-sidle = , + , + , + ; + clocks = <&l4_ao_clkctrl OMAP4_SMARTREFLEX_IVA_CLKCTRL 0>; + clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x4a0db000 0x001000>; @@ -473,11 +498,17 @@ }; target-module@4a0dd000 { - compatible = "ti,sysc-sr"; + compatible = "ti,sysc-omap4-sr", "ti,sysc"; ti,hwmods = "smartreflex_core"; - reg = <0x4a0dd000 0x4>, - <0x4a0dd008 0x4>; - reg-names = "rev", "sysc"; + reg = <0x4a0dd038 0x4>; + reg-names = "sysc"; + ti,sysc-mask = ; + ti,sysc-sidle = , + , + , + ; + clocks = <&l4_ao_clkctrl OMAP4_SMARTREFLEX_CORE_CLKCTRL 0>; + clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x4a0dd000 0x001000>; @@ -490,11 +521,17 @@ }; target-module@4a0d9000 { - compatible = "ti,sysc-sr"; + compatible = "ti,sysc-omap4-sr", "ti,sysc"; ti,hwmods = "smartreflex_mpu"; - reg = <0x4a0d9000 0x4>, - <0x4a0d9008 0x4>; - reg-names = "rev", "sysc"; + reg = <0x4a0d9038 0x4>; + reg-names = "sysc"; + ti,sysc-mask = ; + ti,sysc-sidle = , + , + , + ; + clocks = <&l4_ao_clkctrl OMAP4_SMARTREFLEX_MPU_CLKCTRL 0>; + clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x4a0d9000 0x001000>; @@ -674,7 +711,7 @@ reg-names = "sys", "gdd"; ti,hwmods = "hsi"; - clocks = <&hsi_fck>; + clocks = <&l3_init_clkctrl OMAP4_HSI_CLKCTRL 0>; clock-names = "hsi_fck"; interrupts = ; @@ -710,11 +747,23 @@ }; target-module@52000000 { - compatible = "ti,sysc-omap4"; + compatible = "ti,sysc-omap4", "ti,sysc"; ti,hwmods = "iss"; reg = <0x52000000 0x4>, <0x52000010 0x4>; reg-names = "rev", "sysc"; + ti,sysc-mask = ; + ti,sysc-midle = , + , + , + ; + ti,sysc-sidle = , + , + , + ; + ti,sysc-delay-us = <2>; + clocks = <&iss_clkctrl OMAP4_ISS_CLKCTRL 0>; + clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x52000000 0x1000000>; @@ -817,10 +866,17 @@ }; target-module@40128000 { - compatible = "ti,sysc-mcasp"; + compatible = "ti,sysc-mcasp", "ti,sysc"; ti,hwmods = "mcasp"; - reg = <0x40128004 0x4>; - reg-names = "sysc"; + reg = <0x40128000 0x4>, + <0x40128004 0x4>; + reg-names = "rev", "sysc"; + ti,sysc-sidle = , + , + , + ; + clocks = <&abe_clkctrl OMAP4_MCASP_CLKCTRL 0>; + clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x40128000 0x1000>, /* MPU */ @@ -835,11 +891,18 @@ }; target-module@4012c000 { - compatible = "ti,sysc-omap4"; + compatible = "ti,sysc-omap4", "ti,sysc"; ti,hwmods = "slimbus1"; reg = <0x4012c000 0x4>, <0x4012c010 0x4>; reg-names = "rev", "sysc"; + ti,sysc-mask = ; + ti,sysc-sidle = , + , + , + ; + clocks = <&abe_clkctrl OMAP4_SLIMBUS1_CLKCTRL 0>; + clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x4012c000 0x1000>, /* MPU */ @@ -849,11 +912,20 @@ }; target-module@401f1000 { - compatible = "ti,sysc-omap4"; + compatible = "ti,sysc-omap4", "ti,sysc"; ti,hwmods = "aess"; reg = <0x401f1000 0x4>, <0x401f1010 0x4>; reg-names = "rev", "sysc"; + ti,sysc-midle = , + , + , + ; + ti,sysc-sidle = , + , + ; + clocks = <&abe_clkctrl OMAP4_AESS_CLKCTRL 0>; + clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; ranges = <0x00000000 0x401f1000 0x1000>, /* MPU */ @@ -955,11 +1027,21 @@ }; target-module@4a10a000 { - compatible = "ti,sysc-omap4"; + compatible = "ti,sysc-omap4", "ti,sysc"; ti,hwmods = "fdif"; reg = <0x4a10a000 0x4>, <0x4a10a010 0x4>; reg-names = "rev", "sysc"; + ti,sysc-mask = ; + ti,sysc-midle = , + , + ; + ti,sysc-sidle = , + , + ; + ti,sysc-delay-us = <2>; + clocks = <&iss_clkctrl OMAP4_FDIF_CLKCTRL 0>; + clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x4a10a000 0x1000>; @@ -973,6 +1055,8 @@ interrupts = ; ti,hwmods = "timer1"; ti,timer-alwon; + clocks = <&l4_wkup_clkctrl OMAP4_TIMER1_CLKCTRL 24>; + clock-names = "fck"; }; timer2: timer@48032000 { @@ -1182,11 +1266,21 @@ }; target-module@56000000 { - compatible = "ti,sysc-omap4"; + compatible = "ti,sysc-omap4", "ti,sysc"; ti,hwmods = "gpu"; reg = <0x5601fc00 0x4>, <0x5601fc10 0x4>; reg-names = "rev", "sysc"; + ti,sysc-midle = , + , + , + ; + ti,sysc-sidle = , + , + , + ; + clocks = <&l3_gfx_clkctrl OMAP4_GPU_CLKCTRL 0>; + clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x56000000 0x2000000>; @@ -1202,7 +1296,7 @@ reg = <0x58000000 0x80>; status = "disabled"; ti,hwmods = "dss_core"; - clocks = <&dss_dss_clk>; + clocks = <&l3_dss_clkctrl OMAP4_DSS_CORE_CLKCTRL 8>; clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; @@ -1213,7 +1307,7 @@ reg = <0x58001000 0x1000>; interrupts = ; ti,hwmods = "dss_dispc"; - clocks = <&dss_dss_clk>; + clocks = <&l3_dss_clkctrl OMAP4_DSS_CORE_CLKCTRL 8>; clock-names = "fck"; }; @@ -1222,7 +1316,7 @@ reg = <0x58002000 0x1000>; status = "disabled"; ti,hwmods = "dss_rfbi"; - clocks = <&dss_dss_clk>, <&l3_div_ck>; + clocks = <&l3_dss_clkctrl OMAP4_DSS_CORE_CLKCTRL 8>, <&l3_div_ck>; clock-names = "fck", "ick"; }; @@ -1231,7 +1325,7 @@ reg = <0x58003000 0x1000>; status = "disabled"; ti,hwmods = "dss_venc"; - clocks = <&dss_tv_clk>; + clocks = <&l3_dss_clkctrl OMAP4_DSS_CORE_CLKCTRL 11>; clock-names = "fck"; }; @@ -1244,7 +1338,8 @@ interrupts = ; status = "disabled"; ti,hwmods = "dss_dsi1"; - clocks = <&dss_dss_clk>, <&dss_sys_clk>; + clocks = <&l3_dss_clkctrl OMAP4_DSS_CORE_CLKCTRL 8>, + <&l3_dss_clkctrl OMAP4_DSS_CORE_CLKCTRL 10>; clock-names = "fck", "sys_clk"; }; @@ -1257,7 +1352,8 @@ interrupts = ; status = "disabled"; ti,hwmods = "dss_dsi2"; - clocks = <&dss_dss_clk>, <&dss_sys_clk>; + clocks = <&l3_dss_clkctrl OMAP4_DSS_CORE_CLKCTRL 8>, + <&l3_dss_clkctrl OMAP4_DSS_CORE_CLKCTRL 10>; clock-names = "fck", "sys_clk"; }; @@ -1271,7 +1367,8 @@ interrupts = ; status = "disabled"; ti,hwmods = "dss_hdmi"; - clocks = <&dss_48mhz_clk>, <&dss_sys_clk>; + clocks = <&l3_dss_clkctrl OMAP4_DSS_CORE_CLKCTRL 9>, + <&l3_dss_clkctrl OMAP4_DSS_CORE_CLKCTRL 10>; clock-names = "fck", "sys_clk"; dmas = <&sdma 76>; dma-names = "audio_tx"; @@ -1280,4 +1377,4 @@ }; }; -/include/ "omap44xx-clocks.dtsi" +#include "omap44xx-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap44xx-clocks.dtsi b/arch/arm/boot/dts/omap44xx-clocks.dtsi index 05732ed4f50f..279ff2f419df 100644 --- a/arch/arm/boot/dts/omap44xx-clocks.dtsi +++ b/arch/arm/boot/dts/omap44xx-clocks.dtsi @@ -174,14 +174,6 @@ ti,index-power-of-two; }; - aess_fclk: aess_fclk@528 { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&abe_clk>; - ti,bit-shift = <24>; - ti,max-div = <2>; - reg = <0x0528>; - }; dpll_abe_m3x2_ck: dpll_abe_m3x2_ck@1f4 { #clock-cells = <0>; @@ -464,7 +456,7 @@ ocp_abe_iclk: ocp_abe_iclk@528 { #clock-cells = <0>; compatible = "ti,divider-clock"; - clocks = <&aess_fclk>; + clocks = <&abe_clkctrl OMAP4_AESS_CLKCTRL 24>; ti,bit-shift = <24>; reg = <0x0528>; ti,dividers = <2>, <1>; @@ -478,156 +470,13 @@ clock-div = <4>; }; - dmic_sync_mux_ck: dmic_sync_mux_ck@538 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>; - ti,bit-shift = <25>; - reg = <0x0538>; - }; - - func_dmic_abe_gfclk: func_dmic_abe_gfclk@538 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&dmic_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; - ti,bit-shift = <24>; - reg = <0x0538>; - }; - - mcasp_sync_mux_ck: mcasp_sync_mux_ck@540 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>; - ti,bit-shift = <25>; - reg = <0x0540>; - }; - - func_mcasp_abe_gfclk: func_mcasp_abe_gfclk@540 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&mcasp_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; - ti,bit-shift = <24>; - reg = <0x0540>; - }; - - mcbsp1_sync_mux_ck: mcbsp1_sync_mux_ck@548 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>; - ti,bit-shift = <25>; - reg = <0x0548>; - }; - - func_mcbsp1_gfclk: func_mcbsp1_gfclk@548 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&mcbsp1_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; - ti,bit-shift = <24>; - reg = <0x0548>; - }; - - mcbsp2_sync_mux_ck: mcbsp2_sync_mux_ck@550 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>; - ti,bit-shift = <25>; - reg = <0x0550>; - }; - - func_mcbsp2_gfclk: func_mcbsp2_gfclk@550 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&mcbsp2_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; - ti,bit-shift = <24>; - reg = <0x0550>; - }; - - mcbsp3_sync_mux_ck: mcbsp3_sync_mux_ck@558 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>; - ti,bit-shift = <25>; - reg = <0x0558>; - }; - - func_mcbsp3_gfclk: func_mcbsp3_gfclk@558 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&mcbsp3_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; - ti,bit-shift = <24>; - reg = <0x0558>; - }; - - slimbus1_fclk_1: slimbus1_fclk_1@560 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&func_24m_clk>; - ti,bit-shift = <9>; - reg = <0x0560>; - }; - - slimbus1_fclk_0: slimbus1_fclk_0@560 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&abe_24m_fclk>; - ti,bit-shift = <8>; - reg = <0x0560>; - }; - - slimbus1_fclk_2: slimbus1_fclk_2@560 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&pad_clks_ck>; - ti,bit-shift = <10>; - reg = <0x0560>; - }; - - slimbus1_slimbus_clk: slimbus1_slimbus_clk@560 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&slimbus_clk>; - ti,bit-shift = <11>; - reg = <0x0560>; - }; - - timer5_sync_mux: timer5_sync_mux@568 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&syc_clk_div_ck>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x0568>; - }; - - timer6_sync_mux: timer6_sync_mux@570 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&syc_clk_div_ck>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x0570>; - }; - - timer7_sync_mux: timer7_sync_mux@578 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&syc_clk_div_ck>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x0578>; - }; - - timer8_sync_mux: timer8_sync_mux@580 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&syc_clk_div_ck>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x0580>; - }; - dummy_ck: dummy_ck { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <0>; }; }; + &prm_clocks { sys_clkin_ck: sys_clkin_ck@110 { #clock-cells = <0>; @@ -675,22 +524,6 @@ ti,max-div = <2>; }; - gpio1_dbclk: gpio1_dbclk@1838 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1838>; - }; - - dmt1_clk_mux: dmt1_clk_mux@1840 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin_ck>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x1840>; - }; - usim_ck: usim_ck@1858 { #clock-cells = <0>; compatible = "ti,divider-clock"; @@ -708,45 +541,10 @@ reg = <0x1858>; }; - pmd_stm_clock_mux_ck: pmd_stm_clock_mux_ck@1a20 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin_ck>, <&dpll_core_m6x2_ck>, <&tie_low_clock_ck>; - ti,bit-shift = <20>; - reg = <0x1a20>; - }; - - pmd_trace_clk_mux_ck: pmd_trace_clk_mux_ck@1a20 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin_ck>, <&dpll_core_m6x2_ck>, <&tie_low_clock_ck>; - ti,bit-shift = <22>; - reg = <0x1a20>; - }; - - stm_clk_div_ck: stm_clk_div_ck@1a20 { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&pmd_stm_clock_mux_ck>; - ti,bit-shift = <27>; - ti,max-div = <64>; - reg = <0x1a20>; - ti,index-power-of-two; - }; - - trace_clk_div_div_ck: trace_clk_div_div_ck@1a20 { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&pmd_trace_clk_mux_ck>; - ti,bit-shift = <24>; - reg = <0x1a20>; - ti,dividers = <0>, <1>, <2>, <0>, <4>; - }; - trace_clk_div_ck: trace_clk_div_ck { #clock-cells = <0>; compatible = "ti,clkdm-gate-clock"; - clocks = <&trace_clk_div_div_ck>; + clocks = <&emu_sys_clkctrl OMAP4_DEBUGSS_CLKCTRL 24>; }; }; @@ -975,155 +773,6 @@ ti,max-div = <2>; }; - dss_sys_clk: dss_sys_clk@1120 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&syc_clk_div_ck>; - ti,bit-shift = <10>; - reg = <0x1120>; - }; - - dss_tv_clk: dss_tv_clk@1120 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&extalt_clkin_ck>; - ti,bit-shift = <11>; - reg = <0x1120>; - }; - - dss_dss_clk: dss_dss_clk@1120 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&dpll_per_m5x2_ck>; - ti,bit-shift = <8>; - reg = <0x1120>; - ti,set-rate-parent; - }; - - dss_48mhz_clk: dss_48mhz_clk@1120 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&func_48mc_fclk>; - ti,bit-shift = <9>; - reg = <0x1120>; - }; - - fdif_fck: fdif_fck@1028 { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&dpll_per_m4x2_ck>; - ti,bit-shift = <24>; - ti,max-div = <4>; - reg = <0x1028>; - ti,index-power-of-two; - }; - - gpio2_dbclk: gpio2_dbclk@1460 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1460>; - }; - - gpio3_dbclk: gpio3_dbclk@1468 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1468>; - }; - - gpio4_dbclk: gpio4_dbclk@1470 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1470>; - }; - - gpio5_dbclk: gpio5_dbclk@1478 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1478>; - }; - - gpio6_dbclk: gpio6_dbclk@1480 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1480>; - }; - - sgx_clk_mux: sgx_clk_mux@1220 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&dpll_core_m7x2_ck>, <&dpll_per_m7x2_ck>; - ti,bit-shift = <24>; - reg = <0x1220>; - }; - - hsi_fck: hsi_fck@1338 { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&dpll_per_m2x2_ck>; - ti,bit-shift = <24>; - ti,max-div = <4>; - reg = <0x1338>; - ti,index-power-of-two; - }; - - iss_ctrlclk: iss_ctrlclk@1020 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&func_96m_fclk>; - ti,bit-shift = <8>; - reg = <0x1020>; - }; - - mcbsp4_sync_mux_ck: mcbsp4_sync_mux_ck@14e0 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_96m_fclk>, <&per_abe_nc_fclk>; - ti,bit-shift = <25>; - reg = <0x14e0>; - }; - - per_mcbsp4_gfclk: per_mcbsp4_gfclk@14e0 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&mcbsp4_sync_mux_ck>, <&pad_clks_ck>; - ti,bit-shift = <24>; - reg = <0x14e0>; - }; - - hsmmc1_fclk: hsmmc1_fclk@1328 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_64m_fclk>, <&func_96m_fclk>; - ti,bit-shift = <24>; - reg = <0x1328>; - }; - - hsmmc2_fclk: hsmmc2_fclk@1330 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_64m_fclk>, <&func_96m_fclk>; - ti,bit-shift = <24>; - reg = <0x1330>; - }; - - ocp2scp_usb_phy_phy_48m: ocp2scp_usb_phy_phy_48m@13e0 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&func_48m_fclk>; - ti,bit-shift = <8>; - reg = <0x13e0>; - }; - sha2md5_fck: sha2md5_fck@15c8 { #clock-cells = <0>; compatible = "ti,gate-clock"; @@ -1132,222 +781,6 @@ reg = <0x15c8>; }; - slimbus2_fclk_1: slimbus2_fclk_1@1538 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&per_abe_24m_fclk>; - ti,bit-shift = <9>; - reg = <0x1538>; - }; - - slimbus2_fclk_0: slimbus2_fclk_0@1538 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&func_24mc_fclk>; - ti,bit-shift = <8>; - reg = <0x1538>; - }; - - slimbus2_slimbus_clk: slimbus2_slimbus_clk@1538 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&pad_slimbus_core_clks_ck>; - ti,bit-shift = <10>; - reg = <0x1538>; - }; - - smartreflex_core_fck: smartreflex_core_fck@638 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&l4_wkup_clk_mux_ck>; - ti,bit-shift = <1>; - reg = <0x0638>; - }; - - smartreflex_iva_fck: smartreflex_iva_fck@630 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&l4_wkup_clk_mux_ck>; - ti,bit-shift = <1>; - reg = <0x0630>; - }; - - smartreflex_mpu_fck: smartreflex_mpu_fck@628 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&l4_wkup_clk_mux_ck>; - ti,bit-shift = <1>; - reg = <0x0628>; - }; - - cm2_dm10_mux: cm2_dm10_mux@1428 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin_ck>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x1428>; - }; - - cm2_dm11_mux: cm2_dm11_mux@1430 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin_ck>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x1430>; - }; - - cm2_dm2_mux: cm2_dm2_mux@1438 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin_ck>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x1438>; - }; - - cm2_dm3_mux: cm2_dm3_mux@1440 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin_ck>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x1440>; - }; - - cm2_dm4_mux: cm2_dm4_mux@1448 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin_ck>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x1448>; - }; - - cm2_dm9_mux: cm2_dm9_mux@1450 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin_ck>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x1450>; - }; - - usb_host_fs_fck: usb_host_fs_fck@13d0 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&func_48mc_fclk>; - ti,bit-shift = <1>; - reg = <0x13d0>; - }; - - utmi_p1_gfclk: utmi_p1_gfclk@1358 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&init_60m_fclk>, <&xclk60mhsp1_ck>; - ti,bit-shift = <24>; - reg = <0x1358>; - }; - - usb_host_hs_utmi_p1_clk: usb_host_hs_utmi_p1_clk@1358 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&utmi_p1_gfclk>; - ti,bit-shift = <8>; - reg = <0x1358>; - }; - - utmi_p2_gfclk: utmi_p2_gfclk@1358 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&init_60m_fclk>, <&xclk60mhsp2_ck>; - ti,bit-shift = <25>; - reg = <0x1358>; - }; - - usb_host_hs_utmi_p2_clk: usb_host_hs_utmi_p2_clk@1358 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&utmi_p2_gfclk>; - ti,bit-shift = <9>; - reg = <0x1358>; - }; - - usb_host_hs_utmi_p3_clk: usb_host_hs_utmi_p3_clk@1358 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&init_60m_fclk>; - ti,bit-shift = <10>; - reg = <0x1358>; - }; - - usb_host_hs_hsic480m_p1_clk: usb_host_hs_hsic480m_p1_clk@1358 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&dpll_usb_m2_ck>; - ti,bit-shift = <13>; - reg = <0x1358>; - }; - - usb_host_hs_hsic60m_p1_clk: usb_host_hs_hsic60m_p1_clk@1358 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&init_60m_fclk>; - ti,bit-shift = <11>; - reg = <0x1358>; - }; - - usb_host_hs_hsic60m_p2_clk: usb_host_hs_hsic60m_p2_clk@1358 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&init_60m_fclk>; - ti,bit-shift = <12>; - reg = <0x1358>; - }; - - usb_host_hs_hsic480m_p2_clk: usb_host_hs_hsic480m_p2_clk@1358 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&dpll_usb_m2_ck>; - ti,bit-shift = <14>; - reg = <0x1358>; - }; - - usb_host_hs_func48mclk: usb_host_hs_func48mclk@1358 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&func_48mc_fclk>; - ti,bit-shift = <15>; - reg = <0x1358>; - }; - - usb_host_hs_fck: usb_host_hs_fck@1358 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&init_60m_fclk>; - ti,bit-shift = <1>; - reg = <0x1358>; - }; - - otg_60m_gfclk: otg_60m_gfclk@1360 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&utmi_phy_clkout_ck>, <&xclk60motg_ck>; - ti,bit-shift = <24>; - reg = <0x1360>; - }; - - usb_otg_hs_xclk: usb_otg_hs_xclk@1360 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&otg_60m_gfclk>; - ti,bit-shift = <8>; - reg = <0x1360>; - }; - - usb_otg_hs_ick: usb_otg_hs_ick@1360 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&l3_div_ck>; - ti,bit-shift = <0>; - reg = <0x1360>; - }; - usb_phy_cm_clk32k: usb_phy_cm_clk32k@640 { #clock-cells = <0>; compatible = "ti,gate-clock"; @@ -1355,44 +788,12 @@ ti,bit-shift = <8>; reg = <0x0640>; }; - - usb_tll_hs_usb_ch2_clk: usb_tll_hs_usb_ch2_clk@1368 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&init_60m_fclk>; - ti,bit-shift = <10>; - reg = <0x1368>; - }; - - usb_tll_hs_usb_ch0_clk: usb_tll_hs_usb_ch0_clk@1368 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&init_60m_fclk>; - ti,bit-shift = <8>; - reg = <0x1368>; - }; - - usb_tll_hs_usb_ch1_clk: usb_tll_hs_usb_ch1_clk@1368 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&init_60m_fclk>; - ti,bit-shift = <9>; - reg = <0x1368>; - }; - - usb_tll_hs_ick: usb_tll_hs_ick@1368 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&l4_div_ck>; - ti,bit-shift = <0>; - reg = <0x1368>; - }; }; &cm2_clockdomains { l3_init_clkdm: l3_init_clkdm { compatible = "ti,clockdomain"; - clocks = <&dpll_usb_ck>, <&usb_host_fs_fck>; + clocks = <&dpll_usb_ck>; }; }; @@ -1631,3 +1032,291 @@ reg = <0x0224>; }; }; + +&cm1 { + mpuss_cm: mpuss_cm@300 { + compatible = "ti,omap4-cm"; + reg = <0x300 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x300 0x100>; + + mpuss_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + tesla_cm: tesla_cm@400 { + compatible = "ti,omap4-cm"; + reg = <0x400 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x400 0x100>; + + tesla_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + abe_cm: abe_cm@500 { + compatible = "ti,omap4-cm"; + reg = <0x500 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x500 0x100>; + + abe_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x6c>; + #clock-cells = <2>; + }; + }; + +}; + +&cm2 { + l4_ao_cm: l4_ao_cm@600 { + compatible = "ti,omap4-cm"; + reg = <0x600 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x600 0x100>; + + l4_ao_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x1c>; + #clock-cells = <2>; + }; + }; + + l3_1_cm: l3_1_cm@700 { + compatible = "ti,omap4-cm"; + reg = <0x700 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x700 0x100>; + + l3_1_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + l3_2_cm: l3_2_cm@800 { + compatible = "ti,omap4-cm"; + reg = <0x800 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x800 0x100>; + + l3_2_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x14>; + #clock-cells = <2>; + }; + }; + + ducati_cm: ducati_cm@900 { + compatible = "ti,omap4-cm"; + reg = <0x900 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x900 0x100>; + + ducati_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + l3_dma_cm: l3_dma_cm@a00 { + compatible = "ti,omap4-cm"; + reg = <0xa00 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xa00 0x100>; + + l3_dma_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + l3_emif_cm: l3_emif_cm@b00 { + compatible = "ti,omap4-cm"; + reg = <0xb00 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xb00 0x100>; + + l3_emif_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x1c>; + #clock-cells = <2>; + }; + }; + + d2d_cm: d2d_cm@c00 { + compatible = "ti,omap4-cm"; + reg = <0xc00 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xc00 0x100>; + + d2d_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + l4_cfg_cm: l4_cfg_cm@d00 { + compatible = "ti,omap4-cm"; + reg = <0xd00 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xd00 0x100>; + + l4_cfg_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x14>; + #clock-cells = <2>; + }; + }; + + l3_instr_cm: l3_instr_cm@e00 { + compatible = "ti,omap4-cm"; + reg = <0xe00 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xe00 0x100>; + + l3_instr_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x24>; + #clock-cells = <2>; + }; + }; + + ivahd_cm: ivahd_cm@f00 { + compatible = "ti,omap4-cm"; + reg = <0xf00 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xf00 0x100>; + + ivahd_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0xc>; + #clock-cells = <2>; + }; + }; + + iss_cm: iss_cm@1000 { + compatible = "ti,omap4-cm"; + reg = <0x1000 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1000 0x100>; + + iss_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0xc>; + #clock-cells = <2>; + }; + }; + + l3_dss_cm: l3_dss_cm@1100 { + compatible = "ti,omap4-cm"; + reg = <0x1100 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1100 0x100>; + + l3_dss_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + l3_gfx_cm: l3_gfx_cm@1200 { + compatible = "ti,omap4-cm"; + reg = <0x1200 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1200 0x100>; + + l3_gfx_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + l3_init_cm: l3_init_cm@1300 { + compatible = "ti,omap4-cm"; + reg = <0x1300 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1300 0x100>; + + l3_init_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0xc4>; + #clock-cells = <2>; + }; + }; + + l4_per_cm: l4_per_cm@1400 { + compatible = "ti,omap4-cm"; + reg = <0x1400 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1400 0x200>; + + l4_per_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x144>; + #clock-cells = <2>; + }; + }; + +}; + +&prm { + l4_wkup_cm: l4_wkup_cm@1800 { + compatible = "ti,omap4-cm"; + reg = <0x1800 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1800 0x100>; + + l4_wkup_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x5c>; + #clock-cells = <2>; + }; + }; + + emu_sys_cm: emu_sys_cm@1a00 { + compatible = "ti,omap4-cm"; + reg = <0x1a00 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1a00 0x100>; + + emu_sys_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; +}; diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index 51a7fb3d7b9a..35d4298da83d 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -10,6 +10,7 @@ #include #include #include +#include / { #address-cells = <2>; @@ -201,8 +202,12 @@ }; cm_core_aon: cm_core_aon@4000 { - compatible = "ti,omap5-cm-core-aon"; + compatible = "ti,omap5-cm-core-aon", + "simple-bus"; reg = <0x4000 0x2000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x4000 0x2000>; cm_core_aon_clocks: clocks { #address-cells = <1>; @@ -214,8 +219,11 @@ }; cm_core: cm_core@8000 { - compatible = "ti,omap5-cm-core"; + compatible = "ti,omap5-cm-core", "simple-bus"; reg = <0x8000 0x3000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x8000 0x3000>; cm_core_clocks: clocks { #address-cells = <1>; @@ -240,9 +248,12 @@ }; prm: prm@6000 { - compatible = "ti,omap5-prm"; + compatible = "ti,omap5-prm", "simple-bus"; reg = <0x6000 0x3000>; interrupts = ; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x6000 0x3000>; prm_clocks: clocks { #address-cells = <1>; @@ -734,6 +745,8 @@ interrupts = ; ti,hwmods = "timer1"; ti,timer-alwon; + clocks = <&wkupaon_clkctrl OMAP5_TIMER1_CLKCTRL 24>; + clock-names = "fck"; }; timer2: timer@48032000 { @@ -893,7 +906,8 @@ compatible = "ti,omap-usb2"; reg = <0x4a084000 0x7c>; syscon-phy-power = <&scm_conf 0x300>; - clocks = <&usb_phy_cm_clk32k>, <&usb_otg_ss_refclk960m>; + clocks = <&usb_phy_cm_clk32k>, + <&l3init_clkctrl OMAP5_USB_OTG_SS_CLKCTRL 8>; clock-names = "wkupclk", "refclk"; #phy-cells = <0>; }; @@ -907,7 +921,7 @@ syscon-phy-power = <&scm_conf 0x370>; clocks = <&usb_phy_cm_clk32k>, <&sys_clkin>, - <&usb_otg_ss_refclk960m>; + <&l3init_clkctrl OMAP5_USB_OTG_SS_CLKCTRL 8>; clock-names = "wkupclk", "sysclk", "refclk"; @@ -976,7 +990,8 @@ <0x4A096800 0x40>; /* pll_ctrl */ reg-names = "phy_rx", "phy_tx", "pll_ctrl"; syscon-phy-power = <&scm_conf 0x374>; - clocks = <&sys_clkin>, <&sata_ref_clk>; + clocks = <&sys_clkin>, + <&l3init_clkctrl OMAP5_SATA_CLKCTRL 8>; clock-names = "sysclk", "refclk"; #phy-cells = <0>; }; @@ -988,7 +1003,7 @@ interrupts = ; phys = <&sata_phy>; phy-names = "sata-phy"; - clocks = <&sata_ref_clk>; + clocks = <&l3init_clkctrl OMAP5_SATA_CLKCTRL 8>; ti,hwmods = "sata"; ports-implemented = <0x1>; }; @@ -998,7 +1013,7 @@ reg = <0x58000000 0x80>; status = "disabled"; ti,hwmods = "dss_core"; - clocks = <&dss_dss_clk>; + clocks = <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 8>; clock-names = "fck"; #address-cells = <1>; #size-cells = <1>; @@ -1009,7 +1024,7 @@ reg = <0x58001000 0x1000>; interrupts = ; ti,hwmods = "dss_dispc"; - clocks = <&dss_dss_clk>; + clocks = <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 8>; clock-names = "fck"; }; @@ -1018,7 +1033,7 @@ reg = <0x58002000 0x100>; status = "disabled"; ti,hwmods = "dss_rfbi"; - clocks = <&dss_dss_clk>, <&l3_iclk_div>; + clocks = <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 8>, <&l3_iclk_div>; clock-names = "fck", "ick"; }; @@ -1031,7 +1046,8 @@ interrupts = ; status = "disabled"; ti,hwmods = "dss_dsi1"; - clocks = <&dss_dss_clk>, <&dss_sys_clk>; + clocks = <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 8>, + <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 10>; clock-names = "fck", "sys_clk"; }; @@ -1044,7 +1060,8 @@ interrupts = ; status = "disabled"; ti,hwmods = "dss_dsi2"; - clocks = <&dss_dss_clk>, <&dss_sys_clk>; + clocks = <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 8>, + <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 10>; clock-names = "fck", "sys_clk"; }; @@ -1058,7 +1075,8 @@ interrupts = ; status = "disabled"; ti,hwmods = "dss_hdmi"; - clocks = <&dss_48mhz_clk>, <&dss_sys_clk>; + clocks = <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 9>, + <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 10>; clock-names = "fck", "sys_clk"; dmas = <&sdma 76>; dma-names = "audio_tx"; @@ -1132,7 +1150,7 @@ coefficients = <65 (-1791)>; }; -/include/ "omap54xx-clocks.dtsi" +#include "omap54xx-clocks.dtsi" &gpu_thermal { coefficients = <117 (-2992)>; diff --git a/arch/arm/boot/dts/omap54xx-clocks.dtsi b/arch/arm/boot/dts/omap54xx-clocks.dtsi index 529193442620..9619a746d657 100644 --- a/arch/arm/boot/dts/omap54xx-clocks.dtsi +++ b/arch/arm/boot/dts/omap54xx-clocks.dtsi @@ -432,22 +432,6 @@ reg = <0x0528>; }; - dmic_sync_mux_ck: dmic_sync_mux_ck@538 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>; - ti,bit-shift = <26>; - reg = <0x0538>; - }; - - dmic_gfclk: dmic_gfclk@538 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&dmic_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; - ti,bit-shift = <24>; - reg = <0x0538>; - }; - mcasp_sync_mux_ck: mcasp_sync_mux_ck@540 { #clock-cells = <0>; compatible = "ti,mux-clock"; @@ -464,86 +448,6 @@ reg = <0x0540>; }; - mcbsp1_sync_mux_ck: mcbsp1_sync_mux_ck@548 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>; - ti,bit-shift = <26>; - reg = <0x0548>; - }; - - mcbsp1_gfclk: mcbsp1_gfclk@548 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&mcbsp1_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; - ti,bit-shift = <24>; - reg = <0x0548>; - }; - - mcbsp2_sync_mux_ck: mcbsp2_sync_mux_ck@550 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>; - ti,bit-shift = <26>; - reg = <0x0550>; - }; - - mcbsp2_gfclk: mcbsp2_gfclk@550 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&mcbsp2_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; - ti,bit-shift = <24>; - reg = <0x0550>; - }; - - mcbsp3_sync_mux_ck: mcbsp3_sync_mux_ck@558 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>; - ti,bit-shift = <26>; - reg = <0x0558>; - }; - - mcbsp3_gfclk: mcbsp3_gfclk@558 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&mcbsp3_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>; - ti,bit-shift = <24>; - reg = <0x0558>; - }; - - timer5_gfclk_mux: timer5_gfclk_mux@568 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&dss_syc_gfclk_div>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x0568>; - }; - - timer6_gfclk_mux: timer6_gfclk_mux@570 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&dss_syc_gfclk_div>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x0570>; - }; - - timer7_gfclk_mux: timer7_gfclk_mux@578 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&dss_syc_gfclk_div>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x0578>; - }; - - timer8_gfclk_mux: timer8_gfclk_mux@580 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&dss_syc_gfclk_div>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x0580>; - }; - dummy_ck: dummy_ck { #clock-cells = <0>; compatible = "fixed-clock"; @@ -603,23 +507,8 @@ clock-mult = <1>; clock-div = <1>; }; - - gpio1_dbclk: gpio1_dbclk@1938 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1938>; - }; - - timer1_gfclk_mux: timer1_gfclk_mux@1940 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x1940>; - }; }; + &cm_core_clocks { dpll_per_byp_mux: dpll_per_byp_mux@14c { @@ -825,95 +714,6 @@ ti,dividers = <1>, <8>; }; - dss_32khz_clk: dss_32khz_clk@1420 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <11>; - reg = <0x1420>; - }; - - dss_48mhz_clk: dss_48mhz_clk@1420 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&func_48m_fclk>; - ti,bit-shift = <9>; - reg = <0x1420>; - }; - - dss_dss_clk: dss_dss_clk@1420 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&dpll_per_h12x2_ck>; - ti,bit-shift = <8>; - reg = <0x1420>; - ti,set-rate-parent; - }; - - dss_sys_clk: dss_sys_clk@1420 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&dss_syc_gfclk_div>; - ti,bit-shift = <10>; - reg = <0x1420>; - }; - - gpio2_dbclk: gpio2_dbclk@1060 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1060>; - }; - - gpio3_dbclk: gpio3_dbclk@1068 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1068>; - }; - - gpio4_dbclk: gpio4_dbclk@1070 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1070>; - }; - - gpio5_dbclk: gpio5_dbclk@1078 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1078>; - }; - - gpio6_dbclk: gpio6_dbclk@1080 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1080>; - }; - - gpio7_dbclk: gpio7_dbclk@1110 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1110>; - }; - - gpio8_dbclk: gpio8_dbclk@1118 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1118>; - }; - iss_ctrlclk: iss_ctrlclk@1320 { #clock-cells = <0>; compatible = "ti,gate-clock"; @@ -938,118 +738,6 @@ reg = <0x0f20>; }; - mmc1_32khz_clk: mmc1_32khz_clk@1628 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_32k_ck>; - ti,bit-shift = <8>; - reg = <0x1628>; - }; - - sata_ref_clk: sata_ref_clk@1688 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&sys_clkin>; - ti,bit-shift = <8>; - reg = <0x1688>; - }; - - usb_host_hs_hsic480m_p1_clk: usb_host_hs_hsic480m_p1_clk@1658 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&dpll_usb_m2_ck>; - ti,bit-shift = <13>; - reg = <0x1658>; - }; - - usb_host_hs_hsic480m_p2_clk: usb_host_hs_hsic480m_p2_clk@1658 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&dpll_usb_m2_ck>; - ti,bit-shift = <14>; - reg = <0x1658>; - }; - - usb_host_hs_hsic480m_p3_clk: usb_host_hs_hsic480m_p3_clk@1658 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&dpll_usb_m2_ck>; - ti,bit-shift = <7>; - reg = <0x1658>; - }; - - usb_host_hs_hsic60m_p1_clk: usb_host_hs_hsic60m_p1_clk@1658 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&l3init_60m_fclk>; - ti,bit-shift = <11>; - reg = <0x1658>; - }; - - usb_host_hs_hsic60m_p2_clk: usb_host_hs_hsic60m_p2_clk@1658 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&l3init_60m_fclk>; - ti,bit-shift = <12>; - reg = <0x1658>; - }; - - usb_host_hs_hsic60m_p3_clk: usb_host_hs_hsic60m_p3_clk@1658 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&l3init_60m_fclk>; - ti,bit-shift = <6>; - reg = <0x1658>; - }; - - utmi_p1_gfclk: utmi_p1_gfclk@1658 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&l3init_60m_fclk>, <&xclk60mhsp1_ck>; - ti,bit-shift = <24>; - reg = <0x1658>; - }; - - usb_host_hs_utmi_p1_clk: usb_host_hs_utmi_p1_clk@1658 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&utmi_p1_gfclk>; - ti,bit-shift = <8>; - reg = <0x1658>; - }; - - utmi_p2_gfclk: utmi_p2_gfclk@1658 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&l3init_60m_fclk>, <&xclk60mhsp2_ck>; - ti,bit-shift = <25>; - reg = <0x1658>; - }; - - usb_host_hs_utmi_p2_clk: usb_host_hs_utmi_p2_clk@1658 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&utmi_p2_gfclk>; - ti,bit-shift = <9>; - reg = <0x1658>; - }; - - usb_host_hs_utmi_p3_clk: usb_host_hs_utmi_p3_clk@1658 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&l3init_60m_fclk>; - ti,bit-shift = <10>; - reg = <0x1658>; - }; - - usb_otg_ss_refclk960m: usb_otg_ss_refclk960m@16f0 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&dpll_usb_clkdcoldo>; - ti,bit-shift = <8>; - reg = <0x16f0>; - }; - usb_phy_cm_clk32k: usb_phy_cm_clk32k@640 { #clock-cells = <0>; compatible = "ti,gate-clock"; @@ -1058,30 +746,6 @@ reg = <0x0640>; }; - usb_tll_hs_usb_ch0_clk: usb_tll_hs_usb_ch0_clk@1668 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&l3init_60m_fclk>; - ti,bit-shift = <8>; - reg = <0x1668>; - }; - - usb_tll_hs_usb_ch1_clk: usb_tll_hs_usb_ch1_clk@1668 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&l3init_60m_fclk>; - ti,bit-shift = <9>; - reg = <0x1668>; - }; - - usb_tll_hs_usb_ch2_clk: usb_tll_hs_usb_ch2_clk@1668 { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&l3init_60m_fclk>; - ti,bit-shift = <10>; - reg = <0x1668>; - }; - fdif_fclk: fdif_fclk@1328 { #clock-cells = <0>; compatible = "ti,divider-clock"; @@ -1115,88 +779,6 @@ ti,max-div = <2>; reg = <0x1638>; }; - - mmc1_fclk_mux: mmc1_fclk_mux@1628 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_128m_clk>, <&dpll_per_m2x2_ck>; - ti,bit-shift = <24>; - reg = <0x1628>; - }; - - mmc1_fclk: mmc1_fclk@1628 { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&mmc1_fclk_mux>; - ti,bit-shift = <25>; - ti,max-div = <2>; - reg = <0x1628>; - }; - - mmc2_fclk_mux: mmc2_fclk_mux@1630 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&func_128m_clk>, <&dpll_per_m2x2_ck>; - ti,bit-shift = <24>; - reg = <0x1630>; - }; - - mmc2_fclk: mmc2_fclk@1630 { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&mmc2_fclk_mux>; - ti,bit-shift = <25>; - ti,max-div = <2>; - reg = <0x1630>; - }; - - timer10_gfclk_mux: timer10_gfclk_mux@1028 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x1028>; - }; - - timer11_gfclk_mux: timer11_gfclk_mux@1030 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x1030>; - }; - - timer2_gfclk_mux: timer2_gfclk_mux@1038 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x1038>; - }; - - timer3_gfclk_mux: timer3_gfclk_mux@1040 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x1040>; - }; - - timer4_gfclk_mux: timer4_gfclk_mux@1048 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x1048>; - }; - - timer9_gfclk_mux: timer9_gfclk_mux@1050 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x1050>; - }; }; &cm_core_clockdomains { @@ -1394,3 +976,206 @@ reg = <0x021c>; }; }; + +&cm_core_aon { + mpu_cm: mpu_cm@300 { + compatible = "ti,omap4-cm"; + reg = <0x300 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x300 0x100>; + + mpu_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + dsp_cm: dsp_cm@400 { + compatible = "ti,omap4-cm"; + reg = <0x400 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x400 0x100>; + + dsp_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + abe_cm: abe_cm@500 { + compatible = "ti,omap4-cm"; + reg = <0x500 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x500 0x100>; + + abe_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x64>; + #clock-cells = <2>; + }; + }; + +}; + +&cm_core { + l3main1_cm: l3main1_cm@700 { + compatible = "ti,omap4-cm"; + reg = <0x700 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x700 0x100>; + + l3main1_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + l3main2_cm: l3main2_cm@800 { + compatible = "ti,omap4-cm"; + reg = <0x800 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x800 0x100>; + + l3main2_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + ipu_cm: ipu_cm@900 { + compatible = "ti,omap4-cm"; + reg = <0x900 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x900 0x100>; + + ipu_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + dma_cm: dma_cm@a00 { + compatible = "ti,omap4-cm"; + reg = <0xa00 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xa00 0x100>; + + dma_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + emif_cm: emif_cm@b00 { + compatible = "ti,omap4-cm"; + reg = <0xb00 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xb00 0x100>; + + emif_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x1c>; + #clock-cells = <2>; + }; + }; + + l4cfg_cm: l4cfg_cm@d00 { + compatible = "ti,omap4-cm"; + reg = <0xd00 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xd00 0x100>; + + l4cfg_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x14>; + #clock-cells = <2>; + }; + }; + + l3instr_cm: l3instr_cm@e00 { + compatible = "ti,omap4-cm"; + reg = <0xe00 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xe00 0x100>; + + l3instr_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0xc>; + #clock-cells = <2>; + }; + }; + + l4per_cm: l4per_cm@1000 { + compatible = "ti,omap4-cm"; + reg = <0x1000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1000 0x200>; + + l4per_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x15c>; + #clock-cells = <2>; + }; + }; + + dss_cm: dss_cm@1400 { + compatible = "ti,omap4-cm"; + reg = <0x1400 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1400 0x100>; + + dss_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x4>; + #clock-cells = <2>; + }; + }; + + l3init_cm: l3init_cm@1600 { + compatible = "ti,omap4-cm"; + reg = <0x1600 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1600 0x100>; + + l3init_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0xd4>; + #clock-cells = <2>; + }; + }; +}; + +&prm { + wkupaon_cm: wkupaon_cm@1900 { + compatible = "ti,omap4-cm"; + reg = <0x1900 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1900 0x100>; + + wkupaon_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x5c>; + #clock-cells = <2>; + }; + }; +}; diff --git a/arch/arm/boot/dts/openbmc-flash-layout.dtsi b/arch/arm/boot/dts/openbmc-flash-layout.dtsi new file mode 100644 index 000000000000..6c26524e93e1 --- /dev/null +++ b/arch/arm/boot/dts/openbmc-flash-layout.dtsi @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0+ + +partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + u-boot@0 { + reg = <0x0 0x60000>; + label = "u-boot"; + }; + + u-boot-env@60000 { + reg = <0x60000 0x20000>; + label = "u-boot-env"; + }; + + kernel@80000 { + reg = <0x80000 0x440000>; + label = "kernel"; + }; + + rofs@c0000 { + reg = <0x4c0000 0x1740000>; + label = "rofs"; + }; + + rwfs@1c00000 { + reg = <0x1c00000 0x400000>; + label = "rwfs"; + }; +}; diff --git a/arch/arm/boot/dts/owl-s500-sparky.dts b/arch/arm/boot/dts/owl-s500-sparky.dts new file mode 100644 index 000000000000..c665ce8b88b4 --- /dev/null +++ b/arch/arm/boot/dts/owl-s500-sparky.dts @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Allo.com Sparky + * + * Copyright (c) 2017 Andreas Färber + */ + +/dts-v1/; + +#include "owl-s500.dtsi" + +/ { + compatible = "allo,sparky", "actions,s500"; + model = "Allo.com Sparky"; + + aliases { + serial3 = &uart3; + }; + + chosen { + stdout-path = "serial3:115200n8"; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x40000000>; /* 1 or 2 GiB */ + }; + + uart3_clk: uart3-clk { + compatible = "fixed-clock"; + clock-frequency = <921600>; + #clock-cells = <0>; + }; +}; + +&timer { + clocks = <&hosc>; +}; + +&uart3 { + status = "okay"; + clocks = <&uart3_clk>; +}; diff --git a/arch/arm/boot/dts/wd-mbwe.dts b/arch/arm/boot/dts/ox810se-wd-mbwe.dts similarity index 100% rename from arch/arm/boot/dts/wd-mbwe.dts rename to arch/arm/boot/dts/ox810se-wd-mbwe.dts diff --git a/arch/arm/boot/dts/cloudengines-pogoplug-series-3.dts b/arch/arm/boot/dts/ox820-cloudengines-pogoplug-series-3.dts similarity index 100% rename from arch/arm/boot/dts/cloudengines-pogoplug-series-3.dts rename to arch/arm/boot/dts/ox820-cloudengines-pogoplug-series-3.dts diff --git a/arch/arm/boot/dts/pm9g45.dts b/arch/arm/boot/dts/pm9g45.dts index be5177221cbb..927d00cab014 100644 --- a/arch/arm/boot/dts/pm9g45.dts +++ b/arch/arm/boot/dts/pm9g45.dts @@ -52,6 +52,18 @@ }; }; + tcb0: timer@fff7c000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + mmc0: mmc@fff80000 { pinctrl-0 = < &pinctrl_board_mmc diff --git a/arch/arm/boot/dts/qcom-msm8974-fairphone-fp2.dts b/arch/arm/boot/dts/qcom-msm8974-fairphone-fp2.dts index d0a5df90b543..643c57f84818 100644 --- a/arch/arm/boot/dts/qcom-msm8974-fairphone-fp2.dts +++ b/arch/arm/boot/dts/qcom-msm8974-fairphone-fp2.dts @@ -265,6 +265,28 @@ bias-pull-up; }; }; + + sdhc2_cd_pin_a: sdhc2-cd-pin-active { + pins = "gpio62"; + function = "gpio"; + + drive-strength = <2>; + bias-disable; + }; + + sdhc2_pin_a: sdhc2-pin-active { + clk { + pins = "sdc2_clk"; + drive-strength = <10>; + bias-disable; + }; + + cmd-data { + pins = "sdc2_cmd", "sdc2_data"; + drive-strength = <6>; + bias-pull-up; + }; + }; }; sdhci@f9824900 { @@ -280,6 +302,18 @@ pinctrl-0 = <&sdhc1_pin_a>; }; + sdhci@f98a4900 { + status = "ok"; + + vmmc-supply = <&pm8941_l21>; + vqmmc-supply = <&pm8941_l13>; + + bus-width = <4>; + + pinctrl-names = "default"; + pinctrl-0 = <&sdhc2_pin_a>, <&sdhc2_cd_pin_a>; + }; + usb@f9a55000 { status = "ok"; diff --git a/arch/arm/boot/dts/r7s72100-genmai.dts b/arch/arm/boot/dts/r7s72100-genmai.dts index cd4d5ff7749e..5af2a0116ff2 100644 --- a/arch/arm/boot/dts/r7s72100-genmai.dts +++ b/arch/arm/boot/dts/r7s72100-genmai.dts @@ -123,7 +123,7 @@ pinctrl-0 = <&i2c2_pins>; eeprom@50 { - compatible = "renesas,24c128", "atmel,24c128"; + compatible = "renesas,r1ex24128", "atmel,24c128"; reg = <0x50>; pagesize = <64>; }; diff --git a/arch/arm/boot/dts/r8a73a4.dtsi b/arch/arm/boot/dts/r8a73a4.dtsi index dd4d09712a2a..8e48090e4fdc 100644 --- a/arch/arm/boot/dts/r8a73a4.dtsi +++ b/arch/arm/boot/dts/r8a73a4.dtsi @@ -132,15 +132,12 @@ }; cmt1: timer@e6130000 { - compatible = "renesas,cmt-48-r8a73a4", "renesas,cmt-48-gen2"; + compatible = "renesas,r8a73a4-cmt1", "renesas,rcar-gen2-cmt1"; reg = <0 0xe6130000 0 0x1004>; interrupts = ; clocks = <&mstp3_clks R8A73A4_CLK_CMT1>; clock-names = "fck"; power-domains = <&pd_c5>; - - renesas,channels-mask = <0xff>; - status = "disabled"; }; diff --git a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts index 1788e186a512..03b00d87b39b 100644 --- a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts +++ b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts @@ -131,9 +131,8 @@ #address-cells = <1>; #size-cells = <0>; compatible = "i2c-gpio"; - gpios = <&pfc 208 GPIO_ACTIVE_HIGH /* sda */ - &pfc 91 GPIO_ACTIVE_HIGH /* scl */ - >; + sda-gpios = <&pfc 208 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&pfc 91 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; i2c-gpio,delay-us = <5>; }; diff --git a/arch/arm/boot/dts/r8a7740.dtsi b/arch/arm/boot/dts/r8a7740.dtsi index d37d22682a63..afd3bc5e6cf2 100644 --- a/arch/arm/boot/dts/r8a7740.dtsi +++ b/arch/arm/boot/dts/r8a7740.dtsi @@ -74,9 +74,6 @@ clocks = <&mstp3_clks R8A7740_CLK_CMT1>; clock-names = "fck"; power-domains = <&pd_c5>; - - renesas,channels-mask = <0x3f>; - status = "disabled"; }; @@ -320,7 +317,7 @@ tpu: pwm@e6600000 { compatible = "renesas,tpu-r8a7740", "renesas,tpu"; - reg = <0xe6600000 0x100>; + reg = <0xe6600000 0x148>; clocks = <&mstp3_clks R8A7740_CLK_TPU0>; power-domains = <&pd_a3sp>; status = "disabled"; diff --git a/arch/arm/boot/dts/r8a7743.dtsi b/arch/arm/boot/dts/r8a7743.dtsi index 7bbba4a36f31..0b74c6c7d21d 100644 --- a/arch/arm/boot/dts/r8a7743.dtsi +++ b/arch/arm/boot/dts/r8a7743.dtsi @@ -32,6 +32,40 @@ spi1 = &msiof0; spi2 = &msiof1; spi3 = &msiof2; + vin0 = &vin0; + vin1 = &vin1; + vin2 = &vin2; + }; + + /* + * The external audio clocks are configured as 0 Hz fixed frequency + * clocks by default. + * Boards that provide audio clocks should override them. + */ + audio_clk_a: audio_clk_a { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; + + audio_clk_b: audio_clk_b { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; + + audio_clk_c: audio_clk_c { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; + + /* External CAN clock */ + can_clk: can { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board. */ + clock-frequency = <0>; }; cpus { @@ -76,6 +110,29 @@ }; }; + /* External root clock */ + extal_clk: extal { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board. */ + clock-frequency = <0>; + }; + + /* External PCIe clock - can be overridden by the board */ + pcie_bus_clk: pcie_bus { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; + + /* External SCIF clock */ + scif_clk: scif { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board. */ + clock-frequency = <0>; + }; + soc { compatible = "simple-bus"; interrupt-parent = <&gic>; @@ -247,16 +304,48 @@ resets = <&cpg 407>; }; - timer { - compatible = "arm,armv7-timer"; - interrupts = , - , - , - ; + thermal: thermal@e61f0000 { + compatible = "renesas,thermal-r8a7743", + "renesas,rcar-gen2-thermal", + "renesas,rcar-thermal"; + reg = <0 0xe61f0000 0 0x10>, <0 0xe61f0100 0 0x38>; + interrupts = ; + clocks = <&cpg CPG_MOD 522>; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 522>; + #thermal-sensor-cells = <0>; + }; + + cmt0: timer@ffca0000 { + compatible = "renesas,r8a7743-cmt0", + "renesas,rcar-gen2-cmt0"; + reg = <0 0xffca0000 0 0x1004>; + interrupts = , + ; + clocks = <&cpg CPG_MOD 124>; + clock-names = "fck"; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 124>; + status = "disabled"; + }; + + cmt1: timer@e6130000 { + compatible = "renesas,r8a7743-cmt1", + "renesas,rcar-gen2-cmt1"; + reg = <0 0xe6130000 0 0x1004>; + interrupts = , + , + , + , + , + , + , + ; + clocks = <&cpg CPG_MOD 329>; + clock-names = "fck"; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 329>; + status = "disabled"; }; cpg: clock-controller@e6150000 { @@ -356,6 +445,68 @@ dma-channels = <15>; }; + audma0: dma-controller@ec700000 { + compatible = "renesas,dmac-r8a7743", + "renesas,rcar-dmac"; + reg = <0 0xec700000 0 0x10000>; + interrupts = ; + interrupt-names = "error", + "ch0", "ch1", "ch2", "ch3", + "ch4", "ch5", "ch6", "ch7", + "ch8", "ch9", "ch10", "ch11", + "ch12"; + clocks = <&cpg CPG_MOD 502>; + clock-names = "fck"; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 502>; + #dma-cells = <1>; + dma-channels = <13>; + }; + + audma1: dma-controller@ec720000 { + compatible = "renesas,dmac-r8a7743", + "renesas,rcar-dmac"; + reg = <0 0xec720000 0 0x10000>; + interrupts = ; + interrupt-names = "error", + "ch0", "ch1", "ch2", "ch3", + "ch4", "ch5", "ch6", "ch7", + "ch8", "ch9", "ch10", "ch11", + "ch12"; + clocks = <&cpg CPG_MOD 501>; + clock-names = "fck"; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 501>; + #dma-cells = <1>; + dma-channels = <13>; + }; + usb_dmac0: dma-controller@e65a0000 { compatible = "renesas,r8a7743-usb-dmac", "renesas,usb-dmac"; @@ -827,7 +978,8 @@ }; ether: ethernet@ee700000 { - compatible = "renesas,ether-r8a7743"; + compatible = "renesas,ether-r8a7743", + "renesas,rcar-gen2-ether"; reg = <0 0xee700000 0 0x400>; interrupts = ; clocks = <&cpg CPG_MOD 813>; @@ -952,8 +1104,89 @@ status = "disabled"; }; + pwm0: pwm@e6e30000 { + compatible = "renesas,pwm-r8a7743", "renesas,pwm-rcar"; + reg = <0 0xe6e30000 0 0x8>; + clocks = <&cpg CPG_MOD 523>; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 523>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm1: pwm@e6e31000 { + compatible = "renesas,pwm-r8a7743", "renesas,pwm-rcar"; + reg = <0 0xe6e31000 0 0x8>; + clocks = <&cpg CPG_MOD 523>; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 523>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm2: pwm@e6e32000 { + compatible = "renesas,pwm-r8a7743", "renesas,pwm-rcar"; + reg = <0 0xe6e32000 0 0x8>; + clocks = <&cpg CPG_MOD 523>; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 523>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm3: pwm@e6e33000 { + compatible = "renesas,pwm-r8a7743", "renesas,pwm-rcar"; + reg = <0 0xe6e33000 0 0x8>; + clocks = <&cpg CPG_MOD 523>; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 523>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm4: pwm@e6e34000 { + compatible = "renesas,pwm-r8a7743", "renesas,pwm-rcar"; + reg = <0 0xe6e34000 0 0x8>; + clocks = <&cpg CPG_MOD 523>; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 523>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm5: pwm@e6e35000 { + compatible = "renesas,pwm-r8a7743", "renesas,pwm-rcar"; + reg = <0 0xe6e35000 0 0x8>; + clocks = <&cpg CPG_MOD 523>; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 523>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm6: pwm@e6e36000 { + compatible = "renesas,pwm-r8a7743", "renesas,pwm-rcar"; + reg = <0 0xe6e36000 0 0x8>; + clocks = <&cpg CPG_MOD 523>; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 523>; + #pwm-cells = <2>; + status = "disabled"; + }; + + tpu: pwm@e60f0000 { + compatible = "renesas,tpu-r8a7743", "renesas,tpu"; + reg = <0 0xe60f0000 0 0x148>; + clocks = <&cpg CPG_MOD 304>; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 304>; + #pwm-cells = <3>; + status = "disabled"; + }; + sdhi0: sd@ee100000 { - compatible = "renesas,sdhi-r8a7743"; + compatible = "renesas,sdhi-r8a7743", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee100000 0 0x328>; interrupts = ; clocks = <&cpg CPG_MOD 314>; @@ -967,7 +1200,8 @@ }; sdhi1: sd@ee140000 { - compatible = "renesas,sdhi-r8a7743"; + compatible = "renesas,sdhi-r8a7743", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee140000 0 0x100>; interrupts = ; clocks = <&cpg CPG_MOD 312>; @@ -981,7 +1215,8 @@ }; sdhi2: sd@ee160000 { - compatible = "renesas,sdhi-r8a7743"; + compatible = "renesas,sdhi-r8a7743", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee160000 0 0x100>; interrupts = ; clocks = <&cpg CPG_MOD 311>; @@ -1033,6 +1268,97 @@ }; }; + vin0: video@e6ef0000 { + compatible = "renesas,vin-r8a7743", + "renesas,rcar-gen2-vin"; + reg = <0 0xe6ef0000 0 0x1000>; + interrupts = ; + clocks = <&cpg CPG_MOD 811>; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 811>; + status = "disabled"; + }; + + vin1: video@e6ef1000 { + compatible = "renesas,vin-r8a7743", + "renesas,rcar-gen2-vin"; + reg = <0 0xe6ef1000 0 0x1000>; + interrupts = ; + clocks = <&cpg CPG_MOD 810>; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 810>; + status = "disabled"; + }; + + vin2: video@e6ef2000 { + compatible = "renesas,vin-r8a7743", + "renesas,rcar-gen2-vin"; + reg = <0 0xe6ef2000 0 0x1000>; + interrupts = ; + clocks = <&cpg CPG_MOD 809>; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 809>; + status = "disabled"; + }; + + du: display@feb00000 { + compatible = "renesas,du-r8a7743"; + reg = <0 0xfeb00000 0 0x40000>, + <0 0xfeb90000 0 0x1c>; + reg-names = "du", "lvds.0"; + interrupts = , + ; + clocks = <&cpg CPG_MOD 724>, + <&cpg CPG_MOD 723>, + <&cpg CPG_MOD 726>; + clock-names = "du.0", "du.1", "lvds.0"; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + du_out_rgb: endpoint { + }; + }; + port@1 { + reg = <1>; + du_out_lvds0: endpoint { + }; + }; + }; + }; + + can0: can@e6e80000 { + compatible = "renesas,can-r8a7743", + "renesas,rcar-gen2-can"; + reg = <0 0xe6e80000 0 0x1000>; + interrupts = ; + clocks = <&cpg CPG_MOD 916>, + <&cpg CPG_CORE R8A7743_CLK_RCAN>, + <&can_clk>; + clock-names = "clkp1", "clkp2", "can_clk"; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 916>; + status = "disabled"; + }; + + can1: can@e6e88000 { + compatible = "renesas,can-r8a7743", + "renesas,rcar-gen2-can"; + reg = <0 0xe6e88000 0 0x1000>; + interrupts = ; + clocks = <&cpg CPG_MOD 915>, + <&cpg CPG_CORE R8A7743_CLK_RCAN>, + <&can_clk>; + clock-names = "clkp1", "clkp2", "can_clk"; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 915>; + status = "disabled"; + }; + pci0: pci@ee090000 { compatible = "renesas,pci-r8a7743", "renesas,pci-rcar-gen2"; @@ -1102,14 +1428,247 @@ phy-names = "usb"; }; }; + + pciec: pcie@fe000000 { + compatible = "renesas,pcie-r8a7743", + "renesas,pcie-rcar-gen2"; + reg = <0 0xfe000000 0 0x80000>; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x00 0xff>; + device_type = "pci"; + ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000 + 0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000 + 0x02000000 0 0x30000000 0 0x30000000 0 0x08000000 + 0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>; + /* Map all possible DDR as inbound ranges */ + dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x80000000 + 0x43000000 2 0x00000000 2 0x00000000 1 0x00000000>; + interrupts = , + , + ; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 319>, <&pcie_bus_clk>; + clock-names = "pcie", "pcie_bus"; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 319>; + status = "disabled"; + }; + + rcar_sound: sound@ec500000 { + /* + * #sound-dai-cells is required + * + * Single DAI : #sound-dai-cells = <0>; <&rcar_sound>; + * Multi DAI : #sound-dai-cells = <1>; <&rcar_sound N>; + */ + compatible = "renesas,rcar_sound-r8a7743", + "renesas,rcar_sound-gen2"; + reg = <0 0xec500000 0 0x1000>, /* SCU */ + <0 0xec5a0000 0 0x100>, /* ADG */ + <0 0xec540000 0 0x1000>, /* SSIU */ + <0 0xec541000 0 0x280>, /* SSI */ + <0 0xec740000 0 0x200>; /* Audio DMAC peri peri*/ + reg-names = "scu", "adg", "ssiu", "ssi", "audmapp"; + + clocks = <&cpg CPG_MOD 1005>, + <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>, + <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>, + <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>, + <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>, + <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>, + <&cpg CPG_MOD 1022>, <&cpg CPG_MOD 1023>, + <&cpg CPG_MOD 1024>, <&cpg CPG_MOD 1025>, + <&cpg CPG_MOD 1026>, <&cpg CPG_MOD 1027>, + <&cpg CPG_MOD 1028>, <&cpg CPG_MOD 1029>, + <&cpg CPG_MOD 1030>, <&cpg CPG_MOD 1031>, + <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>, + <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>, + <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>, + <&audio_clk_a>, <&audio_clk_b>, <&audio_clk_c>, + <&cpg CPG_CORE R8A7743_CLK_M2>; + clock-names = "ssi-all", + "ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5", + "ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0", + "src.9", "src.8", "src.7", "src.6", "src.5", + "src.4", "src.3", "src.2", "src.1", "src.0", + "ctu.0", "ctu.1", + "mix.0", "mix.1", + "dvc.0", "dvc.1", + "clk_a", "clk_b", "clk_c", "clk_i"; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 1005>, + <&cpg 1006>, <&cpg 1007>, <&cpg 1008>, <&cpg 1009>, + <&cpg 1010>, <&cpg 1011>, <&cpg 1012>, <&cpg 1013>, + <&cpg 1014>, <&cpg 1015>; + reset-names = "ssi-all", + "ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5", + "ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0"; + status = "disabled"; + + rcar_sound,dvc { + dvc0: dvc-0 { + dmas = <&audma1 0xbc>; + dma-names = "tx"; + }; + dvc1: dvc-1 { + dmas = <&audma1 0xbe>; + dma-names = "tx"; + }; + }; + + rcar_sound,mix { + mix0: mix-0 { }; + mix1: mix-1 { }; + }; + + rcar_sound,ctu { + ctu00: ctu-0 { }; + ctu01: ctu-1 { }; + ctu02: ctu-2 { }; + ctu03: ctu-3 { }; + ctu10: ctu-4 { }; + ctu11: ctu-5 { }; + ctu12: ctu-6 { }; + ctu13: ctu-7 { }; + }; + + rcar_sound,src { + src0: src-0 { + interrupts = ; + dmas = <&audma0 0x85>, <&audma1 0x9a>; + dma-names = "rx", "tx"; + }; + src1: src-1 { + interrupts = ; + dmas = <&audma0 0x87>, <&audma1 0x9c>; + dma-names = "rx", "tx"; + }; + src2: src-2 { + interrupts = ; + dmas = <&audma0 0x89>, <&audma1 0x9e>; + dma-names = "rx", "tx"; + }; + src3: src-3 { + interrupts = ; + dmas = <&audma0 0x8b>, <&audma1 0xa0>; + dma-names = "rx", "tx"; + }; + src4: src-4 { + interrupts = ; + dmas = <&audma0 0x8d>, <&audma1 0xb0>; + dma-names = "rx", "tx"; + }; + src5: src-5 { + interrupts = ; + dmas = <&audma0 0x8f>, <&audma1 0xb2>; + dma-names = "rx", "tx"; + }; + src6: src-6 { + interrupts = ; + dmas = <&audma0 0x91>, <&audma1 0xb4>; + dma-names = "rx", "tx"; + }; + src7: src-7 { + interrupts = ; + dmas = <&audma0 0x93>, <&audma1 0xb6>; + dma-names = "rx", "tx"; + }; + src8: src-8 { + interrupts = ; + dmas = <&audma0 0x95>, <&audma1 0xb8>; + dma-names = "rx", "tx"; + }; + src9: src-9 { + interrupts = ; + dmas = <&audma0 0x97>, <&audma1 0xba>; + dma-names = "rx", "tx"; + }; + }; + + rcar_sound,ssi { + ssi0: ssi-0 { + interrupts = ; + dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi1: ssi-1 { + interrupts = ; + dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi2: ssi-2 { + interrupts = ; + dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi3: ssi-3 { + interrupts = ; + dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi4: ssi-4 { + interrupts = ; + dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi5: ssi-5 { + interrupts = ; + dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi6: ssi-6 { + interrupts = ; + dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi7: ssi-7 { + interrupts = ; + dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi8: ssi-8 { + interrupts = ; + dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi9: ssi-9 { + interrupts = ; + dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + }; + }; }; - /* External root clock */ - extal_clk: extal { - compatible = "fixed-clock"; - #clock-cells = <0>; - /* This value must be overridden by the board. */ - clock-frequency = <0>; + thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&thermal>; + + trips { + cpu-crit { + temperature = <95000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + }; + }; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, + <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, + <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, + <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>; }; /* External USB clock - can be overridden by the board */ @@ -1118,12 +1677,4 @@ #clock-cells = <0>; clock-frequency = <48000000>; }; - - /* External SCIF clock */ - scif_clk: scif { - compatible = "fixed-clock"; - #clock-cells = <0>; - /* This value must be overridden by the board. */ - clock-frequency = <0>; - }; }; diff --git a/arch/arm/boot/dts/r8a7745-iwg22d-sodimm-dbhd-ca.dts b/arch/arm/boot/dts/r8a7745-iwg22d-sodimm-dbhd-ca.dts new file mode 100644 index 000000000000..d34de8266ccd --- /dev/null +++ b/arch/arm/boot/dts/r8a7745-iwg22d-sodimm-dbhd-ca.dts @@ -0,0 +1,158 @@ +/* + * Device Tree Source for the iWave-RZG1E SODIMM carrier board + HDMI daughter + * board + * + * Copyright (C) 2017 Renesas Electronics Corp. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include "r8a7745-iwg22d-sodimm.dts" + +/ { + model = "iWave RainboW-G22D-SODIMM RZ/G1E based board with HDMI add-on"; + compatible = "iwave,g22d", "iwave,g22m", "renesas,r8a7745"; + + aliases { + serial0 = &scif1; + serial4 = &scif5; + serial6 = &hscif2; + }; + + cec_clock: cec-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; + + hdmi-out { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con: endpoint { + remote-endpoint = <&adv7511_out>; + }; + }; + }; +}; + +&du { + pinctrl-0 = <&du0_pins>; + pinctrl-names = "default"; + + status = "okay"; + + ports { + port@0 { + endpoint { + remote-endpoint = <&adv7511_in>; + }; + }; + }; +}; + +&can1 { + pinctrl-0 = <&can1_pins>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&hscif2 { + pinctrl-0 = <&hscif2_pins>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_pins>; + pinctrl-names = "default"; + + status = "okay"; + clock-frequency = <400000>; + + hdmi@39 { + compatible = "adi,adv7511w"; + reg = <0x39>; + interrupt-parent = <&gpio1>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + clocks = <&cec_clock>; + clock-names = "cec"; + pd-gpios = <&gpio2 24 GPIO_ACTIVE_HIGH>; + + adi,input-depth = <8>; + adi,input-colorspace = "rgb"; + adi,input-clock = "1x"; + adi,input-style = <1>; + adi,input-justification = "evenly"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + adv7511_in: endpoint { + remote-endpoint = <&du_out_rgb0>; + }; + }; + + port@1 { + reg = <1>; + adv7511_out: endpoint { + remote-endpoint = <&hdmi_con>; + }; + }; + }; + }; +}; + +&pfc { + can1_pins: can1 { + groups = "can1_data_b"; + function = "can1"; + }; + + du0_pins: du0 { + groups = "du0_rgb888", "du0_sync", "du0_disp", "du0_clk0_out"; + function = "du0"; + }; + + hscif2_pins: hscif2 { + groups = "hscif2_data"; + function = "hscif2"; + }; + + i2c1_pins: i2c1 { + groups = "i2c1_d"; + function = "i2c1"; + }; + + scif1_pins: scif1 { + groups = "scif1_data"; + function = "scif1"; + }; + + scif5_pins: scif5 { + groups = "scif5_data_d"; + function = "scif5"; + }; +}; + +&scif1 { + pinctrl-0 = <&scif1_pins>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&scif5 { + pinctrl-0 = <&scif5_pins>; + pinctrl-names = "default"; + + status = "okay"; +}; diff --git a/arch/arm/boot/dts/r8a7745-iwg22d-sodimm.dts b/arch/arm/boot/dts/r8a7745-iwg22d-sodimm.dts index 52153ec3638c..a4058f4cfbcd 100644 --- a/arch/arm/boot/dts/r8a7745-iwg22d-sodimm.dts +++ b/arch/arm/boot/dts/r8a7745-iwg22d-sodimm.dts @@ -8,6 +8,29 @@ * kind, whether express or implied. */ +/* + * SSI-SGTL5000 + * + * This command is required when Playback/Capture + * + * amixer set "DVC Out" 100% + * amixer set "DVC In" 100% + * + * You can use Mute + * + * amixer set "DVC Out Mute" on + * amixer set "DVC In Mute" on + * + * You can use Volume Ramp + * + * amixer set "DVC Out Ramp Up Rate" "0.125 dB/64 steps" + * amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps" + * amixer set "DVC Out Ramp" on + * aplay xxx.wav & + * amixer set "DVC Out" 80% // Volume Down + * amixer set "DVC Out" 100% // Volume Up + */ + /dts-v1/; #include "r8a7745-iwg22m.dtsi" @@ -16,13 +39,35 @@ compatible = "iwave,g22d", "iwave,g22m", "renesas,r8a7745"; aliases { - serial0 = &scif4; ethernet0 = &avb; + serial3 = &scif4; + serial5 = &hscif1; }; chosen { bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp"; - stdout-path = "serial0:115200n8"; + stdout-path = "serial3:115200n8"; + }; + + audio_clock: audio_clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <26000000>; + }; + + rsnd_sgtl5000: sound { + compatible = "simple-audio-card"; + simple-audio-card,format = "i2s"; + simple-audio-card,bitclock-master = <&sndcodec>; + simple-audio-card,frame-master = <&sndcodec>; + + sndcpu: simple-audio-card,cpu { + sound-dai = <&rcar_sound>; + }; + + sndcodec: simple-audio-card,codec { + sound-dai = <&sgtl5000>; + }; }; vccq_sdhi0: regulator-vccq-sdhi0 { @@ -39,36 +84,6 @@ }; }; -&pfc { - scif4_pins: scif4 { - groups = "scif4_data_b"; - function = "scif4"; - }; - - avb_pins: avb { - groups = "avb_mdio", "avb_gmii"; - function = "avb"; - }; - - sdhi0_pins: sd0 { - groups = "sdhi0_data4", "sdhi0_ctrl"; - function = "sdhi0"; - power-source = <3300>; - }; - - usb1_pins: usb1 { - groups = "usb1"; - function = "usb1"; - }; -}; - -&scif4 { - pinctrl-0 = <&scif4_pins>; - pinctrl-names = "default"; - - status = "okay"; -}; - &avb { pinctrl-0 = <&avb_pins>; pinctrl-names = "default"; @@ -88,6 +103,122 @@ }; }; +&can0 { + pinctrl-0 = <&can0_pins>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&hscif1 { + pinctrl-0 = <&hscif1_pins>; + pinctrl-names = "default"; + + uart-has-rtscts; + status = "okay"; +}; + +&hsusb { + status = "okay"; + pinctrl-0 = <&usb0_pins>; + pinctrl-names = "default"; +}; + +&i2c5 { + pinctrl-0 = <&i2c5_pins>; + pinctrl-names = "default"; + + status = "okay"; + clock-frequency = <400000>; + + sgtl5000: codec@a { + compatible = "fsl,sgtl5000"; + #sound-dai-cells = <0>; + reg = <0x0a>; + clocks = <&audio_clock>; + VDDA-supply = <®_3p3v>; + VDDIO-supply = <®_3p3v>; + }; +}; + +&pci1 { + status = "okay"; + pinctrl-0 = <&usb1_pins>; + pinctrl-names = "default"; +}; + +&pfc { + avb_pins: avb { + groups = "avb_mdio", "avb_gmii"; + function = "avb"; + }; + + can0_pins: can0 { + groups = "can0_data"; + function = "can0"; + }; + + hscif1_pins: hscif1 { + groups = "hscif1_data", "hscif1_ctrl"; + function = "hscif1"; + }; + + i2c5_pins: i2c5 { + groups = "i2c5_b"; + function = "i2c5"; + }; + + scif4_pins: scif4 { + groups = "scif4_data_b"; + function = "scif4"; + }; + + sdhi0_pins: sd0 { + groups = "sdhi0_data4", "sdhi0_ctrl"; + function = "sdhi0"; + power-source = <3300>; + }; + + sound_pins: sound { + groups = "ssi34_ctrl", "ssi3_data", "ssi4_data"; + function = "ssi"; + }; + + usb0_pins: usb0 { + groups = "usb0"; + function = "usb0"; + }; + + usb1_pins: usb1 { + groups = "usb1"; + function = "usb1"; + }; +}; + +&rcar_sound { + pinctrl-0 = <&sound_pins>; + pinctrl-names = "default"; + status = "okay"; + + /* Single DAI */ + + #sound-dai-cells = <0>; + + rcar_sound,dai { + dai0 { + playback = <&ssi3 &src3 &dvc0>; + capture = <&ssi4 &src4 &dvc1>; + }; + }; +}; + +&scif4 { + pinctrl-0 = <&scif4_pins>; + pinctrl-names = "default"; + + status = "okay"; +}; + &sdhi0 { pinctrl-0 = <&sdhi0_pins>; pinctrl-names = "default"; @@ -98,10 +229,8 @@ status = "okay"; }; -&pci1 { - status = "okay"; - pinctrl-0 = <&usb1_pins>; - pinctrl-names = "default"; +&ssi4 { + shared-pin; }; &usbphy { diff --git a/arch/arm/boot/dts/r8a7745.dtsi b/arch/arm/boot/dts/r8a7745.dtsi index 3a50f703601c..ae918e9cce21 100644 --- a/arch/arm/boot/dts/r8a7745.dtsi +++ b/arch/arm/boot/dts/r8a7745.dtsi @@ -25,15 +25,49 @@ i2c3 = &i2c3; i2c4 = &i2c4; i2c5 = &i2c5; + i2c6 = &iic0; + i2c7 = &iic1; spi0 = &qspi; spi1 = &msiof0; spi2 = &msiof1; spi3 = &msiof2; + vin0 = &vin0; + vin1 = &vin1; + }; + + /* + * The external audio clocks are configured as 0 Hz fixed + * frequency clocks by default. Boards that provide audio + * clocks should override them. + */ + audio_clka: audio_clka { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; + audio_clkb: audio_clkb { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; + audio_clkc: audio_clkc { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; + + /* External CAN clock */ + can_clk: can { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board. */ + clock-frequency = <0>; }; cpus { #address-cells = <1>; #size-cells = <0>; + enable-method = "renesas,apmu"; cpu0: cpu@0 { device_type = "cpu"; @@ -45,6 +79,16 @@ next-level-cache = <&L2_CA7>; }; + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <1>; + clock-frequency = <1000000000>; + clocks = <&cpg CPG_CORE R8A7745_CLK_Z2>; + power-domains = <&sysc R8A7745_PD_CA7_CPU1>; + next-level-cache = <&L2_CA7>; + }; + L2_CA7: cache-controller-0 { compatible = "cache"; cache-unified; @@ -53,6 +97,22 @@ }; }; + /* External root clock */ + extal_clk: extal { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board. */ + clock-frequency = <0>; + }; + + /* External SCIF clock */ + scif_clk: scif { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board. */ + clock-frequency = <0>; + }; + soc { compatible = "simple-bus"; interrupt-parent = <&gic>; @@ -61,6 +121,12 @@ #size-cells = <2>; ranges; + apmu@e6151000 { + compatible = "renesas,r8a7745-apmu", "renesas,apmu"; + reg = <0 0xe6151000 0 0x188>; + cpus = <&cpu0 &cpu1>; + }; + gic: interrupt-controller@f1001000 { compatible = "arm,gic-400"; #interrupt-cells = <3>; @@ -203,16 +269,36 @@ resets = <&cpg 407>; }; - timer { - compatible = "arm,armv7-timer"; - interrupts = , - , - , - ; + cmt0: timer@ffca0000 { + compatible = "renesas,r8a7745-cmt0", + "renesas,rcar-gen2-cmt0"; + reg = <0 0xffca0000 0 0x1004>; + interrupts = , + ; + clocks = <&cpg CPG_MOD 124>; + clock-names = "fck"; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 124>; + status = "disabled"; + }; + + cmt1: timer@e6130000 { + compatible = "renesas,r8a7745-cmt1", + "renesas,rcar-gen2-cmt1"; + reg = <0 0xe6130000 0 0x1004>; + interrupts = , + , + , + , + , + , + , + ; + clocks = <&cpg CPG_MOD 329>; + clock-names = "fck"; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 329>; + status = "disabled"; }; cpg: clock-controller@e6150000 { @@ -312,6 +398,65 @@ dma-channels = <15>; }; + audma0: dma-controller@ec700000 { + compatible = "renesas,dmac-r8a7745", + "renesas,rcar-dmac"; + reg = <0 0xec700000 0 0x10000>; + interrupts = ; + interrupt-names = "error", + "ch0", "ch1", "ch2", "ch3", + "ch4", "ch5", "ch6", "ch7", + "ch8", "ch9", "ch10", "ch11", + "ch12"; + clocks = <&cpg CPG_MOD 502>; + clock-names = "fck"; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 502>; + #dma-cells = <1>; + dma-channels = <13>; + }; + + usb_dmac0: dma-controller@e65a0000 { + compatible = "renesas,r8a7745-usb-dmac", + "renesas,usb-dmac"; + reg = <0 0xe65a0000 0 0x100>; + interrupts = ; + interrupt-names = "ch0", "ch1"; + clocks = <&cpg CPG_MOD 330>; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 330>; + #dma-cells = <1>; + dma-channels = <2>; + }; + + usb_dmac1: dma-controller@e65b0000 { + compatible = "renesas,r8a7745-usb-dmac", + "renesas,usb-dmac"; + reg = <0 0xe65b0000 0 0x100>; + interrupts = ; + interrupt-names = "ch0", "ch1"; + clocks = <&cpg CPG_MOD 331>; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 331>; + #dma-cells = <1>; + dma-channels = <2>; + }; + scifa0: serial@e6c40000 { compatible = "renesas,scifa-r8a7745", "renesas,rcar-gen2-scifa", "renesas,scifa"; @@ -615,7 +760,8 @@ }; ether: ethernet@ee700000 { - compatible = "renesas,ether-r8a7745"; + compatible = "renesas,ether-r8a7745", + "renesas,rcar-gen2-ether"; reg = <0 0xee700000 0 0x400>; interrupts = ; clocks = <&cpg CPG_MOD 813>; @@ -724,6 +870,40 @@ status = "disabled"; }; + iic0: i2c@e6500000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,iic-r8a7745", + "renesas,rcar-gen2-iic", + "renesas,rmobile-iic"; + reg = <0 0xe6500000 0 0x425>; + interrupts = ; + clocks = <&cpg CPG_MOD 318>; + dmas = <&dmac0 0x61>, <&dmac0 0x62>, + <&dmac1 0x61>, <&dmac1 0x62>; + dma-names = "tx", "rx", "tx", "rx"; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 318>; + status = "disabled"; + }; + + iic1: i2c@e6510000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,iic-r8a7745", + "renesas,rcar-gen2-iic", + "renesas,rmobile-iic"; + reg = <0 0xe6510000 0 0x425>; + interrupts = ; + clocks = <&cpg CPG_MOD 323>; + dmas = <&dmac0 0x65>, <&dmac0 0x66>, + <&dmac1 0x65>, <&dmac1 0x66>; + dma-names = "tx", "rx", "tx", "rx"; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 323>; + status = "disabled"; + }; + mmcif0: mmc@ee200000 { compatible = "renesas,mmcif-r8a7745", "renesas,sh-mmcif"; @@ -756,6 +936,55 @@ status = "disabled"; }; + vin0: video@e6ef0000 { + compatible = "renesas,vin-r8a7745", + "renesas,rcar-gen2-vin"; + reg = <0 0xe6ef0000 0 0x1000>; + interrupts = ; + clocks = <&cpg CPG_MOD 811>; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 811>; + status = "disabled"; + }; + + vin1: video@e6ef1000 { + compatible = "renesas,vin-r8a7745", + "renesas,rcar-gen2-vin"; + reg = <0 0xe6ef1000 0 0x1000>; + interrupts = ; + clocks = <&cpg CPG_MOD 810>; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 810>; + status = "disabled"; + }; + + du: display@feb00000 { + compatible = "renesas,du-r8a7745"; + reg = <0 0xfeb00000 0 0x40000>; + reg-names = "du"; + interrupts = , + ; + clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>; + clock-names = "du.0", "du.1"; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + du_out_rgb0: endpoint { + }; + }; + port@1 { + reg = <1>; + du_out_rgb1: endpoint { + }; + }; + }; + }; + msiof0: spi@e6e20000 { compatible = "renesas,msiof-r8a7745", "renesas,rcar-gen2-msiof"; @@ -804,8 +1033,89 @@ status = "disabled"; }; + pwm0: pwm@e6e30000 { + compatible = "renesas,pwm-r8a7745", "renesas,pwm-rcar"; + reg = <0 0xe6e30000 0 0x8>; + clocks = <&cpg CPG_MOD 523>; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 523>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm1: pwm@e6e31000 { + compatible = "renesas,pwm-r8a7745", "renesas,pwm-rcar"; + reg = <0 0xe6e31000 0 0x8>; + clocks = <&cpg CPG_MOD 523>; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 523>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm2: pwm@e6e32000 { + compatible = "renesas,pwm-r8a7745", "renesas,pwm-rcar"; + reg = <0 0xe6e32000 0 0x8>; + clocks = <&cpg CPG_MOD 523>; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 523>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm3: pwm@e6e33000 { + compatible = "renesas,pwm-r8a7745", "renesas,pwm-rcar"; + reg = <0 0xe6e33000 0 0x8>; + clocks = <&cpg CPG_MOD 523>; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 523>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm4: pwm@e6e34000 { + compatible = "renesas,pwm-r8a7745", "renesas,pwm-rcar"; + reg = <0 0xe6e34000 0 0x8>; + clocks = <&cpg CPG_MOD 523>; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 523>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm5: pwm@e6e35000 { + compatible = "renesas,pwm-r8a7745", "renesas,pwm-rcar"; + reg = <0 0xe6e35000 0 0x8>; + clocks = <&cpg CPG_MOD 523>; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 523>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pwm6: pwm@e6e36000 { + compatible = "renesas,pwm-r8a7745", "renesas,pwm-rcar"; + reg = <0 0xe6e36000 0 0x8>; + clocks = <&cpg CPG_MOD 523>; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 523>; + #pwm-cells = <2>; + status = "disabled"; + }; + + tpu: pwm@e60f0000 { + compatible = "renesas,tpu-r8a7745", "renesas,tpu"; + reg = <0 0xe60f0000 0 0x148>; + clocks = <&cpg CPG_MOD 304>; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 304>; + #pwm-cells = <3>; + status = "disabled"; + }; + sdhi0: sd@ee100000 { - compatible = "renesas,sdhi-r8a7745"; + compatible = "renesas,sdhi-r8a7745", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee100000 0 0x328>; interrupts = ; clocks = <&cpg CPG_MOD 314>; @@ -819,7 +1129,8 @@ }; sdhi1: sd@ee140000 { - compatible = "renesas,sdhi-r8a7745"; + compatible = "renesas,sdhi-r8a7745", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee140000 0 0x100>; interrupts = ; clocks = <&cpg CPG_MOD 312>; @@ -833,7 +1144,8 @@ }; sdhi2: sd@ee160000 { - compatible = "renesas,sdhi-r8a7745"; + compatible = "renesas,sdhi-r8a7745", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee160000 0 0x100>; interrupts = ; clocks = <&cpg CPG_MOD 311>; @@ -916,6 +1228,23 @@ }; }; + hsusb: usb@e6590000 { + compatible = "renesas,usbhs-r8a7745", + "renesas,rcar-gen2-usbhs"; + reg = <0 0xe6590000 0 0x100>; + interrupts = ; + clocks = <&cpg CPG_MOD 704>; + dmas = <&usb_dmac0 0>, <&usb_dmac0 1>, + <&usb_dmac1 0>, <&usb_dmac1 1>; + dma-names = "ch0", "ch1", "ch2", "ch3"; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 704>; + renesas,buswait = <4>; + phys = <&usb0 1>; + phy-names = "usb"; + status = "disabled"; + }; + usbphy: usb-phy@e6590100 { compatible = "renesas,usb-phy-r8a7745", "renesas,rcar-gen2-usb-phy"; @@ -937,14 +1266,222 @@ #phy-cells = <1>; }; }; + + can0: can@e6e80000 { + compatible = "renesas,can-r8a7745", + "renesas,rcar-gen2-can"; + reg = <0 0xe6e80000 0 0x1000>; + interrupts = ; + clocks = <&cpg CPG_MOD 916>, + <&cpg CPG_CORE R8A7745_CLK_RCAN>, + <&can_clk>; + clock-names = "clkp1", "clkp2", "can_clk"; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 916>; + status = "disabled"; + }; + + can1: can@e6e88000 { + compatible = "renesas,can-r8a7745", + "renesas,rcar-gen2-can"; + reg = <0 0xe6e88000 0 0x1000>; + interrupts = ; + clocks = <&cpg CPG_MOD 915>, + <&cpg CPG_CORE R8A7745_CLK_RCAN>, + <&can_clk>; + clock-names = "clkp1", "clkp2", "can_clk"; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 915>; + status = "disabled"; + }; + + rcar_sound: sound@ec500000 { + /* + * #sound-dai-cells is required + * + * Single DAI : #sound-dai-cells = <0>; <&rcar_sound>; + * Multi DAI : #sound-dai-cells = <1>; <&rcar_sound N>; + */ + compatible = "renesas,rcar_sound-r8a7745", + "renesas,rcar_sound-gen2"; + reg = <0 0xec500000 0 0x1000>, /* SCU */ + <0 0xec5a0000 0 0x100>, /* ADG */ + <0 0xec540000 0 0x1000>, /* SSIU */ + <0 0xec541000 0 0x280>, /* SSI */ + <0 0xec740000 0 0x200>; /* Audio DMAC peri peri */ + reg-names = "scu", "adg", "ssiu", "ssi", "audmapp"; + + clocks = <&cpg CPG_MOD 1005>, + <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>, + <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>, + <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>, + <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>, + <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>, + <&cpg CPG_MOD 1025>, <&cpg CPG_MOD 1026>, + <&cpg CPG_MOD 1027>, <&cpg CPG_MOD 1028>, + <&cpg CPG_MOD 1029>, <&cpg CPG_MOD 1030>, + <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>, + <&cpg CPG_MOD 1021>, <&cpg CPG_MOD 1020>, + <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>, + <&audio_clka>, <&audio_clkb>, <&audio_clkc>, + <&cpg CPG_CORE R8A7745_CLK_M2>; + clock-names = "ssi-all", + "ssi.9", "ssi.8", "ssi.7", "ssi.6", + "ssi.5", "ssi.4", "ssi.3", "ssi.2", + "ssi.1", "ssi.0", + "src.6", "src.5", "src.4", "src.3", + "src.2", "src.1", + "ctu.0", "ctu.1", + "mix.0", "mix.1", + "dvc.0", "dvc.1", + "clk_a", "clk_b", "clk_c", "clk_i"; + power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; + resets = <&cpg 1005>, + <&cpg 1006>, <&cpg 1007>, <&cpg 1008>, + <&cpg 1009>, <&cpg 1010>, <&cpg 1011>, + <&cpg 1012>, <&cpg 1013>, <&cpg 1014>, + <&cpg 1015>; + reset-names = "ssi-all", + "ssi.9", "ssi.8", "ssi.7", "ssi.6", + "ssi.5", "ssi.4", "ssi.3", "ssi.2", + "ssi.1", "ssi.0"; + + status = "disabled"; + + rcar_sound,dvc { + dvc0: dvc-0 { + dmas = <&audma0 0xbc>; + dma-names = "tx"; + }; + dvc1: dvc-1 { + dmas = <&audma0 0xbe>; + dma-names = "tx"; + }; + }; + + rcar_sound,mix { + mix0: mix-0 { }; + mix1: mix-1 { }; + }; + + rcar_sound,ctu { + ctu00: ctu-0 { }; + ctu01: ctu-1 { }; + ctu02: ctu-2 { }; + ctu03: ctu-3 { }; + ctu10: ctu-4 { }; + ctu11: ctu-5 { }; + ctu12: ctu-6 { }; + ctu13: ctu-7 { }; + }; + + rcar_sound,src { + src-0 { + status = "disabled"; + }; + src1: src-1 { + interrupts = ; + dmas = <&audma0 0x87>, <&audma0 0x9c>; + dma-names = "rx", "tx"; + }; + src2: src-2 { + interrupts = ; + dmas = <&audma0 0x89>, <&audma0 0x9e>; + dma-names = "rx", "tx"; + }; + src3: src-3 { + interrupts = ; + dmas = <&audma0 0x8b>, <&audma0 0xa0>; + dma-names = "rx", "tx"; + }; + src4: src-4 { + interrupts = ; + dmas = <&audma0 0x8d>, <&audma0 0xb0>; + dma-names = "rx", "tx"; + }; + src5: src-5 { + interrupts = ; + dmas = <&audma0 0x8f>, <&audma0 0xb2>; + dma-names = "rx", "tx"; + }; + src6: src-6 { + interrupts = ; + dmas = <&audma0 0x91>, <&audma0 0xb4>; + dma-names = "rx", "tx"; + }; + }; + + rcar_sound,ssi { + ssi0: ssi-0 { + interrupts = ; + dmas = <&audma0 0x01>, <&audma0 0x02>, + <&audma0 0x15>, <&audma0 0x16>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi1: ssi-1 { + interrupts = ; + dmas = <&audma0 0x03>, <&audma0 0x04>, + <&audma0 0x49>, <&audma0 0x4a>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi2: ssi-2 { + interrupts = ; + dmas = <&audma0 0x05>, <&audma0 0x06>, + <&audma0 0x63>, <&audma0 0x64>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi3: ssi-3 { + interrupts = ; + dmas = <&audma0 0x07>, <&audma0 0x08>, + <&audma0 0x6f>, <&audma0 0x70>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi4: ssi-4 { + interrupts = ; + dmas = <&audma0 0x09>, <&audma0 0x0a>, + <&audma0 0x71>, <&audma0 0x72>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi5: ssi-5 { + interrupts = ; + dmas = <&audma0 0x0b>, <&audma0 0x0c>, + <&audma0 0x73>, <&audma0 0x74>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi6: ssi-6 { + interrupts = ; + dmas = <&audma0 0x0d>, <&audma0 0x0e>, + <&audma0 0x75>, <&audma0 0x76>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi7: ssi-7 { + interrupts = ; + dmas = <&audma0 0x0f>, <&audma0 0x10>, + <&audma0 0x79>, <&audma0 0x7a>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi8: ssi-8 { + interrupts = ; + dmas = <&audma0 0x11>, <&audma0 0x12>, + <&audma0 0x7b>, <&audma0 0x7c>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi9: ssi-9 { + interrupts = ; + dmas = <&audma0 0x13>, <&audma0 0x14>, + <&audma0 0x7d>, <&audma0 0x7e>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + }; + }; }; - /* External root clock */ - extal_clk: extal { - compatible = "fixed-clock"; - #clock-cells = <0>; - /* This value must be overridden by the board. */ - clock-frequency = <0>; + timer { + compatible = "arm,armv7-timer"; + interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, + <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, + <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, + <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>; }; /* External USB clock - can be overridden by the board */ @@ -953,12 +1490,4 @@ #clock-cells = <0>; clock-frequency = <48000000>; }; - - /* External SCIF clock */ - scif_clk: scif { - compatible = "fixed-clock"; - #clock-cells = <0>; - /* This value must be overridden by the board. */ - clock-frequency = <0>; - }; }; diff --git a/arch/arm/boot/dts/r8a7778.dtsi b/arch/arm/boot/dts/r8a7778.dtsi index a39472aab867..3b49f9ed2e2b 100644 --- a/arch/arm/boot/dts/r8a7778.dtsi +++ b/arch/arm/boot/dts/r8a7778.dtsi @@ -51,7 +51,8 @@ }; ether: ethernet@fde00000 { - compatible = "renesas,ether-r8a7778"; + compatible = "renesas,ether-r8a7778", + "renesas,rcar-gen1-ether"; reg = <0xfde00000 0x400>; interrupts = ; clocks = <&mstp1_clks R8A7778_CLK_ETHER>; @@ -379,7 +380,8 @@ }; sdhi0: sd@ffe4c000 { - compatible = "renesas,sdhi-r8a7778"; + compatible = "renesas,sdhi-r8a7778", + "renesas,rcar-gen1-sdhi"; reg = <0xffe4c000 0x100>; interrupts = ; clocks = <&mstp3_clks R8A7778_CLK_SDHI0>; @@ -388,7 +390,8 @@ }; sdhi1: sd@ffe4d000 { - compatible = "renesas,sdhi-r8a7778"; + compatible = "renesas,sdhi-r8a7778", + "renesas,rcar-gen1-sdhi"; reg = <0xffe4d000 0x100>; interrupts = ; clocks = <&mstp3_clks R8A7778_CLK_SDHI1>; @@ -397,7 +400,8 @@ }; sdhi2: sd@ffe4f000 { - compatible = "renesas,sdhi-r8a7778"; + compatible = "renesas,sdhi-r8a7778", + "renesas,rcar-gen1-sdhi"; reg = <0xffe4f000 0x100>; interrupts = ; clocks = <&mstp3_clks R8A7778_CLK_SDHI2>; diff --git a/arch/arm/boot/dts/r8a7779.dtsi b/arch/arm/boot/dts/r8a7779.dtsi index e8eb94748b27..e79ae306eedd 100644 --- a/arch/arm/boot/dts/r8a7779.dtsi +++ b/arch/arm/boot/dts/r8a7779.dtsi @@ -355,7 +355,8 @@ }; sdhi0: sd@ffe4c000 { - compatible = "renesas,sdhi-r8a7779"; + compatible = "renesas,sdhi-r8a7779", + "renesas,rcar-gen1-sdhi"; reg = <0xffe4c000 0x100>; interrupts = ; clocks = <&mstp3_clks R8A7779_CLK_SDHI0>; @@ -364,7 +365,8 @@ }; sdhi1: sd@ffe4d000 { - compatible = "renesas,sdhi-r8a7779"; + compatible = "renesas,sdhi-r8a7779", + "renesas,rcar-gen1-sdhi"; reg = <0xffe4d000 0x100>; interrupts = ; clocks = <&mstp3_clks R8A7779_CLK_SDHI1>; @@ -373,7 +375,8 @@ }; sdhi2: sd@ffe4e000 { - compatible = "renesas,sdhi-r8a7779"; + compatible = "renesas,sdhi-r8a7779", + "renesas,rcar-gen1-sdhi"; reg = <0xffe4e000 0x100>; interrupts = ; clocks = <&mstp3_clks R8A7779_CLK_SDHI2>; @@ -382,7 +385,8 @@ }; sdhi3: sd@ffe4f000 { - compatible = "renesas,sdhi-r8a7779"; + compatible = "renesas,sdhi-r8a7779", + "renesas,rcar-gen1-sdhi"; reg = <0xffe4f000 0x100>; interrupts = ; clocks = <&mstp3_clks R8A7779_CLK_SDHI3>; diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts index e3d27783b6b5..f2ea632381e7 100644 --- a/arch/arm/boot/dts/r8a7790-lager.dts +++ b/arch/arm/boot/dts/r8a7790-lager.dts @@ -272,9 +272,8 @@ #size-cells = <0>; compatible = "i2c-gpio"; status = "disabled"; - gpios = <&gpio1 17 GPIO_ACTIVE_HIGH /* sda */ - &gpio1 16 GPIO_ACTIVE_HIGH /* scl */ - >; + sda-gpios = <&gpio1 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&gpio1 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; i2c-gpio,delay-us = <5>; }; diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index 62baabd757b6..ed9a68538a55 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -168,7 +168,7 @@ trips { cpu-crit { - temperature = <115000>; + temperature = <95000>; hysteresis = <0>; type = "critical"; }; @@ -311,7 +311,7 @@ }; cmt0: timer@ffca0000 { - compatible = "renesas,cmt-48-r8a7790", "renesas,cmt-48-gen2"; + compatible = "renesas,r8a7790-cmt0", "renesas,rcar-gen2-cmt0"; reg = <0 0xffca0000 0 0x1004>; interrupts = , ; @@ -320,13 +320,11 @@ power-domains = <&sysc R8A7790_PD_ALWAYS_ON>; resets = <&cpg 124>; - renesas,channels-mask = <0x60>; - status = "disabled"; }; cmt1: timer@e6130000 { - compatible = "renesas,cmt-48-r8a7790", "renesas,cmt-48-gen2"; + compatible = "renesas,r8a7790-cmt1", "renesas,rcar-gen2-cmt1"; reg = <0 0xe6130000 0 0x1004>; interrupts = , , @@ -341,8 +339,6 @@ power-domains = <&sysc R8A7790_PD_ALWAYS_ON>; resets = <&cpg 329>; - renesas,channels-mask = <0xff>; - status = "disabled"; }; @@ -662,7 +658,8 @@ }; sdhi0: sd@ee100000 { - compatible = "renesas,sdhi-r8a7790"; + compatible = "renesas,sdhi-r8a7790", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee100000 0 0x328>; interrupts = ; clocks = <&cpg CPG_MOD 314>; @@ -676,7 +673,8 @@ }; sdhi1: sd@ee120000 { - compatible = "renesas,sdhi-r8a7790"; + compatible = "renesas,sdhi-r8a7790", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee120000 0 0x328>; interrupts = ; clocks = <&cpg CPG_MOD 313>; @@ -690,7 +688,8 @@ }; sdhi2: sd@ee140000 { - compatible = "renesas,sdhi-r8a7790"; + compatible = "renesas,sdhi-r8a7790", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee140000 0 0x100>; interrupts = ; clocks = <&cpg CPG_MOD 312>; @@ -704,7 +703,8 @@ }; sdhi3: sd@ee160000 { - compatible = "renesas,sdhi-r8a7790"; + compatible = "renesas,sdhi-r8a7790", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee160000 0 0x100>; interrupts = ; clocks = <&cpg CPG_MOD 311>; @@ -906,7 +906,8 @@ }; ether: ethernet@ee700000 { - compatible = "renesas,ether-r8a7790"; + compatible = "renesas,ether-r8a7790", + "renesas,rcar-gen2-ether"; reg = <0 0xee700000 0 0x400>; interrupts = ; clocks = <&cpg CPG_MOD 813>; diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts index e164eda69baf..a50924d12b6f 100644 --- a/arch/arm/boot/dts/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/r8a7791-koelsch.dts @@ -278,6 +278,12 @@ }; }; + cec_clock: cec-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; + hdmi-out { compatible = "hdmi-connector"; type = "a"; @@ -306,9 +312,8 @@ #size-cells = <0>; compatible = "i2c-gpio"; status = "disabled"; - gpios = <&gpio7 16 GPIO_ACTIVE_HIGH /* sda */ - &gpio7 15 GPIO_ACTIVE_HIGH /* scl */ - >; + sda-gpios = <&gpio7 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&gpio7 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; i2c-gpio,delay-us = <5>; }; @@ -640,12 +645,6 @@ }; }; - cec_clock: cec-clock { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <12000000>; - }; - hdmi@39 { compatible = "adi,adv7511w"; reg = <0x39>; @@ -708,7 +707,7 @@ }; eeprom@50 { - compatible = "renesas,24c02", "atmel,24c02"; + compatible = "renesas,r1ex24002", "atmel,24c02"; reg = <0x50>; pagesize = <16>; }; diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index 67831d0405f3..008a260f86a5 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -92,7 +92,7 @@ trips { cpu-crit { - temperature = <115000>; + temperature = <95000>; hysteresis = <0>; type = "critical"; }; @@ -257,7 +257,7 @@ }; cmt0: timer@ffca0000 { - compatible = "renesas,cmt-48-r8a7791", "renesas,cmt-48-gen2"; + compatible = "renesas,r8a7791-cmt0", "renesas,rcar-gen2-cmt0"; reg = <0 0xffca0000 0 0x1004>; interrupts = , ; @@ -266,13 +266,11 @@ power-domains = <&sysc R8A7791_PD_ALWAYS_ON>; resets = <&cpg 124>; - renesas,channels-mask = <0x60>; - status = "disabled"; }; cmt1: timer@e6130000 { - compatible = "renesas,cmt-48-r8a7791", "renesas,cmt-48-gen2"; + compatible = "renesas,r8a7791-cmt1", "renesas,rcar-gen2-cmt1"; reg = <0 0xe6130000 0 0x1004>; interrupts = , , @@ -287,8 +285,6 @@ power-domains = <&sysc R8A7791_PD_ALWAYS_ON>; resets = <&cpg 329>; - renesas,channels-mask = <0xff>; - status = "disabled"; }; @@ -612,7 +608,8 @@ }; sdhi0: sd@ee100000 { - compatible = "renesas,sdhi-r8a7791"; + compatible = "renesas,sdhi-r8a7791", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee100000 0 0x328>; interrupts = ; clocks = <&cpg CPG_MOD 314>; @@ -626,7 +623,8 @@ }; sdhi1: sd@ee140000 { - compatible = "renesas,sdhi-r8a7791"; + compatible = "renesas,sdhi-r8a7791", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee140000 0 0x100>; interrupts = ; clocks = <&cpg CPG_MOD 312>; @@ -640,7 +638,8 @@ }; sdhi2: sd@ee160000 { - compatible = "renesas,sdhi-r8a7791"; + compatible = "renesas,sdhi-r8a7791", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee160000 0 0x100>; interrupts = ; clocks = <&cpg CPG_MOD 311>; @@ -961,7 +960,8 @@ }; ether: ethernet@ee700000 { - compatible = "renesas,ether-r8a7791"; + compatible = "renesas,ether-r8a7791", + "renesas,rcar-gen2-ether"; reg = <0 0xee700000 0 0x400>; interrupts = ; clocks = <&cpg CPG_MOD 813>; diff --git a/arch/arm/boot/dts/r8a7792.dtsi b/arch/arm/boot/dts/r8a7792.dtsi index 3d080e07374c..3be15a158bad 100644 --- a/arch/arm/boot/dts/r8a7792.dtsi +++ b/arch/arm/boot/dts/r8a7792.dtsi @@ -36,6 +36,14 @@ vin5 = &vin5; }; + /* External CAN clock */ + can_clk: can { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board. */ + clock-frequency = <0>; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -69,6 +77,22 @@ }; }; + /* External root clock */ + extal_clk: extal { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board. */ + clock-frequency = <0>; + }; + + /* External SCIF clock */ + scif_clk: scif { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board. */ + clock-frequency = <0>; + }; + soc { compatible = "simple-bus"; interrupt-parent = <&gic>; @@ -113,18 +137,6 @@ resets = <&cpg 407>; }; - timer { - compatible = "arm,armv7-timer"; - interrupts = , - , - , - ; - }; - rst: reset-controller@e6160000 { compatible = "renesas,r8a7792-rst"; reg = <0 0xe6160000 0 0x0100>; @@ -507,7 +519,8 @@ }; sdhi0: sd@ee100000 { - compatible = "renesas,sdhi-r8a7792"; + compatible = "renesas,sdhi-r8a7792", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee100000 0 0x328>; interrupts = <0 165 IRQ_TYPE_LEVEL_HIGH>; dmas = <&dmac0 0xcd>, <&dmac0 0xce>, @@ -833,27 +846,11 @@ }; }; - /* External root clock */ - extal_clk: extal { - compatible = "fixed-clock"; - #clock-cells = <0>; - /* This value must be overridden by the board. */ - clock-frequency = <0>; - }; - - /* External SCIF clock */ - scif_clk: scif { - compatible = "fixed-clock"; - #clock-cells = <0>; - /* This value must be overridden by the board. */ - clock-frequency = <0>; - }; - - /* External CAN clock */ - can_clk: can { - compatible = "fixed-clock"; - #clock-cells = <0>; - /* This value must be overridden by the board. */ - clock-frequency = <0>; + timer { + compatible = "arm,armv7-timer"; + interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, + <&gic GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, + <&gic GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, + <&gic GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>; }; }; diff --git a/arch/arm/boot/dts/r8a7793.dtsi b/arch/arm/boot/dts/r8a7793.dtsi index 0cd1035de1a4..039b22517526 100644 --- a/arch/arm/boot/dts/r8a7793.dtsi +++ b/arch/arm/boot/dts/r8a7793.dtsi @@ -89,7 +89,7 @@ trips { cpu-crit { - temperature = <115000>; + temperature = <95000>; hysteresis = <0>; type = "critical"; }; @@ -248,7 +248,7 @@ }; cmt0: timer@ffca0000 { - compatible = "renesas,cmt-48-r8a7793", "renesas,cmt-48-gen2"; + compatible = "renesas,r8a7793-cmt0", "renesas,rcar-gen2-cmt0"; reg = <0 0xffca0000 0 0x1004>; interrupts = , ; @@ -257,13 +257,11 @@ power-domains = <&sysc R8A7793_PD_ALWAYS_ON>; resets = <&cpg 124>; - renesas,channels-mask = <0x60>; - status = "disabled"; }; cmt1: timer@e6130000 { - compatible = "renesas,cmt-48-r8a7793", "renesas,cmt-48-gen2"; + compatible = "renesas,r8a7793-cmt1", "renesas,rcar-gen2-cmt1"; reg = <0 0xe6130000 0 0x1004>; interrupts = , , @@ -278,8 +276,6 @@ power-domains = <&sysc R8A7793_PD_ALWAYS_ON>; resets = <&cpg 329>; - renesas,channels-mask = <0xff>; - status = "disabled"; }; @@ -562,7 +558,8 @@ }; sdhi0: sd@ee100000 { - compatible = "renesas,sdhi-r8a7793"; + compatible = "renesas,sdhi-r8a7793", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee100000 0 0x328>; interrupts = ; clocks = <&cpg CPG_MOD 314>; @@ -576,7 +573,8 @@ }; sdhi1: sd@ee140000 { - compatible = "renesas,sdhi-r8a7793"; + compatible = "renesas,sdhi-r8a7793", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee140000 0 0x100>; interrupts = ; clocks = <&cpg CPG_MOD 312>; @@ -590,7 +588,8 @@ }; sdhi2: sd@ee160000 { - compatible = "renesas,sdhi-r8a7793"; + compatible = "renesas,sdhi-r8a7793", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee160000 0 0x100>; interrupts = ; clocks = <&cpg CPG_MOD 311>; @@ -916,7 +915,8 @@ }; ether: ethernet@ee700000 { - compatible = "renesas,ether-r8a7793"; + compatible = "renesas,ether-r8a7793", + "renesas,rcar-gen2-ether"; reg = <0 0xee700000 0 0x400>; interrupts = ; clocks = <&cpg CPG_MOD 813>; diff --git a/arch/arm/boot/dts/r8a7794-alt.dts b/arch/arm/boot/dts/r8a7794-alt.dts index bd98790d964e..60c6515c4996 100644 --- a/arch/arm/boot/dts/r8a7794-alt.dts +++ b/arch/arm/boot/dts/r8a7794-alt.dts @@ -143,9 +143,8 @@ #size-cells = <0>; compatible = "i2c-gpio"; status = "disabled"; - gpios = <&gpio4 9 GPIO_ACTIVE_HIGH /* sda */ - &gpio4 8 GPIO_ACTIVE_HIGH /* scl */ - >; + sda-gpios = <&gpio4 9 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&gpio4 8 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; i2c-gpio,delay-us = <5>; }; diff --git a/arch/arm/boot/dts/r8a7794.dtsi b/arch/arm/boot/dts/r8a7794.dtsi index 5643976c1356..106b4e1649ff 100644 --- a/arch/arm/boot/dts/r8a7794.dtsi +++ b/arch/arm/boot/dts/r8a7794.dtsi @@ -37,6 +37,7 @@ cpus { #address-cells = <1>; #size-cells = <0>; + enable-method = "renesas,apmu"; cpu0: cpu@0 { device_type = "cpu"; @@ -66,6 +67,12 @@ }; }; + apmu@e6151000 { + compatible = "renesas,r8a7794-apmu", "renesas,apmu"; + reg = <0 0xe6151000 0 0x188>; + cpus = <&cpu0 &cpu1>; + }; + gic: interrupt-controller@f1001000 { compatible = "arm,gic-400"; #interrupt-cells = <3>; @@ -181,7 +188,7 @@ }; cmt0: timer@ffca0000 { - compatible = "renesas,cmt-48-gen2"; + compatible = "renesas,r8a7794-cmt0", "renesas,rcar-gen2-cmt0"; reg = <0 0xffca0000 0 0x1004>; interrupts = , ; @@ -190,13 +197,11 @@ power-domains = <&sysc R8A7794_PD_ALWAYS_ON>; resets = <&cpg 124>; - renesas,channels-mask = <0x60>; - status = "disabled"; }; cmt1: timer@e6130000 { - compatible = "renesas,cmt-48-gen2"; + compatible = "renesas,r8a7794-cmt1", "renesas,rcar-gen2-cmt1"; reg = <0 0xe6130000 0 0x1004>; interrupts = , , @@ -211,8 +216,6 @@ power-domains = <&sysc R8A7794_PD_ALWAYS_ON>; resets = <&cpg 329>; - renesas,channels-mask = <0xff>; - status = "disabled"; }; @@ -640,7 +643,8 @@ }; ether: ethernet@ee700000 { - compatible = "renesas,ether-r8a7794"; + compatible = "renesas,ether-r8a7794", + "renesas,rcar-gen2-ether"; reg = <0 0xee700000 0 0x400>; interrupts = ; clocks = <&cpg CPG_MOD 813>; @@ -791,7 +795,8 @@ }; sdhi0: sd@ee100000 { - compatible = "renesas,sdhi-r8a7794"; + compatible = "renesas,sdhi-r8a7794", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee100000 0 0x328>; interrupts = ; clocks = <&cpg CPG_MOD 314>; @@ -805,7 +810,8 @@ }; sdhi1: sd@ee140000 { - compatible = "renesas,sdhi-r8a7794"; + compatible = "renesas,sdhi-r8a7794", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee140000 0 0x100>; interrupts = ; clocks = <&cpg CPG_MOD 312>; @@ -819,7 +825,8 @@ }; sdhi2: sd@ee160000 { - compatible = "renesas,sdhi-r8a7794"; + compatible = "renesas,sdhi-r8a7794", + "renesas,rcar-gen2-sdhi"; reg = <0 0xee160000 0 0x100>; interrupts = ; clocks = <&cpg CPG_MOD 311>; diff --git a/arch/arm/boot/dts/rk3066a-rayeager.dts b/arch/arm/boot/dts/rk3066a-rayeager.dts index cdf301f5778b..4d7057a10a4c 100644 --- a/arch/arm/boot/dts/rk3066a-rayeager.dts +++ b/arch/arm/boot/dts/rk3066a-rayeager.dts @@ -177,6 +177,7 @@ phy0: ethernet-phy@0 { reg = <0>; + reset-gpios = <&gpio1 RK_PD6 GPIO_ACTIVE_LOW>; }; }; diff --git a/arch/arm/boot/dts/s3c2416-pinctrl.dtsi b/arch/arm/boot/dts/s3c2416-pinctrl.dtsi index 6274359fb323..92439ee5d7de 100644 --- a/arch/arm/boot/dts/s3c2416-pinctrl.dtsi +++ b/arch/arm/boot/dts/s3c2416-pinctrl.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung S3C2416 pinctrl settings * * Copyright (c) 2013 Heiko Stuebner - * - * 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. */ #include diff --git a/arch/arm/boot/dts/s3c2416-smdk2416.dts b/arch/arm/boot/dts/s3c2416-smdk2416.dts index f257926c13b7..a1c9d8c695cc 100644 --- a/arch/arm/boot/dts/s3c2416-smdk2416.dts +++ b/arch/arm/boot/dts/s3c2416-smdk2416.dts @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SAMSUNG SMDK2416 board device tree source * * Copyright (c) 2013 Heiko Stuebner - * - * 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. */ /dts-v1/; diff --git a/arch/arm/boot/dts/s3c2416.dtsi b/arch/arm/boot/dts/s3c2416.dtsi index 80f007550324..3c7385cab248 100644 --- a/arch/arm/boot/dts/s3c2416.dtsi +++ b/arch/arm/boot/dts/s3c2416.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's S3C2416 SoC device tree source * * Copyright (c) 2013 Heiko Stuebner - * - * 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. */ #include diff --git a/arch/arm/boot/dts/s3c24xx.dtsi b/arch/arm/boot/dts/s3c24xx.dtsi index 5ed43b857cc4..34c7fe6751cf 100644 --- a/arch/arm/boot/dts/s3c24xx.dtsi +++ b/arch/arm/boot/dts/s3c24xx.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's S3C24XX family device tree source * * Copyright (c) 2013 Heiko Stuebner - * - * 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. */ #include "skeleton.dtsi" diff --git a/arch/arm/boot/dts/s3c6400.dtsi b/arch/arm/boot/dts/s3c6400.dtsi index a7d1c8ec150d..8c28e8a0c824 100644 --- a/arch/arm/boot/dts/s3c6400.dtsi +++ b/arch/arm/boot/dts/s3c6400.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's S3C6400 SoC device tree source * @@ -10,11 +11,7 @@ * Note: This file does not include device nodes for all the controllers in * S3C6400 SoC. As device tree coverage for S3C6400 increases, additional * nodes can be added to this file. - * - * 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. -*/ + */ #include "s3c64xx.dtsi" diff --git a/arch/arm/boot/dts/s3c6410-mini6410.dts b/arch/arm/boot/dts/s3c6410-mini6410.dts index f4afda3594f8..f68601bd9c91 100644 --- a/arch/arm/boot/dts/s3c6410-mini6410.dts +++ b/arch/arm/boot/dts/s3c6410-mini6410.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's S3C6410 based Mini6410 board device tree source * @@ -5,11 +6,7 @@ * * Device tree source file for FriendlyARM Mini6410 board which is based on * Samsung's S3C6410 SoC. - * - * 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. -*/ + */ /dts-v1/; diff --git a/arch/arm/boot/dts/s3c6410-smdk6410.dts b/arch/arm/boot/dts/s3c6410-smdk6410.dts index ecf35ec466f7..b6b5afcd7602 100644 --- a/arch/arm/boot/dts/s3c6410-smdk6410.dts +++ b/arch/arm/boot/dts/s3c6410-smdk6410.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung S3C6410 based SMDK6410 board device tree source. * @@ -5,11 +6,7 @@ * * Device tree source file for SAMSUNG SMDK6410 board which is based on * Samsung's S3C6410 SoC. - * - * 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. -*/ + */ /dts-v1/; diff --git a/arch/arm/boot/dts/s3c6410.dtsi b/arch/arm/boot/dts/s3c6410.dtsi index eb4226b3407c..a766d6de696c 100644 --- a/arch/arm/boot/dts/s3c6410.dtsi +++ b/arch/arm/boot/dts/s3c6410.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's S3C6410 SoC device tree source * @@ -10,11 +11,7 @@ * Note: This file does not include device nodes for all the controllers in * S3C6410 SoC. As device tree coverage for S3C6410 increases, additional * nodes can be added to this file. - * - * 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. -*/ + */ #include "s3c64xx.dtsi" diff --git a/arch/arm/boot/dts/s3c64xx-pinctrl.dtsi b/arch/arm/boot/dts/s3c64xx-pinctrl.dtsi index 4e8e802b4ee1..8e9594d64b57 100644 --- a/arch/arm/boot/dts/s3c64xx-pinctrl.dtsi +++ b/arch/arm/boot/dts/s3c64xx-pinctrl.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's S3C64xx SoC series common device tree source * - pin control-related definitions @@ -6,10 +7,6 @@ * * Samsung's S3C64xx SoCs pin banks, pin-mux and pin-config options are * listed as device tree nodes in this file. - * - * 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. */ #include diff --git a/arch/arm/boot/dts/s3c64xx.dtsi b/arch/arm/boot/dts/s3c64xx.dtsi index c55cbb3af2c0..e2be3fbdd3f3 100644 --- a/arch/arm/boot/dts/s3c64xx.dtsi +++ b/arch/arm/boot/dts/s3c64xx.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's S3C64xx SoC series common device tree source * @@ -10,10 +11,6 @@ * Note: This file does not include device nodes for all the controllers in * S3C64xx SoCs. As device tree coverage for S3C64xx increases, additional * nodes can be added to this file. - * - * 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. */ #include "skeleton.dtsi" diff --git a/arch/arm/boot/dts/s5pv210-aquila.dts b/arch/arm/boot/dts/s5pv210-aquila.dts index 40139923eef0..14969b6529e8 100644 --- a/arch/arm/boot/dts/s5pv210-aquila.dts +++ b/arch/arm/boot/dts/s5pv210-aquila.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's S5PV210 SoC device tree source * @@ -7,10 +8,6 @@ * Tomasz Figa * * Board device tree source for Samsung Aquila board. - * - * 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. */ /dts-v1/; diff --git a/arch/arm/boot/dts/s5pv210-goni.dts b/arch/arm/boot/dts/s5pv210-goni.dts index c56f51ee7897..eb6d1926c0d6 100644 --- a/arch/arm/boot/dts/s5pv210-goni.dts +++ b/arch/arm/boot/dts/s5pv210-goni.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's S5PV210 SoC device tree source * @@ -7,10 +8,6 @@ * Tomasz Figa * * Board device tree source for Samsung Goni board. - * - * 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. */ /dts-v1/; diff --git a/arch/arm/boot/dts/s5pv210-pinctrl.dtsi b/arch/arm/boot/dts/s5pv210-pinctrl.dtsi index 9a3e851e2e22..3a79feab11c3 100644 --- a/arch/arm/boot/dts/s5pv210-pinctrl.dtsi +++ b/arch/arm/boot/dts/s5pv210-pinctrl.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's S5PV210 SoC device tree source * @@ -13,10 +14,6 @@ * Note: This file does not include device nodes for all the controllers in * S5PV210 SoC. As device tree coverage for S5PV210 increases, additional * nodes can be added to this file. - * - * 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. */ #include diff --git a/arch/arm/boot/dts/s5pv210-smdkc110.dts b/arch/arm/boot/dts/s5pv210-smdkc110.dts index 5d14da911aa5..e5aec6c526fb 100644 --- a/arch/arm/boot/dts/s5pv210-smdkc110.dts +++ b/arch/arm/boot/dts/s5pv210-smdkc110.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's S5PV210 SoC device tree source * @@ -11,10 +12,6 @@ * NOTE: This file is completely based on original board file for mach-smdkc110 * available in Linux 3.15 and intends to provide equivalent level of hardware * support. Due to lack of hardware, _no_ testing has been performed. - * - * 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. */ /dts-v1/; diff --git a/arch/arm/boot/dts/s5pv210-smdkv210.dts b/arch/arm/boot/dts/s5pv210-smdkv210.dts index 75398318ed57..84b38f185199 100644 --- a/arch/arm/boot/dts/s5pv210-smdkv210.dts +++ b/arch/arm/boot/dts/s5pv210-smdkv210.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's S5PV210 SoC device tree source * @@ -11,10 +12,6 @@ * NOTE: This file is completely based on original board file for mach-smdkv210 * available in Linux 3.15 and intends to provide equivalent level of hardware * support. Due to lack of hardware, _no_ testing has been performed. - * - * 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. */ /dts-v1/; diff --git a/arch/arm/boot/dts/s5pv210-torbreck.dts b/arch/arm/boot/dts/s5pv210-torbreck.dts index 7cb50bcee888..cd25e72ccd84 100644 --- a/arch/arm/boot/dts/s5pv210-torbreck.dts +++ b/arch/arm/boot/dts/s5pv210-torbreck.dts @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's S5PV210 SoC device tree source * @@ -11,10 +12,6 @@ * NOTE: This file is completely based on original board file for mach-torbreck * available in Linux 3.15 and intends to provide equivalent level of hardware * support. Due to lack of hardware, _no_ testing has been performed. - * - * 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. */ /dts-v1/; diff --git a/arch/arm/boot/dts/s5pv210.dtsi b/arch/arm/boot/dts/s5pv210.dtsi index 726c5d0dbd5b..67358562a6ea 100644 --- a/arch/arm/boot/dts/s5pv210.dtsi +++ b/arch/arm/boot/dts/s5pv210.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Samsung's S5PV210 SoC device tree source * @@ -13,11 +14,7 @@ * Note: This file does not include device nodes for all the controllers in * S5PV210 SoC. As device tree coverage for S5PV210 increases, additional * nodes can be added to this file. - * - * 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. -*/ + */ #include #include @@ -463,6 +460,7 @@ compatible = "samsung,exynos4210-ohci"; reg = <0xec300000 0x100>; interrupts = <23>; + interrupt-parent = <&vic1>; clocks = <&clocks CLK_USB_HOST>; clock-names = "usbhost"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index b44e63995583..61f68e5c48e9 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -1094,7 +1094,9 @@ }; tcb0: timer@f800c000 { - compatible = "atmel,at91sam9x5-tcb"; + compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xf800c000 0x100>; interrupts = <35 IRQ_TYPE_LEVEL_HIGH 0>; clocks = <&tcb0_clk>, <&clk32k>; @@ -1102,7 +1104,9 @@ }; tcb1: timer@f8010000 { - compatible = "atmel,at91sam9x5-tcb"; + compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xf8010000 0x100>; interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>; clocks = <&tcb1_clk>, <&clk32k>; @@ -1427,6 +1431,8 @@ interrupts = <40 IRQ_TYPE_LEVEL_HIGH 7>; clocks = <&adc_clk>; clock-names = "adc_clk"; + dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | AT91_XDMAC_DT_PERID(25))>; + dma-names = "rx"; atmel,min-sample-rate-hz = <200000>; atmel,max-sample-rate-hz = <20000000>; atmel,startup-time-ms = <4>; diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index 1889b4dea066..b9c05b57735e 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi @@ -142,7 +142,9 @@ }; tcb0: timer@f0010000 { - compatible = "atmel,at91sam9x5-tcb"; + compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xf0010000 0x100>; interrupts = <26 IRQ_TYPE_LEVEL_HIGH 0>; clocks = <&tcb0_clk>, <&clk32k>; diff --git a/arch/arm/boot/dts/sama5d3_tcb1.dtsi b/arch/arm/boot/dts/sama5d3_tcb1.dtsi index 801f9745e82f..cb30bdb1a9ca 100644 --- a/arch/arm/boot/dts/sama5d3_tcb1.dtsi +++ b/arch/arm/boot/dts/sama5d3_tcb1.dtsi @@ -28,7 +28,9 @@ }; tcb1: timer@f8014000 { - compatible = "atmel,at91sam9x5-tcb"; + compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xf8014000 0x100>; interrupts = <27 IRQ_TYPE_LEVEL_HIGH 0>; clocks = <&tcb1_clk>, <&clk32k>; diff --git a/arch/arm/boot/dts/sama5d3xcm.dtsi b/arch/arm/boot/dts/sama5d3xcm.dtsi index 9506daf5efb6..3311a882458b 100644 --- a/arch/arm/boot/dts/sama5d3xcm.dtsi +++ b/arch/arm/boot/dts/sama5d3xcm.dtsi @@ -34,6 +34,18 @@ spi0: spi@f0004000 { cs-gpios = <&pioD 13 0>, <0>, <0>, <0>; }; + + tcb0: timer@f0010000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; + }; }; ebi@10000000 { diff --git a/arch/arm/boot/dts/sama5d3xcm_cmp.dtsi b/arch/arm/boot/dts/sama5d3xcm_cmp.dtsi index 75cbf4d4ab1a..a02f59021364 100644 --- a/arch/arm/boot/dts/sama5d3xcm_cmp.dtsi +++ b/arch/arm/boot/dts/sama5d3xcm_cmp.dtsi @@ -69,6 +69,18 @@ cs-gpios = <&pioD 13 0>, <0>, <0>, <0>; }; + tcb0: timer@f0010000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; + }; + macb0: ethernet@f0028000 { phy-mode = "rgmii"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/sama5d3xmb.dtsi b/arch/arm/boot/dts/sama5d3xmb.dtsi index 7f55050dd405..ef0f2d049e15 100644 --- a/arch/arm/boot/dts/sama5d3xmb.dtsi +++ b/arch/arm/boot/dts/sama5d3xmb.dtsi @@ -53,7 +53,7 @@ }; i2c1: i2c@f0018000 { - ov2640: camera@0x30 { + ov2640: camera@30 { compatible = "ovti,ov2640"; reg = <0x30>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/sama5d3xmb_cmp.dtsi b/arch/arm/boot/dts/sama5d3xmb_cmp.dtsi index 83e3d3e08fd4..97e171db5970 100644 --- a/arch/arm/boot/dts/sama5d3xmb_cmp.dtsi +++ b/arch/arm/boot/dts/sama5d3xmb_cmp.dtsi @@ -88,7 +88,7 @@ }; i2c1: i2c@f0018000 { - ov2640: camera@0x30 { + ov2640: camera@30 { compatible = "ovti,ov2640"; reg = <0x30>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi index b069644ed238..373b3621b536 100644 --- a/arch/arm/boot/dts/sama5d4.dtsi +++ b/arch/arm/boot/dts/sama5d4.dtsi @@ -960,7 +960,9 @@ }; tcb0: timer@f801c000 { - compatible = "atmel,at91sam9x5-tcb"; + compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xf801c000 0x100>; interrupts = <40 IRQ_TYPE_LEVEL_HIGH 0>; clocks = <&tcb0_clk>, <&clk32k>; @@ -1188,13 +1190,25 @@ }; tcb1: timer@fc020000 { - compatible = "atmel,at91sam9x5-tcb"; + compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xfc020000 0x100>; interrupts = <41 IRQ_TYPE_LEVEL_HIGH 0>; clocks = <&tcb1_clk>, <&clk32k>; clock-names = "t0_clk", "slow_clk"; }; + tcb2: timer@fc024000 { + compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xfc024000 0x100>; + interrupts = <42 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&tcb2_clk>, <&clk32k>; + clock-names = "t0_clk", "slow_clk"; + }; + macb1: ethernet@fc028000 { compatible = "atmel,sama5d4-gem"; reg = <0xfc028000 0x100>; diff --git a/arch/arm/boot/dts/sh73a0.dtsi b/arch/arm/boot/dts/sh73a0.dtsi index 88d7e5631d34..914a7c2a584f 100644 --- a/arch/arm/boot/dts/sh73a0.dtsi +++ b/arch/arm/boot/dts/sh73a0.dtsi @@ -100,9 +100,6 @@ clocks = <&mstp3_clks SH73A0_CLK_CMT1>; clock-names = "fck"; power-domains = <&pd_c5>; - - renesas,channels-mask = <0x3f>; - status = "disabled"; }; diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 7e24dc8e82d4..c42ca7022e8c 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -651,6 +651,7 @@ #size-cells = <0>; compatible = "snps,designware-i2c"; reg = <0xffc04000 0x1000>; + resets = <&rst I2C0_RESET>; clocks = <&l4_sp_clk>; interrupts = <0 158 0x4>; status = "disabled"; @@ -661,6 +662,7 @@ #size-cells = <0>; compatible = "snps,designware-i2c"; reg = <0xffc05000 0x1000>; + resets = <&rst I2C1_RESET>; clocks = <&l4_sp_clk>; interrupts = <0 159 0x4>; status = "disabled"; @@ -671,6 +673,7 @@ #size-cells = <0>; compatible = "snps,designware-i2c"; reg = <0xffc06000 0x1000>; + resets = <&rst I2C2_RESET>; clocks = <&l4_sp_clk>; interrupts = <0 160 0x4>; status = "disabled"; @@ -681,6 +684,7 @@ #size-cells = <0>; compatible = "snps,designware-i2c"; reg = <0xffc07000 0x1000>; + resets = <&rst I2C3_RESET>; clocks = <&l4_sp_clk>; interrupts = <0 161 0x4>; status = "disabled"; diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi b/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi index 3a32de9ded3b..64cc86a98771 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi +++ b/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi @@ -163,6 +163,7 @@ &usb0 { status = "okay"; + disable-over-current; }; &watchdog1 { diff --git a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts b/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts index 655fe87e272d..2459d133f1be 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts @@ -237,7 +237,7 @@ clock-frequency = <100000>; at24@50 { - compatible = "at24,24c02"; + compatible = "atmel,24c02"; pagesize = <8>; reg = <0x50>; }; diff --git a/arch/arm/boot/dts/spear1310-evb.dts b/arch/arm/boot/dts/spear1310-evb.dts index 84101e4eebbf..0f5f379323a8 100644 --- a/arch/arm/boot/dts/spear1310-evb.dts +++ b/arch/arm/boot/dts/spear1310-evb.dts @@ -349,7 +349,7 @@ spi0: spi@e0100000 { status = "okay"; num-cs = <3>; - cs-gpios = <&gpio1 7 0>, <&spics 0>, <&spics 1>; + cs-gpios = <&gpio1 7 0>, <&spics 0 0>, <&spics 1 0>; stmpe610@0 { compatible = "st,stmpe610"; diff --git a/arch/arm/boot/dts/spear1340.dtsi b/arch/arm/boot/dts/spear1340.dtsi index 5f347054527d..d4dbc4098653 100644 --- a/arch/arm/boot/dts/spear1340.dtsi +++ b/arch/arm/boot/dts/spear1340.dtsi @@ -142,8 +142,8 @@ reg = <0xb4100000 0x1000>; interrupts = <0 105 0x4>; status = "disabled"; - dmas = <&dwdma0 0x600 0 0 1>, /* 0xC << 11 */ - <&dwdma0 0x680 0 1 0>; /* 0xD << 7 */ + dmas = <&dwdma0 12 0 1>, + <&dwdma0 13 1 0>; dma-names = "tx", "rx"; }; diff --git a/arch/arm/boot/dts/spear13xx.dtsi b/arch/arm/boot/dts/spear13xx.dtsi index 17ea0abcdbd7..086b4b333249 100644 --- a/arch/arm/boot/dts/spear13xx.dtsi +++ b/arch/arm/boot/dts/spear13xx.dtsi @@ -100,7 +100,7 @@ reg = <0xb2800000 0x1000>; interrupts = <0 29 0x4>; status = "disabled"; - dmas = <&dwdma0 0 0 0 0>; + dmas = <&dwdma0 0 0 0>; dma-names = "data"; }; @@ -290,8 +290,8 @@ #size-cells = <0>; interrupts = <0 31 0x4>; status = "disabled"; - dmas = <&dwdma0 0x2000 0 0 0>, /* 0x4 << 11 */ - <&dwdma0 0x0280 0 0 0>; /* 0x5 << 7 */ + dmas = <&dwdma0 4 0 0>, + <&dwdma0 5 0 0>; dma-names = "tx", "rx"; }; diff --git a/arch/arm/boot/dts/spear600.dtsi b/arch/arm/boot/dts/spear600.dtsi index 6b32d20acc9f..00166eb9be86 100644 --- a/arch/arm/boot/dts/spear600.dtsi +++ b/arch/arm/boot/dts/spear600.dtsi @@ -194,6 +194,7 @@ rtc: rtc@fc900000 { compatible = "st,spear600-rtc"; reg = <0xfc900000 0x1000>; + interrupt-parent = <&vic0>; interrupts = <10>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi index 68aab50a73ab..733678b75b88 100644 --- a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi +++ b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi @@ -750,6 +750,7 @@ reg = <0x10120000 0x1000>; interrupt-names = "combined"; interrupts = <14>; + interrupt-parent = <&vica>; clocks = <&clcdclk>, <&hclkclcd>; clock-names = "clcdclk", "apb_pclk"; status = "disabled"; diff --git a/arch/arm/boot/dts/stih407.dtsi b/arch/arm/boot/dts/stih407.dtsi index fa149837df14..11fdecd9312e 100644 --- a/arch/arm/boot/dts/stih407.dtsi +++ b/arch/arm/boot/dts/stih407.dtsi @@ -8,6 +8,7 @@ */ #include "stih407-clock.dtsi" #include "stih407-family.dtsi" +#include / { soc { sti-display-subsystem { @@ -122,7 +123,7 @@ <&clk_s_d2_quadfs 0>, <&clk_s_d2_quadfs 1>; - hdmi,hpd-gpio = <&pio5 3>; + hdmi,hpd-gpio = <&pio5 3 GPIO_ACTIVE_LOW>; reset-names = "hdmi"; resets = <&softreset STIH407_HDMI_TX_PHY_SOFTRESET>; ddc = <&hdmiddc>; diff --git a/arch/arm/boot/dts/stih410.dtsi b/arch/arm/boot/dts/stih410.dtsi index cffa50db5d72..68b5ff91d6a7 100644 --- a/arch/arm/boot/dts/stih410.dtsi +++ b/arch/arm/boot/dts/stih410.dtsi @@ -9,6 +9,7 @@ #include "stih410-clock.dtsi" #include "stih407-family.dtsi" #include "stih410-pinctrl.dtsi" +#include / { aliases { bdisp0 = &bdisp0; @@ -213,7 +214,7 @@ <&clk_s_d2_quadfs 0>, <&clk_s_d2_quadfs 1>; - hdmi,hpd-gpio = <&pio5 3>; + hdmi,hpd-gpio = <&pio5 3 GPIO_ACTIVE_LOW>; reset-names = "hdmi"; resets = <&softreset STIH407_HDMI_TX_PHY_SOFTRESET>; ddc = <&hdmiddc>; diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi index 5840f5c75c3b..4f2f2eea0755 100644 --- a/arch/arm/boot/dts/sun4i-a10.dtsi +++ b/arch/arm/boot/dts/sun4i-a10.dtsi @@ -1104,7 +1104,7 @@ be1_out_tcon0: endpoint@0 { reg = <0>; - remote-endpoint = <&tcon1_in_be0>; + remote-endpoint = <&tcon0_in_be1>; }; be1_out_tcon1: endpoint@1 { diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts index 38072c7e10e2..4b9af423c6d5 100644 --- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts +++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts @@ -114,6 +114,10 @@ status = "okay"; }; +&codec { + status = "okay"; +}; + &ehci0 { status = "okay"; }; diff --git a/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts b/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts index 39bc73db72e5..fb591f32252c 100644 --- a/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts +++ b/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts @@ -58,6 +58,17 @@ stdout-path = "serial0:115200n8"; }; + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -90,6 +101,10 @@ cpu-supply = <®_dcdc2>; }; +&de { + status = "okay"; +}; + &ehci0 { status = "okay"; }; @@ -110,6 +125,16 @@ }; }; +&hdmi { + status = "okay"; +}; + +&hdmi_out { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c0_pins_a>; diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index 59655e42e4b0..bd0cd3204273 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -1354,7 +1354,7 @@ be1_out_tcon0: endpoint@0 { reg = <0>; - remote-endpoint = <&tcon1_in_be0>; + remote-endpoint = <&tcon0_in_be1>; }; be1_out_tcon1: endpoint@1 { diff --git a/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts b/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts index c606af3dbfed..6550bf0e594b 100644 --- a/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts +++ b/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts @@ -52,6 +52,7 @@ compatible = "sinovoip,bpi-m3", "allwinner,sun8i-a83t"; aliases { + ethernet0 = &emac; serial0 = &uart0; }; @@ -88,6 +89,24 @@ /* TODO GL830 USB-to-SATA bridge downstream w/ GPIO power controls */ }; +&emac { + pinctrl-names = "default"; + pinctrl-0 = <&emac_rgmii_pins>; + phy-supply = <®_sw>; + phy-handle = <&rgmii_phy>; + phy-mode = "rgmii"; + allwinner,rx-delay-ps = <700>; + allwinner,tx-delay-ps = <700>; + status = "okay"; +}; + +&mdio { + rgmii_phy: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; +}; + &mmc0 { pinctrl-names = "default"; pinctrl-0 = <&mmc0_pins>; diff --git a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts index 7f0a3f6d0cf2..6da08cd0e107 100644 --- a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts +++ b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts @@ -52,6 +52,7 @@ compatible = "cubietech,cubietruck-plus", "allwinner,sun8i-a83t"; aliases { + ethernet0 = &emac; serial0 = &uart0; }; @@ -154,6 +155,22 @@ status = "okay"; }; +&emac { + pinctrl-names = "default"; + pinctrl-0 = <&emac_rgmii_pins>; + phy-supply = <®_dldo4>; + phy-handle = <&rgmii_phy>; + phy-mode = "rgmii"; + status = "okay"; +}; + +&mdio { + rgmii_phy: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; +}; + &mmc0 { pinctrl-names = "default"; pinctrl-0 = <&mmc0_pins>; diff --git a/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts b/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts index a021ee6da396..511fca491fe8 100644 --- a/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts +++ b/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts @@ -45,6 +45,7 @@ #include "sun8i-a83t.dtsi" #include +#include / { model = "TBS A711 Tablet"; @@ -59,6 +60,44 @@ stdout-path = "serial0:115200n8"; }; + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>; + enable-gpios = <&pio 3 29 GPIO_ACTIVE_HIGH>; + + brightness-levels = <0 1 2 4 8 16 32 64 128 255>; + default-brightness-level = <9>; + }; + + panel { + compatible = "tbs,a711-panel", "panel-lvds"; + backlight = <&backlight>; + power-supply = <®_sw>; + + width-mm = <153>; + height-mm = <90>; + data-mapping = "vesa-24"; + + panel-timing { + /* 1024x600 @60Hz */ + clock-frequency = <52000000>; + hactive = <1024>; + vactive = <600>; + hsync-len = <20>; + hfront-porch = <180>; + hback-porch = <160>; + vfront-porch = <12>; + vback-porch = <23>; + vsync-len = <5>; + }; + + port { + panel_input: endpoint { + remote-endpoint = <&tcon0_out_lcd>; + }; + }; + }; + reg_vbat: reg-vbat { compatible = "regulator-fixed"; regulator-name = "vbat"; @@ -89,6 +128,10 @@ }; }; +&de { + status = "okay"; +}; + /* * An USB-2 hub is connected here, which also means we don't need to * enable the OHCI controller. @@ -142,6 +185,12 @@ status = "okay"; }; +&pwm { + pinctrl-names = "default"; + pinctrl-0 = <&pwm_pin>; + status = "okay"; +}; + &r_rsb { status = "okay"; @@ -323,6 +372,18 @@ regulator-name = "vcc-lcd"; }; +&tcon0 { + pinctrl-names = "default"; + pinctrl-0 = <&lcd_lvds_pins>; +}; + +&tcon0_out { + tcon0_out_lcd: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_input>; + }; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pb_pins>; diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi index 19acae1b4089..7f4955a5fab7 100644 --- a/arch/arm/boot/dts/sun8i-a83t.dtsi +++ b/arch/arm/boot/dts/sun8i-a83t.dtsi @@ -45,8 +45,10 @@ #include #include +#include #include #include +#include #include / { @@ -151,6 +153,12 @@ }; }; + de: display-engine { + compatible = "allwinner,sun8i-a83t-display-engine"; + allwinner,pipelines = <&mixer0>; + status = "disabled"; + }; + memory { reg = <0x40000000 0x80000000>; device_type = "memory"; @@ -162,6 +170,44 @@ #size-cells = <1>; ranges; + display_clocks: clock@1000000 { + compatible = "allwinner,sun8i-a83t-de2-clk"; + reg = <0x01000000 0x100000>; + clocks = <&ccu CLK_PLL_DE>, + <&ccu CLK_BUS_DE>; + clock-names = "mod", + "bus"; + resets = <&ccu RST_BUS_DE>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + mixer0: mixer@1100000 { + compatible = "allwinner,sun8i-a83t-de2-mixer-0"; + reg = <0x01100000 0x100000>; + clocks = <&display_clocks CLK_BUS_MIXER0>, + <&display_clocks CLK_MIXER0>; + clock-names = "bus", + "mod"; + resets = <&display_clocks RST_MIXER0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + mixer0_out: port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + mixer0_out_tcon0: endpoint@0 { + reg = <0>; + remote-endpoint = <&tcon0_in_mixer0>; + }; + }; + }; + }; + syscon: syscon@1c00000 { compatible = "allwinner,sun8i-a83t-system-controller", "syscon"; @@ -177,6 +223,39 @@ #dma-cells = <1>; }; + tcon0: lcd-controller@1c0c000 { + compatible = "allwinner,sun8i-a83t-tcon-lcd"; + reg = <0x01c0c000 0x1000>; + interrupts = ; + clocks = <&ccu CLK_BUS_TCON0>, <&ccu CLK_TCON0>; + clock-names = "ahb", "tcon-ch0"; + clock-output-names = "tcon-pixel-clock"; + resets = <&ccu RST_BUS_TCON0>, <&ccu RST_BUS_LVDS>; + reset-names = "lcd", "lvds"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + tcon0_in: port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + tcon0_in_mixer0: endpoint@0 { + reg = <0>; + remote-endpoint = <&mixer0_out_tcon0>; + }; + }; + + tcon0_out: port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + }; + }; + mmc0: mmc@1c0f000 { compatible = "allwinner,sun8i-a83t-mmc", "allwinner,sun7i-a20-mmc"; @@ -336,6 +415,45 @@ #interrupt-cells = <3>; #gpio-cells = <3>; + emac_rgmii_pins: emac-rgmii-pins { + pins = "PD2", "PD3", "PD4", "PD5", "PD6", "PD7", + "PD11", "PD12", "PD13", "PD14", "PD18", + "PD19", "PD21", "PD22", "PD23"; + function = "gmac"; + /* + * data lines in RGMII mode use DDR mode + * and need a higher signal drive strength + */ + drive-strength = <40>; + }; + + i2c0_pins: i2c0-pins { + pins = "PH0", "PH1"; + function = "i2c0"; + }; + + i2c1_pins: i2c1-pins { + pins = "PH2", "PH3"; + function = "i2c1"; + }; + + i2c2_ph_pins: i2c2-ph-pins { + pins = "PH4", "PH5"; + function = "i2c2"; + }; + + i2s1_pins: i2s1-pins { + /* I2S1 does not have external MCLK pin */ + pins = "PG10", "PG11", "PG12", "PG13"; + function = "i2s1"; + }; + + lcd_lvds_pins: lcd-lvds-pins { + pins = "PD18", "PD19", "PD20", "PD21", "PD22", + "PD23", "PD24", "PD25", "PD26", "PD27"; + function = "lvds0"; + }; + mmc0_pins: mmc0-pins { pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5"; @@ -361,6 +479,11 @@ bias-pull-up; }; + pwm_pin: pwm-pin { + pins = "PD28"; + function = "pwm"; + }; + spdif_tx_pin: spdif-tx-pin { pins = "PE18"; function = "spdif"; @@ -418,6 +541,56 @@ status = "disabled"; }; + i2s0: i2s@1c22000 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun8i-a83t-i2s"; + reg = <0x01c22000 0x400>; + interrupts = ; + clocks = <&ccu CLK_BUS_I2S0>, <&ccu CLK_I2S0>; + clock-names = "apb", "mod"; + dmas = <&dma 3>, <&dma 3>; + resets = <&ccu RST_BUS_I2S0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + i2s1: i2s@1c22400 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun8i-a83t-i2s"; + reg = <0x01c22400 0x400>; + interrupts = ; + clocks = <&ccu CLK_BUS_I2S1>, <&ccu CLK_I2S1>; + clock-names = "apb", "mod"; + dmas = <&dma 4>, <&dma 4>; + resets = <&ccu RST_BUS_I2S1>; + dma-names = "rx", "tx"; + pinctrl-names = "default"; + pinctrl-0 = <&i2s1_pins>; + status = "disabled"; + }; + + i2s2: i2s@1c22800 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun8i-a83t-i2s"; + reg = <0x01c22800 0x400>; + interrupts = ; + clocks = <&ccu CLK_BUS_I2S2>, <&ccu CLK_I2S2>; + clock-names = "apb", "mod"; + dmas = <&dma 27>; + resets = <&ccu RST_BUS_I2S2>; + dma-names = "tx"; + status = "disabled"; + }; + + pwm: pwm@1c21400 { + compatible = "allwinner,sun8i-a83t-pwm", + "allwinner,sun8i-h3-pwm"; + reg = <0x01c21400 0x400>; + clocks = <&osc24M>; + #pwm-cells = <3>; + status = "disabled"; + }; + uart0: serial@1c28000 { compatible = "snps,dw-apb-uart"; reg = <0x01c28000 0x400>; @@ -440,6 +613,67 @@ status = "disabled"; }; + i2c0: i2c@1c2ac00 { + compatible = "allwinner,sun8i-a83t-i2c", + "allwinner,sun6i-a31-i2c"; + reg = <0x01c2ac00 0x400>; + interrupts = ; + clocks = <&ccu CLK_BUS_I2C0>; + resets = <&ccu RST_BUS_I2C0>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c1: i2c@1c2b000 { + compatible = "allwinner,sun8i-a83t-i2c", + "allwinner,sun6i-a31-i2c"; + reg = <0x01c2b000 0x400>; + interrupts = ; + clocks = <&ccu CLK_BUS_I2C1>; + resets = <&ccu RST_BUS_I2C1>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c2: i2c@1c2b400 { + compatible = "allwinner,sun8i-a83t-i2c", + "allwinner,sun6i-a31-i2c"; + reg = <0x01c2b400 0x400>; + interrupts = ; + clocks = <&ccu CLK_BUS_I2C2>; + resets = <&ccu RST_BUS_I2C2>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + emac: ethernet@1c30000 { + compatible = "allwinner,sun8i-a83t-emac"; + syscon = <&syscon>; + reg = <0x01c30000 0x104>; + interrupts = ; + interrupt-names = "macirq"; + resets = <&ccu 13>; + reset-names = "stmmaceth"; + clocks = <&ccu 27>; + clock-names = "stmmaceth"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + mdio: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + gic: interrupt-controller@1c81000 { compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; reg = <0x01c81000 0x1000>, diff --git a/arch/arm/boot/dts/sun8i-h2-plus-orangepi-r1.dts b/arch/arm/boot/dts/sun8i-h2-plus-orangepi-r1.dts new file mode 100644 index 000000000000..112f09c67d67 --- /dev/null +++ b/arch/arm/boot/dts/sun8i-h2-plus-orangepi-r1.dts @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2017 Icenowy Zheng + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* Orange Pi R1 is based on Orange Pi Zero design */ +#include "sun8i-h2-plus-orangepi-zero.dts" + +/ { + model = "Xunlong Orange Pi R1"; + compatible = "xunlong,orangepi-r1", "allwinner,sun8i-h2-plus"; + + /delete-node/ reg_vcc_wifi; + + /* + * Ths pin of this regulator is the same with the Wi-Fi extra + * regulator on the original Zero. However it's used for USB + * Ethernet rather than the Wi-Fi now. + */ + reg_vcc_usb_eth: reg-vcc-usb-ethernet { + compatible = "regulator-fixed"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-usb-ethernet"; + enable-active-high; + gpio = <&pio 0 20 GPIO_ACTIVE_HIGH>; + }; + + aliases { + ethernet1 = &rtl8189etv; + }; +}; + +&ohci1 { + /* + * RTL8152B USB-Ethernet adapter is connected to USB1, + * and it's a USB 2.0 device. So the OHCI1 controller + * can be left disabled. + */ + status = "disabled"; +}; + +&mmc1 { + vmmc-supply = <®_vcc3v3>; + vqmmc-supply = <®_vcc3v3>; + + rtl8189etv: sdio_wifi@1 { + reg = <1>; + }; +}; + +&usbphy { + usb1_vbus-supply = <®_vcc_usb_eth>; +}; diff --git a/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts b/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts index f2292deaa590..f1c3f1cc4d97 100644 --- a/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts +++ b/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts @@ -119,7 +119,6 @@ phy-handle = <&ext_rgmii_phy>; phy-mode = "rgmii"; - allwinner,leds-active-low; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun8i-h3-libretech-all-h3-cc.dts b/arch/arm/boot/dts/sun8i-h3-libretech-all-h3-cc.dts new file mode 100644 index 000000000000..d406571a0dd6 --- /dev/null +++ b/arch/arm/boot/dts/sun8i-h3-libretech-all-h3-cc.dts @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2017 Chen-Yu Tsai + * + * SPDX-License-Identifier: (GPL-2.0+ OR MIT) + */ + +/dts-v1/; +#include "sun8i-h3.dtsi" + +#include +#include + +/ { + model = "Libre Computer Board ALL-H3-CC H3"; + compatible = "libretech,all-h3-cc-h3", "allwinner,sun8i-h3"; + + aliases { + ethernet0 = &emac; + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + leds { + compatible = "gpio-leds"; + + pwr_led { + label = "librecomputer:green:pwr"; + gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PL10 */ + default-state = "on"; + }; + + status_led { + label = "librecomputer:blue:status"; + gpios = <&pio 0 7 GPIO_ACTIVE_HIGH>; /* PA7 */ + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + power { + label = "power"; + linux,code = ; + gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 */ + }; + }; + + reg_vcc1v2: vcc1v2 { + compatible = "regulator-fixed"; + regulator-name = "vcc1v2"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <®_vcc5v0>; + gpio = <&r_pio 0 8 GPIO_ACTIVE_HIGH>; /* PL8 */ + enable-active-high; + }; + + reg_vcc3v3: vcc3v3 { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <®_vcc5v0>; + }; + + /* This represents the board's 5V input */ + reg_vcc5v0: vcc5v0 { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + reg_vcc_dram: vcc-dram { + compatible = "regulator-fixed"; + regulator-name = "vcc-dram"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <®_vcc5v0>; + gpio = <&r_pio 0 9 GPIO_ACTIVE_HIGH>; /* PL9 */ + enable-active-high; + }; + + reg_vcc_io: vcc-io { + compatible = "regulator-fixed"; + regulator-name = "vcc-io"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <®_vcc3v3>; + gpio = <&r_pio 0 5 GPIO_ACTIVE_LOW>; /* PL5 */ + }; + + reg_vdd_cpux: vdd-cpux { + compatible = "regulator-fixed"; + regulator-name = "vdd-cpux"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <®_vcc5v0>; + gpio = <&r_pio 0 8 GPIO_ACTIVE_HIGH>; /* PL8 */ + enable-active-high; + }; +}; + +&codec { + allwinner,audio-routing = + "Line Out", "LINEOUT", + "MIC1", "Mic", + "Mic", "MBIAS"; + status = "okay"; +}; + +&ehci0 { + status = "okay"; +}; + +&ehci1 { + status = "okay"; +}; + +&ehci2 { + status = "okay"; +}; + +&ehci3 { + status = "okay"; +}; + +&emac { + phy-handle = <&int_mii_phy>; + phy-mode = "mii"; + allwinner,leds-active-low; + status = "okay"; +}; + +&ir { + pinctrl-names = "default"; + pinctrl-0 = <&ir_pins_a>; + status = "okay"; +}; + +&mmc0 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_pins_a>; + vmmc-supply = <®_vcc_io>; + bus-width = <4>; + cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */ + cd-inverted; + status = "okay"; +}; + +&ohci0 { + status = "okay"; +}; + +&ohci1 { + status = "okay"; +}; + +&ohci2 { + status = "okay"; +}; + +&ohci3 { + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins_a>; + status = "okay"; +}; + +&usb_otg { + dr_mode = "host"; + status = "okay"; +}; + +&usbphy { + /* VBUS on USB ports are always on */ + usb0_vbus-supply = <®_vcc5v0>; + usb1_vbus-supply = <®_vcc5v0>; + usb2_vbus-supply = <®_vcc5v0>; + usb3_vbus-supply = <®_vcc5v0>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi-m1-plus.dts b/arch/arm/boot/dts/sun8i-h3-nanopi-m1-plus.dts index 0a8b79cf5954..a6e61915d648 100644 --- a/arch/arm/boot/dts/sun8i-h3-nanopi-m1-plus.dts +++ b/arch/arm/boot/dts/sun8i-h3-nanopi-m1-plus.dts @@ -48,6 +48,7 @@ aliases { serial1 = &uart3; + ethernet0 = &emac; ethernet1 = &sdio_wifi; }; @@ -83,8 +84,6 @@ phy-handle = <&ext_rgmii_phy>; phy-mode = "rgmii"; - allwinner,leds-active-low; - status = "okay"; }; diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi-m1.dts b/arch/arm/boot/dts/sun8i-h3-nanopi-m1.dts index 3a2ccdb28afd..c77fbca4f227 100644 --- a/arch/arm/boot/dts/sun8i-h3-nanopi-m1.dts +++ b/arch/arm/boot/dts/sun8i-h3-nanopi-m1.dts @@ -45,6 +45,10 @@ / { model = "FriendlyArm NanoPi M1"; compatible = "friendlyarm,nanopi-m1", "allwinner,sun8i-h3"; + + aliases { + ethernet0 = &emac; + }; }; &ehci1 { @@ -55,6 +59,13 @@ status = "okay"; }; +&emac { + phy-handle = <&int_mii_phy>; + phy-mode = "mii"; + allwinner,leds-active-low; + status = "okay"; +}; + &ir { pinctrl-names = "default"; pinctrl-0 = <&ir_pins_a>; diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi-neo.dts b/arch/arm/boot/dts/sun8i-h3-nanopi-neo.dts index 78f6c24952dd..9f33f6fae595 100644 --- a/arch/arm/boot/dts/sun8i-h3-nanopi-neo.dts +++ b/arch/arm/boot/dts/sun8i-h3-nanopi-neo.dts @@ -47,9 +47,26 @@ compatible = "friendlyarm,nanopi-neo", "allwinner,sun8i-h3"; }; +&ehci0 { + status = "okay"; +}; + &emac { phy-handle = <&int_mii_phy>; phy-mode = "mii"; allwinner,leds-active-low; status = "okay"; }; + +&ohci0 { + status = "okay"; +}; + +&usb_otg { + status = "okay"; + dr_mode = "peripheral"; +}; + +&usbphy { + usb0_id_det-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */ +}; diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts index cbc499b04de4..b403e5d787cb 100644 --- a/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts @@ -85,7 +85,6 @@ phy-handle = <&ext_rgmii_phy>; phy-mode = "rgmii"; - allwinner,leds-active-low; status = "okay"; }; diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi index b36f9f423c39..8495deecedad 100644 --- a/arch/arm/boot/dts/sun8i-h3.dtsi +++ b/arch/arm/boot/dts/sun8i-h3.dtsi @@ -85,6 +85,10 @@ compatible = "allwinner,sun8i-h3-ccu"; }; +&display_clocks { + compatible = "allwinner,sun8i-h3-de2-clk"; +}; + &mmc0 { compatible = "allwinner,sun7i-a20-mmc"; clocks = <&ccu CLK_BUS_MMC0>, diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi index 8d40c00d64bb..7a83b15225c7 100644 --- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi +++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi @@ -40,9 +40,11 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include #include #include #include +#include #include #include @@ -51,6 +53,30 @@ #address-cells = <1>; #size-cells = <1>; + chosen { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + framebuffer-hdmi { + compatible = "allwinner,simple-framebuffer", + "simple-framebuffer"; + allwinner,pipeline = "mixer0-lcd0-hdmi"; + clocks = <&display_clocks CLK_MIXER0>, + <&ccu CLK_TCON0>, <&ccu CLK_HDMI>; + status = "disabled"; + }; + + framebuffer-tve { + compatible = "allwinner,simple-framebuffer", + "simple-framebuffer"; + allwinner,pipeline = "mixer1-lcd1-tve"; + clocks = <&display_clocks CLK_MIXER1>, + <&ccu CLK_TVE>; + status = "disabled"; + }; + }; + clocks { #address-cells = <1>; #size-cells = <1>; @@ -85,6 +111,18 @@ #size-cells = <1>; ranges; + display_clocks: clock@1000000 { + /* compatible is in per SoC .dtsi file */ + reg = <0x01000000 0x100000>; + clocks = <&ccu CLK_DE>, + <&ccu CLK_BUS_DE>; + clock-names = "mod", + "bus"; + resets = <&ccu RST_BUS_DE>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + syscon: syscon@1c00000 { compatible = "allwinner,sun8i-h3-system-controller", "syscon"; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 914f59166a99..864a95872b8d 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -10,6 +10,19 @@ compatible = "nvidia,tegra20"; interrupt-parent = <&lic>; + iram@40000000 { + compatible = "mmio-sram"; + reg = <0x40000000 0x40000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x40000000 0x40000>; + + vde_pool: vde { + reg = <0x400 0x3fc00>; + pool; + }; + }; + host1x@50000000 { compatible = "nvidia,tegra20-host1x", "simple-bus"; reg = <0x50000000 0x00024000>; @@ -250,6 +263,28 @@ */ }; + vde@6001a000 { + compatible = "nvidia,tegra20-vde"; + reg = <0x6001a000 0x1000 /* Syntax Engine */ + 0x6001b000 0x1000 /* Video Bitstream Engine */ + 0x6001c000 0x100 /* Macroblock Engine */ + 0x6001c200 0x100 /* Post-processing Engine */ + 0x6001c400 0x100 /* Motion Compensation Engine */ + 0x6001c600 0x100 /* Transform Engine */ + 0x6001c800 0x100 /* Pixel prediction block */ + 0x6001ca00 0x100 /* Video DMA */ + 0x6001d800 0x300>; /* Video frame controls */ + reg-names = "sxe", "bsev", "mbe", "ppe", "mce", + "tfe", "ppb", "vdma", "frameid"; + iram = <&vde_pool>; /* IRAM region */ + interrupts = , /* Sync token interrupt */ + , /* BSE-V interrupt */ + ; /* SXE interrupt */ + interrupt-names = "sync-token", "bsev", "sxe"; + clocks = <&tegra_car TEGRA20_CLK_VDE>; + resets = <&tegra_car 61>; + }; + apbmisc@70000800 { compatible = "nvidia,tegra20-apbmisc"; reg = <0x70000800 0x64 /* Chip revision */ diff --git a/arch/arm/boot/dts/tny_a9260_common.dtsi b/arch/arm/boot/dts/tny_a9260_common.dtsi index 5d83df4675a1..8e3cf5109f98 100644 --- a/arch/arm/boot/dts/tny_a9260_common.dtsi +++ b/arch/arm/boot/dts/tny_a9260_common.dtsi @@ -27,6 +27,18 @@ ahb { apb { + tcb0: timer@fffa0000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + dbgu: serial@fffff200 { status = "okay"; }; diff --git a/arch/arm/boot/dts/tny_a9263.dts b/arch/arm/boot/dts/tny_a9263.dts index 8cf0a9e08571..7b403db4cd34 100644 --- a/arch/arm/boot/dts/tny_a9263.dts +++ b/arch/arm/boot/dts/tny_a9263.dts @@ -36,6 +36,18 @@ status = "okay"; }; + tcb0: timer@fff7c000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + usb1: gadget@fff78000 { atmel,vbus-gpio = <&pioB 11 GPIO_ACTIVE_HIGH>; status = "okay"; diff --git a/arch/arm/boot/dts/uniphier-ld4-ref.dts b/arch/arm/boot/dts/uniphier-ld4-ref.dts index 0056852c4fb0..a3afd0cda42f 100644 --- a/arch/arm/boot/dts/uniphier-ld4-ref.dts +++ b/arch/arm/boot/dts/uniphier-ld4-ref.dts @@ -56,7 +56,7 @@ &gpio { xirq1 { gpio-hog; - gpios = <121 0>; + gpios = ; input; }; }; diff --git a/arch/arm/boot/dts/uniphier-ld4.dtsi b/arch/arm/boot/dts/uniphier-ld4.dtsi index 01fc3e16e2bd..0459e84d4d8e 100644 --- a/arch/arm/boot/dts/uniphier-ld4.dtsi +++ b/arch/arm/boot/dts/uniphier-ld4.dtsi @@ -7,6 +7,8 @@ * SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +#include + / { compatible = "socionext,uniphier-ld4"; #address-cells = <1>; @@ -235,6 +237,7 @@ <&mio_clk 12>; resets = <&sys_rst 8>, <&mio_rst 7>, <&mio_rst 8>, <&mio_rst 12>; + has-transaction-translator; }; usb1: usb@5a810100 { @@ -248,6 +251,7 @@ <&mio_clk 13>; resets = <&sys_rst 8>, <&mio_rst 7>, <&mio_rst 9>, <&mio_rst 13>; + has-transaction-translator; }; usb2: usb@5a820100 { @@ -261,6 +265,7 @@ <&mio_clk 14>; resets = <&sys_rst 8>, <&mio_rst 7>, <&mio_rst 10>, <&mio_rst 14>; + has-transaction-translator; }; soc-glue@5f800000 { @@ -273,6 +278,24 @@ }; }; + soc-glue@5f900000 { + compatible = "socionext,uniphier-ld4-soc-glue-debug", + "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x5f900000 0x2000>; + + efuse@100 { + compatible = "socionext,uniphier-efuse"; + reg = <0x100 0x28>; + }; + + efuse@130 { + compatible = "socionext,uniphier-efuse"; + reg = <0x130 0x8>; + }; + }; + timer@60000200 { compatible = "arm,cortex-a9-global-timer"; reg = <0x60000200 0x20>; diff --git a/arch/arm/boot/dts/uniphier-ld6b-ref.dts b/arch/arm/boot/dts/uniphier-ld6b-ref.dts index 0e510a725976..811b999800ed 100644 --- a/arch/arm/boot/dts/uniphier-ld6b-ref.dts +++ b/arch/arm/boot/dts/uniphier-ld6b-ref.dts @@ -58,7 +58,7 @@ &gpio { xirq4 { gpio-hog; - gpios = <124 0>; + gpios = ; input; }; }; diff --git a/arch/arm/boot/dts/uniphier-pro4-ref.dts b/arch/arm/boot/dts/uniphier-pro4-ref.dts index be99467ac6bb..6a004e5cf786 100644 --- a/arch/arm/boot/dts/uniphier-pro4-ref.dts +++ b/arch/arm/boot/dts/uniphier-pro4-ref.dts @@ -58,7 +58,7 @@ &gpio { xirq2 { gpio-hog; - gpios = <122 0>; + gpios = ; input; }; }; diff --git a/arch/arm/boot/dts/uniphier-pro4.dtsi b/arch/arm/boot/dts/uniphier-pro4.dtsi index 7955c3a49e65..1a29a8619856 100644 --- a/arch/arm/boot/dts/uniphier-pro4.dtsi +++ b/arch/arm/boot/dts/uniphier-pro4.dtsi @@ -7,6 +7,8 @@ * SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +#include + / { compatible = "socionext,uniphier-pro4"; #address-cells = <1>; @@ -269,6 +271,7 @@ <&mio_clk 12>; resets = <&sys_rst 8>, <&mio_rst 7>, <&mio_rst 8>, <&mio_rst 12>; + has-transaction-translator; }; usb3: usb@5a810100 { @@ -282,6 +285,7 @@ <&mio_clk 13>; resets = <&sys_rst 8>, <&mio_rst 7>, <&mio_rst 9>, <&mio_rst 13>; + has-transaction-translator; }; soc-glue@5f800000 { @@ -294,6 +298,29 @@ }; }; + soc-glue@5f900000 { + compatible = "socionext,uniphier-pro4-soc-glue-debug", + "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x5f900000 0x2000>; + + efuse@100 { + compatible = "socionext,uniphier-efuse"; + reg = <0x100 0x28>; + }; + + efuse@130 { + compatible = "socionext,uniphier-efuse"; + reg = <0x130 0x8>; + }; + + efuse@200 { + compatible = "socionext,uniphier-efuse"; + reg = <0x200 0x14>; + }; + }; + aidet: aidet@5fc20000 { compatible = "socionext,uniphier-pro4-aidet"; reg = <0x5fc20000 0x200>; diff --git a/arch/arm/boot/dts/uniphier-pro5.dtsi b/arch/arm/boot/dts/uniphier-pro5.dtsi index 6589b8a2c65c..f291dd63de9c 100644 --- a/arch/arm/boot/dts/uniphier-pro5.dtsi +++ b/arch/arm/boot/dts/uniphier-pro5.dtsi @@ -355,6 +355,39 @@ }; }; + soc-glue@5f900000 { + compatible = "socionext,uniphier-pro5-soc-glue-debug", + "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x5f900000 0x2000>; + + efuse@100 { + compatible = "socionext,uniphier-efuse"; + reg = <0x100 0x28>; + }; + + efuse@130 { + compatible = "socionext,uniphier-efuse"; + reg = <0x130 0x8>; + }; + + efuse@200 { + compatible = "socionext,uniphier-efuse"; + reg = <0x200 0x28>; + }; + + efuse@300 { + compatible = "socionext,uniphier-efuse"; + reg = <0x300 0x14>; + }; + + efuse@400 { + compatible = "socionext,uniphier-efuse"; + reg = <0x400 0x8>; + }; + }; + aidet: aidet@5fc20000 { compatible = "socionext,uniphier-pro5-aidet"; reg = <0x5fc20000 0x200>; diff --git a/arch/arm/boot/dts/uniphier-pxs2.dtsi b/arch/arm/boot/dts/uniphier-pxs2.dtsi index d82d6d872131..c083468c17db 100644 --- a/arch/arm/boot/dts/uniphier-pxs2.dtsi +++ b/arch/arm/boot/dts/uniphier-pxs2.dtsi @@ -7,6 +7,7 @@ * SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +#include #include / { @@ -375,6 +376,24 @@ }; }; + soc-glue@5f900000 { + compatible = "socionext,uniphier-pxs2-soc-glue-debug", + "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x5f900000 0x2000>; + + efuse@100 { + compatible = "socionext,uniphier-efuse"; + reg = <0x100 0x28>; + }; + + efuse@200 { + compatible = "socionext,uniphier-efuse"; + reg = <0x200 0x58>; + }; + }; + aidet: aidet@5fc20000 { compatible = "socionext,uniphier-pxs2-aidet"; reg = <0x5fc20000 0x200>; diff --git a/arch/arm/boot/dts/uniphier-sld8-ref.dts b/arch/arm/boot/dts/uniphier-sld8-ref.dts index 1c0e7077a560..e052ea3b4020 100644 --- a/arch/arm/boot/dts/uniphier-sld8-ref.dts +++ b/arch/arm/boot/dts/uniphier-sld8-ref.dts @@ -56,7 +56,7 @@ &gpio { xirq0 { gpio-hog; - gpios = <120 0>; + gpios = ; input; }; }; diff --git a/arch/arm/boot/dts/uniphier-sld8.dtsi b/arch/arm/boot/dts/uniphier-sld8.dtsi index 71885366cd23..bc8c24078faa 100644 --- a/arch/arm/boot/dts/uniphier-sld8.dtsi +++ b/arch/arm/boot/dts/uniphier-sld8.dtsi @@ -7,6 +7,8 @@ * SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +#include + / { compatible = "socionext,uniphier-sld8"; #address-cells = <1>; @@ -239,6 +241,7 @@ <&mio_clk 12>; resets = <&sys_rst 8>, <&mio_rst 7>, <&mio_rst 8>, <&mio_rst 12>; + has-transaction-translator; }; usb1: usb@5a810100 { @@ -252,6 +255,7 @@ <&mio_clk 13>; resets = <&sys_rst 8>, <&mio_rst 7>, <&mio_rst 9>, <&mio_rst 13>; + has-transaction-translator; }; usb2: usb@5a820100 { @@ -265,6 +269,7 @@ <&mio_clk 14>; resets = <&sys_rst 8>, <&mio_rst 7>, <&mio_rst 10>, <&mio_rst 14>; + has-transaction-translator; }; soc-glue@5f800000 { @@ -277,6 +282,24 @@ }; }; + soc-glue@5f900000 { + compatible = "socionext,uniphier-sld8-soc-glue-debug", + "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x5f900000 0x2000>; + + efuse@100 { + compatible = "socionext,uniphier-efuse"; + reg = <0x100 0x28>; + }; + + efuse@200 { + compatible = "socionext,uniphier-efuse"; + reg = <0x200 0x14>; + }; + }; + timer@60000200 { compatible = "arm,cortex-a9-global-timer"; reg = <0x60000200 0x20>; diff --git a/arch/arm/boot/dts/usb_a9260_common.dtsi b/arch/arm/boot/dts/usb_a9260_common.dtsi index 34a49995eda3..de3fa3ab34d6 100644 --- a/arch/arm/boot/dts/usb_a9260_common.dtsi +++ b/arch/arm/boot/dts/usb_a9260_common.dtsi @@ -23,6 +23,18 @@ status = "okay"; }; + tcb0: timer@fffa0000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + macb0: ethernet@fffc4000 { phy-mode = "rmii"; status = "okay"; diff --git a/arch/arm/boot/dts/usb_a9263.dts b/arch/arm/boot/dts/usb_a9263.dts index 7b1125be99c4..0a753b4c74e7 100644 --- a/arch/arm/boot/dts/usb_a9263.dts +++ b/arch/arm/boot/dts/usb_a9263.dts @@ -36,6 +36,18 @@ status = "okay"; }; + tcb0: timer@fff7c000 { + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + macb0: ethernet@fffbc000 { phy-mode = "rmii"; status = "okay"; diff --git a/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi b/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi index 091b738041a0..d8b2972527eb 100644 --- a/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi +++ b/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi @@ -140,7 +140,7 @@ /* M41T0M6 real time clock on carrier board */ rtc: m41t0m6@68 { - compatible = "st,m41t00"; + compatible = "st,m41t0"; reg = <0x68>; }; }; diff --git a/arch/arm/boot/dts/vf500.dtsi b/arch/arm/boot/dts/vf500.dtsi index 3d9896171bfc..348bcd30c0f7 100644 --- a/arch/arm/boot/dts/vf500.dtsi +++ b/arch/arm/boot/dts/vf500.dtsi @@ -58,7 +58,7 @@ soc { aips-bus@40000000 { - intc: interrupt-controller@40002000 { + intc: interrupt-controller@40003000 { compatible = "arm,cortex-a9-gic"; #interrupt-cells = <3>; interrupt-controller; diff --git a/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts b/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts index acdf12ad0622..782b69a3acdf 100644 --- a/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts +++ b/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts @@ -255,16 +255,19 @@ port@0 { reg = <0>; label = "lan6"; + phy-handle = <&switch2phy0>; }; port@1 { reg = <1>; label = "lan7"; + phy-handle = <&switch2phy1>; }; port@2 { reg = <2>; label = "lan8"; + phy-handle = <&switch2phy2>; }; port@3 { @@ -304,6 +307,20 @@ }; }; }; + mdio { + #address-cells = <1>; + #size-cells = <0>; + + switch2phy0: phy@0 { + reg = <0>; + }; + switch2phy1: phy@1 { + reg = <1>; + }; + switch2phy2: phy@2 { + reg = <2>; + }; + }; }; }; @@ -371,7 +388,8 @@ reg = <0x22>; gpio-controller; #gpio-cells = <2>; - interrupt-parent = <&gpio2>; + interrupt-controller; + interrupt-parent = <&gpio3>; interrupts = <2 IRQ_TYPE_LEVEL_LOW>; }; }; diff --git a/arch/arm/boot/dts/vf610-zii-dev-rev-c.dts b/arch/arm/boot/dts/vf610-zii-dev-rev-c.dts index 4b8edc8982cf..c6f134c78303 100644 --- a/arch/arm/boot/dts/vf610-zii-dev-rev-c.dts +++ b/arch/arm/boot/dts/vf610-zii-dev-rev-c.dts @@ -73,7 +73,7 @@ #size-cells = <0>; reg = <0>; dsa,member = <0 0>; - eeprom-length = <512>; + eeprom-length = <65536>; interrupt-parent = <&gpio0>; interrupts = <27 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; @@ -170,7 +170,7 @@ #size-cells = <0>; reg = <0>; dsa,member = <0 1>; - eeprom-length = <512>; + eeprom-length = <65536>; interrupt-parent = <&gpio0>; interrupts = <26 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; diff --git a/arch/arm/boot/dts/vf610-zii-dev.dtsi b/arch/arm/boot/dts/vf610-zii-dev.dtsi index 6b58d3a97992..aadd36db0092 100644 --- a/arch/arm/boot/dts/vf610-zii-dev.dtsi +++ b/arch/arm/boot/dts/vf610-zii-dev.dtsi @@ -96,6 +96,10 @@ status = "okay"; }; +&edma1 { + status = "okay"; +}; + &esdhc1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_esdhc1>; diff --git a/arch/arm/boot/dts/vfxxx.dtsi b/arch/arm/boot/dts/vfxxx.dtsi index 5d654b5b4ce6..c3f09b737924 100644 --- a/arch/arm/boot/dts/vfxxx.dtsi +++ b/arch/arm/boot/dts/vfxxx.dtsi @@ -84,6 +84,11 @@ mask = <0x1000>; }; + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc0 16>, <&adc1 16>; + }; + soc { #address-cells = <1>; #size-cells = <1>; @@ -762,10 +767,5 @@ status = "disabled"; }; }; - - iio-hwmon { - compatible = "iio-hwmon"; - io-channels = <&adc0 16>, <&adc1 16>; - }; }; }; diff --git a/arch/arm/common/bL_switcher_dummy_if.c b/arch/arm/common/bL_switcher_dummy_if.c index 4c10c6452678..f4dc1714a79e 100644 --- a/arch/arm/common/bL_switcher_dummy_if.c +++ b/arch/arm/common/bL_switcher_dummy_if.c @@ -57,3 +57,7 @@ static struct miscdevice bL_switcher_device = { &bL_switcher_fops }; module_misc_device(bL_switcher_device); + +MODULE_AUTHOR("Nicolas Pitre "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("big.LITTLE switcher dummy user interface"); diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 4ecd5120fce7..a2c878769eaf 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -108,6 +108,7 @@ struct sa1111 { spinlock_t lock; void __iomem *base; struct sa1111_platform_data *pdata; + struct irq_domain *irqdomain; struct gpio_chip gc; #ifdef CONFIG_PM void *saved_state; @@ -125,7 +126,7 @@ struct sa1111_dev_info { unsigned long skpcr_mask; bool dma; unsigned int devid; - unsigned int irq[6]; + unsigned int hwirq[6]; }; static struct sa1111_dev_info sa1111_devices[] = { @@ -134,7 +135,7 @@ static struct sa1111_dev_info sa1111_devices[] = { .skpcr_mask = SKPCR_UCLKEN, .dma = true, .devid = SA1111_DEVID_USB, - .irq = { + .hwirq = { IRQ_USBPWR, IRQ_HCIM, IRQ_HCIBUFFACC, @@ -148,7 +149,7 @@ static struct sa1111_dev_info sa1111_devices[] = { .skpcr_mask = SKPCR_I2SCLKEN | SKPCR_L3CLKEN, .dma = true, .devid = SA1111_DEVID_SAC, - .irq = { + .hwirq = { AUDXMTDMADONEA, AUDXMTDMADONEB, AUDRCVDMADONEA, @@ -164,7 +165,7 @@ static struct sa1111_dev_info sa1111_devices[] = { .offset = SA1111_KBD, .skpcr_mask = SKPCR_PTCLKEN, .devid = SA1111_DEVID_PS2_KBD, - .irq = { + .hwirq = { IRQ_TPRXINT, IRQ_TPTXINT }, @@ -173,7 +174,7 @@ static struct sa1111_dev_info sa1111_devices[] = { .offset = SA1111_MSE, .skpcr_mask = SKPCR_PMCLKEN, .devid = SA1111_DEVID_PS2_MSE, - .irq = { + .hwirq = { IRQ_MSRXINT, IRQ_MSTXINT }, @@ -182,7 +183,7 @@ static struct sa1111_dev_info sa1111_devices[] = { .offset = 0x1800, .skpcr_mask = 0, .devid = SA1111_DEVID_PCMCIA, - .irq = { + .hwirq = { IRQ_S0_READY_NINT, IRQ_S0_CD_VALID, IRQ_S0_BVD1_STSCHG, @@ -193,6 +194,19 @@ static struct sa1111_dev_info sa1111_devices[] = { }, }; +static int sa1111_map_irq(struct sa1111 *sachip, irq_hw_number_t hwirq) +{ + return irq_create_mapping(sachip->irqdomain, hwirq); +} + +static void sa1111_handle_irqdomain(struct irq_domain *irqdomain, int irq) +{ + struct irq_desc *d = irq_to_desc(irq_linear_revmap(irqdomain, irq)); + + if (d) + generic_handle_irq_desc(d); +} + /* * SA1111 interrupt support. Since clearing an IRQ while there are * active IRQs causes the interrupt output to pulse, the upper levels @@ -202,49 +216,45 @@ static void sa1111_irq_handler(struct irq_desc *desc) { unsigned int stat0, stat1, i; struct sa1111 *sachip = irq_desc_get_handler_data(desc); + struct irq_domain *irqdomain; void __iomem *mapbase = sachip->base + SA1111_INTC; - stat0 = sa1111_readl(mapbase + SA1111_INTSTATCLR0); - stat1 = sa1111_readl(mapbase + SA1111_INTSTATCLR1); + stat0 = readl_relaxed(mapbase + SA1111_INTSTATCLR0); + stat1 = readl_relaxed(mapbase + SA1111_INTSTATCLR1); - sa1111_writel(stat0, mapbase + SA1111_INTSTATCLR0); + writel_relaxed(stat0, mapbase + SA1111_INTSTATCLR0); desc->irq_data.chip->irq_ack(&desc->irq_data); - sa1111_writel(stat1, mapbase + SA1111_INTSTATCLR1); + writel_relaxed(stat1, mapbase + SA1111_INTSTATCLR1); if (stat0 == 0 && stat1 == 0) { do_bad_IRQ(desc); return; } + irqdomain = sachip->irqdomain; + for (i = 0; stat0; i++, stat0 >>= 1) if (stat0 & 1) - generic_handle_irq(i + sachip->irq_base); + sa1111_handle_irqdomain(irqdomain, i); for (i = 32; stat1; i++, stat1 >>= 1) if (stat1 & 1) - generic_handle_irq(i + sachip->irq_base); + sa1111_handle_irqdomain(irqdomain, i); /* For level-based interrupts */ desc->irq_data.chip->irq_unmask(&desc->irq_data); } -#define SA1111_IRQMASK_LO(x) (1 << (x - sachip->irq_base)) -#define SA1111_IRQMASK_HI(x) (1 << (x - sachip->irq_base - 32)) - static u32 sa1111_irqmask(struct irq_data *d) { - struct sa1111 *sachip = irq_data_get_irq_chip_data(d); - - return BIT((d->irq - sachip->irq_base) & 31); + return BIT(irqd_to_hwirq(d) & 31); } static int sa1111_irqbank(struct irq_data *d) { - struct sa1111 *sachip = irq_data_get_irq_chip_data(d); - - return ((d->irq - sachip->irq_base) / 32) * 4; + return (irqd_to_hwirq(d) / 32) * 4; } static void sa1111_ack_irq(struct irq_data *d) @@ -257,9 +267,9 @@ static void sa1111_mask_irq(struct irq_data *d) void __iomem *mapbase = sachip->base + SA1111_INTC + sa1111_irqbank(d); u32 ie; - ie = sa1111_readl(mapbase + SA1111_INTEN0); + ie = readl_relaxed(mapbase + SA1111_INTEN0); ie &= ~sa1111_irqmask(d); - sa1111_writel(ie, mapbase + SA1111_INTEN0); + writel(ie, mapbase + SA1111_INTEN0); } static void sa1111_unmask_irq(struct irq_data *d) @@ -268,9 +278,9 @@ static void sa1111_unmask_irq(struct irq_data *d) void __iomem *mapbase = sachip->base + SA1111_INTC + sa1111_irqbank(d); u32 ie; - ie = sa1111_readl(mapbase + SA1111_INTEN0); + ie = readl_relaxed(mapbase + SA1111_INTEN0); ie |= sa1111_irqmask(d); - sa1111_writel(ie, mapbase + SA1111_INTEN0); + writel_relaxed(ie, mapbase + SA1111_INTEN0); } /* @@ -287,11 +297,11 @@ static int sa1111_retrigger_irq(struct irq_data *d) u32 ip, mask = sa1111_irqmask(d); int i; - ip = sa1111_readl(mapbase + SA1111_INTPOL0); + ip = readl_relaxed(mapbase + SA1111_INTPOL0); for (i = 0; i < 8; i++) { - sa1111_writel(ip ^ mask, mapbase + SA1111_INTPOL0); - sa1111_writel(ip, mapbase + SA1111_INTPOL0); - if (sa1111_readl(mapbase + SA1111_INTSTATCLR0) & mask) + writel_relaxed(ip ^ mask, mapbase + SA1111_INTPOL0); + writel_relaxed(ip, mapbase + SA1111_INTPOL0); + if (readl_relaxed(mapbase + SA1111_INTSTATCLR0) & mask) break; } @@ -313,13 +323,13 @@ static int sa1111_type_irq(struct irq_data *d, unsigned int flags) if ((!(flags & IRQ_TYPE_EDGE_RISING) ^ !(flags & IRQ_TYPE_EDGE_FALLING)) == 0) return -EINVAL; - ip = sa1111_readl(mapbase + SA1111_INTPOL0); + ip = readl_relaxed(mapbase + SA1111_INTPOL0); if (flags & IRQ_TYPE_EDGE_RISING) ip &= ~mask; else ip |= mask; - sa1111_writel(ip, mapbase + SA1111_INTPOL0); - sa1111_writel(ip, mapbase + SA1111_WAKEPOL0); + writel_relaxed(ip, mapbase + SA1111_INTPOL0); + writel_relaxed(ip, mapbase + SA1111_WAKEPOL0); return 0; } @@ -330,12 +340,12 @@ static int sa1111_wake_irq(struct irq_data *d, unsigned int on) void __iomem *mapbase = sachip->base + SA1111_INTC + sa1111_irqbank(d); u32 we, mask = sa1111_irqmask(d); - we = sa1111_readl(mapbase + SA1111_WAKEEN0); + we = readl_relaxed(mapbase + SA1111_WAKEEN0); if (on) we |= mask; else we &= ~mask; - sa1111_writel(we, mapbase + SA1111_WAKEEN0); + writel_relaxed(we, mapbase + SA1111_WAKEEN0); return 0; } @@ -350,10 +360,30 @@ static struct irq_chip sa1111_irq_chip = { .irq_set_wake = sa1111_wake_irq, }; +static int sa1111_irqdomain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct sa1111 *sachip = d->host_data; + + /* Disallow unavailable interrupts */ + if (hwirq > SSPROR && hwirq < AUDXMTDMADONEA) + return -EINVAL; + + irq_set_chip_data(irq, sachip); + irq_set_chip_and_handler(irq, &sa1111_irq_chip, handle_edge_irq); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); + + return 0; +} + +static const struct irq_domain_ops sa1111_irqdomain_ops = { + .map = sa1111_irqdomain_map, + .xlate = irq_domain_xlate_twocell, +}; + static int sa1111_setup_irq(struct sa1111 *sachip, unsigned irq_base) { void __iomem *irqbase = sachip->base + SA1111_INTC; - unsigned i, irq; int ret; /* @@ -373,37 +403,39 @@ static int sa1111_setup_irq(struct sa1111 *sachip, unsigned irq_base) sachip->irq_base = ret; /* disable all IRQs */ - sa1111_writel(0, irqbase + SA1111_INTEN0); - sa1111_writel(0, irqbase + SA1111_INTEN1); - sa1111_writel(0, irqbase + SA1111_WAKEEN0); - sa1111_writel(0, irqbase + SA1111_WAKEEN1); + writel_relaxed(0, irqbase + SA1111_INTEN0); + writel_relaxed(0, irqbase + SA1111_INTEN1); + writel_relaxed(0, irqbase + SA1111_WAKEEN0); + writel_relaxed(0, irqbase + SA1111_WAKEEN1); /* * detect on rising edge. Note: Feb 2001 Errata for SA1111 * specifies that S0ReadyInt and S1ReadyInt should be '1'. */ - sa1111_writel(0, irqbase + SA1111_INTPOL0); - sa1111_writel(BIT(IRQ_S0_READY_NINT & 31) | - BIT(IRQ_S1_READY_NINT & 31), - irqbase + SA1111_INTPOL1); + writel_relaxed(0, irqbase + SA1111_INTPOL0); + writel_relaxed(BIT(IRQ_S0_READY_NINT & 31) | + BIT(IRQ_S1_READY_NINT & 31), + irqbase + SA1111_INTPOL1); /* clear all IRQs */ - sa1111_writel(~0, irqbase + SA1111_INTSTATCLR0); - sa1111_writel(~0, irqbase + SA1111_INTSTATCLR1); + writel_relaxed(~0, irqbase + SA1111_INTSTATCLR0); + writel_relaxed(~0, irqbase + SA1111_INTSTATCLR1); - for (i = IRQ_GPAIN0; i <= SSPROR; i++) { - irq = sachip->irq_base + i; - irq_set_chip_and_handler(irq, &sa1111_irq_chip, handle_edge_irq); - irq_set_chip_data(irq, sachip); - irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); + sachip->irqdomain = irq_domain_add_linear(NULL, SA1111_IRQ_NR, + &sa1111_irqdomain_ops, + sachip); + if (!sachip->irqdomain) { + irq_free_descs(sachip->irq_base, SA1111_IRQ_NR); + return -ENOMEM; } - for (i = AUDXMTDMADONEA; i <= IRQ_S1_BVD1_STSCHG; i++) { - irq = sachip->irq_base + i; - irq_set_chip_and_handler(irq, &sa1111_irq_chip, handle_edge_irq); - irq_set_chip_data(irq, sachip); - irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); - } + irq_domain_associate_many(sachip->irqdomain, + sachip->irq_base + IRQ_GPAIN0, + IRQ_GPAIN0, SSPROR + 1 - IRQ_GPAIN0); + irq_domain_associate_many(sachip->irqdomain, + sachip->irq_base + AUDXMTDMADONEA, + AUDXMTDMADONEA, + IRQ_S1_BVD1_STSCHG + 1 - AUDXMTDMADONEA); /* * Register SA1111 interrupt @@ -420,20 +452,22 @@ static int sa1111_setup_irq(struct sa1111 *sachip, unsigned irq_base) static void sa1111_remove_irq(struct sa1111 *sachip) { + struct irq_domain *domain = sachip->irqdomain; void __iomem *irqbase = sachip->base + SA1111_INTC; + int i; /* disable all IRQs */ - sa1111_writel(0, irqbase + SA1111_INTEN0); - sa1111_writel(0, irqbase + SA1111_INTEN1); - sa1111_writel(0, irqbase + SA1111_WAKEEN0); - sa1111_writel(0, irqbase + SA1111_WAKEEN1); + writel_relaxed(0, irqbase + SA1111_INTEN0); + writel_relaxed(0, irqbase + SA1111_INTEN1); + writel_relaxed(0, irqbase + SA1111_WAKEEN0); + writel_relaxed(0, irqbase + SA1111_WAKEEN1); - if (sachip->irq != NO_IRQ) { - irq_set_chained_handler_and_data(sachip->irq, NULL, NULL); - irq_free_descs(sachip->irq_base, SA1111_IRQ_NR); + irq_set_chained_handler_and_data(sachip->irq, NULL, NULL); + for (i = 0; i < SA1111_IRQ_NR; i++) + irq_dispose_mapping(irq_find_mapping(domain, i)); + irq_domain_remove(domain); - release_mem_region(sachip->phys + SA1111_INTC, 512); - } + release_mem_region(sachip->phys + SA1111_INTC, 512); } enum { @@ -572,7 +606,7 @@ static int sa1111_gpio_to_irq(struct gpio_chip *gc, unsigned offset) { struct sa1111 *sachip = gc_to_sa1111(gc); - return sachip->irq_base + offset; + return sa1111_map_irq(sachip, offset); } static int sa1111_setup_gpios(struct sa1111 *sachip) @@ -618,11 +652,11 @@ static void sa1111_wake(struct sa1111 *sachip) /* * Turn VCO on, and disable PLL Bypass. */ - r = sa1111_readl(sachip->base + SA1111_SKCR); + r = readl_relaxed(sachip->base + SA1111_SKCR); r &= ~SKCR_VCO_OFF; - sa1111_writel(r, sachip->base + SA1111_SKCR); + writel_relaxed(r, sachip->base + SA1111_SKCR); r |= SKCR_PLL_BYPASS | SKCR_OE_EN; - sa1111_writel(r, sachip->base + SA1111_SKCR); + writel_relaxed(r, sachip->base + SA1111_SKCR); /* * Wait lock time. SA1111 manual _doesn't_ @@ -634,7 +668,7 @@ static void sa1111_wake(struct sa1111 *sachip) * Enable RCLK. We also ensure that RDYEN is set. */ r |= SKCR_RCLKEN | SKCR_RDYEN; - sa1111_writel(r, sachip->base + SA1111_SKCR); + writel_relaxed(r, sachip->base + SA1111_SKCR); /* * Wait 14 RCLK cycles for the chip to finish coming out @@ -645,7 +679,7 @@ static void sa1111_wake(struct sa1111 *sachip) /* * Ensure all clocks are initially off. */ - sa1111_writel(0, sachip->base + SA1111_SKPCR); + writel_relaxed(0, sachip->base + SA1111_SKPCR); spin_unlock_irqrestore(&sachip->lock, flags); } @@ -675,7 +709,7 @@ sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, if (cas_latency == 3) smcr |= SMCR_CLAT; - sa1111_writel(smcr, sachip->base + SA1111_SMCR); + writel_relaxed(smcr, sachip->base + SA1111_SMCR); /* * Now clear the bits in the DMA mask to work around the SA1111 @@ -723,8 +757,8 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, dev->mapbase = sachip->base + info->offset; dev->skpcr_mask = info->skpcr_mask; - for (i = 0; i < ARRAY_SIZE(info->irq); i++) - dev->irq[i] = sachip->irq_base + info->irq[i]; + for (i = 0; i < ARRAY_SIZE(info->hwirq); i++) + dev->hwirq[i] = info->hwirq[i]; /* * If the parent device has a DMA mask associated with it, and @@ -814,7 +848,7 @@ static int __sa1111_probe(struct device *me, struct resource *mem, int irq) /* * Probe for the chip. Only touch the SBI registers. */ - id = sa1111_readl(sachip->base + SA1111_SKID); + id = readl_relaxed(sachip->base + SA1111_SKID); if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id); ret = -ENODEV; @@ -833,11 +867,9 @@ static int __sa1111_probe(struct device *me, struct resource *mem, int irq) * The interrupt controller must be initialised before any * other device to ensure that the interrupts are available. */ - if (sachip->irq != NO_IRQ) { - ret = sa1111_setup_irq(sachip, pd->irq_base); - if (ret) - goto err_clk; - } + ret = sa1111_setup_irq(sachip, pd->irq_base); + if (ret) + goto err_clk; /* Setup the GPIOs - should really be done after the IRQ setup */ ret = sa1111_setup_gpios(sachip); @@ -864,8 +896,8 @@ static int __sa1111_probe(struct device *me, struct resource *mem, int irq) * DMA. It can otherwise be held firmly in the off position. * (currently, we always enable it.) */ - val = sa1111_readl(sachip->base + SA1111_SKPCR); - sa1111_writel(val | SKPCR_DCLKEN, sachip->base + SA1111_SKPCR); + val = readl_relaxed(sachip->base + SA1111_SKPCR); + writel_relaxed(val | SKPCR_DCLKEN, sachip->base + SA1111_SKPCR); /* * Enable the SA1110 memory bus request and grant signals. @@ -962,31 +994,31 @@ static int sa1111_suspend_noirq(struct device *dev) * Save state. */ base = sachip->base; - save->skcr = sa1111_readl(base + SA1111_SKCR); - save->skpcr = sa1111_readl(base + SA1111_SKPCR); - save->skcdr = sa1111_readl(base + SA1111_SKCDR); - save->skaud = sa1111_readl(base + SA1111_SKAUD); - save->skpwm0 = sa1111_readl(base + SA1111_SKPWM0); - save->skpwm1 = sa1111_readl(base + SA1111_SKPWM1); + save->skcr = readl_relaxed(base + SA1111_SKCR); + save->skpcr = readl_relaxed(base + SA1111_SKPCR); + save->skcdr = readl_relaxed(base + SA1111_SKCDR); + save->skaud = readl_relaxed(base + SA1111_SKAUD); + save->skpwm0 = readl_relaxed(base + SA1111_SKPWM0); + save->skpwm1 = readl_relaxed(base + SA1111_SKPWM1); - sa1111_writel(0, sachip->base + SA1111_SKPWM0); - sa1111_writel(0, sachip->base + SA1111_SKPWM1); + writel_relaxed(0, sachip->base + SA1111_SKPWM0); + writel_relaxed(0, sachip->base + SA1111_SKPWM1); base = sachip->base + SA1111_INTC; - save->intpol0 = sa1111_readl(base + SA1111_INTPOL0); - save->intpol1 = sa1111_readl(base + SA1111_INTPOL1); - save->inten0 = sa1111_readl(base + SA1111_INTEN0); - save->inten1 = sa1111_readl(base + SA1111_INTEN1); - save->wakepol0 = sa1111_readl(base + SA1111_WAKEPOL0); - save->wakepol1 = sa1111_readl(base + SA1111_WAKEPOL1); - save->wakeen0 = sa1111_readl(base + SA1111_WAKEEN0); - save->wakeen1 = sa1111_readl(base + SA1111_WAKEEN1); + save->intpol0 = readl_relaxed(base + SA1111_INTPOL0); + save->intpol1 = readl_relaxed(base + SA1111_INTPOL1); + save->inten0 = readl_relaxed(base + SA1111_INTEN0); + save->inten1 = readl_relaxed(base + SA1111_INTEN1); + save->wakepol0 = readl_relaxed(base + SA1111_WAKEPOL0); + save->wakepol1 = readl_relaxed(base + SA1111_WAKEPOL1); + save->wakeen0 = readl_relaxed(base + SA1111_WAKEEN0); + save->wakeen1 = readl_relaxed(base + SA1111_WAKEEN1); /* * Disable. */ - val = sa1111_readl(sachip->base + SA1111_SKCR); - sa1111_writel(val | SKCR_SLEEP, sachip->base + SA1111_SKCR); + val = readl_relaxed(sachip->base + SA1111_SKCR); + writel_relaxed(val | SKCR_SLEEP, sachip->base + SA1111_SKCR); clk_disable(sachip->clk); @@ -1023,7 +1055,7 @@ static int sa1111_resume_noirq(struct device *dev) * Ensure that the SA1111 is still here. * FIXME: shouldn't do this here. */ - id = sa1111_readl(sachip->base + SA1111_SKID); + id = readl_relaxed(sachip->base + SA1111_SKID); if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { __sa1111_remove(sachip); dev_set_drvdata(dev, NULL); @@ -1047,26 +1079,26 @@ static int sa1111_resume_noirq(struct device *dev) */ spin_lock_irqsave(&sachip->lock, flags); - sa1111_writel(0, sachip->base + SA1111_INTC + SA1111_INTEN0); - sa1111_writel(0, sachip->base + SA1111_INTC + SA1111_INTEN1); + writel_relaxed(0, sachip->base + SA1111_INTC + SA1111_INTEN0); + writel_relaxed(0, sachip->base + SA1111_INTC + SA1111_INTEN1); base = sachip->base; - sa1111_writel(save->skcr, base + SA1111_SKCR); - sa1111_writel(save->skpcr, base + SA1111_SKPCR); - sa1111_writel(save->skcdr, base + SA1111_SKCDR); - sa1111_writel(save->skaud, base + SA1111_SKAUD); - sa1111_writel(save->skpwm0, base + SA1111_SKPWM0); - sa1111_writel(save->skpwm1, base + SA1111_SKPWM1); + writel_relaxed(save->skcr, base + SA1111_SKCR); + writel_relaxed(save->skpcr, base + SA1111_SKPCR); + writel_relaxed(save->skcdr, base + SA1111_SKCDR); + writel_relaxed(save->skaud, base + SA1111_SKAUD); + writel_relaxed(save->skpwm0, base + SA1111_SKPWM0); + writel_relaxed(save->skpwm1, base + SA1111_SKPWM1); base = sachip->base + SA1111_INTC; - sa1111_writel(save->intpol0, base + SA1111_INTPOL0); - sa1111_writel(save->intpol1, base + SA1111_INTPOL1); - sa1111_writel(save->inten0, base + SA1111_INTEN0); - sa1111_writel(save->inten1, base + SA1111_INTEN1); - sa1111_writel(save->wakepol0, base + SA1111_WAKEPOL0); - sa1111_writel(save->wakepol1, base + SA1111_WAKEPOL1); - sa1111_writel(save->wakeen0, base + SA1111_WAKEEN0); - sa1111_writel(save->wakeen1, base + SA1111_WAKEEN1); + writel_relaxed(save->intpol0, base + SA1111_INTPOL0); + writel_relaxed(save->intpol1, base + SA1111_INTPOL1); + writel_relaxed(save->inten0, base + SA1111_INTEN0); + writel_relaxed(save->inten1, base + SA1111_INTEN1); + writel_relaxed(save->wakepol0, base + SA1111_WAKEPOL0); + writel_relaxed(save->wakepol1, base + SA1111_WAKEPOL1); + writel_relaxed(save->wakeen0, base + SA1111_WAKEEN0); + writel_relaxed(save->wakeen1, base + SA1111_WAKEEN1); spin_unlock_irqrestore(&sachip->lock, flags); @@ -1153,7 +1185,7 @@ static unsigned int __sa1111_pll_clock(struct sa1111 *sachip) { unsigned int skcdr, fbdiv, ipdiv, opdiv; - skcdr = sa1111_readl(sachip->base + SA1111_SKCDR); + skcdr = readl_relaxed(sachip->base + SA1111_SKCDR); fbdiv = (skcdr & 0x007f) + 2; ipdiv = ((skcdr & 0x0f80) >> 7) + 2; @@ -1195,13 +1227,13 @@ void sa1111_select_audio_mode(struct sa1111_dev *sadev, int mode) spin_lock_irqsave(&sachip->lock, flags); - val = sa1111_readl(sachip->base + SA1111_SKCR); + val = readl_relaxed(sachip->base + SA1111_SKCR); if (mode == SA1111_AUDIO_I2S) { val &= ~SKCR_SELAC; } else { val |= SKCR_SELAC; } - sa1111_writel(val, sachip->base + SA1111_SKCR); + writel_relaxed(val, sachip->base + SA1111_SKCR); spin_unlock_irqrestore(&sachip->lock, flags); } @@ -1226,7 +1258,7 @@ int sa1111_set_audio_rate(struct sa1111_dev *sadev, int rate) if (div > 128) div = 128; - sa1111_writel(div - 1, sachip->base + SA1111_SKAUD); + writel_relaxed(div - 1, sachip->base + SA1111_SKAUD); return 0; } @@ -1244,7 +1276,7 @@ int sa1111_get_audio_rate(struct sa1111_dev *sadev) if (sadev->devid != SA1111_DEVID_SAC) return -EINVAL; - div = sa1111_readl(sachip->base + SA1111_SKAUD) + 1; + div = readl_relaxed(sachip->base + SA1111_SKAUD) + 1; return __sa1111_pll_clock(sachip) / (256 * div); } @@ -1261,10 +1293,10 @@ void sa1111_set_io_dir(struct sa1111_dev *sadev, #define MODIFY_BITS(port, mask, dir) \ if (mask) { \ - val = sa1111_readl(port); \ + val = readl_relaxed(port); \ val &= ~(mask); \ val |= (dir) & (mask); \ - sa1111_writel(val, port); \ + writel_relaxed(val, port); \ } spin_lock_irqsave(&sachip->lock, flags); @@ -1329,8 +1361,8 @@ int sa1111_enable_device(struct sa1111_dev *sadev) if (ret == 0) { spin_lock_irqsave(&sachip->lock, flags); - val = sa1111_readl(sachip->base + SA1111_SKPCR); - sa1111_writel(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR); + val = readl_relaxed(sachip->base + SA1111_SKPCR); + writel_relaxed(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR); spin_unlock_irqrestore(&sachip->lock, flags); } return ret; @@ -1348,8 +1380,8 @@ void sa1111_disable_device(struct sa1111_dev *sadev) unsigned int val; spin_lock_irqsave(&sachip->lock, flags); - val = sa1111_readl(sachip->base + SA1111_SKPCR); - sa1111_writel(val & ~sadev->skpcr_mask, sachip->base + SA1111_SKPCR); + val = readl_relaxed(sachip->base + SA1111_SKPCR); + writel_relaxed(val & ~sadev->skpcr_mask, sachip->base + SA1111_SKPCR); spin_unlock_irqrestore(&sachip->lock, flags); if (sachip->pdata && sachip->pdata->disable) @@ -1359,9 +1391,10 @@ EXPORT_SYMBOL(sa1111_disable_device); int sa1111_get_irq(struct sa1111_dev *sadev, unsigned num) { - if (num >= ARRAY_SIZE(sadev->irq)) + struct sa1111 *sachip = sa1111_chip_driver(sadev); + if (num >= ARRAY_SIZE(sadev->hwirq)) return -EINVAL; - return sadev->irq[num]; + return sa1111_map_irq(sachip, sadev->hwirq[num]); } EXPORT_SYMBOL_GPL(sa1111_get_irq); @@ -1379,36 +1412,6 @@ static int sa1111_match(struct device *_dev, struct device_driver *_drv) return !!(dev->devid & drv->devid); } -static int sa1111_bus_suspend(struct device *dev, pm_message_t state) -{ - struct sa1111_dev *sadev = to_sa1111_device(dev); - struct sa1111_driver *drv = SA1111_DRV(dev->driver); - int ret = 0; - - if (drv && drv->suspend) - ret = drv->suspend(sadev, state); - return ret; -} - -static int sa1111_bus_resume(struct device *dev) -{ - struct sa1111_dev *sadev = to_sa1111_device(dev); - struct sa1111_driver *drv = SA1111_DRV(dev->driver); - int ret = 0; - - if (drv && drv->resume) - ret = drv->resume(sadev); - return ret; -} - -static void sa1111_bus_shutdown(struct device *dev) -{ - struct sa1111_driver *drv = SA1111_DRV(dev->driver); - - if (drv && drv->shutdown) - drv->shutdown(to_sa1111_device(dev)); -} - static int sa1111_bus_probe(struct device *dev) { struct sa1111_dev *sadev = to_sa1111_device(dev); @@ -1436,9 +1439,6 @@ struct bus_type sa1111_bus_type = { .match = sa1111_match, .probe = sa1111_bus_probe, .remove = sa1111_bus_remove, - .suspend = sa1111_bus_suspend, - .resume = sa1111_bus_resume, - .shutdown = sa1111_bus_shutdown, }; EXPORT_SYMBOL(sa1111_bus_type); diff --git a/arch/arm/configs/aspeed_g4_defconfig b/arch/arm/configs/aspeed_g4_defconfig index d23b9d56a88b..95946dee9c77 100644 --- a/arch/arm/configs/aspeed_g4_defconfig +++ b/arch/arm/configs/aspeed_g4_defconfig @@ -1,7 +1,6 @@ CONFIG_KERNEL_XZ=y # CONFIG_SWAP is not set CONFIG_SYSVIPC=y -CONFIG_IRQ_DOMAIN_DEBUG=y CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 diff --git a/arch/arm/configs/aspeed_g5_defconfig b/arch/arm/configs/aspeed_g5_defconfig index c0ad7b82086b..8c7ea033cdc2 100644 --- a/arch/arm/configs/aspeed_g5_defconfig +++ b/arch/arm/configs/aspeed_g5_defconfig @@ -1,7 +1,6 @@ CONFIG_KERNEL_XZ=y # CONFIG_SWAP is not set CONFIG_SYSVIPC=y -CONFIG_IRQ_DOMAIN_DEBUG=y CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 diff --git a/arch/arm/configs/cns3420vb_defconfig b/arch/arm/configs/cns3420vb_defconfig index 63a953d855a6..c6dcd6e4f4e6 100644 --- a/arch/arm/configs/cns3420vb_defconfig +++ b/arch/arm/configs/cns3420vb_defconfig @@ -28,7 +28,6 @@ CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_CMDLINE="console=ttyS0,38400 mem=128M root=/dev/mmcblk0p1 ro rootwait" CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -# CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig index bd0cf22f9ceb..026154c1d55a 100644 --- a/arch/arm/configs/davinci_all_defconfig +++ b/arch/arm/configs/davinci_all_defconfig @@ -94,6 +94,7 @@ CONFIG_PPP=m CONFIG_PPP_DEFLATE=m CONFIG_PPP_ASYNC=m CONFIG_PPP_SYNC_TTY=m +CONFIG_USB_USBNET=m CONFIG_INPUT_EVDEV=m CONFIG_INPUT_EVBUG=m CONFIG_KEYBOARD_ATKBD=m diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig index f1d7834990ec..629189c62fd1 100644 --- a/arch/arm/configs/exynos_defconfig +++ b/arch/arm/configs/exynos_defconfig @@ -3,6 +3,7 @@ CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_CGROUPS=y CONFIG_BLK_DEV_INITRD=y +CONFIG_PERF_EVENTS=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_PARTITION_ADVANCED=y @@ -179,6 +180,7 @@ CONFIG_REGULATOR_TPS65090=y CONFIG_REGULATOR_WM8994=y CONFIG_MEDIA_SUPPORT=m CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CEC_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_MEDIA_USB_SUPPORT=y @@ -195,6 +197,8 @@ CONFIG_VIDEO_SAMSUNG_S5P_MFC=m CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m CONFIG_V4L_TEST_DRIVERS=y CONFIG_VIDEO_VIVID=m +CONFIG_CEC_PLATFORM_DRIVERS=y +CONFIG_VIDEO_SAMSUNG_S5P_CEC=m CONFIG_DRM=y CONFIG_DRM_EXYNOS=y CONFIG_DRM_EXYNOS_FIMD=y @@ -207,6 +211,7 @@ CONFIG_DRM_PANEL_SAMSUNG_LD9040=y CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=y CONFIG_DRM_NXP_PTN3460=y CONFIG_DRM_PARADE_PS8622=y +CONFIG_DRM_SII9234=y CONFIG_LCD_CLASS_DEVICE=y CONFIG_LCD_PLATFORM=y CONFIG_BACKLIGHT_PWM=y @@ -218,6 +223,7 @@ CONFIG_SND_SOC_SAMSUNG=y CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994=y CONFIG_SND_SOC_SMDK_WM8994_PCM=y CONFIG_SND_SOC_SNOW=y +CONFIG_SND_SOC_ODROID=y CONFIG_SND_SIMPLE_CARD=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y @@ -281,6 +287,7 @@ CONFIG_DEVFREQ_GOV_POWERSAVE=y CONFIG_DEVFREQ_GOV_USERSPACE=y CONFIG_ARM_EXYNOS_BUS_DEVFREQ=y CONFIG_DEVFREQ_EVENT_EXYNOS_NOCP=y +CONFIG_EXYNOS_IOMMU=y CONFIG_EXTCON=y CONFIG_EXTCON_MAX14577=y CONFIG_EXTCON_MAX77693=y diff --git a/arch/arm/configs/hisi_defconfig b/arch/arm/configs/hisi_defconfig index b2e340b272ee..74d611e41e02 100644 --- a/arch/arm/configs/hisi_defconfig +++ b/arch/arm/configs/hisi_defconfig @@ -1,4 +1,3 @@ -CONFIG_IRQ_DOMAIN_DEBUG=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_BLK_DEV_INITRD=y diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index 0d4494922561..4cb9829fccd1 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -55,6 +55,7 @@ CONFIG_FORCE_MAX_ZONEORDER=14 CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" CONFIG_KEXEC=y CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y @@ -80,6 +81,7 @@ CONFIG_CAN=y CONFIG_CAN_FLEXCAN=y CONFIG_BT=y CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_SERDEV=y CONFIG_BT_HCIUART_H4=y CONFIG_BT_HCIUART_LL=y CONFIG_CFG80211=y @@ -155,6 +157,7 @@ CONFIG_USB_USBNET=y CONFIG_USB_NET_CDC_EEM=m CONFIG_BRCMFMAC=m CONFIG_WL12XX=m +CONFIG_WL18XX=m CONFIG_WLCORE_SDIO=m # CONFIG_WILINK_PLATFORM_DATA is not set CONFIG_INPUT_EVDEV=y @@ -185,6 +188,8 @@ CONFIG_SERIAL_IMX=y CONFIG_SERIAL_IMX_CONSOLE=y CONFIG_SERIAL_FSL_LPUART=y CONFIG_SERIAL_FSL_LPUART_CONSOLE=y +CONFIG_SERIAL_DEV_BUS=y +CONFIG_SERIAL_DEV_CTRL_TTYPORT=y # CONFIG_I2C_COMPAT is not set CONFIG_I2C_CHARDEV=y CONFIG_I2C_MUX=y @@ -248,6 +253,7 @@ CONFIG_VIDEO_OV5640=m CONFIG_SOC_CAMERA_OV2640=y CONFIG_IMX_IPUV3_CORE=y CONFIG_DRM=y +CONFIG_DRM_PANEL_LVDS=y CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_DW_HDMI_AHB_AUDIO=m CONFIG_DRM_DW_HDMI_CEC=y @@ -340,6 +346,7 @@ CONFIG_LEDS_TRIGGER_ONESHOT=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_LEDS_TRIGGER_BACKLIGHT=y CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y CONFIG_RTC_CLASS=y CONFIG_RTC_INTF_DEV_UIE_EMUL=y CONFIG_RTC_DRV_DS1307=y @@ -349,6 +356,7 @@ CONFIG_RTC_DRV_PCF8563=y CONFIG_RTC_DRV_M41T80=y CONFIG_RTC_DRV_MC13XXX=y CONFIG_RTC_DRV_MXC=y +CONFIG_RTC_DRV_MXC_V2=y CONFIG_RTC_DRV_SNVS=y CONFIG_DMADEVICES=y CONFIG_FSL_EDMA=y diff --git a/arch/arm/configs/keystone_defconfig b/arch/arm/configs/keystone_defconfig index f710c192b33a..2536c231eea1 100644 --- a/arch/arm/configs/keystone_defconfig +++ b/arch/arm/configs/keystone_defconfig @@ -228,3 +228,10 @@ CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_USER_API_HASH=y CONFIG_CRYPTO_USER_API_SKCIPHER=y +CONFIG_SPI_CADENCE_QUADSPI=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_GPIO_DECODER=m +CONFIG_GPIO_PCA953X=m +CONFIG_LEDS_TRIGGER_ACTIVITY=y +CONFIG_LEDS_TRIGGER_CPU=y diff --git a/arch/arm/configs/magician_defconfig b/arch/arm/configs/magician_defconfig index ec5674c229a3..de5be2fc7306 100644 --- a/arch/arm/configs/magician_defconfig +++ b/arch/arm/configs/magician_defconfig @@ -54,7 +54,6 @@ CONFIG_BT_BNEP_PROTO_FILTER=y CONFIG_BT_HIDP=m CONFIG_BT_HCIBTUSB=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -# CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y diff --git a/arch/arm/configs/mini2440_defconfig b/arch/arm/configs/mini2440_defconfig index cf7dcb2c86e6..88ea02e7ba19 100644 --- a/arch/arm/configs/mini2440_defconfig +++ b/arch/arm/configs/mini2440_defconfig @@ -77,7 +77,6 @@ CONFIG_MAC80211=m CONFIG_MAC80211_MESH=y CONFIG_MAC80211_LEDS=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -# CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_CONNECTOR=m CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 61509c4b769f..da7387689b88 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -1,6 +1,5 @@ CONFIG_SYSVIPC=y CONFIG_FHANDLE=y -CONFIG_IRQ_DOMAIN_DEBUG=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_CGROUPS=y @@ -116,6 +115,8 @@ CONFIG_ARCH_ZYNQ=y CONFIG_TRUSTED_FOUNDATIONS=y CONFIG_PCI=y CONFIG_PCI_HOST_GENERIC=y +CONFIG_PCI_DRA7XX=y +CONFIG_PCI_DRA7XX_EP=y CONFIG_PCI_KEYSTONE=y CONFIG_PCI_MSI=y CONFIG_PCI_MVEBU=y @@ -123,6 +124,9 @@ CONFIG_PCI_TEGRA=y CONFIG_PCI_RCAR_GEN2=y CONFIG_PCIE_RCAR=y CONFIG_PCIEPORTBUS=y +CONFIG_PCI_ENDPOINT=y +CONFIG_PCI_ENDPOINT_CONFIGFS=y +CONFIG_PCI_EPF_TEST=m CONFIG_SMP=y CONFIG_NR_CPUS=16 CONFIG_HIGHPTE=y @@ -222,6 +226,7 @@ CONFIG_ATMEL_SSC=m CONFIG_QCOM_COINCELL=m CONFIG_APDS9802ALS=y CONFIG_ISL29003=y +CONFIG_PCI_ENDPOINT_TEST=m CONFIG_EEPROM_AT24=y CONFIG_BLK_DEV_SD=y CONFIG_BLK_DEV_SR=y @@ -557,6 +562,7 @@ CONFIG_REGULATOR_VEXPRESS=y CONFIG_REGULATOR_WM8994=m CONFIG_MEDIA_SUPPORT=m CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CEC_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_MEDIA_USB_SUPPORT=y @@ -582,6 +588,8 @@ CONFIG_VIDEO_STI_DELTA=m CONFIG_VIDEO_RENESAS_JPU=m CONFIG_VIDEO_RENESAS_VSP1=m CONFIG_V4L_TEST_DRIVERS=y +CONFIG_CEC_PLATFORM_DRIVERS=y +CONFIG_VIDEO_SAMSUNG_S5P_CEC=m # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set CONFIG_VIDEO_ADV7180=m CONFIG_VIDEO_ML86V7667=m @@ -613,6 +621,7 @@ CONFIG_DRM_TEGRA=y CONFIG_DRM_PANEL_SAMSUNG_LD9040=m CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=m CONFIG_DRM_PANEL_SIMPLE=y +CONFIG_DRM_SII9234=m CONFIG_DRM_STI=m CONFIG_DRM_VC4=y CONFIG_FB_ARMCLCD=y @@ -651,6 +660,7 @@ CONFIG_SND_SOC_SAMSUNG=m CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994=m CONFIG_SND_SOC_SMDK_WM8994_PCM=m CONFIG_SND_SOC_SNOW=m +CONFIG_SND_SOC_ODROID=m CONFIG_SND_SOC_SH4_FSI=m CONFIG_SND_SOC_RCAR=m CONFIG_SND_SIMPLE_SCU_CARD=m @@ -879,6 +889,7 @@ CONFIG_PWM_ATMEL=m CONFIG_PWM_ATMEL_HLCDC_PWM=m CONFIG_PWM_ATMEL_TCB=m CONFIG_PWM_FSL_FTM=m +CONFIG_PWM_RCAR=m CONFIG_PWM_RENESAS_TPU=y CONFIG_PWM_ROCKCHIP=m CONFIG_PWM_SAMSUNG=m diff --git a/arch/arm/configs/mv78xx0_defconfig b/arch/arm/configs/mv78xx0_defconfig index 752e2e74de5b..0448bd8075ac 100644 --- a/arch/arm/configs/mv78xx0_defconfig +++ b/arch/arm/configs/mv78xx0_defconfig @@ -37,7 +37,6 @@ CONFIG_IP_PNP_BOOTP=y # CONFIG_IPV6 is not set CONFIG_NET_PKTGEN=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -# CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y diff --git a/arch/arm/configs/mvebu_v7_defconfig b/arch/arm/configs/mvebu_v7_defconfig index 69553704f2dc..ddaeda4f2e82 100644 --- a/arch/arm/configs/mvebu_v7_defconfig +++ b/arch/arm/configs/mvebu_v7_defconfig @@ -1,6 +1,5 @@ CONFIG_SYSVIPC=y CONFIG_FHANDLE=y -CONFIG_IRQ_DOMAIN_DEBUG=y CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y @@ -57,7 +56,7 @@ CONFIG_MTD_CFI_STAA=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_M25P80=y CONFIG_MTD_NAND=y -CONFIG_MTD_NAND_PXA3xx=y +CONFIG_MTD_NAND_MARVELL=y CONFIG_MTD_SPI_NOR=y CONFIG_SRAM=y CONFIG_MTD_UBI=y diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig index e5822ab01b7d..bbfb6759447b 100644 --- a/arch/arm/configs/mxs_defconfig +++ b/arch/arm/configs/mxs_defconfig @@ -46,7 +46,6 @@ CONFIG_CAN_FLEXCAN=m # CONFIG_WIRELESS is not set CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y -# CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index 7b97200c1d64..2f145c4af93a 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -48,6 +48,13 @@ CONFIG_SOC_AM43XX=y CONFIG_SOC_DRA7XX=y CONFIG_ARM_THUMBEE=y CONFIG_ARM_ERRATA_411920=y +CONFIG_PCI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_DRA7XX=y +CONFIG_PCI_DRA7XX_EP=y +CONFIG_PCI_ENDPOINT=y +CONFIG_PCI_ENDPOINT_CONFIGFS=y +CONFIG_PCI_EPF_TEST=m CONFIG_SMP=y CONFIG_NR_CPUS=2 CONFIG_CMA=y @@ -137,6 +144,7 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=16384 CONFIG_SENSORS_TSL2550=m CONFIG_SRAM=y +CONFIG_PCI_ENDPOINT_TEST=m CONFIG_EEPROM_AT24=m CONFIG_BLK_DEV_SD=y CONFIG_SCSI_SCAN_ASYNC=y @@ -468,6 +476,7 @@ CONFIG_PWM_TIECAP=m CONFIG_PWM_TIEHRPWM=m CONFIG_PWM_TWL=m CONFIG_PWM_TWL_LED=m +CONFIG_PHY_CPCAP_USB=m CONFIG_PHY_DM816X_USB=m CONFIG_OMAP_USB2=m CONFIG_TI_PIPE3=y @@ -516,3 +525,13 @@ CONFIG_LIBCRC32C=y CONFIG_FONTS=y CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y +CONFIG_KERNEL_MODE_NEON=y +CONFIG_ARM_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM=m +CONFIG_CRYPTO_SHA1_ARM_NEON=m +CONFIG_CRYPTO_SHA256_ARM=m +CONFIG_CRYPTO_SHA512_ARM=m +CONFIG_CRYPTO_AES_ARM=m +CONFIG_CRYPTO_AES_ARM_BS=m +CONFIG_CRYPTO_CHACHA20_NEON=m +CONFIG_CRYPTO_GHASH_ARM_CE=m diff --git a/arch/arm/configs/orion5x_defconfig b/arch/arm/configs/orion5x_defconfig index b831baddae02..bf9046331f6e 100644 --- a/arch/arm/configs/orion5x_defconfig +++ b/arch/arm/configs/orion5x_defconfig @@ -60,7 +60,6 @@ CONFIG_IP_PNP_BOOTP=y CONFIG_NET_DSA=y CONFIG_NET_PKTGEN=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -# CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y diff --git a/arch/arm/configs/pxa_defconfig b/arch/arm/configs/pxa_defconfig index 830e817a028a..837d0c9c8b0e 100644 --- a/arch/arm/configs/pxa_defconfig +++ b/arch/arm/configs/pxa_defconfig @@ -1,7 +1,6 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_FHANDLE=y -CONFIG_IRQ_DOMAIN_DEBUG=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_BSD_PROCESS_ACCT=y diff --git a/arch/arm/configs/qcom_defconfig b/arch/arm/configs/qcom_defconfig index c784d04e2ab7..dd2a089f939f 100644 --- a/arch/arm/configs/qcom_defconfig +++ b/arch/arm/configs/qcom_defconfig @@ -136,7 +136,9 @@ CONFIG_REGULATOR_QCOM_RPM=y CONFIG_REGULATOR_QCOM_SMD_RPM=y CONFIG_REGULATOR_QCOM_SPMI=y CONFIG_MEDIA_SUPPORT=y +CONFIG_DRM=y CONFIG_FB=y +CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_BACKLIGHT_LCD_SUPPORT=y # CONFIG_LCD_CLASS_DEVICE is not set CONFIG_BACKLIGHT_CLASS_DEVICE=y @@ -200,6 +202,7 @@ CONFIG_MSM_LCC_8960=y CONFIG_MDM_LCC_9615=y CONFIG_MSM_MMCC_8960=y CONFIG_MSM_MMCC_8974=y +CONFIG_MSM_IOMMU=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_REMOTEPROC=y diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index 6529cb43e0fd..2080025556b5 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -2,7 +2,6 @@ # CONFIG_SWAP is not set CONFIG_SYSVIPC=y CONFIG_FHANDLE=y -CONFIG_IRQ_DOMAIN_DEBUG=y CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig index 7b4fc0143148..578434cfd1a0 100644 --- a/arch/arm/configs/shmobile_defconfig +++ b/arch/arm/configs/shmobile_defconfig @@ -173,6 +173,7 @@ CONFIG_SND_SOC=y CONFIG_SND_SOC_SH4_FSI=y CONFIG_SND_SOC_RCAR=y CONFIG_SND_SOC_AK4642=y +CONFIG_SND_SOC_SGTL5000=y CONFIG_SND_SOC_WM8978=y CONFIG_SND_SIMPLE_SCU_CARD=y CONFIG_USB=y @@ -207,6 +208,7 @@ CONFIG_STAGING_BOARD=y CONFIG_IIO=y CONFIG_AK8975=y CONFIG_PWM=y +CONFIG_PWM_RCAR=y CONFIG_PWM_RENESAS_TPU=y CONFIG_GENERIC_PHY=y CONFIG_PHY_RCAR_GEN2=y diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig index 5caaf971fb50..df433abfcb02 100644 --- a/arch/arm/configs/sunxi_defconfig +++ b/arch/arm/configs/sunxi_defconfig @@ -10,6 +10,7 @@ CONFIG_SMP=y CONFIG_NR_CPUS=8 CONFIG_AEABI=y CONFIG_HIGHMEM=y +CONFIG_CMA=y CONFIG_ARM_APPENDED_DTB=y CONFIG_ARM_ATAG_DTB_COMPAT=y CONFIG_CPU_FREQ=y @@ -33,6 +34,7 @@ CONFIG_CAN_SUN4I=y # CONFIG_WIRELESS is not set CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DMA_CMA=y CONFIG_BLK_DEV_SD=y CONFIG_ATA=y CONFIG_AHCI_SUNXI=y diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig index 6678f2929356..c7b99ebf5fcf 100644 --- a/arch/arm/configs/tegra_defconfig +++ b/arch/arm/configs/tegra_defconfig @@ -1,5 +1,4 @@ CONFIG_SYSVIPC=y -CONFIG_IRQ_DOMAIN_DEBUG=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y @@ -76,7 +75,6 @@ CONFIG_RFKILL_INPUT=y CONFIG_RFKILL_GPIO=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y -# CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_DMA_CMA=y CONFIG_CMA_SIZE_MBYTES=64 CONFIG_TEGRA_GMI=y diff --git a/arch/arm/configs/vf610m4_defconfig b/arch/arm/configs/vf610m4_defconfig index b7ecb83a95b6..a89f035c3b01 100644 --- a/arch/arm/configs/vf610m4_defconfig +++ b/arch/arm/configs/vf610m4_defconfig @@ -23,7 +23,6 @@ CONFIG_BINFMT_SHARED_FLAT=y # CONFIG_UEVENT_HELPER is not set # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FIRMWARE_IN_KERNEL is not set # CONFIG_ALLOW_DEV_COREDUMP is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=4 diff --git a/arch/arm/configs/vt8500_v6_v7_defconfig b/arch/arm/configs/vt8500_v6_v7_defconfig index 1bfaa7bfc392..9b85326ba287 100644 --- a/arch/arm/configs/vt8500_v6_v7_defconfig +++ b/arch/arm/configs/vt8500_v6_v7_defconfig @@ -1,4 +1,3 @@ -CONFIG_IRQ_DOMAIN_DEBUG=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_BLK_DEV_INITRD=y diff --git a/arch/arm/crypto/aes-neonbs-glue.c b/arch/arm/crypto/aes-neonbs-glue.c index 18768f330449..07e31941dc67 100644 --- a/arch/arm/crypto/aes-neonbs-glue.c +++ b/arch/arm/crypto/aes-neonbs-glue.c @@ -181,9 +181,8 @@ static int cbc_init(struct crypto_tfm *tfm) struct aesbs_cbc_ctx *ctx = crypto_tfm_ctx(tfm); ctx->enc_tfm = crypto_alloc_cipher("aes", 0, 0); - if (IS_ERR(ctx->enc_tfm)) - return PTR_ERR(ctx->enc_tfm); - return 0; + + return PTR_ERR_OR_ZERO(ctx->enc_tfm); } static void cbc_exit(struct crypto_tfm *tfm) @@ -258,9 +257,8 @@ static int xts_init(struct crypto_tfm *tfm) struct aesbs_xts_ctx *ctx = crypto_tfm_ctx(tfm); ctx->tweak_tfm = crypto_alloc_cipher("aes", 0, 0); - if (IS_ERR(ctx->tweak_tfm)) - return PTR_ERR(ctx->tweak_tfm); - return 0; + + return PTR_ERR_OR_ZERO(ctx->tweak_tfm); } static void xts_exit(struct crypto_tfm *tfm) diff --git a/arch/arm/crypto/crc32-ce-glue.c b/arch/arm/crypto/crc32-ce-glue.c index 1b0e0e86ee9c..96e62ec105d0 100644 --- a/arch/arm/crypto/crc32-ce-glue.c +++ b/arch/arm/crypto/crc32-ce-glue.c @@ -188,6 +188,7 @@ static struct shash_alg crc32_pmull_algs[] = { { .base.cra_name = "crc32", .base.cra_driver_name = "crc32-arm-ce", .base.cra_priority = 200, + .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, .base.cra_blocksize = 1, .base.cra_module = THIS_MODULE, }, { @@ -203,6 +204,7 @@ static struct shash_alg crc32_pmull_algs[] = { { .base.cra_name = "crc32c", .base.cra_driver_name = "crc32c-arm-ce", .base.cra_priority = 200, + .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, .base.cra_blocksize = 1, .base.cra_module = THIS_MODULE, } }; diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild index 0f2c8a2a8131..873e3c189279 100644 --- a/arch/arm/include/asm/Kbuild +++ b/arch/arm/include/asm/Kbuild @@ -1,4 +1,3 @@ -generic-y += clkdev.h generic-y += current.h generic-y += early_ioremap.h generic-y += emergency-restart.h diff --git a/arch/arm/include/asm/bitops.h b/arch/arm/include/asm/bitops.h index ce5ee762ed66..4cab9bb823fb 100644 --- a/arch/arm/include/asm/bitops.h +++ b/arch/arm/include/asm/bitops.h @@ -338,6 +338,7 @@ static inline int find_next_bit_le(const void *p, int size, int offset) #endif +#include #include /* diff --git a/arch/arm/include/asm/dma-direct.h b/arch/arm/include/asm/dma-direct.h new file mode 100644 index 000000000000..5b0a8a421894 --- /dev/null +++ b/arch/arm/include/asm/dma-direct.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef ASM_ARM_DMA_DIRECT_H +#define ASM_ARM_DMA_DIRECT_H 1 + +static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) +{ + unsigned int offset = paddr & ~PAGE_MASK; + return pfn_to_dma(dev, __phys_to_pfn(paddr)) + offset; +} + +static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr) +{ + unsigned int offset = dev_addr & ~PAGE_MASK; + return __pfn_to_phys(dma_to_pfn(dev, dev_addr)) + offset; +} + +static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) +{ + u64 limit, mask; + + if (!dev->dma_mask) + return 0; + + mask = *dev->dma_mask; + + limit = (mask + 1) & ~mask; + if (limit && size > limit) + return 0; + + if ((addr | (addr + size - 1)) & ~mask) + return 0; + + return 1; +} + +#endif /* ASM_ARM_DMA_DIRECT_H */ diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index daf837423a76..8436f6ade57d 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -18,7 +18,7 @@ extern const struct dma_map_ops arm_coherent_dma_ops; static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus) { - return IS_ENABLED(CONFIG_MMU) ? &arm_dma_ops : &dma_noop_ops; + return IS_ENABLED(CONFIG_MMU) ? &arm_dma_ops : &dma_direct_ops; } #ifdef __arch_page_to_dma @@ -109,39 +109,6 @@ static inline bool is_device_dma_coherent(struct device *dev) return dev->archdata.dma_coherent; } -static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) -{ - unsigned int offset = paddr & ~PAGE_MASK; - return pfn_to_dma(dev, __phys_to_pfn(paddr)) + offset; -} - -static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr) -{ - unsigned int offset = dev_addr & ~PAGE_MASK; - return __pfn_to_phys(dma_to_pfn(dev, dev_addr)) + offset; -} - -static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) -{ - u64 limit, mask; - - if (!dev->dma_mask) - return 0; - - mask = *dev->dma_mask; - - limit = (mask + 1) & ~mask; - if (limit && size > limit) - return 0; - - if ((addr | (addr + size - 1)) & ~mask) - return 0; - - return 1; -} - -static inline void dma_mark_clean(void *addr, size_t size) { } - /** * arm_dma_alloc - allocate consistent memory for DMA * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices diff --git a/arch/arm/include/asm/exception.h b/arch/arm/include/asm/exception.h index a7273ad9587a..58e039a851af 100644 --- a/arch/arm/include/asm/exception.h +++ b/arch/arm/include/asm/exception.h @@ -10,11 +10,10 @@ #include -#define __exception __attribute__((section(".exception.text"))) #ifdef CONFIG_FUNCTION_GRAPH_TRACER #define __exception_irq_entry __irq_entry #else -#define __exception_irq_entry __exception +#define __exception_irq_entry #endif #endif /* __ASM_ARM_EXCEPTION_H */ diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h index 01c3d92624e5..8d1f498e5dd8 100644 --- a/arch/arm/include/asm/glue-cache.h +++ b/arch/arm/include/asm/glue-cache.h @@ -117,6 +117,10 @@ # endif #endif +#if defined(CONFIG_CACHE_B15_RAC) +# define MULTI_CACHE 1 +#endif + #if defined(CONFIG_CPU_V7M) # define MULTI_CACHE 1 #endif diff --git a/arch/arm/include/asm/hardware/cache-b15-rac.h b/arch/arm/include/asm/hardware/cache-b15-rac.h new file mode 100644 index 000000000000..3d43ec06fd35 --- /dev/null +++ b/arch/arm/include/asm/hardware/cache-b15-rac.h @@ -0,0 +1,10 @@ +#ifndef __ASM_ARM_HARDWARE_CACHE_B15_RAC_H +#define __ASM_ARM_HARDWARE_CACHE_B15_RAC_H + +#ifndef __ASSEMBLY__ + +void b15_flush_kern_cache_all(void); + +#endif + +#endif diff --git a/arch/arm/include/asm/hardware/sa1111.h b/arch/arm/include/asm/hardware/sa1111.h index 0bbf163d1ed3..798e520e8a49 100644 --- a/arch/arm/include/asm/hardware/sa1111.h +++ b/arch/arm/include/asm/hardware/sa1111.h @@ -15,33 +15,6 @@ #include -/* - * The SA1111 is always located at virtual 0xf4000000, and is always - * "native" endian. - */ - -#define SA1111_VBASE 0xf4000000 - -/* Don't use these! */ -#define SA1111_p2v( x ) ((x) - SA1111_BASE + SA1111_VBASE) -#define SA1111_v2p( x ) ((x) - SA1111_VBASE + SA1111_BASE) - -#ifndef __ASSEMBLY__ -#define _SA1111(x) ((x) + sa1111->resource.start) -#endif - -#define sa1111_writel(val,addr) __raw_writel(val, addr) -#define sa1111_readl(addr) __raw_readl(addr) - -/* - * 26 bits of the SA-1110 address bus are available to the SA-1111. - * Use these when feeding target addresses to the DMA engines. - */ - -#define SA1111_ADDR_WIDTH (26) -#define SA1111_ADDR_MASK ((1<arch.ctxt.gp_regs.usr_regs.ARM_cpsr & MODE_MASK; - return cpsr_mode > USR_MODE;; + return cpsr_mode > USR_MODE; } static inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index a9f7d3f47134..248b930563e5 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -48,6 +48,8 @@ KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) #define KVM_REQ_IRQ_PENDING KVM_ARCH_REQ(1) +DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use); + u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode); int __attribute_const__ kvm_target_cpu(void); int kvm_reset_vcpu(struct kvm_vcpu *vcpu); @@ -238,6 +240,9 @@ int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, int exception_index); +static inline void handle_exit_early(struct kvm_vcpu *vcpu, struct kvm_run *run, + int exception_index) {} + static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr, unsigned long hyp_stack_ptr, unsigned long vector_ptr) @@ -301,4 +306,13 @@ int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu, /* All host FP/SIMD state is restored on guest exit, so nothing to save: */ static inline void kvm_fpsimd_flush_cpu_state(void) {} +static inline void kvm_arm_vhe_guest_enter(void) {} +static inline void kvm_arm_vhe_guest_exit(void) {} + +static inline bool kvm_arm_harden_branch_predictor(void) +{ + /* No way to detect it yet, pretend it is not there. */ + return false; +} + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/include/asm/kvm_hyp.h b/arch/arm/include/asm/kvm_hyp.h index ab20ffa8b9e7..1ab8329e9ff7 100644 --- a/arch/arm/include/asm/kvm_hyp.h +++ b/arch/arm/include/asm/kvm_hyp.h @@ -21,7 +21,6 @@ #include #include #include -#include #include #define __hyp_text __section(.hyp.text) notrace @@ -69,6 +68,8 @@ #define HIFAR __ACCESS_CP15(c6, 4, c0, 2) #define HPFAR __ACCESS_CP15(c6, 4, c0, 4) #define ICIALLUIS __ACCESS_CP15(c7, 0, c1, 0) +#define BPIALLIS __ACCESS_CP15(c7, 0, c1, 6) +#define ICIMVAU __ACCESS_CP15(c7, 0, c5, 1) #define ATS1CPR __ACCESS_CP15(c7, 0, c8, 0) #define TLBIALLIS __ACCESS_CP15(c8, 0, c3, 0) #define TLBIALL __ACCESS_CP15(c8, 0, c7, 0) diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h index fa6f2174276b..de1b919404e4 100644 --- a/arch/arm/include/asm/kvm_mmu.h +++ b/arch/arm/include/asm/kvm_mmu.h @@ -37,6 +37,8 @@ #include #include +#include +#include #include #include @@ -83,6 +85,18 @@ static inline pmd_t kvm_s2pmd_mkwrite(pmd_t pmd) return pmd; } +static inline pte_t kvm_s2pte_mkexec(pte_t pte) +{ + pte_val(pte) &= ~L_PTE_XN; + return pte; +} + +static inline pmd_t kvm_s2pmd_mkexec(pmd_t pmd) +{ + pmd_val(pmd) &= ~PMD_SECT_XN; + return pmd; +} + static inline void kvm_set_s2pte_readonly(pte_t *pte) { pte_val(*pte) = (pte_val(*pte) & ~L_PTE_S2_RDWR) | L_PTE_S2_RDONLY; @@ -93,6 +107,11 @@ static inline bool kvm_s2pte_readonly(pte_t *pte) return (pte_val(*pte) & L_PTE_S2_RDWR) == L_PTE_S2_RDONLY; } +static inline bool kvm_s2pte_exec(pte_t *pte) +{ + return !(pte_val(*pte) & L_PTE_XN); +} + static inline void kvm_set_s2pmd_readonly(pmd_t *pmd) { pmd_val(*pmd) = (pmd_val(*pmd) & ~L_PMD_S2_RDWR) | L_PMD_S2_RDONLY; @@ -103,6 +122,11 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd) return (pmd_val(*pmd) & L_PMD_S2_RDWR) == L_PMD_S2_RDONLY; } +static inline bool kvm_s2pmd_exec(pmd_t *pmd) +{ + return !(pmd_val(*pmd) & PMD_SECT_XN); +} + static inline bool kvm_page_empty(void *ptr) { struct page *ptr_page = virt_to_page(ptr); @@ -126,21 +150,10 @@ static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu) return (vcpu_cp15(vcpu, c1_SCTLR) & 0b101) == 0b101; } -static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, - kvm_pfn_t pfn, - unsigned long size) +static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size) { /* - * If we are going to insert an instruction page and the icache is - * either VIPT or PIPT, there is a potential problem where the host - * (or another VM) may have used the same page as this guest, and we - * read incorrect data from the icache. If we're using a PIPT cache, - * we can invalidate just that page, but if we are using a VIPT cache - * we need to invalidate the entire icache - damn shame - as written - * in the ARM ARM (DDI 0406C.b - Page B3-1393). - * - * VIVT caches are tagged using both the ASID and the VMID and doesn't - * need any kind of flushing (DDI 0406C.b - Page B3-1392). + * Clean the dcache to the Point of Coherency. * * We need to do this through a kernel mapping (using the * user-space mapping has proved to be the wrong @@ -155,9 +168,63 @@ static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, kvm_flush_dcache_to_poc(va, PAGE_SIZE); - if (icache_is_pipt()) - __cpuc_coherent_user_range((unsigned long)va, - (unsigned long)va + PAGE_SIZE); + size -= PAGE_SIZE; + pfn++; + + kunmap_atomic(va); + } +} + +static inline void __invalidate_icache_guest_page(kvm_pfn_t pfn, + unsigned long size) +{ + u32 iclsz; + + /* + * If we are going to insert an instruction page and the icache is + * either VIPT or PIPT, there is a potential problem where the host + * (or another VM) may have used the same page as this guest, and we + * read incorrect data from the icache. If we're using a PIPT cache, + * we can invalidate just that page, but if we are using a VIPT cache + * we need to invalidate the entire icache - damn shame - as written + * in the ARM ARM (DDI 0406C.b - Page B3-1393). + * + * VIVT caches are tagged using both the ASID and the VMID and doesn't + * need any kind of flushing (DDI 0406C.b - Page B3-1392). + */ + + VM_BUG_ON(size & ~PAGE_MASK); + + if (icache_is_vivt_asid_tagged()) + return; + + if (!icache_is_pipt()) { + /* any kind of VIPT cache */ + __flush_icache_all(); + return; + } + + /* + * CTR IminLine contains Log2 of the number of words in the + * cache line, so we can get the number of words as + * 2 << (IminLine - 1). To get the number of bytes, we + * multiply by 4 (the number of bytes in a 32-bit word), and + * get 4 << (IminLine). + */ + iclsz = 4 << (read_cpuid(CPUID_CACHETYPE) & 0xf); + + while (size) { + void *va = kmap_atomic_pfn(pfn); + void *end = va + PAGE_SIZE; + void *addr = va; + + do { + write_sysreg(addr, ICIMVAU); + addr += iclsz; + } while (addr < end); + + dsb(ishst); + isb(); size -= PAGE_SIZE; pfn++; @@ -165,9 +232,11 @@ static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, kunmap_atomic(va); } - if (!icache_is_pipt() && !icache_is_vivt_asid_tagged()) { - /* any kind of VIPT cache */ - __flush_icache_all(); + /* Check if we need to invalidate the BTB */ + if ((read_cpuid_ext(CPUID_EXT_MMFR1) >> 28) != 4) { + write_sysreg(0, BPIALLIS); + dsb(ishst); + isb(); } } @@ -211,6 +280,11 @@ static inline bool __kvm_cpu_uses_extended_idmap(void) return false; } +static inline unsigned long __kvm_idmap_ptrs_per_pgd(void) +{ + return PTRS_PER_PGD; +} + static inline void __kvm_extend_hypmap(pgd_t *boot_hyp_pgd, pgd_t *hyp_pgd, pgd_t *merged_hyp_pgd, @@ -221,6 +295,18 @@ static inline unsigned int kvm_get_vmid_bits(void) return 8; } +static inline void *kvm_get_hyp_vector(void) +{ + return kvm_ksym_ref(__kvm_hyp_vector); +} + +static inline int kvm_map_vectors(void) +{ + return 0; +} + +#define kvm_phys_to_vttbr(addr) (addr) + #endif /* !__ASSEMBLY__ */ #endif /* __ARM_KVM_MMU_H__ */ diff --git a/arch/arm/include/asm/kvm_psci.h b/arch/arm/include/asm/kvm_psci.h deleted file mode 100644 index 6bda945d31fa..000000000000 --- a/arch/arm/include/asm/kvm_psci.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2012 - ARM Ltd - * Author: Marc Zyngier - * - * 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 . - */ - -#ifndef __ARM_KVM_PSCI_H__ -#define __ARM_KVM_PSCI_H__ - -#define KVM_ARM_PSCI_0_1 1 -#define KVM_ARM_PSCI_0_2 2 - -int kvm_psci_version(struct kvm_vcpu *vcpu); -int kvm_psci_call(struct kvm_vcpu *vcpu); - -#endif /* __ARM_KVM_PSCI_H__ */ diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index 1f54e4e98c1e..496667703693 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -88,6 +88,7 @@ #else /* CONFIG_MMU */ #ifndef __ASSEMBLY__ +extern unsigned long setup_vectors_base(void); extern unsigned long vectors_base; #define VECTORS_BASE vectors_base #endif diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h index 960d9dc4f380..1f0de808d111 100644 --- a/arch/arm/include/asm/pci.h +++ b/arch/arm/include/asm/pci.h @@ -10,10 +10,7 @@ extern unsigned long pcibios_min_io; extern unsigned long pcibios_min_mem; #define PCIBIOS_MIN_MEM pcibios_min_mem -static inline int pcibios_assign_all_busses(void) -{ - return pci_has_flag(PCI_REASSIGN_ALL_RSRC); -} +#define pcibios_assign_all_busses() pci_has_flag(PCI_REASSIGN_ALL_BUS) #ifdef CONFIG_PCI_DOMAINS static inline int pci_proc_domain(struct pci_bus *bus) diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h index 1a7a17b2a1ba..2a4836087358 100644 --- a/arch/arm/include/asm/pgtable-3level.h +++ b/arch/arm/include/asm/pgtable-3level.h @@ -249,6 +249,9 @@ PMD_BIT_FUNC(mkyoung, |= PMD_SECT_AF); #define pfn_pmd(pfn,prot) (__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))) #define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot) +/* No hardware dirty/accessed bits -- generic_pmdp_establish() fits */ +#define pmdp_establish generic_pmdp_establish + /* represent a notpresent pmd by faulting entry, this is used by pmdp_invalidate */ static inline pmd_t pmd_mknotpresent(pmd_t pmd) { diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 150ece66ddf3..a757401129f9 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -102,8 +102,8 @@ extern pgprot_t pgprot_s2_device; #define PAGE_HYP_EXEC _MOD_PROT(pgprot_kernel, L_PTE_HYP | L_PTE_RDONLY) #define PAGE_HYP_RO _MOD_PROT(pgprot_kernel, L_PTE_HYP | L_PTE_RDONLY | L_PTE_XN) #define PAGE_HYP_DEVICE _MOD_PROT(pgprot_hyp_device, L_PTE_HYP) -#define PAGE_S2 _MOD_PROT(pgprot_s2, L_PTE_S2_RDONLY) -#define PAGE_S2_DEVICE _MOD_PROT(pgprot_s2_device, L_PTE_S2_RDONLY) +#define PAGE_S2 _MOD_PROT(pgprot_s2, L_PTE_S2_RDONLY | L_PTE_XN) +#define PAGE_S2_DEVICE _MOD_PROT(pgprot_s2_device, L_PTE_S2_RDONLY | L_PTE_XN) #define __PAGE_NONE __pgprot(_L_PTE_DEFAULT | L_PTE_RDONLY | L_PTE_XN | L_PTE_NONE) #define __PAGE_SHARED __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_XN) diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h index 338cbe0a18ef..1bf65b47808a 100644 --- a/arch/arm/include/asm/processor.h +++ b/arch/arm/include/asm/processor.h @@ -45,6 +45,16 @@ struct thread_struct { struct debug_info debug; }; +/* + * Everything usercopied to/from thread_struct is statically-sized, so + * no hardened usercopy whitelist is needed. + */ +static inline void arch_thread_struct_whitelist(unsigned long *offset, + unsigned long *size) +{ + *offset = *size = 0; +} + #define INIT_THREAD { } #define start_thread(regs,pc,sp) \ diff --git a/arch/arm/include/asm/ptdump.h b/arch/arm/include/asm/ptdump.h new file mode 100644 index 000000000000..3ebf9718288d --- /dev/null +++ b/arch/arm/include/asm/ptdump.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2014 ARM Ltd. */ +#ifndef __ASM_PTDUMP_H +#define __ASM_PTDUMP_H + +#ifdef CONFIG_ARM_PTDUMP_CORE + +#include +#include + +struct addr_marker { + unsigned long start_address; + char *name; +}; + +struct ptdump_info { + struct mm_struct *mm; + const struct addr_marker *markers; + unsigned long base_addr; +}; + +void ptdump_walk_pgd(struct seq_file *s, struct ptdump_info *info); +#ifdef CONFIG_ARM_PTDUMP_DEBUGFS +int ptdump_debugfs_register(struct ptdump_info *info, const char *name); +#else +static inline int ptdump_debugfs_register(struct ptdump_info *info, + const char *name) +{ + return 0; +} +#endif /* CONFIG_ARM_PTDUMP_DEBUGFS */ + +void ptdump_check_wx(void); + +#endif /* CONFIG_ARM_PTDUMP_CORE */ + +#ifdef CONFIG_DEBUG_WX +#define debug_checkwx() ptdump_check_wx() +#else +#define debug_checkwx() do { } while (0) +#endif + +#endif /* __ASM_PTDUMP_H */ diff --git a/arch/arm/include/asm/sections.h b/arch/arm/include/asm/sections.h index 63dfe1f10335..4ceb4f757d4d 100644 --- a/arch/arm/include/asm/sections.h +++ b/arch/arm/include/asm/sections.h @@ -6,4 +6,25 @@ extern char _exiprom[]; +extern char __idmap_text_start[]; +extern char __idmap_text_end[]; +extern char __entry_text_start[]; +extern char __entry_text_end[]; +extern char __hyp_idmap_text_start[]; +extern char __hyp_idmap_text_end[]; + +static inline bool in_entry_text(unsigned long addr) +{ + return memory_contains(__entry_text_start, __entry_text_end, + (void *)addr, 1); +} + +static inline bool in_idmap_text(unsigned long addr) +{ + void *a = (void *)addr; + return memory_contains(__idmap_text_start, __idmap_text_end, a, 1) || + memory_contains(__hyp_idmap_text_start, __hyp_idmap_text_end, + a, 1); +} + #endif /* _ASM_ARM_SECTIONS_H */ diff --git a/arch/arm/include/asm/string.h b/arch/arm/include/asm/string.h index f54a3136aac6..111a1d8a41dd 100644 --- a/arch/arm/include/asm/string.h +++ b/arch/arm/include/asm/string.h @@ -39,18 +39,4 @@ static inline void *memset64(uint64_t *p, uint64_t v, __kernel_size_t n) return __memset64(p, v, n * 8, v >> 32); } -extern void __memzero(void *ptr, __kernel_size_t n); - -#define memset(p,v,n) \ - ({ \ - void *__p = (p); size_t __n = n; \ - if ((__n) != 0) { \ - if (__builtin_constant_p((v)) && (v) == 0) \ - __memzero((__p),(__n)); \ - else \ - memset((__p),(v),(__n)); \ - } \ - (__p); \ - }) - #endif diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 776757d1604a..e71cc35de163 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -75,9 +75,6 @@ struct thread_info { .addr_limit = KERNEL_DS, \ } -#define init_thread_info (init_thread_union.thread_info) -#define init_stack (init_thread_union.stack) - /* * how to get the current stack pointer in C */ diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h index f9a6c5fc3fd1..a00288d75ee6 100644 --- a/arch/arm/include/asm/traps.h +++ b/arch/arm/include/asm/traps.h @@ -28,18 +28,6 @@ static inline int __in_irqentry_text(unsigned long ptr) ptr < (unsigned long)&__irqentry_text_end; } -static inline int in_exception_text(unsigned long ptr) -{ - extern char __exception_text_start[]; - extern char __exception_text_end[]; - int in; - - in = ptr >= (unsigned long)&__exception_text_start && - ptr < (unsigned long)&__exception_text_end; - - return in ? : __in_irqentry_text(ptr); -} - extern void __init early_trap_init(void *); extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame); extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs); diff --git a/arch/arm/include/asm/unified.h b/arch/arm/include/asm/unified.h index a91ae499614c..2c3b952be63e 100644 --- a/arch/arm/include/asm/unified.h +++ b/arch/arm/include/asm/unified.h @@ -20,8 +20,10 @@ #ifndef __ASM_UNIFIED_H #define __ASM_UNIFIED_H -#if defined(__ASSEMBLY__) && defined(CONFIG_ARM_ASM_UNIFIED) +#if defined(__ASSEMBLY__) .syntax unified +#else +__asm__(".syntax unified"); #endif #ifdef CONFIG_CPU_V7M @@ -64,77 +66,4 @@ #endif /* CONFIG_THUMB2_KERNEL */ -#ifndef CONFIG_ARM_ASM_UNIFIED - -/* - * If the unified assembly syntax isn't used (in ARM mode), these - * macros expand to an empty string - */ -#ifdef __ASSEMBLY__ - .macro it, cond - .endm - .macro itt, cond - .endm - .macro ite, cond - .endm - .macro ittt, cond - .endm - .macro itte, cond - .endm - .macro itet, cond - .endm - .macro itee, cond - .endm - .macro itttt, cond - .endm - .macro ittte, cond - .endm - .macro ittet, cond - .endm - .macro ittee, cond - .endm - .macro itett, cond - .endm - .macro itete, cond - .endm - .macro iteet, cond - .endm - .macro iteee, cond - .endm -#else /* !__ASSEMBLY__ */ -__asm__( -" .macro it, cond\n" -" .endm\n" -" .macro itt, cond\n" -" .endm\n" -" .macro ite, cond\n" -" .endm\n" -" .macro ittt, cond\n" -" .endm\n" -" .macro itte, cond\n" -" .endm\n" -" .macro itet, cond\n" -" .endm\n" -" .macro itee, cond\n" -" .endm\n" -" .macro itttt, cond\n" -" .endm\n" -" .macro ittte, cond\n" -" .endm\n" -" .macro ittet, cond\n" -" .endm\n" -" .macro ittee, cond\n" -" .endm\n" -" .macro itett, cond\n" -" .endm\n" -" .macro itete, cond\n" -" .endm\n" -" .macro iteet, cond\n" -" .endm\n" -" .macro iteee, cond\n" -" .endm\n"); -#endif /* __ASSEMBLY__ */ - -#endif /* CONFIG_ARM_ASM_UNIFIED */ - #endif /* !__ASM_UNIFIED_H */ diff --git a/arch/arm/include/uapi/asm/siginfo.h b/arch/arm/include/uapi/asm/siginfo.h new file mode 100644 index 000000000000..d0513880be21 --- /dev/null +++ b/arch/arm/include/uapi/asm/siginfo.h @@ -0,0 +1,13 @@ +#ifndef __ASM_SIGINFO_H +#define __ASM_SIGINFO_H + +#include + +/* + * SIGFPE si_codes + */ +#ifdef __KERNEL__ +#define FPE_FIXME 0 /* Broken dup of SI_USER */ +#endif /* __KERNEL__ */ + +#endif diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 5266fd9ad6b4..783fbb4de5f9 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -92,7 +92,6 @@ EXPORT_SYMBOL(__memset64); EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(memchr); -EXPORT_SYMBOL(__memzero); EXPORT_SYMBOL(mmioset); EXPORT_SYMBOL(mmiocpy); diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index 0cd0aefb3a8f..ed46ca69813d 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -527,7 +527,7 @@ void pci_common_init_dev(struct device *parent, struct hw_pci *hw) struct pci_sys_data *sys; LIST_HEAD(head); - pci_add_flags(PCI_REASSIGN_ALL_RSRC); + pci_add_flags(PCI_REASSIGN_ALL_BUS); if (hw->preinit) hw->preinit(); pcibios_init_hw(parent, hw, &head); diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index fbc707626b3e..1752033b0070 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -82,11 +82,7 @@ #endif .endm -#ifdef CONFIG_KPROBES - .section .kprobes.text,"ax",%progbits -#else - .text -#endif + .section .entry.text,"ax",%progbits /* * Invalid mode handlers diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index e655dcd0a933..3c4f88701f22 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -37,6 +37,7 @@ saved_pc .req lr #define TRACE(x...) #endif + .section .entry.text,"ax",%progbits .align 5 #if !(IS_ENABLED(CONFIG_TRACE_IRQFLAGS) || IS_ENABLED(CONFIG_CONTEXT_TRACKING)) /* diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S index 21dde771a7dd..6e0375e7db05 100644 --- a/arch/arm/kernel/head-common.S +++ b/arch/arm/kernel/head-common.S @@ -105,8 +105,9 @@ __mmap_switched: ARM( ldmia r4!, {r0, r1, sp} ) THUMB( ldmia r4!, {r0, r1, r3} ) THUMB( mov sp, r3 ) - sub r1, r1, r0 - bl __memzero @ clear .bss + sub r2, r1, r0 + mov r1, #0 + bl memset @ clear .bss ldmia r4, {r0, r1, r2, r3} str r9, [r0] @ Save processor ID diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index af2a7f1e3103..629e25152c0d 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -44,17 +44,17 @@ static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]); static DEFINE_PER_CPU(struct perf_event *, wp_on_reg[ARM_MAX_WRP]); /* Number of BRP/WRP registers on this CPU. */ -static int core_num_brps; -static int core_num_wrps; +static int core_num_brps __ro_after_init; +static int core_num_wrps __ro_after_init; /* Debug architecture version. */ -static u8 debug_arch; +static u8 debug_arch __ro_after_init; /* Does debug architecture support OS Save and Restore? */ -static bool has_ossr; +static bool has_ossr __ro_after_init; /* Maximum supported watchpoint length. */ -static u8 max_watchpoint_len; +static u8 max_watchpoint_len __ro_after_init; #define READ_WB_REG_CASE(OP2, M, VAL) \ case ((OP2 << 4) + M): \ diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index d96714e1858c..1523cb18b109 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -121,8 +120,8 @@ void __show_regs(struct pt_regs *regs) show_regs_print_info(KERN_DEFAULT); - print_symbol("PC is at %s\n", instruction_pointer(regs)); - print_symbol("LR is at %s\n", regs->ARM_lr); + printk("PC is at %pS\n", (void *)instruction_pointer(regs)); + printk("LR is at %pS\n", (void *)regs->ARM_lr); printk("pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n", regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr); printk("sp : %08lx ip : %08lx fp : %08lx\n", diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 58e3771e4c5b..7724b0f661b3 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -390,7 +390,6 @@ static void ptrace_hbptriggered(struct perf_event *bp, struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp); long num; int i; - siginfo_t info; for (i = 0; i < ARM_MAX_HBP_SLOTS; ++i) if (current->thread.debug.hbp[i] == bp) @@ -398,12 +397,7 @@ static void ptrace_hbptriggered(struct perf_event *bp, num = (i == ARM_MAX_HBP_SLOTS) ? 0 : ptrace_hbp_idx_to_num(i); - info.si_signo = SIGTRAP; - info.si_errno = (int)num; - info.si_code = TRAP_HWBKPT; - info.si_addr = (void __user *)(bkpt->trigger); - - force_sig_info(SIGTRAP, &info, current); + force_sig_ptrace_errno_trap((int)num, (void __user *)(bkpt->trigger)); } /* diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index b4fbf00ee4ad..2da087926ebe 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -379,6 +379,9 @@ asmlinkage void secondary_start_kernel(void) cpu_init(); +#ifndef CONFIG_MMU + setup_vectors_base(); +#endif pr_debug("CPU%u: Booted secondary processor\n", cpu); preempt_disable(); diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c index 65228bf4c6df..a56e7c856ab5 100644 --- a/arch/arm/kernel/stacktrace.c +++ b/arch/arm/kernel/stacktrace.c @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -63,7 +64,6 @@ EXPORT_SYMBOL(walk_stackframe); #ifdef CONFIG_STACKTRACE struct stack_trace_data { struct stack_trace *trace; - unsigned long last_pc; unsigned int no_sched_functions; unsigned int skip; }; @@ -87,16 +87,7 @@ static int save_trace(struct stackframe *frame, void *d) if (trace->nr_entries >= trace->max_entries) return 1; - /* - * in_exception_text() is designed to test if the PC is one of - * the functions which has an exception stack above it, but - * unfortunately what is in frame->pc is the return LR value, - * not the saved PC value. So, we need to track the previous - * frame PC value when doing this. - */ - addr = data->last_pc; - data->last_pc = frame->pc; - if (!in_exception_text(addr)) + if (!in_entry_text(frame->pc)) return 0; regs = (struct pt_regs *)frame->sp; @@ -114,7 +105,6 @@ static noinline void __save_stack_trace(struct task_struct *tsk, struct stackframe frame; data.trace = trace; - data.last_pc = ULONG_MAX; data.skip = trace->skip; data.no_sched_functions = nosched; diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 3e26c6f7a191..5e3633c24e63 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -72,7 +72,7 @@ void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from); #endif - if (in_exception_text(where)) + if (in_entry_text(from)) dump_mem("", "Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs)); } @@ -433,7 +433,7 @@ static int call_undef_hook(struct pt_regs *regs, unsigned int instr) return fn ? fn(regs, instr) : 1; } -asmlinkage void __exception do_undefinstr(struct pt_regs *regs) +asmlinkage void do_undefinstr(struct pt_regs *regs) { unsigned int instr; siginfo_t info; diff --git a/arch/arm/kernel/vmlinux-xip.lds.S b/arch/arm/kernel/vmlinux-xip.lds.S index ec4b3f94ad80..12b87591eb7c 100644 --- a/arch/arm/kernel/vmlinux-xip.lds.S +++ b/arch/arm/kernel/vmlinux-xip.lds.S @@ -96,9 +96,9 @@ SECTIONS .text : { /* Real text segment */ _stext = .; /* Text and read-only data */ IDMAP_TEXT - __exception_text_start = .; - *(.exception.text) - __exception_text_end = .; + __entry_text_start = .; + *(.entry.text) + __entry_text_end = .; IRQENTRY_TEXT TEXT_TEXT SCHED_TEXT diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index ee53f6518872..84a1ae3ce46e 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -105,9 +105,9 @@ SECTIONS .text : { /* Real text segment */ _stext = .; /* Text and read-only data */ IDMAP_TEXT - __exception_text_start = .; - *(.exception.text) - __exception_text_end = .; + __entry_text_start = .; + *(.entry.text) + __entry_text_end = .; IRQENTRY_TEXT SOFTIRQENTRY_TEXT TEXT_TEXT diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c index cf8bf6bf87c4..910bd8dabb3c 100644 --- a/arch/arm/kvm/handle_exit.c +++ b/arch/arm/kvm/handle_exit.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include "trace.h" @@ -36,9 +36,9 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) kvm_vcpu_hvc_get_imm(vcpu)); vcpu->stat.hvc_exit_stat++; - ret = kvm_psci_call(vcpu); + ret = kvm_hvc_call_handler(vcpu); if (ret < 0) { - kvm_inject_undefined(vcpu); + vcpu_set_reg(vcpu, 0, ~0UL); return 1; } @@ -47,7 +47,16 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) { - kvm_inject_undefined(vcpu); + /* + * "If an SMC instruction executed at Non-secure EL1 is + * trapped to EL2 because HCR_EL2.TSC is 1, the exception is a + * Trap exception, not a Secure Monitor Call exception [...]" + * + * We need to advance the PC after the trap, as it would + * otherwise return to the same address... + */ + vcpu_set_reg(vcpu, 0, ~0UL); + kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); return 1; } diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c index 330c9ce34ba5..ae45ae96aac2 100644 --- a/arch/arm/kvm/hyp/switch.c +++ b/arch/arm/kvm/hyp/switch.c @@ -18,6 +18,7 @@ #include #include +#include __asm__(".arch_extension virt"); diff --git a/arch/arm/kvm/hyp/tlb.c b/arch/arm/kvm/hyp/tlb.c index 6d810af2d9fd..c0edd450e104 100644 --- a/arch/arm/kvm/hyp/tlb.c +++ b/arch/arm/kvm/hyp/tlb.c @@ -19,6 +19,7 @@ */ #include +#include /** * Flush per-VMID TLBs diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 4cb0b9624d8f..ad25fd1872c7 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -8,7 +8,7 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ csumpartialcopy.o csumpartialcopyuser.o clearbit.o \ delay.o delay-loop.o findbit.o memchr.o memcpy.o \ - memmove.o memset.o memzero.o setbit.o \ + memmove.o memset.o setbit.o \ strchr.o strrchr.o \ testchangebit.o testclearbit.o testsetbit.o \ ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ diff --git a/arch/arm/lib/memzero.S b/arch/arm/lib/memzero.S deleted file mode 100644 index 0eded952e089..000000000000 --- a/arch/arm/lib/memzero.S +++ /dev/null @@ -1,137 +0,0 @@ -/* - * linux/arch/arm/lib/memzero.S - * - * Copyright (C) 1995-2000 Russell King - * - * 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. - */ -#include -#include -#include - - .text - .align 5 - .word 0 -/* - * Align the pointer in r0. r3 contains the number of bytes that we are - * mis-aligned by, and r1 is the number of bytes. If r1 < 4, then we - * don't bother; we use byte stores instead. - */ -UNWIND( .fnstart ) -1: subs r1, r1, #4 @ 1 do we have enough - blt 5f @ 1 bytes to align with? - cmp r3, #2 @ 1 - strltb r2, [r0], #1 @ 1 - strleb r2, [r0], #1 @ 1 - strb r2, [r0], #1 @ 1 - add r1, r1, r3 @ 1 (r1 = r1 - (4 - r3)) -/* - * The pointer is now aligned and the length is adjusted. Try doing the - * memzero again. - */ - -ENTRY(__memzero) - mov r2, #0 @ 1 - ands r3, r0, #3 @ 1 unaligned? - bne 1b @ 1 -/* - * r3 = 0, and we know that the pointer in r0 is aligned to a word boundary. - */ - cmp r1, #16 @ 1 we can skip this chunk if we - blt 4f @ 1 have < 16 bytes - -#if ! CALGN(1)+0 - -/* - * We need an extra register for this loop - save the return address and - * use the LR - */ - str lr, [sp, #-4]! @ 1 -UNWIND( .fnend ) -UNWIND( .fnstart ) -UNWIND( .save {lr} ) - mov ip, r2 @ 1 - mov lr, r2 @ 1 - -3: subs r1, r1, #64 @ 1 write 32 bytes out per loop - stmgeia r0!, {r2, r3, ip, lr} @ 4 - stmgeia r0!, {r2, r3, ip, lr} @ 4 - stmgeia r0!, {r2, r3, ip, lr} @ 4 - stmgeia r0!, {r2, r3, ip, lr} @ 4 - bgt 3b @ 1 - ldmeqfd sp!, {pc} @ 1/2 quick exit -/* - * No need to correct the count; we're only testing bits from now on - */ - tst r1, #32 @ 1 - stmneia r0!, {r2, r3, ip, lr} @ 4 - stmneia r0!, {r2, r3, ip, lr} @ 4 - tst r1, #16 @ 1 16 bytes or more? - stmneia r0!, {r2, r3, ip, lr} @ 4 - ldr lr, [sp], #4 @ 1 -UNWIND( .fnend ) - -#else - -/* - * This version aligns the destination pointer in order to write - * whole cache lines at once. - */ - - stmfd sp!, {r4-r7, lr} -UNWIND( .fnend ) -UNWIND( .fnstart ) -UNWIND( .save {r4-r7, lr} ) - mov r4, r2 - mov r5, r2 - mov r6, r2 - mov r7, r2 - mov ip, r2 - mov lr, r2 - - cmp r1, #96 - andgts ip, r0, #31 - ble 3f - - rsb ip, ip, #32 - sub r1, r1, ip - movs ip, ip, lsl #(32 - 4) - stmcsia r0!, {r4, r5, r6, r7} - stmmiia r0!, {r4, r5} - movs ip, ip, lsl #2 - strcs r2, [r0], #4 - -3: subs r1, r1, #64 - stmgeia r0!, {r2-r7, ip, lr} - stmgeia r0!, {r2-r7, ip, lr} - bgt 3b - ldmeqfd sp!, {r4-r7, pc} - - tst r1, #32 - stmneia r0!, {r2-r7, ip, lr} - tst r1, #16 - stmneia r0!, {r4-r7} - ldmfd sp!, {r4-r7, lr} -UNWIND( .fnend ) - -#endif - -UNWIND( .fnstart ) -4: tst r1, #8 @ 1 8 bytes or more? - stmneia r0!, {r2, r3} @ 2 - tst r1, #4 @ 1 4 bytes or more? - strne r2, [r0], #4 @ 1 -/* - * When we get here, we've got less than 4 bytes to zero. We - * may have an unaligned pointer as well. - */ -5: tst r1, #2 @ 1 2 bytes or more? - strneb r2, [r0], #1 @ 1 - strneb r2, [r0], #1 @ 1 - tst r1, #1 @ 1 a byte left over - strneb r2, [r0], #1 @ 1 - ret lr @ 1 -UNWIND( .fnend ) -ENDPROC(__memzero) diff --git a/arch/arm/mach-bcm/brcmstb.c b/arch/arm/mach-bcm/brcmstb.c index 07e3a86c6466..5f127d5f1045 100644 --- a/arch/arm/mach-bcm/brcmstb.c +++ b/arch/arm/mach-bcm/brcmstb.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -38,7 +37,6 @@ u32 brcmstb_uart_config[3] = { static void __init brcmstb_init_irq(void) { irqchip_init(); - brcmstb_biuctrl_init(); } static const char *const brcmstb_match[] __initconst = { diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index cbde0030c092..d898a94f6eae 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -798,11 +798,11 @@ static int da850_lcd_hw_init(void) { int status; - status = gpio_request(DA850_LCD_BL_PIN, "lcd bl\n"); + status = gpio_request(DA850_LCD_BL_PIN, "lcd bl"); if (status < 0) return status; - status = gpio_request(DA850_LCD_PWR_PIN, "lcd pwr\n"); + status = gpio_request(DA850_LCD_PWR_PIN, "lcd pwr"); if (status < 0) { gpio_free(DA850_LCD_BL_PIN); return status; diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index 62e7bc3018f0..e457f299cd44 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -108,11 +109,20 @@ static struct platform_device davinci_nand_device = { }, }; +static struct gpiod_lookup_table i2c_recovery_gpiod_table = { + .dev_id = "i2c_davinci", + .table = { + GPIO_LOOKUP("davinci_gpio", 15, "sda", + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP("davinci_gpio", 14, "scl", + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, +}; + static struct davinci_i2c_platform_data i2c_pdata = { .bus_freq = 400 /* kHz */, .bus_delay = 0 /* usec */, - .sda_pin = 15, - .scl_pin = 14, + .gpio_recovery = true, }; static int dm355evm_mmc_gpios = -EINVAL; @@ -141,6 +151,7 @@ static struct i2c_board_info dm355evm_i2c_info[] = { static void __init evm_init_i2c(void) { + gpiod_add_lookup_table(&i2c_recovery_gpiod_table); davinci_init_i2c(&i2c_pdata); gpio_request(5, "dm355evm_msp"); diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index b07c9b18d427..85e6fb33b1ee 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -595,18 +596,28 @@ static struct i2c_board_info __initdata i2c_info[] = { }, }; +static struct gpiod_lookup_table i2c_recovery_gpiod_table = { + .dev_id = "i2c_davinci", + .table = { + GPIO_LOOKUP("davinci_gpio", 44, "sda", + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + GPIO_LOOKUP("davinci_gpio", 43, "scl", + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, +}; + /* The msp430 uses a slow bitbanged I2C implementation (ergo 20 KHz), * which requires 100 usec of idle bus after i2c writes sent to it. */ static struct davinci_i2c_platform_data i2c_pdata = { .bus_freq = 20 /* kHz */, .bus_delay = 100 /* usec */, - .sda_pin = 44, - .scl_pin = 43, + .gpio_recovery = true, }; static void __init evm_init_i2c(void) { + gpiod_add_lookup_table(&i2c_recovery_gpiod_table); davinci_init_i2c(&i2c_pdata); i2c_add_driver(&dm6446evm_msp_driver); i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info)); diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c index 0c02aaad0539..4da210a1a110 100644 --- a/arch/arm/mach-davinci/board-neuros-osd2.c +++ b/arch/arm/mach-davinci/board-neuros-osd2.c @@ -128,7 +128,7 @@ static struct platform_device davinci_fb_device = { .num_resources = 0, }; -static struct gpio_led ntosd2_leds[] = { +static const struct gpio_led ntosd2_leds[] = { { .name = "led1_green", .gpio = GPIO(10), }, { .name = "led1_red", .gpio = GPIO(11), }, { .name = "led2_green", .gpio = GPIO(12), }, diff --git a/arch/arm/mach-davinci/common.c b/arch/arm/mach-davinci/common.c index 9f9fbfa6da0d..bcb6a7ba84e9 100644 --- a/arch/arm/mach-davinci/common.c +++ b/arch/arm/mach-davinci/common.c @@ -77,7 +77,7 @@ static int __init davinci_init_id(struct davinci_soc_info *soc_info) return -EINVAL; } -void __init davinci_common_init(struct davinci_soc_info *soc_info) +void __init davinci_common_init(const struct davinci_soc_info *soc_info) { int ret; diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c index bd88470f3e5c..57ab18cf2a89 100644 --- a/arch/arm/mach-davinci/da830.c +++ b/arch/arm/mach-davinci/da830.c @@ -417,7 +417,7 @@ static struct clk_lookup da830_clks[] = { CLK("davinci-mcasp.0", NULL, &mcasp0_clk), CLK("davinci-mcasp.1", NULL, &mcasp1_clk), CLK("davinci-mcasp.2", NULL, &mcasp2_clk), - CLK("musb-da8xx", "usb20", &usb20_clk), + CLK("musb-da8xx", NULL, &usb20_clk), CLK("cppi41-dmaengine", NULL, &cppi41_clk), CLK(NULL, "aemif", &aemif_clk), CLK(NULL, "aintc", &aintc_clk), @@ -426,7 +426,7 @@ static struct clk_lookup da830_clks[] = { CLK("davinci_mdio.0", "fck", &emac_clk), CLK(NULL, "gpio", &gpio_clk), CLK("i2c_davinci.2", NULL, &i2c1_clk), - CLK("ohci-da8xx", "usb11", &usb11_clk), + CLK("ohci-da8xx", NULL, &usb11_clk), CLK(NULL, "emif3", &emif3_clk), CLK(NULL, "arm", &arm_clk), CLK(NULL, "rmii", &rmii_clk), @@ -1194,7 +1194,7 @@ static struct davinci_timer_info da830_timer_info = { .clocksource_id = T0_BOT, }; -static struct davinci_soc_info davinci_soc_info_da830 = { +static const struct davinci_soc_info davinci_soc_info_da830 = { .io_desc = da830_io_desc, .io_desc_num = ARRAY_SIZE(da830_io_desc), .jtag_id_reg = DA8XX_SYSCFG0_BASE + DA8XX_JTAG_ID_REG, diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 07d6f0eb8c82..aa37cbdf7d4d 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -563,8 +563,8 @@ static struct clk_lookup da850_clks[] = { CLK("da830-mmc.1", NULL, &mmcsd1_clk), CLK("ti-aemif", NULL, &aemif_clk), CLK("davinci-nand.0", "aemif", &aemif_nand_clk), - CLK("ohci-da8xx", "usb11", &usb11_clk), - CLK("musb-da8xx", "usb20", &usb20_clk), + CLK("ohci-da8xx", NULL, &usb11_clk), + CLK("musb-da8xx", NULL, &usb20_clk), CLK("cppi41-dmaengine", NULL, &cppi41_clk), CLK("spi_davinci.0", NULL, &spi0_clk), CLK("spi_davinci.1", NULL, &spi1_clk), @@ -1347,7 +1347,7 @@ int __init da850_register_gpio(void) return da8xx_register_gpio(&da850_gpio_platform_data); } -static struct davinci_soc_info davinci_soc_info_da850 = { +static const struct davinci_soc_info davinci_soc_info_da850 = { .io_desc = da850_io_desc, .io_desc_num = ARRAY_SIZE(da850_io_desc), .jtag_id_reg = DA8XX_SYSCFG0_BASE + DA8XX_JTAG_ID_REG, diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index 22440c05d66a..e1c40e73d30a 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -252,7 +252,7 @@ int __init da830_register_edma(struct edma_rsv_info *rsv) da8xx_edma0_pdata.slavecnt = ARRAY_SIZE(da830_edma_map); edma_pdev = platform_device_register_full(&da8xx_edma0_device); - return IS_ERR(edma_pdev) ? PTR_ERR(edma_pdev) : 0; + return PTR_ERR_OR_ZERO(edma_pdev); } static const struct dma_slave_map da850_edma0_map[] = { @@ -297,7 +297,7 @@ int __init da850_register_edma(struct edma_rsv_info *rsv[2]) da850_edma1_pdata.slavecnt = ARRAY_SIZE(da850_edma1_map); edma_pdev = platform_device_register_full(&da850_edma1_device); - return IS_ERR(edma_pdev) ? PTR_ERR(edma_pdev) : 0; + return PTR_ERR_OR_ZERO(edma_pdev); } static struct resource da8xx_i2c_resources0[] = { diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index bd50367f654e..938747f20c22 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -1006,7 +1006,7 @@ struct platform_device dm355_serial_device[] = { } }; -static struct davinci_soc_info davinci_soc_info_dm355 = { +static const struct davinci_soc_info davinci_soc_info_dm355 = { .io_desc = dm355_io_desc, .io_desc_num = ARRAY_SIZE(dm355_io_desc), .jtag_id_reg = 0x01c40028, diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index 5ace9380626a..5d9f96df08e9 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -1110,7 +1110,7 @@ struct platform_device dm365_serial_device[] = { } }; -static struct davinci_soc_info davinci_soc_info_dm365 = { +static const struct davinci_soc_info davinci_soc_info_dm365 = { .io_desc = dm365_io_desc, .io_desc_num = ARRAY_SIZE(dm365_io_desc), .jtag_id_reg = 0x01c40028, diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index b437c3730f65..6b41e1ca511e 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -899,7 +899,7 @@ struct platform_device dm644x_serial_device[] = { } }; -static struct davinci_soc_info davinci_soc_info_dm644x = { +static const struct davinci_soc_info davinci_soc_info_dm644x = { .io_desc = dm644x_io_desc, .io_desc_num = ARRAY_SIZE(dm644x_io_desc), .jtag_id_reg = 0x01c40028, diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c index da21353cac45..6fc06a6ad4f8 100644 --- a/arch/arm/mach-davinci/dm646x.c +++ b/arch/arm/mach-davinci/dm646x.c @@ -882,7 +882,7 @@ struct platform_device dm646x_serial_device[] = { } }; -static struct davinci_soc_info davinci_soc_info_dm646x = { +static const struct davinci_soc_info davinci_soc_info_dm646x = { .io_desc = dm646x_io_desc, .io_desc_num = ARRAY_SIZE(dm646x_io_desc), .jtag_id_reg = 0x01c40028, @@ -949,7 +949,7 @@ int __init dm646x_init_edma(struct edma_rsv_info *rsv) dm646x_edma_pdata.rsv = rsv; edma_pdev = platform_device_register_full(&dm646x_edma_device); - return IS_ERR(edma_pdev) ? PTR_ERR(edma_pdev) : 0; + return PTR_ERR_OR_ZERO(edma_pdev); } void __init dm646x_init(void) diff --git a/arch/arm/mach-davinci/include/mach/common.h b/arch/arm/mach-davinci/include/mach/common.h index 037aa66bcac1..433a008ff796 100644 --- a/arch/arm/mach-davinci/include/mach/common.h +++ b/arch/arm/mach-davinci/include/mach/common.h @@ -79,7 +79,7 @@ struct davinci_soc_info { extern struct davinci_soc_info davinci_soc_info; -extern void davinci_common_init(struct davinci_soc_info *soc_info); +extern void davinci_common_init(const struct davinci_soc_info *soc_info); extern void davinci_init_ide(void); void davinci_restart(enum reboot_mode mode, const char *cmd); void davinci_init_late(void); diff --git a/arch/arm/mach-ep93xx/Kconfig b/arch/arm/mach-ep93xx/Kconfig index 61a75ca3684e..c095236d7ff8 100644 --- a/arch/arm/mach-ep93xx/Kconfig +++ b/arch/arm/mach-ep93xx/Kconfig @@ -21,6 +21,13 @@ config MACH_ADSSPHERE Say 'Y' here if you want your kernel to support the ADS Sphere board. +config MACH_BK3 + bool "Support Liebherr BK3.1" + select MACH_TS72XX + help + Say 'Y' here if you want your kernel to support the + Liebherr controller BK3.1. + config MACH_EDB93XX bool diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c index f386ebae0163..c089a2a4fe30 100644 --- a/arch/arm/mach-ep93xx/ts72xx.c +++ b/arch/arm/mach-ep93xx/ts72xx.c @@ -19,10 +19,15 @@ #include #include #include +#include +#include +#include #include #include #include +#include +#include #include #include @@ -31,6 +36,9 @@ #include "soc.h" #include "ts72xx.h" +/************************************************************************* + * IO map + *************************************************************************/ static struct map_desc ts72xx_io_desc[] __initdata = { { .virtual = (unsigned long)TS72XX_MODEL_VIRT_BASE, @@ -47,6 +55,11 @@ static struct map_desc ts72xx_io_desc[] __initdata = { .pfn = __phys_to_pfn(TS72XX_OPTIONS2_PHYS_BASE), .length = TS72XX_OPTIONS2_SIZE, .type = MT_DEVICE, + }, { + .virtual = (unsigned long)TS72XX_CPLDVER_VIRT_BASE, + .pfn = __phys_to_pfn(TS72XX_CPLDVER_PHYS_BASE), + .length = TS72XX_CPLDVER_SIZE, + .type = MT_DEVICE, } }; @@ -123,8 +136,6 @@ static struct platform_nand_data ts72xx_nand_data = { .nr_chips = 1, .chip_offset = 0, .chip_delay = 15, - .partitions = ts72xx_nand_parts, - .nr_partitions = ARRAY_SIZE(ts72xx_nand_parts), }, .ctrl = { .cmd_ctrl = ts72xx_nand_hwcontrol, @@ -148,8 +159,8 @@ static struct platform_device ts72xx_nand_flash = { .num_resources = ARRAY_SIZE(ts72xx_nand_resource), }; - -static void __init ts72xx_register_flash(void) +void __init ts72xx_register_flash(struct mtd_partition *parts, int n, + resource_size_t start) { /* * TS7200 has NOR flash all other TS72xx board have NAND flash. @@ -157,16 +168,12 @@ static void __init ts72xx_register_flash(void) if (board_is_ts7200()) { ep93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_16M); } else { - resource_size_t start; - - if (is_ts9420_installed()) - start = EP93XX_CS7_PHYS_BASE; - else - start = EP93XX_CS6_PHYS_BASE; - ts72xx_nand_resource[0].start = start; ts72xx_nand_resource[0].end = start + SZ_16M - 1; + ts72xx_nand_data.chip.partitions = parts; + ts72xx_nand_data.chip.nr_partitions = n; + platform_device_register(&ts72xx_nand_flash); } } @@ -207,10 +214,79 @@ static struct platform_device ts72xx_wdt_device = { .num_resources = ARRAY_SIZE(ts72xx_wdt_resources), }; +/************************************************************************* + * ETH + *************************************************************************/ static struct ep93xx_eth_data __initdata ts72xx_eth_data = { .phy_id = 1, }; +/************************************************************************* + * SPI SD/MMC host + *************************************************************************/ +#define BK3_EN_SDCARD_PHYS_BASE 0x12400000 +#define BK3_EN_SDCARD_PWR 0x0 +#define BK3_DIS_SDCARD_PWR 0x0C +static void bk3_mmc_spi_setpower(struct device *dev, unsigned int vdd) +{ + void __iomem *pwr_sd = ioremap(BK3_EN_SDCARD_PHYS_BASE, SZ_4K); + + if (!pwr_sd) { + pr_err("Failed to enable SD card power!"); + return; + } + + pr_debug("%s: SD card pwr %s VDD:0x%x\n", __func__, + !!vdd ? "ON" : "OFF", vdd); + + if (!!vdd) + __raw_writeb(BK3_EN_SDCARD_PWR, pwr_sd); + else + __raw_writeb(BK3_DIS_SDCARD_PWR, pwr_sd); + + iounmap(pwr_sd); +} + +static struct mmc_spi_platform_data bk3_spi_mmc_data = { + .detect_delay = 500, + .powerup_msecs = 100, + .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, + .caps = MMC_CAP_NONREMOVABLE, + .setpower = bk3_mmc_spi_setpower, +}; + +/************************************************************************* + * SPI Bus - SD card access + *************************************************************************/ +static struct spi_board_info bk3_spi_board_info[] __initdata = { + { + .modalias = "mmc_spi", + .platform_data = &bk3_spi_mmc_data, + .max_speed_hz = 7.4E6, + .bus_num = 0, + .chip_select = 0, + .mode = SPI_MODE_0, + }, +}; + +/* + * This is a stub -> the FGPIO[3] pin is not connected on the schematic + * The all work is performed automatically by !SPI_FRAME (SFRM1) and + * goes through CPLD + */ +static int bk3_spi_chipselects[] __initdata = { + EP93XX_GPIO_LINE_F(3), +}; + +static struct ep93xx_spi_info bk3_spi_master __initdata = { + .chipselect = bk3_spi_chipselects, + .num_chipselect = ARRAY_SIZE(bk3_spi_chipselects), + .use_dma = 1, +}; + +/************************************************************************* + * TS72XX support code + *************************************************************************/ #if IS_ENABLED(CONFIG_FPGA_MGR_TS73XX) /* Relative to EP93XX_CS1_PHYS_BASE */ @@ -257,7 +333,9 @@ static struct ep93xx_spi_info ts72xx_spi_info __initdata = { static void __init ts72xx_init_machine(void) { ep93xx_init_devices(); - ts72xx_register_flash(); + ts72xx_register_flash(ts72xx_nand_parts, ARRAY_SIZE(ts72xx_nand_parts), + is_ts9420_installed() ? + EP93XX_CS7_PHYS_BASE : EP93XX_CS6_PHYS_BASE); platform_device_register(&ts72xx_rtc_device); platform_device_register(&ts72xx_wdt_device); @@ -280,3 +358,66 @@ MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC") .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END + +/************************************************************************* + * EP93xx I2S audio peripheral handling + *************************************************************************/ +static struct resource ep93xx_i2s_resource[] = { + DEFINE_RES_MEM(EP93XX_I2S_PHYS_BASE, 0x100), + DEFINE_RES_IRQ_NAMED(IRQ_EP93XX_SAI, "spilink i2s slave"), +}; + +static struct platform_device ep93xx_i2s_device = { + .name = "ep93xx-spilink-i2s", + .id = -1, + .num_resources = ARRAY_SIZE(ep93xx_i2s_resource), + .resource = ep93xx_i2s_resource, +}; + +/************************************************************************* + * BK3 support code + *************************************************************************/ +static struct mtd_partition bk3_nand_parts[] = { + { + .name = "System", + .offset = 0x00000000, + .size = 0x01e00000, + }, { + .name = "Data", + .offset = 0x01e00000, + .size = 0x05f20000 + }, { + .name = "RedBoot", + .offset = 0x07d20000, + .size = 0x002e0000, + .mask_flags = MTD_WRITEABLE, /* force RO */ + }, +}; + +static void __init bk3_init_machine(void) +{ + ep93xx_init_devices(); + + ts72xx_register_flash(bk3_nand_parts, ARRAY_SIZE(bk3_nand_parts), + EP93XX_CS6_PHYS_BASE); + + ep93xx_register_eth(&ts72xx_eth_data, 1); + + ep93xx_register_spi(&bk3_spi_master, bk3_spi_board_info, + ARRAY_SIZE(bk3_spi_board_info)); + + /* Configure ep93xx's I2S to use AC97 pins */ + ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_I2SONAC97); + platform_device_register(&ep93xx_i2s_device); +} + +MACHINE_START(BK3, "Liebherr controller BK3.1") + /* Maintainer: Lukasz Majewski */ + .atag_offset = 0x100, + .map_io = ts72xx_map_io, + .init_irq = ep93xx_init_irq, + .init_time = ep93xx_timer_init, + .init_machine = bk3_init_machine, + .init_late = ep93xx_init_late, + .restart = ep93xx_restart, +MACHINE_END diff --git a/arch/arm/mach-ep93xx/ts72xx.h b/arch/arm/mach-ep93xx/ts72xx.h index 8a3206a54b39..00b4941d29c9 100644 --- a/arch/arm/mach-ep93xx/ts72xx.h +++ b/arch/arm/mach-ep93xx/ts72xx.h @@ -10,8 +10,12 @@ * febff000 22000000 4K model number register (bits 0-2) * febfe000 22400000 4K options register * febfd000 22800000 4K options register #2 + * febfc000 23400000 4K CPLD version register */ +#ifndef __TS72XX_H_ +#define __TS72XX_H_ + #define TS72XX_MODEL_PHYS_BASE 0x22000000 #define TS72XX_MODEL_VIRT_BASE IOMEM(0xfebff000) #define TS72XX_MODEL_SIZE 0x00001000 @@ -39,6 +43,10 @@ #define TS72XX_OPTIONS2_TS9420 0x04 #define TS72XX_OPTIONS2_TS9420_BOOT 0x02 +#define TS72XX_CPLDVER_PHYS_BASE 0x23400000 +#define TS72XX_CPLDVER_VIRT_BASE IOMEM(0xfebfc000) +#define TS72XX_CPLDVER_SIZE 0x00001000 + #ifndef __ASSEMBLY__ static inline int ts72xx_model(void) @@ -83,3 +91,4 @@ static inline int is_ts9420_installed(void) TS72XX_OPTIONS2_TS9420); } #endif +#endif /* __TS72XX_H_ */ diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 44fa753bd79c..647c319f9f5f 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -1,9 +1,7 @@ -# arch/arm/mach-exynos/Kconfig +# SPDX-License-Identifier: GPL-2.0 # # Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. # http://www.samsung.com/ -# -# Licensed under GPLv2 # Configuration options for the EXYNOS diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 9ea6c54645ad..cd00c82a1add 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -1,9 +1,7 @@ -# arch/arm/mach-exynos/Makefile +# SPDX-License-Identifier: GPL-2.0 # # Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. # http://www.samsung.com/ -# -# Licensed under GPLv2 ccflags-$(CONFIG_ARCH_MULTIPLATFORM) += -I$(srctree)/$(src)/include -I$(srctree)/arch/arm/plat-samsung/include diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index 3f715524c9d6..098f84a149a3 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Common Header for EXYNOS machines - * - * 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. */ #ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H diff --git a/arch/arm/mach-exynos/exynos-smc.S b/arch/arm/mach-exynos/exynos-smc.S index 2e27aa3813fd..d259532ba937 100644 --- a/arch/arm/mach-exynos/exynos-smc.S +++ b/arch/arm/mach-exynos/exynos-smc.S @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2012 Samsung Electronics. * * Copied from omap-smc.S Copyright (C) 2010 Texas Instruments, Inc. - * - * 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. */ #include diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 9a9caac1125a..fbd108ce8745 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -1,13 +1,9 @@ -/* - * SAMSUNG EXYNOS Flattened Device Tree enabled machine - * - * Copyright (c) 2010-2014 Samsung Electronics Co., Ltd. - * http://www.samsung.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. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// SAMSUNG EXYNOS Flattened Device Tree enabled machine +// +// Copyright (c) 2010-2014 Samsung Electronics Co., Ltd. +// http://www.samsung.com #include #include diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index 2a51e4603a6f..be1f20fe28f4 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c @@ -1,12 +1,8 @@ -/* - * Copyright (C) 2012 Samsung Electronics. - * Kyungmin Park - * Tomasz Figa - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2012 Samsung Electronics. +// Kyungmin Park +// Tomasz Figa #include #include diff --git a/arch/arm/mach-exynos/headsmp.S b/arch/arm/mach-exynos/headsmp.S index d3d24ab351ae..005695c9bf40 100644 --- a/arch/arm/mach-exynos/headsmp.S +++ b/arch/arm/mach-exynos/headsmp.S @@ -1,13 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* - * * Cloned from linux/arch/arm/mach-realview/headsmp.S * * Copyright (c) 2003 ARM Limited * All Rights Reserved - * - * 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. */ #include #include diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index 5fb0040cc6d3..37a5ea5e2602 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * EXYNOS - Memory map definitions - * - * 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. -*/ + */ #ifndef __ASM_ARCH_MAP_H #define __ASM_ARCH_MAP_H __FILE__ diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c index b42622562ea7..72bc035bedbe 100644 --- a/arch/arm/mach-exynos/mcpm-exynos.c +++ b/arch/arm/mach-exynos/mcpm-exynos.c @@ -1,15 +1,8 @@ -/* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * arch/arm/mach-exynos/mcpm-exynos.c - * - * Based on arch/arm/mach-vexpress/dcscb.c - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2014 Samsung Electronics Co., Ltd. +// http://www.samsung.com +// +// Based on arch/arm/mach-vexpress/dcscb.c #include #include diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index 5a03bffe7226..5156fe70e030 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c @@ -1,16 +1,11 @@ - /* - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Cloned from linux/arch/arm/mach-vexpress/platsmp.c - * - * Copyright (C) 2002 ARM Ltd. - * All Rights Reserved - * - * 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. -*/ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. +// http://www.samsung.com +// +// Cloned from linux/arch/arm/mach-vexpress/platsmp.c +// +// Copyright (C) 2002 ARM Ltd. +// All Rights Reserved #include #include diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index c9740d96db9e..dc4346ecf16d 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -1,17 +1,13 @@ -/* - * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * EXYNOS - Power Management support - * - * Based on arch/arm/mach-s3c2410/pm.c - * Copyright (c) 2006 Simtec Electronics - * Ben Dooks - * - * 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. -*/ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. +// http://www.samsung.com +// +// EXYNOS - Power Management support +// +// Based on arch/arm/mach-s3c2410/pm.c +// Copyright (c) 2006 Simtec Electronics +// Ben Dooks #include #include diff --git a/arch/arm/mach-exynos/sleep.S b/arch/arm/mach-exynos/sleep.S index 4292cae43f3c..2783c3a0c06a 100644 --- a/arch/arm/mach-exynos/sleep.S +++ b/arch/arm/mach-exynos/sleep.S @@ -1,18 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Exynos low-level resume code - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-exynos/smc.h b/arch/arm/mach-exynos/smc.h index c2845717bc8f..f355185d4239 100644 --- a/arch/arm/mach-exynos/smc.h +++ b/arch/arm/mach-exynos/smc.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2012 Samsung Electronics. * * EXYNOS - SMC Call - * - * 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. */ #ifndef __ASM_ARCH_EXYNOS_SMC_H diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c index 370d37ded7e7..c2ed997fedef 100644 --- a/arch/arm/mach-exynos/suspend.c +++ b/arch/arm/mach-exynos/suspend.c @@ -1,17 +1,13 @@ -/* - * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * EXYNOS - Suspend support - * - * Based on arch/arm/mach-s3c2410/pm.c - * Copyright (c) 2006 Simtec Electronics - * Ben Dooks - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. +// http://www.samsung.com +// +// EXYNOS - Suspend support +// +// Based on arch/arm/mach-s3c2410/pm.c +// Copyright (c) 2006 Simtec Electronics +// Ben Dooks #include #include diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index b09a2ec19267..c8d68e918b2f 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -71,15 +71,6 @@ enum mxc_cpu_pwr_mode { STOP_POWER_OFF, /* STOP + SRPG */ }; -enum mx3_cpu_pwr_mode { - MX3_RUN, - MX3_WAIT, - MX3_DOZE, - MX3_SLEEP, -}; - -void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode); - void imx_enable_cpu(int cpu, bool enable); void imx_set_cpu_jump(int cpu, void *jump_addr); u32 imx_get_cpu_arg(int cpu); diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c index 78262899a590..5fb1d2254b5e 100644 --- a/arch/arm/mach-imx/mmdc.c +++ b/arch/arm/mach-imx/mmdc.c @@ -547,7 +547,6 @@ static int imx_mmdc_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; void __iomem *mmdc_base, *reg; u32 val; - int timeout = 0x400; mmdc_base = of_iomap(np, 0); WARN_ON(!mmdc_base); @@ -565,16 +564,6 @@ static int imx_mmdc_probe(struct platform_device *pdev) val &= ~(1 << BP_MMDC_MAPSR_PSD); writel_relaxed(val, reg); - /* Ensure it's successfully enabled */ - while (!(readl_relaxed(reg) & 1 << BP_MMDC_MAPSR_PSS) && --timeout) - cpu_relax(); - - if (unlikely(!timeout)) { - pr_warn("%s: failed to enable automatic power saving\n", - __func__); - return -EBUSY; - } - return imx_mmdc_perf_init(pdev, mmdc_base); } diff --git a/arch/arm/mach-ixp4xx/vulcan-setup.c b/arch/arm/mach-ixp4xx/vulcan-setup.c index 731fb2019ecb..2c03d2f6b647 100644 --- a/arch/arm/mach-ixp4xx/vulcan-setup.c +++ b/arch/arm/mach-ixp4xx/vulcan-setup.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -162,9 +163,16 @@ static struct platform_device vulcan_max6369 = { .num_resources = 1, }; +static struct gpiod_lookup_table vulcan_w1_gpiod_table = { + .dev_id = "w1-gpio", + .table = { + GPIO_LOOKUP_IDX("IXP4XX_GPIO_CHIP", 14, NULL, 0, + GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), + }, +}; + static struct w1_gpio_platform_data vulcan_w1_gpio_pdata = { - .pin = 14, - .ext_pullup_enable_pin = -EINVAL, + /* Intentionally left blank */ }; static struct platform_device vulcan_w1_gpio = { @@ -233,6 +241,7 @@ static void __init vulcan_init(void) IXP4XX_EXP_BUS_WR_EN | IXP4XX_EXP_BUS_BYTE_EN; + gpiod_add_lookup_table(&vulcan_w1_gpiod_table); platform_add_devices(vulcan_devices, ARRAY_SIZE(vulcan_devices)); } diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig index 70e49d54434e..91cc461f7b04 100644 --- a/arch/arm/mach-mediatek/Kconfig +++ b/arch/arm/mach-mediatek/Kconfig @@ -1,5 +1,5 @@ menuconfig ARCH_MEDIATEK - bool "Mediatek MT65xx & MT81xx SoC" + bool "MediaTek SoC Support" depends on ARCH_MULTI_V7 select ARM_GIC select PINCTRL diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig index aff6164b2083..d90f61e6254f 100644 --- a/arch/arm/mach-meson/Kconfig +++ b/arch/arm/mach-meson/Kconfig @@ -23,6 +23,7 @@ config MACH_MESON8 default ARCH_MESON select MESON6_TIMER select COMMON_CLK_MESON8B + select MESON_IRQ_GPIO config MACH_MESON8B bool "Amlogic Meson8b SoCs support" diff --git a/arch/arm/mach-mmp/mmp2.h b/arch/arm/mach-mmp/mmp2.h index a4b82f719de1..adafc4fba8f4 100644 --- a/arch/arm/mach-mmp/mmp2.h +++ b/arch/arm/mach-mmp/mmp2.h @@ -10,7 +10,7 @@ extern void __init mmp2_init_irq(void); extern void mmp2_clear_pmic_int(void); #include -#include +#include #include #include "devices.h" diff --git a/arch/arm/mach-mmp/pxa168.h b/arch/arm/mach-mmp/pxa168.h index b39bff37ff11..0331c58b07a2 100644 --- a/arch/arm/mach-mmp/pxa168.h +++ b/arch/arm/mach-mmp/pxa168.h @@ -11,7 +11,7 @@ extern void pxa168_restart(enum reboot_mode, const char *); extern void pxa168_clear_keypad_wakeup(void); #include -#include +#include #include #include

|", "\n"}, - {0, " [Byte|Word|Dword|Qword]", - "Display ACPI objects or memory\n"}, - {1, " Handlers", "Info about global handlers\n"}, - {1, " Help [Command]", "This help screen or individual command\n"}, - {1, " History", "Display command history buffer\n"}, - {1, " Level ] [console]", - "Get/Set debug level for file or console\n"}, - {1, " Locks", "Current status of internal mutexes\n"}, - {1, " Osi [Install|Remove ]", - "Display or modify global _OSI list\n"}, - {1, " Quit or Exit", "Exit this command\n"}, - {8, " Stats ", - "Display namespace and memory statistics\n"}, - {1, " Allocations", "Display list of current memory allocations\n"}, - {1, " Memory", "Dump internal memory lists\n"}, - {1, " Misc", "Namespace search and mutex stats\n"}, - {1, " Objects", "Summary of namespace objects\n"}, - {1, " Sizes", "Sizes for each of the internal objects\n"}, - {1, " Stack", "Display CPU stack usage\n"}, - {1, " Tables", "Info about current ACPI table(s)\n"}, - {1, " Tables", "Display info about loaded ACPI tables\n"}, - {1, " ! ", "Execute command from history buffer\n"}, - {1, " !!", "Execute last command again\n"}, - - {0, "\nNamespace Access Commands:", "\n"}, + {0, "\nNamespace Access:", "\n"}, {1, " Businfo", "Display system bus info\n"}, {1, " Disassemble ", "Disassemble a control method\n"}, {1, " Find (? is wildcard)", @@ -275,19 +253,74 @@ static const struct acpi_db_command_help acpi_gbl_db_command_help[] = { {1, " Template ", "Format/dump a Buffer/ResourceTemplate\n"}, {1, " Type ", "Display object type\n"}, - {0, "\nControl Method Execution Commands:", "\n"}, + {0, "\nControl Method Execution:", "\n"}, + {1, " Evaluate [Arguments]", + "Evaluate object or control method\n"}, + {1, " Execute [Arguments]", "Synonym for Evaluate\n"}, +#ifdef ACPI_APPLICATION + {1, " Background [Arguments]", + "Evaluate object/method in a separate thread\n"}, + {1, " Thread ", + "Spawn threads to execute method(s)\n"}, +#endif + {1, " Debug [Arguments]", "Single-Step a control method\n"}, + {7, " [Arguments] formats:", "Control method argument formats\n"}, + {1, " Hex Integer", "Integer\n"}, + {1, " \"Ascii String\"", "String\n"}, + {1, " (Hex Byte List)", "Buffer\n"}, + {1, " (01 42 7A BF)", "Buffer example (4 bytes)\n"}, + {1, " [Package Element List]", "Package\n"}, + {1, " [0x01 0x1234 \"string\"]", + "Package example (3 elements)\n"}, + + {0, "\nMiscellaneous:", "\n"}, + {1, " Allocations", "Display list of current memory allocations\n"}, + {2, " Dump
|", "\n"}, + {0, " [Byte|Word|Dword|Qword]", + "Display ACPI objects or memory\n"}, + {1, " Handlers", "Info about global handlers\n"}, + {1, " Help [Command]", "This help screen or individual command\n"}, + {1, " History", "Display command history buffer\n"}, + {1, " Level ] [console]", + "Get/Set debug level for file or console\n"}, + {1, " Locks", "Current status of internal mutexes\n"}, + {1, " Osi [Install|Remove ]", + "Display or modify global _OSI list\n"}, + {1, " Quit or Exit", "Exit this command\n"}, + {8, " Stats ", + "Display namespace and memory statistics\n"}, + {1, " Allocations", "Display list of current memory allocations\n"}, + {1, " Memory", "Dump internal memory lists\n"}, + {1, " Misc", "Namespace search and mutex stats\n"}, + {1, " Objects", "Summary of namespace objects\n"}, + {1, " Sizes", "Sizes for each of the internal objects\n"}, + {1, " Stack", "Display CPU stack usage\n"}, + {1, " Tables", "Info about current ACPI table(s)\n"}, + {1, " Tables", "Display info about loaded ACPI tables\n"}, +#ifdef ACPI_APPLICATION + {1, " Terminate", "Delete namespace and all internal objects\n"}, +#endif + {1, " ! ", "Execute command from history buffer\n"}, + {1, " !!", "Execute last command again\n"}, + + {0, "\nMethod and Namespace Debugging:", "\n"}, + {5, " Trace [] [Once]", + "Trace control method execution\n"}, + {1, " Enable", "Enable all messages\n"}, + {1, " Disable", "Disable tracing\n"}, + {1, " Method", "Enable method execution messages\n"}, + {1, " Opcode", "Enable opcode execution messages\n"}, + {3, " Test ", "Invoke a debug test\n"}, + {1, " Objects", "Read/write/compare all namespace data objects\n"}, + {1, " Predefined", + "Validate all ACPI predefined names (_STA, etc.)\n"}, + {1, " Execute predefined", + "Execute all predefined (public) methods\n"}, + + {0, "\nControl Method Single-Step Execution:", "\n"}, {1, " Arguments (or Args)", "Display method arguments\n"}, {1, " Breakpoint ", "Set an AML execution breakpoint\n"}, {1, " Call", "Run to next control method invocation\n"}, - {1, " Debug [Arguments]", "Single Step a control method\n"}, - {6, " Evaluate", "Synonym for Execute\n"}, - {5, " Execute [Arguments]", "Execute control method\n"}, - {1, " Hex Integer", "Integer method argument\n"}, - {1, " \"Ascii String\"", "String method argument\n"}, - {1, " (Hex Byte List)", "Buffer method argument\n"}, - {1, " [Package Element List]", "Package method argument\n"}, - {5, " Execute predefined", - "Execute all predefined (public) methods\n"}, {1, " Go", "Allow method to run to completion\n"}, {1, " Information", "Display info about the current method\n"}, {1, " Into", "Step into (not over) a method call\n"}, @@ -296,41 +329,24 @@ static const struct acpi_db_command_help acpi_gbl_db_command_help[] = { {1, " Results", "Display method result stack\n"}, {1, " Set <#> ", "Set method data (Arguments/Locals)\n"}, {1, " Stop", "Terminate control method\n"}, - {5, " Trace [] [Once]", - "Trace control method execution\n"}, - {1, " Enable", "Enable all messages\n"}, - {1, " Disable", "Disable tracing\n"}, - {1, " Method", "Enable method execution messages\n"}, - {1, " Opcode", "Enable opcode execution messages\n"}, {1, " Tree", "Display control method calling tree\n"}, {1, " ", "Single step next AML opcode (over calls)\n"}, #ifdef ACPI_APPLICATION - {0, "\nHardware Simulation Commands:", "\n"}, - {1, " EnableAcpi", "Enable ACPI (hardware) mode\n"}, - {1, " Event ", "Generate AcpiEvent (Fixed/GPE)\n"}, - {1, " Gpe [GpeBlockDevice]", "Simulate a GPE\n"}, - {1, " Gpes", "Display info on all GPE devices\n"}, - {1, " Sci", "Generate an SCI\n"}, - {1, " Sleep [SleepState]", "Simulate sleep/wake sequence(s) (0-5)\n"}, - - {0, "\nFile I/O Commands:", "\n"}, + {0, "\nFile Operations:", "\n"}, {1, " Close", "Close debug output file\n"}, {1, " Load ", "Load ACPI table from a file\n"}, {1, " Open ", "Open a file for debug output\n"}, {1, " Unload ", "Unload an ACPI table via namespace object\n"}, - {0, "\nUser Space Commands:", "\n"}, - {1, " Terminate", "Delete namespace and all internal objects\n"}, - {1, " Thread ", - "Spawn threads to execute method(s)\n"}, - - {0, "\nDebug Test Commands:", "\n"}, - {3, " Test ", "Invoke a debug test\n"}, - {1, " Objects", "Read/write/compare all namespace data objects\n"}, - {1, " Predefined", - "Execute all ACPI predefined names (_STA, etc.)\n"}, + {0, "\nHardware Simulation:", "\n"}, + {1, " EnableAcpi", "Enable ACPI (hardware) mode\n"}, + {1, " Event ", "Generate AcpiEvent (Fixed/GPE)\n"}, + {1, " Gpe [GpeBlockDevice]", "Simulate a GPE\n"}, + {1, " Gpes", "Display info on all GPE devices\n"}, + {1, " Sci", "Generate an SCI\n"}, + {1, " Sleep [SleepState]", "Simulate sleep/wake sequence(s) (0-5)\n"}, #endif {0, NULL, NULL} }; @@ -442,11 +458,15 @@ static void acpi_db_display_help(char *command) /* No argument to help, display help for all commands */ + acpi_os_printf("\nSummary of AML Debugger Commands\n\n"); + while (next->invocation) { acpi_os_printf("%-38s%s", next->invocation, next->description); next++; } + acpi_os_printf("\n"); + } else { /* Display help for all commands that match the subtring */ @@ -1087,6 +1107,13 @@ acpi_db_command_dispatch(char *input_buffer, /* acpi_initialize (NULL); */ break; + case CMD_BACKGROUND: + + acpi_db_create_execution_thread(acpi_gbl_db_args[1], + &acpi_gbl_db_args[2], + &acpi_gbl_db_arg_types[2]); + break; + case CMD_THREADS: acpi_db_create_execution_threads(acpi_gbl_db_args[1], diff --git a/drivers/acpi/acpica/dbmethod.c b/drivers/acpi/acpica/dbmethod.c index df62c9245efc..2cda0bff6f2c 100644 --- a/drivers/acpi/acpica/dbmethod.c +++ b/drivers/acpi/acpica/dbmethod.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbnames.c b/drivers/acpi/acpica/dbnames.c index 8c207c772517..8796fc1e0360 100644 --- a/drivers/acpi/acpica/dbnames.c +++ b/drivers/acpi/acpica/dbnames.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbobject.c b/drivers/acpi/acpica/dbobject.c index e7b415c20aa8..d2063cbab39a 100644 --- a/drivers/acpi/acpica/dbobject.c +++ b/drivers/acpi/acpica/dbobject.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbstats.c b/drivers/acpi/acpica/dbstats.c index 99fb0160b8fb..d6aaef54e369 100644 --- a/drivers/acpi/acpica/dbstats.c +++ b/drivers/acpi/acpica/dbstats.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbtest.c b/drivers/acpi/acpica/dbtest.c index c6bee6143266..56e446b89d18 100644 --- a/drivers/acpi/acpica/dbtest.c +++ b/drivers/acpi/acpica/dbtest.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbutils.c b/drivers/acpi/acpica/dbutils.c index bfa972b64171..cd40854ee9be 100644 --- a/drivers/acpi/acpica/dbutils.c +++ b/drivers/acpi/acpica/dbutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c index b6985323e7eb..77bbfa97cf91 100644 --- a/drivers/acpi/acpica/dbxface.c +++ b/drivers/acpi/acpica/dbxface.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c index 2873455c986d..04a9f60e7ad1 100644 --- a/drivers/acpi/acpica/dsargs.c +++ b/drivers/acpi/acpica/dsargs.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c index f470e81b0499..606697e741a5 100644 --- a/drivers/acpi/acpica/dscontrol.c +++ b/drivers/acpi/acpica/dscontrol.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -118,6 +118,8 @@ acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state, control_state->control.package_end = walk_state->parser_state.pkg_end; control_state->control.opcode = op->common.aml_opcode; + control_state->control.loop_timeout = acpi_os_get_timer() + + (u64)(acpi_gbl_max_loop_iterations * ACPI_100NSEC_PER_SEC); /* Push the control state on this walk's control stack */ @@ -206,15 +208,15 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state *walk_state, /* Predicate was true, the body of the loop was just executed */ /* - * This loop counter mechanism allows the interpreter to escape - * possibly infinite loops. This can occur in poorly written AML - * when the hardware does not respond within a while loop and the - * loop does not implement a timeout. + * This infinite loop detection mechanism allows the interpreter + * to escape possibly infinite loops. This can occur in poorly + * written AML when the hardware does not respond within a while + * loop and the loop does not implement a timeout. */ - control_state->control.loop_count++; - if (control_state->control.loop_count > - acpi_gbl_max_loop_iterations) { - status = AE_AML_INFINITE_LOOP; + if (ACPI_TIME_AFTER(acpi_os_get_timer(), + control_state->control. + loop_timeout)) { + status = AE_AML_LOOP_TIMEOUT; break; } diff --git a/drivers/acpi/acpica/dsdebug.c b/drivers/acpi/acpica/dsdebug.c index d1f457eda980..14ec52eba408 100644 --- a/drivers/acpi/acpica/dsdebug.c +++ b/drivers/acpi/acpica/dsdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 7bcf5f5ea029..95ea639a9424 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -209,7 +209,8 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, ACPI_IMODE_LOAD_PASS1, flags, walk_state, &node); if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(arg->common.value.string, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + arg->common.value.string, status); return_ACPI_STATUS(status); } } @@ -383,7 +384,9 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, walk_state, &info->connection_node); if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(child->common. + ACPI_ERROR_NAMESPACE(walk_state-> + scope_info, + child->common. value.name, status); return_ACPI_STATUS(status); @@ -402,7 +405,8 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, ACPI_NS_DONT_OPEN_SCOPE, walk_state, &info->field_node); if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE((char *)&arg->named.name, + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + (char *)&arg->named.name, status); return_ACPI_STATUS(status); } else { @@ -498,7 +502,8 @@ acpi_ds_create_field(union acpi_parse_object *op, ®ion_node); #endif if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(arg->common.value.name, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + arg->common.value.name, status); return_ACPI_STATUS(status); } } @@ -618,7 +623,8 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, ACPI_IMODE_LOAD_PASS1, flags, walk_state, &node); if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE((char *)&arg->named.name, + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + (char *)&arg->named.name, status); if (status != AE_ALREADY_EXISTS) { return_ACPI_STATUS(status); @@ -681,7 +687,8 @@ acpi_ds_create_bank_field(union acpi_parse_object *op, ®ion_node); #endif if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(arg->common.value.name, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + arg->common.value.name, status); return_ACPI_STATUS(status); } } @@ -695,7 +702,8 @@ acpi_ds_create_bank_field(union acpi_parse_object *op, ACPI_NS_SEARCH_PARENT, walk_state, &info.register_node); if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(arg->common.value.string, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + arg->common.value.string, status); return_ACPI_STATUS(status); } @@ -765,7 +773,8 @@ acpi_ds_create_index_field(union acpi_parse_object *op, ACPI_NS_SEARCH_PARENT, walk_state, &info.register_node); if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(arg->common.value.string, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + arg->common.value.string, status); return_ACPI_STATUS(status); } @@ -778,7 +787,8 @@ acpi_ds_create_index_field(union acpi_parse_object *op, ACPI_NS_SEARCH_PARENT, walk_state, &info.data_register_node); if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(arg->common.value.string, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + arg->common.value.string, status); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index b1842dd4edf7..946ff2e130d9 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index d7fc36917c67..b9c460c2d763 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c index 27a7de95f7b0..157f1645d91a 100644 --- a/drivers/acpi/acpica/dsmthdat.c +++ b/drivers/acpi/acpica/dsmthdat.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index 82448551781b..4fa3400a95ba 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -112,7 +112,9 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, acpi_namespace_node, &(op->common.node))); if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(op->common.value. + ACPI_ERROR_NAMESPACE(walk_state-> + scope_info, + op->common.value. string, status); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index 0336df7ac47d..0181cd317751 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dspkginit.c b/drivers/acpi/acpica/dspkginit.c index 6d487edfe2de..902bee78036c 100644 --- a/drivers/acpi/acpica/dspkginit.c +++ b/drivers/acpi/acpica/dspkginit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -297,8 +297,10 @@ acpi_ds_init_package_element(u8 object_type, { union acpi_operand_object **element_ptr; + ACPI_FUNCTION_TRACE(ds_init_package_element); + if (!source_object) { - return (AE_OK); + return_ACPI_STATUS(AE_OK); } /* @@ -329,7 +331,7 @@ acpi_ds_init_package_element(u8 object_type, source_object->package.flags |= AOPOBJ_DATA_VALID; } - return (AE_OK); + return_ACPI_STATUS(AE_OK); } /******************************************************************************* @@ -352,6 +354,7 @@ acpi_ds_resolve_package_element(union acpi_operand_object **element_ptr) union acpi_generic_state scope_info; union acpi_operand_object *element = *element_ptr; struct acpi_namespace_node *resolved_node; + struct acpi_namespace_node *original_node; char *external_path = NULL; acpi_object_type type; @@ -441,6 +444,7 @@ acpi_ds_resolve_package_element(union acpi_operand_object **element_ptr) * will remain as named references. This behavior is not described * in the ACPI spec, but it appears to be an oversight. */ + original_node = resolved_node; status = acpi_ex_resolve_node_to_value(&resolved_node, NULL); if (ACPI_FAILURE(status)) { return_VOID; @@ -468,26 +472,27 @@ acpi_ds_resolve_package_element(union acpi_operand_object **element_ptr) */ case ACPI_TYPE_DEVICE: case ACPI_TYPE_THERMAL: - - /* TBD: This may not be necesssary */ - - acpi_ut_add_reference(resolved_node->object); + case ACPI_TYPE_METHOD: break; case ACPI_TYPE_MUTEX: - case ACPI_TYPE_METHOD: case ACPI_TYPE_POWER: case ACPI_TYPE_PROCESSOR: case ACPI_TYPE_EVENT: case ACPI_TYPE_REGION: + /* acpi_ex_resolve_node_to_value gave these an extra reference */ + + acpi_ut_remove_reference(original_node->object); break; default: /* * For all other types - the node was resolved to an actual - * operand object with a value, return the object + * operand object with a value, return the object. Remove + * a reference on the existing object. */ + acpi_ut_remove_reference(element); *element_ptr = (union acpi_operand_object *)resolved_node; break; } diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index 0dabd9b95684..a4ce0b4a55a6 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -583,7 +583,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, } if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(name_string, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + name_string, status); } } diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c index 22f45d090733..2c07d220a50f 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index eaa859a89702..fa4ef9229e17 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -207,7 +207,8 @@ acpi_ds_load1_begin_op(struct acpi_walk_state *walk_state, } #endif if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(path, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, path, + status); return_ACPI_STATUS(status); } @@ -375,7 +376,8 @@ acpi_ds_load1_begin_op(struct acpi_walk_state *walk_state, } if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(path, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + path, status); return_ACPI_STATUS(status); } } diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c index aad83ef5a4ec..3b1313ba60d0 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -184,11 +184,14 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, if (status == AE_NOT_FOUND) { status = AE_OK; } else { - ACPI_ERROR_NAMESPACE(buffer_ptr, + ACPI_ERROR_NAMESPACE(walk_state-> + scope_info, + buffer_ptr, status); } #else - ACPI_ERROR_NAMESPACE(buffer_ptr, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + buffer_ptr, status); #endif return_ACPI_STATUS(status); } @@ -343,7 +346,8 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, } if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(buffer_ptr, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + buffer_ptr, status); return_ACPI_STATUS(status); } @@ -719,7 +723,8 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) */ op->common.node = new_node; } else { - ACPI_ERROR_NAMESPACE(arg->common.value.string, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + arg->common.value.string, status); } break; diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c index 3e081983d2ee..8b5c3613c060 100644 --- a/drivers/acpi/acpica/dswscope.c +++ b/drivers/acpi/acpica/dswscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index da111a1f5bfb..ee002d17526e 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c index d3b6b314fa50..4b2b0b44a16b 100644 --- a/drivers/acpi/acpica/evevent.c +++ b/drivers/acpi/acpica/evevent.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evglock.c b/drivers/acpi/acpica/evglock.c index 0ce33b0f430c..012b80de1501 100644 --- a/drivers/acpi/acpica/evglock.c +++ b/drivers/acpi/acpica/evglock.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 263d8fc4a9e2..410a3907c051 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index 3a3cb8624f41..7ce756cc28ab 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index 8649c6242478..8ad4816c9950 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c index c8adb400330a..729a8960a3af 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c index 2db61ef1b4a3..20fb51c06b8d 100644 --- a/drivers/acpi/acpica/evhandler.c +++ b/drivers/acpi/acpica/evhandler.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c index 4f6bb3f016ab..40d0b1f541a0 100644 --- a/drivers/acpi/acpica/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 28b447ff92df..de196c8e3f30 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -298,6 +298,16 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, ACPI_EXCEPTION((AE_INFO, status, "Returned by Handler for [%s]", acpi_ut_get_region_name(region_obj->region. space_id))); + + /* + * Special case for an EC timeout. These are seen so frequently + * that an additional error message is helpful + */ + if ((region_obj->region.space_id == ACPI_ADR_SPACE_EC) && + (status == AE_TIME)) { + ACPI_ERROR((AE_INFO, + "Timeout from EC hardware or EC device driver")); + } } if (!(handler_desc->address_space.handler_flags & diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 93ec528bcd9a..4187f563fede 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c index 8ce73b962006..d5594f79f877 100644 --- a/drivers/acpi/acpica/evsci.c +++ b/drivers/acpi/acpica/evsci.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index dd1b9dd64cef..9b3c01bf1438 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index c773ac4892cb..96c2520f9570 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 67c7c4ce276c..cbb1598df9dc 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index beba9d56a0d8..705fcd86151a 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exconcat.c b/drivers/acpi/acpica/exconcat.c index 59b8de2f07d3..ea20e10dd1f2 100644 --- a/drivers/acpi/acpica/exconcat.c +++ b/drivers/acpi/acpica/exconcat.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 61813bd43f9e..827f47b72663 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index 23ebadb06a95..9abcc41a573b 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index b8adb11f1b07..3dece45dd997 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index a8191d2ca5e3..d931a66a16e3 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 83398dc4b7c2..4989ce9591ae 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -617,10 +617,11 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) u32 length; u32 index; - ACPI_FUNCTION_NAME(ex_dump_operand) + ACPI_FUNCTION_NAME(ex_dump_operand); - /* Check if debug output enabled */ - if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_EXEC, _COMPONENT)) { + /* Check if debug output enabled */ + + if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_EXEC, _COMPONENT)) { return; } @@ -904,7 +905,7 @@ void acpi_ex_dump_operands(union acpi_operand_object **operands, const char *opcode_name, u32 num_operands) { - ACPI_FUNCTION_NAME(ex_dump_operands); + ACPI_FUNCTION_TRACE(ex_dump_operands); if (!opcode_name) { opcode_name = "UNKNOWN"; @@ -928,7 +929,7 @@ acpi_ex_dump_operands(union acpi_operand_object **operands, ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "**** End operand dump for [%s]\n", opcode_name)); - return; + return_VOID; } /******************************************************************************* diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index 5fda981f6498..e3b0650e5bb6 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index a656608dca84..3d0f274be88b 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index dbad3ebd7df5..1518fcb22ae1 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index ecd95b3f35f1..24c9741dee48 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c index caa5ed1f65ec..c7b249cda5c0 100644 --- a/drivers/acpi/acpica/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index f787651348c1..dae01c93e480 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index 57980b7d3594..3cafa1d6f31a 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index ce857addc8db..f16c655121ff 100644 --- a/drivers/acpi/acpica/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index 688032b58a21..8b39fffce6dc 100644 --- a/drivers/acpi/acpica/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c index 8de060664204..1d1040f2e3f8 100644 --- a/drivers/acpi/acpica/exprep.c +++ b/drivers/acpi/acpica/exprep.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index 7bcc9d809b7e..387c438aa485 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c index 91c1de046442..77fa8d9aa5bf 100644 --- a/drivers/acpi/acpica/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c index 5e1854ea85f6..b104bc3ca809 100644 --- a/drivers/acpi/acpica/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c index 1c7c9962b0de..2643d34f194d 100644 --- a/drivers/acpi/acpica/exresop.c +++ b/drivers/acpi/acpica/exresop.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index bdd43cde8f36..8f106bdcad5f 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c index 56f59cf5da29..3d458d1996b0 100644 --- a/drivers/acpi/acpica/exstoren.c +++ b/drivers/acpi/acpica/exstoren.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c index 4ba7fcbf23b0..905443a3c28f 100644 --- a/drivers/acpi/acpica/exstorob.c +++ b/drivers/acpi/acpica/exstorob.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c index ad3b610057f3..420d9b145d2e 100644 --- a/drivers/acpi/acpica/exsystem.c +++ b/drivers/acpi/acpica/exsystem.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/extrace.c b/drivers/acpi/acpica/extrace.c index ae9df8672d9e..9a67d507a132 100644 --- a/drivers/acpi/acpica/extrace.c +++ b/drivers/acpi/acpica/extrace.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c index 34d608358eaf..fb80d3f55d63 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c index fad249e774b4..68e958d4c25f 100644 --- a/drivers/acpi/acpica/hwacpi.c +++ b/drivers/acpi/acpica/hwacpi.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c index 12626d021a9b..64855b62a5ae 100644 --- a/drivers/acpi/acpica/hwesleep.c +++ b/drivers/acpi/acpica/hwesleep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index 09b6822aa5cc..c1c54af148d0 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c index 283819930be6..faa2fa45eb1c 100644 --- a/drivers/acpi/acpica/hwpci.c +++ b/drivers/acpi/acpica/hwpci.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index aa6e00081915..f3e7b7851a3a 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index 1fe7387a00e6..c85c373ecbc4 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index a2f4e25d45b1..511e3b8ffc6d 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -150,10 +150,10 @@ ACPI_EXPORT_SYMBOL(acpi_get_timer) * ******************************************************************************/ acpi_status -acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed) +acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 *time_elapsed) { acpi_status status; - u32 delta_ticks; + u64 delta_ticks; u64 quotient; ACPI_FUNCTION_TRACE(acpi_get_timer_duration); @@ -168,30 +168,29 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed) return_ACPI_STATUS(AE_SUPPORT); } + if (start_ticks == end_ticks) { + *time_elapsed = 0; + return_ACPI_STATUS(AE_OK); + } + /* * Compute Tick Delta: * Handle (max one) timer rollovers on 24-bit versus 32-bit timers. */ - if (start_ticks < end_ticks) { - delta_ticks = end_ticks - start_ticks; - } else if (start_ticks > end_ticks) { + delta_ticks = end_ticks; + if (start_ticks > end_ticks) { if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) { /* 24-bit Timer */ - delta_ticks = - (((0x00FFFFFF - start_ticks) + - end_ticks) & 0x00FFFFFF); + delta_ticks |= (u64)1 << 24; } else { /* 32-bit Timer */ - delta_ticks = (0xFFFFFFFF - start_ticks) + end_ticks; + delta_ticks |= (u64)1 << 32; } - } else { /* start_ticks == end_ticks */ - - *time_elapsed = 0; - return_ACPI_STATUS(AE_OK); } + delta_ticks -= start_ticks; /* * Compute Duration (Requires a 64-bit multiply and divide): @@ -199,10 +198,10 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed) * time_elapsed (microseconds) = * (delta_ticks * ACPI_USEC_PER_SEC) / ACPI_PM_TIMER_FREQUENCY; */ - status = acpi_ut_short_divide(((u64)delta_ticks) * ACPI_USEC_PER_SEC, + status = acpi_ut_short_divide(delta_ticks * ACPI_USEC_PER_SEC, ACPI_PM_TIMER_FREQUENCY, "ient, NULL); - *time_elapsed = (u32) quotient; + *time_elapsed = (u32)quotient; return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c index 3094cec4eab4..65d82e6add0b 100644 --- a/drivers/acpi/acpica/hwvalid.c +++ b/drivers/acpi/acpica/hwvalid.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -128,14 +128,14 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) acpi_io_address last_address; const struct acpi_port_info *port_info; - ACPI_FUNCTION_NAME(hw_validate_io_request); + ACPI_FUNCTION_TRACE(hw_validate_io_request); /* Supported widths are 8/16/32 */ if ((bit_width != 8) && (bit_width != 16) && (bit_width != 32)) { ACPI_ERROR((AE_INFO, "Bad BitWidth parameter: %8.8X", bit_width)); - return (AE_BAD_PARAMETER); + return_ACPI_STATUS(AE_BAD_PARAMETER); } port_info = acpi_protected_ports; @@ -153,13 +153,13 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) ACPI_ERROR((AE_INFO, "Illegal I/O port address/length above 64K: %8.8X%8.8X/0x%X", ACPI_FORMAT_UINT64(address), byte_width)); - return (AE_LIMIT); + return_ACPI_STATUS(AE_LIMIT); } /* Exit if requested address is not within the protected port table */ if (address > acpi_protected_ports[ACPI_PORT_INFO_ENTRIES - 1].end) { - return (AE_OK); + return_ACPI_STATUS(AE_OK); } /* Check request against the list of protected I/O ports */ @@ -180,8 +180,8 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) /* Port illegality may depend on the _OSI calls made by the BIOS */ if (acpi_gbl_osi_data >= port_info->osi_dependency) { - ACPI_DEBUG_PRINT((ACPI_DB_IO, - "Denied AML access to port 0x%8.8X%8.8X/%X (%s 0x%.4X-0x%.4X)", + ACPI_DEBUG_PRINT((ACPI_DB_VALUES, + "Denied AML access to port 0x%8.8X%8.8X/%X (%s 0x%.4X-0x%.4X)\n", ACPI_FORMAT_UINT64(address), byte_width, port_info->name, port_info->start, @@ -198,7 +198,7 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) } } - return (AE_OK); + return_ACPI_STATUS(AE_OK); } /****************************************************************************** diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index b3c6e439933c..d320b129b7d7 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index e5c095ca6083..589c774bbf9a 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index f2733f51ca8d..07f672b5a1d1 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -644,17 +644,18 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, this_node->object; } } -#ifdef ACPI_ASL_COMPILER - if (!acpi_gbl_disasm_flag && - (this_node->flags & ANOBJ_IS_EXTERNAL)) { - this_node->flags |= IMPLICIT_EXTERNAL; - } -#endif } /* Special handling for the last segment (num_segments == 0) */ else { +#ifdef ACPI_ASL_COMPILER + if (!acpi_gbl_disasm_flag + && (this_node->flags & ANOBJ_IS_EXTERNAL)) { + this_node->flags &= ~IMPLICIT_EXTERNAL; + } +#endif + /* * Sanity typecheck of the target object: * diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index 8ba5b32c9f71..ce57ccf4c1bf 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsarguments.c b/drivers/acpi/acpica/nsarguments.c index 67b7370dcae5..ce296ac14cf0 100644 --- a/drivers/acpi/acpica/nsarguments.c +++ b/drivers/acpi/acpica/nsarguments.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsconvert.c b/drivers/acpi/acpica/nsconvert.c index 539d775bbc92..2f9d5d190fa9 100644 --- a/drivers/acpi/acpica/nsconvert.c +++ b/drivers/acpi/acpica/nsconvert.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -495,7 +495,8 @@ acpi_ns_convert_to_reference(struct acpi_namespace_node *scope, /* Check if we are resolving a named reference within a package */ - ACPI_ERROR_NAMESPACE(original_object->string.pointer, status); + ACPI_ERROR_NAMESPACE(&scope_info, + original_object->string.pointer, status); goto error_exit; } diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index 4123b5077a7d..e2ac16818dc3 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c index 5026594763ea..09ac00dee450 100644 --- a/drivers/acpi/acpica/nsdumpdv.c +++ b/drivers/acpi/acpica/nsdumpdv.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index d22167cbd0ca..c2d883b8c45e 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index 9c6297949712..c17af4a3ab67 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index d2915e186ae1..fdfe9309bd33 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index a410760a0308..c686eda7ca66 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,6 +49,9 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsnames") +/* Local Prototypes */ +static void acpi_ns_normalize_pathname(char *original_path); + /******************************************************************************* * * FUNCTION: acpi_ns_get_external_pathname @@ -63,6 +66,7 @@ ACPI_MODULE_NAME("nsnames") * for error and debug statements. * ******************************************************************************/ + char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) { char *name_buffer; @@ -352,3 +356,148 @@ char *acpi_ns_get_normalized_pathname(struct acpi_namespace_node *node, return_PTR(name_buffer); } + +/******************************************************************************* + * + * FUNCTION: acpi_ns_build_prefixed_pathname + * + * PARAMETERS: prefix_scope - Scope/Path that prefixes the internal path + * internal_path - Name or path of the namespace node + * + * RETURN: None + * + * DESCRIPTION: Construct a fully qualified pathname from a concatenation of: + * 1) Path associated with the prefix_scope namespace node + * 2) External path representation of the Internal path + * + ******************************************************************************/ + +char *acpi_ns_build_prefixed_pathname(union acpi_generic_state *prefix_scope, + const char *internal_path) +{ + acpi_status status; + char *full_path = NULL; + char *external_path = NULL; + char *prefix_path = NULL; + u32 prefix_path_length = 0; + + /* If there is a prefix, get the pathname to it */ + + if (prefix_scope && prefix_scope->scope.node) { + prefix_path = + acpi_ns_get_normalized_pathname(prefix_scope->scope.node, + TRUE); + if (prefix_path) { + prefix_path_length = strlen(prefix_path); + } + } + + status = acpi_ns_externalize_name(ACPI_UINT32_MAX, internal_path, + NULL, &external_path); + if (ACPI_FAILURE(status)) { + goto cleanup; + } + + /* Merge the prefix path and the path. 2 is for one dot and trailing null */ + + full_path = + ACPI_ALLOCATE_ZEROED(prefix_path_length + strlen(external_path) + + 2); + if (!full_path) { + goto cleanup; + } + + /* Don't merge if the External path is already fully qualified */ + + if (prefix_path && (*external_path != '\\') && (*external_path != '^')) { + strcat(full_path, prefix_path); + if (prefix_path[1]) { + strcat(full_path, "."); + } + } + + acpi_ns_normalize_pathname(external_path); + strcat(full_path, external_path); + +cleanup: + if (prefix_path) { + ACPI_FREE(prefix_path); + } + if (external_path) { + ACPI_FREE(external_path); + } + + return (full_path); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ns_normalize_pathname + * + * PARAMETERS: original_path - Path to be normalized, in External format + * + * RETURN: The original path is processed in-place + * + * DESCRIPTION: Remove trailing underscores from each element of a path. + * + * For example: \A___.B___.C___ becomes \A.B.C + * + ******************************************************************************/ + +static void acpi_ns_normalize_pathname(char *original_path) +{ + char *input_path = original_path; + char *new_path_buffer; + char *new_path; + u32 i; + + /* Allocate a temp buffer in which to construct the new path */ + + new_path_buffer = ACPI_ALLOCATE_ZEROED(strlen(input_path) + 1); + new_path = new_path_buffer; + if (!new_path_buffer) { + return; + } + + /* Special characters may appear at the beginning of the path */ + + if (*input_path == '\\') { + *new_path = *input_path; + new_path++; + input_path++; + } + + while (*input_path == '^') { + *new_path = *input_path; + new_path++; + input_path++; + } + + /* Remainder of the path */ + + while (*input_path) { + + /* Do one nameseg at a time */ + + for (i = 0; (i < ACPI_NAME_SIZE) && *input_path; i++) { + if ((i == 0) || (*input_path != '_')) { /* First char is allowed to be underscore */ + *new_path = *input_path; + new_path++; + } + + input_path++; + } + + /* Dot means that there are more namesegs to come */ + + if (*input_path == '.') { + *new_path = *input_path; + new_path++; + input_path++; + } + } + + *new_path = 0; + strcpy(original_path, new_path_buffer); + ACPI_FREE(new_path_buffer); +} diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c index 707b2aa501e1..757e44555ec3 100644 --- a/drivers/acpi/acpica/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index 2fc33a5203f4..c5b22ea5b369 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index 9d14b509529e..4f1f6d6d9ddf 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsprepkg.c b/drivers/acpi/acpica/nsprepkg.c index a8ea8fb1d299..7805d5ce8127 100644 --- a/drivers/acpi/acpica/nsprepkg.c +++ b/drivers/acpi/acpica/nsprepkg.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index 418ef2ac82ab..7b6b6d281f1c 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index 06037e044694..29c3973c7815 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index 5de8957f5ef0..a469447f5c02 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -417,6 +417,7 @@ acpi_ns_search_and_enter(u32 target_name, if (flags & ACPI_NS_EXTERNAL || (walk_state && walk_state->opcode == AML_SCOPE_OP)) { new_node->flags |= ANOBJ_IS_EXTERNAL; + new_node->flags |= IMPLICIT_EXTERNAL; } #endif diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index b43fe5fce64b..0487fdb59b0e 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 6b6e6f498cff..dd7ae1bc8af8 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index 783f4c838aee..1075bd9541f5 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -61,10 +61,10 @@ static void acpi_ns_resolve_references(struct acpi_evaluate_info *info); * * PARAMETERS: handle - Object handle (optional) * pathname - Object pathname (optional) - * external_params - List of parameters to pass to method, + * external_params - List of parameters to pass to a method, * terminated by NULL. May be NULL * if no parameters are being passed. - * return_buffer - Where to put method's return value (if + * return_buffer - Where to put the object's return value (if * any). If NULL, no value is returned. * return_type - Expected type of return object * @@ -100,13 +100,14 @@ acpi_evaluate_object_typed(acpi_handle handle, free_buffer_on_error = TRUE; } + /* Get a handle here, in order to build an error message if needed */ + + target_handle = handle; if (pathname) { status = acpi_get_handle(handle, pathname, &target_handle); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } - } else { - target_handle = handle; } full_pathname = acpi_ns_get_external_pathname(target_handle); diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 106966235805..e9603fc9586c 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index 47f689ec3fcb..ac1fbf767cac 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index eb9dfaca555f..dbc51bc5fdd6 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -361,7 +361,7 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, /* Final exception check (may have been changed from code above) */ if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(path, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, path, status); if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) { diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index bb04dec168ad..7dca287d7690 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index 0bef6df71bba..b18f1e048985 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -372,16 +372,10 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state, * external declaration opcode. Setting walk_state->Aml to * walk_state->parser_state.Aml + 2 moves increments the * walk_state->Aml past the object type and the paramcount of the - * external opcode. For the error message, only print the AML - * offset. We could attempt to print the name but this may cause - * a segmentation fault when printing the namepath because the - * AML may be incorrect. + * external opcode. */ - acpi_os_printf - ("// Invalid external declaration at AML offset 0x%x.\n", - walk_state->aml - - walk_state->parser_state.aml_start); walk_state->aml = walk_state->parser_state.aml + 2; + walk_state->parser_state.aml = walk_state->aml; return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); } #endif diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index a402ad772a1e..d31f3eb23225 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psopinfo.c b/drivers/acpi/acpica/psopinfo.c index eff22950232b..1dc1fc79297e 100644 --- a/drivers/acpi/acpica/psopinfo.c +++ b/drivers/acpi/acpica/psopinfo.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index ac88319dc111..2474ff961294 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psscope.c b/drivers/acpi/acpica/psscope.c index 22d7f1d6849b..f49cdcc65700 100644 --- a/drivers/acpi/acpica/psscope.c +++ b/drivers/acpi/acpica/psscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c index c06d6e2fc7a5..f9fa88c79b32 100644 --- a/drivers/acpi/acpica/pstree.c +++ b/drivers/acpi/acpica/pstree.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index 02642760cb93..fe151f42de3a 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -94,9 +94,11 @@ void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode) op->common.descriptor_type = ACPI_DESC_TYPE_PARSER; op->common.aml_opcode = opcode; - ACPI_DISASM_ONLY_MEMBERS(strncpy(op->common.aml_op_name, - (acpi_ps_get_opcode_info(opcode))-> - name, sizeof(op->common.aml_op_name))); + ACPI_DISASM_ONLY_MEMBERS(acpi_ut_safe_strncpy(op->common.aml_op_name, + (acpi_ps_get_opcode_info + (opcode))->name, + sizeof(op->common. + aml_op_name))); } /******************************************************************************* @@ -158,10 +160,10 @@ union acpi_parse_object *acpi_ps_alloc_op(u16 opcode, u8 *aml) if (opcode == AML_SCOPE_OP) { acpi_gbl_current_scope = op; } - } - if (gbl_capture_comments) { - ASL_CV_TRANSFER_COMMENTS(op); + if (acpi_gbl_capture_comments) { + ASL_CV_TRANSFER_COMMENTS(op); + } } return (op); diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c index 22a37c82af19..bc5c779e54e8 100644 --- a/drivers/acpi/acpica/pswalk.c +++ b/drivers/acpi/acpica/pswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index c88a681586bf..d2270ade5cf8 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c index a131a28bb09d..213bad89675b 100644 --- a/drivers/acpi/acpica/rsaddr.c +++ b/drivers/acpi/acpica/rsaddr.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index 659fb718504a..576f7aae162b 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index f72ff0b54a63..fe07001ea865 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c index 55fd1880efbe..bc4c4755aeb9 100644 --- a/drivers/acpi/acpica/rsdump.c +++ b/drivers/acpi/acpica/rsdump.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsdumpinfo.c b/drivers/acpi/acpica/rsdumpinfo.c index da150e17795b..c4a2a08e31ac 100644 --- a/drivers/acpi/acpica/rsdumpinfo.c +++ b/drivers/acpi/acpica/rsdumpinfo.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c index b0e50518d766..e819bb0f45af 100644 --- a/drivers/acpi/acpica/rsinfo.c +++ b/drivers/acpi/acpica/rsinfo.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsio.c b/drivers/acpi/acpica/rsio.c index b7a47fbc519b..eafd993592f6 100644 --- a/drivers/acpi/acpica/rsio.c +++ b/drivers/acpi/acpica/rsio.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsirq.c b/drivers/acpi/acpica/rsirq.c index 092a733c42b8..aabd73298eb8 100644 --- a/drivers/acpi/acpica/rsirq.c +++ b/drivers/acpi/acpica/rsirq.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c index 36a6657dd34d..11214780ea8f 100644 --- a/drivers/acpi/acpica/rslist.c +++ b/drivers/acpi/acpica/rslist.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsmemory.c b/drivers/acpi/acpica/rsmemory.c index 273eecb3001b..05e375abc6b5 100644 --- a/drivers/acpi/acpica/rsmemory.c +++ b/drivers/acpi/acpica/rsmemory.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c index cc4b5486c4bc..7b4627181cc6 100644 --- a/drivers/acpi/acpica/rsmisc.c +++ b/drivers/acpi/acpica/rsmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsserial.c b/drivers/acpi/acpica/rsserial.c index 14d12d6eb716..87dac2812072 100644 --- a/drivers/acpi/acpica/rsserial.c +++ b/drivers/acpi/acpica/rsserial.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c index b2aeca01204a..49ff7f851d58 100644 --- a/drivers/acpi/acpica/rsutils.c +++ b/drivers/acpi/acpica/rsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index be65e65e216e..3b481f0b81c5 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index b19a2f0ea331..ec69267f1447 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 5f051d82188d..d1763c5e4e91 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c index fea89c8d305c..999a64a48e1a 100644 --- a/drivers/acpi/acpica/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 0dfc0ac3c141..00be16da1ee2 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbprint.c b/drivers/acpi/acpica/tbprint.c index edfd7b10be19..8cdcdd2c4697 100644 --- a/drivers/acpi/acpica/tbprint.c +++ b/drivers/acpi/acpica/tbprint.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 0c6768d20395..30d40ff8992b 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 5ecb8d2e6834..dca91b6f8cc2 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index d81f442228b8..e09b4b26300e 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c index f9f9a7da2cad..abf3c62e1e80 100644 --- a/drivers/acpi/acpica/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c index 26a0633115be..d8540f380ae5 100644 --- a/drivers/acpi/acpica/utaddress.c +++ b/drivers/acpi/acpica/utaddress.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c index 5594a359dbf1..12fbaddbfb0d 100644 --- a/drivers/acpi/acpica/utalloc.c +++ b/drivers/acpi/acpica/utalloc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utascii.c b/drivers/acpi/acpica/utascii.c index 909bdb198651..95565e46a695 100644 --- a/drivers/acpi/acpica/utascii.c +++ b/drivers/acpi/acpica/utascii.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utbuffer.c b/drivers/acpi/acpica/utbuffer.c index f17eaa009dde..2c5a14c2f46b 100644 --- a/drivers/acpi/acpica/utbuffer.c +++ b/drivers/acpi/acpica/utbuffer.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c index 531493306dee..08e6944404b3 100644 --- a/drivers/acpi/acpica/utcache.c +++ b/drivers/acpi/acpica/utcache.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index e9382255d6c6..01434af99035 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 615a885e2ca3..2201be1bf4c2 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -163,6 +163,9 @@ acpi_debug_print(u32 requested_debug_level, { acpi_thread_id thread_id; va_list args; +#ifdef ACPI_APPLICATION + int fill_count; +#endif /* Check if debug output enabled */ @@ -202,10 +205,21 @@ acpi_debug_print(u32 requested_debug_level, acpi_os_printf("[%u] ", (u32)thread_id); } - acpi_os_printf("[%02ld] ", acpi_gbl_nesting_level); -#endif + fill_count = 48 - acpi_gbl_nesting_level - + strlen(acpi_ut_trim_function_name(function_name)); + if (fill_count < 0) { + fill_count = 0; + } + acpi_os_printf("[%02ld] %*s", + acpi_gbl_nesting_level, acpi_gbl_nesting_level + 1, " "); + acpi_os_printf("%s%*s: ", + acpi_ut_trim_function_name(function_name), fill_count, + " "); + +#else acpi_os_printf("%-22.22s: ", acpi_ut_trim_function_name(function_name)); +#endif va_start(args, format); acpi_os_vprintf(format, args); diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index 02cd2c2d961a..1a3f316a18a8 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -395,11 +395,6 @@ const char *acpi_ut_get_reference_name(union acpi_operand_object *object) return (acpi_gbl_ref_class_names[object->reference.class]); } -#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) -/* - * Strings and procedures used for debug only - */ - /******************************************************************************* * * FUNCTION: acpi_ut_get_mutex_name @@ -433,6 +428,12 @@ const char *acpi_ut_get_mutex_name(u32 mutex_id) return (acpi_gbl_mutex_names[mutex_id]); } +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) + +/* + * Strings and procedures used for debug only + */ + /******************************************************************************* * * FUNCTION: acpi_ut_get_notify_name diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index c6eb9fae70f9..7d8d0208f0a3 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/uterror.c b/drivers/acpi/acpica/uterror.c index e3368186e1c1..ce5e891291bf 100644 --- a/drivers/acpi/acpica/uterror.c +++ b/drivers/acpi/acpica/uterror.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -180,6 +180,78 @@ acpi_ut_predefined_bios_error(const char *module_name, va_end(arg_list); } +/******************************************************************************* + * + * FUNCTION: acpi_ut_prefixed_namespace_error + * + * PARAMETERS: module_name - Caller's module name (for error output) + * line_number - Caller's line number (for error output) + * prefix_scope - Scope/Path that prefixes the internal path + * internal_path - Name or path of the namespace node + * lookup_status - Exception code from NS lookup + * + * RETURN: None + * + * DESCRIPTION: Print error message with the full pathname constructed this way: + * + * prefix_scope_node_full_path.externalized_internal_path + * + * NOTE: 10/2017: Treat the major ns_lookup errors as firmware errors + * + ******************************************************************************/ + +void +acpi_ut_prefixed_namespace_error(const char *module_name, + u32 line_number, + union acpi_generic_state *prefix_scope, + const char *internal_path, + acpi_status lookup_status) +{ + char *full_path; + const char *message; + + /* + * Main cases: + * 1) Object creation, object must not already exist + * 2) Object lookup, object must exist + */ + switch (lookup_status) { + case AE_ALREADY_EXISTS: + + acpi_os_printf(ACPI_MSG_BIOS_ERROR); + message = "Failure creating"; + break; + + case AE_NOT_FOUND: + + acpi_os_printf(ACPI_MSG_BIOS_ERROR); + message = "Failure looking up"; + break; + + default: + + acpi_os_printf(ACPI_MSG_ERROR); + message = "Failure looking up"; + break; + } + + /* Concatenate the prefix path and the internal path */ + + full_path = + acpi_ns_build_prefixed_pathname(prefix_scope, internal_path); + + acpi_os_printf("%s [%s], %s", message, + full_path ? full_path : "Could not get pathname", + acpi_format_exception(lookup_status)); + + if (full_path) { + ACPI_FREE(full_path); + } + + ACPI_MSG_SUFFIX; +} + +#ifdef __OBSOLETE_FUNCTION /******************************************************************************* * * FUNCTION: acpi_ut_namespace_error @@ -240,6 +312,7 @@ acpi_ut_namespace_error(const char *module_name, ACPI_MSG_SUFFIX; ACPI_MSG_REDIRECT_END; } +#endif /******************************************************************************* * diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c index 3fce7519c690..b8be0b82a130 100644 --- a/drivers/acpi/acpica/uteval.c +++ b/drivers/acpi/acpica/uteval.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utexcep.c b/drivers/acpi/acpica/utexcep.c index eb6dcab33d2f..e3dbad8b73e5 100644 --- a/drivers/acpi/acpica/utexcep.c +++ b/drivers/acpi/acpica/utexcep.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index 230a50c82f22..933595b0e594 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/uthex.c b/drivers/acpi/acpica/uthex.c index fb406daf47fa..f5886d557a94 100644 --- a/drivers/acpi/acpica/uthex.c +++ b/drivers/acpi/acpica/uthex.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c index a6eb580ee21d..db3c3c1d33da 100644 --- a/drivers/acpi/acpica/utids.c +++ b/drivers/acpi/acpica/utids.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c index 23e766d1691d..a2005b030347 100644 --- a/drivers/acpi/acpica/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -206,7 +206,6 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_next_owner_id_offset = 0; acpi_gbl_debugger_configuration = DEBUGGER_THREADING; acpi_gbl_osi_mutex = NULL; - acpi_gbl_max_loop_iterations = ACPI_MAX_LOOP_COUNT; /* Hardware oriented */ diff --git a/drivers/acpi/acpica/utlock.c b/drivers/acpi/acpica/utlock.c index db2d9910866e..0636074a4c23 100644 --- a/drivers/acpi/acpica/utlock.c +++ b/drivers/acpi/acpica/utlock.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c index 5f9c680076c4..eddf71990433 100644 --- a/drivers/acpi/acpica/utmath.c +++ b/drivers/acpi/acpica/utmath.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -134,7 +134,7 @@ acpi_status acpi_ut_short_shift_left(u64 operand, u32 count, u64 *out_result) if ((count & 63) >= 32) { operand_ovl.part.hi = operand_ovl.part.lo; - operand_ovl.part.lo ^= operand_ovl.part.lo; + operand_ovl.part.lo = 0; count = (count & 63) - 32; } ACPI_SHIFT_LEFT_64_BY_32(operand_ovl.part.hi, @@ -171,7 +171,7 @@ acpi_status acpi_ut_short_shift_right(u64 operand, u32 count, u64 *out_result) if ((count & 63) >= 32) { operand_ovl.part.lo = operand_ovl.part.hi; - operand_ovl.part.hi ^= operand_ovl.part.hi; + operand_ovl.part.hi = 0; count = (count & 63) - 32; } ACPI_SHIFT_RIGHT_64_BY_32(operand_ovl.part.hi, diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 45c78c2adbf0..a331313ad5fa 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index 586354788018..6767bd1626f7 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -286,8 +286,9 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id; } else { ACPI_EXCEPTION((AE_INFO, status, - "Thread %u could not acquire Mutex [0x%X]", - (u32)this_thread_id, mutex_id)); + "Thread %u could not acquire Mutex [%s] (0x%X)", + (u32)this_thread_id, + acpi_ut_get_mutex_name(mutex_id), mutex_id)); } return (status); @@ -322,8 +323,8 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) */ if (acpi_gbl_mutex_info[mutex_id].thread_id == ACPI_MUTEX_NOT_ACQUIRED) { ACPI_ERROR((AE_INFO, - "Mutex [0x%X] is not acquired, cannot release", - mutex_id)); + "Mutex [%s] (0x%X) is not acquired, cannot release", + acpi_ut_get_mutex_name(mutex_id), mutex_id)); return (AE_NOT_ACQUIRED); } diff --git a/drivers/acpi/acpica/utnonansi.c b/drivers/acpi/acpica/utnonansi.c index 792664982ea3..94219610e259 100644 --- a/drivers/acpi/acpica/utnonansi.c +++ b/drivers/acpi/acpica/utnonansi.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -140,7 +140,7 @@ int acpi_ut_stricmp(char *string1, char *string2) return (c1 - c2); } -#if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION) +#if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION) || defined (ACPI_DEBUG_OUTPUT) /******************************************************************************* * * FUNCTION: acpi_ut_safe_strcpy, acpi_ut_safe_strcat, acpi_ut_safe_strncat @@ -199,4 +199,13 @@ acpi_ut_safe_strncat(char *dest, strncat(dest, source, max_transfer_length); return (FALSE); } + +void acpi_ut_safe_strncpy(char *dest, char *source, acpi_size dest_size) +{ + /* Always terminate destination string */ + + strncpy(dest, source, dest_size); + dest[dest_size - 1] = 0; +} + #endif diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index cb3db9fed50d..375901c0a596 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c index 3175b133c0e4..00ea104f6a0a 100644 --- a/drivers/acpi/acpica/utosi.c +++ b/drivers/acpi/acpica/utosi.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -101,6 +101,8 @@ static struct acpi_interface_info acpi_default_supported_interfaces[] = { {"Windows 2012", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8 and Server 2012 - Added 08/2012 */ {"Windows 2013", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8.1 and Server 2012 R2 - Added 01/2014 */ {"Windows 2015", NULL, 0, ACPI_OSI_WIN_10}, /* Windows 10 - Added 03/2015 */ + {"Windows 2016", NULL, 0, ACPI_OSI_WIN_10_RS1}, /* Windows 10 version 1607 - Added 12/2017 */ + {"Windows 2017", NULL, 0, ACPI_OSI_WIN_10_RS2}, /* Windows 10 version 1703 - Added 12/2017 */ /* Feature Group Strings */ diff --git a/drivers/acpi/acpica/utownerid.c b/drivers/acpi/acpica/utownerid.c index 1b3ee74a87eb..9923dfa708be 100644 --- a/drivers/acpi/acpica/utownerid.c +++ b/drivers/acpi/acpica/utownerid.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utpredef.c b/drivers/acpi/acpica/utpredef.c index 350709f23e4c..ae6fef02b692 100644 --- a/drivers/acpi/acpica/utpredef.c +++ b/drivers/acpi/acpica/utpredef.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utprint.c b/drivers/acpi/acpica/utprint.c index c008589b41bd..ac07700f5b79 100644 --- a/drivers/acpi/acpica/utprint.c +++ b/drivers/acpi/acpica/utprint.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utresdecode.c b/drivers/acpi/acpica/utresdecode.c index e15a2538558b..93fa3450ca88 100644 --- a/drivers/acpi/acpica/utresdecode.c +++ b/drivers/acpi/acpica/utresdecode.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index f9801d13547f..4d289d9c734c 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c index eafabcd2fada..7750c48739d8 100644 --- a/drivers/acpi/acpica/utstate.c +++ b/drivers/acpi/acpica/utstate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c index 9eacbcb9e4f4..a9507d1976ff 100644 --- a/drivers/acpi/acpica/utstring.c +++ b/drivers/acpi/acpica/utstring.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utstrsuppt.c b/drivers/acpi/acpica/utstrsuppt.c index 965fb5cec94f..6fc76f0b60e9 100644 --- a/drivers/acpi/acpica/utstrsuppt.c +++ b/drivers/acpi/acpica/utstrsuppt.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -52,10 +52,9 @@ static acpi_status acpi_ut_insert_digit(u64 *accumulated_value, u32 base, int ascii_digit); static acpi_status -acpi_ut_strtoul_multiply64(u64 multiplicand, u64 multiplier, u64 *out_product); +acpi_ut_strtoul_multiply64(u64 multiplicand, u32 base, u64 *out_product); -static acpi_status -acpi_ut_strtoul_add64(u64 addend1, u64 addend2, u64 *out_sum); +static acpi_status acpi_ut_strtoul_add64(u64 addend1, u32 digit, u64 *out_sum); /******************************************************************************* * @@ -357,7 +356,7 @@ acpi_ut_insert_digit(u64 *accumulated_value, u32 base, int ascii_digit) * FUNCTION: acpi_ut_strtoul_multiply64 * * PARAMETERS: multiplicand - Current accumulated converted integer - * multiplier - Base/Radix + * base - Base/Radix * out_product - Where the product is returned * * RETURN: Status and 64-bit product @@ -369,33 +368,40 @@ acpi_ut_insert_digit(u64 *accumulated_value, u32 base, int ascii_digit) ******************************************************************************/ static acpi_status -acpi_ut_strtoul_multiply64(u64 multiplicand, u64 multiplier, u64 *out_product) +acpi_ut_strtoul_multiply64(u64 multiplicand, u32 base, u64 *out_product) { - u64 val; + u64 product; + u64 quotient; /* Exit if either operand is zero */ *out_product = 0; - if (!multiplicand || !multiplier) { + if (!multiplicand || !base) { return (AE_OK); } - /* Check for 64-bit overflow before the actual multiplication */ - - acpi_ut_short_divide(ACPI_UINT64_MAX, (u32)multiplier, &val, NULL); - if (multiplicand > val) { + /* + * Check for 64-bit overflow before the actual multiplication. + * + * Notes: 64-bit division is often not supported on 32-bit platforms + * (it requires a library function), Therefore ACPICA has a local + * 64-bit divide function. Also, Multiplier is currently only used + * as the radix (8/10/16), to the 64/32 divide will always work. + */ + acpi_ut_short_divide(ACPI_UINT64_MAX, base, "ient, NULL); + if (multiplicand > quotient) { return (AE_NUMERIC_OVERFLOW); } - val = multiplicand * multiplier; + product = multiplicand * base; /* Check for 32-bit overflow if necessary */ - if ((acpi_gbl_integer_bit_width == 32) && (val > ACPI_UINT32_MAX)) { + if ((acpi_gbl_integer_bit_width == 32) && (product > ACPI_UINT32_MAX)) { return (AE_NUMERIC_OVERFLOW); } - *out_product = val; + *out_product = product; return (AE_OK); } @@ -404,7 +410,7 @@ acpi_ut_strtoul_multiply64(u64 multiplicand, u64 multiplier, u64 *out_product) * FUNCTION: acpi_ut_strtoul_add64 * * PARAMETERS: addend1 - Current accumulated converted integer - * addend2 - New hex value/char + * digit - New hex value/char * out_sum - Where sum is returned (Accumulator) * * RETURN: Status and 64-bit sum @@ -415,17 +421,17 @@ acpi_ut_strtoul_multiply64(u64 multiplicand, u64 multiplier, u64 *out_product) * ******************************************************************************/ -static acpi_status acpi_ut_strtoul_add64(u64 addend1, u64 addend2, u64 *out_sum) +static acpi_status acpi_ut_strtoul_add64(u64 addend1, u32 digit, u64 *out_sum) { u64 sum; /* Check for 64-bit overflow before the actual addition */ - if ((addend1 > 0) && (addend2 > (ACPI_UINT64_MAX - addend1))) { + if ((addend1 > 0) && (digit > (ACPI_UINT64_MAX - addend1))) { return (AE_NUMERIC_OVERFLOW); } - sum = addend1 + addend2; + sum = addend1 + digit; /* Check for 32-bit overflow if necessary */ diff --git a/drivers/acpi/acpica/utstrtoul64.c b/drivers/acpi/acpica/utstrtoul64.c index e2067dcb9389..9f7cef1de34a 100644 --- a/drivers/acpi/acpica/utstrtoul64.c +++ b/drivers/acpi/acpica/utstrtoul64.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c index 3c8de88ecbd5..8cc70ca4e0fb 100644 --- a/drivers/acpi/acpica/uttrack.c +++ b/drivers/acpi/acpica/uttrack.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -402,8 +402,8 @@ acpi_ut_track_allocation(struct acpi_debug_mem_block *allocation, allocation->component = component; allocation->line = line; - strncpy(allocation->module, module, ACPI_MAX_MODULE_NAME); - allocation->module[ACPI_MAX_MODULE_NAME - 1] = 0; + acpi_ut_safe_strncpy(allocation->module, (char *)module, + ACPI_MAX_MODULE_NAME); if (!element) { @@ -717,7 +717,7 @@ exit: if (!num_outstanding) { ACPI_INFO(("No outstanding allocations")); } else { - ACPI_ERROR((AE_INFO, "%u(0x%X) Outstanding allocations", + ACPI_ERROR((AE_INFO, "%u (0x%X) Outstanding cache allocations", num_outstanding, num_outstanding)); } diff --git a/drivers/acpi/acpica/utuuid.c b/drivers/acpi/acpica/utuuid.c index 5028e06718b1..95946fdb55d5 100644 --- a/drivers/acpi/acpica/utuuid.c +++ b/drivers/acpi/acpica/utuuid.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index 6b9ba4029f8e..25ef2ce64603 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c index 950a1e500bfa..a78861ded894 100644 --- a/drivers/acpi/acpica/utxferror.c +++ b/drivers/acpi/acpica/utxferror.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -96,8 +96,8 @@ ACPI_EXPORT_SYMBOL(acpi_error) * * RETURN: None * - * DESCRIPTION: Print "ACPI Exception" message with module/line/version info - * and decoded acpi_status. + * DESCRIPTION: Print an "ACPI Error" message with module/line/version + * info as well as decoded acpi_status. * ******************************************************************************/ void ACPI_INTERNAL_VAR_XFACE @@ -111,10 +111,10 @@ acpi_exception(const char *module_name, /* For AE_OK, just print the message */ if (ACPI_SUCCESS(status)) { - acpi_os_printf(ACPI_MSG_EXCEPTION); + acpi_os_printf(ACPI_MSG_ERROR); } else { - acpi_os_printf(ACPI_MSG_EXCEPTION "%s, ", + acpi_os_printf(ACPI_MSG_ERROR "%s, ", acpi_format_exception(status)); } diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c index 6d5180601cf2..e727db52a55e 100644 --- a/drivers/acpi/acpica/utxfinit.c +++ b/drivers/acpi/acpica/utxfinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxfmutex.c b/drivers/acpi/acpica/utxfmutex.c index 0b85f113f726..764782fcf1bd 100644 --- a/drivers/acpi/acpica/utxfmutex.c +++ b/drivers/acpi/acpica/utxfmutex.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2017, Intel Corp. + * Copyright (C) 2000 - 2018, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 6402f7fad3bb..1efefe919555 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -410,7 +410,52 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int flags = 0; if (flags != -1) - memory_failure_queue(pfn, 0, flags); + memory_failure_queue(pfn, flags); +#endif +} + +/* + * PCIe AER errors need to be sent to the AER driver for reporting and + * recovery. The GHES severities map to the following AER severities and + * require the following handling: + * + * GHES_SEV_CORRECTABLE -> AER_CORRECTABLE + * These need to be reported by the AER driver but no recovery is + * necessary. + * GHES_SEV_RECOVERABLE -> AER_NONFATAL + * GHES_SEV_RECOVERABLE && CPER_SEC_RESET -> AER_FATAL + * These both need to be reported and recovered from by the AER driver. + * GHES_SEV_PANIC does not make it to this handling since the kernel must + * panic. + */ +static void ghes_handle_aer(struct acpi_hest_generic_data *gdata) +{ +#ifdef CONFIG_ACPI_APEI_PCIEAER + struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata); + + if (pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID && + pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) { + unsigned int devfn; + int aer_severity; + + devfn = PCI_DEVFN(pcie_err->device_id.device, + pcie_err->device_id.function); + aer_severity = cper_severity_to_aer(gdata->error_severity); + + /* + * If firmware reset the component to contain + * the error, we must reinitialize it before + * use, so treat it as a fatal AER error. + */ + if (gdata->flags & CPER_SEC_RESET) + aer_severity = AER_FATAL; + + aer_recover_queue(pcie_err->device_id.segment, + pcie_err->device_id.bus, + devfn, aer_severity, + (struct aer_capability_regs *) + pcie_err->aer_info); + } #endif } @@ -441,38 +486,9 @@ static void ghes_do_proc(struct ghes *ghes, arch_apei_report_mem_error(sev, mem_err); ghes_handle_memory_failure(gdata, sev); } -#ifdef CONFIG_ACPI_APEI_PCIEAER else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { - struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata); - - if (sev == GHES_SEV_RECOVERABLE && - sec_sev == GHES_SEV_RECOVERABLE && - pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID && - pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) { - unsigned int devfn; - int aer_severity; - - devfn = PCI_DEVFN(pcie_err->device_id.device, - pcie_err->device_id.function); - aer_severity = cper_severity_to_aer(gdata->error_severity); - - /* - * If firmware reset the component to contain - * the error, we must reinitialize it before - * use, so treat it as a fatal AER error. - */ - if (gdata->flags & CPER_SEC_RESET) - aer_severity = AER_FATAL; - - aer_recover_queue(pcie_err->device_id.segment, - pcie_err->device_id.bus, - devfn, aer_severity, - (struct aer_capability_regs *) - pcie_err->aer_info); - } - + ghes_handle_aer(gdata); } -#endif else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) { struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata); @@ -870,7 +886,6 @@ static void ghes_print_queued_estatus(void) struct ghes_estatus_node *estatus_node; struct acpi_hest_generic *generic; struct acpi_hest_generic_status *estatus; - u32 len, node_len; llnode = llist_del_all(&ghes_estatus_llist); /* @@ -882,8 +897,6 @@ static void ghes_print_queued_estatus(void) estatus_node = llist_entry(llnode, struct ghes_estatus_node, llnode); estatus = GHES_ESTATUS_FROM_NODE(estatus_node); - len = cper_estatus_len(estatus); - node_len = GHES_ESTATUS_NODE_LEN(len); generic = estatus_node->generic; ghes_print_estatus(NULL, generic, estatus); llnode = llnode->next; diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 13e7b56e33ae..7128488a3a72 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -70,6 +70,7 @@ static async_cookie_t async_cookie; static bool battery_driver_registered; static int battery_bix_broken_package; static int battery_notification_delay_ms; +static int battery_full_discharging; static unsigned int cache_time = 1000; module_param(cache_time, uint, 0644); MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); @@ -214,9 +215,12 @@ static int acpi_battery_get_property(struct power_supply *psy, return -ENODEV; switch (psp) { case POWER_SUPPLY_PROP_STATUS: - if (battery->state & ACPI_BATTERY_STATE_DISCHARGING) - val->intval = POWER_SUPPLY_STATUS_DISCHARGING; - else if (battery->state & ACPI_BATTERY_STATE_CHARGING) + if (battery->state & ACPI_BATTERY_STATE_DISCHARGING) { + if (battery_full_discharging && battery->rate_now == 0) + val->intval = POWER_SUPPLY_STATUS_FULL; + else + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + } else if (battery->state & ACPI_BATTERY_STATE_CHARGING) val->intval = POWER_SUPPLY_STATUS_CHARGING; else if (acpi_battery_is_charged(battery)) val->intval = POWER_SUPPLY_STATUS_FULL; @@ -1166,6 +1170,12 @@ battery_notification_delay_quirk(const struct dmi_system_id *d) return 0; } +static int __init battery_full_discharging_quirk(const struct dmi_system_id *d) +{ + battery_full_discharging = 1; + return 0; +} + static const struct dmi_system_id bat_dmi_table[] __initconst = { { .callback = battery_bix_broken_package_quirk, @@ -1183,6 +1193,38 @@ static const struct dmi_system_id bat_dmi_table[] __initconst = { DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-573G"), }, }, + { + .callback = battery_full_discharging_quirk, + .ident = "ASUS GL502VSK", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "GL502VSK"), + }, + }, + { + .callback = battery_full_discharging_quirk, + .ident = "ASUS UX305LA", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "UX305LA"), + }, + }, + { + .callback = battery_full_discharging_quirk, + .ident = "ASUS UX360UA", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "UX360UA"), + }, + }, + { + .callback = battery_full_discharging_quirk, + .ident = "ASUS UX410UAK", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "UX410UAK"), + }, + }, {}, }; @@ -1237,13 +1279,11 @@ static int acpi_battery_add(struct acpi_device *device) #ifdef CONFIG_ACPI_PROCFS_POWER result = acpi_battery_add_fs(device); -#endif if (result) { -#ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_remove_fs(device); -#endif goto fail; } +#endif printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 4d0979e02a28..676c9788e1c8 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -66,10 +66,37 @@ static int set_copy_dsdt(const struct dmi_system_id *id) return 0; } #endif +static int set_gbl_term_list(const struct dmi_system_id *id) +{ + acpi_gbl_parse_table_as_term_list = 1; + return 0; +} -static const struct dmi_system_id dsdt_dmi_table[] __initconst = { +static const struct dmi_system_id acpi_quirks_dmi_table[] __initconst = { + /* + * Touchpad on Dell XPS 9570/Precision M5530 doesn't work under I2C + * mode. + * https://bugzilla.kernel.org/show_bug.cgi?id=198515 + */ + { + .callback = set_gbl_term_list, + .ident = "Dell Precision M5530", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Precision M5530"), + }, + }, + { + .callback = set_gbl_term_list, + .ident = "Dell XPS 15 9570", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "XPS 15 9570"), + }, + }, /* * Invoke DSDT corruption work-around on all Toshiba Satellite. + * DSDT will be copied to memory. * https://bugzilla.kernel.org/show_bug.cgi?id=14679 */ { @@ -83,7 +110,7 @@ static const struct dmi_system_id dsdt_dmi_table[] __initconst = { {} }; #else -static const struct dmi_system_id dsdt_dmi_table[] __initconst = { +static const struct dmi_system_id acpi_quirks_dmi_table[] __initconst = { {} }; #endif @@ -108,6 +135,7 @@ acpi_status acpi_bus_get_status_handle(acpi_handle handle, } return status; } +EXPORT_SYMBOL_GPL(acpi_bus_get_status_handle); int acpi_bus_get_status(struct acpi_device *device) { @@ -119,6 +147,12 @@ int acpi_bus_get_status(struct acpi_device *device) return 0; } + /* Battery devices must have their deps met before calling _STA */ + if (acpi_device_is_battery(device) && device->dep_unmet) { + acpi_set_device_status(device, 0); + return 0; + } + status = acpi_bus_get_status_handle(device->handle, &sta); if (ACPI_FAILURE(status)) return -ENODEV; @@ -785,6 +819,24 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, } EXPORT_SYMBOL_GPL(acpi_match_device); +void *acpi_get_match_data(const struct device *dev) +{ + const struct acpi_device_id *match; + + if (!dev->driver) + return NULL; + + if (!dev->driver->acpi_match_table) + return NULL; + + match = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!match) + return NULL; + + return (void *)match->driver_data; +} +EXPORT_SYMBOL_GPL(acpi_get_match_data); + int acpi_match_device_ids(struct acpi_device *device, const struct acpi_device_id *ids) { @@ -1001,11 +1053,8 @@ void __init acpi_early_init(void) acpi_permanent_mmap = true; - /* - * If the machine falls into the DMI check table, - * DSDT will be copied to memory - */ - dmi_check_system(dsdt_dmi_table); + /* Check machine-specific quirks */ + dmi_check_system(acpi_quirks_dmi_table); status = acpi_reallocate_root_table(); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index bf8e4d371fa7..e1eee7a60fad 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #define PREFIX "ACPI: " @@ -76,6 +77,22 @@ static const struct acpi_device_id button_device_ids[] = { }; MODULE_DEVICE_TABLE(acpi, button_device_ids); +/* + * Some devices which don't even have a lid in anyway have a broken _LID + * method (e.g. pointing to a floating gpio pin) causing spurious LID events. + */ +static const struct dmi_system_id lid_blacklst[] = { + { + /* GP-electronic T701 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "T701"), + DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"), + }, + }, + {} +}; + static int acpi_button_add(struct acpi_device *device); static int acpi_button_remove(struct acpi_device *device); static void acpi_button_notify(struct acpi_device *device, u32 event); @@ -210,6 +227,8 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state) } /* Send the platform triggered reliable event */ if (do_update) { + acpi_handle_debug(device->handle, "ACPI LID %s\n", + state ? "open" : "closed"); input_report_switch(button->input, SW_LID, !state); input_sync(button->input); button->last_state = !!state; @@ -473,6 +492,9 @@ static int acpi_button_add(struct acpi_device *device) char *name, *class; int error; + if (!strcmp(hid, ACPI_BUTTON_HID_LID) && dmi_check_system(lid_blacklst)) + return -ENODEV; + button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL); if (!button) return -ENOMEM; diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 06ea4749ebd9..0afbb2658cbc 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -119,7 +119,7 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr); * to PCC commands. Keeping it high enough to cover emulators where * the processors run painfully slow. */ -#define NUM_RETRIES 500 +#define NUM_RETRIES 500ULL struct cppc_attr { struct attribute attr; diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index a4c8ad98560d..c4d0a1c912f0 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -990,7 +990,7 @@ void acpi_subsys_complete(struct device *dev) * the sleep state it is going out of and it has never been resumed till * now, resume it in case the firmware powered it up. */ - if (dev->power.direct_complete && pm_resume_via_firmware()) + if (pm_runtime_suspended(dev) && pm_resume_via_firmware()) pm_request_resume(dev); } EXPORT_SYMBOL_GPL(acpi_subsys_complete); @@ -1039,10 +1039,28 @@ EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late); */ int acpi_subsys_suspend_noirq(struct device *dev) { - if (dev_pm_smart_suspend_and_suspended(dev)) - return 0; + int ret; - return pm_generic_suspend_noirq(dev); + if (dev_pm_smart_suspend_and_suspended(dev)) { + dev->power.may_skip_resume = true; + return 0; + } + + ret = pm_generic_suspend_noirq(dev); + if (ret) + return ret; + + /* + * If the target system sleep state is suspend-to-idle, it is sufficient + * to check whether or not the device's wakeup settings are good for + * runtime PM. Otherwise, the pm_resume_via_firmware() check will cause + * acpi_subsys_complete() to take care of fixing up the device's state + * anyway, if need be. + */ + dev->power.may_skip_resume = device_may_wakeup(dev) || + !device_can_wakeup(dev); + + return 0; } EXPORT_SYMBOL_GPL(acpi_subsys_suspend_noirq); @@ -1052,6 +1070,9 @@ EXPORT_SYMBOL_GPL(acpi_subsys_suspend_noirq); */ int acpi_subsys_resume_noirq(struct device *dev) { + if (dev_pm_may_skip_resume(dev)) + return 0; + /* * Devices with DPM_FLAG_SMART_SUSPEND may be left in runtime suspend * during system suspend, so update their runtime PM status to "active" diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c index a041689e5701..545e91420cde 100644 --- a/drivers/acpi/device_sysfs.c +++ b/drivers/acpi/device_sysfs.c @@ -357,7 +357,7 @@ static ssize_t real_power_state_show(struct device *dev, return sprintf(buf, "%s\n", acpi_power_state_string(state)); } -static DEVICE_ATTR(real_power_state, 0444, real_power_state_show, NULL); +static DEVICE_ATTR_RO(real_power_state); static ssize_t power_state_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -367,7 +367,7 @@ static ssize_t power_state_show(struct device *dev, return sprintf(buf, "%s\n", acpi_power_state_string(adev->power.state)); } -static DEVICE_ATTR(power_state, 0444, power_state_show, NULL); +static DEVICE_ATTR_RO(power_state); static ssize_t acpi_eject_store(struct device *d, struct device_attribute *attr, @@ -462,7 +462,7 @@ static ssize_t description_show(struct device *dev, return result; } -static DEVICE_ATTR(description, 0444, description_show, NULL); +static DEVICE_ATTR_RO(description); static ssize_t acpi_device_sun_show(struct device *dev, struct device_attribute *attr, diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 0252c9b9af3d..d9f38c645e4a 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1516,7 +1516,7 @@ static int acpi_ec_setup(struct acpi_ec *ec, bool handle_events) } acpi_handle_info(ec->handle, - "GPE=0x%lx, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", + "GPE=0x%x, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", ec->gpe, ec->command_addr, ec->data_addr); return ret; } diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c index 6c7dd7af789e..dd70d6c2bca0 100644 --- a/drivers/acpi/ec_sys.c +++ b/drivers/acpi/ec_sys.c @@ -128,7 +128,7 @@ static int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count) return -ENOMEM; } - if (!debugfs_create_x32("gpe", 0444, dev_dir, (u32 *)&first_ec->gpe)) + if (!debugfs_create_x32("gpe", 0444, dev_dir, &first_ec->gpe)) goto error; if (!debugfs_create_bool("use_global_lock", 0444, dev_dir, &first_ec->global_lock)) diff --git a/drivers/acpi/evged.c b/drivers/acpi/evged.c index 46f060356a22..f13ba2c07667 100644 --- a/drivers/acpi/evged.c +++ b/drivers/acpi/evged.c @@ -49,6 +49,11 @@ #define MODULE_NAME "acpi-ged" +struct acpi_ged_device { + struct device *dev; + struct list_head event_list; +}; + struct acpi_ged_event { struct list_head node; struct device *dev; @@ -76,7 +81,8 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares, unsigned int irq; unsigned int gsi; unsigned int irqflags = IRQF_ONESHOT; - struct device *dev = context; + struct acpi_ged_device *geddev = context; + struct device *dev = geddev->dev; acpi_handle handle = ACPI_HANDLE(dev); acpi_handle evt_handle; struct resource r; @@ -102,8 +108,6 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares, return AE_ERROR; } - dev_info(dev, "GED listening GSI %u @ IRQ %u\n", gsi, irq); - event = devm_kzalloc(dev, sizeof(*event), GFP_KERNEL); if (!event) return AE_ERROR; @@ -116,29 +120,58 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares, if (r.flags & IORESOURCE_IRQ_SHAREABLE) irqflags |= IRQF_SHARED; - if (devm_request_threaded_irq(dev, irq, NULL, acpi_ged_irq_handler, - irqflags, "ACPI:Ged", event)) { + if (request_threaded_irq(irq, NULL, acpi_ged_irq_handler, + irqflags, "ACPI:Ged", event)) { dev_err(dev, "failed to setup event handler for irq %u\n", irq); return AE_ERROR; } + dev_dbg(dev, "GED listening GSI %u @ IRQ %u\n", gsi, irq); + list_add_tail(&event->node, &geddev->event_list); return AE_OK; } static int ged_probe(struct platform_device *pdev) { + struct acpi_ged_device *geddev; acpi_status acpi_ret; + geddev = devm_kzalloc(&pdev->dev, sizeof(*geddev), GFP_KERNEL); + if (!geddev) + return -ENOMEM; + + geddev->dev = &pdev->dev; + INIT_LIST_HEAD(&geddev->event_list); acpi_ret = acpi_walk_resources(ACPI_HANDLE(&pdev->dev), "_CRS", - acpi_ged_request_interrupt, &pdev->dev); + acpi_ged_request_interrupt, geddev); if (ACPI_FAILURE(acpi_ret)) { dev_err(&pdev->dev, "unable to parse the _CRS record\n"); return -EINVAL; } + platform_set_drvdata(pdev, geddev); return 0; } +static void ged_shutdown(struct platform_device *pdev) +{ + struct acpi_ged_device *geddev = platform_get_drvdata(pdev); + struct acpi_ged_event *event, *next; + + list_for_each_entry_safe(event, next, &geddev->event_list, node) { + free_irq(event->irq, event); + list_del(&event->node); + dev_dbg(geddev->dev, "GED releasing GSI %u @ IRQ %u\n", + event->gsi, event->irq); + } +} + +static int ged_remove(struct platform_device *pdev) +{ + ged_shutdown(pdev); + return 0; +} + static const struct acpi_device_id ged_acpi_ids[] = { {"ACPI0013"}, {}, @@ -146,6 +179,8 @@ static const struct acpi_device_id ged_acpi_ids[] = { static struct platform_driver ged_driver = { .probe = ged_probe, + .remove = ged_remove, + .shutdown = ged_shutdown, .driver = { .name = MODULE_NAME, .acpi_match_table = ACPI_PTR(ged_acpi_ids), diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 7f43423de43c..1d0a501bc7f0 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -159,7 +159,7 @@ static inline void acpi_early_processor_osc(void) {} -------------------------------------------------------------------------- */ struct acpi_ec { acpi_handle handle; - unsigned long gpe; + u32 gpe; unsigned long command_addr; unsigned long data_addr; bool global_lock; diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index abeb4df4f22e..bbe48ad20886 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -838,6 +838,18 @@ static bool add_flush(struct acpi_nfit_desc *acpi_desc, return true; } +static bool add_platform_cap(struct acpi_nfit_desc *acpi_desc, + struct acpi_nfit_capabilities *pcap) +{ + struct device *dev = acpi_desc->dev; + u32 mask; + + mask = (1 << (pcap->highest_capability + 1)) - 1; + acpi_desc->platform_cap = pcap->capabilities & mask; + dev_dbg(dev, "%s: cap: %#x\n", __func__, acpi_desc->platform_cap); + return true; +} + static void *add_table(struct acpi_nfit_desc *acpi_desc, struct nfit_table_prev *prev, void *table, const void *end) { @@ -883,6 +895,10 @@ static void *add_table(struct acpi_nfit_desc *acpi_desc, case ACPI_NFIT_TYPE_SMBIOS: dev_dbg(dev, "%s: smbios\n", __func__); break; + case ACPI_NFIT_TYPE_CAPABILITIES: + if (!add_platform_cap(acpi_desc, table)) + return err; + break; default: dev_err(dev, "unknown table '%d' parsing nfit\n", hdr->type); break; @@ -1867,6 +1883,9 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) struct kernfs_node *nfit_kernfs; nvdimm = nfit_mem->nvdimm; + if (!nvdimm) + continue; + nfit_kernfs = sysfs_get_dirent(nvdimm_kobj(nvdimm)->sd, "nfit"); if (nfit_kernfs) nfit_mem->flags_attr = sysfs_get_dirent(nfit_kernfs, @@ -2656,6 +2675,12 @@ static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc, else ndr_desc->numa_node = NUMA_NO_NODE; + if(acpi_desc->platform_cap & ACPI_NFIT_CAPABILITY_CACHE_FLUSH) + set_bit(ND_REGION_PERSIST_CACHE, &ndr_desc->flags); + + if (acpi_desc->platform_cap & ACPI_NFIT_CAPABILITY_MEM_FLUSH) + set_bit(ND_REGION_PERSIST_MEMCTRL, &ndr_desc->flags); + list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) { struct acpi_nfit_memory_map *memdev = nfit_memdev->memdev; struct nd_mapping_desc *mapping; @@ -3464,6 +3489,7 @@ static __init int nfit_init(void) BUILD_BUG_ON(sizeof(struct acpi_nfit_smbios) != 9); BUILD_BUG_ON(sizeof(struct acpi_nfit_control_region) != 80); BUILD_BUG_ON(sizeof(struct acpi_nfit_data_region) != 40); + BUILD_BUG_ON(sizeof(struct acpi_nfit_capabilities) != 16); guid_parse(UUID_VOLATILE_MEMORY, &nfit_uuid[NFIT_SPA_VOLATILE]); guid_parse(UUID_PERSISTENT_MEMORY, &nfit_uuid[NFIT_SPA_PM]); diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index f0cf18b2da8b..50d36e166d70 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h @@ -202,6 +202,7 @@ struct acpi_nfit_desc { unsigned long dimm_cmd_force_en; unsigned long bus_cmd_force_en; unsigned long bus_nfit_cmd_force_en; + unsigned int platform_cap; int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa, void *iobuf, u64 len, int rw); }; diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 917f1cc0fda4..8ccaae3550d2 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -460,8 +460,7 @@ int __init acpi_numa_init(void) srat_proc, ARRAY_SIZE(srat_proc), 0); cnt = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, - acpi_parse_memory_affinity, - NR_NODE_MEMBLKS); + acpi_parse_memory_affinity, 0); } /* SLIT: System Locality Information Table */ diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index bc3d914dfc3e..85ad679390e3 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -612,7 +612,7 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link) acpi_isa_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING; - printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d\n", + pr_info("%s [%s] enabled at IRQ %d\n", acpi_device_name(link->device), acpi_device_bid(link->device), link->irq.active); } diff --git a/drivers/acpi/pmic/intel_pmic_bxtwc.c b/drivers/acpi/pmic/intel_pmic_bxtwc.c index 90011aad4d20..886ac8b93cd0 100644 --- a/drivers/acpi/pmic/intel_pmic_bxtwc.c +++ b/drivers/acpi/pmic/intel_pmic_bxtwc.c @@ -400,7 +400,7 @@ static int intel_bxtwc_pmic_opregion_probe(struct platform_device *pdev) &intel_bxtwc_pmic_opregion_data); } -static struct platform_device_id bxt_wc_opregion_id_table[] = { +static const struct platform_device_id bxt_wc_opregion_id_table[] = { { .name = "bxt_wcove_region" }, {}, }; @@ -412,9 +412,4 @@ static struct platform_driver intel_bxtwc_pmic_opregion_driver = { }, .id_table = bxt_wc_opregion_id_table, }; - -static int __init intel_bxtwc_pmic_opregion_driver_init(void) -{ - return platform_driver_register(&intel_bxtwc_pmic_opregion_driver); -} -device_initcall(intel_bxtwc_pmic_opregion_driver_init); +builtin_platform_driver(intel_bxtwc_pmic_opregion_driver); diff --git a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c index 109c1e9c9c7a..f6d73a243d80 100644 --- a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c +++ b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c @@ -131,7 +131,4 @@ static struct platform_driver chtdc_ti_pmic_opregion_driver = { }, .id_table = chtdc_ti_pmic_opregion_id_table, }; -module_platform_driver(chtdc_ti_pmic_opregion_driver); - -MODULE_DESCRIPTION("Dollar Cove TI PMIC opregion driver"); -MODULE_LICENSE("GPL v2"); +builtin_platform_driver(chtdc_ti_pmic_opregion_driver); diff --git a/drivers/acpi/pmic/intel_pmic_chtwc.c b/drivers/acpi/pmic/intel_pmic_chtwc.c index 85636d7a9d39..9912422c8185 100644 --- a/drivers/acpi/pmic/intel_pmic_chtwc.c +++ b/drivers/acpi/pmic/intel_pmic_chtwc.c @@ -260,11 +260,10 @@ static int intel_cht_wc_pmic_opregion_probe(struct platform_device *pdev) &intel_cht_wc_pmic_opregion_data); } -static struct platform_device_id cht_wc_opregion_id_table[] = { +static const struct platform_device_id cht_wc_opregion_id_table[] = { { .name = "cht_wcove_region" }, {}, }; -MODULE_DEVICE_TABLE(platform, cht_wc_opregion_id_table); static struct platform_driver intel_cht_wc_pmic_opregion_driver = { .probe = intel_cht_wc_pmic_opregion_probe, @@ -273,8 +272,4 @@ static struct platform_driver intel_cht_wc_pmic_opregion_driver = { }, .id_table = cht_wc_opregion_id_table, }; -module_platform_driver(intel_cht_wc_pmic_opregion_driver); - -MODULE_DESCRIPTION("Intel CHT Whiskey Cove PMIC operation region driver"); -MODULE_AUTHOR("Hans de Goede "); -MODULE_LICENSE("GPL"); +builtin_platform_driver(intel_cht_wc_pmic_opregion_driver); diff --git a/drivers/acpi/pmic/intel_pmic_crc.c b/drivers/acpi/pmic/intel_pmic_crc.c index d7f1761ab1bc..7ffa74048107 100644 --- a/drivers/acpi/pmic/intel_pmic_crc.c +++ b/drivers/acpi/pmic/intel_pmic_crc.c @@ -201,9 +201,4 @@ static struct platform_driver intel_crc_pmic_opregion_driver = { .name = "crystal_cove_pmic", }, }; - -static int __init intel_crc_pmic_opregion_driver_init(void) -{ - return platform_driver_register(&intel_crc_pmic_opregion_driver); -} -device_initcall(intel_crc_pmic_opregion_driver_init); +builtin_platform_driver(intel_crc_pmic_opregion_driver); diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c index 6c99d3f81095..316e55174aa9 100644 --- a/drivers/acpi/pmic/intel_pmic_xpower.c +++ b/drivers/acpi/pmic/intel_pmic_xpower.c @@ -278,9 +278,4 @@ static struct platform_driver intel_xpower_pmic_opregion_driver = { .name = "axp288_pmic_acpi", }, }; - -static int __init intel_xpower_pmic_opregion_driver_init(void) -{ - return platform_driver_register(&intel_xpower_pmic_opregion_driver); -} -device_initcall(intel_xpower_pmic_opregion_driver_init); +builtin_platform_driver(intel_xpower_pmic_opregion_driver); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index d50a7b6ccddd..abb559cd28d7 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -207,6 +207,7 @@ static void tsc_check_state(int state) switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: case X86_VENDOR_INTEL: + case X86_VENDOR_CENTAUR: /* * AMD Fam10h TSC will tick in all * C/P/S0/S1 states when this bit is set. @@ -291,6 +292,9 @@ static int acpi_processor_get_power_info_default(struct acpi_processor *pr) pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1; pr->power.states[ACPI_STATE_C1].valid = 1; pr->power.states[ACPI_STATE_C1].entry_method = ACPI_CSTATE_HALT; + + snprintf(pr->power.states[ACPI_STATE_C1].desc, + ACPI_CX_DESC_LEN, "ACPI HLT"); } /* the C0 state only exists as a filler in our array */ pr->power.states[ACPI_STATE_C0].valid = 1; diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 18b72eec3507..c7cf48ad5cb9 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -159,7 +159,7 @@ void acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag) { int ret; - if (ignore_ppc) { + if (ignore_ppc || !pr->performance) { /* * Only when it is notification event, the _OST object * will be evaluated. Otherwise it is skipped. diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index e26ea209b63e..466d1503aba0 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -1271,9 +1271,17 @@ static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, return 0; } +static void * +acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode, + const struct device *dev) +{ + return acpi_get_match_data(dev); +} + #define DECLARE_ACPI_FWNODE_OPS(ops) \ const struct fwnode_operations ops = { \ .device_is_available = acpi_fwnode_device_is_available, \ + .device_get_match_data = acpi_fwnode_device_get_match_data, \ .property_present = acpi_fwnode_property_present, \ .property_read_int_array = \ acpi_fwnode_property_read_int_array, \ diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index 2fa8304171e0..7a3431018e0a 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -275,8 +275,8 @@ static int acpi_smbus_hc_add(struct acpi_device *device) device->driver_data = hc; acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc); - printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n", - hc->ec, hc->offset, hc->query_bit); + dev_info(&device->dev, "SBS HC: offset = 0x%0x, query_bit = 0x%0x\n", + hc->offset, hc->query_bit); return 0; } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index b0fe5272c76a..8e63d937babb 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1565,6 +1565,8 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, device_initialize(&device->dev); dev_set_uevent_suppress(&device->dev, true); acpi_init_coherency(device); + /* Assume there are unmet deps until acpi_device_dep_initialize() runs */ + device->dep_unmet = 1; } void acpi_device_add_finalize(struct acpi_device *device) @@ -1588,6 +1590,14 @@ static int acpi_add_single_object(struct acpi_device **child, } acpi_init_device_object(device, handle, type, sta); + /* + * For ACPI_BUS_TYPE_DEVICE getting the status is delayed till here so + * that we can call acpi_bus_get_status() and use its quirk handling. + * Note this must be done before the get power-/wakeup_dev-flags calls. + */ + if (type == ACPI_BUS_TYPE_DEVICE) + acpi_bus_get_status(device); + acpi_bus_get_power_flags(device); acpi_bus_get_wakeup_device_flags(device); @@ -1660,9 +1670,11 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type, return -ENODEV; *type = ACPI_BUS_TYPE_DEVICE; - status = acpi_bus_get_status_handle(handle, sta); - if (ACPI_FAILURE(status)) - *sta = 0; + /* + * acpi_add_single_object updates this once we've an acpi_device + * so that acpi_bus_get_status' quirk handling can be used. + */ + *sta = 0; break; case ACPI_TYPE_PROCESSOR: *type = ACPI_BUS_TYPE_PROCESSOR; @@ -1760,6 +1772,8 @@ static void acpi_device_dep_initialize(struct acpi_device *adev) acpi_status status; int i; + adev->dep_unmet = 0; + if (!acpi_has_method(adev->handle, "_DEP")) return; diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 8082871b409a..46cde0912762 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -367,10 +367,20 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = { {}, }; +static bool ignore_blacklist; + +void __init acpi_sleep_no_blacklist(void) +{ + ignore_blacklist = true; +} + static void __init acpi_sleep_dmi_check(void) { int year; + if (ignore_blacklist) + return; + if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year >= 2012) acpi_nvs_nosave_s3(); @@ -697,7 +707,8 @@ static const struct acpi_device_id lps0_device_ids[] = { #define ACPI_LPS0_ENTRY 5 #define ACPI_LPS0_EXIT 6 -#define ACPI_S2IDLE_FUNC_MASK ((1 << ACPI_LPS0_ENTRY) | (1 << ACPI_LPS0_EXIT)) +#define ACPI_LPS0_SCREEN_MASK ((1 << ACPI_LPS0_SCREEN_OFF) | (1 << ACPI_LPS0_SCREEN_ON)) +#define ACPI_LPS0_PLATFORM_MASK ((1 << ACPI_LPS0_ENTRY) | (1 << ACPI_LPS0_EXIT)) static acpi_handle lps0_device_handle; static guid_t lps0_dsm_guid; @@ -900,7 +911,8 @@ static int lps0_device_attach(struct acpi_device *adev, if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) { char bitmask = *(char *)out_obj->buffer.pointer; - if ((bitmask & ACPI_S2IDLE_FUNC_MASK) == ACPI_S2IDLE_FUNC_MASK) { + if ((bitmask & ACPI_LPS0_PLATFORM_MASK) == ACPI_LPS0_PLATFORM_MASK || + (bitmask & ACPI_LPS0_SCREEN_MASK) == ACPI_LPS0_SCREEN_MASK) { lps0_dsm_func_mask = bitmask; lps0_device_handle = adev->handle; /* diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c index 324b35bfe781..89e97d21a89c 100644 --- a/drivers/acpi/spcr.c +++ b/drivers/acpi/spcr.c @@ -21,7 +21,7 @@ * occasionally getting stuck as 1. To avoid the potential for a hang, check * TXFE == 0 instead of BUSY == 1. This may not be suitable for all UART * implementations, so only do so if an affected platform is detected in - * parse_spcr(). + * acpi_parse_spcr(). */ bool qdf2400_e44_present; EXPORT_SYMBOL(qdf2400_e44_present); @@ -74,19 +74,21 @@ static bool xgene_8250_erratum_present(struct acpi_table_spcr *tb) } /** - * parse_spcr() - parse ACPI SPCR table and add preferred console + * acpi_parse_spcr() - parse ACPI SPCR table and add preferred console * - * @earlycon: set up earlycon for the console specified by the table + * @enable_earlycon: set up earlycon for the console specified by the table + * @enable_console: setup the console specified by the table. * * For the architectures with support for ACPI, CONFIG_ACPI_SPCR_TABLE may be * defined to parse ACPI SPCR table. As a result of the parsing preferred - * console is registered and if @earlycon is true, earlycon is set up. + * console is registered and if @enable_earlycon is true, earlycon is set up. + * If @enable_console is true the system console is also configured. * * When CONFIG_ACPI_SPCR_TABLE is defined, this function should be called * from arch initialization code as soon as the DT/ACPI decision is made. * */ -int __init parse_spcr(bool earlycon) +int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console) { static char opts[64]; struct acpi_table_spcr *table; @@ -105,11 +107,8 @@ int __init parse_spcr(bool earlycon) if (ACPI_FAILURE(status)) return -ENOENT; - if (table->header.revision < 2) { - err = -ENOENT; - pr_err("wrong table version\n"); - goto done; - } + if (table->header.revision < 2) + pr_info("SPCR table version %d\n", table->header.revision); if (table->serial_port.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { switch (ACPI_ACCESS_BIT_WIDTH(( @@ -185,7 +184,7 @@ int __init parse_spcr(bool earlycon) */ if (qdf2400_erratum_44_present(&table->header)) { qdf2400_e44_present = true; - if (earlycon) + if (enable_earlycon) uart = "qdf2400_e44"; } @@ -205,11 +204,13 @@ int __init parse_spcr(bool earlycon) pr_info("console: %s\n", opts); - if (earlycon) + if (enable_earlycon) setup_earlycon(opts); - err = add_preferred_console(uart, 0, opts + strlen(uart) + 1); - + if (enable_console) + err = add_preferred_console(uart, 0, opts + strlen(uart) + 1); + else + err = 0; done: acpi_put_table((struct acpi_table_header *)table); return err; diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 06a150bb35bf..4fc59c3bc673 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -816,14 +816,8 @@ end: * interface: * echo unmask > /sys/firmware/acpi/interrupts/gpe00 */ - -/* - * Currently, the GPE flooding prevention only supports to mask the GPEs - * numbered from 00 to 7f. - */ -#define ACPI_MASKABLE_GPE_MAX 0x80 - -static u64 __initdata acpi_masked_gpes; +#define ACPI_MASKABLE_GPE_MAX 0xFF +static DECLARE_BITMAP(acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX) __initdata; static int __init acpi_gpe_set_masked_gpes(char *val) { @@ -831,7 +825,7 @@ static int __init acpi_gpe_set_masked_gpes(char *val) if (kstrtou8(val, 0, &gpe) || gpe > ACPI_MASKABLE_GPE_MAX) return -EINVAL; - acpi_masked_gpes |= ((u64)1<pnp.unique_id, match->uid))) return 0; + match->dev_name = acpi_dev_name(adev); + if (match->hrv == -1) return 1; @@ -789,20 +792,44 @@ static int acpi_dev_present_cb(struct device *dev, void *data) */ bool acpi_dev_present(const char *hid, const char *uid, s64 hrv) { - struct acpi_dev_present_info match = {}; + struct acpi_dev_match_info match = {}; struct device *dev; strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id)); match.uid = uid; match.hrv = hrv; - dev = bus_find_device(&acpi_bus_type, NULL, &match, - acpi_dev_present_cb); - + dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb); return !!dev; } EXPORT_SYMBOL(acpi_dev_present); +/** + * acpi_dev_get_first_match_name - Return name of first match of ACPI device + * @hid: Hardware ID of the device. + * @uid: Unique ID of the device, pass NULL to not check _UID + * @hrv: Hardware Revision of the device, pass -1 to not check _HRV + * + * Return device name if a matching device was present + * at the moment of invocation, or NULL otherwise. + * + * See additional information in acpi_dev_present() as well. + */ +const char * +acpi_dev_get_first_match_name(const char *hid, const char *uid, s64 hrv) +{ + struct acpi_dev_match_info match = {}; + struct device *dev; + + strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id)); + match.uid = uid; + match.hrv = hrv; + + dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb); + return dev ? match.dev_name : NULL; +} +EXPORT_SYMBOL(acpi_dev_get_first_match_name); + /* * acpi_backlight= handling, this is done here rather then in video_detect.c * because __setup cannot be used in modules. diff --git a/drivers/android/binder.c b/drivers/android/binder.c index a7ecfde66b7b..15e3d3c2260d 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -141,7 +141,7 @@ enum { }; static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR | BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION; -module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO); +module_param_named(debug_mask, binder_debug_mask, uint, 0644); static char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES; module_param_named(devices, binder_devices_param, charp, 0444); @@ -160,7 +160,7 @@ static int binder_set_stop_on_user_error(const char *val, return ret; } module_param_call(stop_on_user_error, binder_set_stop_on_user_error, - param_get_int, &binder_stop_on_user_error, S_IWUSR | S_IRUGO); + param_get_int, &binder_stop_on_user_error, 0644); #define binder_debug(mask, x...) \ do { \ @@ -249,7 +249,7 @@ static struct binder_transaction_log_entry *binder_transaction_log_add( unsigned int cur = atomic_inc_return(&log->cur); if (cur >= ARRAY_SIZE(log->entry)) - log->full = 1; + log->full = true; e = &log->entry[cur % ARRAY_SIZE(log->entry)]; WRITE_ONCE(e->debug_id_done, 0); /* @@ -493,8 +493,6 @@ enum binder_deferred_state { * (protected by @inner_lock) * @todo: list of work for this process * (protected by @inner_lock) - * @wait: wait queue head to wait for proc work - * (invariant after initialized) * @stats: per-process binder statistics * (atomics, no lock needed) * @delivered_death: list of delivered death notification @@ -537,7 +535,6 @@ struct binder_proc { bool is_dead; struct list_head todo; - wait_queue_head_t wait; struct binder_stats stats; struct list_head delivered_death; int max_threads; @@ -579,6 +576,8 @@ enum { * (protected by @proc->inner_lock) * @todo: list of work to do for this thread * (protected by @proc->inner_lock) + * @process_todo: whether work in @todo should be processed + * (protected by @proc->inner_lock) * @return_error: transaction errors reported by this thread * (only accessed by this thread) * @reply_error: transaction errors reported by target thread @@ -604,6 +603,7 @@ struct binder_thread { bool looper_need_return; /* can be written by other thread */ struct binder_transaction *transaction_stack; struct list_head todo; + bool process_todo; struct binder_error return_error; struct binder_error reply_error; wait_queue_head_t wait; @@ -789,6 +789,16 @@ static bool binder_worklist_empty(struct binder_proc *proc, return ret; } +/** + * binder_enqueue_work_ilocked() - Add an item to the work list + * @work: struct binder_work to add to list + * @target_list: list to add work to + * + * Adds the work to the specified list. Asserts that work + * is not already on a list. + * + * Requires the proc->inner_lock to be held. + */ static void binder_enqueue_work_ilocked(struct binder_work *work, struct list_head *target_list) @@ -799,22 +809,56 @@ binder_enqueue_work_ilocked(struct binder_work *work, } /** - * binder_enqueue_work() - Add an item to the work list - * @proc: binder_proc associated with list + * binder_enqueue_deferred_thread_work_ilocked() - Add deferred thread work + * @thread: thread to queue work to * @work: struct binder_work to add to list - * @target_list: list to add work to * - * Adds the work to the specified list. Asserts that work - * is not already on a list. + * Adds the work to the todo list of the thread. Doesn't set the process_todo + * flag, which means that (if it wasn't already set) the thread will go to + * sleep without handling this work when it calls read. + * + * Requires the proc->inner_lock to be held. */ static void -binder_enqueue_work(struct binder_proc *proc, - struct binder_work *work, - struct list_head *target_list) +binder_enqueue_deferred_thread_work_ilocked(struct binder_thread *thread, + struct binder_work *work) { - binder_inner_proc_lock(proc); - binder_enqueue_work_ilocked(work, target_list); - binder_inner_proc_unlock(proc); + binder_enqueue_work_ilocked(work, &thread->todo); +} + +/** + * binder_enqueue_thread_work_ilocked() - Add an item to the thread work list + * @thread: thread to queue work to + * @work: struct binder_work to add to list + * + * Adds the work to the todo list of the thread, and enables processing + * of the todo queue. + * + * Requires the proc->inner_lock to be held. + */ +static void +binder_enqueue_thread_work_ilocked(struct binder_thread *thread, + struct binder_work *work) +{ + binder_enqueue_work_ilocked(work, &thread->todo); + thread->process_todo = true; +} + +/** + * binder_enqueue_thread_work() - Add an item to the thread work list + * @thread: thread to queue work to + * @work: struct binder_work to add to list + * + * Adds the work to the todo list of the thread, and enables processing + * of the todo queue. + */ +static void +binder_enqueue_thread_work(struct binder_thread *thread, + struct binder_work *work) +{ + binder_inner_proc_lock(thread->proc); + binder_enqueue_thread_work_ilocked(thread, work); + binder_inner_proc_unlock(thread->proc); } static void @@ -940,7 +984,7 @@ err: static bool binder_has_work_ilocked(struct binder_thread *thread, bool do_proc_work) { - return !binder_worklist_empty_ilocked(&thread->todo) || + return thread->process_todo || thread->looper_need_return || (do_proc_work && !binder_worklist_empty_ilocked(&thread->proc->todo)); @@ -1228,6 +1272,17 @@ static int binder_inc_node_nilocked(struct binder_node *node, int strong, node->local_strong_refs++; if (!node->has_strong_ref && target_list) { binder_dequeue_work_ilocked(&node->work); + /* + * Note: this function is the only place where we queue + * directly to a thread->todo without using the + * corresponding binder_enqueue_thread_work() helper + * functions; in this case it's ok to not set the + * process_todo flag, since we know this node work will + * always be followed by other work that starts queue + * processing: in case of synchronous transactions, a + * BR_REPLY or BR_ERROR; in case of oneway + * transactions, a BR_TRANSACTION_COMPLETE. + */ binder_enqueue_work_ilocked(&node->work, target_list); } } else { @@ -1239,6 +1294,9 @@ static int binder_inc_node_nilocked(struct binder_node *node, int strong, node->debug_id); return -EINVAL; } + /* + * See comment above + */ binder_enqueue_work_ilocked(&node->work, target_list); } } @@ -1928,9 +1986,9 @@ static void binder_send_failed_reply(struct binder_transaction *t, binder_pop_transaction_ilocked(target_thread, t); if (target_thread->reply_error.cmd == BR_OK) { target_thread->reply_error.cmd = error_code; - binder_enqueue_work_ilocked( - &target_thread->reply_error.work, - &target_thread->todo); + binder_enqueue_thread_work_ilocked( + target_thread, + &target_thread->reply_error.work); wake_up_interruptible(&target_thread->wait); } else { WARN(1, "Unexpected reply error: %u\n", @@ -2569,20 +2627,18 @@ static bool binder_proc_transaction(struct binder_transaction *t, struct binder_proc *proc, struct binder_thread *thread) { - struct list_head *target_list = NULL; struct binder_node *node = t->buffer->target_node; bool oneway = !!(t->flags & TF_ONE_WAY); - bool wakeup = true; + bool pending_async = false; BUG_ON(!node); binder_node_lock(node); if (oneway) { BUG_ON(thread); if (node->has_async_transaction) { - target_list = &node->async_todo; - wakeup = false; + pending_async = true; } else { - node->has_async_transaction = 1; + node->has_async_transaction = true; } } @@ -2594,19 +2650,17 @@ static bool binder_proc_transaction(struct binder_transaction *t, return false; } - if (!thread && !target_list) + if (!thread && !pending_async) thread = binder_select_thread_ilocked(proc); if (thread) - target_list = &thread->todo; - else if (!target_list) - target_list = &proc->todo; + binder_enqueue_thread_work_ilocked(thread, &t->work); + else if (!pending_async) + binder_enqueue_work_ilocked(&t->work, &proc->todo); else - BUG_ON(target_list != &node->async_todo); + binder_enqueue_work_ilocked(&t->work, &node->async_todo); - binder_enqueue_work_ilocked(&t->work, target_list); - - if (wakeup) + if (!pending_async) binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */); binder_inner_proc_unlock(proc); @@ -3101,10 +3155,10 @@ static void binder_transaction(struct binder_proc *proc, } } tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; - binder_enqueue_work(proc, tcomplete, &thread->todo); t->work.type = BINDER_WORK_TRANSACTION; if (reply) { + binder_enqueue_thread_work(thread, tcomplete); binder_inner_proc_lock(target_proc); if (target_thread->is_dead) { binder_inner_proc_unlock(target_proc); @@ -3112,13 +3166,21 @@ static void binder_transaction(struct binder_proc *proc, } BUG_ON(t->buffer->async_transaction != 0); binder_pop_transaction_ilocked(target_thread, in_reply_to); - binder_enqueue_work_ilocked(&t->work, &target_thread->todo); + binder_enqueue_thread_work_ilocked(target_thread, &t->work); binder_inner_proc_unlock(target_proc); wake_up_interruptible_sync(&target_thread->wait); binder_free_transaction(in_reply_to); } else if (!(t->flags & TF_ONE_WAY)) { BUG_ON(t->buffer->async_transaction != 0); binder_inner_proc_lock(proc); + /* + * Defer the TRANSACTION_COMPLETE, so we don't return to + * userspace immediately; this allows the target process to + * immediately start processing this transaction, reducing + * latency. We will then return the TRANSACTION_COMPLETE when + * the target replies (or there is an error). + */ + binder_enqueue_deferred_thread_work_ilocked(thread, tcomplete); t->need_reply = 1; t->from_parent = thread->transaction_stack; thread->transaction_stack = t; @@ -3132,6 +3194,7 @@ static void binder_transaction(struct binder_proc *proc, } else { BUG_ON(target_node == NULL); BUG_ON(t->buffer->async_transaction != 1); + binder_enqueue_thread_work(thread, tcomplete); if (!binder_proc_transaction(t, target_proc, NULL)) goto err_dead_proc_or_thread; } @@ -3210,15 +3273,11 @@ err_invalid_target_handle: BUG_ON(thread->return_error.cmd != BR_OK); if (in_reply_to) { thread->return_error.cmd = BR_TRANSACTION_COMPLETE; - binder_enqueue_work(thread->proc, - &thread->return_error.work, - &thread->todo); + binder_enqueue_thread_work(thread, &thread->return_error.work); binder_send_failed_reply(in_reply_to, return_error); } else { thread->return_error.cmd = return_error; - binder_enqueue_work(thread->proc, - &thread->return_error.work, - &thread->todo); + binder_enqueue_thread_work(thread, &thread->return_error.work); } } @@ -3424,7 +3483,7 @@ static int binder_thread_write(struct binder_proc *proc, w = binder_dequeue_work_head_ilocked( &buf_node->async_todo); if (!w) { - buf_node->has_async_transaction = 0; + buf_node->has_async_transaction = false; } else { binder_enqueue_work_ilocked( w, &proc->todo); @@ -3522,10 +3581,9 @@ static int binder_thread_write(struct binder_proc *proc, WARN_ON(thread->return_error.cmd != BR_OK); thread->return_error.cmd = BR_ERROR; - binder_enqueue_work( - thread->proc, - &thread->return_error.work, - &thread->todo); + binder_enqueue_thread_work( + thread, + &thread->return_error.work); binder_debug( BINDER_DEBUG_FAILED_TRANSACTION, "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n", @@ -3605,9 +3663,9 @@ static int binder_thread_write(struct binder_proc *proc, if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) - binder_enqueue_work_ilocked( - &death->work, - &thread->todo); + binder_enqueue_thread_work_ilocked( + thread, + &death->work); else { binder_enqueue_work_ilocked( &death->work, @@ -3662,8 +3720,8 @@ static int binder_thread_write(struct binder_proc *proc, if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) - binder_enqueue_work_ilocked( - &death->work, &thread->todo); + binder_enqueue_thread_work_ilocked( + thread, &death->work); else { binder_enqueue_work_ilocked( &death->work, @@ -3837,6 +3895,8 @@ retry: break; } w = binder_dequeue_work_head_ilocked(list); + if (binder_worklist_empty_ilocked(&thread->todo)) + thread->process_todo = false; switch (w->type) { case BINDER_WORK_TRANSACTION: { @@ -4302,6 +4362,18 @@ static int binder_thread_release(struct binder_proc *proc, if (t) spin_lock(&t->lock); } + + /* + * If this thread used poll, make sure we remove the waitqueue + * from any epoll data structures holding it with POLLFREE. + * waitqueue_active() is safe to use here because we're holding + * the inner lock. + */ + if ((thread->looper & BINDER_LOOPER_STATE_POLL) && + waitqueue_active(&thread->wait)) { + wake_up_poll(&thread->wait, EPOLLHUP | POLLFREE); + } + binder_inner_proc_unlock(thread->proc); if (send_reply) @@ -4311,7 +4383,7 @@ static int binder_thread_release(struct binder_proc *proc, return active_transactions; } -static unsigned int binder_poll(struct file *filp, +static __poll_t binder_poll(struct file *filp, struct poll_table_struct *wait) { struct binder_proc *proc = filp->private_data; @@ -4329,7 +4401,7 @@ static unsigned int binder_poll(struct file *filp, poll_wait(filp, &thread->wait, wait); if (binder_has_work(thread, wait_for_proc_work)) - return POLLIN; + return EPOLLIN; return 0; } @@ -4646,7 +4718,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) return 0; err_bad_arg: - pr_err("binder_mmap: %d %lx-%lx %s failed %d\n", + pr_err("%s: %d %lx-%lx %s failed %d\n", __func__, proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); return ret; } @@ -4656,7 +4728,7 @@ static int binder_open(struct inode *nodp, struct file *filp) struct binder_proc *proc; struct binder_device *binder_dev; - binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n", + binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d:%d\n", __func__, current->group_leader->pid, current->pid); proc = kzalloc(sizeof(*proc), GFP_KERNEL); @@ -4695,7 +4767,7 @@ static int binder_open(struct inode *nodp, struct file *filp) * anyway print all contexts that a given PID has, so this * is not a problem. */ - proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO, + proc->debugfs_entry = debugfs_create_file(strbuf, 0444, binder_debugfs_dir_entry_proc, (void *)(unsigned long)proc->pid, &binder_proc_fops); @@ -5524,7 +5596,9 @@ static int __init binder_init(void) struct binder_device *device; struct hlist_node *tmp; - binder_alloc_shrinker_init(); + ret = binder_alloc_shrinker_init(); + if (ret) + return ret; atomic_set(&binder_transaction_log.cur, ~0U); atomic_set(&binder_transaction_log_failed.cur, ~0U); @@ -5536,27 +5610,27 @@ static int __init binder_init(void) if (binder_debugfs_dir_entry_root) { debugfs_create_file("state", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, NULL, &binder_state_fops); debugfs_create_file("stats", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, NULL, &binder_stats_fops); debugfs_create_file("transactions", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, NULL, &binder_transactions_fops); debugfs_create_file("transaction_log", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, &binder_transaction_log, &binder_transaction_log_fops); debugfs_create_file("failed_transaction_log", - S_IRUGO, + 0444, binder_debugfs_dir_entry_root, &binder_transaction_log_failed, &binder_transaction_log_fops); diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 6f6f745605af..5a426c877dfb 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -281,6 +281,9 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, goto err_vm_insert_page_failed; } + if (index + 1 > alloc->pages_high) + alloc->pages_high = index + 1; + trace_binder_alloc_page_end(alloc, index); /* vm_insert_page does not seem to increment the refcount */ } @@ -324,11 +327,12 @@ err_no_vma: return vma ? -ENOMEM : -ESRCH; } -struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc, - size_t data_size, - size_t offsets_size, - size_t extra_buffers_size, - int is_async) +static struct binder_buffer *binder_alloc_new_buf_locked( + struct binder_alloc *alloc, + size_t data_size, + size_t offsets_size, + size_t extra_buffers_size, + int is_async) { struct rb_node *n = alloc->free_buffers.rb_node; struct binder_buffer *buffer; @@ -666,7 +670,7 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc, goto err_already_mapped; } - area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP); + area = get_vm_area(vma->vm_end - vma->vm_start, VM_ALLOC); if (area == NULL) { ret = -ENOMEM; failure_string = "get_vm_area"; @@ -853,6 +857,7 @@ void binder_alloc_print_pages(struct seq_file *m, } mutex_unlock(&alloc->mutex); seq_printf(m, " pages: %d:%d:%d\n", active, lru, free); + seq_printf(m, " pages high watermark: %zu\n", alloc->pages_high); } /** @@ -1002,8 +1007,14 @@ void binder_alloc_init(struct binder_alloc *alloc) INIT_LIST_HEAD(&alloc->buffers); } -void binder_alloc_shrinker_init(void) +int binder_alloc_shrinker_init(void) { - list_lru_init(&binder_alloc_lru); - register_shrinker(&binder_shrinker); + int ret = list_lru_init(&binder_alloc_lru); + + if (ret == 0) { + ret = register_shrinker(&binder_shrinker); + if (ret) + list_lru_destroy(&binder_alloc_lru); + } + return ret; } diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index 2dd33b6df104..9ef64e563856 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -92,6 +92,7 @@ struct binder_lru_page { * @pages: array of binder_lru_page * @buffer_size: size of address space specified via mmap * @pid: pid for associated binder_proc (invariant after init) + * @pages_high: high watermark of offset in @pages * * Bookkeeping structure for per-proc address space management for binder * buffers. It is normally initialized during binder_init() and binder_mmap() @@ -112,6 +113,7 @@ struct binder_alloc { size_t buffer_size; uint32_t buffer_free; int pid; + size_t pages_high; }; #ifdef CONFIG_ANDROID_BINDER_IPC_SELFTEST @@ -128,7 +130,7 @@ extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, size_t extra_buffers_size, int is_async); extern void binder_alloc_init(struct binder_alloc *alloc); -void binder_alloc_shrinker_init(void); +extern int binder_alloc_shrinker_init(void); extern void binder_alloc_vma_close(struct binder_alloc *alloc); extern struct binder_buffer * binder_alloc_prepare_to_free(struct binder_alloc *alloc, diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index cb5339166563..a7120d621154 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -92,6 +92,25 @@ config SATA_AHCI If unsure, say N. +config SATA_MOBILE_LPM_POLICY + int "Default SATA Link Power Management policy for mobile chipsets" + range 0 4 + default 0 + depends on SATA_AHCI + help + Select the Default SATA Link Power Management (LPM) policy to use + for mobile / laptop variants of chipsets / "South Bridges". + + The value set has the following meanings: + 0 => Keep firmware settings + 1 => Maximum performance + 2 => Medium power + 3 => Medium power with Device Initiated PM enabled + 4 => Minimum power + + Note "Minimum power" is known to cause issues, including disk + corruption, with some disks and should not be used. + config SATA_AHCI_PLATFORM tristate "Platform AHCI SATA support" help @@ -925,15 +944,6 @@ endif # ATA_BMDMA comment "PIO-only SFF controllers" -config PATA_AT32 - tristate "Atmel AVR32 PATA support (Experimental)" - depends on AVR32 && PLATFORM_AT32AP - help - This option enables support for the IDE devices on the - Atmel AT32AP platform. - - If unsure, say N. - config PATA_CMD640_PCI tristate "CMD640 PCI PATA support (Experimental)" depends on PCI diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 8daec3e657f8..f1f5a3fbc777 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -96,7 +96,6 @@ obj-$(CONFIG_PATA_VIA) += pata_via.o obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o # SFF PIO only -obj-$(CONFIG_PATA_AT32) += pata_at32.o obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o obj-$(CONFIG_PATA_FALCON) += pata_falcon.o obj-$(CONFIG_PATA_ISAPNP) += pata_isapnp.o diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 5443cb71d7ba..355a95a83a34 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -65,6 +65,7 @@ enum board_ids { /* board IDs by feature in alphabetical order */ board_ahci, board_ahci_ign_iferr, + board_ahci_mobile, board_ahci_nomsi, board_ahci_noncq, board_ahci_nosntf, @@ -140,6 +141,13 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, + [board_ahci_mobile] = { + AHCI_HFLAGS (AHCI_HFLAG_IS_MOBILE), + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, [board_ahci_nomsi] = { AHCI_HFLAGS (AHCI_HFLAG_NO_MSI), .flags = AHCI_FLAG_COMMON, @@ -252,13 +260,13 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */ { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */ { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x2929), board_ahci_mobile }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292a), board_ahci_mobile }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292b), board_ahci_mobile }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292c), board_ahci_mobile }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292f), board_ahci_mobile }, /* ICH9M */ { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x294e), board_ahci_mobile }, /* ICH9M */ { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */ { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */ { PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */ @@ -268,9 +276,9 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */ { PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */ { PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */ - { PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */ + { PCI_VDEVICE(INTEL, 0x3b29), board_ahci_mobile }, /* PCH M AHCI */ { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */ - { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */ + { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci_mobile }, /* PCH M RAID */ { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */ { PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */ { PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */ @@ -293,9 +301,9 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */ { PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */ { PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */ - { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */ + { PCI_VDEVICE(INTEL, 0x1c03), board_ahci_mobile }, /* CPT M AHCI */ { PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */ - { PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT RAID */ + { PCI_VDEVICE(INTEL, 0x1c05), board_ahci_mobile }, /* CPT M RAID */ { PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */ { PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */ { PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */ @@ -304,28 +312,28 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG RAID */ { PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */ { PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */ - { PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point AHCI */ + { PCI_VDEVICE(INTEL, 0x1e03), board_ahci_mobile }, /* Panther M AHCI */ { PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */ { PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */ { PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */ - { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */ + { PCI_VDEVICE(INTEL, 0x1e07), board_ahci_mobile }, /* Panther M RAID */ { PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */ { PCI_VDEVICE(INTEL, 0x8c02), board_ahci }, /* Lynx Point AHCI */ - { PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point AHCI */ + { PCI_VDEVICE(INTEL, 0x8c03), board_ahci_mobile }, /* Lynx M AHCI */ { PCI_VDEVICE(INTEL, 0x8c04), board_ahci }, /* Lynx Point RAID */ - { PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point RAID */ + { PCI_VDEVICE(INTEL, 0x8c05), board_ahci_mobile }, /* Lynx M RAID */ { PCI_VDEVICE(INTEL, 0x8c06), board_ahci }, /* Lynx Point RAID */ - { PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point RAID */ + { PCI_VDEVICE(INTEL, 0x8c07), board_ahci_mobile }, /* Lynx M RAID */ { PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */ - { PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point RAID */ - { PCI_VDEVICE(INTEL, 0x9c02), board_ahci }, /* Lynx Point-LP AHCI */ - { PCI_VDEVICE(INTEL, 0x9c03), board_ahci }, /* Lynx Point-LP AHCI */ - { PCI_VDEVICE(INTEL, 0x9c04), board_ahci }, /* Lynx Point-LP RAID */ - { PCI_VDEVICE(INTEL, 0x9c05), board_ahci }, /* Lynx Point-LP RAID */ - { PCI_VDEVICE(INTEL, 0x9c06), board_ahci }, /* Lynx Point-LP RAID */ - { PCI_VDEVICE(INTEL, 0x9c07), board_ahci }, /* Lynx Point-LP RAID */ - { PCI_VDEVICE(INTEL, 0x9c0e), board_ahci }, /* Lynx Point-LP RAID */ - { PCI_VDEVICE(INTEL, 0x9c0f), board_ahci }, /* Lynx Point-LP RAID */ + { PCI_VDEVICE(INTEL, 0x8c0f), board_ahci_mobile }, /* Lynx M RAID */ + { PCI_VDEVICE(INTEL, 0x9c02), board_ahci_mobile }, /* Lynx LP AHCI */ + { PCI_VDEVICE(INTEL, 0x9c03), board_ahci_mobile }, /* Lynx LP AHCI */ + { PCI_VDEVICE(INTEL, 0x9c04), board_ahci_mobile }, /* Lynx LP RAID */ + { PCI_VDEVICE(INTEL, 0x9c05), board_ahci_mobile }, /* Lynx LP RAID */ + { PCI_VDEVICE(INTEL, 0x9c06), board_ahci_mobile }, /* Lynx LP RAID */ + { PCI_VDEVICE(INTEL, 0x9c07), board_ahci_mobile }, /* Lynx LP RAID */ + { PCI_VDEVICE(INTEL, 0x9c0e), board_ahci_mobile }, /* Lynx LP RAID */ + { PCI_VDEVICE(INTEL, 0x9c0f), board_ahci_mobile }, /* Lynx LP RAID */ { PCI_VDEVICE(INTEL, 0x1f22), board_ahci }, /* Avoton AHCI */ { PCI_VDEVICE(INTEL, 0x1f23), board_ahci }, /* Avoton AHCI */ { PCI_VDEVICE(INTEL, 0x1f24), board_ahci }, /* Avoton RAID */ @@ -353,26 +361,26 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x8d66), board_ahci }, /* Wellsburg RAID */ { PCI_VDEVICE(INTEL, 0x8d6e), board_ahci }, /* Wellsburg RAID */ { PCI_VDEVICE(INTEL, 0x23a3), board_ahci }, /* Coleto Creek AHCI */ - { PCI_VDEVICE(INTEL, 0x9c83), board_ahci }, /* Wildcat Point-LP AHCI */ - { PCI_VDEVICE(INTEL, 0x9c85), board_ahci }, /* Wildcat Point-LP RAID */ - { PCI_VDEVICE(INTEL, 0x9c87), board_ahci }, /* Wildcat Point-LP RAID */ - { PCI_VDEVICE(INTEL, 0x9c8f), board_ahci }, /* Wildcat Point-LP RAID */ + { PCI_VDEVICE(INTEL, 0x9c83), board_ahci_mobile }, /* Wildcat LP AHCI */ + { PCI_VDEVICE(INTEL, 0x9c85), board_ahci_mobile }, /* Wildcat LP RAID */ + { PCI_VDEVICE(INTEL, 0x9c87), board_ahci_mobile }, /* Wildcat LP RAID */ + { PCI_VDEVICE(INTEL, 0x9c8f), board_ahci_mobile }, /* Wildcat LP RAID */ { PCI_VDEVICE(INTEL, 0x8c82), board_ahci }, /* 9 Series AHCI */ - { PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series AHCI */ + { PCI_VDEVICE(INTEL, 0x8c83), board_ahci_mobile }, /* 9 Series M AHCI */ { PCI_VDEVICE(INTEL, 0x8c84), board_ahci }, /* 9 Series RAID */ - { PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series RAID */ + { PCI_VDEVICE(INTEL, 0x8c85), board_ahci_mobile }, /* 9 Series M RAID */ { PCI_VDEVICE(INTEL, 0x8c86), board_ahci }, /* 9 Series RAID */ - { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */ + { PCI_VDEVICE(INTEL, 0x8c87), board_ahci_mobile }, /* 9 Series M RAID */ { PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */ - { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */ - { PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */ - { PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */ - { PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */ + { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci_mobile }, /* 9 Series M RAID */ + { PCI_VDEVICE(INTEL, 0x9d03), board_ahci_mobile }, /* Sunrise LP AHCI */ + { PCI_VDEVICE(INTEL, 0x9d05), board_ahci_mobile }, /* Sunrise LP RAID */ + { PCI_VDEVICE(INTEL, 0x9d07), board_ahci_mobile }, /* Sunrise LP RAID */ { PCI_VDEVICE(INTEL, 0xa102), board_ahci }, /* Sunrise Point-H AHCI */ - { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */ + { PCI_VDEVICE(INTEL, 0xa103), board_ahci_mobile }, /* Sunrise M AHCI */ { PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */ { PCI_VDEVICE(INTEL, 0xa106), board_ahci }, /* Sunrise Point-H RAID */ - { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */ + { PCI_VDEVICE(INTEL, 0xa107), board_ahci_mobile }, /* Sunrise M RAID */ { PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */ { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Lewisburg AHCI*/ @@ -386,6 +394,11 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa356), board_ahci }, /* Cannon Lake PCH-H RAID */ + { PCI_VDEVICE(INTEL, 0x0f22), board_ahci_mobile }, /* Bay Trail AHCI */ + { PCI_VDEVICE(INTEL, 0x0f23), board_ahci_mobile }, /* Bay Trail AHCI */ + { PCI_VDEVICE(INTEL, 0x22a3), board_ahci_mobile }, /* Cherry Tr. AHCI */ + { PCI_VDEVICE(INTEL, 0x5ae3), board_ahci_mobile }, /* ApolloLake AHCI */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, @@ -593,6 +606,9 @@ static int marvell_enable = 1; module_param(marvell_enable, int, 0644); MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)"); +static int mobile_lpm_policy = CONFIG_SATA_MOBILE_LPM_POLICY; +module_param(mobile_lpm_policy, int, 0644); +MODULE_PARM_DESC(mobile_lpm_policy, "Default LPM policy for mobile chipsets"); static void ahci_pci_save_initial_config(struct pci_dev *pdev, struct ahci_host_priv *hpriv) @@ -1728,6 +1744,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (ap->flags & ATA_FLAG_EM) ap->em_message_type = hpriv->em_msg_type; + if ((hpriv->flags & AHCI_HFLAG_IS_MOBILE) && + mobile_lpm_policy >= ATA_LPM_UNKNOWN && + mobile_lpm_policy <= ATA_LPM_MIN_POWER) + ap->target_lpm_policy = mobile_lpm_policy; /* disabled/not-implemented port */ if (!(hpriv->port_map & (1 << i))) diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 749fd94441b0..a9d996e17d75 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -251,6 +251,9 @@ enum { AHCI_HFLAG_YES_ALPM = (1 << 23), /* force ALPM cap on */ AHCI_HFLAG_NO_WRITE_TO_RO = (1 << 24), /* don't write to read only registers */ + AHCI_HFLAG_IS_MOBILE = (1 << 25), /* mobile chipset, use + SATA_MOBILE_LPM_POLICY + as default lpm_policy */ /* ap->flags bits */ diff --git a/drivers/ata/ahci_brcm.c b/drivers/ata/ahci_brcm.c index 5936d1679bf3..ea430819c80b 100644 --- a/drivers/ata/ahci_brcm.c +++ b/drivers/ata/ahci_brcm.c @@ -70,6 +70,13 @@ (DATA_ENDIAN << DMADESC_ENDIAN_SHIFT) | \ (MMIO_ENDIAN << MMIO_ENDIAN_SHIFT)) +#define BUS_CTRL_ENDIAN_NSP_CONF \ + (0x02 << DMADATA_ENDIAN_SHIFT | 0x02 << DMADESC_ENDIAN_SHIFT) + +#define BUS_CTRL_ENDIAN_CONF_MASK \ + (0x3 << MMIO_ENDIAN_SHIFT | 0x3 << DMADESC_ENDIAN_SHIFT | \ + 0x3 << DMADATA_ENDIAN_SHIFT | 0x3 << PIODATA_ENDIAN_SHIFT) + enum brcm_ahci_version { BRCM_SATA_BCM7425 = 1, BRCM_SATA_BCM7445, @@ -89,14 +96,6 @@ struct brcm_ahci_priv { enum brcm_ahci_version version; }; -static const struct ata_port_info ahci_brcm_port_info = { - .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM, - .link_flags = ATA_LFLAG_NO_DB_DELAY, - .pio_mask = ATA_PIO4, - .udma_mask = ATA_UDMA6, - .port_ops = &ahci_platform_ops, -}; - static inline u32 brcm_sata_readreg(void __iomem *addr) { /* @@ -250,20 +249,105 @@ static u32 brcm_ahci_get_portmask(struct platform_device *pdev, static void brcm_sata_init(struct brcm_ahci_priv *priv) { void __iomem *ctrl = priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL; + u32 data; /* Configure endianness */ - if (priv->version == BRCM_SATA_NSP) { - u32 data = brcm_sata_readreg(ctrl); - - data &= ~((0x03 << DMADATA_ENDIAN_SHIFT) | - (0x03 << DMADESC_ENDIAN_SHIFT)); - data |= (0x02 << DMADATA_ENDIAN_SHIFT) | - (0x02 << DMADESC_ENDIAN_SHIFT); - brcm_sata_writereg(data, ctrl); - } else - brcm_sata_writereg(BUS_CTRL_ENDIAN_CONF, ctrl); + data = brcm_sata_readreg(ctrl); + data &= ~BUS_CTRL_ENDIAN_CONF_MASK; + if (priv->version == BRCM_SATA_NSP) + data |= BUS_CTRL_ENDIAN_NSP_CONF; + else + data |= BUS_CTRL_ENDIAN_CONF; + brcm_sata_writereg(data, ctrl); } +static unsigned int brcm_ahci_read_id(struct ata_device *dev, + struct ata_taskfile *tf, u16 *id) +{ + struct ata_port *ap = dev->link->ap; + struct ata_host *host = ap->host; + struct ahci_host_priv *hpriv = host->private_data; + struct brcm_ahci_priv *priv = hpriv->plat_data; + void __iomem *mmio = hpriv->mmio; + unsigned int err_mask; + unsigned long flags; + int i, rc; + u32 ctl; + + /* Try to read the device ID and, if this fails, proceed with the + * recovery sequence below + */ + err_mask = ata_do_dev_read_id(dev, tf, id); + if (likely(!err_mask)) + return err_mask; + + /* Disable host interrupts */ + spin_lock_irqsave(&host->lock, flags); + ctl = readl(mmio + HOST_CTL); + ctl &= ~HOST_IRQ_EN; + writel(ctl, mmio + HOST_CTL); + readl(mmio + HOST_CTL); /* flush */ + spin_unlock_irqrestore(&host->lock, flags); + + /* Perform the SATA PHY reset sequence */ + brcm_sata_phy_disable(priv, ap->port_no); + + /* Bring the PHY back on */ + brcm_sata_phy_enable(priv, ap->port_no); + + /* Re-initialize and calibrate the PHY */ + for (i = 0; i < hpriv->nports; i++) { + rc = phy_init(hpriv->phys[i]); + if (rc) + goto disable_phys; + + rc = phy_calibrate(hpriv->phys[i]); + if (rc) { + phy_exit(hpriv->phys[i]); + goto disable_phys; + } + } + + /* Re-enable host interrupts */ + spin_lock_irqsave(&host->lock, flags); + ctl = readl(mmio + HOST_CTL); + ctl |= HOST_IRQ_EN; + writel(ctl, mmio + HOST_CTL); + readl(mmio + HOST_CTL); /* flush */ + spin_unlock_irqrestore(&host->lock, flags); + + return ata_do_dev_read_id(dev, tf, id); + +disable_phys: + while (--i >= 0) { + phy_power_off(hpriv->phys[i]); + phy_exit(hpriv->phys[i]); + } + + return AC_ERR_OTHER; +} + +static void brcm_ahci_host_stop(struct ata_host *host) +{ + struct ahci_host_priv *hpriv = host->private_data; + + ahci_platform_disable_resources(hpriv); +} + +static struct ata_port_operations ahci_brcm_platform_ops = { + .inherits = &ahci_ops, + .host_stop = brcm_ahci_host_stop, + .read_id = brcm_ahci_read_id, +}; + +static const struct ata_port_info ahci_brcm_port_info = { + .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM, + .link_flags = ATA_LFLAG_NO_DB_DELAY, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_brcm_platform_ops, +}; + #ifdef CONFIG_PM_SLEEP static int brcm_ahci_suspend(struct device *dev) { diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index b702c20fbc2b..7ecb1322a514 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -458,7 +458,7 @@ static const struct piix_map_db *piix_map_db_table[] = { [ich8_2port_sata_byt] = &ich8_2port_map_db, }; -static struct pci_bits piix_enable_bits[] = { +static const struct pci_bits piix_enable_bits[] = { { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */ }; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 8193b38a1cae..3c09122bf038 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4449,6 +4449,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { * https://bugzilla.kernel.org/show_bug.cgi?id=121671 */ { "LITEON CX1-JB*-HP", NULL, ATA_HORKAGE_MAX_SEC_1024 }, + { "LITEON EP1-*", NULL, ATA_HORKAGE_MAX_SEC_1024 }, /* Devices we expect to fail diagnostics */ diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index d19cd88ed2d3..0b122f903b8a 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -466,7 +466,8 @@ static void ali_init_chipset(struct pci_dev *pdev) tmp |= 0x01; /* CD_ROM enable for DMA */ pci_write_config_byte(pdev, 0x53, tmp); } - north = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); + north = pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus), 0, + PCI_DEVFN(0, 0)); if (north && north->vendor == PCI_VENDOR_ID_AL && ali_isa_bridge) { /* Configure the ALi bridge logic. For non ALi rely on BIOS. Set the south bridge enable bit */ diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c deleted file mode 100644 index 9aeb7a6dd4d4..000000000000 --- a/drivers/ata/pata_at32.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * AVR32 SMC/CFC PATA Driver - * - * Copyright (C) 2007 Atmel Norway - * - * 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. - */ - -#define DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define DRV_NAME "pata_at32" -#define DRV_VERSION "0.0.3" - -/* - * CompactFlash controller memory layout relative to the base address: - * - * Attribute memory: 0000 0000 -> 003f ffff - * Common memory: 0040 0000 -> 007f ffff - * I/O memory: 0080 0000 -> 00bf ffff - * True IDE Mode: 00c0 0000 -> 00df ffff - * Alt IDE Mode: 00e0 0000 -> 00ff ffff - * - * Only True IDE and Alt True IDE mode are needed for this driver. - * - * True IDE mode => CS0 = 0, CS1 = 1 (cmd, error, stat, etc) - * Alt True IDE mode => CS0 = 1, CS1 = 0 (ctl, alt_stat) - */ -#define CF_IDE_OFFSET 0x00c00000 -#define CF_ALT_IDE_OFFSET 0x00e00000 -#define CF_RES_SIZE 2048 - -/* - * Define DEBUG_BUS if you are doing debugging of your own EBI -> PATA - * adaptor with a logic analyzer or similar. - */ -#undef DEBUG_BUS - -/* - * ATA PIO modes - * - * Name | Mb/s | Min cycle time | Mask - * --------+-------+----------------+-------- - * Mode 0 | 3.3 | 600 ns | 0x01 - * Mode 1 | 5.2 | 383 ns | 0x03 - * Mode 2 | 8.3 | 240 ns | 0x07 - * Mode 3 | 11.1 | 180 ns | 0x0f - * Mode 4 | 16.7 | 120 ns | 0x1f - * - * Alter PIO_MASK below according to table to set maximal PIO mode. - */ -enum { - PIO_MASK = ATA_PIO4, -}; - -/* - * Struct containing private information about device. - */ -struct at32_ide_info { - unsigned int irq; - struct resource res_ide; - struct resource res_alt; - void __iomem *ide_addr; - void __iomem *alt_addr; - unsigned int cs; - struct smc_config smc; -}; - -/* - * Setup SMC for the given ATA timing. - */ -static int pata_at32_setup_timing(struct device *dev, - struct at32_ide_info *info, - const struct ata_timing *ata) -{ - struct smc_config *smc = &info->smc; - struct smc_timing timing; - - int active; - int recover; - - memset(&timing, 0, sizeof(struct smc_timing)); - - /* Total cycle time */ - timing.read_cycle = ata->cyc8b; - - /* DIOR <= CFIOR timings */ - timing.nrd_setup = ata->setup; - timing.nrd_pulse = ata->act8b; - timing.nrd_recover = ata->rec8b; - - /* Convert nanosecond timing to clock cycles */ - smc_set_timing(smc, &timing); - - /* Add one extra cycle setup due to signal ring */ - smc->nrd_setup = smc->nrd_setup + 1; - - active = smc->nrd_setup + smc->nrd_pulse; - recover = smc->read_cycle - active; - - /* Need at least two cycles recovery */ - if (recover < 2) - smc->read_cycle = active + 2; - - /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */ - smc->ncs_read_setup = 1; - smc->ncs_read_pulse = smc->read_cycle - 2; - - /* Write timings same as read timings */ - smc->write_cycle = smc->read_cycle; - smc->nwe_setup = smc->nrd_setup; - smc->nwe_pulse = smc->nrd_pulse; - smc->ncs_write_setup = smc->ncs_read_setup; - smc->ncs_write_pulse = smc->ncs_read_pulse; - - /* Do some debugging output of ATA and SMC timings */ - dev_dbg(dev, "ATA: C=%d S=%d P=%d R=%d\n", - ata->cyc8b, ata->setup, ata->act8b, ata->rec8b); - - dev_dbg(dev, "SMC: C=%d S=%d P=%d NS=%d NP=%d\n", - smc->read_cycle, smc->nrd_setup, smc->nrd_pulse, - smc->ncs_read_setup, smc->ncs_read_pulse); - - /* Finally, configure the SMC */ - return smc_set_configuration(info->cs, smc); -} - -/* - * Procedures for libATA. - */ -static void pata_at32_set_piomode(struct ata_port *ap, struct ata_device *adev) -{ - struct ata_timing timing; - struct at32_ide_info *info = ap->host->private_data; - - int ret; - - /* Compute ATA timing */ - ret = ata_timing_compute(adev, adev->pio_mode, &timing, 1000, 0); - if (ret) { - dev_warn(ap->dev, "Failed to compute ATA timing %d\n", ret); - return; - } - - /* Setup SMC to ATA timing */ - ret = pata_at32_setup_timing(ap->dev, info, &timing); - if (ret) { - dev_warn(ap->dev, "Failed to setup ATA timing %d\n", ret); - return; - } -} - -static struct scsi_host_template at32_sht = { - ATA_PIO_SHT(DRV_NAME), -}; - -static struct ata_port_operations at32_port_ops = { - .inherits = &ata_sff_port_ops, - .cable_detect = ata_cable_40wire, - .set_piomode = pata_at32_set_piomode, -}; - -static int __init pata_at32_init_one(struct device *dev, - struct at32_ide_info *info) -{ - struct ata_host *host; - struct ata_port *ap; - - host = ata_host_alloc(dev, 1); - if (!host) - return -ENOMEM; - - ap = host->ports[0]; - - /* Setup ATA bindings */ - ap->ops = &at32_port_ops; - ap->pio_mask = PIO_MASK; - ap->flags |= ATA_FLAG_SLAVE_POSS; - - /* - * Since all 8-bit taskfile transfers has to go on the lower - * byte of the data bus and there is a bug in the SMC that - * makes it impossible to alter the bus width during runtime, - * we need to hardwire the address signals as follows: - * - * A_IDE(2:0) <= A_EBI(3:1) - * - * This makes all addresses on the EBI even, thus all data - * will be on the lower byte of the data bus. All addresses - * used by libATA need to be altered according to this. - */ - ap->ioaddr.altstatus_addr = info->alt_addr + (0x06 << 1); - ap->ioaddr.ctl_addr = info->alt_addr + (0x06 << 1); - - ap->ioaddr.data_addr = info->ide_addr + (ATA_REG_DATA << 1); - ap->ioaddr.error_addr = info->ide_addr + (ATA_REG_ERR << 1); - ap->ioaddr.feature_addr = info->ide_addr + (ATA_REG_FEATURE << 1); - ap->ioaddr.nsect_addr = info->ide_addr + (ATA_REG_NSECT << 1); - ap->ioaddr.lbal_addr = info->ide_addr + (ATA_REG_LBAL << 1); - ap->ioaddr.lbam_addr = info->ide_addr + (ATA_REG_LBAM << 1); - ap->ioaddr.lbah_addr = info->ide_addr + (ATA_REG_LBAH << 1); - ap->ioaddr.device_addr = info->ide_addr + (ATA_REG_DEVICE << 1); - ap->ioaddr.status_addr = info->ide_addr + (ATA_REG_STATUS << 1); - ap->ioaddr.command_addr = info->ide_addr + (ATA_REG_CMD << 1); - - /* Set info as private data of ATA host */ - host->private_data = info; - - /* Register ATA device and return */ - return ata_host_activate(host, info->irq, ata_sff_interrupt, - IRQF_SHARED | IRQF_TRIGGER_RISING, - &at32_sht); -} - -/* - * This function may come in handy for people analyzing their own - * EBI -> PATA adaptors. - */ -#ifdef DEBUG_BUS - -static void __init pata_at32_debug_bus(struct device *dev, - struct at32_ide_info *info) -{ - const int d1 = 0xff; - const int d2 = 0x00; - - int i; - - /* Write 8-bit values (registers) */ - iowrite8(d1, info->alt_addr + (0x06 << 1)); - iowrite8(d2, info->alt_addr + (0x06 << 1)); - - for (i = 0; i < 8; i++) { - iowrite8(d1, info->ide_addr + (i << 1)); - iowrite8(d2, info->ide_addr + (i << 1)); - } - - /* Write 16 bit values (data) */ - iowrite16(d1, info->ide_addr); - iowrite16(d1 << 8, info->ide_addr); - - iowrite16(d1, info->ide_addr); - iowrite16(d1 << 8, info->ide_addr); -} - -#endif - -static int __init pata_at32_probe(struct platform_device *pdev) -{ - const struct ata_timing initial_timing = - {XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0}; - - struct device *dev = &pdev->dev; - struct at32_ide_info *info; - struct ide_platform_data *board = dev_get_platdata(&pdev->dev); - struct resource *res; - - int irq; - int ret; - - if (!board) - return -ENXIO; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENXIO; - - /* Retrive IRQ */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - - /* Setup struct containing private information */ - info = kzalloc(sizeof(struct at32_ide_info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->irq = irq; - info->cs = board->cs; - - /* Request memory resources */ - info->res_ide.start = res->start + CF_IDE_OFFSET; - info->res_ide.end = info->res_ide.start + CF_RES_SIZE - 1; - info->res_ide.name = "ide"; - info->res_ide.flags = IORESOURCE_MEM; - - ret = request_resource(res, &info->res_ide); - if (ret) - goto err_req_res_ide; - - info->res_alt.start = res->start + CF_ALT_IDE_OFFSET; - info->res_alt.end = info->res_alt.start + CF_RES_SIZE - 1; - info->res_alt.name = "alt"; - info->res_alt.flags = IORESOURCE_MEM; - - ret = request_resource(res, &info->res_alt); - if (ret) - goto err_req_res_alt; - - /* Setup non-timing elements of SMC */ - info->smc.bus_width = 2; /* 16 bit data bus */ - info->smc.nrd_controlled = 1; /* Sample data on rising edge of NRD */ - info->smc.nwe_controlled = 0; /* Drive data on falling edge of NCS */ - info->smc.nwait_mode = 3; /* NWAIT is in READY mode */ - info->smc.byte_write = 0; /* Byte select access type */ - info->smc.tdf_mode = 0; /* TDF optimization disabled */ - info->smc.tdf_cycles = 0; /* No TDF wait cycles */ - - /* Setup SMC to ATA timing */ - ret = pata_at32_setup_timing(dev, info, &initial_timing); - if (ret) - goto err_setup_timing; - - /* Map ATA address space */ - ret = -ENOMEM; - info->ide_addr = devm_ioremap(dev, info->res_ide.start, 16); - info->alt_addr = devm_ioremap(dev, info->res_alt.start, 16); - if (!info->ide_addr || !info->alt_addr) - goto err_ioremap; - -#ifdef DEBUG_BUS - pata_at32_debug_bus(dev, info); -#endif - - /* Setup and register ATA device */ - ret = pata_at32_init_one(dev, info); - if (ret) - goto err_ata_device; - - return 0; - - err_ata_device: - err_ioremap: - err_setup_timing: - release_resource(&info->res_alt); - err_req_res_alt: - release_resource(&info->res_ide); - err_req_res_ide: - kfree(info); - - return ret; -} - -static int __exit pata_at32_remove(struct platform_device *pdev) -{ - struct ata_host *host = platform_get_drvdata(pdev); - struct at32_ide_info *info; - - if (!host) - return 0; - - info = host->private_data; - ata_host_detach(host); - - if (!info) - return 0; - - release_resource(&info->res_ide); - release_resource(&info->res_alt); - - kfree(info); - - return 0; -} - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:at32_ide"); - -static struct platform_driver pata_at32_driver = { - .remove = __exit_p(pata_at32_remove), - .driver = { - .name = "at32_ide", - }, -}; - -module_platform_driver_probe(pata_at32_driver, pata_at32_probe); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("AVR32 SMC/CFC PATA Driver"); -MODULE_AUTHOR("Kristoffer Nyborg Gregertsen "); -MODULE_VERSION(DRV_VERSION); diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 49d705c9f0f7..4d49fd3c927b 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -278,6 +278,10 @@ static int atiixp_init_one(struct pci_dev *pdev, const struct pci_device_id *id) }; const struct ata_port_info *ppi[] = { &info, &info }; + /* SB600 doesn't have secondary port wired */ + if((pdev->device == PCI_DEVICE_ID_ATI_IXP600_IDE)) + ppi[1] = &ata_dummy_port_info; + return ata_pci_bmdma_init_one(pdev, ppi, &atiixp_sht, NULL, ATA_HOST_PARALLEL_SCAN); } diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 7a21edf89e72..8468b300193b 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -683,7 +683,7 @@ static u8 *it821x_firmware_command(struct ata_port *ap, u8 cmd, int len) ioread16_rep(ap->ioaddr.data_addr, buf, len/2); return (u8 *)buf; } - mdelay(1); + usleep_range(500, 1000); } kfree(buf); printk(KERN_ERR "it821x_firmware_command: timeout\n"); diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 6db2e34bd52f..1a18e675ba9f 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -580,7 +580,7 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b ioread16(mmio_base + PDC_PLL_CTL); /* flush */ /* Wait the PLL circuit to be stable */ - mdelay(30); + msleep(30); #ifdef PDC_DEBUG /* @@ -620,7 +620,7 @@ static long pdc_detect_pll_input_clock(struct ata_host *host) start_time = ktime_get(); /* Let the counter run for 100 ms. */ - mdelay(100); + msleep(100); /* Read the counter values again */ end_count = pdc_read_counter(host); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index cc208b72b199..42d4589b43d4 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -3596,7 +3596,7 @@ static void mv_reset_channel(struct mv_host_priv *hpriv, void __iomem *mmio, hpriv->ops->phy_errata(hpriv, mmio, port_no); if (IS_GEN_I(hpriv)) - mdelay(1); + usleep_range(500, 1000); } static void mv_pmp_select(struct ata_port *ap, int pmp) diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index ce47eb17901d..6470e3c4c990 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -473,7 +473,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, ENI_PRV_POS(skb) = eni_vcc->descr+size+1; skb_queue_tail(&eni_dev->rx_queue,skb); eni_vcc->last = skb; -rx_enqueued++; + rx_enqueued++; } eni_vcc->descr = here; eni_out(dma_wr,MID_DMA_WR_RX); @@ -715,7 +715,7 @@ static void get_service(struct atm_dev *dev) else eni_dev->slow = vcc; eni_dev->last_slow = vcc; } -putting++; + putting++; ENI_VCC(vcc)->servicing++; } } @@ -744,7 +744,7 @@ static void dequeue_rx(struct atm_dev *dev) } EVENT("dequeued (size=%ld,pos=0x%lx)\n",ENI_PRV_SIZE(skb), ENI_PRV_POS(skb)); -rx_dequeued++; + rx_dequeued++; vcc = ATM_SKB(skb)->vcc; eni_vcc = ENI_VCC(vcc); first = 0; @@ -1174,7 +1174,7 @@ DPRINTK("doing direct send\n"); /* @@@ well, this doesn't work anyway */ DPRINTK("dma_wr set to %d, tx_pos is now %ld\n",dma_wr,tx->tx_pos); eni_out(dma_wr,MID_DMA_WR_TX); skb_queue_tail(&eni_dev->tx_queue,skb); -queued++; + queued++; return enq_ok; } @@ -1195,7 +1195,7 @@ static void poll_tx(struct atm_dev *dev) if (res == enq_ok) continue; DPRINTK("re-queuing TX PDU\n"); skb_queue_head(&tx->backlog,skb); -requeued++; + requeued++; if (res == enq_jam) return; break; } @@ -1232,7 +1232,7 @@ static void dequeue_tx(struct atm_dev *dev) else dev_kfree_skb_irq(skb); atomic_inc(&vcc->stats->tx); wake_up(&eni_dev->tx_wait); -dma_complete++; + dma_complete++; } } @@ -1555,7 +1555,7 @@ static void eni_tasklet(unsigned long data) } if (events & MID_TX_COMPLETE) { EVENT("INT: TX COMPLETE\n",0,0); -tx_complete++; + tx_complete++; wake_up(&eni_dev->tx_wait); /* poll_rx ? */ } @@ -2069,14 +2069,14 @@ static int eni_send(struct atm_vcc *vcc,struct sk_buff *skb) } *(u32 *) skb->data = htonl(*(u32 *) skb->data); } -submitted++; + submitted++; ATM_SKB(skb)->vcc = vcc; tasklet_disable(&ENI_DEV(vcc->dev)->task); res = do_tx(skb); tasklet_enable(&ENI_DEV(vcc->dev)->task); if (res == enq_ok) return 0; skb_queue_tail(&ENI_VCC(vcc)->tx->backlog,skb); -backlogged++; + backlogged++; tasklet_schedule(&ENI_DEV(vcc->dev)->task); return 0; } diff --git a/drivers/atm/he.c b/drivers/atm/he.c index e58538c29377..29f102dcfec4 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -738,13 +738,13 @@ static int he_init_cs_block_rcm(struct he_dev *he_dev) #else /* this is pretty, but avoids _divdu3 and is mostly correct */ mult = he_dev->atm_dev->link_rate / ATM_OC3_PCR; - if (rate_cps > (272 * mult)) + if (rate_cps > (272ULL * mult)) buf = 4; - else if (rate_cps > (204 * mult)) + else if (rate_cps > (204ULL * mult)) buf = 3; - else if (rate_cps > (136 * mult)) + else if (rate_cps > (136ULL * mult)) buf = 2; - else if (rate_cps > (68 * mult)) + else if (rate_cps > (68ULL * mult)) buf = 1; else buf = 0; diff --git a/drivers/auxdisplay/img-ascii-lcd.c b/drivers/auxdisplay/img-ascii-lcd.c index db040b378224..9180b9bd5821 100644 --- a/drivers/auxdisplay/img-ascii-lcd.c +++ b/drivers/auxdisplay/img-ascii-lcd.c @@ -441,3 +441,7 @@ static struct platform_driver img_ascii_lcd_driver = { .remove = img_ascii_lcd_remove, }; module_platform_driver(img_ascii_lcd_driver); + +MODULE_DESCRIPTION("Imagination Technologies ASCII LCD Display"); +MODULE_AUTHOR("Paul Burton "); +MODULE_LICENSE("GPL"); diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 49fd50fccd48..29b0eb452b3a 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -86,10 +86,9 @@ config FW_LOADER require userspace firmware loading support, but a module built out-of-tree does. -config FIRMWARE_IN_KERNEL - bool "Include in-kernel firmware blobs in kernel binary" +config EXTRA_FIRMWARE + string "External firmware blobs to build into the kernel binary" depends on FW_LOADER - default y help Various drivers in the kernel source tree may require firmware, which is generally available in your distribution's linux-firmware @@ -99,23 +98,6 @@ config FIRMWARE_IN_KERNEL /lib/firmware/ on your system, so they can be loaded by userspace helpers on request. - Enabling this option will build each required firmware blob - specified by EXTRA_FIRMWARE into the kernel directly, where - request_firmware() will find them without having to call out to - userspace. This may be useful if your root file system requires a - device that uses such firmware and you do not wish to use an - initrd. - - This single option controls the inclusion of firmware for - every driver that uses request_firmware(), which avoids a - proliferation of 'Include firmware for xxx device' options. - - Say 'N' and let firmware be loaded from userspace. - -config EXTRA_FIRMWARE - string "External firmware blobs to build into the kernel binary" - depends on FW_LOADER - help This option allows firmware to be built into the kernel for the case where the user either cannot or doesn't want to provide it from userspace at runtime (for example, when the firmware in question is @@ -126,11 +108,11 @@ config EXTRA_FIRMWARE firmware files -- the same names that appear in MODULE_FIRMWARE() and request_firmware() in the source. These files should exist under the directory specified by the EXTRA_FIRMWARE_DIR option, which is - by default the firmware subdirectory of the kernel source tree. + /lib/firmware by default. For example, you might set CONFIG_EXTRA_FIRMWARE="usb8388.bin", copy - the usb8388.bin file into the firmware directory, and build the kernel. - Then any request_firmware("usb8388.bin") will be satisfied internally + the usb8388.bin file into /lib/firmware, and build the kernel. Then + any request_firmware("usb8388.bin") will be satisfied internally without needing to call out to userspace. WARNING: If you include additional firmware files into your binary diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 4de87b0b53c8..52ec5174bcb1 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -1,15 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Arch specific cpu topology information * * Copyright (C) 2016, ARM Ltd. * Written by: Juri Lelli, ARM Ltd. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Released under the GPLv2 only. - * SPDX-License-Identifier: GPL-2.0 */ #include diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 95e3ef82f3b7..20736aaa0e69 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * attribute_container.c - implementation of a simple container for classes * * Copyright (c) 2005 - James Bottomley * - * This file is licensed under GPLv2 - * * The basic idea here is to enable a device to be attached to an * aritrary numer of classes without having to allocate storage for them. * Instead, the contained classes select the devices they need to attach diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 22a64fd3309b..ef6183306b40 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * bus.c - bus driver management * @@ -5,9 +6,6 @@ * Copyright (c) 2002-3 Open Source Development Labs * Copyright (c) 2007 Greg Kroah-Hartman * Copyright (c) 2007 Novell Inc. - * - * This file is released under the GPLv2 - * */ #include @@ -309,7 +307,7 @@ int bus_for_each_dev(struct bus_type *bus, struct device *start, klist_iter_init_node(&bus->p->klist_devices, &i, (start ? &start->p->knode_bus : NULL)); - while ((dev = next_device(&i)) && !error) + while (!error && (dev = next_device(&i))) error = fn(dev, data); klist_iter_exit(&i); return error; diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index 07532d83be0b..edf726267282 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * cacheinfo support - processor cache information via sysfs * * Based on arch/x86/kernel/cpu/intel_cacheinfo.c * Author: Sudeep Holla - * - * 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 "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; 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 . */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/base/class.c b/drivers/base/class.c index 52eb8e644acd..54def4e02f00 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * class.c - basic device class management * @@ -5,9 +6,6 @@ * Copyright (c) 2002-3 Open Source Development Labs * Copyright (c) 2003-2004 Greg Kroah-Hartman * Copyright (c) 2003-2004 IBM Corp. - * - * This file is released under the GPLv2 - * */ #include diff --git a/drivers/base/component.c b/drivers/base/component.c index 89b032f2ffd2..8946dfee4768 100644 --- a/drivers/base/component.c +++ b/drivers/base/component.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Componentized device handling. * - * 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 is work in progress. We gather up the component devices into a list, * and bind them when instructed. At the moment, we're specific to the DRM * subsystem, and only handles one master device, but this doesn't have to be @@ -17,6 +14,7 @@ #include #include #include +#include struct component; @@ -41,6 +39,7 @@ struct master { const struct component_master_ops *ops; struct device *dev; struct component_match *match; + struct dentry *dentry; }; struct component { @@ -56,6 +55,80 @@ static DEFINE_MUTEX(component_mutex); static LIST_HEAD(component_list); static LIST_HEAD(masters); +#ifdef CONFIG_DEBUG_FS + +static struct dentry *component_debugfs_dir; + +static int component_devices_show(struct seq_file *s, void *data) +{ + struct master *m = s->private; + struct component_match *match = m->match; + size_t i; + + mutex_lock(&component_mutex); + seq_printf(s, "%-40s %20s\n", "master name", "status"); + seq_puts(s, "-------------------------------------------------------------\n"); + seq_printf(s, "%-40s %20s\n\n", + dev_name(m->dev), m->bound ? "bound" : "not bound"); + + seq_printf(s, "%-40s %20s\n", "device name", "status"); + seq_puts(s, "-------------------------------------------------------------\n"); + for (i = 0; i < match->num; i++) { + struct device *d = (struct device *)match->compare[i].data; + + seq_printf(s, "%-40s %20s\n", dev_name(d), + match->compare[i].component ? + "registered" : "not registered"); + } + mutex_unlock(&component_mutex); + + return 0; +} + +static int component_devices_open(struct inode *inode, struct file *file) +{ + return single_open(file, component_devices_show, inode->i_private); +} + +static const struct file_operations component_devices_fops = { + .open = component_devices_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init component_debug_init(void) +{ + component_debugfs_dir = debugfs_create_dir("device_component", NULL); + + return 0; +} + +core_initcall(component_debug_init); + +static void component_master_debugfs_add(struct master *m) +{ + m->dentry = debugfs_create_file(dev_name(m->dev), 0444, + component_debugfs_dir, + m, &component_devices_fops); +} + +static void component_master_debugfs_del(struct master *m) +{ + debugfs_remove(m->dentry); + m->dentry = NULL; +} + +#else + +static void component_master_debugfs_add(struct master *m) +{ } + +static void component_master_debugfs_del(struct master *m) +{ } + +#endif + static struct master *__master_find(struct device *dev, const struct component_master_ops *ops) { @@ -290,6 +363,7 @@ static void free_master(struct master *master) struct component_match *match = master->match; int i; + component_master_debugfs_del(master); list_del(&master->node); if (match) { @@ -323,6 +397,7 @@ int component_master_add_with_match(struct device *dev, master->ops = ops; master->match = match; + component_master_debugfs_add(master); /* Add to the list of available masters. */ mutex_lock(&component_mutex); list_add(&master->node, &masters); diff --git a/drivers/base/container.c b/drivers/base/container.c index ecbfbe2e908f..1ba42d2d3532 100644 --- a/drivers/base/container.c +++ b/drivers/base/container.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * System bus type for containers. * * Copyright (C) 2013, Intel Corporation * Author: Rafael J. Wysocki - * - * 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. */ #include diff --git a/drivers/base/core.c b/drivers/base/core.c index 110230d86527..b2261f92f2f1 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * drivers/base/core.c - core driver model code (device registration, etc) * @@ -5,9 +6,6 @@ * Copyright (c) 2002-3 Open Source Development Labs * Copyright (c) 2006 Greg Kroah-Hartman * Copyright (c) 2006 Novell, Inc. - * - * This file is released under the GPLv2 - * */ #include @@ -22,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -687,8 +684,8 @@ static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, if (dev_attr->show) ret = dev_attr->show(dev, dev_attr, buf); if (ret >= (ssize_t)PAGE_SIZE) { - print_symbol("dev_attr_show: %s returned bad count\n", - (unsigned long)dev_attr->show); + printk("dev_attr_show: %pS returned bad count\n", + dev_attr->show); } return ret; } @@ -2116,7 +2113,7 @@ int device_for_each_child(struct device *parent, void *data, return 0; klist_iter_init(&parent->p->klist_children, &i); - while ((child = next_device(&i)) && !error) + while (!error && (child = next_device(&i))) error = fn(child, data); klist_iter_exit(&i); return error; diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index d99038487a0d..d21a2d913107 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * CPU subsystem support */ diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 2c964f56dafe..de6fd092bf2f 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * drivers/base/dd.c - The core device/driver interactions. * @@ -13,8 +14,6 @@ * Copyright (c) 2002-3 Open Source Development Labs * Copyright (c) 2007-2009 Greg Kroah-Hartman * Copyright (c) 2007-2009 Novell Inc. - * - * This file is released under the GPLv2 */ #include @@ -289,6 +288,18 @@ static void driver_bound(struct device *dev) kobject_uevent(&dev->kobj, KOBJ_BIND); } +static ssize_t coredump_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + device_lock(dev); + if (dev->driver->coredump) + dev->driver->coredump(dev); + device_unlock(dev); + + return count; +} +static DEVICE_ATTR_WO(coredump); + static int driver_sysfs_add(struct device *dev) { int ret; @@ -298,14 +309,26 @@ static int driver_sysfs_add(struct device *dev) BUS_NOTIFY_BIND_DRIVER, dev); ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj, + kobject_name(&dev->kobj)); + if (ret) + goto fail; + + ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj, + "driver"); + if (ret) + goto rm_dev; + + if (!IS_ENABLED(CONFIG_DEV_COREDUMP) || !dev->driver->coredump || + !device_create_file(dev, &dev_attr_coredump)) + return 0; + + sysfs_remove_link(&dev->kobj, "driver"); + +rm_dev: + sysfs_remove_link(&dev->driver->p->kobj, kobject_name(&dev->kobj)); - if (ret == 0) { - ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj, - "driver"); - if (ret) - sysfs_remove_link(&dev->driver->p->kobj, - kobject_name(&dev->kobj)); - } + +fail: return ret; } @@ -314,6 +337,8 @@ static void driver_sysfs_remove(struct device *dev) struct device_driver *drv = dev->driver; if (drv) { + if (drv->coredump) + device_remove_file(dev, &dev_attr_coredump); sysfs_remove_link(&drv->p->kobj, kobject_name(&dev->kobj)); sysfs_remove_link(&dev->kobj, "driver"); } diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c index 7be310f7db73..f1a3353f3494 100644 --- a/drivers/base/devcoredump.c +++ b/drivers/base/devcoredump.c @@ -1,23 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * This file is provided under the GPLv2 license. - * - * GPL LICENSE SUMMARY - * * Copyright(c) 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 Intel Deutschland GmbH * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License 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. - * - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 71d577025285..95b67281cd2a 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * drivers/base/devres.c - device resource management * * Copyright (c) 2006 SUSE Linux Products GmbH * Copyright (c) 2006 Tejun Heo - * - * This file is released under the GPLv2. */ #include diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index ea9726e71468..d987dcd1bd56 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Contiguous Memory Allocator for DMA mapping framework * Copyright (c) 2010-2011 by Samsung Electronics. * Written by: * Marek Szyprowski * Michal Nazarewicz - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License or (at your optional) any later version of the license. */ #define pr_fmt(fmt) "cma: " fmt diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c index e584eddef0a7..3b118353ea17 100644 --- a/drivers/base/dma-mapping.c +++ b/drivers/base/dma-mapping.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * drivers/base/dma-mapping.c - arch-independent dma-mapping routines * * Copyright (c) 2006 SUSE Linux Products GmbH * Copyright (c) 2006 Tejun Heo - * - * This file is released under the GPLv2. */ #include diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 4eabfe28d2b3..ba912558a510 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * driver.c - centralized device driver management * @@ -5,9 +6,6 @@ * Copyright (c) 2002-3 Open Source Development Labs * Copyright (c) 2007 Greg Kroah-Hartman * Copyright (c) 2007 Novell Inc. - * - * This file is released under the GPLv2 - * */ #include @@ -52,7 +50,7 @@ int driver_for_each_device(struct device_driver *drv, struct device *start, klist_iter_init_node(&drv->p->klist_devices, &i, start ? &start->p->knode_driver : NULL); - while ((dev = next_device(&i)) && !error) + while (!error && (dev = next_device(&i))) error = fn(dev, data); klist_iter_exit(&i); return error; diff --git a/drivers/base/firmware.c b/drivers/base/firmware.c index 113815556809..8dff940e0db9 100644 --- a/drivers/base/firmware.c +++ b/drivers/base/firmware.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * firmware.c - firmware subsystem hoohaw. * @@ -5,8 +6,6 @@ * Copyright (c) 2002-3 Open Source Development Labs * Copyright (c) 2007 Greg Kroah-Hartman * Copyright (c) 2007 Novell Inc. - * - * This file is released under the GPLv2 */ #include #include diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 4b57cf5bc81d..7dd36ace6152 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * firmware_class.c - Multi purpose firmware loading support * @@ -41,6 +42,96 @@ MODULE_AUTHOR("Manuel Estrada Sainz"); MODULE_DESCRIPTION("Multi purpose firmware loading support"); MODULE_LICENSE("GPL"); +enum fw_status { + FW_STATUS_UNKNOWN, + FW_STATUS_LOADING, + FW_STATUS_DONE, + FW_STATUS_ABORTED, +}; + +/* + * Concurrent request_firmware() for the same firmware need to be + * serialized. struct fw_state is simple state machine which hold the + * state of the firmware loading. + */ +struct fw_state { + struct completion completion; + enum fw_status status; +}; + +/* firmware behavior options */ +#define FW_OPT_UEVENT (1U << 0) +#define FW_OPT_NOWAIT (1U << 1) +#define FW_OPT_USERHELPER (1U << 2) +#define FW_OPT_NO_WARN (1U << 3) +#define FW_OPT_NOCACHE (1U << 4) +#define FW_OPT_NOFALLBACK (1U << 5) + +struct firmware_cache { + /* firmware_buf instance will be added into the below list */ + spinlock_t lock; + struct list_head head; + int state; + +#ifdef CONFIG_PM_SLEEP + /* + * Names of firmware images which have been cached successfully + * will be added into the below list so that device uncache + * helper can trace which firmware images have been cached + * before. + */ + spinlock_t name_lock; + struct list_head fw_names; + + struct delayed_work work; + + struct notifier_block pm_notify; +#endif +}; + +struct fw_priv { + struct kref ref; + struct list_head list; + struct firmware_cache *fwc; + struct fw_state fw_st; + void *data; + size_t size; + size_t allocated_size; +#ifdef CONFIG_FW_LOADER_USER_HELPER + bool is_paged_buf; + bool need_uevent; + struct page **pages; + int nr_pages; + int page_array_size; + struct list_head pending_list; +#endif + const char *fw_name; +}; + +struct fw_cache_entry { + struct list_head list; + const char *name; +}; + +struct fw_name_devm { + unsigned long magic; + const char *name; +}; + +static inline struct fw_priv *to_fw_priv(struct kref *ref) +{ + return container_of(ref, struct fw_priv, ref); +} + +#define FW_LOADER_NO_CACHE 0 +#define FW_LOADER_START_CACHE 1 + +/* fw_lock could be moved to 'struct fw_sysfs' but since it is just + * guarding for corner cases a global lock should be OK */ +static DEFINE_MUTEX(fw_lock); + +static struct firmware_cache fw_cache; + /* Builtin firmware support */ #ifdef CONFIG_FW_LOADER @@ -48,6 +139,14 @@ MODULE_LICENSE("GPL"); extern struct builtin_fw __start_builtin_fw[]; extern struct builtin_fw __end_builtin_fw[]; +static void fw_copy_to_prealloc_buf(struct firmware *fw, + void *buf, size_t size) +{ + if (!buf || size < fw->size) + return; + memcpy(buf, fw->data, fw->size); +} + static bool fw_get_builtin_firmware(struct firmware *fw, const char *name, void *buf, size_t size) { @@ -57,9 +156,8 @@ static bool fw_get_builtin_firmware(struct firmware *fw, const char *name, if (strcmp(name, b_fw->name) == 0) { fw->size = b_fw->size; fw->data = b_fw->data; + fw_copy_to_prealloc_buf(fw, buf, size); - if (buf && fw->size <= size) - memcpy(buf, fw->data, fw->size); return true; } } @@ -93,13 +191,6 @@ static inline bool fw_is_builtin_firmware(const struct firmware *fw) } #endif -enum fw_status { - FW_STATUS_UNKNOWN, - FW_STATUS_LOADING, - FW_STATUS_DONE, - FW_STATUS_ABORTED, -}; - static int loading_timeout = 60; /* In seconds */ static inline long firmware_loading_timeout(void) @@ -107,29 +198,17 @@ static inline long firmware_loading_timeout(void) return loading_timeout > 0 ? loading_timeout * HZ : MAX_JIFFY_OFFSET; } -/* - * Concurrent request_firmware() for the same firmware need to be - * serialized. struct fw_state is simple state machine which hold the - * state of the firmware loading. - */ -struct fw_state { - struct completion completion; - enum fw_status status; -}; - -static void fw_state_init(struct fw_state *fw_st) +static void fw_state_init(struct fw_priv *fw_priv) { + struct fw_state *fw_st = &fw_priv->fw_st; + init_completion(&fw_st->completion); fw_st->status = FW_STATUS_UNKNOWN; } -static inline bool __fw_state_is_done(enum fw_status status) -{ - return status == FW_STATUS_DONE || status == FW_STATUS_ABORTED; -} - -static int __fw_state_wait_common(struct fw_state *fw_st, long timeout) +static int __fw_state_wait_common(struct fw_priv *fw_priv, long timeout) { + struct fw_state *fw_st = &fw_priv->fw_st; long ret; ret = wait_for_completion_killable_timeout(&fw_st->completion, timeout); @@ -141,226 +220,172 @@ static int __fw_state_wait_common(struct fw_state *fw_st, long timeout) return ret < 0 ? ret : 0; } -static void __fw_state_set(struct fw_state *fw_st, +static void __fw_state_set(struct fw_priv *fw_priv, enum fw_status status) { + struct fw_state *fw_st = &fw_priv->fw_st; + WRITE_ONCE(fw_st->status, status); if (status == FW_STATUS_DONE || status == FW_STATUS_ABORTED) complete_all(&fw_st->completion); } -#define fw_state_start(fw_st) \ - __fw_state_set(fw_st, FW_STATUS_LOADING) -#define fw_state_done(fw_st) \ - __fw_state_set(fw_st, FW_STATUS_DONE) -#define fw_state_aborted(fw_st) \ - __fw_state_set(fw_st, FW_STATUS_ABORTED) -#define fw_state_wait(fw_st) \ - __fw_state_wait_common(fw_st, MAX_SCHEDULE_TIMEOUT) - -static int __fw_state_check(struct fw_state *fw_st, enum fw_status status) +static inline void fw_state_start(struct fw_priv *fw_priv) { + __fw_state_set(fw_priv, FW_STATUS_LOADING); +} + +static inline void fw_state_done(struct fw_priv *fw_priv) +{ + __fw_state_set(fw_priv, FW_STATUS_DONE); +} + +static inline void fw_state_aborted(struct fw_priv *fw_priv) +{ + __fw_state_set(fw_priv, FW_STATUS_ABORTED); +} + +static inline int fw_state_wait(struct fw_priv *fw_priv) +{ + return __fw_state_wait_common(fw_priv, MAX_SCHEDULE_TIMEOUT); +} + +static bool __fw_state_check(struct fw_priv *fw_priv, + enum fw_status status) +{ + struct fw_state *fw_st = &fw_priv->fw_st; + return fw_st->status == status; } -#define fw_state_is_aborted(fw_st) \ - __fw_state_check(fw_st, FW_STATUS_ABORTED) +static inline bool fw_state_is_aborted(struct fw_priv *fw_priv) +{ + return __fw_state_check(fw_priv, FW_STATUS_ABORTED); +} #ifdef CONFIG_FW_LOADER_USER_HELPER -#define fw_state_aborted(fw_st) \ - __fw_state_set(fw_st, FW_STATUS_ABORTED) -#define fw_state_is_done(fw_st) \ - __fw_state_check(fw_st, FW_STATUS_DONE) -#define fw_state_is_loading(fw_st) \ - __fw_state_check(fw_st, FW_STATUS_LOADING) -#define fw_state_wait_timeout(fw_st, timeout) \ - __fw_state_wait_common(fw_st, timeout) +static inline bool fw_sysfs_done(struct fw_priv *fw_priv) +{ + return __fw_state_check(fw_priv, FW_STATUS_DONE); +} + +static inline bool fw_sysfs_loading(struct fw_priv *fw_priv) +{ + return __fw_state_check(fw_priv, FW_STATUS_LOADING); +} + +static inline int fw_sysfs_wait_timeout(struct fw_priv *fw_priv, long timeout) +{ + return __fw_state_wait_common(fw_priv, timeout); +} #endif /* CONFIG_FW_LOADER_USER_HELPER */ -/* firmware behavior options */ -#define FW_OPT_UEVENT (1U << 0) -#define FW_OPT_NOWAIT (1U << 1) -#ifdef CONFIG_FW_LOADER_USER_HELPER -#define FW_OPT_USERHELPER (1U << 2) -#else -#define FW_OPT_USERHELPER 0 -#endif -#ifdef CONFIG_FW_LOADER_USER_HELPER_FALLBACK -#define FW_OPT_FALLBACK FW_OPT_USERHELPER -#else -#define FW_OPT_FALLBACK 0 -#endif -#define FW_OPT_NO_WARN (1U << 3) -#define FW_OPT_NOCACHE (1U << 4) - -struct firmware_cache { - /* firmware_buf instance will be added into the below list */ - spinlock_t lock; - struct list_head head; - int state; - -#ifdef CONFIG_PM_SLEEP - /* - * Names of firmware images which have been cached successfully - * will be added into the below list so that device uncache - * helper can trace which firmware images have been cached - * before. - */ - spinlock_t name_lock; - struct list_head fw_names; - - struct delayed_work work; - - struct notifier_block pm_notify; -#endif -}; - -struct firmware_buf { - struct kref ref; - struct list_head list; - struct firmware_cache *fwc; - struct fw_state fw_st; - void *data; - size_t size; - size_t allocated_size; -#ifdef CONFIG_FW_LOADER_USER_HELPER - bool is_paged_buf; - bool need_uevent; - struct page **pages; - int nr_pages; - int page_array_size; - struct list_head pending_list; -#endif - const char *fw_id; -}; - -struct fw_cache_entry { - struct list_head list; - const char *name; -}; - -struct fw_name_devm { - unsigned long magic; - const char *name; -}; - -#define to_fwbuf(d) container_of(d, struct firmware_buf, ref) - -#define FW_LOADER_NO_CACHE 0 -#define FW_LOADER_START_CACHE 1 - static int fw_cache_piggyback_on_request(const char *name); -/* fw_lock could be moved to 'struct firmware_priv' but since it is just - * guarding for corner cases a global lock should be OK */ -static DEFINE_MUTEX(fw_lock); - -static struct firmware_cache fw_cache; - -static struct firmware_buf *__allocate_fw_buf(const char *fw_name, - struct firmware_cache *fwc, - void *dbuf, size_t size) +static struct fw_priv *__allocate_fw_priv(const char *fw_name, + struct firmware_cache *fwc, + void *dbuf, size_t size) { - struct firmware_buf *buf; + struct fw_priv *fw_priv; - buf = kzalloc(sizeof(*buf), GFP_ATOMIC); - if (!buf) + fw_priv = kzalloc(sizeof(*fw_priv), GFP_ATOMIC); + if (!fw_priv) return NULL; - buf->fw_id = kstrdup_const(fw_name, GFP_ATOMIC); - if (!buf->fw_id) { - kfree(buf); + fw_priv->fw_name = kstrdup_const(fw_name, GFP_ATOMIC); + if (!fw_priv->fw_name) { + kfree(fw_priv); return NULL; } - kref_init(&buf->ref); - buf->fwc = fwc; - buf->data = dbuf; - buf->allocated_size = size; - fw_state_init(&buf->fw_st); + kref_init(&fw_priv->ref); + fw_priv->fwc = fwc; + fw_priv->data = dbuf; + fw_priv->allocated_size = size; + fw_state_init(fw_priv); #ifdef CONFIG_FW_LOADER_USER_HELPER - INIT_LIST_HEAD(&buf->pending_list); + INIT_LIST_HEAD(&fw_priv->pending_list); #endif - pr_debug("%s: fw-%s buf=%p\n", __func__, fw_name, buf); + pr_debug("%s: fw-%s fw_priv=%p\n", __func__, fw_name, fw_priv); - return buf; + return fw_priv; } -static struct firmware_buf *__fw_lookup_buf(const char *fw_name) +static struct fw_priv *__lookup_fw_priv(const char *fw_name) { - struct firmware_buf *tmp; + struct fw_priv *tmp; struct firmware_cache *fwc = &fw_cache; list_for_each_entry(tmp, &fwc->head, list) - if (!strcmp(tmp->fw_id, fw_name)) + if (!strcmp(tmp->fw_name, fw_name)) return tmp; return NULL; } /* Returns 1 for batching firmware requests with the same name */ -static int fw_lookup_and_allocate_buf(const char *fw_name, - struct firmware_cache *fwc, - struct firmware_buf **buf, void *dbuf, - size_t size) +static int alloc_lookup_fw_priv(const char *fw_name, + struct firmware_cache *fwc, + struct fw_priv **fw_priv, void *dbuf, + size_t size) { - struct firmware_buf *tmp; + struct fw_priv *tmp; spin_lock(&fwc->lock); - tmp = __fw_lookup_buf(fw_name); + tmp = __lookup_fw_priv(fw_name); if (tmp) { kref_get(&tmp->ref); spin_unlock(&fwc->lock); - *buf = tmp; - pr_debug("batched request - sharing the same struct firmware_buf and lookup for multiple requests\n"); + *fw_priv = tmp; + pr_debug("batched request - sharing the same struct fw_priv and lookup for multiple requests\n"); return 1; } - tmp = __allocate_fw_buf(fw_name, fwc, dbuf, size); + tmp = __allocate_fw_priv(fw_name, fwc, dbuf, size); if (tmp) list_add(&tmp->list, &fwc->head); spin_unlock(&fwc->lock); - *buf = tmp; + *fw_priv = tmp; return tmp ? 0 : -ENOMEM; } -static void __fw_free_buf(struct kref *ref) +static void __free_fw_priv(struct kref *ref) __releases(&fwc->lock) { - struct firmware_buf *buf = to_fwbuf(ref); - struct firmware_cache *fwc = buf->fwc; + struct fw_priv *fw_priv = to_fw_priv(ref); + struct firmware_cache *fwc = fw_priv->fwc; - pr_debug("%s: fw-%s buf=%p data=%p size=%u\n", - __func__, buf->fw_id, buf, buf->data, - (unsigned int)buf->size); + pr_debug("%s: fw-%s fw_priv=%p data=%p size=%u\n", + __func__, fw_priv->fw_name, fw_priv, fw_priv->data, + (unsigned int)fw_priv->size); - list_del(&buf->list); + list_del(&fw_priv->list); spin_unlock(&fwc->lock); #ifdef CONFIG_FW_LOADER_USER_HELPER - if (buf->is_paged_buf) { + if (fw_priv->is_paged_buf) { int i; - vunmap(buf->data); - for (i = 0; i < buf->nr_pages; i++) - __free_page(buf->pages[i]); - vfree(buf->pages); + vunmap(fw_priv->data); + for (i = 0; i < fw_priv->nr_pages; i++) + __free_page(fw_priv->pages[i]); + vfree(fw_priv->pages); } else #endif - if (!buf->allocated_size) - vfree(buf->data); - kfree_const(buf->fw_id); - kfree(buf); + if (!fw_priv->allocated_size) + vfree(fw_priv->data); + kfree_const(fw_priv->fw_name); + kfree(fw_priv); } -static void fw_free_buf(struct firmware_buf *buf) +static void free_fw_priv(struct fw_priv *fw_priv) { - struct firmware_cache *fwc = buf->fwc; + struct firmware_cache *fwc = fw_priv->fwc; spin_lock(&fwc->lock); - if (!kref_put(&buf->ref, __fw_free_buf)) + if (!kref_put(&fw_priv->ref, __free_fw_priv)) spin_unlock(&fwc->lock); } @@ -383,7 +408,7 @@ module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644); MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path"); static int -fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf) +fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv) { loff_t size; int i, len; @@ -393,9 +418,9 @@ fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf) size_t msize = INT_MAX; /* Already populated data member means we're loading into a buffer */ - if (buf->data) { + if (fw_priv->data) { id = READING_FIRMWARE_PREALLOC_BUFFER; - msize = buf->allocated_size; + msize = fw_priv->allocated_size; } path = __getname(); @@ -408,15 +433,15 @@ fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf) continue; len = snprintf(path, PATH_MAX, "%s/%s", - fw_path[i], buf->fw_id); + fw_path[i], fw_priv->fw_name); if (len >= PATH_MAX) { rc = -ENAMETOOLONG; break; } - buf->size = 0; - rc = kernel_read_file_from_path(path, &buf->data, &size, msize, - id); + fw_priv->size = 0; + rc = kernel_read_file_from_path(path, &fw_priv->data, &size, + msize, id); if (rc) { if (rc == -ENOENT) dev_dbg(device, "loading %s failed with error %d\n", @@ -426,9 +451,9 @@ fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf) path, rc); continue; } - dev_dbg(device, "direct-loading %s\n", buf->fw_id); - buf->size = size; - fw_state_done(&buf->fw_st); + dev_dbg(device, "direct-loading %s\n", fw_priv->fw_name); + fw_priv->size = size; + fw_state_done(fw_priv); break; } __putname(path); @@ -444,22 +469,22 @@ static void firmware_free_data(const struct firmware *fw) vfree(fw->data); return; } - fw_free_buf(fw->priv); + free_fw_priv(fw->priv); } /* store the pages buffer info firmware from buf */ -static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw) +static void fw_set_page_data(struct fw_priv *fw_priv, struct firmware *fw) { - fw->priv = buf; + fw->priv = fw_priv; #ifdef CONFIG_FW_LOADER_USER_HELPER - fw->pages = buf->pages; + fw->pages = fw_priv->pages; #endif - fw->size = buf->size; - fw->data = buf->data; + fw->size = fw_priv->size; + fw->data = fw_priv->data; - pr_debug("%s: fw-%s buf=%p data=%p size=%u\n", - __func__, buf->fw_id, buf, buf->data, - (unsigned int)buf->size); + pr_debug("%s: fw-%s fw_priv=%p data=%p size=%u\n", + __func__, fw_priv->fw_name, fw_priv, fw_priv->data, + (unsigned int)fw_priv->size); } #ifdef CONFIG_PM_SLEEP @@ -523,13 +548,13 @@ static int fw_add_devm_name(struct device *dev, const char *name) } #endif -static int assign_firmware_buf(struct firmware *fw, struct device *device, - unsigned int opt_flags) +static int assign_fw(struct firmware *fw, struct device *device, + unsigned int opt_flags) { - struct firmware_buf *buf = fw->priv; + struct fw_priv *fw_priv = fw->priv; mutex_lock(&fw_lock); - if (!buf->size || fw_state_is_aborted(&buf->fw_st)) { + if (!fw_priv->size || fw_state_is_aborted(fw_priv)) { mutex_unlock(&fw_lock); return -ENOENT; } @@ -544,20 +569,20 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device, /* don't cache firmware handled without uevent */ if (device && (opt_flags & FW_OPT_UEVENT) && !(opt_flags & FW_OPT_NOCACHE)) - fw_add_devm_name(device, buf->fw_id); + fw_add_devm_name(device, fw_priv->fw_name); /* * After caching firmware image is started, let it piggyback * on request firmware. */ if (!(opt_flags & FW_OPT_NOCACHE) && - buf->fwc->state == FW_LOADER_START_CACHE) { - if (fw_cache_piggyback_on_request(buf->fw_id)) - kref_get(&buf->ref); + fw_priv->fwc->state == FW_LOADER_START_CACHE) { + if (fw_cache_piggyback_on_request(fw_priv->fw_name)) + kref_get(&fw_priv->ref); } /* pass the pages buffer to driver at the last minute */ - fw_set_page_data(buf, fw); + fw_set_page_data(fw_priv, fw); mutex_unlock(&fw_lock); return 0; } @@ -566,49 +591,50 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device, * user-mode helper code */ #ifdef CONFIG_FW_LOADER_USER_HELPER -struct firmware_priv { +struct fw_sysfs { bool nowait; struct device dev; - struct firmware_buf *buf; + struct fw_priv *fw_priv; struct firmware *fw; }; -static struct firmware_priv *to_firmware_priv(struct device *dev) +static struct fw_sysfs *to_fw_sysfs(struct device *dev) { - return container_of(dev, struct firmware_priv, dev); + return container_of(dev, struct fw_sysfs, dev); } -static void __fw_load_abort(struct firmware_buf *buf) +static void __fw_load_abort(struct fw_priv *fw_priv) { /* * There is a small window in which user can write to 'loading' * between loading done and disappearance of 'loading' */ - if (fw_state_is_done(&buf->fw_st)) + if (fw_sysfs_done(fw_priv)) return; - list_del_init(&buf->pending_list); - fw_state_aborted(&buf->fw_st); + list_del_init(&fw_priv->pending_list); + fw_state_aborted(fw_priv); } -static void fw_load_abort(struct firmware_priv *fw_priv) +static void fw_load_abort(struct fw_sysfs *fw_sysfs) { - struct firmware_buf *buf = fw_priv->buf; + struct fw_priv *fw_priv = fw_sysfs->fw_priv; - __fw_load_abort(buf); + __fw_load_abort(fw_priv); } static LIST_HEAD(pending_fw_head); static void kill_pending_fw_fallback_reqs(bool only_kill_custom) { - struct firmware_buf *buf; - struct firmware_buf *next; + struct fw_priv *fw_priv; + struct fw_priv *next; mutex_lock(&fw_lock); - list_for_each_entry_safe(buf, next, &pending_fw_head, pending_list) { - if (!buf->need_uevent || !only_kill_custom) - __fw_load_abort(buf); + list_for_each_entry_safe(fw_priv, next, &pending_fw_head, + pending_list) { + if (!fw_priv->need_uevent || !only_kill_custom) + __fw_load_abort(fw_priv); } mutex_unlock(&fw_lock); } @@ -651,18 +677,18 @@ ATTRIBUTE_GROUPS(firmware_class); static void fw_dev_release(struct device *dev) { - struct firmware_priv *fw_priv = to_firmware_priv(dev); + struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); - kfree(fw_priv); + kfree(fw_sysfs); } -static int do_firmware_uevent(struct firmware_priv *fw_priv, struct kobj_uevent_env *env) +static int do_firmware_uevent(struct fw_sysfs *fw_sysfs, struct kobj_uevent_env *env) { - if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->buf->fw_id)) + if (add_uevent_var(env, "FIRMWARE=%s", fw_sysfs->fw_priv->fw_name)) return -ENOMEM; if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout)) return -ENOMEM; - if (add_uevent_var(env, "ASYNC=%d", fw_priv->nowait)) + if (add_uevent_var(env, "ASYNC=%d", fw_sysfs->nowait)) return -ENOMEM; return 0; @@ -670,12 +696,12 @@ static int do_firmware_uevent(struct firmware_priv *fw_priv, struct kobj_uevent_ static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) { - struct firmware_priv *fw_priv = to_firmware_priv(dev); + struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); int err = 0; mutex_lock(&fw_lock); - if (fw_priv->buf) - err = do_firmware_uevent(fw_priv, env); + if (fw_sysfs->fw_priv) + err = do_firmware_uevent(fw_sysfs, env); mutex_unlock(&fw_lock); return err; } @@ -687,15 +713,25 @@ static struct class firmware_class = { .dev_release = fw_dev_release, }; +static inline int register_sysfs_loader(void) +{ + return class_register(&firmware_class); +} + +static inline void unregister_sysfs_loader(void) +{ + class_unregister(&firmware_class); +} + static ssize_t firmware_loading_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct firmware_priv *fw_priv = to_firmware_priv(dev); + struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); int loading = 0; mutex_lock(&fw_lock); - if (fw_priv->buf) - loading = fw_state_is_loading(&fw_priv->buf->fw_st); + if (fw_sysfs->fw_priv) + loading = fw_sysfs_loading(fw_sysfs->fw_priv); mutex_unlock(&fw_lock); return sprintf(buf, "%d\n", loading); @@ -707,14 +743,15 @@ static ssize_t firmware_loading_show(struct device *dev, #endif /* one pages buffer should be mapped/unmapped only once */ -static int fw_map_pages_buf(struct firmware_buf *buf) +static int map_fw_priv_pages(struct fw_priv *fw_priv) { - if (!buf->is_paged_buf) + if (!fw_priv->is_paged_buf) return 0; - vunmap(buf->data); - buf->data = vmap(buf->pages, buf->nr_pages, 0, PAGE_KERNEL_RO); - if (!buf->data) + vunmap(fw_priv->data); + fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0, + PAGE_KERNEL_RO); + if (!fw_priv->data) return -ENOMEM; return 0; } @@ -736,32 +773,32 @@ static ssize_t firmware_loading_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct firmware_priv *fw_priv = to_firmware_priv(dev); - struct firmware_buf *fw_buf; + struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); + struct fw_priv *fw_priv; ssize_t written = count; int loading = simple_strtol(buf, NULL, 10); int i; mutex_lock(&fw_lock); - fw_buf = fw_priv->buf; - if (fw_state_is_aborted(&fw_buf->fw_st)) + fw_priv = fw_sysfs->fw_priv; + if (fw_state_is_aborted(fw_priv)) goto out; switch (loading) { case 1: /* discarding any previous partial load */ - if (!fw_state_is_done(&fw_buf->fw_st)) { - for (i = 0; i < fw_buf->nr_pages; i++) - __free_page(fw_buf->pages[i]); - vfree(fw_buf->pages); - fw_buf->pages = NULL; - fw_buf->page_array_size = 0; - fw_buf->nr_pages = 0; - fw_state_start(&fw_buf->fw_st); + if (!fw_sysfs_done(fw_priv)) { + for (i = 0; i < fw_priv->nr_pages; i++) + __free_page(fw_priv->pages[i]); + vfree(fw_priv->pages); + fw_priv->pages = NULL; + fw_priv->page_array_size = 0; + fw_priv->nr_pages = 0; + fw_state_start(fw_priv); } break; case 0: - if (fw_state_is_loading(&fw_buf->fw_st)) { + if (fw_sysfs_loading(fw_priv)) { int rc; /* @@ -770,25 +807,25 @@ static ssize_t firmware_loading_store(struct device *dev, * see the mapped 'buf->data' once the loading * is completed. * */ - rc = fw_map_pages_buf(fw_buf); + rc = map_fw_priv_pages(fw_priv); if (rc) dev_err(dev, "%s: map pages failed\n", __func__); else rc = security_kernel_post_read_file(NULL, - fw_buf->data, fw_buf->size, + fw_priv->data, fw_priv->size, READING_FIRMWARE); /* * Same logic as fw_load_abort, only the DONE bit * is ignored and we set ABORT only on failure. */ - list_del_init(&fw_buf->pending_list); + list_del_init(&fw_priv->pending_list); if (rc) { - fw_state_aborted(&fw_buf->fw_st); + fw_state_aborted(fw_priv); written = rc; } else { - fw_state_done(&fw_buf->fw_st); + fw_state_done(fw_priv); } break; } @@ -797,7 +834,7 @@ static ssize_t firmware_loading_store(struct device *dev, dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading); /* fallthrough */ case -1: - fw_load_abort(fw_priv); + fw_load_abort(fw_sysfs); break; } out: @@ -807,16 +844,16 @@ out: static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store); -static void firmware_rw_buf(struct firmware_buf *buf, char *buffer, +static void firmware_rw_data(struct fw_priv *fw_priv, char *buffer, loff_t offset, size_t count, bool read) { if (read) - memcpy(buffer, buf->data + offset, count); + memcpy(buffer, fw_priv->data + offset, count); else - memcpy(buf->data + offset, buffer, count); + memcpy(fw_priv->data + offset, buffer, count); } -static void firmware_rw(struct firmware_buf *buf, char *buffer, +static void firmware_rw(struct fw_priv *fw_priv, char *buffer, loff_t offset, size_t count, bool read) { while (count) { @@ -825,14 +862,14 @@ static void firmware_rw(struct firmware_buf *buf, char *buffer, int page_ofs = offset & (PAGE_SIZE-1); int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count); - page_data = kmap(buf->pages[page_nr]); + page_data = kmap(fw_priv->pages[page_nr]); if (read) memcpy(buffer, page_data + page_ofs, page_cnt); else memcpy(page_data + page_ofs, buffer, page_cnt); - kunmap(buf->pages[page_nr]); + kunmap(fw_priv->pages[page_nr]); buffer += page_cnt; offset += page_cnt; count -= page_cnt; @@ -844,69 +881,69 @@ static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj, char *buffer, loff_t offset, size_t count) { struct device *dev = kobj_to_dev(kobj); - struct firmware_priv *fw_priv = to_firmware_priv(dev); - struct firmware_buf *buf; + struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); + struct fw_priv *fw_priv; ssize_t ret_count; mutex_lock(&fw_lock); - buf = fw_priv->buf; - if (!buf || fw_state_is_done(&buf->fw_st)) { + fw_priv = fw_sysfs->fw_priv; + if (!fw_priv || fw_sysfs_done(fw_priv)) { ret_count = -ENODEV; goto out; } - if (offset > buf->size) { + if (offset > fw_priv->size) { ret_count = 0; goto out; } - if (count > buf->size - offset) - count = buf->size - offset; + if (count > fw_priv->size - offset) + count = fw_priv->size - offset; ret_count = count; - if (buf->data) - firmware_rw_buf(buf, buffer, offset, count, true); + if (fw_priv->data) + firmware_rw_data(fw_priv, buffer, offset, count, true); else - firmware_rw(buf, buffer, offset, count, true); + firmware_rw(fw_priv, buffer, offset, count, true); out: mutex_unlock(&fw_lock); return ret_count; } -static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size) +static int fw_realloc_pages(struct fw_sysfs *fw_sysfs, int min_size) { - struct firmware_buf *buf = fw_priv->buf; + struct fw_priv *fw_priv= fw_sysfs->fw_priv; int pages_needed = PAGE_ALIGN(min_size) >> PAGE_SHIFT; /* If the array of pages is too small, grow it... */ - if (buf->page_array_size < pages_needed) { + if (fw_priv->page_array_size < pages_needed) { int new_array_size = max(pages_needed, - buf->page_array_size * 2); + fw_priv->page_array_size * 2); struct page **new_pages; new_pages = vmalloc(new_array_size * sizeof(void *)); if (!new_pages) { - fw_load_abort(fw_priv); + fw_load_abort(fw_sysfs); return -ENOMEM; } - memcpy(new_pages, buf->pages, - buf->page_array_size * sizeof(void *)); - memset(&new_pages[buf->page_array_size], 0, sizeof(void *) * - (new_array_size - buf->page_array_size)); - vfree(buf->pages); - buf->pages = new_pages; - buf->page_array_size = new_array_size; + memcpy(new_pages, fw_priv->pages, + fw_priv->page_array_size * sizeof(void *)); + memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) * + (new_array_size - fw_priv->page_array_size)); + vfree(fw_priv->pages); + fw_priv->pages = new_pages; + fw_priv->page_array_size = new_array_size; } - while (buf->nr_pages < pages_needed) { - buf->pages[buf->nr_pages] = + while (fw_priv->nr_pages < pages_needed) { + fw_priv->pages[fw_priv->nr_pages] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); - if (!buf->pages[buf->nr_pages]) { - fw_load_abort(fw_priv); + if (!fw_priv->pages[fw_priv->nr_pages]) { + fw_load_abort(fw_sysfs); return -ENOMEM; } - buf->nr_pages++; + fw_priv->nr_pages++; } return 0; } @@ -928,37 +965,37 @@ static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj, char *buffer, loff_t offset, size_t count) { struct device *dev = kobj_to_dev(kobj); - struct firmware_priv *fw_priv = to_firmware_priv(dev); - struct firmware_buf *buf; + struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); + struct fw_priv *fw_priv; ssize_t retval; if (!capable(CAP_SYS_RAWIO)) return -EPERM; mutex_lock(&fw_lock); - buf = fw_priv->buf; - if (!buf || fw_state_is_done(&buf->fw_st)) { + fw_priv = fw_sysfs->fw_priv; + if (!fw_priv || fw_sysfs_done(fw_priv)) { retval = -ENODEV; goto out; } - if (buf->data) { - if (offset + count > buf->allocated_size) { + if (fw_priv->data) { + if (offset + count > fw_priv->allocated_size) { retval = -ENOMEM; goto out; } - firmware_rw_buf(buf, buffer, offset, count, false); + firmware_rw_data(fw_priv, buffer, offset, count, false); retval = count; } else { - retval = fw_realloc_buffer(fw_priv, offset + count); + retval = fw_realloc_pages(fw_sysfs, offset + count); if (retval) goto out; retval = count; - firmware_rw(buf, buffer, offset, count, false); + firmware_rw(fw_priv, buffer, offset, count, false); } - buf->size = max_t(size_t, offset + count, buf->size); + fw_priv->size = max_t(size_t, offset + count, fw_priv->size); out: mutex_unlock(&fw_lock); return retval; @@ -991,22 +1028,22 @@ static const struct attribute_group *fw_dev_attr_groups[] = { NULL }; -static struct firmware_priv * +static struct fw_sysfs * fw_create_instance(struct firmware *firmware, const char *fw_name, struct device *device, unsigned int opt_flags) { - struct firmware_priv *fw_priv; + struct fw_sysfs *fw_sysfs; struct device *f_dev; - fw_priv = kzalloc(sizeof(*fw_priv), GFP_KERNEL); - if (!fw_priv) { - fw_priv = ERR_PTR(-ENOMEM); + fw_sysfs = kzalloc(sizeof(*fw_sysfs), GFP_KERNEL); + if (!fw_sysfs) { + fw_sysfs = ERR_PTR(-ENOMEM); goto exit; } - fw_priv->nowait = !!(opt_flags & FW_OPT_NOWAIT); - fw_priv->fw = firmware; - f_dev = &fw_priv->dev; + fw_sysfs->nowait = !!(opt_flags & FW_OPT_NOWAIT); + fw_sysfs->fw = firmware; + f_dev = &fw_sysfs->dev; device_initialize(f_dev); dev_set_name(f_dev, "%s", fw_name); @@ -1014,20 +1051,20 @@ fw_create_instance(struct firmware *firmware, const char *fw_name, f_dev->class = &firmware_class; f_dev->groups = fw_dev_attr_groups; exit: - return fw_priv; + return fw_sysfs; } /* load a firmware via user helper */ -static int _request_firmware_load(struct firmware_priv *fw_priv, +static int _request_firmware_load(struct fw_sysfs *fw_sysfs, unsigned int opt_flags, long timeout) { int retval = 0; - struct device *f_dev = &fw_priv->dev; - struct firmware_buf *buf = fw_priv->buf; + struct device *f_dev = &fw_sysfs->dev; + struct fw_priv *fw_priv = fw_sysfs->fw_priv; /* fall back on userspace loading */ - if (!buf->data) - buf->is_paged_buf = true; + if (!fw_priv->data) + fw_priv->is_paged_buf = true; dev_set_uevent_suppress(f_dev, true); @@ -1038,31 +1075,31 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, } mutex_lock(&fw_lock); - list_add(&buf->pending_list, &pending_fw_head); + list_add(&fw_priv->pending_list, &pending_fw_head); mutex_unlock(&fw_lock); if (opt_flags & FW_OPT_UEVENT) { - buf->need_uevent = true; + fw_priv->need_uevent = true; dev_set_uevent_suppress(f_dev, false); - dev_dbg(f_dev, "firmware: requesting %s\n", buf->fw_id); - kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD); + dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_name); + kobject_uevent(&fw_sysfs->dev.kobj, KOBJ_ADD); } else { timeout = MAX_JIFFY_OFFSET; } - retval = fw_state_wait_timeout(&buf->fw_st, timeout); + retval = fw_sysfs_wait_timeout(fw_priv, timeout); if (retval < 0) { mutex_lock(&fw_lock); - fw_load_abort(fw_priv); + fw_load_abort(fw_sysfs); mutex_unlock(&fw_lock); } - if (fw_state_is_aborted(&buf->fw_st)) { + if (fw_state_is_aborted(fw_priv)) { if (retval == -ERESTARTSYS) retval = -EINTR; else retval = -EAGAIN; - } else if (buf->is_paged_buf && !buf->data) + } else if (fw_priv->is_paged_buf && !fw_priv->data) retval = -ENOMEM; device_del(f_dev); @@ -1075,7 +1112,7 @@ static int fw_load_from_user_helper(struct firmware *firmware, const char *name, struct device *device, unsigned int opt_flags) { - struct firmware_priv *fw_priv; + struct fw_sysfs *fw_sysfs; long timeout; int ret; @@ -1096,17 +1133,17 @@ static int fw_load_from_user_helper(struct firmware *firmware, } } - fw_priv = fw_create_instance(firmware, name, device, opt_flags); - if (IS_ERR(fw_priv)) { - ret = PTR_ERR(fw_priv); + fw_sysfs = fw_create_instance(firmware, name, device, opt_flags); + if (IS_ERR(fw_sysfs)) { + ret = PTR_ERR(fw_sysfs); goto out_unlock; } - fw_priv->buf = firmware->priv; - ret = _request_firmware_load(fw_priv, opt_flags, timeout); + fw_sysfs->fw_priv = firmware->priv; + ret = _request_firmware_load(fw_sysfs, opt_flags, timeout); if (!ret) - ret = assign_firmware_buf(firmware, device, opt_flags); + ret = assign_fw(firmware, device, opt_flags); out_unlock: usermodehelper_read_unlock(); @@ -1114,16 +1151,60 @@ out_unlock: return ret; } -#else /* CONFIG_FW_LOADER_USER_HELPER */ -static inline int -fw_load_from_user_helper(struct firmware *firmware, const char *name, - struct device *device, unsigned int opt_flags) +#ifdef CONFIG_FW_LOADER_USER_HELPER_FALLBACK +static bool fw_force_sysfs_fallback(unsigned int opt_flags) { - return -ENOENT; + return true; +} +#else +static bool fw_force_sysfs_fallback(unsigned int opt_flags) +{ + if (!(opt_flags & FW_OPT_USERHELPER)) + return false; + return true; +} +#endif + +static bool fw_run_sysfs_fallback(unsigned int opt_flags) +{ + if ((opt_flags & FW_OPT_NOFALLBACK)) + return false; + + return fw_force_sysfs_fallback(opt_flags); +} + +static int fw_sysfs_fallback(struct firmware *fw, const char *name, + struct device *device, + unsigned int opt_flags, + int ret) +{ + if (!fw_run_sysfs_fallback(opt_flags)) + return ret; + + dev_warn(device, "Falling back to user helper\n"); + return fw_load_from_user_helper(fw, name, device, opt_flags); +} +#else /* CONFIG_FW_LOADER_USER_HELPER */ +static int fw_sysfs_fallback(struct firmware *fw, const char *name, + struct device *device, + unsigned int opt_flags, + int ret) +{ + /* Keep carrying over the same error */ + return ret; } static inline void kill_pending_fw_fallback_reqs(bool only_kill_custom) { } +static inline int register_sysfs_loader(void) +{ + return 0; +} + +static inline void unregister_sysfs_loader(void) +{ +} + #endif /* CONFIG_FW_LOADER_USER_HELPER */ /* prepare firmware and firmware_buf structs; @@ -1135,7 +1216,7 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name, struct device *device, void *dbuf, size_t size) { struct firmware *firmware; - struct firmware_buf *buf; + struct fw_priv *fw_priv; int ret; *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL); @@ -1150,18 +1231,18 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name, return 0; /* assigned */ } - ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf, dbuf, size); + ret = alloc_lookup_fw_priv(name, &fw_cache, &fw_priv, dbuf, size); /* - * bind with 'buf' now to avoid warning in failure path + * bind with 'priv' now to avoid warning in failure path * of requesting firmware. */ - firmware->priv = buf; + firmware->priv = fw_priv; if (ret > 0) { - ret = fw_state_wait(&buf->fw_st); + ret = fw_state_wait(fw_priv); if (!ret) { - fw_set_page_data(buf, firmware); + fw_set_page_data(fw_priv, firmware); return 0; /* assigned */ } } @@ -1177,20 +1258,20 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name, * released until the last user calls release_firmware(). * * Failed batched requests are possible as well, in such cases we just share - * the struct firmware_buf and won't release it until all requests are woken + * the struct fw_priv and won't release it until all requests are woken * and have gone through this same path. */ static void fw_abort_batch_reqs(struct firmware *fw) { - struct firmware_buf *buf; + struct fw_priv *fw_priv; /* Loaded directly? */ if (!fw || !fw->priv) return; - buf = fw->priv; - if (!fw_state_is_aborted(&buf->fw_st)) - fw_state_aborted(&buf->fw_st); + fw_priv = fw->priv; + if (!fw_state_is_aborted(fw_priv)) + fw_state_aborted(fw_priv); } /* called from request_firmware() and request_firmware_work_func() */ @@ -1220,13 +1301,9 @@ _request_firmware(const struct firmware **firmware_p, const char *name, dev_warn(device, "Direct firmware load for %s failed with error %d\n", name, ret); - if (opt_flags & FW_OPT_USERHELPER) { - dev_warn(device, "Falling back to user helper\n"); - ret = fw_load_from_user_helper(fw, name, device, - opt_flags); - } + ret = fw_sysfs_fallback(fw, name, device, opt_flags, ret); } else - ret = assign_firmware_buf(fw, device, opt_flags); + ret = assign_fw(fw, device, opt_flags); out: if (ret < 0) { @@ -1268,7 +1345,7 @@ request_firmware(const struct firmware **firmware_p, const char *name, /* Need to pin this module until return */ __module_get(THIS_MODULE); ret = _request_firmware(firmware_p, name, device, NULL, 0, - FW_OPT_UEVENT | FW_OPT_FALLBACK); + FW_OPT_UEVENT); module_put(THIS_MODULE); return ret; } @@ -1292,7 +1369,8 @@ int request_firmware_direct(const struct firmware **firmware_p, __module_get(THIS_MODULE); ret = _request_firmware(firmware_p, name, device, NULL, 0, - FW_OPT_UEVENT | FW_OPT_NO_WARN); + FW_OPT_UEVENT | FW_OPT_NO_WARN | + FW_OPT_NOFALLBACK); module_put(THIS_MODULE); return ret; } @@ -1321,8 +1399,7 @@ request_firmware_into_buf(const struct firmware **firmware_p, const char *name, __module_get(THIS_MODULE); ret = _request_firmware(firmware_p, name, device, buf, size, - FW_OPT_UEVENT | FW_OPT_FALLBACK | - FW_OPT_NOCACHE); + FW_OPT_UEVENT | FW_OPT_NOCACHE); module_put(THIS_MODULE); return ret; } @@ -1414,7 +1491,7 @@ request_firmware_nowait( fw_work->device = device; fw_work->context = context; fw_work->cont = cont; - fw_work->opt_flags = FW_OPT_NOWAIT | FW_OPT_FALLBACK | + fw_work->opt_flags = FW_OPT_NOWAIT | (uevent ? FW_OPT_UEVENT : FW_OPT_USERHELPER); if (!try_module_get(module)) { @@ -1463,13 +1540,13 @@ static int cache_firmware(const char *fw_name) return ret; } -static struct firmware_buf *fw_lookup_buf(const char *fw_name) +static struct fw_priv *lookup_fw_priv(const char *fw_name) { - struct firmware_buf *tmp; + struct fw_priv *tmp; struct firmware_cache *fwc = &fw_cache; spin_lock(&fwc->lock); - tmp = __fw_lookup_buf(fw_name); + tmp = __lookup_fw_priv(fw_name); spin_unlock(&fwc->lock); return tmp; @@ -1488,7 +1565,7 @@ static struct firmware_buf *fw_lookup_buf(const char *fw_name) */ static int uncache_firmware(const char *fw_name) { - struct firmware_buf *buf; + struct fw_priv *fw_priv; struct firmware fw; pr_debug("%s: %s\n", __func__, fw_name); @@ -1496,9 +1573,9 @@ static int uncache_firmware(const char *fw_name) if (fw_get_builtin_firmware(&fw, fw_name, NULL, 0)) return 0; - buf = fw_lookup_buf(fw_name); - if (buf) { - fw_free_buf(buf); + fw_priv = lookup_fw_priv(fw_name); + if (fw_priv) { + free_fw_priv(fw_priv); return 0; } @@ -1767,11 +1844,44 @@ static int fw_suspend(void) static struct syscore_ops fw_syscore_ops = { .suspend = fw_suspend, }; + +static int __init register_fw_pm_ops(void) +{ + int ret; + + spin_lock_init(&fw_cache.name_lock); + INIT_LIST_HEAD(&fw_cache.fw_names); + + INIT_DELAYED_WORK(&fw_cache.work, + device_uncache_fw_images_work); + + fw_cache.pm_notify.notifier_call = fw_pm_notify; + ret = register_pm_notifier(&fw_cache.pm_notify); + if (ret) + return ret; + + register_syscore_ops(&fw_syscore_ops); + + return ret; +} + +static inline void unregister_fw_pm_ops(void) +{ + unregister_syscore_ops(&fw_syscore_ops); + unregister_pm_notifier(&fw_cache.pm_notify); +} #else static int fw_cache_piggyback_on_request(const char *name) { return 0; } +static inline int register_fw_pm_ops(void) +{ + return 0; +} +static inline void unregister_fw_pm_ops(void) +{ +} #endif static void __init fw_cache_init(void) @@ -1779,19 +1889,6 @@ static void __init fw_cache_init(void) spin_lock_init(&fw_cache.lock); INIT_LIST_HEAD(&fw_cache.head); fw_cache.state = FW_LOADER_NO_CACHE; - -#ifdef CONFIG_PM_SLEEP - spin_lock_init(&fw_cache.name_lock); - INIT_LIST_HEAD(&fw_cache.fw_names); - - INIT_DELAYED_WORK(&fw_cache.work, - device_uncache_fw_images_work); - - fw_cache.pm_notify.notifier_call = fw_pm_notify; - register_pm_notifier(&fw_cache.pm_notify); - - register_syscore_ops(&fw_syscore_ops); -#endif } static int fw_shutdown_notify(struct notifier_block *unused1, @@ -1812,25 +1909,31 @@ static struct notifier_block fw_shutdown_nb = { static int __init firmware_class_init(void) { + int ret; + + /* No need to unfold these on exit */ fw_cache_init(); - register_reboot_notifier(&fw_shutdown_nb); -#ifdef CONFIG_FW_LOADER_USER_HELPER - return class_register(&firmware_class); -#else - return 0; -#endif + + ret = register_fw_pm_ops(); + if (ret) + return ret; + + ret = register_reboot_notifier(&fw_shutdown_nb); + if (ret) + goto out; + + return register_sysfs_loader(); + +out: + unregister_fw_pm_ops(); + return ret; } static void __exit firmware_class_exit(void) { -#ifdef CONFIG_PM_SLEEP - unregister_syscore_ops(&fw_syscore_ops); - unregister_pm_notifier(&fw_cache.pm_notify); -#endif + unregister_fw_pm_ops(); unregister_reboot_notifier(&fw_shutdown_nb); -#ifdef CONFIG_FW_LOADER_USER_HELPER - class_unregister(&firmware_class); -#endif + unregister_sysfs_loader(); } fs_initcall(firmware_class_init); diff --git a/drivers/base/hypervisor.c b/drivers/base/hypervisor.c index 4f8b741f4615..1ce59b4b53ce 100644 --- a/drivers/base/hypervisor.c +++ b/drivers/base/hypervisor.c @@ -1,11 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * hypervisor.c - /sys/hypervisor subsystem. * * Copyright (C) IBM Corp. 2006 * Copyright (C) 2007 Greg Kroah-Hartman * Copyright (C) 2007 Novell Inc. - * - * This file is released under the GPLv2 */ #include diff --git a/drivers/base/init.c b/drivers/base/init.c index 48c0e220acc0..dd85b05a6a16 100644 --- a/drivers/base/init.c +++ b/drivers/base/init.c @@ -1,8 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs - * - * This file is released under the GPLv2 */ #include diff --git a/drivers/base/isa.c b/drivers/base/isa.c index 372d10af2600..2772f5d1948a 100644 --- a/drivers/base/isa.c +++ b/drivers/base/isa.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * ISA bus. */ diff --git a/drivers/base/map.c b/drivers/base/map.c index c1d38234d725..5650ab2b247a 100644 --- a/drivers/base/map.c +++ b/drivers/base/map.c @@ -1,8 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * linux/drivers/base/map.c * * (C) Copyright Al Viro 2002,2003 - * Released under GPL v2. * * NOTE: data structure needs to be changed. It works, but for large dev_t * it will be too slow. It is isolated, though, so these changes will be diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 1d60b58a8c19..fe4b24f05f6a 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -569,7 +569,7 @@ store_hard_offline_page(struct device *dev, if (kstrtoull(buf, 0, &pfn) < 0) return -EINVAL; pfn >>= PAGE_SHIFT; - ret = memory_failure(pfn, 0, 0); + ret = memory_failure(pfn, 0); return ret ? ret : count; } diff --git a/drivers/base/module.c b/drivers/base/module.c index 2a215780eda2..46ad4d636731 100644 --- a/drivers/base/module.c +++ b/drivers/base/module.c @@ -1,8 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * module.c - module sysfs fun for drivers - * - * This file is released under the GPLv2 - * */ #include #include diff --git a/drivers/base/pinctrl.c b/drivers/base/pinctrl.c index eb929dd6ef1e..c22864458511 100644 --- a/drivers/base/pinctrl.c +++ b/drivers/base/pinctrl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Driver core interface to the pinctrl subsystem. * @@ -6,8 +7,6 @@ * Based on bits of regulator core, gpio core and clk core * * Author: Linus Walleij - * - * License terms: GNU General Public License (GPL) version 2 */ #include diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c index e5473525e7b2..8e22073aeeed 100644 --- a/drivers/base/platform-msi.c +++ b/drivers/base/platform-msi.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * MSI framework for platform devices * * Copyright (C) 2015 ARM Limited, All Rights Reserved. * Author: Marc Zyngier - * - * 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 . */ #include diff --git a/drivers/base/platform.c b/drivers/base/platform.c index c203fb90c1a0..f1bf7b38d91c 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -1,11 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * platform.c - platform 'pseudo' bus for legacy devices * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs * - * This file is released under the GPLv2 - * * Please see Documentation/driver-model/platform.txt for more * information. */ diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 0c80bea05bcb..1ea0e2502e8e 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1032,15 +1032,12 @@ static int genpd_prepare(struct device *dev) static int genpd_finish_suspend(struct device *dev, bool poweroff) { struct generic_pm_domain *genpd; - int ret; + int ret = 0; genpd = dev_to_genpd(dev); if (IS_ERR(genpd)) return -EINVAL; - if (dev->power.wakeup_path && genpd_is_active_wakeup(genpd)) - return 0; - if (poweroff) ret = pm_generic_poweroff_noirq(dev); else @@ -1048,10 +1045,19 @@ static int genpd_finish_suspend(struct device *dev, bool poweroff) if (ret) return ret; - if (genpd->dev_ops.stop && genpd->dev_ops.start) { - ret = pm_runtime_force_suspend(dev); - if (ret) + if (dev->power.wakeup_path && genpd_is_active_wakeup(genpd)) + return 0; + + if (genpd->dev_ops.stop && genpd->dev_ops.start && + !pm_runtime_status_suspended(dev)) { + ret = genpd_stop_dev(genpd, dev); + if (ret) { + if (poweroff) + pm_generic_restore_noirq(dev); + else + pm_generic_resume_noirq(dev); return ret; + } } genpd_lock(genpd); @@ -1085,7 +1091,7 @@ static int genpd_suspend_noirq(struct device *dev) static int genpd_resume_noirq(struct device *dev) { struct generic_pm_domain *genpd; - int ret = 0; + int ret; dev_dbg(dev, "%s()\n", __func__); @@ -1094,21 +1100,21 @@ static int genpd_resume_noirq(struct device *dev) return -EINVAL; if (dev->power.wakeup_path && genpd_is_active_wakeup(genpd)) - return 0; + return pm_generic_resume_noirq(dev); genpd_lock(genpd); genpd_sync_power_on(genpd, true, 0); genpd->suspended_count--; genpd_unlock(genpd); - if (genpd->dev_ops.stop && genpd->dev_ops.start) - ret = pm_runtime_force_resume(dev); + if (genpd->dev_ops.stop && genpd->dev_ops.start && + !pm_runtime_status_suspended(dev)) { + ret = genpd_start_dev(genpd, dev); + if (ret) + return ret; + } - ret = pm_generic_resume_noirq(dev); - if (ret) - return ret; - - return ret; + return pm_generic_resume_noirq(dev); } /** @@ -1135,8 +1141,9 @@ static int genpd_freeze_noirq(struct device *dev) if (ret) return ret; - if (genpd->dev_ops.stop && genpd->dev_ops.start) - ret = pm_runtime_force_suspend(dev); + if (genpd->dev_ops.stop && genpd->dev_ops.start && + !pm_runtime_status_suspended(dev)) + ret = genpd_stop_dev(genpd, dev); return ret; } @@ -1159,8 +1166,9 @@ static int genpd_thaw_noirq(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - if (genpd->dev_ops.stop && genpd->dev_ops.start) { - ret = pm_runtime_force_resume(dev); + if (genpd->dev_ops.stop && genpd->dev_ops.start && + !pm_runtime_status_suspended(dev)) { + ret = genpd_start_dev(genpd, dev); if (ret) return ret; } @@ -1217,8 +1225,9 @@ static int genpd_restore_noirq(struct device *dev) genpd_sync_power_on(genpd, true, 0); genpd_unlock(genpd); - if (genpd->dev_ops.stop && genpd->dev_ops.start) { - ret = pm_runtime_force_resume(dev); + if (genpd->dev_ops.stop && genpd->dev_ops.start && + !pm_runtime_status_suspended(dev)) { + ret = genpd_start_dev(genpd, dev); if (ret) return ret; } @@ -2199,20 +2208,8 @@ int genpd_dev_pm_attach(struct device *dev) ret = of_parse_phandle_with_args(dev->of_node, "power-domains", "#power-domain-cells", 0, &pd_args); - if (ret < 0) { - if (ret != -ENOENT) - return ret; - - /* - * Try legacy Samsung-specific bindings - * (for backwards compatibility of DT ABI) - */ - pd_args.args_count = 0; - pd_args.np = of_parse_phandle(dev->of_node, - "samsung,power-domain", 0); - if (!pd_args.np) - return -ENOENT; - } + if (ret < 0) + return ret; mutex_lock(&gpd_list_lock); pd = genpd_get_from_provider(&pd_args); @@ -2293,6 +2290,38 @@ static int genpd_parse_state(struct genpd_power_state *genpd_state, return 0; } +static int genpd_iterate_idle_states(struct device_node *dn, + struct genpd_power_state *states) +{ + int ret; + struct of_phandle_iterator it; + struct device_node *np; + int i = 0; + + ret = of_count_phandle_with_args(dn, "domain-idle-states", NULL); + if (ret <= 0) + return ret; + + /* Loop over the phandles until all the requested entry is found */ + of_for_each_phandle(&it, ret, dn, "domain-idle-states", NULL, 0) { + np = it.node; + if (!of_match_node(idle_state_match, np)) + continue; + if (states) { + ret = genpd_parse_state(&states[i], np); + if (ret) { + pr_err("Parsing idle state node %pOF failed with err %d\n", + np, ret); + of_node_put(np); + return ret; + } + } + i++; + } + + return i; +} + /** * of_genpd_parse_idle_states: Return array of idle states for the genpd. * @@ -2302,49 +2331,31 @@ static int genpd_parse_state(struct genpd_power_state *genpd_state, * * Returns the device states parsed from the OF node. The memory for the states * is allocated by this function and is the responsibility of the caller to - * free the memory after use. + * free the memory after use. If no domain idle states is found it returns + * -EINVAL and in case of errors, a negative error code. */ int of_genpd_parse_idle_states(struct device_node *dn, struct genpd_power_state **states, int *n) { struct genpd_power_state *st; - struct device_node *np; - int i = 0; - int err, ret; - int count; - struct of_phandle_iterator it; - const struct of_device_id *match_id; + int ret; - count = of_count_phandle_with_args(dn, "domain-idle-states", NULL); - if (count <= 0) - return -EINVAL; + ret = genpd_iterate_idle_states(dn, NULL); + if (ret <= 0) + return ret < 0 ? ret : -EINVAL; - st = kcalloc(count, sizeof(*st), GFP_KERNEL); + st = kcalloc(ret, sizeof(*st), GFP_KERNEL); if (!st) return -ENOMEM; - /* Loop over the phandles until all the requested entry is found */ - of_for_each_phandle(&it, err, dn, "domain-idle-states", NULL, 0) { - np = it.node; - match_id = of_match_node(idle_state_match, np); - if (!match_id) - continue; - ret = genpd_parse_state(&st[i++], np); - if (ret) { - pr_err - ("Parsing idle state node %pOF failed with err %d\n", - np, ret); - of_node_put(np); - kfree(st); - return ret; - } + ret = genpd_iterate_idle_states(dn, st); + if (ret <= 0) { + kfree(st); + return ret < 0 ? ret : -EINVAL; } - *n = i; - if (!i) - kfree(st); - else - *states = st; + *states = st; + *n = ret; return 0; } diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 08744b572af6..02a497e7c785 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -541,30 +540,41 @@ void dev_pm_skip_next_resume_phases(struct device *dev) } /** - * device_resume_noirq - Execute a "noirq resume" callback for given device. - * @dev: Device to handle. - * @state: PM transition of the system being carried out. - * @async: If true, the device is being resumed asynchronously. - * - * The driver of @dev will not receive interrupts while this function is being - * executed. + * suspend_event - Return a "suspend" message for given "resume" one. + * @resume_msg: PM message representing a system-wide resume transition. */ -static int device_resume_noirq(struct device *dev, pm_message_t state, bool async) +static pm_message_t suspend_event(pm_message_t resume_msg) { - pm_callback_t callback = NULL; - const char *info = NULL; - int error = 0; + switch (resume_msg.event) { + case PM_EVENT_RESUME: + return PMSG_SUSPEND; + case PM_EVENT_THAW: + case PM_EVENT_RESTORE: + return PMSG_FREEZE; + case PM_EVENT_RECOVER: + return PMSG_HIBERNATE; + } + return PMSG_ON; +} - TRACE_DEVICE(dev); - TRACE_RESUME(0); +/** + * dev_pm_may_skip_resume - System-wide device resume optimization check. + * @dev: Target device. + * + * Checks whether or not the device may be left in suspend after a system-wide + * transition to the working state. + */ +bool dev_pm_may_skip_resume(struct device *dev) +{ + return !dev->power.must_resume && pm_transition.event != PM_EVENT_RESTORE; +} - if (dev->power.syscore || dev->power.direct_complete) - goto Out; - - if (!dev->power.is_noirq_suspended) - goto Out; - - dpm_wait_for_superior(dev, async); +static pm_callback_t dpm_subsys_resume_noirq_cb(struct device *dev, + pm_message_t state, + const char **info_p) +{ + pm_callback_t callback; + const char *info; if (dev->pm_domain) { info = "noirq power domain "; @@ -578,17 +588,106 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn } else if (dev->bus && dev->bus->pm) { info = "noirq bus "; callback = pm_noirq_op(dev->bus->pm, state); + } else { + return NULL; } - if (!callback && dev->driver && dev->driver->pm) { + if (info_p) + *info_p = info; + + return callback; +} + +static pm_callback_t dpm_subsys_suspend_noirq_cb(struct device *dev, + pm_message_t state, + const char **info_p); + +static pm_callback_t dpm_subsys_suspend_late_cb(struct device *dev, + pm_message_t state, + const char **info_p); + +/** + * device_resume_noirq - Execute a "noirq resume" callback for given device. + * @dev: Device to handle. + * @state: PM transition of the system being carried out. + * @async: If true, the device is being resumed asynchronously. + * + * The driver of @dev will not receive interrupts while this function is being + * executed. + */ +static int device_resume_noirq(struct device *dev, pm_message_t state, bool async) +{ + pm_callback_t callback; + const char *info; + bool skip_resume; + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); + + if (dev->power.syscore || dev->power.direct_complete) + goto Out; + + if (!dev->power.is_noirq_suspended) + goto Out; + + dpm_wait_for_superior(dev, async); + + skip_resume = dev_pm_may_skip_resume(dev); + + callback = dpm_subsys_resume_noirq_cb(dev, state, &info); + if (callback) + goto Run; + + if (skip_resume) + goto Skip; + + if (dev_pm_smart_suspend_and_suspended(dev)) { + pm_message_t suspend_msg = suspend_event(state); + + /* + * If "freeze" callbacks have been skipped during a transition + * related to hibernation, the subsequent "thaw" callbacks must + * be skipped too or bad things may happen. Otherwise, resume + * callbacks are going to be run for the device, so its runtime + * PM status must be changed to reflect the new state after the + * transition under way. + */ + if (!dpm_subsys_suspend_late_cb(dev, suspend_msg, NULL) && + !dpm_subsys_suspend_noirq_cb(dev, suspend_msg, NULL)) { + if (state.event == PM_EVENT_THAW) { + skip_resume = true; + goto Skip; + } else { + pm_runtime_set_active(dev); + } + } + } + + if (dev->driver && dev->driver->pm) { info = "noirq driver "; callback = pm_noirq_op(dev->driver->pm, state); } +Run: error = dpm_run_callback(callback, dev, state, info); + +Skip: dev->power.is_noirq_suspended = false; - Out: + if (skip_resume) { + /* + * The device is going to be left in suspend, but it might not + * have been in runtime suspend before the system suspended, so + * its runtime PM status needs to be updated to avoid confusing + * the runtime PM framework when runtime PM is enabled for the + * device again. + */ + pm_runtime_set_suspended(dev); + dev_pm_skip_next_resume_phases(dev); + } + +Out: complete_all(&dev->power.completion); TRACE_RESUME(error); return error; @@ -681,30 +780,12 @@ void dpm_resume_noirq(pm_message_t state) dpm_noirq_end(); } -/** - * device_resume_early - Execute an "early resume" callback for given device. - * @dev: Device to handle. - * @state: PM transition of the system being carried out. - * @async: If true, the device is being resumed asynchronously. - * - * Runtime PM is disabled for @dev while this function is being executed. - */ -static int device_resume_early(struct device *dev, pm_message_t state, bool async) +static pm_callback_t dpm_subsys_resume_early_cb(struct device *dev, + pm_message_t state, + const char **info_p) { - pm_callback_t callback = NULL; - const char *info = NULL; - int error = 0; - - TRACE_DEVICE(dev); - TRACE_RESUME(0); - - if (dev->power.syscore || dev->power.direct_complete) - goto Out; - - if (!dev->power.is_late_suspended) - goto Out; - - dpm_wait_for_superior(dev, async); + pm_callback_t callback; + const char *info; if (dev->pm_domain) { info = "early power domain "; @@ -718,8 +799,43 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn } else if (dev->bus && dev->bus->pm) { info = "early bus "; callback = pm_late_early_op(dev->bus->pm, state); + } else { + return NULL; } + if (info_p) + *info_p = info; + + return callback; +} + +/** + * device_resume_early - Execute an "early resume" callback for given device. + * @dev: Device to handle. + * @state: PM transition of the system being carried out. + * @async: If true, the device is being resumed asynchronously. + * + * Runtime PM is disabled for @dev while this function is being executed. + */ +static int device_resume_early(struct device *dev, pm_message_t state, bool async) +{ + pm_callback_t callback; + const char *info; + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); + + if (dev->power.syscore || dev->power.direct_complete) + goto Out; + + if (!dev->power.is_late_suspended) + goto Out; + + dpm_wait_for_superior(dev, async); + + callback = dpm_subsys_resume_early_cb(dev, state, &info); + if (!callback && dev->driver && dev->driver->pm) { info = "early driver "; callback = pm_late_early_op(dev->driver->pm, state); @@ -1089,6 +1205,77 @@ static pm_message_t resume_event(pm_message_t sleep_state) return PMSG_ON; } +static void dpm_superior_set_must_resume(struct device *dev) +{ + struct device_link *link; + int idx; + + if (dev->parent) + dev->parent->power.must_resume = true; + + idx = device_links_read_lock(); + + list_for_each_entry_rcu(link, &dev->links.suppliers, c_node) + link->supplier->power.must_resume = true; + + device_links_read_unlock(idx); +} + +static pm_callback_t dpm_subsys_suspend_noirq_cb(struct device *dev, + pm_message_t state, + const char **info_p) +{ + pm_callback_t callback; + const char *info; + + if (dev->pm_domain) { + info = "noirq power domain "; + callback = pm_noirq_op(&dev->pm_domain->ops, state); + } else if (dev->type && dev->type->pm) { + info = "noirq type "; + callback = pm_noirq_op(dev->type->pm, state); + } else if (dev->class && dev->class->pm) { + info = "noirq class "; + callback = pm_noirq_op(dev->class->pm, state); + } else if (dev->bus && dev->bus->pm) { + info = "noirq bus "; + callback = pm_noirq_op(dev->bus->pm, state); + } else { + return NULL; + } + + if (info_p) + *info_p = info; + + return callback; +} + +static bool device_must_resume(struct device *dev, pm_message_t state, + bool no_subsys_suspend_noirq) +{ + pm_message_t resume_msg = resume_event(state); + + /* + * If all of the device driver's "noirq", "late" and "early" callbacks + * are invoked directly by the core, the decision to allow the device to + * stay in suspend can be based on its current runtime PM status and its + * wakeup settings. + */ + if (no_subsys_suspend_noirq && + !dpm_subsys_suspend_late_cb(dev, state, NULL) && + !dpm_subsys_resume_early_cb(dev, resume_msg, NULL) && + !dpm_subsys_resume_noirq_cb(dev, resume_msg, NULL)) + return !pm_runtime_status_suspended(dev) && + (resume_msg.event != PM_EVENT_RESUME || + (device_can_wakeup(dev) && !device_may_wakeup(dev))); + + /* + * The only safe strategy here is to require that if the device may not + * be left in suspend, resume callbacks must be invoked for it. + */ + return !dev->power.may_skip_resume; +} + /** * __device_suspend_noirq - Execute a "noirq suspend" callback for given device. * @dev: Device to handle. @@ -1100,8 +1287,9 @@ static pm_message_t resume_event(pm_message_t sleep_state) */ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool async) { - pm_callback_t callback = NULL; - const char *info = NULL; + pm_callback_t callback; + const char *info; + bool no_subsys_cb = false; int error = 0; TRACE_DEVICE(dev); @@ -1120,30 +1308,40 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a if (dev->power.syscore || dev->power.direct_complete) goto Complete; - if (dev->pm_domain) { - info = "noirq power domain "; - callback = pm_noirq_op(&dev->pm_domain->ops, state); - } else if (dev->type && dev->type->pm) { - info = "noirq type "; - callback = pm_noirq_op(dev->type->pm, state); - } else if (dev->class && dev->class->pm) { - info = "noirq class "; - callback = pm_noirq_op(dev->class->pm, state); - } else if (dev->bus && dev->bus->pm) { - info = "noirq bus "; - callback = pm_noirq_op(dev->bus->pm, state); - } + callback = dpm_subsys_suspend_noirq_cb(dev, state, &info); + if (callback) + goto Run; - if (!callback && dev->driver && dev->driver->pm) { + no_subsys_cb = !dpm_subsys_suspend_late_cb(dev, state, NULL); + + if (dev_pm_smart_suspend_and_suspended(dev) && no_subsys_cb) + goto Skip; + + if (dev->driver && dev->driver->pm) { info = "noirq driver "; callback = pm_noirq_op(dev->driver->pm, state); } +Run: error = dpm_run_callback(callback, dev, state, info); - if (!error) - dev->power.is_noirq_suspended = true; - else + if (error) { async_error = error; + goto Complete; + } + +Skip: + dev->power.is_noirq_suspended = true; + + if (dev_pm_test_driver_flags(dev, DPM_FLAG_LEAVE_SUSPENDED)) { + dev->power.must_resume = dev->power.must_resume || + atomic_read(&dev->power.usage_count) > 1 || + device_must_resume(dev, state, no_subsys_cb); + } else { + dev->power.must_resume = true; + } + + if (dev->power.must_resume) + dpm_superior_set_must_resume(dev); Complete: complete_all(&dev->power.completion); @@ -1249,6 +1447,50 @@ int dpm_suspend_noirq(pm_message_t state) return ret; } +static void dpm_propagate_wakeup_to_parent(struct device *dev) +{ + struct device *parent = dev->parent; + + if (!parent) + return; + + spin_lock_irq(&parent->power.lock); + + if (dev->power.wakeup_path && !parent->power.ignore_children) + parent->power.wakeup_path = true; + + spin_unlock_irq(&parent->power.lock); +} + +static pm_callback_t dpm_subsys_suspend_late_cb(struct device *dev, + pm_message_t state, + const char **info_p) +{ + pm_callback_t callback; + const char *info; + + if (dev->pm_domain) { + info = "late power domain "; + callback = pm_late_early_op(&dev->pm_domain->ops, state); + } else if (dev->type && dev->type->pm) { + info = "late type "; + callback = pm_late_early_op(dev->type->pm, state); + } else if (dev->class && dev->class->pm) { + info = "late class "; + callback = pm_late_early_op(dev->class->pm, state); + } else if (dev->bus && dev->bus->pm) { + info = "late bus "; + callback = pm_late_early_op(dev->bus->pm, state); + } else { + return NULL; + } + + if (info_p) + *info_p = info; + + return callback; +} + /** * __device_suspend_late - Execute a "late suspend" callback for given device. * @dev: Device to handle. @@ -1259,8 +1501,8 @@ int dpm_suspend_noirq(pm_message_t state) */ static int __device_suspend_late(struct device *dev, pm_message_t state, bool async) { - pm_callback_t callback = NULL; - const char *info = NULL; + pm_callback_t callback; + const char *info; int error = 0; TRACE_DEVICE(dev); @@ -1281,30 +1523,29 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as if (dev->power.syscore || dev->power.direct_complete) goto Complete; - if (dev->pm_domain) { - info = "late power domain "; - callback = pm_late_early_op(&dev->pm_domain->ops, state); - } else if (dev->type && dev->type->pm) { - info = "late type "; - callback = pm_late_early_op(dev->type->pm, state); - } else if (dev->class && dev->class->pm) { - info = "late class "; - callback = pm_late_early_op(dev->class->pm, state); - } else if (dev->bus && dev->bus->pm) { - info = "late bus "; - callback = pm_late_early_op(dev->bus->pm, state); - } + callback = dpm_subsys_suspend_late_cb(dev, state, &info); + if (callback) + goto Run; - if (!callback && dev->driver && dev->driver->pm) { + if (dev_pm_smart_suspend_and_suspended(dev) && + !dpm_subsys_suspend_noirq_cb(dev, state, NULL)) + goto Skip; + + if (dev->driver && dev->driver->pm) { info = "late driver "; callback = pm_late_early_op(dev->driver->pm, state); } +Run: error = dpm_run_callback(callback, dev, state, info); - if (!error) - dev->power.is_late_suspended = true; - else + if (error) { async_error = error; + goto Complete; + } + dpm_propagate_wakeup_to_parent(dev); + +Skip: + dev->power.is_late_suspended = true; Complete: TRACE_SUSPEND(error); @@ -1435,11 +1676,17 @@ static int legacy_suspend(struct device *dev, pm_message_t state, return error; } -static void dpm_clear_suppliers_direct_complete(struct device *dev) +static void dpm_clear_superiors_direct_complete(struct device *dev) { struct device_link *link; int idx; + if (dev->parent) { + spin_lock_irq(&dev->parent->power.lock); + dev->parent->power.direct_complete = false; + spin_unlock_irq(&dev->parent->power.lock); + } + idx = device_links_read_lock(); list_for_each_entry_rcu(link, &dev->links.suppliers, c_node) { @@ -1500,6 +1747,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) dev->power.direct_complete = false; } + dev->power.may_skip_resume = false; + dev->power.must_resume = false; + dpm_watchdog_set(&wd, dev); device_lock(dev); @@ -1543,20 +1793,12 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) End: if (!error) { - struct device *parent = dev->parent; - dev->power.is_suspended = true; - if (parent) { - spin_lock_irq(&parent->power.lock); + if (device_may_wakeup(dev)) + dev->power.wakeup_path = true; - dev->parent->power.direct_complete = false; - if (dev->power.wakeup_path - && !dev->parent->power.ignore_children) - dev->parent->power.wakeup_path = true; - - spin_unlock_irq(&parent->power.lock); - } - dpm_clear_suppliers_direct_complete(dev); + dpm_propagate_wakeup_to_parent(dev); + dpm_clear_superiors_direct_complete(dev); } device_unlock(dev); @@ -1665,8 +1907,9 @@ static int device_prepare(struct device *dev, pm_message_t state) if (dev->power.syscore) return 0; - WARN_ON(dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) && - !pm_runtime_enabled(dev)); + WARN_ON(!pm_runtime_enabled(dev) && + dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND | + DPM_FLAG_LEAVE_SUSPENDED)); /* * If a device's parent goes into runtime suspend at the wrong time, @@ -1678,7 +1921,7 @@ static int device_prepare(struct device *dev, pm_message_t state) device_lock(dev); - dev->power.wakeup_path = device_may_wakeup(dev); + dev->power.wakeup_path = false; if (dev->power.no_pm_callbacks) { ret = 1; /* Let device go direct_complete */ diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 7beee75399d4..21244c53e377 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -41,20 +41,15 @@ extern void dev_pm_disable_wake_irq_check(struct device *dev); #ifdef CONFIG_PM_SLEEP -extern int device_wakeup_attach_irq(struct device *dev, - struct wake_irq *wakeirq); +extern void device_wakeup_attach_irq(struct device *dev, struct wake_irq *wakeirq); extern void device_wakeup_detach_irq(struct device *dev); extern void device_wakeup_arm_wake_irqs(void); extern void device_wakeup_disarm_wake_irqs(void); #else -static inline int -device_wakeup_attach_irq(struct device *dev, - struct wake_irq *wakeirq) -{ - return 0; -} +static inline void device_wakeup_attach_irq(struct device *dev, + struct wake_irq *wakeirq) {} static inline void device_wakeup_detach_irq(struct device *dev) { diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 6e89b51ea3d9..8bef3cb2424d 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -1613,22 +1613,34 @@ void pm_runtime_drop_link(struct device *dev) spin_unlock_irq(&dev->power.lock); } +static bool pm_runtime_need_not_resume(struct device *dev) +{ + return atomic_read(&dev->power.usage_count) <= 1 && + (atomic_read(&dev->power.child_count) == 0 || + dev->power.ignore_children); +} + /** * pm_runtime_force_suspend - Force a device into suspend state if needed. * @dev: Device to suspend. * * Disable runtime PM so we safely can check the device's runtime PM status and - * if it is active, invoke it's .runtime_suspend callback to bring it into - * suspend state. Keep runtime PM disabled to preserve the state unless we - * encounter errors. + * if it is active, invoke its ->runtime_suspend callback to suspend it and + * change its runtime PM status field to RPM_SUSPENDED. Also, if the device's + * usage and children counters don't indicate that the device was in use before + * the system-wide transition under way, decrement its parent's children counter + * (if there is a parent). Keep runtime PM disabled to preserve the state + * unless we encounter errors. * * Typically this function may be invoked from a system suspend callback to make - * sure the device is put into low power state. + * sure the device is put into low power state and it should only be used during + * system-wide PM transitions to sleep states. It assumes that the analogous + * pm_runtime_force_resume() will be used to resume the device. */ int pm_runtime_force_suspend(struct device *dev) { int (*callback)(struct device *); - int ret = 0; + int ret; pm_runtime_disable(dev); if (pm_runtime_status_suspended(dev)) @@ -1636,27 +1648,23 @@ int pm_runtime_force_suspend(struct device *dev) callback = RPM_GET_CALLBACK(dev, runtime_suspend); - if (!callback) { - ret = -ENOSYS; - goto err; - } - - ret = callback(dev); + ret = callback ? callback(dev) : 0; if (ret) goto err; /* - * Increase the runtime PM usage count for the device's parent, in case - * when we find the device being used when system suspend was invoked. - * This informs pm_runtime_force_resume() to resume the parent - * immediately, which is needed to be able to resume its children, - * when not deferring the resume to be managed via runtime PM. + * If the device can stay in suspend after the system-wide transition + * to the working state that will follow, drop the children counter of + * its parent, but set its status to RPM_SUSPENDED anyway in case this + * function will be called again for it in the meantime. */ - if (dev->parent && atomic_read(&dev->power.usage_count) > 1) - pm_runtime_get_noresume(dev->parent); + if (pm_runtime_need_not_resume(dev)) + pm_runtime_set_suspended(dev); + else + __update_runtime_status(dev, RPM_SUSPENDED); - pm_runtime_set_suspended(dev); return 0; + err: pm_runtime_enable(dev); return ret; @@ -1669,13 +1677,9 @@ EXPORT_SYMBOL_GPL(pm_runtime_force_suspend); * * Prior invoking this function we expect the user to have brought the device * into low power state by a call to pm_runtime_force_suspend(). Here we reverse - * those actions and brings the device into full power, if it is expected to be - * used on system resume. To distinguish that, we check whether the runtime PM - * usage count is greater than 1 (the PM core increases the usage count in the - * system PM prepare phase), as that indicates a real user (such as a subsystem, - * driver, userspace, etc.) is using it. If that is the case, the device is - * expected to be used on system resume as well, so then we resume it. In the - * other case, we defer the resume to be managed via runtime PM. + * those actions and bring the device into full power, if it is expected to be + * used on system resume. In the other case, we defer the resume to be managed + * via runtime PM. * * Typically this function may be invoked from a system resume callback. */ @@ -1684,32 +1688,18 @@ int pm_runtime_force_resume(struct device *dev) int (*callback)(struct device *); int ret = 0; - callback = RPM_GET_CALLBACK(dev, runtime_resume); - - if (!callback) { - ret = -ENOSYS; - goto out; - } - - if (!pm_runtime_status_suspended(dev)) + if (!pm_runtime_status_suspended(dev) || pm_runtime_need_not_resume(dev)) goto out; /* - * Decrease the parent's runtime PM usage count, if we increased it - * during system suspend in pm_runtime_force_suspend(). - */ - if (atomic_read(&dev->power.usage_count) > 1) { - if (dev->parent) - pm_runtime_put_noidle(dev->parent); - } else { - goto out; - } + * The value of the parent's children counter is correct already, so + * just update the status of the device. + */ + __update_runtime_status(dev, RPM_ACTIVE); - ret = pm_runtime_set_active(dev); - if (ret) - goto out; + callback = RPM_GET_CALLBACK(dev, runtime_resume); - ret = callback(dev); + ret = callback ? callback(dev) : 0; if (ret) { pm_runtime_set_suspended(dev); goto out; diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index e153e28b1857..0f651efc58a1 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -108,16 +108,10 @@ static ssize_t control_show(struct device *dev, struct device_attribute *attr, static ssize_t control_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t n) { - char *cp; - int len = n; - - cp = memchr(buf, '\n', n); - if (cp) - len = cp - buf; device_lock(dev); - if (len == sizeof ctrl_auto - 1 && strncmp(buf, ctrl_auto, len) == 0) + if (sysfs_streq(buf, ctrl_auto)) pm_runtime_allow(dev); - else if (len == sizeof ctrl_on - 1 && strncmp(buf, ctrl_on, len) == 0) + else if (sysfs_streq(buf, ctrl_on)) pm_runtime_forbid(dev); else n = -EINVAL; @@ -125,9 +119,9 @@ static ssize_t control_store(struct device * dev, struct device_attribute *attr, return n; } -static DEVICE_ATTR(control, 0644, control_show, control_store); +static DEVICE_ATTR_RW(control); -static ssize_t rtpm_active_time_show(struct device *dev, +static ssize_t runtime_active_time_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret; @@ -138,9 +132,9 @@ static ssize_t rtpm_active_time_show(struct device *dev, return ret; } -static DEVICE_ATTR(runtime_active_time, 0444, rtpm_active_time_show, NULL); +static DEVICE_ATTR_RO(runtime_active_time); -static ssize_t rtpm_suspended_time_show(struct device *dev, +static ssize_t runtime_suspended_time_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret; @@ -152,9 +146,9 @@ static ssize_t rtpm_suspended_time_show(struct device *dev, return ret; } -static DEVICE_ATTR(runtime_suspended_time, 0444, rtpm_suspended_time_show, NULL); +static DEVICE_ATTR_RO(runtime_suspended_time); -static ssize_t rtpm_status_show(struct device *dev, +static ssize_t runtime_status_show(struct device *dev, struct device_attribute *attr, char *buf) { const char *p; @@ -184,7 +178,7 @@ static ssize_t rtpm_status_show(struct device *dev, return sprintf(buf, p); } -static DEVICE_ATTR(runtime_status, 0444, rtpm_status_show, NULL); +static DEVICE_ATTR_RO(runtime_status); static ssize_t autosuspend_delay_ms_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -211,26 +205,25 @@ static ssize_t autosuspend_delay_ms_store(struct device *dev, return n; } -static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show, - autosuspend_delay_ms_store); +static DEVICE_ATTR_RW(autosuspend_delay_ms); -static ssize_t pm_qos_resume_latency_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t pm_qos_resume_latency_us_show(struct device *dev, + struct device_attribute *attr, + char *buf) { s32 value = dev_pm_qos_requested_resume_latency(dev); if (value == 0) return sprintf(buf, "n/a\n"); - else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) + if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) value = 0; return sprintf(buf, "%d\n", value); } -static ssize_t pm_qos_resume_latency_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t n) +static ssize_t pm_qos_resume_latency_us_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t n) { s32 value; int ret; @@ -245,7 +238,7 @@ static ssize_t pm_qos_resume_latency_store(struct device *dev, if (value == 0) value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; - } else if (!strcmp(buf, "n/a") || !strcmp(buf, "n/a\n")) { + } else if (sysfs_streq(buf, "n/a")) { value = 0; } else { return -EINVAL; @@ -256,26 +249,25 @@ static ssize_t pm_qos_resume_latency_store(struct device *dev, return ret < 0 ? ret : n; } -static DEVICE_ATTR(pm_qos_resume_latency_us, 0644, - pm_qos_resume_latency_show, pm_qos_resume_latency_store); +static DEVICE_ATTR_RW(pm_qos_resume_latency_us); -static ssize_t pm_qos_latency_tolerance_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t pm_qos_latency_tolerance_us_show(struct device *dev, + struct device_attribute *attr, + char *buf) { s32 value = dev_pm_qos_get_user_latency_tolerance(dev); if (value < 0) return sprintf(buf, "auto\n"); - else if (value == PM_QOS_LATENCY_ANY) + if (value == PM_QOS_LATENCY_ANY) return sprintf(buf, "any\n"); return sprintf(buf, "%d\n", value); } -static ssize_t pm_qos_latency_tolerance_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t n) +static ssize_t pm_qos_latency_tolerance_us_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t n) { s32 value; int ret; @@ -285,9 +277,9 @@ static ssize_t pm_qos_latency_tolerance_store(struct device *dev, if (value < 0) return -EINVAL; } else { - if (!strcmp(buf, "auto") || !strcmp(buf, "auto\n")) + if (sysfs_streq(buf, "auto")) value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT; - else if (!strcmp(buf, "any") || !strcmp(buf, "any\n")) + else if (sysfs_streq(buf, "any")) value = PM_QOS_LATENCY_ANY; else return -EINVAL; @@ -296,8 +288,7 @@ static ssize_t pm_qos_latency_tolerance_store(struct device *dev, return ret < 0 ? ret : n; } -static DEVICE_ATTR(pm_qos_latency_tolerance_us, 0644, - pm_qos_latency_tolerance_show, pm_qos_latency_tolerance_store); +static DEVICE_ATTR_RW(pm_qos_latency_tolerance_us); static ssize_t pm_qos_no_power_off_show(struct device *dev, struct device_attribute *attr, @@ -323,49 +314,39 @@ static ssize_t pm_qos_no_power_off_store(struct device *dev, return ret < 0 ? ret : n; } -static DEVICE_ATTR(pm_qos_no_power_off, 0644, - pm_qos_no_power_off_show, pm_qos_no_power_off_store); +static DEVICE_ATTR_RW(pm_qos_no_power_off); #ifdef CONFIG_PM_SLEEP static const char _enabled[] = "enabled"; static const char _disabled[] = "disabled"; -static ssize_t -wake_show(struct device * dev, struct device_attribute *attr, char * buf) +static ssize_t wakeup_show(struct device *dev, struct device_attribute *attr, + char *buf) { return sprintf(buf, "%s\n", device_can_wakeup(dev) ? (device_may_wakeup(dev) ? _enabled : _disabled) : ""); } -static ssize_t -wake_store(struct device * dev, struct device_attribute *attr, - const char * buf, size_t n) +static ssize_t wakeup_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) { - char *cp; - int len = n; - if (!device_can_wakeup(dev)) return -EINVAL; - cp = memchr(buf, '\n', n); - if (cp) - len = cp - buf; - if (len == sizeof _enabled - 1 - && strncmp(buf, _enabled, sizeof _enabled - 1) == 0) + if (sysfs_streq(buf, _enabled)) device_set_wakeup_enable(dev, 1); - else if (len == sizeof _disabled - 1 - && strncmp(buf, _disabled, sizeof _disabled - 1) == 0) + else if (sysfs_streq(buf, _disabled)) device_set_wakeup_enable(dev, 0); else return -EINVAL; return n; } -static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store); +static DEVICE_ATTR_RW(wakeup); static ssize_t wakeup_count_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { unsigned long count = 0; bool enabled = false; @@ -379,10 +360,11 @@ static ssize_t wakeup_count_show(struct device *dev, return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n"); } -static DEVICE_ATTR(wakeup_count, 0444, wakeup_count_show, NULL); +static DEVICE_ATTR_RO(wakeup_count); static ssize_t wakeup_active_count_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { unsigned long count = 0; bool enabled = false; @@ -396,11 +378,11 @@ static ssize_t wakeup_active_count_show(struct device *dev, return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n"); } -static DEVICE_ATTR(wakeup_active_count, 0444, wakeup_active_count_show, NULL); +static DEVICE_ATTR_RO(wakeup_active_count); static ssize_t wakeup_abort_count_show(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { unsigned long count = 0; bool enabled = false; @@ -414,7 +396,7 @@ static ssize_t wakeup_abort_count_show(struct device *dev, return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n"); } -static DEVICE_ATTR(wakeup_abort_count, 0444, wakeup_abort_count_show, NULL); +static DEVICE_ATTR_RO(wakeup_abort_count); static ssize_t wakeup_expire_count_show(struct device *dev, struct device_attribute *attr, @@ -432,10 +414,10 @@ static ssize_t wakeup_expire_count_show(struct device *dev, return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n"); } -static DEVICE_ATTR(wakeup_expire_count, 0444, wakeup_expire_count_show, NULL); +static DEVICE_ATTR_RO(wakeup_expire_count); static ssize_t wakeup_active_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { unsigned int active = 0; bool enabled = false; @@ -449,10 +431,11 @@ static ssize_t wakeup_active_show(struct device *dev, return enabled ? sprintf(buf, "%u\n", active) : sprintf(buf, "\n"); } -static DEVICE_ATTR(wakeup_active, 0444, wakeup_active_show, NULL); +static DEVICE_ATTR_RO(wakeup_active); -static ssize_t wakeup_total_time_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t wakeup_total_time_ms_show(struct device *dev, + struct device_attribute *attr, + char *buf) { s64 msec = 0; bool enabled = false; @@ -466,10 +449,10 @@ static ssize_t wakeup_total_time_show(struct device *dev, return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n"); } -static DEVICE_ATTR(wakeup_total_time_ms, 0444, wakeup_total_time_show, NULL); +static DEVICE_ATTR_RO(wakeup_total_time_ms); -static ssize_t wakeup_max_time_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t wakeup_max_time_ms_show(struct device *dev, + struct device_attribute *attr, char *buf) { s64 msec = 0; bool enabled = false; @@ -483,10 +466,11 @@ static ssize_t wakeup_max_time_show(struct device *dev, return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n"); } -static DEVICE_ATTR(wakeup_max_time_ms, 0444, wakeup_max_time_show, NULL); +static DEVICE_ATTR_RO(wakeup_max_time_ms); -static ssize_t wakeup_last_time_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t wakeup_last_time_ms_show(struct device *dev, + struct device_attribute *attr, + char *buf) { s64 msec = 0; bool enabled = false; @@ -500,12 +484,12 @@ static ssize_t wakeup_last_time_show(struct device *dev, return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n"); } -static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL); +static DEVICE_ATTR_RO(wakeup_last_time_ms); #ifdef CONFIG_PM_AUTOSLEEP -static ssize_t wakeup_prevent_sleep_time_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t wakeup_prevent_sleep_time_ms_show(struct device *dev, + struct device_attribute *attr, + char *buf) { s64 msec = 0; bool enabled = false; @@ -519,40 +503,39 @@ static ssize_t wakeup_prevent_sleep_time_show(struct device *dev, return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n"); } -static DEVICE_ATTR(wakeup_prevent_sleep_time_ms, 0444, - wakeup_prevent_sleep_time_show, NULL); +static DEVICE_ATTR_RO(wakeup_prevent_sleep_time_ms); #endif /* CONFIG_PM_AUTOSLEEP */ #endif /* CONFIG_PM_SLEEP */ #ifdef CONFIG_PM_ADVANCED_DEBUG -static ssize_t rtpm_usagecount_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t runtime_usage_show(struct device *dev, + struct device_attribute *attr, char *buf) { return sprintf(buf, "%d\n", atomic_read(&dev->power.usage_count)); } +static DEVICE_ATTR_RO(runtime_usage); -static ssize_t rtpm_children_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t runtime_active_kids_show(struct device *dev, + struct device_attribute *attr, + char *buf) { return sprintf(buf, "%d\n", dev->power.ignore_children ? 0 : atomic_read(&dev->power.child_count)); } +static DEVICE_ATTR_RO(runtime_active_kids); -static ssize_t rtpm_enabled_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t runtime_enabled_show(struct device *dev, + struct device_attribute *attr, char *buf) { - if ((dev->power.disable_depth) && (dev->power.runtime_auto == false)) + if (dev->power.disable_depth && (dev->power.runtime_auto == false)) return sprintf(buf, "disabled & forbidden\n"); - else if (dev->power.disable_depth) + if (dev->power.disable_depth) return sprintf(buf, "disabled\n"); - else if (dev->power.runtime_auto == false) + if (dev->power.runtime_auto == false) return sprintf(buf, "forbidden\n"); return sprintf(buf, "enabled\n"); } - -static DEVICE_ATTR(runtime_usage, 0444, rtpm_usagecount_show, NULL); -static DEVICE_ATTR(runtime_active_kids, 0444, rtpm_children_show, NULL); -static DEVICE_ATTR(runtime_enabled, 0444, rtpm_enabled_show, NULL); +static DEVICE_ATTR_RO(runtime_enabled); #ifdef CONFIG_PM_SLEEP static ssize_t async_show(struct device *dev, struct device_attribute *attr, @@ -566,23 +549,16 @@ static ssize_t async_show(struct device *dev, struct device_attribute *attr, static ssize_t async_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) { - char *cp; - int len = n; - - cp = memchr(buf, '\n', n); - if (cp) - len = cp - buf; - if (len == sizeof _enabled - 1 && strncmp(buf, _enabled, len) == 0) + if (sysfs_streq(buf, _enabled)) device_enable_async_suspend(dev); - else if (len == sizeof _disabled - 1 && - strncmp(buf, _disabled, len) == 0) + else if (sysfs_streq(buf, _disabled)) device_disable_async_suspend(dev); else return -EINVAL; return n; } -static DEVICE_ATTR(async, 0644, async_show, async_store); +static DEVICE_ATTR_RW(async); #endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_ADVANCED_DEBUG */ diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c index ae0429827f31..a8ac86e4d79e 100644 --- a/drivers/base/power/wakeirq.c +++ b/drivers/base/power/wakeirq.c @@ -33,7 +33,6 @@ static int dev_pm_attach_wake_irq(struct device *dev, int irq, struct wake_irq *wirq) { unsigned long flags; - int err; if (!dev || !wirq) return -EINVAL; @@ -45,12 +44,11 @@ static int dev_pm_attach_wake_irq(struct device *dev, int irq, return -EEXIST; } - err = device_wakeup_attach_irq(dev, wirq); - if (!err) - dev->power.wakeirq = wirq; + dev->power.wakeirq = wirq; + device_wakeup_attach_irq(dev, wirq); spin_unlock_irqrestore(&dev->power.lock, flags); - return err; + return 0; } /** diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 38559f04db2c..ea01621ed769 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -19,6 +19,11 @@ #include "power.h" +#ifndef CONFIG_SUSPEND +suspend_state_t pm_suspend_target_state; +#define pm_suspend_target_state (PM_SUSPEND_ON) +#endif + /* * If set, the suspend/hibernate code will abort transitions to a sleep state * if wakeup events are registered during or immediately before the transition. @@ -268,6 +273,9 @@ int device_wakeup_enable(struct device *dev) if (!dev || !dev->power.can_wakeup) return -EINVAL; + if (pm_suspend_target_state != PM_SUSPEND_ON) + dev_dbg(dev, "Suspicious %s() during system transition!\n", __func__); + ws = wakeup_source_register(dev_name(dev)); if (!ws) return -ENOMEM; @@ -291,22 +299,19 @@ EXPORT_SYMBOL_GPL(device_wakeup_enable); * * Call under the device's power.lock lock. */ -int device_wakeup_attach_irq(struct device *dev, +void device_wakeup_attach_irq(struct device *dev, struct wake_irq *wakeirq) { struct wakeup_source *ws; ws = dev->power.wakeup; - if (!ws) { - dev_err(dev, "forgot to call call device_init_wakeup?\n"); - return -EINVAL; - } + if (!ws) + return; if (ws->wakeirq) - return -EEXIST; + dev_err(dev, "Leftover wakeup IRQ found, overriding\n"); ws->wakeirq = wakeirq; - return 0; } /** @@ -448,9 +453,7 @@ int device_init_wakeup(struct device *dev, bool enable) device_set_wakeup_capable(dev, true); ret = device_wakeup_enable(dev); } else { - if (dev->power.can_wakeup) - device_wakeup_disable(dev); - + device_wakeup_disable(dev); device_set_wakeup_capable(dev, false); } @@ -464,9 +467,6 @@ EXPORT_SYMBOL_GPL(device_init_wakeup); */ int device_set_wakeup_enable(struct device *dev, bool enable) { - if (!dev || !dev->power.can_wakeup) - return -EINVAL; - return enable ? device_wakeup_enable(dev) : device_wakeup_disable(dev); } EXPORT_SYMBOL_GPL(device_set_wakeup_enable); diff --git a/drivers/base/property.c b/drivers/base/property.c index 851b1b6596a4..302236281d83 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * property.c - Unified device property interface. * * Copyright (C) 2014, Intel Corporation * Authors: Rafael J. Wysocki * Mika Westerberg - * - * 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. */ #include @@ -16,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -698,6 +696,23 @@ int fwnode_property_get_reference_args(const struct fwnode_handle *fwnode, } EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args); +static void property_entry_free_data(const struct property_entry *p) +{ + size_t i, nval; + + if (p->is_array) { + if (p->is_string && p->pointer.str) { + nval = p->length / sizeof(const char *); + for (i = 0; i < nval; i++) + kfree(p->pointer.str[i]); + } + kfree(p->pointer.raw_data); + } else if (p->is_string) { + kfree(p->value.str); + } + kfree(p->name); +} + static int property_copy_string_array(struct property_entry *dst, const struct property_entry *src) { @@ -728,34 +743,24 @@ static int property_entry_copy_data(struct property_entry *dst, { int error; - dst->name = kstrdup(src->name, GFP_KERNEL); - if (!dst->name) - return -ENOMEM; - if (src->is_array) { - if (!src->length) { - error = -ENODATA; - goto out_free_name; - } + if (!src->length) + return -ENODATA; if (src->is_string) { error = property_copy_string_array(dst, src); if (error) - goto out_free_name; + return error; } else { dst->pointer.raw_data = kmemdup(src->pointer.raw_data, src->length, GFP_KERNEL); - if (!dst->pointer.raw_data) { - error = -ENOMEM; - goto out_free_name; - } + if (!dst->pointer.raw_data) + return -ENOMEM; } } else if (src->is_string) { dst->value.str = kstrdup(src->value.str, GFP_KERNEL); - if (!dst->value.str && src->value.str) { - error = -ENOMEM; - goto out_free_name; - } + if (!dst->value.str && src->value.str) + return -ENOMEM; } else { dst->value.raw_data = src->value.raw_data; } @@ -764,28 +769,15 @@ static int property_entry_copy_data(struct property_entry *dst, dst->is_array = src->is_array; dst->is_string = src->is_string; + dst->name = kstrdup(src->name, GFP_KERNEL); + if (!dst->name) + goto out_free_data; + return 0; -out_free_name: - kfree(dst->name); - return error; -} - -static void property_entry_free_data(const struct property_entry *p) -{ - size_t i, nval; - - if (p->is_array) { - if (p->is_string && p->pointer.str) { - nval = p->length / sizeof(const char *); - for (i = 0; i < nval; i++) - kfree(p->pointer.str[i]); - } - kfree(p->pointer.raw_data); - } else if (p->is_string) { - kfree(p->value.str); - } - kfree(p->name); +out_free_data: + property_entry_free_data(dst); + return -ENOMEM; } /** @@ -996,6 +988,32 @@ fwnode_get_next_child_node(const struct fwnode_handle *fwnode, } EXPORT_SYMBOL_GPL(fwnode_get_next_child_node); +/** + * fwnode_get_next_available_child_node - Return the next + * available child node handle for a node + * @fwnode: Firmware node to find the next child node for. + * @child: Handle to one of the node's child nodes or a %NULL handle. + */ +struct fwnode_handle * +fwnode_get_next_available_child_node(const struct fwnode_handle *fwnode, + struct fwnode_handle *child) +{ + struct fwnode_handle *next_child = child; + + if (!fwnode) + return NULL; + + do { + next_child = fwnode_get_next_child_node(fwnode, next_child); + + if (!next_child || fwnode_device_is_available(next_child)) + break; + } while (next_child); + + return next_child; +} +EXPORT_SYMBOL_GPL(fwnode_get_next_available_child_node); + /** * device_get_next_child_node - Return the next child node handle for a device * @dev: Device to find the next child node for. @@ -1126,21 +1144,21 @@ enum dev_dma_attr device_get_dma_attr(struct device *dev) EXPORT_SYMBOL_GPL(device_get_dma_attr); /** - * device_get_phy_mode - Get phy mode for given device - * @dev: Pointer to the given device + * fwnode_get_phy_mode - Get phy mode for given firmware node + * @fwnode: Pointer to the given node * * The function gets phy interface string from property 'phy-mode' or * 'phy-connection-type', and return its index in phy_modes table, or errno in * error case. */ -int device_get_phy_mode(struct device *dev) +int fwnode_get_phy_mode(struct fwnode_handle *fwnode) { const char *pm; int err, i; - err = device_property_read_string(dev, "phy-mode", &pm); + err = fwnode_property_read_string(fwnode, "phy-mode", &pm); if (err < 0) - err = device_property_read_string(dev, + err = fwnode_property_read_string(fwnode, "phy-connection-type", &pm); if (err < 0) return err; @@ -1151,13 +1169,27 @@ int device_get_phy_mode(struct device *dev) return -ENODEV; } +EXPORT_SYMBOL_GPL(fwnode_get_phy_mode); + +/** + * device_get_phy_mode - Get phy mode for given device + * @dev: Pointer to the given device + * + * The function gets phy interface string from property 'phy-mode' or + * 'phy-connection-type', and return its index in phy_modes table, or errno in + * error case. + */ +int device_get_phy_mode(struct device *dev) +{ + return fwnode_get_phy_mode(dev_fwnode(dev)); +} EXPORT_SYMBOL_GPL(device_get_phy_mode); -static void *device_get_mac_addr(struct device *dev, +static void *fwnode_get_mac_addr(struct fwnode_handle *fwnode, const char *name, char *addr, int alen) { - int ret = device_property_read_u8_array(dev, name, addr, alen); + int ret = fwnode_property_read_u8_array(fwnode, name, addr, alen); if (ret == 0 && alen == ETH_ALEN && is_valid_ether_addr(addr)) return addr; @@ -1165,8 +1197,8 @@ static void *device_get_mac_addr(struct device *dev, } /** - * device_get_mac_address - Get the MAC for a given device - * @dev: Pointer to the device + * fwnode_get_mac_address - Get the MAC from the firmware node + * @fwnode: Pointer to the firmware node * @addr: Address of buffer to store the MAC in * @alen: Length of the buffer pointed to by addr, should be ETH_ALEN * @@ -1187,22 +1219,59 @@ static void *device_get_mac_addr(struct device *dev, * In this case, the real MAC is in 'local-mac-address', and 'mac-address' * exists but is all zeros. */ -void *device_get_mac_address(struct device *dev, char *addr, int alen) +void *fwnode_get_mac_address(struct fwnode_handle *fwnode, char *addr, int alen) { char *res; - res = device_get_mac_addr(dev, "mac-address", addr, alen); + res = fwnode_get_mac_addr(fwnode, "mac-address", addr, alen); if (res) return res; - res = device_get_mac_addr(dev, "local-mac-address", addr, alen); + res = fwnode_get_mac_addr(fwnode, "local-mac-address", addr, alen); if (res) return res; - return device_get_mac_addr(dev, "address", addr, alen); + return fwnode_get_mac_addr(fwnode, "address", addr, alen); +} +EXPORT_SYMBOL(fwnode_get_mac_address); + +/** + * device_get_mac_address - Get the MAC for a given device + * @dev: Pointer to the device + * @addr: Address of buffer to store the MAC in + * @alen: Length of the buffer pointed to by addr, should be ETH_ALEN + */ +void *device_get_mac_address(struct device *dev, char *addr, int alen) +{ + return fwnode_get_mac_address(dev_fwnode(dev), addr, alen); } EXPORT_SYMBOL(device_get_mac_address); +/** + * fwnode_irq_get - Get IRQ directly from a fwnode + * @fwnode: Pointer to the firmware node + * @index: Zero-based index of the IRQ + * + * Returns Linux IRQ number on success. Other values are determined + * accordingly to acpi_/of_ irq_get() operation. + */ +int fwnode_irq_get(struct fwnode_handle *fwnode, unsigned int index) +{ + struct device_node *of_node = to_of_node(fwnode); + struct resource res; + int ret; + + if (IS_ENABLED(CONFIG_OF) && of_node) + return of_irq_get(of_node, index); + + ret = acpi_irq_get(ACPI_HANDLE_FWNODE(fwnode), index, &res); + if (ret) + return ret; + + return res.start; +} +EXPORT_SYMBOL(fwnode_irq_get); + /** * device_graph_get_next_endpoint - Get next endpoint firmware node * @fwnode: Pointer to the parent firmware node @@ -1340,3 +1409,10 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, return fwnode_call_int_op(fwnode, graph_parse_endpoint, endpoint); } EXPORT_SYMBOL(fwnode_graph_parse_endpoint); + +void *device_get_match_data(struct device *dev) +{ + return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, + dev); +} +EXPORT_SYMBOL_GPL(device_get_match_data); diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 3a1535d812d8..aff34c0c2a3e 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -6,7 +6,6 @@ config REGMAP default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) select IRQ_DOMAIN if REGMAP_IRQ - select REGMAP_HWSPINLOCK if HWSPINLOCK=y bool config REGCACHE_COMPRESSED @@ -21,6 +20,10 @@ config REGMAP_I2C tristate depends on I2C +config REGMAP_SLIMBUS + tristate + depends on SLIMBUS + config REGMAP_SPI tristate depends on SPI @@ -39,5 +42,6 @@ config REGMAP_MMIO config REGMAP_IRQ bool -config REGMAP_HWSPINLOCK - bool +config REGMAP_SOUNDWIRE + tristate + depends on SOUNDWIRE_BUS diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index 0d298c446108..5ed0023fabda 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile @@ -8,8 +8,10 @@ obj-$(CONFIG_REGCACHE_COMPRESSED) += regcache-lzo.o obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o +obj-$(CONFIG_REGMAP_SLIMBUS) += regmap-slimbus.o obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o obj-$(CONFIG_REGMAP_W1) += regmap-w1.o +obj-$(CONFIG_REGMAP_SOUNDWIRE) += regmap-sdw.o diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 8641183cac2f..53785e0e297a 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -77,6 +77,7 @@ struct regmap { int async_ret; #ifdef CONFIG_DEBUG_FS + bool debugfs_disable; struct dentry *debugfs; const char *debugfs_name; @@ -215,10 +216,17 @@ struct regmap_field { extern void regmap_debugfs_initcall(void); extern void regmap_debugfs_init(struct regmap *map, const char *name); extern void regmap_debugfs_exit(struct regmap *map); + +static inline void regmap_debugfs_disable(struct regmap *map) +{ + map->debugfs_disable = true; +} + #else static inline void regmap_debugfs_initcall(void) { } static inline void regmap_debugfs_init(struct regmap *map, const char *name) { } static inline void regmap_debugfs_exit(struct regmap *map) { } +static inline void regmap_debugfs_disable(struct regmap *map) { } #endif /* regcache core declarations */ diff --git a/drivers/base/regmap/regcache-flat.c b/drivers/base/regmap/regcache-flat.c index 4d2e50bfc726..bc6cd88b8cc6 100644 --- a/drivers/base/regmap/regcache-flat.c +++ b/drivers/base/regmap/regcache-flat.c @@ -37,9 +37,12 @@ static int regcache_flat_init(struct regmap *map) cache = map->cache; - for (i = 0; i < map->num_reg_defaults; i++) - cache[regcache_flat_get_index(map, map->reg_defaults[i].reg)] = - map->reg_defaults[i].def; + for (i = 0; i < map->num_reg_defaults; i++) { + unsigned int reg = map->reg_defaults[i].reg; + unsigned int index = regcache_flat_get_index(map, reg); + + cache[index] = map->reg_defaults[i].def; + } return 0; } @@ -56,8 +59,9 @@ static int regcache_flat_read(struct regmap *map, unsigned int reg, unsigned int *value) { unsigned int *cache = map->cache; + unsigned int index = regcache_flat_get_index(map, reg); - *value = cache[regcache_flat_get_index(map, reg)]; + *value = cache[index]; return 0; } @@ -66,8 +70,9 @@ static int regcache_flat_write(struct regmap *map, unsigned int reg, unsigned int value) { unsigned int *cache = map->cache; + unsigned int index = regcache_flat_get_index(map, reg); - cache[regcache_flat_get_index(map, reg)] = value; + cache[index] = value; return 0; } diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 36ce3511c733..f3266334063e 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -529,6 +529,18 @@ void regmap_debugfs_init(struct regmap *map, const char *name) struct regmap_range_node *range_node; const char *devname = "dummy"; + /* + * Userspace can initiate reads from the hardware over debugfs. + * Normally internal regmap structures and buffers are protected with + * a mutex or a spinlock, but if the regmap owner decided to disable + * all locking mechanisms, this is no longer the case. For safety: + * don't create the debugfs entries if locking is disabled. + */ + if (map->debugfs_disable) { + dev_dbg(map->dev, "regmap locking disabled - not creating debugfs entries\n"); + return; + } + /* If we don't have the debugfs root yet, postpone init */ if (!regmap_debugfs_root) { struct regmap_debugfs_node *node; diff --git a/drivers/base/regmap/regmap-sdw.c b/drivers/base/regmap/regmap-sdw.c new file mode 100644 index 000000000000..50a66382d87d --- /dev/null +++ b/drivers/base/regmap/regmap-sdw.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2015-17 Intel Corporation. + +#include +#include +#include +#include +#include "internal.h" + +static int regmap_sdw_write(void *context, unsigned int reg, unsigned int val) +{ + struct device *dev = context; + struct sdw_slave *slave = dev_to_sdw_dev(dev); + + return sdw_write(slave, reg, val); +} + +static int regmap_sdw_read(void *context, unsigned int reg, unsigned int *val) +{ + struct device *dev = context; + struct sdw_slave *slave = dev_to_sdw_dev(dev); + int read; + + read = sdw_read(slave, reg); + if (read < 0) + return read; + + *val = read; + return 0; +} + +static struct regmap_bus regmap_sdw = { + .reg_read = regmap_sdw_read, + .reg_write = regmap_sdw_write, + .reg_format_endian_default = REGMAP_ENDIAN_LITTLE, + .val_format_endian_default = REGMAP_ENDIAN_LITTLE, +}; + +static int regmap_sdw_config_check(const struct regmap_config *config) +{ + /* All register are 8-bits wide as per MIPI Soundwire 1.0 Spec */ + if (config->val_bits != 8) + return -ENOTSUPP; + + /* Registers are 32 bits wide */ + if (config->reg_bits != 32) + return -ENOTSUPP; + + if (config->pad_bits != 0) + return -ENOTSUPP; + + return 0; +} + +struct regmap *__regmap_init_sdw(struct sdw_slave *sdw, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) +{ + int ret; + + ret = regmap_sdw_config_check(config); + if (ret) + return ERR_PTR(ret); + + return __regmap_init(&sdw->dev, ®map_sdw, + &sdw->dev, config, lock_key, lock_name); +} +EXPORT_SYMBOL_GPL(__regmap_init_sdw); + +struct regmap *__devm_regmap_init_sdw(struct sdw_slave *sdw, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) +{ + int ret; + + ret = regmap_sdw_config_check(config); + if (ret) + return ERR_PTR(ret); + + return __devm_regmap_init(&sdw->dev, ®map_sdw, + &sdw->dev, config, lock_key, lock_name); +} +EXPORT_SYMBOL_GPL(__devm_regmap_init_sdw); + +MODULE_DESCRIPTION("Regmap SoundWire Module"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/base/regmap/regmap-slimbus.c b/drivers/base/regmap/regmap-slimbus.c new file mode 100644 index 000000000000..c90bee81d954 --- /dev/null +++ b/drivers/base/regmap/regmap-slimbus.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017, Linaro Ltd. + +#include +#include +#include + +#include "internal.h" + +static int regmap_slimbus_byte_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct slim_device *sdev = context; + int v; + + v = slim_readb(sdev, reg); + + if (v < 0) + return v; + + *val = v; + + return 0; +} + +static int regmap_slimbus_byte_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct slim_device *sdev = context; + + return slim_writeb(sdev, reg, val); +} + +static struct regmap_bus regmap_slimbus_bus = { + .reg_write = regmap_slimbus_byte_reg_write, + .reg_read = regmap_slimbus_byte_reg_read, + .reg_format_endian_default = REGMAP_ENDIAN_LITTLE, + .val_format_endian_default = REGMAP_ENDIAN_LITTLE, +}; + +static const struct regmap_bus *regmap_get_slimbus(struct slim_device *slim, + const struct regmap_config *config) +{ + if (config->val_bits == 8 && config->reg_bits == 8) + return ®map_slimbus_bus; + + return ERR_PTR(-ENOTSUPP); +} + +struct regmap *__regmap_init_slimbus(struct slim_device *slimbus, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) +{ + const struct regmap_bus *bus = regmap_get_slimbus(slimbus, config); + + if (IS_ERR(bus)) + return ERR_CAST(bus); + + return __regmap_init(&slimbus->dev, bus, &slimbus->dev, config, + lock_key, lock_name); +} +EXPORT_SYMBOL_GPL(__regmap_init_slimbus); + +struct regmap *__devm_regmap_init_slimbus(struct slim_device *slimbus, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) +{ + const struct regmap_bus *bus = regmap_get_slimbus(slimbus, config); + + if (IS_ERR(bus)) + return ERR_CAST(bus); + + return __devm_regmap_init(&slimbus->dev, bus, &slimbus, config, + lock_key, lock_name); +} +EXPORT_SYMBOL_GPL(__devm_regmap_init_slimbus); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 8d516a9bfc01..ee302ccdfbc8 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -414,7 +414,6 @@ static unsigned int regmap_parse_64_native(const void *buf) } #endif -#ifdef REGMAP_HWSPINLOCK static void regmap_lock_hwlock(void *__map) { struct regmap *map = __map; @@ -457,7 +456,11 @@ static void regmap_unlock_hwlock_irqrestore(void *__map) hwspin_unlock_irqrestore(map->hwlock, &map->spinlock_flags); } -#endif + +static void regmap_lock_unlock_none(void *__map) +{ + +} static void regmap_lock_mutex(void *__map) { @@ -669,16 +672,26 @@ struct regmap *__regmap_init(struct device *dev, goto err; } - if (config->lock && config->unlock) { + if (config->name) { + map->name = kstrdup_const(config->name, GFP_KERNEL); + if (!map->name) { + ret = -ENOMEM; + goto err_map; + } + } + + if (config->disable_locking) { + map->lock = map->unlock = regmap_lock_unlock_none; + regmap_debugfs_disable(map); + } else if (config->lock && config->unlock) { map->lock = config->lock; map->unlock = config->unlock; map->lock_arg = config->lock_arg; - } else if (config->hwlock_id) { -#ifdef REGMAP_HWSPINLOCK + } else if (config->use_hwlock) { map->hwlock = hwspin_lock_request_specific(config->hwlock_id); if (!map->hwlock) { ret = -ENXIO; - goto err_map; + goto err_name; } switch (config->hwlock_mode) { @@ -697,10 +710,6 @@ struct regmap *__regmap_init(struct device *dev, } map->lock_arg = map; -#else - ret = -EINVAL; - goto err_map; -#endif } else { if ((bus && bus->fast_io) || config->fast_io) { @@ -762,14 +771,15 @@ struct regmap *__regmap_init(struct device *dev, map->volatile_reg = config->volatile_reg; map->precious_reg = config->precious_reg; map->cache_type = config->cache_type; - map->name = config->name; spin_lock_init(&map->async_lock); INIT_LIST_HEAD(&map->async_list); INIT_LIST_HEAD(&map->async_free); init_waitqueue_head(&map->async_waitq); - if (config->read_flag_mask || config->write_flag_mask) { + if (config->read_flag_mask || + config->write_flag_mask || + config->zero_flag_mask) { map->read_flag_mask = config->read_flag_mask; map->write_flag_mask = config->write_flag_mask; } else if (bus) { @@ -1116,8 +1126,10 @@ err_range: regmap_range_exit(map); kfree(map->work_buf); err_hwlock: - if (IS_ENABLED(REGMAP_HWSPINLOCK) && map->hwlock) + if (map->hwlock) hwspin_lock_free(map->hwlock); +err_name: + kfree_const(map->name); err_map: kfree(map); err: @@ -1305,8 +1317,9 @@ void regmap_exit(struct regmap *map) kfree(async->work_buf); kfree(async); } - if (IS_ENABLED(REGMAP_HWSPINLOCK) && map->hwlock) + if (map->hwlock) hwspin_lock_free(map->hwlock); + kfree_const(map->name); kfree(map); } EXPORT_SYMBOL_GPL(regmap_exit); @@ -2423,13 +2436,15 @@ static int _regmap_bus_read(void *context, unsigned int reg, { int ret; struct regmap *map = context; + void *work_val = map->work_buf + map->format.reg_bytes + + map->format.pad_bytes; if (!map->format.parse_val) return -EINVAL; - ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes); + ret = _regmap_raw_read(map, reg, work_val, map->format.val_bytes); if (ret == 0) - *val = map->format.parse_val(map->work_buf); + *val = map->format.parse_val(work_val); return ret; } diff --git a/drivers/base/soc.c b/drivers/base/soc.c index 909dedae4c4e..4e80f48ad5d6 100644 --- a/drivers/base/soc.c +++ b/drivers/base/soc.c @@ -1,8 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) ST-Ericsson SA 2011 * * Author: Lee Jones for ST-Ericsson. - * License terms: GNU General Public License (GPL), version 2 */ #include diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c index 8d98a329f6ea..6e076f359dcc 100644 --- a/drivers/base/syscore.c +++ b/drivers/base/syscore.c @@ -1,9 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * syscore.c - Execution of system core operations. * * Copyright (C) 2011 Rafael J. Wysocki , Novell Inc. - * - * This file is released under the GPLv2. */ #include diff --git a/drivers/base/test/test_async_driver_probe.c b/drivers/base/test/test_async_driver_probe.c index a3355d66bc12..e7f145d662f0 100644 --- a/drivers/base/test/test_async_driver_probe.c +++ b/drivers/base/test/test_async_driver_probe.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2014 Google, Inc. - * - * 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. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/base/topology.c b/drivers/base/topology.c index d936fcf9f1fb..5fd9f167ecc1 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * driver/base/topology.c - Populate sysfs with cpu topology information * @@ -6,22 +7,6 @@ * Copyright (C) 2006, Intel Corp. * * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, GOOD TITLE or - * NON INFRINGEMENT. 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, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * */ #include #include diff --git a/drivers/base/transport_class.c b/drivers/base/transport_class.c index f6c453c3816e..5ed86ded6e6b 100644 --- a/drivers/base/transport_class.c +++ b/drivers/base/transport_class.c @@ -1,11 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * transport_class.c - implementation of generic transport classes * using attribute_containers * * Copyright (c) 2005 - James Bottomley * - * This file is licensed under GPLv2 - * * The basic idea here is to allow any "device controller" (which * would most often be a Host Bus Adapter to use the services of one * or more tranport classes for performing transport specific diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig index 02d78f6cecbb..ba8acca036df 100644 --- a/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig @@ -55,7 +55,7 @@ config BCMA_DRIVER_PCI config BCMA_DRIVER_PCI_HOSTMODE bool "Driver for PCI core working in hostmode" - depends on MIPS && BCMA_DRIVER_PCI + depends on MIPS && BCMA_DRIVER_PCI && PCI_DRIVERS_LEGACY help PCI core hostmode operation (external PCI bus). diff --git a/drivers/bcma/driver_pcie2.c b/drivers/bcma/driver_pcie2.c index b1a6e327cb23..cf889fc62ac7 100644 --- a/drivers/bcma/driver_pcie2.c +++ b/drivers/bcma/driver_pcie2.c @@ -83,7 +83,8 @@ static void bcma_core_pcie2_hw_ltr_war(struct bcma_drv_pcie2 *pcie2) bcma_core_pcie2_set_ltr_vals(pcie2); /* TODO: - si_core_wrapperreg(pcie2, 3, 0x60, 0x8080, 0); */ + *si_core_wrapperreg(pcie2, 3, 0x60, 0x8080, 0); + */ /* enable the LTR */ devstsctr2 |= PCIE2_CAP_DEVSTSCTRL2_LTRENAB; diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 442e777bdfb2..f781eff7d23e 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -268,17 +268,17 @@ static bool DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller) void *AllocationPointer = NULL; void *ScatterGatherCPU = NULL; dma_addr_t ScatterGatherDMA; - struct pci_pool *ScatterGatherPool; + struct dma_pool *ScatterGatherPool; void *RequestSenseCPU = NULL; dma_addr_t RequestSenseDMA; - struct pci_pool *RequestSensePool = NULL; + struct dma_pool *RequestSensePool = NULL; if (Controller->FirmwareType == DAC960_V1_Controller) { CommandAllocationLength = offsetof(DAC960_Command_T, V1.EndMarker); CommandAllocationGroupSize = DAC960_V1_CommandAllocationGroupSize; - ScatterGatherPool = pci_pool_create("DAC960_V1_ScatterGather", - Controller->PCIDevice, + ScatterGatherPool = dma_pool_create("DAC960_V1_ScatterGather", + &Controller->PCIDevice->dev, DAC960_V1_ScatterGatherLimit * sizeof(DAC960_V1_ScatterGatherSegment_T), sizeof(DAC960_V1_ScatterGatherSegment_T), 0); if (ScatterGatherPool == NULL) @@ -290,18 +290,18 @@ static bool DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller) { CommandAllocationLength = offsetof(DAC960_Command_T, V2.EndMarker); CommandAllocationGroupSize = DAC960_V2_CommandAllocationGroupSize; - ScatterGatherPool = pci_pool_create("DAC960_V2_ScatterGather", - Controller->PCIDevice, + ScatterGatherPool = dma_pool_create("DAC960_V2_ScatterGather", + &Controller->PCIDevice->dev, DAC960_V2_ScatterGatherLimit * sizeof(DAC960_V2_ScatterGatherSegment_T), sizeof(DAC960_V2_ScatterGatherSegment_T), 0); if (ScatterGatherPool == NULL) return DAC960_Failure(Controller, "AUXILIARY STRUCTURE CREATION (SG)"); - RequestSensePool = pci_pool_create("DAC960_V2_RequestSense", - Controller->PCIDevice, sizeof(DAC960_SCSI_RequestSense_T), + RequestSensePool = dma_pool_create("DAC960_V2_RequestSense", + &Controller->PCIDevice->dev, sizeof(DAC960_SCSI_RequestSense_T), sizeof(int), 0); if (RequestSensePool == NULL) { - pci_pool_destroy(ScatterGatherPool); + dma_pool_destroy(ScatterGatherPool); return DAC960_Failure(Controller, "AUXILIARY STRUCTURE CREATION (SG)"); } @@ -335,16 +335,16 @@ static bool DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller) Command->Next = Controller->FreeCommands; Controller->FreeCommands = Command; Controller->Commands[CommandIdentifier-1] = Command; - ScatterGatherCPU = pci_pool_alloc(ScatterGatherPool, GFP_ATOMIC, + ScatterGatherCPU = dma_pool_alloc(ScatterGatherPool, GFP_ATOMIC, &ScatterGatherDMA); if (ScatterGatherCPU == NULL) return DAC960_Failure(Controller, "AUXILIARY STRUCTURE CREATION"); if (RequestSensePool != NULL) { - RequestSenseCPU = pci_pool_alloc(RequestSensePool, GFP_ATOMIC, + RequestSenseCPU = dma_pool_alloc(RequestSensePool, GFP_ATOMIC, &RequestSenseDMA); if (RequestSenseCPU == NULL) { - pci_pool_free(ScatterGatherPool, ScatterGatherCPU, + dma_pool_free(ScatterGatherPool, ScatterGatherCPU, ScatterGatherDMA); return DAC960_Failure(Controller, "AUXILIARY STRUCTURE CREATION"); @@ -379,8 +379,8 @@ static bool DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller) static void DAC960_DestroyAuxiliaryStructures(DAC960_Controller_T *Controller) { int i; - struct pci_pool *ScatterGatherPool = Controller->ScatterGatherPool; - struct pci_pool *RequestSensePool = NULL; + struct dma_pool *ScatterGatherPool = Controller->ScatterGatherPool; + struct dma_pool *RequestSensePool = NULL; void *ScatterGatherCPU; dma_addr_t ScatterGatherDMA; void *RequestSenseCPU; @@ -411,9 +411,9 @@ static void DAC960_DestroyAuxiliaryStructures(DAC960_Controller_T *Controller) RequestSenseDMA = Command->V2.RequestSenseDMA; } if (ScatterGatherCPU != NULL) - pci_pool_free(ScatterGatherPool, ScatterGatherCPU, ScatterGatherDMA); + dma_pool_free(ScatterGatherPool, ScatterGatherCPU, ScatterGatherDMA); if (RequestSenseCPU != NULL) - pci_pool_free(RequestSensePool, RequestSenseCPU, RequestSenseDMA); + dma_pool_free(RequestSensePool, RequestSenseCPU, RequestSenseDMA); if ((Command->CommandIdentifier % Controller->CommandAllocationGroupSize) == 1) { @@ -437,13 +437,11 @@ static void DAC960_DestroyAuxiliaryStructures(DAC960_Controller_T *Controller) Controller->CurrentStatusBuffer = NULL; } - if (ScatterGatherPool != NULL) - pci_pool_destroy(ScatterGatherPool); + dma_pool_destroy(ScatterGatherPool); if (Controller->FirmwareType == DAC960_V1_Controller) return; - if (RequestSensePool != NULL) - pci_pool_destroy(RequestSensePool); + dma_pool_destroy(RequestSensePool); for (i = 0; i < DAC960_MaxLogicalDrives; i++) { kfree(Controller->V2.LogicalDeviceInformation[i]); @@ -6619,43 +6617,27 @@ static void DAC960_DestroyProcEntries(DAC960_Controller_T *Controller) #ifdef DAC960_GAM_MINOR -/* - * DAC960_gam_ioctl is the ioctl function for performing RAID operations. -*/ - -static long DAC960_gam_ioctl(struct file *file, unsigned int Request, - unsigned long Argument) +static long DAC960_gam_get_controller_info(DAC960_ControllerInfo_T __user *UserSpaceControllerInfo) { - long ErrorCode = 0; - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - - mutex_lock(&DAC960_mutex); - switch (Request) - { - case DAC960_IOCTL_GET_CONTROLLER_COUNT: - ErrorCode = DAC960_ControllerCount; - break; - case DAC960_IOCTL_GET_CONTROLLER_INFO: - { - DAC960_ControllerInfo_T __user *UserSpaceControllerInfo = - (DAC960_ControllerInfo_T __user *) Argument; DAC960_ControllerInfo_T ControllerInfo; DAC960_Controller_T *Controller; int ControllerNumber; + long ErrorCode; + if (UserSpaceControllerInfo == NULL) ErrorCode = -EINVAL; else ErrorCode = get_user(ControllerNumber, &UserSpaceControllerInfo->ControllerNumber); if (ErrorCode != 0) - break; + goto out; ErrorCode = -ENXIO; if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) { - break; + goto out; } Controller = DAC960_Controllers[ControllerNumber]; if (Controller == NULL) - break; + goto out; memset(&ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T)); ControllerInfo.ControllerNumber = ControllerNumber; ControllerInfo.FirmwareType = Controller->FirmwareType; @@ -6670,12 +6652,12 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, strcpy(ControllerInfo.FirmwareVersion, Controller->FirmwareVersion); ErrorCode = (copy_to_user(UserSpaceControllerInfo, &ControllerInfo, sizeof(DAC960_ControllerInfo_T)) ? -EFAULT : 0); - break; - } - case DAC960_IOCTL_V1_EXECUTE_COMMAND: - { - DAC960_V1_UserCommand_T __user *UserSpaceUserCommand = - (DAC960_V1_UserCommand_T __user *) Argument; +out: + return ErrorCode; +} + +static long DAC960_gam_v1_execute_command(DAC960_V1_UserCommand_T __user *UserSpaceUserCommand) +{ DAC960_V1_UserCommand_T UserCommand; DAC960_Controller_T *Controller; DAC960_Command_T *Command = NULL; @@ -6688,39 +6670,41 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, int ControllerNumber, DataTransferLength; unsigned char *DataTransferBuffer = NULL; dma_addr_t DataTransferBufferDMA; + long ErrorCode; + if (UserSpaceUserCommand == NULL) { ErrorCode = -EINVAL; - break; + goto out; } if (copy_from_user(&UserCommand, UserSpaceUserCommand, sizeof(DAC960_V1_UserCommand_T))) { ErrorCode = -EFAULT; - break; + goto out; } ControllerNumber = UserCommand.ControllerNumber; ErrorCode = -ENXIO; if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) - break; + goto out; Controller = DAC960_Controllers[ControllerNumber]; if (Controller == NULL) - break; + goto out; ErrorCode = -EINVAL; if (Controller->FirmwareType != DAC960_V1_Controller) - break; + goto out; CommandOpcode = UserCommand.CommandMailbox.Common.CommandOpcode; DataTransferLength = UserCommand.DataTransferLength; if (CommandOpcode & 0x80) - break; + goto out; if (CommandOpcode == DAC960_V1_DCDB) { if (copy_from_user(&DCDB, UserCommand.DCDB, sizeof(DAC960_V1_DCDB_T))) { ErrorCode = -EFAULT; - break; + goto out; } if (DCDB.Channel >= DAC960_V1_MaxChannels) - break; + goto out; if (!((DataTransferLength == 0 && DCDB.Direction == DAC960_V1_DCDB_NoDataTransfer) || @@ -6730,15 +6714,15 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, (DataTransferLength < 0 && DCDB.Direction == DAC960_V1_DCDB_DataTransferSystemToDevice))) - break; + goto out; if (((DCDB.TransferLengthHigh4 << 16) | DCDB.TransferLength) != abs(DataTransferLength)) - break; + goto out; DCDB_IOBUF = pci_alloc_consistent(Controller->PCIDevice, sizeof(DAC960_V1_DCDB_T), &DCDB_IOBUFDMA); if (DCDB_IOBUF == NULL) { ErrorCode = -ENOMEM; - break; + goto out; } } ErrorCode = -ENOMEM; @@ -6748,19 +6732,19 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, DataTransferLength, &DataTransferBufferDMA); if (DataTransferBuffer == NULL) - break; + goto out; } else if (DataTransferLength < 0) { DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, -DataTransferLength, &DataTransferBufferDMA); if (DataTransferBuffer == NULL) - break; + goto out; if (copy_from_user(DataTransferBuffer, UserCommand.DataTransferBuffer, -DataTransferLength)) { ErrorCode = -EFAULT; - break; + goto out; } } if (CommandOpcode == DAC960_V1_DCDB) @@ -6837,12 +6821,12 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, if (DCDB_IOBUF != NULL) pci_free_consistent(Controller->PCIDevice, sizeof(DAC960_V1_DCDB_T), DCDB_IOBUF, DCDB_IOBUFDMA); - break; - } - case DAC960_IOCTL_V2_EXECUTE_COMMAND: - { - DAC960_V2_UserCommand_T __user *UserSpaceUserCommand = - (DAC960_V2_UserCommand_T __user *) Argument; + out: + return ErrorCode; +} + +static long DAC960_gam_v2_execute_command(DAC960_V2_UserCommand_T __user *UserSpaceUserCommand) +{ DAC960_V2_UserCommand_T UserCommand; DAC960_Controller_T *Controller; DAC960_Command_T *Command = NULL; @@ -6855,26 +6839,26 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, dma_addr_t DataTransferBufferDMA; unsigned char *RequestSenseBuffer = NULL; dma_addr_t RequestSenseBufferDMA; + long ErrorCode = -EINVAL; - ErrorCode = -EINVAL; if (UserSpaceUserCommand == NULL) - break; + goto out; if (copy_from_user(&UserCommand, UserSpaceUserCommand, sizeof(DAC960_V2_UserCommand_T))) { ErrorCode = -EFAULT; - break; + goto out; } ErrorCode = -ENXIO; ControllerNumber = UserCommand.ControllerNumber; if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) - break; + goto out; Controller = DAC960_Controllers[ControllerNumber]; if (Controller == NULL) - break; + goto out; if (Controller->FirmwareType != DAC960_V2_Controller){ ErrorCode = -EINVAL; - break; + goto out; } DataTransferLength = UserCommand.DataTransferLength; ErrorCode = -ENOMEM; @@ -6884,14 +6868,14 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, DataTransferLength, &DataTransferBufferDMA); if (DataTransferBuffer == NULL) - break; + goto out; } else if (DataTransferLength < 0) { DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, -DataTransferLength, &DataTransferBufferDMA); if (DataTransferBuffer == NULL) - break; + goto out; if (copy_from_user(DataTransferBuffer, UserCommand.DataTransferBuffer, -DataTransferLength)) { @@ -7001,42 +6985,44 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, if (RequestSenseBuffer != NULL) pci_free_consistent(Controller->PCIDevice, RequestSenseLength, RequestSenseBuffer, RequestSenseBufferDMA); - break; - } - case DAC960_IOCTL_V2_GET_HEALTH_STATUS: - { - DAC960_V2_GetHealthStatus_T __user *UserSpaceGetHealthStatus = - (DAC960_V2_GetHealthStatus_T __user *) Argument; +out: + return ErrorCode; +} + +static long DAC960_gam_v2_get_health_status(DAC960_V2_GetHealthStatus_T __user *UserSpaceGetHealthStatus) +{ DAC960_V2_GetHealthStatus_T GetHealthStatus; DAC960_V2_HealthStatusBuffer_T HealthStatusBuffer; DAC960_Controller_T *Controller; int ControllerNumber; + long ErrorCode; + if (UserSpaceGetHealthStatus == NULL) { ErrorCode = -EINVAL; - break; + goto out; } if (copy_from_user(&GetHealthStatus, UserSpaceGetHealthStatus, sizeof(DAC960_V2_GetHealthStatus_T))) { ErrorCode = -EFAULT; - break; + goto out; } ErrorCode = -ENXIO; ControllerNumber = GetHealthStatus.ControllerNumber; if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) - break; + goto out; Controller = DAC960_Controllers[ControllerNumber]; if (Controller == NULL) - break; + goto out; if (Controller->FirmwareType != DAC960_V2_Controller) { ErrorCode = -EINVAL; - break; + goto out; } if (copy_from_user(&HealthStatusBuffer, GetHealthStatus.HealthStatusBuffer, sizeof(DAC960_V2_HealthStatusBuffer_T))) { ErrorCode = -EFAULT; - break; + goto out; } ErrorCode = wait_event_interruptible_timeout(Controller->HealthStatusWaitQueue, !(Controller->V2.HealthStatusBuffer->StatusChangeCounter @@ -7046,7 +7032,7 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, DAC960_MonitoringTimerInterval); if (ErrorCode == -ERESTARTSYS) { ErrorCode = -EINTR; - break; + goto out; } if (copy_to_user(GetHealthStatus.HealthStatusBuffer, Controller->V2.HealthStatusBuffer, @@ -7054,7 +7040,39 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, ErrorCode = -EFAULT; else ErrorCode = 0; - } + +out: + return ErrorCode; +} + +/* + * DAC960_gam_ioctl is the ioctl function for performing RAID operations. +*/ + +static long DAC960_gam_ioctl(struct file *file, unsigned int Request, + unsigned long Argument) +{ + long ErrorCode = 0; + void __user *argp = (void __user *)Argument; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + + mutex_lock(&DAC960_mutex); + switch (Request) + { + case DAC960_IOCTL_GET_CONTROLLER_COUNT: + ErrorCode = DAC960_ControllerCount; + break; + case DAC960_IOCTL_GET_CONTROLLER_INFO: + ErrorCode = DAC960_gam_get_controller_info(argp); + break; + case DAC960_IOCTL_V1_EXECUTE_COMMAND: + ErrorCode = DAC960_gam_v1_execute_command(argp); + break; + case DAC960_IOCTL_V2_EXECUTE_COMMAND: + ErrorCode = DAC960_gam_v2_execute_command(argp); + break; + case DAC960_IOCTL_V2_GET_HEALTH_STATUS: + ErrorCode = DAC960_gam_v2_get_health_status(argp); break; default: ErrorCode = -ENOTTY; diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h index 6a6226a2b932..21aff470d268 100644 --- a/drivers/block/DAC960.h +++ b/drivers/block/DAC960.h @@ -2316,7 +2316,7 @@ typedef struct DAC960_Controller bool SuppressEnclosureMessages; struct timer_list MonitoringTimer; struct gendisk *disks[DAC960_MaxLogicalDrives]; - struct pci_pool *ScatterGatherPool; + struct dma_pool *ScatterGatherPool; DAC960_Command_T *FreeCommands; unsigned char *CombinedStatusBuffer; unsigned char *CurrentStatusBuffer; @@ -2429,7 +2429,7 @@ typedef struct DAC960_Controller bool NeedDeviceSerialNumberInformation; bool StartLogicalDeviceInformationScan; bool StartPhysicalDeviceInformationScan; - struct pci_pool *RequestSensePool; + struct dma_pool *RequestSensePool; dma_addr_t FirstCommandMailboxDMA; DAC960_V2_CommandMailbox_T *FirstCommandMailbox; diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 40579d0cb3d1..ad9b687a236a 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -20,6 +20,10 @@ config BLK_DEV_NULL_BLK tristate "Null test block driver" select CONFIGFS_FS +config BLK_DEV_NULL_BLK_FAULT_INJECTION + bool "Support fault injection for Null test block driver" + depends on BLK_DEV_NULL_BLK && FAULT_INJECTION + config BLK_DEV_FD tristate "Normal floppy disk support" depends on ARCH_MAY_HAVE_PC_FDC diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 9220f8e833d0..c0ebda1283cc 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -112,8 +112,7 @@ enum frame_flags { struct frame { struct list_head head; u32 tag; - struct timeval sent; /* high-res time packet was sent */ - u32 sent_jiffs; /* low-res jiffies-based sent time */ + ktime_t sent; /* high-res time packet was sent */ ulong waited; ulong waited_total; struct aoetgt *t; /* parent target I belong to */ diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 812fed069708..540bb60cd071 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -398,8 +398,7 @@ aoecmd_ata_rw(struct aoedev *d) skb = skb_clone(f->skb, GFP_ATOMIC); if (skb) { - do_gettimeofday(&f->sent); - f->sent_jiffs = (u32) jiffies; + f->sent = ktime_get(); __skb_queue_head_init(&queue); __skb_queue_tail(&queue, skb); aoenet_xmit(&queue); @@ -489,8 +488,7 @@ resend(struct aoedev *d, struct frame *f) skb = skb_clone(skb, GFP_ATOMIC); if (skb == NULL) return; - do_gettimeofday(&f->sent); - f->sent_jiffs = (u32) jiffies; + f->sent = ktime_get(); __skb_queue_head_init(&queue); __skb_queue_tail(&queue, skb); aoenet_xmit(&queue); @@ -499,33 +497,17 @@ resend(struct aoedev *d, struct frame *f) static int tsince_hr(struct frame *f) { - struct timeval now; - int n; + u64 delta = ktime_to_ns(ktime_sub(ktime_get(), f->sent)); - do_gettimeofday(&now); - n = now.tv_usec - f->sent.tv_usec; - n += (now.tv_sec - f->sent.tv_sec) * USEC_PER_SEC; + /* delta is normally under 4.2 seconds, avoid 64-bit division */ + if (likely(delta <= UINT_MAX)) + return (u32)delta / NSEC_PER_USEC; - if (n < 0) - n = -n; + /* avoid overflow after 71 minutes */ + if (delta > ((u64)INT_MAX * NSEC_PER_USEC)) + return INT_MAX; - /* For relatively long periods, use jiffies to avoid - * discrepancies caused by updates to the system time. - * - * On system with HZ of 1000, 32-bits is over 49 days - * worth of jiffies, or over 71 minutes worth of usecs. - * - * Jiffies overflow is handled by subtraction of unsigned ints: - * (gdb) print (unsigned) 2 - (unsigned) 0xfffffffe - * $3 = 4 - * (gdb) - */ - if (n > USEC_PER_SEC / 4) { - n = ((u32) jiffies) - f->sent_jiffs; - n *= USEC_PER_SEC / HZ; - } - - return n; + return div_u64(delta, NSEC_PER_USEC); } static int @@ -589,7 +571,6 @@ reassign_frame(struct frame *f) nf->waited = 0; nf->waited_total = f->waited_total; nf->sent = f->sent; - nf->sent_jiffs = f->sent_jiffs; f->skb = skb; return nf; @@ -633,8 +614,7 @@ probe(struct aoetgt *t) skb = skb_clone(f->skb, GFP_ATOMIC); if (skb) { - do_gettimeofday(&f->sent); - f->sent_jiffs = (u32) jiffies; + f->sent = ktime_get(); __skb_queue_head_init(&queue); __skb_queue_tail(&queue, skb); aoenet_xmit(&queue); @@ -1432,10 +1412,8 @@ aoecmd_ata_id(struct aoedev *d) d->timer.function = rexmit_timer; skb = skb_clone(skb, GFP_ATOMIC); - if (skb) { - do_gettimeofday(&f->sent); - f->sent_jiffs = (u32) jiffies; - } + if (skb) + f->sent = ktime_get(); return skb; } diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index bd97908c766f..9f4e6f502b84 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -953,7 +953,7 @@ static void drbd_bm_endio(struct bio *bio) struct drbd_bm_aio_ctx *ctx = bio->bi_private; struct drbd_device *device = ctx->device; struct drbd_bitmap *b = device->bitmap; - unsigned int idx = bm_page_to_idx(bio->bi_io_vec[0].bv_page); + unsigned int idx = bm_page_to_idx(bio_first_page_all(bio)); if ((ctx->flags & BM_AIO_COPY_PAGES) == 0 && !bm_test_page_unchanged(b->bm_pages[idx])) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 4b4697a1f963..0a0394aa1b9c 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1847,7 +1847,7 @@ int drbd_send(struct drbd_connection *connection, struct socket *sock, void *buf, size_t size, unsigned msg_flags) { struct kvec iov = {.iov_base = buf, .iov_len = size}; - struct msghdr msg; + struct msghdr msg = {.msg_flags = msg_flags | MSG_NOSIGNAL}; int rv, sent = 0; if (!sock) @@ -1855,12 +1855,6 @@ int drbd_send(struct drbd_connection *connection, struct socket *sock, /* THINK if (signal_pending) return ... ? */ - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = msg_flags | MSG_NOSIGNAL; - iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &iov, 1, size); if (sock == connection->data.socket) { diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index cb2fa63f6bc0..c72dee0ef083 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -516,7 +516,8 @@ static int drbd_recv_short(struct socket *sock, void *buf, size_t size, int flag struct msghdr msg = { .msg_flags = (flags ? flags : MSG_WAITALL | MSG_NOSIGNAL) }; - return kernel_recvmsg(sock, &msg, &iov, 1, size, msg.msg_flags); + iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, &iov, 1, size); + return sock_recvmsg(sock, &msg, msg.msg_flags); } static int drbd_recv(struct drbd_connection *connection, void *buf, size_t size) diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index ad0477ae820f..287a09611c0f 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -12,9 +12,9 @@ #include #include #include -#include #include #include +#include #define SECTOR_SHIFT 9 #define PAGE_SECTORS_SHIFT (PAGE_SHIFT - SECTOR_SHIFT) @@ -27,6 +27,10 @@ #define TICKS_PER_SEC 50ULL #define TIMER_INTERVAL (NSEC_PER_SEC / TICKS_PER_SEC) +#ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION +static DECLARE_FAULT_ATTR(null_timeout_attr); +#endif + static inline u64 mb_per_tick(int mbps) { return (1 << 20) / TICKS_PER_SEC * ((u64) mbps); @@ -107,7 +111,6 @@ struct nullb_device { unsigned int hw_queue_depth; /* queue depth */ unsigned int index; /* index of the disk, only valid with a disk */ unsigned int mbps; /* Bandwidth throttle cap (in MB/s) */ - bool use_lightnvm; /* register as a LightNVM device */ bool blocking; /* blocking blk-mq device */ bool use_per_node_hctx; /* use per-node allocation for hardware context */ bool power; /* power on/off the device */ @@ -121,7 +124,6 @@ struct nullb { unsigned int index; struct request_queue *q; struct gendisk *disk; - struct nvm_dev *ndev; struct blk_mq_tag_set *tag_set; struct blk_mq_tag_set __tag_set; unsigned int queue_depth; @@ -139,7 +141,6 @@ static LIST_HEAD(nullb_list); static struct mutex lock; static int null_major; static DEFINE_IDA(nullb_indexes); -static struct kmem_cache *ppa_cache; static struct blk_mq_tag_set tag_set; enum { @@ -166,6 +167,11 @@ static int g_home_node = NUMA_NO_NODE; module_param_named(home_node, g_home_node, int, S_IRUGO); MODULE_PARM_DESC(home_node, "Home node for the device"); +#ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION +static char g_timeout_str[80]; +module_param_string(timeout, g_timeout_str, sizeof(g_timeout_str), S_IRUGO); +#endif + static int g_queue_mode = NULL_Q_MQ; static int null_param_store_val(const char *str, int *val, int min, int max) @@ -208,10 +214,6 @@ static int nr_devices = 1; module_param(nr_devices, int, S_IRUGO); MODULE_PARM_DESC(nr_devices, "Number of devices to register"); -static bool g_use_lightnvm; -module_param_named(use_lightnvm, g_use_lightnvm, bool, S_IRUGO); -MODULE_PARM_DESC(use_lightnvm, "Register as a LightNVM device"); - static bool g_blocking; module_param_named(blocking, g_blocking, bool, S_IRUGO); MODULE_PARM_DESC(blocking, "Register as a blocking blk-mq driver device"); @@ -345,7 +347,6 @@ NULLB_DEVICE_ATTR(blocksize, uint); NULLB_DEVICE_ATTR(irqmode, uint); NULLB_DEVICE_ATTR(hw_queue_depth, uint); NULLB_DEVICE_ATTR(index, uint); -NULLB_DEVICE_ATTR(use_lightnvm, bool); NULLB_DEVICE_ATTR(blocking, bool); NULLB_DEVICE_ATTR(use_per_node_hctx, bool); NULLB_DEVICE_ATTR(memory_backed, bool); @@ -455,7 +456,6 @@ static struct configfs_attribute *nullb_device_attrs[] = { &nullb_device_attr_irqmode, &nullb_device_attr_hw_queue_depth, &nullb_device_attr_index, - &nullb_device_attr_use_lightnvm, &nullb_device_attr_blocking, &nullb_device_attr_use_per_node_hctx, &nullb_device_attr_power, @@ -573,7 +573,6 @@ static struct nullb_device *null_alloc_dev(void) dev->blocksize = g_bs; dev->irqmode = g_irqmode; dev->hw_queue_depth = g_hw_queue_depth; - dev->use_lightnvm = g_use_lightnvm; dev->blocking = g_blocking; dev->use_per_node_hctx = g_use_per_node_hctx; return dev; @@ -1231,7 +1230,7 @@ static blk_status_t null_handle_cmd(struct nullb_cmd *cmd) return BLK_STS_OK; } else /* requeue request */ - return BLK_STS_RESOURCE; + return BLK_STS_DEV_RESOURCE; } } @@ -1352,6 +1351,12 @@ static blk_qc_t null_queue_bio(struct request_queue *q, struct bio *bio) return BLK_QC_T_NONE; } +static enum blk_eh_timer_return null_rq_timed_out_fn(struct request *rq) +{ + pr_info("null: rq %p timed out\n", rq); + return BLK_EH_HANDLED; +} + static int null_rq_prep_fn(struct request_queue *q, struct request *req) { struct nullb *nullb = q->queuedata; @@ -1369,6 +1374,16 @@ static int null_rq_prep_fn(struct request_queue *q, struct request *req) return BLKPREP_DEFER; } +static bool should_timeout_request(struct request *rq) +{ +#ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION + if (g_timeout_str[0]) + return should_fail(&null_timeout_attr, 1); +#endif + + return false; +} + static void null_request_fn(struct request_queue *q) { struct request *rq; @@ -1376,12 +1391,20 @@ static void null_request_fn(struct request_queue *q) while ((rq = blk_fetch_request(q)) != NULL) { struct nullb_cmd *cmd = rq->special; - spin_unlock_irq(q->queue_lock); - null_handle_cmd(cmd); - spin_lock_irq(q->queue_lock); + if (!should_timeout_request(rq)) { + spin_unlock_irq(q->queue_lock); + null_handle_cmd(cmd); + spin_lock_irq(q->queue_lock); + } } } +static enum blk_eh_timer_return null_timeout_rq(struct request *rq, bool res) +{ + pr_info("null: rq %p timed out\n", rq); + return BLK_EH_HANDLED; +} + static blk_status_t null_queue_rq(struct blk_mq_hw_ctx *hctx, const struct blk_mq_queue_data *bd) { @@ -1399,12 +1422,16 @@ static blk_status_t null_queue_rq(struct blk_mq_hw_ctx *hctx, blk_mq_start_request(bd->rq); - return null_handle_cmd(cmd); + if (!should_timeout_request(bd->rq)) + return null_handle_cmd(cmd); + + return BLK_STS_OK; } static const struct blk_mq_ops null_mq_ops = { .queue_rq = null_queue_rq, .complete = null_softirq_done_fn, + .timeout = null_timeout_rq, }; static void cleanup_queue(struct nullb_queue *nq) @@ -1423,170 +1450,6 @@ static void cleanup_queues(struct nullb *nullb) kfree(nullb->queues); } -#ifdef CONFIG_NVM - -static void null_lnvm_end_io(struct request *rq, blk_status_t status) -{ - struct nvm_rq *rqd = rq->end_io_data; - - /* XXX: lighnvm core seems to expect NVM_RSP_* values here.. */ - rqd->error = status ? -EIO : 0; - nvm_end_io(rqd); - - blk_put_request(rq); -} - -static int null_lnvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd) -{ - struct request_queue *q = dev->q; - struct request *rq; - struct bio *bio = rqd->bio; - - rq = blk_mq_alloc_request(q, - op_is_write(bio_op(bio)) ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); - if (IS_ERR(rq)) - return -ENOMEM; - - blk_init_request_from_bio(rq, bio); - - rq->end_io_data = rqd; - - blk_execute_rq_nowait(q, NULL, rq, 0, null_lnvm_end_io); - - return 0; -} - -static int null_lnvm_id(struct nvm_dev *dev, struct nvm_id *id) -{ - struct nullb *nullb = dev->q->queuedata; - sector_t size = (sector_t)nullb->dev->size * 1024 * 1024ULL; - sector_t blksize; - struct nvm_id_group *grp; - - id->ver_id = 0x1; - id->vmnt = 0; - id->cap = 0x2; - id->dom = 0x1; - - id->ppaf.blk_offset = 0; - id->ppaf.blk_len = 16; - id->ppaf.pg_offset = 16; - id->ppaf.pg_len = 16; - id->ppaf.sect_offset = 32; - id->ppaf.sect_len = 8; - id->ppaf.pln_offset = 40; - id->ppaf.pln_len = 8; - id->ppaf.lun_offset = 48; - id->ppaf.lun_len = 8; - id->ppaf.ch_offset = 56; - id->ppaf.ch_len = 8; - - sector_div(size, nullb->dev->blocksize); /* convert size to pages */ - size >>= 8; /* concert size to pgs pr blk */ - grp = &id->grp; - grp->mtype = 0; - grp->fmtype = 0; - grp->num_ch = 1; - grp->num_pg = 256; - blksize = size; - size >>= 16; - grp->num_lun = size + 1; - sector_div(blksize, grp->num_lun); - grp->num_blk = blksize; - grp->num_pln = 1; - - grp->fpg_sz = nullb->dev->blocksize; - grp->csecs = nullb->dev->blocksize; - grp->trdt = 25000; - grp->trdm = 25000; - grp->tprt = 500000; - grp->tprm = 500000; - grp->tbet = 1500000; - grp->tbem = 1500000; - grp->mpos = 0x010101; /* single plane rwe */ - grp->cpar = nullb->dev->hw_queue_depth; - - return 0; -} - -static void *null_lnvm_create_dma_pool(struct nvm_dev *dev, char *name) -{ - mempool_t *virtmem_pool; - - virtmem_pool = mempool_create_slab_pool(64, ppa_cache); - if (!virtmem_pool) { - pr_err("null_blk: Unable to create virtual memory pool\n"); - return NULL; - } - - return virtmem_pool; -} - -static void null_lnvm_destroy_dma_pool(void *pool) -{ - mempool_destroy(pool); -} - -static void *null_lnvm_dev_dma_alloc(struct nvm_dev *dev, void *pool, - gfp_t mem_flags, dma_addr_t *dma_handler) -{ - return mempool_alloc(pool, mem_flags); -} - -static void null_lnvm_dev_dma_free(void *pool, void *entry, - dma_addr_t dma_handler) -{ - mempool_free(entry, pool); -} - -static struct nvm_dev_ops null_lnvm_dev_ops = { - .identity = null_lnvm_id, - .submit_io = null_lnvm_submit_io, - - .create_dma_pool = null_lnvm_create_dma_pool, - .destroy_dma_pool = null_lnvm_destroy_dma_pool, - .dev_dma_alloc = null_lnvm_dev_dma_alloc, - .dev_dma_free = null_lnvm_dev_dma_free, - - /* Simulate nvme protocol restriction */ - .max_phys_sect = 64, -}; - -static int null_nvm_register(struct nullb *nullb) -{ - struct nvm_dev *dev; - int rv; - - dev = nvm_alloc_dev(0); - if (!dev) - return -ENOMEM; - - dev->q = nullb->q; - memcpy(dev->name, nullb->disk_name, DISK_NAME_LEN); - dev->ops = &null_lnvm_dev_ops; - - rv = nvm_register(dev); - if (rv) { - kfree(dev); - return rv; - } - nullb->ndev = dev; - return 0; -} - -static void null_nvm_unregister(struct nullb *nullb) -{ - nvm_unregister(nullb->ndev); -} -#else -static int null_nvm_register(struct nullb *nullb) -{ - pr_err("null_blk: CONFIG_NVM needs to be enabled for LightNVM\n"); - return -EINVAL; -} -static void null_nvm_unregister(struct nullb *nullb) {} -#endif /* CONFIG_NVM */ - static void null_del_dev(struct nullb *nullb) { struct nullb_device *dev = nullb->dev; @@ -1595,10 +1458,7 @@ static void null_del_dev(struct nullb *nullb) list_del_init(&nullb->list); - if (dev->use_lightnvm) - null_nvm_unregister(nullb); - else - del_gendisk(nullb->disk); + del_gendisk(nullb->disk); if (test_bit(NULLB_DEV_FL_THROTTLED, &nullb->dev->flags)) { hrtimer_cancel(&nullb->bw_timer); @@ -1610,8 +1470,7 @@ static void null_del_dev(struct nullb *nullb) if (dev->queue_mode == NULL_Q_MQ && nullb->tag_set == &nullb->__tag_set) blk_mq_free_tag_set(nullb->tag_set); - if (!dev->use_lightnvm) - put_disk(nullb->disk); + put_disk(nullb->disk); cleanup_queues(nullb); if (null_cache_active(nullb)) null_free_device_storage(nullb->dev, true); @@ -1775,11 +1634,6 @@ static void null_validate_conf(struct nullb_device *dev) { dev->blocksize = round_down(dev->blocksize, 512); dev->blocksize = clamp_t(unsigned int, dev->blocksize, 512, 4096); - if (dev->use_lightnvm && dev->blocksize != 4096) - dev->blocksize = 4096; - - if (dev->use_lightnvm && dev->queue_mode != NULL_Q_MQ) - dev->queue_mode = NULL_Q_MQ; if (dev->queue_mode == NULL_Q_MQ && dev->use_per_node_hctx) { if (dev->submit_queues != nr_online_nodes) @@ -1805,6 +1659,20 @@ static void null_validate_conf(struct nullb_device *dev) dev->mbps = 0; } +static bool null_setup_fault(void) +{ +#ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION + if (!g_timeout_str[0]) + return true; + + if (!setup_fault_attr(&null_timeout_attr, g_timeout_str)) + return false; + + null_timeout_attr.verbose = 0; +#endif + return true; +} + static int null_add_dev(struct nullb_device *dev) { struct nullb *nullb; @@ -1838,6 +1706,10 @@ static int null_add_dev(struct nullb_device *dev) if (rv) goto out_cleanup_queues; + if (!null_setup_fault()) + goto out_cleanup_queues; + + nullb->tag_set->timeout = 5 * HZ; nullb->q = blk_mq_init_queue(nullb->tag_set); if (IS_ERR(nullb->q)) { rv = -ENOMEM; @@ -1861,8 +1733,14 @@ static int null_add_dev(struct nullb_device *dev) rv = -ENOMEM; goto out_cleanup_queues; } + + if (!null_setup_fault()) + goto out_cleanup_blk_queue; + blk_queue_prep_rq(nullb->q, null_rq_prep_fn); blk_queue_softirq_done(nullb->q, null_softirq_done_fn); + blk_queue_rq_timed_out(nullb->q, null_rq_timed_out_fn); + nullb->q->rq_timeout = 5 * HZ; rv = init_driver_queues(nullb); if (rv) goto out_cleanup_blk_queue; @@ -1895,11 +1773,7 @@ static int null_add_dev(struct nullb_device *dev) sprintf(nullb->disk_name, "nullb%d", nullb->index); - if (dev->use_lightnvm) - rv = null_nvm_register(nullb); - else - rv = null_gendisk_register(nullb); - + rv = null_gendisk_register(nullb); if (rv) goto out_cleanup_blk_queue; @@ -1938,18 +1812,6 @@ static int __init null_init(void) g_bs = PAGE_SIZE; } - if (g_use_lightnvm && g_bs != 4096) { - pr_warn("null_blk: LightNVM only supports 4k block size\n"); - pr_warn("null_blk: defaults block size to 4k\n"); - g_bs = 4096; - } - - if (g_use_lightnvm && g_queue_mode != NULL_Q_MQ) { - pr_warn("null_blk: LightNVM only supported for blk-mq\n"); - pr_warn("null_blk: defaults queue mode to blk-mq\n"); - g_queue_mode = NULL_Q_MQ; - } - if (g_queue_mode == NULL_Q_MQ && g_use_per_node_hctx) { if (g_submit_queues != nr_online_nodes) { pr_warn("null_blk: submit_queues param is set to %u.\n", @@ -1982,16 +1844,6 @@ static int __init null_init(void) goto err_conf; } - if (g_use_lightnvm) { - ppa_cache = kmem_cache_create("ppa_cache", 64 * sizeof(u64), - 0, 0, NULL); - if (!ppa_cache) { - pr_err("null_blk: unable to create ppa cache\n"); - ret = -ENOMEM; - goto err_ppa; - } - } - for (i = 0; i < nr_devices; i++) { dev = null_alloc_dev(); if (!dev) { @@ -2015,8 +1867,6 @@ err_dev: null_del_dev(nullb); null_free_dev(dev); } - kmem_cache_destroy(ppa_cache); -err_ppa: unregister_blkdev(null_major, "nullb"); err_conf: configfs_unregister_subsystem(&nullb_subsys); @@ -2047,8 +1897,6 @@ static void __exit null_exit(void) if (g_queue_mode == NULL_Q_MQ && shared_tags) blk_mq_free_tag_set(&tag_set); - - kmem_cache_destroy(ppa_cache); } module_init(null_init); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 67974796c350..531a0915066b 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2579,14 +2579,14 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) bdev = bdget(dev); if (!bdev) return -ENOMEM; - if (!blk_queue_scsi_passthrough(bdev_get_queue(bdev))) { - WARN_ONCE(true, "Attempt to register a non-SCSI queue\n"); - bdput(bdev); - return -EINVAL; - } ret = blkdev_get(bdev, FMODE_READ | FMODE_NDELAY, NULL); if (ret) return ret; + if (!blk_queue_scsi_passthrough(bdev_get_queue(bdev))) { + WARN_ONCE(true, "Attempt to register a non-SCSI queue\n"); + blkdev_put(bdev, FMODE_READ | FMODE_NDELAY); + return -EINVAL; + } /* This is safe, since we have a reference from open(). */ __module_get(THIS_MODULE); @@ -2745,7 +2745,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) pd->pkt_dev = MKDEV(pktdev_major, idx); ret = pkt_new_dev(pd, dev); if (ret) - goto out_new_dev; + goto out_mem2; /* inherit events of the host device */ disk->events = pd->bdev->bd_disk->events; @@ -2763,8 +2763,6 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) mutex_unlock(&ctl_mutex); return 0; -out_new_dev: - blk_cleanup_queue(disk->queue); out_mem2: put_disk(disk); out_mem: diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index cc93522a6d41..8e40da093766 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -124,11 +124,13 @@ static int atomic_dec_return_safe(atomic_t *v) #define RBD_FEATURE_STRIPINGV2 (1ULL<<1) #define RBD_FEATURE_EXCLUSIVE_LOCK (1ULL<<2) #define RBD_FEATURE_DATA_POOL (1ULL<<7) +#define RBD_FEATURE_OPERATIONS (1ULL<<8) #define RBD_FEATURES_ALL (RBD_FEATURE_LAYERING | \ RBD_FEATURE_STRIPINGV2 | \ RBD_FEATURE_EXCLUSIVE_LOCK | \ - RBD_FEATURE_DATA_POOL) + RBD_FEATURE_DATA_POOL | \ + RBD_FEATURE_OPERATIONS) /* Features supported by this (client software) implementation. */ @@ -281,7 +283,6 @@ struct rbd_obj_request { int result; rbd_obj_callback_t callback; - struct completion completion; struct kref kref; }; @@ -1734,10 +1735,7 @@ static void rbd_obj_request_complete(struct rbd_obj_request *obj_request) { dout("%s: obj %p cb %p\n", __func__, obj_request, obj_request->callback); - if (obj_request->callback) - obj_request->callback(obj_request); - else - complete_all(&obj_request->completion); + obj_request->callback(obj_request); } static void rbd_obj_request_error(struct rbd_obj_request *obj_request, int err) @@ -2013,7 +2011,6 @@ rbd_obj_request_create(enum obj_request_type type) obj_request->which = BAD_WHICH; obj_request->type = type; INIT_LIST_HEAD(&obj_request->links); - init_completion(&obj_request->completion); kref_init(&obj_request->kref); dout("%s %p\n", __func__, obj_request); @@ -2129,15 +2126,13 @@ static struct rbd_img_request *rbd_img_request_create( { struct rbd_img_request *img_request; - img_request = kmem_cache_alloc(rbd_img_request_cache, GFP_NOIO); + img_request = kmem_cache_zalloc(rbd_img_request_cache, GFP_NOIO); if (!img_request) return NULL; - img_request->rq = NULL; img_request->rbd_dev = rbd_dev; img_request->offset = offset; img_request->length = length; - img_request->flags = 0; if (op_type == OBJ_OP_DISCARD) { img_request_discard_set(img_request); img_request->snapc = snapc; @@ -2149,11 +2144,8 @@ static struct rbd_img_request *rbd_img_request_create( } if (rbd_dev_parent_get(rbd_dev)) img_request_layered_set(img_request); + spin_lock_init(&img_request->completion_lock); - img_request->next_completion = 0; - img_request->callback = NULL; - img_request->result = 0; - img_request->obj_request_count = 0; INIT_LIST_HEAD(&img_request->obj_requests); kref_init(&img_request->kref); @@ -2692,8 +2684,6 @@ static int rbd_img_obj_parent_read_full(struct rbd_obj_request *obj_request) parent_request->copyup_pages = NULL; parent_request->copyup_page_count = 0; - parent_request->obj_request = NULL; - rbd_obj_request_put(obj_request); out_err: if (pages) ceph_release_page_vector(pages, page_count); diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index de0d08133c7e..e41935ab41ef 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -2603,7 +2602,8 @@ static void *skd_alloc_dma(struct skd_device *skdev, struct kmem_cache *s, buf = kmem_cache_alloc(s, gfp); if (!buf) return NULL; - *dma_handle = dma_map_single(dev, buf, s->size, dir); + *dma_handle = dma_map_single(dev, buf, + kmem_cache_size(s), dir); if (dma_mapping_error(dev, *dma_handle)) { kmem_cache_free(s, buf); buf = NULL; @@ -2618,7 +2618,8 @@ static void skd_free_dma(struct skd_device *skdev, struct kmem_cache *s, if (!vaddr) return; - dma_unmap_single(&skdev->pdev->dev, dma_handle, s->size, dir); + dma_unmap_single(&skdev->pdev->dev, dma_handle, + kmem_cache_size(s), dir); kmem_cache_free(s, vaddr); } diff --git a/drivers/block/smart1,2.h b/drivers/block/smart1,2.h deleted file mode 100644 index e5565fbaeb30..000000000000 --- a/drivers/block/smart1,2.h +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Disk Array driver for Compaq SMART2 Controllers - * Copyright 1998 Compaq Computer Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, GOOD TITLE or - * NON INFRINGEMENT. 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, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Questions/Comments/Bugfixes to iss_storagedev@hp.com - * - * If you want to make changes, improve or add functionality to this - * driver, you'll probably need the Compaq Array Controller Interface - * Specificiation (Document number ECG086/1198) - */ - -/* - * This file contains the controller communication implementation for - * Compaq SMART-1 and SMART-2 controllers. To the best of my knowledge, - * this should support: - * - * PCI: - * SMART-2/P, SMART-2DH, SMART-2SL, SMART-221, SMART-3100ES, SMART-3200 - * Integerated SMART Array Controller, SMART-4200, SMART-4250ES - * - * EISA: - * SMART-2/E, SMART, IAES, IDA-2, IDA - */ - -/* - * Memory mapped FIFO interface (SMART 42xx cards) - */ -static void smart4_submit_command(ctlr_info_t *h, cmdlist_t *c) -{ - writel(c->busaddr, h->vaddr + S42XX_REQUEST_PORT_OFFSET); -} - -/* - * This card is the opposite of the other cards. - * 0 turns interrupts on... - * 0x08 turns them off... - */ -static void smart4_intr_mask(ctlr_info_t *h, unsigned long val) -{ - if (val) - { /* Turn interrupts on */ - writel(0, h->vaddr + S42XX_REPLY_INTR_MASK_OFFSET); - } else /* Turn them off */ - { - writel( S42XX_INTR_OFF, - h->vaddr + S42XX_REPLY_INTR_MASK_OFFSET); - } -} - -/* - * For older cards FIFO Full = 0. - * On this card 0 means there is room, anything else FIFO Full. - * - */ -static unsigned long smart4_fifo_full(ctlr_info_t *h) -{ - - return (!readl(h->vaddr + S42XX_REQUEST_PORT_OFFSET)); -} - -/* This type of controller returns -1 if the fifo is empty, - * Not 0 like the others. - * And we need to let it know we read a value out - */ -static unsigned long smart4_completed(ctlr_info_t *h) -{ - long register_value - = readl(h->vaddr + S42XX_REPLY_PORT_OFFSET); - - /* Fifo is empty */ - if( register_value == 0xffffffff) - return 0; - - /* Need to let it know we got the reply */ - /* We do this by writing a 0 to the port we just read from */ - writel(0, h->vaddr + S42XX_REPLY_PORT_OFFSET); - - return ((unsigned long) register_value); -} - - /* - * This hardware returns interrupt pending at a different place and - * it does not tell us if the fifo is empty, we will have check - * that by getting a 0 back from the command_completed call. - */ -static unsigned long smart4_intr_pending(ctlr_info_t *h) -{ - unsigned long register_value = - readl(h->vaddr + S42XX_INTR_STATUS); - - if( register_value & S42XX_INTR_PENDING) - return FIFO_NOT_EMPTY; - return 0 ; -} - -static struct access_method smart4_access = { - smart4_submit_command, - smart4_intr_mask, - smart4_fifo_full, - smart4_intr_pending, - smart4_completed, -}; - -/* - * Memory mapped FIFO interface (PCI SMART2 and SMART 3xxx cards) - */ -static void smart2_submit_command(ctlr_info_t *h, cmdlist_t *c) -{ - writel(c->busaddr, h->vaddr + COMMAND_FIFO); -} - -static void smart2_intr_mask(ctlr_info_t *h, unsigned long val) -{ - writel(val, h->vaddr + INTR_MASK); -} - -static unsigned long smart2_fifo_full(ctlr_info_t *h) -{ - return readl(h->vaddr + COMMAND_FIFO); -} - -static unsigned long smart2_completed(ctlr_info_t *h) -{ - return readl(h->vaddr + COMMAND_COMPLETE_FIFO); -} - -static unsigned long smart2_intr_pending(ctlr_info_t *h) -{ - return readl(h->vaddr + INTR_PENDING); -} - -static struct access_method smart2_access = { - smart2_submit_command, - smart2_intr_mask, - smart2_fifo_full, - smart2_intr_pending, - smart2_completed, -}; - -/* - * IO access for SMART-2/E cards - */ -static void smart2e_submit_command(ctlr_info_t *h, cmdlist_t *c) -{ - outl(c->busaddr, h->io_mem_addr + COMMAND_FIFO); -} - -static void smart2e_intr_mask(ctlr_info_t *h, unsigned long val) -{ - outl(val, h->io_mem_addr + INTR_MASK); -} - -static unsigned long smart2e_fifo_full(ctlr_info_t *h) -{ - return inl(h->io_mem_addr + COMMAND_FIFO); -} - -static unsigned long smart2e_completed(ctlr_info_t *h) -{ - return inl(h->io_mem_addr + COMMAND_COMPLETE_FIFO); -} - -static unsigned long smart2e_intr_pending(ctlr_info_t *h) -{ - return inl(h->io_mem_addr + INTR_PENDING); -} - -static struct access_method smart2e_access = { - smart2e_submit_command, - smart2e_intr_mask, - smart2e_fifo_full, - smart2e_intr_pending, - smart2e_completed, -}; - -/* - * IO access for older SMART-1 type cards - */ -#define SMART1_SYSTEM_MASK 0xC8E -#define SMART1_SYSTEM_DOORBELL 0xC8F -#define SMART1_LOCAL_MASK 0xC8C -#define SMART1_LOCAL_DOORBELL 0xC8D -#define SMART1_INTR_MASK 0xC89 -#define SMART1_LISTADDR 0xC90 -#define SMART1_LISTLEN 0xC94 -#define SMART1_TAG 0xC97 -#define SMART1_COMPLETE_ADDR 0xC98 -#define SMART1_LISTSTATUS 0xC9E - -#define CHANNEL_BUSY 0x01 -#define CHANNEL_CLEAR 0x02 - -static void smart1_submit_command(ctlr_info_t *h, cmdlist_t *c) -{ - /* - * This __u16 is actually a bunch of control flags on SMART - * and below. We want them all to be zero. - */ - c->hdr.size = 0; - - outb(CHANNEL_CLEAR, h->io_mem_addr + SMART1_SYSTEM_DOORBELL); - - outl(c->busaddr, h->io_mem_addr + SMART1_LISTADDR); - outw(c->size, h->io_mem_addr + SMART1_LISTLEN); - - outb(CHANNEL_BUSY, h->io_mem_addr + SMART1_LOCAL_DOORBELL); -} - -static void smart1_intr_mask(ctlr_info_t *h, unsigned long val) -{ - if (val == 1) { - outb(0xFD, h->io_mem_addr + SMART1_SYSTEM_DOORBELL); - outb(CHANNEL_BUSY, h->io_mem_addr + SMART1_LOCAL_DOORBELL); - outb(0x01, h->io_mem_addr + SMART1_INTR_MASK); - outb(0x01, h->io_mem_addr + SMART1_SYSTEM_MASK); - } else { - outb(0, h->io_mem_addr + 0xC8E); - } -} - -static unsigned long smart1_fifo_full(ctlr_info_t *h) -{ - unsigned char chan; - chan = inb(h->io_mem_addr + SMART1_SYSTEM_DOORBELL) & CHANNEL_CLEAR; - return chan; -} - -static unsigned long smart1_completed(ctlr_info_t *h) -{ - unsigned char status; - unsigned long cmd; - - if (inb(h->io_mem_addr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY) { - outb(CHANNEL_BUSY, h->io_mem_addr + SMART1_SYSTEM_DOORBELL); - - cmd = inl(h->io_mem_addr + SMART1_COMPLETE_ADDR); - status = inb(h->io_mem_addr + SMART1_LISTSTATUS); - - outb(CHANNEL_CLEAR, h->io_mem_addr + SMART1_LOCAL_DOORBELL); - - /* - * this is x86 (actually compaq x86) only, so it's ok - */ - if (cmd) ((cmdlist_t*)bus_to_virt(cmd))->req.hdr.rcode = status; - } else { - cmd = 0; - } - return cmd; -} - -static unsigned long smart1_intr_pending(ctlr_info_t *h) -{ - unsigned char chan; - chan = inb(h->io_mem_addr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY; - return chan; -} - -static struct access_method smart1_access = { - smart1_submit_command, - smart1_intr_mask, - smart1_fifo_full, - smart1_intr_pending, - smart1_completed, -}; diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 68846897d213..4a07593c2efd 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -276,7 +276,7 @@ static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx, /* Out of mem doesn't actually happen, since we fall back * to direct descriptors */ if (err == -ENOMEM || err == -ENOSPC) - return BLK_STS_RESOURCE; + return BLK_STS_DEV_RESOURCE; return BLK_STS_IOERR; } @@ -373,14 +373,12 @@ static ssize_t virtblk_serial_show(struct device *dev, static DEVICE_ATTR(serial, S_IRUGO, virtblk_serial_show, NULL); -static void virtblk_config_changed_work(struct work_struct *work) +/* The queue's logical block size must be set before calling this */ +static void virtblk_update_capacity(struct virtio_blk *vblk, bool resize) { - struct virtio_blk *vblk = - container_of(work, struct virtio_blk, config_work); struct virtio_device *vdev = vblk->vdev; struct request_queue *q = vblk->disk->queue; char cap_str_2[10], cap_str_10[10]; - char *envp[] = { "RESIZE=1", NULL }; unsigned long long nblocks; u64 capacity; @@ -402,13 +400,24 @@ static void virtblk_config_changed_work(struct work_struct *work) STRING_UNITS_10, cap_str_10, sizeof(cap_str_10)); dev_notice(&vdev->dev, - "new size: %llu %d-byte logical blocks (%s/%s)\n", + "[%s] %s%llu %d-byte logical blocks (%s/%s)\n", + vblk->disk->disk_name, + resize ? "new size: " : "", nblocks, queue_logical_block_size(q), cap_str_10, cap_str_2); set_capacity(vblk->disk, capacity); +} + +static void virtblk_config_changed_work(struct work_struct *work) +{ + struct virtio_blk *vblk = + container_of(work, struct virtio_blk, config_work); + char *envp[] = { "RESIZE=1", NULL }; + + virtblk_update_capacity(vblk, true); revalidate_disk(vblk->disk); kobject_uevent_env(&disk_to_dev(vblk->disk)->kobj, KOBJ_CHANGE, envp); } @@ -621,7 +630,6 @@ static int virtblk_probe(struct virtio_device *vdev) struct request_queue *q; int err, index; - u64 cap; u32 v, blk_size, sg_elems, opt_io_size; u16 min_io_size; u8 physical_block_exp, alignment_offset; @@ -719,17 +727,6 @@ static int virtblk_probe(struct virtio_device *vdev) if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO)) set_disk_ro(vblk->disk, 1); - /* Host must always specify the capacity. */ - virtio_cread(vdev, struct virtio_blk_config, capacity, &cap); - - /* If capacity is too big, truncate with warning. */ - if ((sector_t)cap != cap) { - dev_warn(&vdev->dev, "Capacity %llu too large: truncating\n", - (unsigned long long)cap); - cap = (sector_t)-1; - } - set_capacity(vblk->disk, cap); - /* We can handle whatever the host told us to handle. */ blk_queue_max_segments(q, vblk->sg_elems-2); @@ -780,6 +777,7 @@ static int virtblk_probe(struct virtio_device *vdev) if (!err && opt_io_size) blk_queue_io_opt(q, blk_size * opt_io_size); + virtblk_update_capacity(vblk, false); virtio_device_ready(vdev); device_add_disk(&vdev->dev, vblk->disk); diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 891265acb10e..e126e4cac2ca 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -911,7 +911,7 @@ out_err: out_busy: blk_mq_stop_hw_queue(hctx); spin_unlock_irqrestore(&rinfo->ring_lock, flags); - return BLK_STS_RESOURCE; + return BLK_STS_DEV_RESOURCE; } static void blkif_complete_rq(struct request *rq) diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index d70eba30003a..0afa6c8c3857 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -430,7 +430,7 @@ static void put_entry_bdev(struct zram *zram, unsigned long entry) static void zram_page_end_io(struct bio *bio) { - struct page *page = bio->bi_io_vec[0].bv_page; + struct page *page = bio_first_page_all(bio); page_endio(page, op_is_write(bio_op(bio)), blk_status_to_errno(bio->bi_status)); diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 60e1c7d6986d..07e55cd8f8c8 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -31,6 +31,16 @@ config BT_HCIBTUSB Say Y here to compile support for Bluetooth USB devices into the kernel or say M to compile it as module (btusb). +config BT_HCIBTUSB_AUTOSUSPEND + bool "Enable USB autosuspend for Bluetooth USB devices by default" + depends on BT_HCIBTUSB + help + Say Y here to enable USB autosuspend for Bluetooth USB devices by + default. + + This can be overridden by passing btusb.enable_autosuspend=[y|n] + on the kernel commandline. + config BT_HCIBTUSB_BCM bool "Broadcom protocol support" depends on BT_HCIBTUSB @@ -67,6 +77,7 @@ config BT_HCIBTSDIO config BT_HCIUART tristate "HCI UART driver" depends on SERIAL_DEV_BUS || !SERIAL_DEV_BUS + depends on NVMEM || !NVMEM depends on TTY help Bluetooth HCI UART driver. @@ -97,6 +108,7 @@ config BT_HCIUART_NOKIA tristate "UART Nokia H4+ protocol support" depends on BT_HCIUART depends on BT_HCIUART_SERDEV + depends on GPIOLIB depends on PM select BT_HCIUART_H4 select BT_BCM @@ -158,6 +170,7 @@ config BT_HCIUART_3WIRE config BT_HCIUART_INTEL bool "Intel protocol support" depends on BT_HCIUART + depends on GPIOLIB select BT_HCIUART_H4 select BT_INTEL help @@ -171,6 +184,7 @@ config BT_HCIUART_BCM depends on BT_HCIUART depends on BT_HCIUART_SERDEV depends on (!ACPI || SERIAL_DEV_CTRL_TTYPORT) + depends on GPIOLIB select BT_HCIUART_H4 select BT_BCM help diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index d513ef4743dc..82437a69f99c 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -302,9 +302,7 @@ static void bluecard_write_wakeup(struct bluecard_info *info) } /* Wait until the command reaches the baseband */ - prepare_to_wait(&wq, &wait, TASK_INTERRUPTIBLE); - schedule_timeout(HZ/10); - finish_wait(&wq, &wait); + mdelay(100); /* Set baud on baseband */ info->ctrl_reg &= ~0x03; @@ -316,9 +314,7 @@ static void bluecard_write_wakeup(struct bluecard_info *info) outb(info->ctrl_reg, iobase + REG_CONTROL); /* Wait before the next HCI packet can be send */ - prepare_to_wait(&wq, &wait, TASK_INTERRUPTIBLE); - schedule_timeout(HZ); - finish_wait(&wq, &wait); + mdelay(1000); } if (len == skb->len) { diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index 7971bfbd4321..801ea4ca65e4 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c @@ -259,7 +259,7 @@ static int bpa10x_flush(struct hci_dev *hdev) static int bpa10x_setup(struct hci_dev *hdev) { - const u8 req[] = { 0x07 }; + static const u8 req[] = { 0x07 }; struct sk_buff *skb; BT_DBG("%s", hdev->name); diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index afa4cb3b16e3..6659f113042c 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -323,6 +323,7 @@ static const struct { { 0x410e, "BCM43341B0" }, /* 002.001.014 */ { 0x4406, "BCM4324B3" }, /* 002.004.006 */ { 0x610c, "BCM4354" }, /* 003.001.012 */ + { 0x2122, "BCM4343A0" }, /* 001.001.034 */ { 0x2209, "BCM43430A1" }, /* 001.002.009 */ { 0x6119, "BCM4345C0" }, /* 003.001.025 */ { 0x230f, "BCM4356A2" }, /* 001.003.015 */ diff --git a/drivers/bluetooth/btbcm.h b/drivers/bluetooth/btbcm.h index d9e6b41658e5..cfe6ad4cc621 100644 --- a/drivers/bluetooth/btbcm.h +++ b/drivers/bluetooth/btbcm.h @@ -44,8 +44,8 @@ struct bcm_set_sleep_mode { __u8 tristate_control; __u8 usb_auto_sleep; __u8 usb_resume_timeout; - __u8 pulsed_host_wake; __u8 break_to_host; + __u8 pulsed_host_wake; } __packed; struct bcm_set_pcm_int_params { diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 4459555c9d88..5270d5513201 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -75,7 +76,7 @@ EXPORT_SYMBOL_GPL(btintel_check_bdaddr); int btintel_enter_mfg(struct hci_dev *hdev) { - const u8 param[] = { 0x01, 0x00 }; + static const u8 param[] = { 0x01, 0x00 }; struct sk_buff *skb; skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_CMD_TIMEOUT); @@ -569,6 +570,160 @@ struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read, } EXPORT_SYMBOL_GPL(btintel_regmap_init); +int btintel_send_intel_reset(struct hci_dev *hdev, u32 boot_param) +{ + struct intel_reset params = { 0x00, 0x01, 0x00, 0x01, 0x00000000 }; + struct sk_buff *skb; + + params.boot_param = cpu_to_le32(boot_param); + + skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(params), ¶ms, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_err(hdev, "Failed to send Intel Reset command"); + return PTR_ERR(skb); + } + + kfree_skb(skb); + + return 0; +} +EXPORT_SYMBOL_GPL(btintel_send_intel_reset); + +int btintel_read_boot_params(struct hci_dev *hdev, + struct intel_boot_params *params) +{ + struct sk_buff *skb; + + skb = __hci_cmd_sync(hdev, 0xfc0d, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_err(hdev, "Reading Intel boot parameters failed (%ld)", + PTR_ERR(skb)); + return PTR_ERR(skb); + } + + if (skb->len != sizeof(*params)) { + bt_dev_err(hdev, "Intel boot parameters size mismatch"); + kfree_skb(skb); + return -EILSEQ; + } + + memcpy(params, skb->data, sizeof(*params)); + + kfree_skb(skb); + + if (params->status) { + bt_dev_err(hdev, "Intel boot parameters command failed (%02x)", + params->status); + return -bt_to_errno(params->status); + } + + bt_dev_info(hdev, "Device revision is %u", + le16_to_cpu(params->dev_revid)); + + bt_dev_info(hdev, "Secure boot is %s", + params->secure_boot ? "enabled" : "disabled"); + + bt_dev_info(hdev, "OTP lock is %s", + params->otp_lock ? "enabled" : "disabled"); + + bt_dev_info(hdev, "API lock is %s", + params->api_lock ? "enabled" : "disabled"); + + bt_dev_info(hdev, "Debug lock is %s", + params->debug_lock ? "enabled" : "disabled"); + + bt_dev_info(hdev, "Minimum firmware build %u week %u %u", + params->min_fw_build_nn, params->min_fw_build_cw, + 2000 + params->min_fw_build_yy); + + return 0; +} +EXPORT_SYMBOL_GPL(btintel_read_boot_params); + +int btintel_download_firmware(struct hci_dev *hdev, const struct firmware *fw, + u32 *boot_param) +{ + int err; + const u8 *fw_ptr; + u32 frag_len; + + /* Start the firmware download transaction with the Init fragment + * represented by the 128 bytes of CSS header. + */ + err = btintel_secure_send(hdev, 0x00, 128, fw->data); + if (err < 0) { + bt_dev_err(hdev, "Failed to send firmware header (%d)", err); + goto done; + } + + /* Send the 256 bytes of public key information from the firmware + * as the PKey fragment. + */ + err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128); + if (err < 0) { + bt_dev_err(hdev, "Failed to send firmware pkey (%d)", err); + goto done; + } + + /* Send the 256 bytes of signature information from the firmware + * as the Sign fragment. + */ + err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388); + if (err < 0) { + bt_dev_err(hdev, "Failed to send firmware signature (%d)", err); + goto done; + } + + fw_ptr = fw->data + 644; + frag_len = 0; + + while (fw_ptr - fw->data < fw->size) { + struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len); + + /* Each SKU has a different reset parameter to use in the + * HCI_Intel_Reset command and it is embedded in the firmware + * data. So, instead of using static value per SKU, check + * the firmware data and save it for later use. + */ + if (le16_to_cpu(cmd->opcode) == 0xfc0e) { + /* The boot parameter is the first 32-bit value + * and rest of 3 octets are reserved. + */ + *boot_param = get_unaligned_le32(fw_ptr + sizeof(*cmd)); + + bt_dev_dbg(hdev, "boot_param=0x%x", *boot_param); + } + + frag_len += sizeof(*cmd) + cmd->plen; + + /* The parameter length of the secure send command requires + * a 4 byte alignment. It happens so that the firmware file + * contains proper Intel_NOP commands to align the fragments + * as needed. + * + * Send set of commands with 4 byte alignment from the + * firmware data buffer as a single Data fragement. + */ + if (!(frag_len % 4)) { + err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr); + if (err < 0) { + bt_dev_err(hdev, + "Failed to send firmware data (%d)", + err); + goto done; + } + + fw_ptr += frag_len; + frag_len = 0; + } + } + +done: + return err; +} +EXPORT_SYMBOL_GPL(btintel_download_firmware); + MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION); MODULE_VERSION(VERSION); diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index 1e8955aaafed..41c642cc523f 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -69,6 +69,14 @@ struct intel_secure_send_result { __u8 status; } __packed; +struct intel_reset { + __u8 reset_type; + __u8 patch_enable; + __u8 ddc_reload; + __u8 boot_option; + __le32 boot_param; +} __packed; + #if IS_ENABLED(CONFIG_BT_INTEL) int btintel_check_bdaddr(struct hci_dev *hdev); @@ -89,7 +97,11 @@ int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver); struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read, u16 opcode_write); - +int btintel_send_intel_reset(struct hci_dev *hdev, u32 boot_param); +int btintel_read_boot_params(struct hci_dev *hdev, + struct intel_boot_params *params); +int btintel_download_firmware(struct hci_dev *dev, const struct firmware *fw, + u32 *boot_param); #else static inline int btintel_check_bdaddr(struct hci_dev *hdev) @@ -165,4 +177,23 @@ static inline struct regmap *btintel_regmap_init(struct hci_dev *hdev, { return ERR_PTR(-EINVAL); } + +static inline int btintel_send_intel_reset(struct hci_dev *hdev, + u32 reset_param) +{ + return -EOPNOTSUPP; +} + +static inline int btintel_read_boot_params(struct hci_dev *hdev, + struct intel_boot_params *params) +{ + return -EOPNOTSUPP; +} + +static inline int btintel_download_firmware(struct hci_dev *dev, + const struct firmware *fw, + u32 *boot_param) +{ + return -EOPNOTSUPP; +} #endif diff --git a/drivers/bluetooth/btqcomsmd.c b/drivers/bluetooth/btqcomsmd.c index 663bed63b871..2c9a5fc9137d 100644 --- a/drivers/bluetooth/btqcomsmd.c +++ b/drivers/bluetooth/btqcomsmd.c @@ -88,7 +88,8 @@ static int btqcomsmd_send(struct hci_dev *hdev, struct sk_buff *skb) break; } - kfree_skb(skb); + if (!ret) + kfree_skb(skb); return ret; } diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c index c8e945d19ffe..20142bc77554 100644 --- a/drivers/bluetooth/btsdio.c +++ b/drivers/bluetooth/btsdio.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -292,6 +293,14 @@ static int btsdio_probe(struct sdio_func *func, tuple = tuple->next; } + /* BCM43341 devices soldered onto the PCB (non-removable) use an + * uart connection for bluetooth, ignore the BT SDIO interface. + */ + if (func->vendor == SDIO_VENDOR_ID_BROADCOM && + func->device == SDIO_DEVICE_ID_BROADCOM_43341 && + !mmc_card_is_removable(func->card->host)) + return -ENODEV; + data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index f7120c9eb9bd..2a55380ad730 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -40,6 +41,7 @@ static bool disable_scofix; static bool force_scofix; +static bool enable_autosuspend = IS_ENABLED(CONFIG_BT_HCIBTUSB_AUTOSUSPEND); static bool reset = true; @@ -263,6 +265,7 @@ static const struct usb_device_id blacklist_table[] = { /* QCA ROME chipset */ { USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME }, + { USB_DEVICE(0x0cf3, 0xe010), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe301), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME }, @@ -270,6 +273,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0489, 0xe09f), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0489, 0xe0a2), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x04ca, 0x3011), .driver_info = BTUSB_QCA_ROME }, + { USB_DEVICE(0x04ca, 0x3015), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x04ca, 0x3016), .driver_info = BTUSB_QCA_ROME }, /* Broadcom BCM2035 */ @@ -387,9 +391,8 @@ static const struct usb_device_id blacklist_table[] = { #define BTUSB_FIRMWARE_LOADED 7 #define BTUSB_FIRMWARE_FAILED 8 #define BTUSB_BOOTING 9 -#define BTUSB_RESET_RESUME 10 -#define BTUSB_DIAG_RUNNING 11 -#define BTUSB_OOB_WAKE_ENABLED 12 +#define BTUSB_DIAG_RUNNING 10 +#define BTUSB_OOB_WAKE_ENABLED 11 struct btusb_data { struct hci_dev *hdev; @@ -2006,15 +2009,11 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb) static int btusb_setup_intel_new(struct hci_dev *hdev) { - static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01, - 0x00, 0x08, 0x04, 0x00 }; struct btusb_data *data = hci_get_drvdata(hdev); - struct sk_buff *skb; struct intel_version ver; - struct intel_boot_params *params; + struct intel_boot_params params; const struct firmware *fw; - const u8 *fw_ptr; - u32 frag_len; + u32 boot_param; char fwname[64]; ktime_t calltime, delta, rettime; unsigned long long duration; @@ -2022,6 +2021,12 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) BT_DBG("%s", hdev->name); + /* Set the default boot parameter to 0x0 and it is updated to + * SKU specific boot parameter after reading Intel_Write_Boot_Params + * command while downloading the firmware. + */ + boot_param = 0x00000000; + calltime = ktime_get(); /* Read the Intel version information to determine if the device @@ -2092,55 +2097,24 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) /* Read the secure boot parameters to identify the operating * details of the bootloader. */ - skb = __hci_cmd_sync(hdev, 0xfc0d, 0, NULL, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - BT_ERR("%s: Reading Intel boot parameters failed (%ld)", - hdev->name, PTR_ERR(skb)); - return PTR_ERR(skb); - } - - if (skb->len != sizeof(*params)) { - BT_ERR("%s: Intel boot parameters size mismatch", hdev->name); - kfree_skb(skb); - return -EILSEQ; - } - - params = (struct intel_boot_params *)skb->data; - - bt_dev_info(hdev, "Device revision is %u", - le16_to_cpu(params->dev_revid)); - - bt_dev_info(hdev, "Secure boot is %s", - params->secure_boot ? "enabled" : "disabled"); - - bt_dev_info(hdev, "OTP lock is %s", - params->otp_lock ? "enabled" : "disabled"); - - bt_dev_info(hdev, "API lock is %s", - params->api_lock ? "enabled" : "disabled"); - - bt_dev_info(hdev, "Debug lock is %s", - params->debug_lock ? "enabled" : "disabled"); - - bt_dev_info(hdev, "Minimum firmware build %u week %u %u", - params->min_fw_build_nn, params->min_fw_build_cw, - 2000 + params->min_fw_build_yy); + err = btintel_read_boot_params(hdev, ¶ms); + if (err) + return err; /* It is required that every single firmware fragment is acknowledged * with a command complete event. If the boot parameters indicate * that this bootloader does not send them, then abort the setup. */ - if (params->limited_cce != 0x00) { + if (params.limited_cce != 0x00) { BT_ERR("%s: Unsupported Intel firmware loading method (%u)", - hdev->name, params->limited_cce); - kfree_skb(skb); + hdev->name, params.limited_cce); return -EINVAL; } /* If the OTP has no valid Bluetooth device address, then there will * also be no valid address for the operational firmware. */ - if (!bacmp(¶ms->otp_bdaddr, BDADDR_ANY)) { + if (!bacmp(¶ms.otp_bdaddr, BDADDR_ANY)) { bt_dev_info(hdev, "No device address configured"); set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); } @@ -2171,7 +2145,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) case 0x0c: /* WsP */ snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.sfi", le16_to_cpu(ver.hw_variant), - le16_to_cpu(params->dev_revid)); + le16_to_cpu(params.dev_revid)); break; case 0x11: /* JfP */ case 0x12: /* ThP */ @@ -2189,7 +2163,6 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) if (err < 0) { BT_ERR("%s: Failed to load Intel firmware file (%d)", hdev->name, err); - kfree_skb(skb); return err; } @@ -2203,7 +2176,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) case 0x0c: /* WsP */ snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.ddc", le16_to_cpu(ver.hw_variant), - le16_to_cpu(params->dev_revid)); + le16_to_cpu(params.dev_revid)); break; case 0x11: /* JfP */ case 0x12: /* ThP */ @@ -2217,8 +2190,6 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) return -EINVAL; } - kfree_skb(skb); - if (fw->size < 644) { BT_ERR("%s: Invalid size of firmware file (%zu)", hdev->name, fw->size); @@ -2228,64 +2199,10 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) set_bit(BTUSB_DOWNLOADING, &data->flags); - /* Start the firmware download transaction with the Init fragment - * represented by the 128 bytes of CSS header. - */ - err = btintel_secure_send(hdev, 0x00, 128, fw->data); - if (err < 0) { - BT_ERR("%s: Failed to send firmware header (%d)", - hdev->name, err); + /* Start firmware downloading and get boot parameter */ + err = btintel_download_firmware(hdev, fw, &boot_param); + if (err < 0) goto done; - } - - /* Send the 256 bytes of public key information from the firmware - * as the PKey fragment. - */ - err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128); - if (err < 0) { - BT_ERR("%s: Failed to send firmware public key (%d)", - hdev->name, err); - goto done; - } - - /* Send the 256 bytes of signature information from the firmware - * as the Sign fragment. - */ - err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388); - if (err < 0) { - BT_ERR("%s: Failed to send firmware signature (%d)", - hdev->name, err); - goto done; - } - - fw_ptr = fw->data + 644; - frag_len = 0; - - while (fw_ptr - fw->data < fw->size) { - struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len); - - frag_len += sizeof(*cmd) + cmd->plen; - - /* The parameter length of the secure send command requires - * a 4 byte alignment. It happens so that the firmware file - * contains proper Intel_NOP commands to align the fragments - * as needed. - * - * Send set of commands with 4 byte alignment from the - * firmware data buffer as a single Data fragement. - */ - if (!(frag_len % 4)) { - err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr); - if (err < 0) { - BT_ERR("%s: Failed to send firmware data (%d)", - hdev->name, err); - goto done; - } - - fw_ptr += frag_len; - frag_len = 0; - } - } set_bit(BTUSB_FIRMWARE_LOADED, &data->flags); @@ -2338,12 +2255,9 @@ done: set_bit(BTUSB_BOOTING, &data->flags); - skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(reset_param), reset_param, - HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - kfree_skb(skb); + err = btintel_send_intel_reset(hdev, boot_param); + if (err) + return err; /* The bootloader will not indicate when the device is ready. This * is done by the operational firmware sending bootup notification. @@ -3120,9 +3034,9 @@ static int btusb_probe(struct usb_interface *intf, /* QCA Rome devices lose their updated firmware over suspend, * but the USB hub doesn't notice any status change. - * Explicitly request a device reset on resume. + * explicitly request a device reset on resume. */ - set_bit(BTUSB_RESET_RESUME, &data->flags); + interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME; } #ifdef CONFIG_BT_HCIBTUSB_RTL @@ -3133,7 +3047,7 @@ static int btusb_probe(struct usb_interface *intf, * but the USB hub doesn't notice any status change. * Explicitly request a device reset on resume. */ - set_bit(BTUSB_RESET_RESUME, &data->flags); + interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME; } #endif @@ -3213,6 +3127,9 @@ static int btusb_probe(struct usb_interface *intf, } #endif + if (enable_autosuspend) + usb_enable_autosuspend(data->udev); + err = hci_register_dev(hdev); if (err < 0) goto out_free_dev; @@ -3299,14 +3216,6 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message) enable_irq(data->oob_wake_irq); } - /* Optionally request a device reset on resume, but only when - * wakeups are disabled. If wakeups are enabled we assume the - * device will stay powered up throughout suspend. - */ - if (test_bit(BTUSB_RESET_RESUME, &data->flags) && - !device_may_wakeup(&data->udev->dev)) - data->udev->reset_resume = 1; - return 0; } @@ -3425,6 +3334,9 @@ MODULE_PARM_DESC(disable_scofix, "Disable fixup of wrong SCO buffer size"); module_param(force_scofix, bool, 0644); MODULE_PARM_DESC(force_scofix, "Force fixup of wrong SCO buffers size"); +module_param(enable_autosuspend, bool, 0644); +MODULE_PARM_DESC(enable_autosuspend, "Enable USB autosuspend by default"); + module_param(reset, bool, 0644); MODULE_PARM_DESC(reset, "Send HCI reset command on initialization"); diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index 707c2d1b84c7..0438a64b8185 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -52,7 +53,37 @@ #define BCM_AUTOSUSPEND_DELAY 5000 /* default autosleep delay */ -/* device driver resources */ +/** + * struct bcm_device - device driver resources + * @serdev_hu: HCI UART controller struct + * @list: bcm_device_list node + * @dev: physical UART slave + * @name: device name logged by bt_dev_*() functions + * @device_wakeup: BT_WAKE pin, + * assert = Bluetooth device must wake up or remain awake, + * deassert = Bluetooth device may sleep when sleep criteria are met + * @shutdown: BT_REG_ON pin, + * power up or power down Bluetooth device internal regulators + * @set_device_wakeup: callback to toggle BT_WAKE pin + * either by accessing @device_wakeup or by calling @btlp + * @set_shutdown: callback to toggle BT_REG_ON pin + * either by accessing @shutdown or by calling @btpu/@btpd + * @btlp: Apple ACPI method to toggle BT_WAKE pin ("Bluetooth Low Power") + * @btpu: Apple ACPI method to drive BT_REG_ON pin high ("Bluetooth Power Up") + * @btpd: Apple ACPI method to drive BT_REG_ON pin low ("Bluetooth Power Down") + * @clk: clock used by Bluetooth device + * @clk_enabled: whether @clk is prepared and enabled + * @init_speed: default baudrate of Bluetooth device; + * the host UART is initially set to this baudrate so that + * it can configure the Bluetooth device for @oper_speed + * @oper_speed: preferred baudrate of Bluetooth device; + * set to 0 if @init_speed is already the preferred baudrate + * @irq: interrupt triggered by HOST_WAKE_BT pin + * @irq_active_low: whether @irq is active low + * @hu: pointer to HCI UART controller struct, + * used to disable flow control during runtime suspend and system sleep + * @is_suspended: whether flow control is currently disabled + */ struct bcm_device { /* Must be the first member, hci_serdev.c expects this. */ struct hci_uart serdev_hu; @@ -63,6 +94,11 @@ struct bcm_device { const char *name; struct gpio_desc *device_wakeup; struct gpio_desc *shutdown; + int (*set_device_wakeup)(struct bcm_device *, bool); + int (*set_shutdown)(struct bcm_device *, bool); +#ifdef CONFIG_ACPI + acpi_handle btlp, btpu, btpd; +#endif struct clk *clk; bool clk_enabled; @@ -74,7 +110,7 @@ struct bcm_device { #ifdef CONFIG_PM struct hci_uart *hu; - bool is_suspended; /* suspend/resume flag */ + bool is_suspended; #endif }; @@ -170,11 +206,21 @@ static bool bcm_device_exists(struct bcm_device *device) static int bcm_gpio_set_power(struct bcm_device *dev, bool powered) { - if (powered && !IS_ERR(dev->clk) && !dev->clk_enabled) - clk_prepare_enable(dev->clk); + int err; - gpiod_set_value(dev->shutdown, powered); - gpiod_set_value(dev->device_wakeup, powered); + if (powered && !IS_ERR(dev->clk) && !dev->clk_enabled) { + err = clk_prepare_enable(dev->clk); + if (err) + return err; + } + + err = dev->set_shutdown(dev, powered); + if (err) + goto err_clk_disable; + + err = dev->set_device_wakeup(dev, powered); + if (err) + goto err_revert_shutdown; if (!powered && !IS_ERR(dev->clk) && dev->clk_enabled) clk_disable_unprepare(dev->clk); @@ -182,6 +228,13 @@ static int bcm_gpio_set_power(struct bcm_device *dev, bool powered) dev->clk_enabled = powered; return 0; + +err_revert_shutdown: + dev->set_shutdown(dev, !powered); +err_clk_disable: + if (powered && !IS_ERR(dev->clk) && !dev->clk_enabled) + clk_disable_unprepare(dev->clk); + return err; } #ifdef CONFIG_PM @@ -191,9 +244,7 @@ static irqreturn_t bcm_host_wake(int irq, void *data) bt_dev_dbg(bdev, "Host wake IRQ"); - pm_runtime_get(bdev->dev); - pm_runtime_mark_last_busy(bdev->dev); - pm_runtime_put_autosuspend(bdev->dev); + pm_request_resume(bdev->dev); return IRQ_HANDLED; } @@ -218,8 +269,10 @@ static int bcm_request_irq(struct bcm_data *bcm) bdev->irq_active_low ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING, "host_wake", bdev); - if (err) + if (err) { + bdev->irq = err; goto unlock; + } device_init_wakeup(bdev->dev, true); @@ -247,8 +300,8 @@ static const struct bcm_set_sleep_mode default_sleep_params = { /* Irrelevant USB flags */ .usb_auto_sleep = 0, .usb_resume_timeout = 0, + .break_to_host = 0, .pulsed_host_wake = 0, - .break_to_host = 0 }; static int bcm_setup_sleep(struct hci_uart *hu) @@ -304,6 +357,7 @@ static int bcm_open(struct hci_uart *hu) { struct bcm_data *bcm; struct list_head *p; + int err; bt_dev_dbg(hu->hdev, "hu %p", hu); @@ -318,7 +372,10 @@ static int bcm_open(struct hci_uart *hu) mutex_lock(&bcm_device_lock); if (hu->serdev) { - serdev_device_open(hu->serdev); + err = serdev_device_open(hu->serdev); + if (err) + goto err_free; + bcm->dev = serdev_device_get_drvdata(hu->serdev); goto out; } @@ -346,17 +403,33 @@ out: if (bcm->dev) { hu->init_speed = bcm->dev->init_speed; hu->oper_speed = bcm->dev->oper_speed; - bcm_gpio_set_power(bcm->dev, true); + err = bcm_gpio_set_power(bcm->dev, true); + if (err) + goto err_unset_hu; } mutex_unlock(&bcm_device_lock); return 0; + +err_unset_hu: + if (hu->serdev) + serdev_device_close(hu->serdev); +#ifdef CONFIG_PM + else + bcm->dev->hu = NULL; +#endif +err_free: + mutex_unlock(&bcm_device_lock); + hu->priv = NULL; + kfree(bcm); + return err; } static int bcm_close(struct hci_uart *hu) { struct bcm_data *bcm = hu->priv; struct bcm_device *bdev = NULL; + int err; bt_dev_dbg(hu->hdev, "hu %p", hu); @@ -374,16 +447,17 @@ static int bcm_close(struct hci_uart *hu) } if (bdev) { - bcm_gpio_set_power(bdev, false); -#ifdef CONFIG_PM - pm_runtime_disable(bdev->dev); - pm_runtime_set_suspended(bdev->dev); - - if (device_can_wakeup(bdev->dev)) { + if (IS_ENABLED(CONFIG_PM) && bdev->irq > 0) { devm_free_irq(bdev->dev, bdev->irq, bdev); device_init_wakeup(bdev->dev, false); + pm_runtime_disable(bdev->dev); } -#endif + + err = bcm_gpio_set_power(bdev, false); + if (err) + bt_dev_err(hu->hdev, "Failed to power down"); + else + pm_runtime_set_suspended(bdev->dev); } mutex_unlock(&bcm_device_lock); @@ -512,11 +586,8 @@ static int bcm_recv(struct hci_uart *hu, const void *data, int count) } else if (!bcm->rx_skb) { /* Delay auto-suspend when receiving completed packet */ mutex_lock(&bcm_device_lock); - if (bcm->dev && bcm_device_exists(bcm->dev)) { - pm_runtime_get(bcm->dev->dev); - pm_runtime_mark_last_busy(bcm->dev->dev); - pm_runtime_put_autosuspend(bcm->dev->dev); - } + if (bcm->dev && bcm_device_exists(bcm->dev)) + pm_request_resume(bcm->dev->dev); mutex_unlock(&bcm_device_lock); } @@ -566,6 +637,7 @@ static struct sk_buff *bcm_dequeue(struct hci_uart *hu) static int bcm_suspend_device(struct device *dev) { struct bcm_device *bdev = dev_get_drvdata(dev); + int err; bt_dev_dbg(bdev, ""); @@ -577,27 +649,37 @@ static int bcm_suspend_device(struct device *dev) } /* Suspend the device */ - if (bdev->device_wakeup) { - gpiod_set_value(bdev->device_wakeup, false); - bt_dev_dbg(bdev, "suspend, delaying 15 ms"); - mdelay(15); + err = bdev->set_device_wakeup(bdev, false); + if (err) { + if (bdev->is_suspended && bdev->hu) { + bdev->is_suspended = false; + hci_uart_set_flow_control(bdev->hu, false); + } + return -EBUSY; } + bt_dev_dbg(bdev, "suspend, delaying 15 ms"); + msleep(15); + return 0; } static int bcm_resume_device(struct device *dev) { struct bcm_device *bdev = dev_get_drvdata(dev); + int err; bt_dev_dbg(bdev, ""); - if (bdev->device_wakeup) { - gpiod_set_value(bdev->device_wakeup, true); - bt_dev_dbg(bdev, "resume, delaying 15 ms"); - mdelay(15); + err = bdev->set_device_wakeup(bdev, true); + if (err) { + dev_err(dev, "Failed to power up\n"); + return err; } + bt_dev_dbg(bdev, "resume, delaying 15 ms"); + msleep(15); + /* When this executes, the device has woken up already */ if (bdev->is_suspended && bdev->hu) { bdev->is_suspended = false; @@ -632,7 +714,7 @@ static int bcm_suspend(struct device *dev) if (pm_runtime_active(dev)) bcm_suspend_device(dev); - if (device_may_wakeup(dev)) { + if (device_may_wakeup(dev) && bdev->irq > 0) { error = enable_irq_wake(bdev->irq); if (!error) bt_dev_dbg(bdev, "BCM irq: enabled"); @@ -648,6 +730,7 @@ unlock: static int bcm_resume(struct device *dev) { struct bcm_device *bdev = dev_get_drvdata(dev); + int err = 0; bt_dev_dbg(bdev, "resume: is_suspended %d", bdev->is_suspended); @@ -662,19 +745,21 @@ static int bcm_resume(struct device *dev) if (!bdev->hu) goto unlock; - if (device_may_wakeup(dev)) { + if (device_may_wakeup(dev) && bdev->irq > 0) { disable_irq_wake(bdev->irq); bt_dev_dbg(bdev, "BCM irq: disabled"); } - bcm_resume_device(dev); + err = bcm_resume_device(dev); unlock: mutex_unlock(&bcm_device_lock); - pm_runtime_disable(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); + if (!err) { + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + } return 0; } @@ -771,25 +856,84 @@ static int bcm_resource(struct acpi_resource *ares, void *data) return 0; } + +static int bcm_apple_set_device_wakeup(struct bcm_device *dev, bool awake) +{ + if (ACPI_FAILURE(acpi_execute_simple_method(dev->btlp, NULL, !awake))) + return -EIO; + + return 0; +} + +static int bcm_apple_set_shutdown(struct bcm_device *dev, bool powered) +{ + if (ACPI_FAILURE(acpi_evaluate_object(powered ? dev->btpu : dev->btpd, + NULL, NULL, NULL))) + return -EIO; + + return 0; +} + +static int bcm_apple_get_resources(struct bcm_device *dev) +{ + struct acpi_device *adev = ACPI_COMPANION(dev->dev); + const union acpi_object *obj; + + if (!adev || + ACPI_FAILURE(acpi_get_handle(adev->handle, "BTLP", &dev->btlp)) || + ACPI_FAILURE(acpi_get_handle(adev->handle, "BTPU", &dev->btpu)) || + ACPI_FAILURE(acpi_get_handle(adev->handle, "BTPD", &dev->btpd))) + return -ENODEV; + + if (!acpi_dev_get_property(adev, "baud", ACPI_TYPE_BUFFER, &obj) && + obj->buffer.length == 8) + dev->init_speed = *(u64 *)obj->buffer.pointer; + + dev->set_device_wakeup = bcm_apple_set_device_wakeup; + dev->set_shutdown = bcm_apple_set_shutdown; + + return 0; +} +#else +static inline int bcm_apple_get_resources(struct bcm_device *dev) +{ + return -EOPNOTSUPP; +} #endif /* CONFIG_ACPI */ +static int bcm_gpio_set_device_wakeup(struct bcm_device *dev, bool awake) +{ + gpiod_set_value(dev->device_wakeup, awake); + return 0; +} + +static int bcm_gpio_set_shutdown(struct bcm_device *dev, bool powered) +{ + gpiod_set_value(dev->shutdown, powered); + return 0; +} + static int bcm_get_resources(struct bcm_device *dev) { dev->name = dev_name(dev->dev); + if (x86_apple_machine && !bcm_apple_get_resources(dev)) + return 0; + dev->clk = devm_clk_get(dev->dev, NULL); - dev->device_wakeup = devm_gpiod_get_optional(dev->dev, - "device-wakeup", - GPIOD_OUT_LOW); + dev->device_wakeup = devm_gpiod_get(dev->dev, "device-wakeup", + GPIOD_OUT_LOW); if (IS_ERR(dev->device_wakeup)) return PTR_ERR(dev->device_wakeup); - dev->shutdown = devm_gpiod_get_optional(dev->dev, "shutdown", - GPIOD_OUT_LOW); + dev->shutdown = devm_gpiod_get(dev->dev, "shutdown", GPIOD_OUT_LOW); if (IS_ERR(dev->shutdown)) return PTR_ERR(dev->shutdown); + dev->set_device_wakeup = bcm_gpio_set_device_wakeup; + dev->set_shutdown = bcm_gpio_set_shutdown; + /* IRQ can be declared in ACPI table as Interrupt or GpioInt */ if (dev->irq <= 0) { struct gpio_desc *gpio; @@ -802,7 +946,7 @@ static int bcm_get_resources(struct bcm_device *dev) dev->irq = gpiod_to_irq(gpio); } - dev_info(dev->dev, "BCM irq: %d\n", dev->irq); + dev_dbg(dev->dev, "BCM irq: %d\n", dev->irq); return 0; } @@ -892,7 +1036,9 @@ static int bcm_probe(struct platform_device *pdev) list_add_tail(&dev->list, &bcm_device_list); mutex_unlock(&bcm_device_lock); - bcm_gpio_set_power(dev, false); + ret = bcm_gpio_set_power(dev, false); + if (ret) + dev_err(&pdev->dev, "Failed to power down\n"); return 0; } @@ -939,6 +1085,7 @@ static const struct acpi_device_id bcm_acpi_match[] = { { "BCM2E65", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, { "BCM2E67", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, { "BCM2E71", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, + { "BCM2E72", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, { "BCM2E7B", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, { "BCM2E7C", (kernel_ulong_t)&acpi_bcm_int_last_gpios }, { "BCM2E7E", (kernel_ulong_t)&acpi_bcm_int_first_gpios }, @@ -993,7 +1140,9 @@ static int bcm_serdev_probe(struct serdev_device *serdev) if (err) return err; - bcm_gpio_set_power(bcmdev, false); + err = bcm_gpio_set_power(bcmdev, false); + if (err) + dev_err(&serdev->dev, "Failed to power down\n"); return hci_uart_register_device(&bcmdev->serdev_hu, &bcm_proto); } diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index aad07e40ea4f..7c166e3b308b 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -540,18 +540,15 @@ static int intel_set_baudrate(struct hci_uart *hu, unsigned int speed) static int intel_setup(struct hci_uart *hu) { - static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01, - 0x00, 0x08, 0x04, 0x00 }; struct intel_data *intel = hu->priv; struct hci_dev *hdev = hu->hdev; struct sk_buff *skb; struct intel_version ver; - struct intel_boot_params *params; + struct intel_boot_params params; struct list_head *p; const struct firmware *fw; - const u8 *fw_ptr; char fwname[64]; - u32 frag_len; + u32 boot_param; ktime_t calltime, delta, rettime; unsigned long long duration; unsigned int init_speed, oper_speed; @@ -563,6 +560,12 @@ static int intel_setup(struct hci_uart *hu) hu->hdev->set_diag = btintel_set_diag; hu->hdev->set_bdaddr = btintel_set_bdaddr; + /* Set the default boot parameter to 0x0 and it is updated to + * SKU specific boot parameter after reading Intel_Write_Boot_Params + * command while downloading the firmware. + */ + boot_param = 0x00000000; + calltime = ktime_get(); if (hu->init_speed) @@ -656,85 +659,95 @@ static int intel_setup(struct hci_uart *hu) /* Read the secure boot parameters to identify the operating * details of the bootloader. */ - skb = __hci_cmd_sync(hdev, 0xfc0d, 0, NULL, HCI_CMD_TIMEOUT); - if (IS_ERR(skb)) { - bt_dev_err(hdev, "Reading Intel boot parameters failed (%ld)", - PTR_ERR(skb)); - return PTR_ERR(skb); - } - - if (skb->len != sizeof(*params)) { - bt_dev_err(hdev, "Intel boot parameters size mismatch"); - kfree_skb(skb); - return -EILSEQ; - } - - params = (struct intel_boot_params *)skb->data; - if (params->status) { - bt_dev_err(hdev, "Intel boot parameters command failure (%02x)", - params->status); - err = -bt_to_errno(params->status); - kfree_skb(skb); + err = btintel_read_boot_params(hdev, ¶ms); + if (err) return err; - } - - bt_dev_info(hdev, "Device revision is %u", - le16_to_cpu(params->dev_revid)); - - bt_dev_info(hdev, "Secure boot is %s", - params->secure_boot ? "enabled" : "disabled"); - - bt_dev_info(hdev, "Minimum firmware build %u week %u %u", - params->min_fw_build_nn, params->min_fw_build_cw, - 2000 + params->min_fw_build_yy); /* It is required that every single firmware fragment is acknowledged * with a command complete event. If the boot parameters indicate * that this bootloader does not send them, then abort the setup. */ - if (params->limited_cce != 0x00) { + if (params.limited_cce != 0x00) { bt_dev_err(hdev, "Unsupported Intel firmware loading method (%u)", - params->limited_cce); - kfree_skb(skb); + params.limited_cce); return -EINVAL; } /* If the OTP has no valid Bluetooth device address, then there will * also be no valid address for the operational firmware. */ - if (!bacmp(¶ms->otp_bdaddr, BDADDR_ANY)) { + if (!bacmp(¶ms.otp_bdaddr, BDADDR_ANY)) { bt_dev_info(hdev, "No device address configured"); set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); } /* With this Intel bootloader only the hardware variant and device - * revision information are used to select the right firmware. + * revision information are used to select the right firmware for SfP + * and WsP. * * The firmware filename is ibt--.sfi. * * Currently the supported hardware variants are: * 11 (0x0b) for iBT 3.0 (LnP/SfP) + * 12 (0x0c) for iBT 3.5 (WsP) + * + * For ThP/JfP and for future SKU's, the FW name varies based on HW + * variant, HW revision and FW revision, as these are dependent on CNVi + * and RF Combination. + * + * 18 (0x12) for iBT3.5 (ThP/JfP) + * + * The firmware file name for these will be + * ibt---.sfi. + * */ - snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.sfi", - le16_to_cpu(ver.hw_variant), - le16_to_cpu(params->dev_revid)); + switch (ver.hw_variant) { + case 0x0b: /* SfP */ + case 0x0c: /* WsP */ + snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.sfi", + le16_to_cpu(ver.hw_variant), + le16_to_cpu(params.dev_revid)); + break; + case 0x12: /* ThP */ + snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.sfi", + le16_to_cpu(ver.hw_variant), + le16_to_cpu(ver.hw_revision), + le16_to_cpu(ver.fw_revision)); + break; + default: + bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)", + ver.hw_variant); + return -EINVAL; + } err = request_firmware(&fw, fwname, &hdev->dev); if (err < 0) { bt_dev_err(hdev, "Failed to load Intel firmware file (%d)", err); - kfree_skb(skb); return err; } bt_dev_info(hdev, "Found device firmware: %s", fwname); /* Save the DDC file name for later */ - snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.ddc", - le16_to_cpu(ver.hw_variant), - le16_to_cpu(params->dev_revid)); - - kfree_skb(skb); + switch (ver.hw_variant) { + case 0x0b: /* SfP */ + case 0x0c: /* WsP */ + snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.ddc", + le16_to_cpu(ver.hw_variant), + le16_to_cpu(params.dev_revid)); + break; + case 0x12: /* ThP */ + snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.ddc", + le16_to_cpu(ver.hw_variant), + le16_to_cpu(ver.hw_revision), + le16_to_cpu(ver.fw_revision)); + break; + default: + bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)", + ver.hw_variant); + return -EINVAL; + } if (fw->size < 644) { bt_dev_err(hdev, "Invalid size of firmware file (%zu)", @@ -745,70 +758,10 @@ static int intel_setup(struct hci_uart *hu) set_bit(STATE_DOWNLOADING, &intel->flags); - /* Start the firmware download transaction with the Init fragment - * represented by the 128 bytes of CSS header. - */ - err = btintel_secure_send(hdev, 0x00, 128, fw->data); - if (err < 0) { - bt_dev_err(hdev, "Failed to send firmware header (%d)", err); + /* Start firmware downloading and get boot parameter */ + err = btintel_download_firmware(hdev, fw, &boot_param); + if (err < 0) goto done; - } - - /* Send the 256 bytes of public key information from the firmware - * as the PKey fragment. - */ - err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128); - if (err < 0) { - bt_dev_err(hdev, "Failed to send firmware public key (%d)", - err); - goto done; - } - - /* Send the 256 bytes of signature information from the firmware - * as the Sign fragment. - */ - err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388); - if (err < 0) { - bt_dev_err(hdev, "Failed to send firmware signature (%d)", - err); - goto done; - } - - fw_ptr = fw->data + 644; - frag_len = 0; - - while (fw_ptr - fw->data < fw->size) { - struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len); - - frag_len += sizeof(*cmd) + cmd->plen; - - bt_dev_dbg(hdev, "Patching %td/%zu", (fw_ptr - fw->data), - fw->size); - - /* The parameter length of the secure send command requires - * a 4 byte alignment. It happens so that the firmware file - * contains proper Intel_NOP commands to align the fragments - * as needed. - * - * Send set of commands with 4 byte alignment from the - * firmware data buffer as a single Data fragement. - */ - if (frag_len % 4) - continue; - - /* Send each command from the firmware data buffer as - * a single Data fragment. - */ - err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr); - if (err < 0) { - bt_dev_err(hdev, "Failed to send firmware data (%d)", - err); - goto done; - } - - fw_ptr += frag_len; - frag_len = 0; - } set_bit(STATE_FIRMWARE_LOADED, &intel->flags); @@ -869,12 +822,9 @@ done: set_bit(STATE_BOOTING, &intel->flags); - skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(reset_param), reset_param, - HCI_CMD_TIMEOUT); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - kfree_skb(skb); + err = btintel_send_intel_reset(hdev, boot_param); + if (err) + return err; /* The bootloader will not indicate when the device is ready. This * is done by the operational firmware sending bootup notification. diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index c823914b3a80..b6a71705b7d6 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -794,7 +794,7 @@ static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, return 0; } -static unsigned int hci_uart_tty_poll(struct tty_struct *tty, +static __poll_t hci_uart_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) { return 0; diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index e2c078d61730..1b4417a623a4 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -53,9 +53,14 @@ #include #include #include +#include #include "hci_uart.h" +/* Vendor-specific HCI commands */ +#define HCI_VS_WRITE_BD_ADDR 0xfc06 +#define HCI_VS_UPDATE_UART_HCI_BAUDRATE 0xff36 + /* HCILL commands */ #define HCILL_GO_TO_SLEEP_IND 0x30 #define HCILL_GO_TO_SLEEP_ACK 0x31 @@ -86,6 +91,7 @@ struct ll_device { struct serdev_device *serdev; struct gpio_desc *enable_gpio; struct clk *ext_clk; + bdaddr_t bdaddr; }; struct ll_struct { @@ -620,7 +626,7 @@ static int download_firmware(struct ll_device *lldev) case ACTION_SEND_COMMAND: /* action send */ bt_dev_dbg(lldev->hu.hdev, "S"); cmd = (struct hci_command *)action_ptr; - if (cmd->opcode == 0xff36) { + if (cmd->opcode == HCI_VS_UPDATE_UART_HCI_BAUDRATE) { /* ignore remote change * baud rate HCI VS command */ @@ -628,11 +634,11 @@ static int download_firmware(struct ll_device *lldev) break; } if (cmd->prefix != 1) - bt_dev_dbg(lldev->hu.hdev, "command type %d\n", cmd->prefix); + bt_dev_dbg(lldev->hu.hdev, "command type %d", cmd->prefix); skb = __hci_cmd_sync(lldev->hu.hdev, cmd->opcode, cmd->plen, &cmd->speed, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { - bt_dev_err(lldev->hu.hdev, "send command failed\n"); + bt_dev_err(lldev->hu.hdev, "send command failed"); err = PTR_ERR(skb); goto out_rel_fw; } @@ -659,6 +665,24 @@ out_rel_fw: return err; } +static int ll_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + bdaddr_t bdaddr_swapped; + struct sk_buff *skb; + + /* HCI_VS_WRITE_BD_ADDR (at least on a CC2560A chip) expects the BD + * address to be MSB first, but bdaddr_t has the convention of being + * LSB first. + */ + baswap(&bdaddr_swapped, bdaddr); + skb = __hci_cmd_sync(hdev, HCI_VS_WRITE_BD_ADDR, sizeof(bdaddr_t), + &bdaddr_swapped, HCI_INIT_TIMEOUT); + if (!IS_ERR(skb)) + kfree_skb(skb); + + return PTR_ERR_OR_ZERO(skb); +} + static int ll_setup(struct hci_uart *hu) { int err, retry = 3; @@ -671,14 +695,20 @@ static int ll_setup(struct hci_uart *hu) lldev = serdev_device_get_drvdata(serdev); + hu->hdev->set_bdaddr = ll_set_bdaddr; + serdev_device_set_flow_control(serdev, true); do { - /* Configure BT_EN to HIGH state */ + /* Reset the Bluetooth device */ gpiod_set_value_cansleep(lldev->enable_gpio, 0); msleep(5); gpiod_set_value_cansleep(lldev->enable_gpio, 1); - msleep(100); + err = serdev_device_wait_for_cts(serdev, true, 200); + if (err) { + bt_dev_err(hu->hdev, "Failed to get CTS"); + return err; + } err = download_firmware(lldev); if (!err) @@ -691,6 +721,18 @@ static int ll_setup(struct hci_uart *hu) if (err) return err; + /* Set BD address if one was specified at probe */ + if (!bacmp(&lldev->bdaddr, BDADDR_NONE)) { + /* This means that there was an error getting the BD address + * during probe, so mark the device as having a bad address. + */ + set_bit(HCI_QUIRK_INVALID_BDADDR, &hu->hdev->quirks); + } else if (bacmp(&lldev->bdaddr, BDADDR_ANY)) { + err = ll_set_bdaddr(hu->hdev, &lldev->bdaddr); + if (err) + set_bit(HCI_QUIRK_INVALID_BDADDR, &hu->hdev->quirks); + } + /* Operational speed if any */ if (hu->oper_speed) speed = hu->oper_speed; @@ -700,7 +742,12 @@ static int ll_setup(struct hci_uart *hu) speed = 0; if (speed) { - struct sk_buff *skb = __hci_cmd_sync(hu->hdev, 0xff36, sizeof(speed), &speed, HCI_INIT_TIMEOUT); + __le32 speed_le = cpu_to_le32(speed); + struct sk_buff *skb; + + skb = __hci_cmd_sync(hu->hdev, HCI_VS_UPDATE_UART_HCI_BAUDRATE, + sizeof(speed_le), &speed_le, + HCI_INIT_TIMEOUT); if (!IS_ERR(skb)) { kfree_skb(skb); serdev_device_set_baudrate(serdev, speed); @@ -716,6 +763,7 @@ static int hci_ti_probe(struct serdev_device *serdev) { struct hci_uart *hu; struct ll_device *lldev; + struct nvmem_cell *bdaddr_cell; u32 max_speed = 3000000; lldev = devm_kzalloc(&serdev->dev, sizeof(struct ll_device), GFP_KERNEL); @@ -737,6 +785,52 @@ static int hci_ti_probe(struct serdev_device *serdev) of_property_read_u32(serdev->dev.of_node, "max-speed", &max_speed); hci_uart_set_speeds(hu, 115200, max_speed); + /* optional BD address from nvram */ + bdaddr_cell = nvmem_cell_get(&serdev->dev, "bd-address"); + if (IS_ERR(bdaddr_cell)) { + int err = PTR_ERR(bdaddr_cell); + + if (err == -EPROBE_DEFER) + return err; + + /* ENOENT means there is no matching nvmem cell and ENOSYS + * means that nvmem is not enabled in the kernel configuration. + */ + if (err != -ENOENT && err != -ENOSYS) { + /* If there was some other error, give userspace a + * chance to fix the problem instead of failing to load + * the driver. Using BDADDR_NONE as a flag that is + * tested later in the setup function. + */ + dev_warn(&serdev->dev, + "Failed to get \"bd-address\" nvmem cell (%d)\n", + err); + bacpy(&lldev->bdaddr, BDADDR_NONE); + } + } else { + bdaddr_t *bdaddr; + size_t len; + + bdaddr = nvmem_cell_read(bdaddr_cell, &len); + nvmem_cell_put(bdaddr_cell); + if (IS_ERR(bdaddr)) { + dev_err(&serdev->dev, "Failed to read nvmem bd-address\n"); + return PTR_ERR(bdaddr); + } + if (len != sizeof(bdaddr_t)) { + dev_err(&serdev->dev, "Invalid nvmem bd-address length\n"); + kfree(bdaddr); + return -EINVAL; + } + + /* As per the device tree bindings, the value from nvmem is + * expected to be MSB first, but in the kernel it is expected + * that bdaddr_t is LSB first. + */ + baswap(&lldev->bdaddr, bdaddr); + kfree(bdaddr); + } + return hci_uart_register_device(hu, &llp); } @@ -748,6 +842,7 @@ static void hci_ti_remove(struct serdev_device *serdev) } static const struct of_device_id hci_ti_of_match[] = { + { .compatible = "ti,cc2560" }, { .compatible = "ti,wl1271-st" }, { .compatible = "ti,wl1273-st" }, { .compatible = "ti,wl1281-st" }, diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index bbd7db7384e6..05ec530b8a3a 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -932,6 +932,9 @@ static int qca_setup(struct hci_uart *hu) if (!ret) { set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); qca_debugfs_init(hdev); + } else if (ret == -ENOENT) { + /* No patch/nvm-config found, run with original fw/config */ + ret = 0; } /* Setup bdaddr */ diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index 71664b22ec9d..e0e6461b9200 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -303,6 +303,7 @@ int hci_uart_register_device(struct hci_uart *hu, hci_set_drvdata(hdev, hu); INIT_WORK(&hu->write_work, hci_uart_write_work); + percpu_init_rwsem(&hu->proto_lock); /* Only when vendor specific setup callback is provided, consider * the manufacturer information valid. This avoids filling in the diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index e6f6dbc04131..22f9145a426f 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -299,16 +299,16 @@ static ssize_t vhci_write(struct kiocb *iocb, struct iov_iter *from) return vhci_get_user(data, from); } -static unsigned int vhci_poll(struct file *file, poll_table *wait) +static __poll_t vhci_poll(struct file *file, poll_table *wait) { struct vhci_data *data = file->private_data; poll_wait(file, &data->read_wait, wait); if (!skb_queue_empty(&data->readq)) - return POLLIN | POLLRDNORM; + return EPOLLIN | EPOLLRDNORM; - return POLLOUT | POLLWRNORM; + return EPOLLOUT | EPOLLWRNORM; } static void vhci_open_timeout(struct work_struct *work) diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index dc7b3c7b7d42..57e011d36a79 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -120,7 +120,7 @@ config QCOM_EBI2 SRAM, ethernet adapters, FPGAs and LCD displays. config SIMPLE_PM_BUS - bool "Simple Power-Managed Bus Driver" + tristate "Simple Power-Managed Bus Driver" depends on OF && PM help Driver for transparent busses that don't need a real driver, but diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 5012e3ad1225..b040447575ad 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -375,3 +375,8 @@ static void __exit omap_l3_exit(void) platform_driver_unregister(&omap_l3_driver); } module_exit(omap_l3_exit); + +MODULE_AUTHOR("Santosh Shilimkar"); +MODULE_AUTHOR("Sricharan R"); +MODULE_DESCRIPTION("OMAP L3 Interconnect error handling driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/bus/omap_l3_smx.c b/drivers/bus/omap_l3_smx.c index 360a5c0a4ee0..b853a729537a 100644 --- a/drivers/bus/omap_l3_smx.c +++ b/drivers/bus/omap_l3_smx.c @@ -309,3 +309,9 @@ static void __exit omap3_l3_exit(void) platform_driver_unregister(&omap3_l3_driver); } module_exit(omap3_l3_exit); + +MODULE_AUTHOR("Felipe Balbi"); +MODULE_AUTHOR("Santosh Shilimkar"); +MODULE_AUTHOR("Sricharan R"); +MODULE_DESCRIPTION("OMAP3XXX L3 Interconnect Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index c3c76a1ea8a8..4d46003c46cf 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -18,6 +18,9 @@ #include #include #include +#include + +#include enum sysc_registers { SYSC_REVISION, @@ -36,6 +39,9 @@ enum sysc_clocks { static const char * const clock_names[] = { "fck", "ick", }; +#define SYSC_IDLEMODE_MASK 3 +#define SYSC_CLOCKACTIVITY_MASK 3 + /** * struct sysc - TI sysc interconnect target module registers and capabilities * @dev: struct device pointer @@ -45,6 +51,10 @@ static const char * const clock_names[] = { "fck", "ick", }; * @offsets: register offsets from module base * @clocks: clocks used by the interconnect target module * @legacy_mode: configured for legacy mode if set + * @cap: interconnect target module capabilities + * @cfg: interconnect target module configuration + * @name: name if available + * @revision: interconnect target module revision */ struct sysc { struct device *dev; @@ -54,12 +64,34 @@ struct sysc { int offsets[SYSC_MAX_REGS]; struct clk *clocks[SYSC_MAX_CLOCKS]; const char *legacy_mode; + const struct sysc_capabilities *cap; + struct sysc_config cfg; + const char *name; + u32 revision; }; +static u32 sysc_read(struct sysc *ddata, int offset) +{ + if (ddata->cfg.quirks & SYSC_QUIRK_16BIT) { + u32 val; + + val = readw_relaxed(ddata->module_va + offset); + val |= (readw_relaxed(ddata->module_va + offset + 4) << 16); + + return val; + } + + return readl_relaxed(ddata->module_va + offset); +} + static u32 sysc_read_revision(struct sysc *ddata) { - return readl_relaxed(ddata->module_va + - ddata->offsets[SYSC_REVISION]); + int offset = ddata->offsets[SYSC_REVISION]; + + if (offset < 0) + return 0; + + return sysc_read(ddata, offset); } static int sysc_get_one_clock(struct sysc *ddata, @@ -206,6 +238,21 @@ static int sysc_check_children(struct sysc *ddata) return 0; } +/* + * So far only I2C uses 16-bit read access with clockactivity with revision + * in two registers with stride of 4. We can detect this based on the rev + * register size to configure things far enough to be able to properly read + * the revision register. + */ +static void sysc_check_quirk_16bit(struct sysc *ddata, struct resource *res) +{ + if (resource_size(res) == 8) { + dev_dbg(ddata->dev, + "enabling 16-bit and clockactivity quirks\n"); + ddata->cfg.quirks |= SYSC_QUIRK_16BIT | SYSC_QUIRK_USE_CLOCKACT; + } +} + /** * sysc_parse_one - parses the interconnect target module registers * @ddata: device driver data @@ -236,6 +283,8 @@ static int sysc_parse_one(struct sysc *ddata, enum sysc_registers reg) } ddata->offsets[reg] = res->start - ddata->module_pa; + if (reg == SYSC_REVISION) + sysc_check_quirk_16bit(ddata, res); return 0; } @@ -369,22 +418,12 @@ static int sysc_map_and_check_registers(struct sysc *ddata) */ static int sysc_show_rev(char *bufp, struct sysc *ddata) { - int error, len; + int len; if (ddata->offsets[SYSC_REVISION] < 0) return sprintf(bufp, ":NA"); - error = pm_runtime_get_sync(ddata->dev); - if (error < 0) { - pm_runtime_put_noidle(ddata->dev); - - return 0; - } - - len = sprintf(bufp, ":%08x", sysc_read_revision(ddata)); - - pm_runtime_mark_last_busy(ddata->dev); - pm_runtime_put_autosuspend(ddata->dev); + len = sprintf(bufp, ":%08x", ddata->revision); return len; } @@ -464,6 +503,151 @@ static const struct dev_pm_ops sysc_pm_ops = { NULL) }; +/* At this point the module is configured enough to read the revision */ +static int sysc_init_module(struct sysc *ddata) +{ + int error; + + error = pm_runtime_get_sync(ddata->dev); + if (error < 0) { + pm_runtime_put_noidle(ddata->dev); + + return 0; + } + ddata->revision = sysc_read_revision(ddata); + pm_runtime_put_sync(ddata->dev); + + return 0; +} + +static int sysc_init_sysc_mask(struct sysc *ddata) +{ + struct device_node *np = ddata->dev->of_node; + int error; + u32 val; + + error = of_property_read_u32(np, "ti,sysc-mask", &val); + if (error) + return 0; + + if (val) + ddata->cfg.sysc_val = val & ddata->cap->sysc_mask; + else + ddata->cfg.sysc_val = ddata->cap->sysc_mask; + + return 0; +} + +static int sysc_init_idlemode(struct sysc *ddata, u8 *idlemodes, + const char *name) +{ + struct device_node *np = ddata->dev->of_node; + struct property *prop; + const __be32 *p; + u32 val; + + of_property_for_each_u32(np, name, prop, p, val) { + if (val >= SYSC_NR_IDLEMODES) { + dev_err(ddata->dev, "invalid idlemode: %i\n", val); + return -EINVAL; + } + *idlemodes |= (1 << val); + } + + return 0; +} + +static int sysc_init_idlemodes(struct sysc *ddata) +{ + int error; + + error = sysc_init_idlemode(ddata, &ddata->cfg.midlemodes, + "ti,sysc-midle"); + if (error) + return error; + + error = sysc_init_idlemode(ddata, &ddata->cfg.sidlemodes, + "ti,sysc-sidle"); + if (error) + return error; + + return 0; +} + +/* + * Only some devices on omap4 and later have SYSCONFIG reset done + * bit. We can detect this if there is no SYSSTATUS at all, or the + * SYSTATUS bit 0 is not used. Note that some SYSSTATUS registers + * have multiple bits for the child devices like OHCI and EHCI. + * Depends on SYSC being parsed first. + */ +static int sysc_init_syss_mask(struct sysc *ddata) +{ + struct device_node *np = ddata->dev->of_node; + int error; + u32 val; + + error = of_property_read_u32(np, "ti,syss-mask", &val); + if (error) { + if ((ddata->cap->type == TI_SYSC_OMAP4 || + ddata->cap->type == TI_SYSC_OMAP4_TIMER) && + (ddata->cfg.sysc_val & SYSC_OMAP4_SOFTRESET)) + ddata->cfg.quirks |= SYSC_QUIRK_RESET_STATUS; + + return 0; + } + + if (!(val & 1) && (ddata->cfg.sysc_val & SYSC_OMAP4_SOFTRESET)) + ddata->cfg.quirks |= SYSC_QUIRK_RESET_STATUS; + + ddata->cfg.syss_mask = val; + + return 0; +} + +/* Device tree configured quirks */ +struct sysc_dts_quirk { + const char *name; + u32 mask; +}; + +static const struct sysc_dts_quirk sysc_dts_quirks[] = { + { .name = "ti,no-idle-on-init", + .mask = SYSC_QUIRK_NO_IDLE_ON_INIT, }, + { .name = "ti,no-reset-on-init", + .mask = SYSC_QUIRK_NO_RESET_ON_INIT, }, +}; + +static int sysc_init_dts_quirks(struct sysc *ddata) +{ + struct device_node *np = ddata->dev->of_node; + const struct property *prop; + int i, len, error; + u32 val; + + ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL); + + for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) { + prop = of_get_property(np, sysc_dts_quirks[i].name, &len); + if (!prop) + break; + + ddata->cfg.quirks |= sysc_dts_quirks[i].mask; + } + + error = of_property_read_u32(np, "ti,sysc-delay-us", &val); + if (!error) { + if (val > 255) { + dev_warn(ddata->dev, "bad ti,sysc-delay-us: %i\n", + val); + } + + ddata->cfg.srst_udelay = (u8)val; + } + + return 0; +} + static void sysc_unprepare(struct sysc *ddata) { int i; @@ -474,9 +658,230 @@ static void sysc_unprepare(struct sysc *ddata) } } +/* + * Common sysc register bits found on omap2, also known as type1 + */ +static const struct sysc_regbits sysc_regbits_omap2 = { + .dmadisable_shift = -ENODEV, + .midle_shift = 12, + .sidle_shift = 3, + .clkact_shift = 8, + .emufree_shift = 5, + .enwkup_shift = 2, + .srst_shift = 1, + .autoidle_shift = 0, +}; + +static const struct sysc_capabilities sysc_omap2 = { + .type = TI_SYSC_OMAP2, + .sysc_mask = SYSC_OMAP2_CLOCKACTIVITY | SYSC_OMAP2_EMUFREE | + SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_SOFTRESET | + SYSC_OMAP2_AUTOIDLE, + .regbits = &sysc_regbits_omap2, +}; + +/* All omap2 and 3 timers, and timers 1, 2 & 10 on omap 4 and 5 */ +static const struct sysc_capabilities sysc_omap2_timer = { + .type = TI_SYSC_OMAP2_TIMER, + .sysc_mask = SYSC_OMAP2_CLOCKACTIVITY | SYSC_OMAP2_EMUFREE | + SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_SOFTRESET | + SYSC_OMAP2_AUTOIDLE, + .regbits = &sysc_regbits_omap2, + .mod_quirks = SYSC_QUIRK_USE_CLOCKACT, +}; + +/* + * SHAM2 (SHA1/MD5) sysc found on omap3, a variant of sysc_regbits_omap2 + * with different sidle position + */ +static const struct sysc_regbits sysc_regbits_omap3_sham = { + .dmadisable_shift = -ENODEV, + .midle_shift = -ENODEV, + .sidle_shift = 4, + .clkact_shift = -ENODEV, + .enwkup_shift = -ENODEV, + .srst_shift = 1, + .autoidle_shift = 0, + .emufree_shift = -ENODEV, +}; + +static const struct sysc_capabilities sysc_omap3_sham = { + .type = TI_SYSC_OMAP3_SHAM, + .sysc_mask = SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE, + .regbits = &sysc_regbits_omap3_sham, +}; + +/* + * AES register bits found on omap3 and later, a variant of + * sysc_regbits_omap2 with different sidle position + */ +static const struct sysc_regbits sysc_regbits_omap3_aes = { + .dmadisable_shift = -ENODEV, + .midle_shift = -ENODEV, + .sidle_shift = 6, + .clkact_shift = -ENODEV, + .enwkup_shift = -ENODEV, + .srst_shift = 1, + .autoidle_shift = 0, + .emufree_shift = -ENODEV, +}; + +static const struct sysc_capabilities sysc_omap3_aes = { + .type = TI_SYSC_OMAP3_AES, + .sysc_mask = SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE, + .regbits = &sysc_regbits_omap3_aes, +}; + +/* + * Common sysc register bits found on omap4, also known as type2 + */ +static const struct sysc_regbits sysc_regbits_omap4 = { + .dmadisable_shift = 16, + .midle_shift = 4, + .sidle_shift = 2, + .clkact_shift = -ENODEV, + .enwkup_shift = -ENODEV, + .emufree_shift = 1, + .srst_shift = 0, + .autoidle_shift = -ENODEV, +}; + +static const struct sysc_capabilities sysc_omap4 = { + .type = TI_SYSC_OMAP4, + .sysc_mask = SYSC_OMAP4_DMADISABLE | SYSC_OMAP4_FREEEMU | + SYSC_OMAP4_SOFTRESET, + .regbits = &sysc_regbits_omap4, +}; + +static const struct sysc_capabilities sysc_omap4_timer = { + .type = TI_SYSC_OMAP4_TIMER, + .sysc_mask = SYSC_OMAP4_DMADISABLE | SYSC_OMAP4_FREEEMU | + SYSC_OMAP4_SOFTRESET, + .regbits = &sysc_regbits_omap4, +}; + +/* + * Common sysc register bits found on omap4, also known as type3 + */ +static const struct sysc_regbits sysc_regbits_omap4_simple = { + .dmadisable_shift = -ENODEV, + .midle_shift = 2, + .sidle_shift = 0, + .clkact_shift = -ENODEV, + .enwkup_shift = -ENODEV, + .srst_shift = -ENODEV, + .emufree_shift = -ENODEV, + .autoidle_shift = -ENODEV, +}; + +static const struct sysc_capabilities sysc_omap4_simple = { + .type = TI_SYSC_OMAP4_SIMPLE, + .regbits = &sysc_regbits_omap4_simple, +}; + +/* + * SmartReflex sysc found on omap34xx + */ +static const struct sysc_regbits sysc_regbits_omap34xx_sr = { + .dmadisable_shift = -ENODEV, + .midle_shift = -ENODEV, + .sidle_shift = -ENODEV, + .clkact_shift = 20, + .enwkup_shift = -ENODEV, + .srst_shift = -ENODEV, + .emufree_shift = -ENODEV, + .autoidle_shift = -ENODEV, +}; + +static const struct sysc_capabilities sysc_34xx_sr = { + .type = TI_SYSC_OMAP34XX_SR, + .sysc_mask = SYSC_OMAP2_CLOCKACTIVITY, + .regbits = &sysc_regbits_omap34xx_sr, + .mod_quirks = SYSC_QUIRK_USE_CLOCKACT | SYSC_QUIRK_UNCACHED, +}; + +/* + * SmartReflex sysc found on omap36xx and later + */ +static const struct sysc_regbits sysc_regbits_omap36xx_sr = { + .dmadisable_shift = -ENODEV, + .midle_shift = -ENODEV, + .sidle_shift = 24, + .clkact_shift = -ENODEV, + .enwkup_shift = 26, + .srst_shift = -ENODEV, + .emufree_shift = -ENODEV, + .autoidle_shift = -ENODEV, +}; + +static const struct sysc_capabilities sysc_36xx_sr = { + .type = TI_SYSC_OMAP36XX_SR, + .sysc_mask = SYSC_OMAP3_SR_ENAWAKEUP, + .regbits = &sysc_regbits_omap36xx_sr, + .mod_quirks = SYSC_QUIRK_UNCACHED, +}; + +static const struct sysc_capabilities sysc_omap4_sr = { + .type = TI_SYSC_OMAP4_SR, + .regbits = &sysc_regbits_omap36xx_sr, +}; + +/* + * McASP register bits found on omap4 and later + */ +static const struct sysc_regbits sysc_regbits_omap4_mcasp = { + .dmadisable_shift = -ENODEV, + .midle_shift = -ENODEV, + .sidle_shift = 0, + .clkact_shift = -ENODEV, + .enwkup_shift = -ENODEV, + .srst_shift = -ENODEV, + .emufree_shift = -ENODEV, + .autoidle_shift = -ENODEV, +}; + +static const struct sysc_capabilities sysc_omap4_mcasp = { + .type = TI_SYSC_OMAP4_MCASP, + .regbits = &sysc_regbits_omap4_mcasp, +}; + +/* + * FS USB host found on omap4 and later + */ +static const struct sysc_regbits sysc_regbits_omap4_usb_host_fs = { + .dmadisable_shift = -ENODEV, + .midle_shift = -ENODEV, + .sidle_shift = 24, + .clkact_shift = -ENODEV, + .enwkup_shift = 26, + .srst_shift = -ENODEV, + .emufree_shift = -ENODEV, + .autoidle_shift = -ENODEV, +}; + +static const struct sysc_capabilities sysc_omap4_usb_host_fs = { + .type = TI_SYSC_OMAP4_USB_HOST_FS, + .sysc_mask = SYSC_OMAP2_ENAWAKEUP, + .regbits = &sysc_regbits_omap4_usb_host_fs, +}; + +static int sysc_init_match(struct sysc *ddata) +{ + const struct sysc_capabilities *cap; + + cap = of_device_get_match_data(ddata->dev); + if (!cap) + return -EINVAL; + + ddata->cap = cap; + if (ddata->cap) + ddata->cfg.quirks |= ddata->cap->mod_quirks; + + return 0; +} + static int sysc_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; struct sysc *ddata; int error; @@ -485,7 +890,15 @@ static int sysc_probe(struct platform_device *pdev) return -ENOMEM; ddata->dev = &pdev->dev; - ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL); + platform_set_drvdata(pdev, ddata); + + error = sysc_init_match(ddata); + if (error) + return error; + + error = sysc_init_dts_quirks(ddata); + if (error) + goto unprepare; error = sysc_get_clocks(ddata); if (error) @@ -495,9 +908,24 @@ static int sysc_probe(struct platform_device *pdev) if (error) goto unprepare; - platform_set_drvdata(pdev, ddata); + error = sysc_init_sysc_mask(ddata); + if (error) + goto unprepare; + + error = sysc_init_idlemodes(ddata); + if (error) + goto unprepare; + + error = sysc_init_syss_mask(ddata); + if (error) + goto unprepare; pm_runtime_enable(ddata->dev); + + error = sysc_init_module(ddata); + if (error) + goto unprepare; + error = pm_runtime_get_sync(ddata->dev); if (error < 0) { pm_runtime_put_noidle(ddata->dev); @@ -554,16 +982,19 @@ unprepare: } static const struct of_device_id sysc_match[] = { - { .compatible = "ti,sysc-omap2" }, - { .compatible = "ti,sysc-omap4" }, - { .compatible = "ti,sysc-omap4-simple" }, - { .compatible = "ti,sysc-omap3430-sr" }, - { .compatible = "ti,sysc-omap3630-sr" }, - { .compatible = "ti,sysc-omap4-sr" }, - { .compatible = "ti,sysc-omap3-sham" }, - { .compatible = "ti,sysc-omap-aes" }, - { .compatible = "ti,sysc-mcasp" }, - { .compatible = "ti,sysc-usb-host-fs" }, + { .compatible = "ti,sysc-omap2", .data = &sysc_omap2, }, + { .compatible = "ti,sysc-omap2-timer", .data = &sysc_omap2_timer, }, + { .compatible = "ti,sysc-omap4", .data = &sysc_omap4, }, + { .compatible = "ti,sysc-omap4-timer", .data = &sysc_omap4_timer, }, + { .compatible = "ti,sysc-omap4-simple", .data = &sysc_omap4_simple, }, + { .compatible = "ti,sysc-omap3430-sr", .data = &sysc_34xx_sr, }, + { .compatible = "ti,sysc-omap3630-sr", .data = &sysc_36xx_sr, }, + { .compatible = "ti,sysc-omap4-sr", .data = &sysc_omap4_sr, }, + { .compatible = "ti,sysc-omap3-sham", .data = &sysc_omap3_sham, }, + { .compatible = "ti,sysc-omap-aes", .data = &sysc_omap3_aes, }, + { .compatible = "ti,sysc-mcasp", .data = &sysc_omap4_mcasp, }, + { .compatible = "ti,sysc-usb-host-fs", + .data = &sysc_omap4_usb_host_fs, }, { }, }; MODULE_DEVICE_TABLE(of, sysc_match); diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index 828b34445203..623205bcd04a 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -340,11 +340,17 @@ static int agp_nvidia_probe(struct pci_dev *pdev, u8 cap_ptr; nvidia_private.dev_1 = - pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1)); + pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus), + (unsigned int)pdev->bus->number, + PCI_DEVFN(0, 1)); nvidia_private.dev_2 = - pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 2)); + pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus), + (unsigned int)pdev->bus->number, + PCI_DEVFN(0, 2)); nvidia_private.dev_3 = - pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(30, 0)); + pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus), + (unsigned int)pdev->bus->number, + PCI_DEVFN(30, 0)); if (!nvidia_private.dev_1 || !nvidia_private.dev_2 || !nvidia_private.dev_3) { printk(KERN_INFO PFX "Detected an NVIDIA nForce/nForce2 " diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index 03be4ac79b0d..4dbdd3bc9bb8 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -474,7 +474,8 @@ static int agp_serverworks_probe(struct pci_dev *pdev, } /* Everything is on func 1 here so we are hardcoding function one */ - bridge_dev = pci_get_bus_and_slot((unsigned int)pdev->bus->number, + bridge_dev = pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus), + (unsigned int)pdev->bus->number, PCI_DEVFN(0, 1)); if (!bridge_dev) { dev_info(&pdev->dev, "can't find secondary device\n"); diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c index 1dfb9f8de171..a5e2f9e557ea 100644 --- a/drivers/char/apm-emulation.c +++ b/drivers/char/apm-emulation.c @@ -236,12 +236,12 @@ static ssize_t apm_read(struct file *fp, char __user *buf, size_t count, loff_t return ret; } -static unsigned int apm_poll(struct file *fp, poll_table * wait) +static __poll_t apm_poll(struct file *fp, poll_table * wait) { struct apm_user *as = fp->private_data; poll_wait(fp, &apm_waitqueue, wait); - return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM; + return queue_empty(&as->queue) ? 0 : EPOLLIN | EPOLLRDNORM; } /* diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index 0d7b577e0ff0..06749e295ada 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -406,7 +406,7 @@ static long dsp56k_ioctl(struct file *file, unsigned int cmd, * Do I need this function at all??? */ #if 0 -static unsigned int dsp56k_poll(struct file *file, poll_table *wait) +static __poll_t dsp56k_poll(struct file *file, poll_table *wait) { int dev = iminor(file_inode(file)) & 0x0f; @@ -414,7 +414,7 @@ static unsigned int dsp56k_poll(struct file *file, poll_table *wait) { case DSP56K_DEV_56001: /* poll_wait(file, ???, wait); */ - return POLLIN | POLLRDNORM | POLLOUT; + return EPOLLIN | EPOLLRDNORM | EPOLLOUT; default: printk("DSP56k driver: Unknown minor device: %d\n", dev); diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c index 839ee61d352a..f882460b5a44 100644 --- a/drivers/char/dtlk.c +++ b/drivers/char/dtlk.c @@ -62,7 +62,7 @@ #include /* for get_user, etc. */ #include /* for wait_queue */ #include /* for __init, module_{init,exit} */ -#include /* for POLLIN, etc. */ +#include /* for EPOLLIN, etc. */ #include /* local header file for DoubleTalk values */ #ifdef TRACING @@ -91,7 +91,7 @@ static ssize_t dtlk_read(struct file *, char __user *, size_t nbytes, loff_t * ppos); static ssize_t dtlk_write(struct file *, const char __user *, size_t nbytes, loff_t * ppos); -static unsigned int dtlk_poll(struct file *, poll_table *); +static __poll_t dtlk_poll(struct file *, poll_table *); static int dtlk_open(struct inode *, struct file *); static int dtlk_release(struct inode *, struct file *); static long dtlk_ioctl(struct file *file, @@ -228,9 +228,9 @@ static ssize_t dtlk_write(struct file *file, const char __user *buf, return -EAGAIN; } -static unsigned int dtlk_poll(struct file *file, poll_table * wait) +static __poll_t dtlk_poll(struct file *file, poll_table * wait) { - int mask = 0; + __poll_t mask = 0; unsigned long expires; TRACE_TEXT(" dtlk_poll"); @@ -244,11 +244,11 @@ static unsigned int dtlk_poll(struct file *file, poll_table * wait) if (dtlk_has_indexing && dtlk_readable()) { del_timer(&dtlk_timer); - mask = POLLIN | POLLRDNORM; + mask = EPOLLIN | EPOLLRDNORM; } if (dtlk_writeable()) { del_timer(&dtlk_timer); - mask |= POLLOUT | POLLWRNORM; + mask |= EPOLLOUT | EPOLLWRNORM; } /* there are no exception conditions */ diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index b941e6d59fd6..be426eb2a353 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -342,7 +342,7 @@ out: return retval; } -static unsigned int hpet_poll(struct file *file, poll_table * wait) +static __poll_t hpet_poll(struct file *file, poll_table * wait) { unsigned long v; struct hpet_dev *devp; @@ -359,7 +359,7 @@ static unsigned int hpet_poll(struct file *file, poll_table * wait) spin_unlock_irq(&hpet_lock); if (v != 0) - return POLLIN | POLLRDNORM; + return EPOLLIN | EPOLLRDNORM; return 0; } diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index f6e3e5abc117..4d0f571c15f9 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -73,26 +73,14 @@ config HW_RANDOM_ATMEL If unsure, say Y. -config HW_RANDOM_BCM63XX - tristate "Broadcom BCM63xx Random Number Generator support" - depends on BCM63XX || BMIPS_GENERIC - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on the Broadcom BCM63xx SoCs. - - To compile this driver as a module, choose M here: the - module will be called bcm63xx-rng - - If unusure, say Y. - config HW_RANDOM_BCM2835 - tristate "Broadcom BCM2835 Random Number Generator support" - depends on ARCH_BCM2835 || ARCH_BCM_NSP || ARCH_BCM_5301X + tristate "Broadcom BCM2835/BCM63xx Random Number Generator support" + depends on ARCH_BCM2835 || ARCH_BCM_NSP || ARCH_BCM_5301X || \ + ARCH_BCM_63XX || BCM63XX || BMIPS_GENERIC default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number - Generator hardware found on the Broadcom BCM2835 SoCs. + Generator hardware found on the Broadcom BCM2835 and BCM63xx SoCs. To compile this driver as a module, choose M here: the module will be called bcm2835-rng @@ -306,19 +294,6 @@ config HW_RANDOM_POWERNV If unsure, say Y. -config HW_RANDOM_TPM - tristate "TPM HW Random Number Generator support" - depends on TCG_TPM - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator in the Trusted Platform Module - - To compile this driver as a module, choose M here: the - module will be called tpm-rng. - - If unsure, say Y. - config HW_RANDOM_HISI tristate "Hisilicon Random Number Generator support" depends on HW_RANDOM && ARCH_HISI @@ -449,6 +424,18 @@ config HW_RANDOM_S390 If unsure, say Y. +config HW_RANDOM_EXYNOS + tristate "Samsung Exynos True Random Number Generator support" + depends on ARCH_EXYNOS || COMPILE_TEST + default HW_RANDOM + ---help--- + This driver provides support for the True Random Number + Generator available in Exynos SoCs. + + To compile this driver as a module, choose M here: the module + will be called exynos-trng. + + If unsure, say Y. endif # HW_RANDOM config UML_RANDOM diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index f3728d008fff..b780370bd4eb 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -9,11 +9,11 @@ obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o -obj-$(CONFIG_HW_RANDOM_BCM63XX) += bcm63xx-rng.o obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o obj-$(CONFIG_HW_RANDOM_N2RNG) += n2-rng.o n2-rng-y := n2-drv.o n2-asm.o obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o +obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-trng.o obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o obj-$(CONFIG_HW_RANDOM_OMAP3_ROM) += omap3-rom-rng.o @@ -27,7 +27,6 @@ obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o obj-$(CONFIG_HW_RANDOM_HISI) += hisi-rng.o -obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c index 574211a49549..7a84cec30c3a 100644 --- a/drivers/char/hw_random/bcm2835-rng.c +++ b/drivers/char/hw_random/bcm2835-rng.c @@ -15,6 +15,7 @@ #include #include #include +#include #define RNG_CTRL 0x0 #define RNG_STATUS 0x4 @@ -29,116 +30,180 @@ #define RNG_INT_OFF 0x1 -static void __init nsp_rng_init(void __iomem *base) -{ - u32 val; +struct bcm2835_rng_priv { + struct hwrng rng; + void __iomem *base; + bool mask_interrupts; + struct clk *clk; +}; - /* mask the interrupt */ - val = readl(base + RNG_INT_MASK); - val |= RNG_INT_OFF; - writel(val, base + RNG_INT_MASK); +static inline struct bcm2835_rng_priv *to_rng_priv(struct hwrng *rng) +{ + return container_of(rng, struct bcm2835_rng_priv, rng); +} + +static inline u32 rng_readl(struct bcm2835_rng_priv *priv, u32 offset) +{ + /* MIPS chips strapped for BE will automagically configure the + * peripheral registers for CPU-native byte order. + */ + if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) + return __raw_readl(priv->base + offset); + else + return readl(priv->base + offset); +} + +static inline void rng_writel(struct bcm2835_rng_priv *priv, u32 val, + u32 offset) +{ + if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) + __raw_writel(val, priv->base + offset); + else + writel(val, priv->base + offset); } static int bcm2835_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait) { - void __iomem *rng_base = (void __iomem *)rng->priv; + struct bcm2835_rng_priv *priv = to_rng_priv(rng); u32 max_words = max / sizeof(u32); u32 num_words, count; - while ((__raw_readl(rng_base + RNG_STATUS) >> 24) == 0) { + while ((rng_readl(priv, RNG_STATUS) >> 24) == 0) { if (!wait) return 0; cpu_relax(); } - num_words = readl(rng_base + RNG_STATUS) >> 24; + num_words = rng_readl(priv, RNG_STATUS) >> 24; if (num_words > max_words) num_words = max_words; for (count = 0; count < num_words; count++) - ((u32 *)buf)[count] = readl(rng_base + RNG_DATA); + ((u32 *)buf)[count] = rng_readl(priv, RNG_DATA); return num_words * sizeof(u32); } -static struct hwrng bcm2835_rng_ops = { - .name = "bcm2835", - .read = bcm2835_rng_read, +static int bcm2835_rng_init(struct hwrng *rng) +{ + struct bcm2835_rng_priv *priv = to_rng_priv(rng); + int ret = 0; + u32 val; + + if (!IS_ERR(priv->clk)) { + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + } + + if (priv->mask_interrupts) { + /* mask the interrupt */ + val = rng_readl(priv, RNG_INT_MASK); + val |= RNG_INT_OFF; + rng_writel(priv, val, RNG_INT_MASK); + } + + /* set warm-up count & enable */ + rng_writel(priv, RNG_WARMUP_COUNT, RNG_STATUS); + rng_writel(priv, RNG_RBGEN, RNG_CTRL); + + return ret; +} + +static void bcm2835_rng_cleanup(struct hwrng *rng) +{ + struct bcm2835_rng_priv *priv = to_rng_priv(rng); + + /* disable rng hardware */ + rng_writel(priv, 0, RNG_CTRL); + + if (!IS_ERR(priv->clk)) + clk_disable_unprepare(priv->clk); +} + +struct bcm2835_rng_of_data { + bool mask_interrupts; +}; + +static const struct bcm2835_rng_of_data nsp_rng_of_data = { + .mask_interrupts = true, }; static const struct of_device_id bcm2835_rng_of_match[] = { { .compatible = "brcm,bcm2835-rng"}, - { .compatible = "brcm,bcm-nsp-rng", .data = nsp_rng_init}, - { .compatible = "brcm,bcm5301x-rng", .data = nsp_rng_init}, + { .compatible = "brcm,bcm-nsp-rng", .data = &nsp_rng_of_data }, + { .compatible = "brcm,bcm5301x-rng", .data = &nsp_rng_of_data }, + { .compatible = "brcm,bcm6368-rng"}, {}, }; static int bcm2835_rng_probe(struct platform_device *pdev) { + const struct bcm2835_rng_of_data *of_data; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - void (*rng_setup)(void __iomem *base); const struct of_device_id *rng_id; - void __iomem *rng_base; + struct bcm2835_rng_priv *priv; + struct resource *r; int err; + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + /* map peripheral */ - rng_base = of_iomap(np, 0); - if (!rng_base) { - dev_err(dev, "failed to remap rng regs"); - return -ENODEV; - } - bcm2835_rng_ops.priv = (unsigned long)rng_base; + priv->base = devm_ioremap_resource(dev, r); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + /* Clock is optional on most platforms */ + priv->clk = devm_clk_get(dev, NULL); + + priv->rng.name = pdev->name; + priv->rng.init = bcm2835_rng_init; + priv->rng.read = bcm2835_rng_read; + priv->rng.cleanup = bcm2835_rng_cleanup; rng_id = of_match_node(bcm2835_rng_of_match, np); - if (!rng_id) { - iounmap(rng_base); + if (!rng_id) return -EINVAL; - } - /* Check for rng init function, execute it */ - rng_setup = rng_id->data; - if (rng_setup) - rng_setup(rng_base); - /* set warm-up count & enable */ - __raw_writel(RNG_WARMUP_COUNT, rng_base + RNG_STATUS); - __raw_writel(RNG_RBGEN, rng_base + RNG_CTRL); + /* Check for rng init function, execute it */ + of_data = rng_id->data; + if (of_data) + priv->mask_interrupts = of_data->mask_interrupts; /* register driver */ - err = hwrng_register(&bcm2835_rng_ops); - if (err) { + err = devm_hwrng_register(dev, &priv->rng); + if (err) dev_err(dev, "hwrng registration failed\n"); - iounmap(rng_base); - } else + else dev_info(dev, "hwrng registered\n"); return err; } -static int bcm2835_rng_remove(struct platform_device *pdev) -{ - void __iomem *rng_base = (void __iomem *)bcm2835_rng_ops.priv; - - /* disable rng hardware */ - __raw_writel(0, rng_base + RNG_CTRL); - - /* unregister driver */ - hwrng_unregister(&bcm2835_rng_ops); - iounmap(rng_base); - - return 0; -} - MODULE_DEVICE_TABLE(of, bcm2835_rng_of_match); +static struct platform_device_id bcm2835_rng_devtype[] = { + { .name = "bcm2835-rng" }, + { .name = "bcm63xx-rng" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, bcm2835_rng_devtype); + static struct platform_driver bcm2835_rng_driver = { .driver = { .name = "bcm2835-rng", .of_match_table = bcm2835_rng_of_match, }, .probe = bcm2835_rng_probe, - .remove = bcm2835_rng_remove, + .id_table = bcm2835_rng_devtype, }; module_platform_driver(bcm2835_rng_driver); diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c deleted file mode 100644 index 5132c9cde50d..000000000000 --- a/drivers/char/hw_random/bcm63xx-rng.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Broadcom BCM63xx Random Number Generator support - * - * Copyright (C) 2011, Florian Fainelli - * Copyright (C) 2009, Broadcom Corporation - * - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#define RNG_CTRL 0x00 -#define RNG_EN (1 << 0) - -#define RNG_STAT 0x04 -#define RNG_AVAIL_MASK (0xff000000) - -#define RNG_DATA 0x08 -#define RNG_THRES 0x0c -#define RNG_MASK 0x10 - -struct bcm63xx_rng_priv { - struct hwrng rng; - struct clk *clk; - void __iomem *regs; -}; - -#define to_rng_priv(rng) container_of(rng, struct bcm63xx_rng_priv, rng) - -static int bcm63xx_rng_init(struct hwrng *rng) -{ - struct bcm63xx_rng_priv *priv = to_rng_priv(rng); - u32 val; - int error; - - error = clk_prepare_enable(priv->clk); - if (error) - return error; - - val = __raw_readl(priv->regs + RNG_CTRL); - val |= RNG_EN; - __raw_writel(val, priv->regs + RNG_CTRL); - - return 0; -} - -static void bcm63xx_rng_cleanup(struct hwrng *rng) -{ - struct bcm63xx_rng_priv *priv = to_rng_priv(rng); - u32 val; - - val = __raw_readl(priv->regs + RNG_CTRL); - val &= ~RNG_EN; - __raw_writel(val, priv->regs + RNG_CTRL); - - clk_disable_unprepare(priv->clk); -} - -static int bcm63xx_rng_data_present(struct hwrng *rng, int wait) -{ - struct bcm63xx_rng_priv *priv = to_rng_priv(rng); - - return __raw_readl(priv->regs + RNG_STAT) & RNG_AVAIL_MASK; -} - -static int bcm63xx_rng_data_read(struct hwrng *rng, u32 *data) -{ - struct bcm63xx_rng_priv *priv = to_rng_priv(rng); - - *data = __raw_readl(priv->regs + RNG_DATA); - - return 4; -} - -static int bcm63xx_rng_probe(struct platform_device *pdev) -{ - struct resource *r; - int ret; - struct bcm63xx_rng_priv *priv; - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) { - dev_err(&pdev->dev, "no iomem resource\n"); - return -ENXIO; - } - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->rng.name = pdev->name; - priv->rng.init = bcm63xx_rng_init; - priv->rng.cleanup = bcm63xx_rng_cleanup; - priv->rng.data_present = bcm63xx_rng_data_present; - priv->rng.data_read = bcm63xx_rng_data_read; - - priv->clk = devm_clk_get(&pdev->dev, "ipsec"); - if (IS_ERR(priv->clk)) { - ret = PTR_ERR(priv->clk); - dev_err(&pdev->dev, "no clock for device: %d\n", ret); - return ret; - } - - if (!devm_request_mem_region(&pdev->dev, r->start, - resource_size(r), pdev->name)) { - dev_err(&pdev->dev, "request mem failed"); - return -EBUSY; - } - - priv->regs = devm_ioremap_nocache(&pdev->dev, r->start, - resource_size(r)); - if (!priv->regs) { - dev_err(&pdev->dev, "ioremap failed"); - return -ENOMEM; - } - - ret = devm_hwrng_register(&pdev->dev, &priv->rng); - if (ret) { - dev_err(&pdev->dev, "failed to register rng device: %d\n", - ret); - return ret; - } - - dev_info(&pdev->dev, "registered RNG driver\n"); - - return 0; -} - -#ifdef CONFIG_OF -static const struct of_device_id bcm63xx_rng_of_match[] = { - { .compatible = "brcm,bcm6368-rng", }, - {}, -}; -MODULE_DEVICE_TABLE(of, bcm63xx_rng_of_match); -#endif - -static struct platform_driver bcm63xx_rng_driver = { - .probe = bcm63xx_rng_probe, - .driver = { - .name = "bcm63xx-rng", - .of_match_table = of_match_ptr(bcm63xx_rng_of_match), - }, -}; - -module_platform_driver(bcm63xx_rng_driver); - -MODULE_AUTHOR("Florian Fainelli "); -MODULE_DESCRIPTION("Broadcom BCM63xx RNG driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 657b8770b6b9..91bb98c42a1c 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -306,6 +306,10 @@ static int enable_best_rng(void) ret = ((new_rng == current_rng) ? 0 : set_current_rng(new_rng)); if (!ret) cur_rng_set_by_user = 0; + } else { + drop_current_rng(); + cur_rng_set_by_user = 0; + ret = 0; } return ret; diff --git a/drivers/char/hw_random/exynos-trng.c b/drivers/char/hw_random/exynos-trng.c new file mode 100644 index 000000000000..1947aed7c044 --- /dev/null +++ b/drivers/char/hw_random/exynos-trng.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RNG driver for Exynos TRNGs + * + * Author: Łukasz Stelmach + * + * Copyright 2017 (c) Samsung Electronics Software, Inc. + * + * Based on the Exynos PRNG driver drivers/crypto/exynos-rng by + * Krzysztof Kozłowski + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EXYNOS_TRNG_CLKDIV (0x0) + +#define EXYNOS_TRNG_CTRL (0x20) +#define EXYNOS_TRNG_CTRL_RNGEN BIT(31) + +#define EXYNOS_TRNG_POST_CTRL (0x30) +#define EXYNOS_TRNG_ONLINE_CTRL (0x40) +#define EXYNOS_TRNG_ONLINE_STAT (0x44) +#define EXYNOS_TRNG_ONLINE_MAXCHI2 (0x48) +#define EXYNOS_TRNG_FIFO_CTRL (0x50) +#define EXYNOS_TRNG_FIFO_0 (0x80) +#define EXYNOS_TRNG_FIFO_1 (0x84) +#define EXYNOS_TRNG_FIFO_2 (0x88) +#define EXYNOS_TRNG_FIFO_3 (0x8c) +#define EXYNOS_TRNG_FIFO_4 (0x90) +#define EXYNOS_TRNG_FIFO_5 (0x94) +#define EXYNOS_TRNG_FIFO_6 (0x98) +#define EXYNOS_TRNG_FIFO_7 (0x9c) +#define EXYNOS_TRNG_FIFO_LEN (8) +#define EXYNOS_TRNG_CLOCK_RATE (500000) + + +struct exynos_trng_dev { + struct device *dev; + void __iomem *mem; + struct clk *clk; + struct hwrng rng; +}; + +static int exynos_trng_do_read(struct hwrng *rng, void *data, size_t max, + bool wait) +{ + struct exynos_trng_dev *trng; + int val; + + max = min_t(size_t, max, (EXYNOS_TRNG_FIFO_LEN * 4)); + + trng = (struct exynos_trng_dev *)rng->priv; + + writel_relaxed(max * 8, trng->mem + EXYNOS_TRNG_FIFO_CTRL); + val = readl_poll_timeout(trng->mem + EXYNOS_TRNG_FIFO_CTRL, val, + val == 0, 200, 1000000); + if (val < 0) + return val; + + memcpy_fromio(data, trng->mem + EXYNOS_TRNG_FIFO_0, max); + + return max; +} + +static int exynos_trng_init(struct hwrng *rng) +{ + struct exynos_trng_dev *trng = (struct exynos_trng_dev *)rng->priv; + unsigned long sss_rate; + u32 val; + + sss_rate = clk_get_rate(trng->clk); + + /* + * For most TRNG circuits the clock frequency of under 500 kHz + * is safe. + */ + val = sss_rate / (EXYNOS_TRNG_CLOCK_RATE * 2); + if (val > 0x7fff) { + dev_err(trng->dev, "clock divider too large: %d", val); + return -ERANGE; + } + val = val << 1; + writel_relaxed(val, trng->mem + EXYNOS_TRNG_CLKDIV); + + /* Enable the generator. */ + val = EXYNOS_TRNG_CTRL_RNGEN; + writel_relaxed(val, trng->mem + EXYNOS_TRNG_CTRL); + + /* + * Disable post-processing. /dev/hwrng is supposed to deliver + * unprocessed data. + */ + writel_relaxed(0, trng->mem + EXYNOS_TRNG_POST_CTRL); + + return 0; +} + +static int exynos_trng_probe(struct platform_device *pdev) +{ + struct exynos_trng_dev *trng; + struct resource *res; + int ret = -ENOMEM; + + trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL); + if (!trng) + return ret; + + trng->rng.name = devm_kstrdup(&pdev->dev, dev_name(&pdev->dev), + GFP_KERNEL); + if (!trng->rng.name) + return ret; + + trng->rng.init = exynos_trng_init; + trng->rng.read = exynos_trng_do_read; + trng->rng.priv = (unsigned long) trng; + + platform_set_drvdata(pdev, trng); + trng->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + trng->mem = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(trng->mem)) + return PTR_ERR(trng->mem); + + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "Could not get runtime PM.\n"); + goto err_pm_get; + } + + trng->clk = devm_clk_get(&pdev->dev, "secss"); + if (IS_ERR(trng->clk)) { + ret = PTR_ERR(trng->clk); + dev_err(&pdev->dev, "Could not get clock.\n"); + goto err_clock; + } + + ret = clk_prepare_enable(trng->clk); + if (ret) { + dev_err(&pdev->dev, "Could not enable the clk.\n"); + goto err_clock; + } + + ret = hwrng_register(&trng->rng); + if (ret) { + dev_err(&pdev->dev, "Could not register hwrng device.\n"); + goto err_register; + } + + dev_info(&pdev->dev, "Exynos True Random Number Generator.\n"); + + return 0; + +err_register: + clk_disable_unprepare(trng->clk); + +err_clock: + pm_runtime_put_sync(&pdev->dev); + +err_pm_get: + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static int exynos_trng_remove(struct platform_device *pdev) +{ + struct exynos_trng_dev *trng = platform_get_drvdata(pdev); + + hwrng_unregister(&trng->rng); + clk_disable_unprepare(trng->clk); + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static int __maybe_unused exynos_trng_suspend(struct device *dev) +{ + pm_runtime_put_sync(dev); + + return 0; +} + +static int __maybe_unused exynos_trng_resume(struct device *dev) +{ + int ret; + + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + dev_err(dev, "Could not get runtime PM.\n"); + pm_runtime_put_noidle(dev); + return ret; + } + + return 0; +} + +static SIMPLE_DEV_PM_OPS(exynos_trng_pm_ops, exynos_trng_suspend, + exynos_trng_resume); + +static const struct of_device_id exynos_trng_dt_match[] = { + { + .compatible = "samsung,exynos5250-trng", + }, + { }, +}; +MODULE_DEVICE_TABLE(of, exynos_trng_dt_match); + +static struct platform_driver exynos_trng_driver = { + .driver = { + .name = "exynos-trng", + .pm = &exynos_trng_pm_ops, + .of_match_table = exynos_trng_dt_match, + }, + .probe = exynos_trng_probe, + .remove = exynos_trng_remove, +}; + +module_platform_driver(exynos_trng_driver); +MODULE_AUTHOR("Łukasz Stelmach"); +MODULE_DESCRIPTION("H/W TRNG driver for Exynos chips"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/char/hw_random/imx-rngc.c b/drivers/char/hw_random/imx-rngc.c index 88db42d30760..eca87249bcff 100644 --- a/drivers/char/hw_random/imx-rngc.c +++ b/drivers/char/hw_random/imx-rngc.c @@ -282,8 +282,7 @@ static int __exit imx_rngc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int imx_rngc_suspend(struct device *dev) +static int __maybe_unused imx_rngc_suspend(struct device *dev) { struct imx_rngc *rngc = dev_get_drvdata(dev); @@ -292,7 +291,7 @@ static int imx_rngc_suspend(struct device *dev) return 0; } -static int imx_rngc_resume(struct device *dev) +static int __maybe_unused imx_rngc_resume(struct device *dev) { struct imx_rngc *rngc = dev_get_drvdata(dev); @@ -301,11 +300,7 @@ static int imx_rngc_resume(struct device *dev) return 0; } -static const struct dev_pm_ops imx_rngc_pm_ops = { - .suspend = imx_rngc_suspend, - .resume = imx_rngc_resume, -}; -#endif +SIMPLE_DEV_PM_OPS(imx_rngc_pm_ops, imx_rngc_suspend, imx_rngc_resume); static const struct of_device_id imx_rngc_dt_ids[] = { { .compatible = "fsl,imx25-rngb", .data = NULL, }, @@ -316,9 +311,7 @@ MODULE_DEVICE_TABLE(of, imx_rngc_dt_ids); static struct platform_driver imx_rngc_driver = { .driver = { .name = "imx_rngc", -#ifdef CONFIG_PM .pm = &imx_rngc_pm_ops, -#endif .of_match_table = imx_rngc_dt_ids, }, .remove = __exit_p(imx_rngc_remove), diff --git a/drivers/char/hw_random/mtk-rng.c b/drivers/char/hw_random/mtk-rng.c index 8da7bcf54105..7f99cd52b40e 100644 --- a/drivers/char/hw_random/mtk-rng.c +++ b/drivers/char/hw_random/mtk-rng.c @@ -135,6 +135,7 @@ static int mtk_rng_probe(struct platform_device *pdev) #endif priv->rng.read = mtk_rng_read; priv->rng.priv = (unsigned long)&pdev->dev; + priv->rng.quality = 900; priv->clk = devm_clk_get(&pdev->dev, "rng"); if (IS_ERR(priv->clk)) { diff --git a/drivers/char/hw_random/tpm-rng.c b/drivers/char/hw_random/tpm-rng.c deleted file mode 100644 index d6d448266f07..000000000000 --- a/drivers/char/hw_random/tpm-rng.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2012 Kent Yoder IBM Corporation - * - * HWRNG interfaces to pull RNG data from a TPM - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include - -#define MODULE_NAME "tpm-rng" - -static int tpm_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) -{ - return tpm_get_random(TPM_ANY_NUM, data, max); -} - -static struct hwrng tpm_rng = { - .name = MODULE_NAME, - .read = tpm_rng_read, -}; - -static int __init rng_init(void) -{ - return hwrng_register(&tpm_rng); -} -module_init(rng_init); - -static void __exit rng_exit(void) -{ - hwrng_unregister(&tpm_rng); -} -module_exit(rng_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Kent Yoder "); -MODULE_DESCRIPTION("RNG driver for TPM devices"); diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c index 6edfaa72b98b..c95b93b7598b 100644 --- a/drivers/char/ipmi/bt-bmc.c +++ b/drivers/char/ipmi/bt-bmc.c @@ -338,10 +338,10 @@ static int bt_bmc_release(struct inode *inode, struct file *file) return 0; } -static unsigned int bt_bmc_poll(struct file *file, poll_table *wait) +static __poll_t bt_bmc_poll(struct file *file, poll_table *wait) { struct bt_bmc *bt_bmc = file_bt_bmc(file); - unsigned int mask = 0; + __poll_t mask = 0; u8 ctrl; poll_wait(file, &bt_bmc->queue, wait); @@ -349,10 +349,10 @@ static unsigned int bt_bmc_poll(struct file *file, poll_table *wait) ctrl = bt_inb(bt_bmc, BT_CTRL); if (ctrl & BT_CTRL_H2B_ATN) - mask |= POLLIN; + mask |= EPOLLIN; if (!(ctrl & (BT_CTRL_H_BUSY | BT_CTRL_B2H_ATN))) - mask |= POLLOUT; + mask |= EPOLLOUT; return mask; } diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 2ffca4232686..5f1bc9174735 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -78,10 +78,10 @@ static void file_receive_handler(struct ipmi_recv_msg *msg, spin_unlock_irqrestore(&(priv->recv_msg_lock), flags); } -static unsigned int ipmi_poll(struct file *file, poll_table *wait) +static __poll_t ipmi_poll(struct file *file, poll_table *wait) { struct ipmi_file_private *priv = file->private_data; - unsigned int mask = 0; + __poll_t mask = 0; unsigned long flags; poll_wait(file, &priv->wait, wait); @@ -89,7 +89,7 @@ static unsigned int ipmi_poll(struct file *file, poll_table *wait) spin_lock_irqsave(&priv->recv_msg_lock, flags); if (!list_empty(&(priv->recv_msgs))) - mask |= (POLLIN | POLLRDNORM); + mask |= (EPOLLIN | EPOLLRDNORM); spin_unlock_irqrestore(&priv->recv_msg_lock, flags); diff --git a/drivers/char/ipmi/ipmi_dmi.c b/drivers/char/ipmi/ipmi_dmi.c index ab78b3be7e33..c5112b17d7ea 100644 --- a/drivers/char/ipmi/ipmi_dmi.c +++ b/drivers/char/ipmi/ipmi_dmi.c @@ -106,7 +106,10 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr, pr_err("ipmi:dmi: Error allocation IPMI platform device\n"); return; } - pdev->driver_override = override; + pdev->driver_override = kasprintf(GFP_KERNEL, "%s", + override); + if (!pdev->driver_override) + goto err; if (type == IPMI_DMI_TYPE_SSIF) { set_prop_entry(p[pidx++], "i2c-addr", u16, base_addr); diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index f45732a2cb3e..e0b0d7e2d976 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -84,7 +84,7 @@ static int panic_op_write_handler(const char *val, char valcp[16]; char *s; - strncpy(valcp, val, 16); + strncpy(valcp, val, 15); valcp[15] = '\0'; s = strstrip(valcp); @@ -2588,7 +2588,7 @@ static ssize_t device_id_show(struct device *dev, return snprintf(buf, 10, "%u\n", id.device_id); } -static DEVICE_ATTR(device_id, S_IRUGO, device_id_show, NULL); +static DEVICE_ATTR_RO(device_id); static ssize_t provides_device_sdrs_show(struct device *dev, struct device_attribute *attr, @@ -2604,8 +2604,7 @@ static ssize_t provides_device_sdrs_show(struct device *dev, return snprintf(buf, 10, "%u\n", (id.device_revision & 0x80) >> 7); } -static DEVICE_ATTR(provides_device_sdrs, S_IRUGO, provides_device_sdrs_show, - NULL); +static DEVICE_ATTR_RO(provides_device_sdrs); static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -2620,7 +2619,7 @@ static ssize_t revision_show(struct device *dev, struct device_attribute *attr, return snprintf(buf, 20, "%u\n", id.device_revision & 0x0F); } -static DEVICE_ATTR(revision, S_IRUGO, revision_show, NULL); +static DEVICE_ATTR_RO(revision); static ssize_t firmware_revision_show(struct device *dev, struct device_attribute *attr, @@ -2637,7 +2636,7 @@ static ssize_t firmware_revision_show(struct device *dev, return snprintf(buf, 20, "%u.%x\n", id.firmware_revision_1, id.firmware_revision_2); } -static DEVICE_ATTR(firmware_revision, S_IRUGO, firmware_revision_show, NULL); +static DEVICE_ATTR_RO(firmware_revision); static ssize_t ipmi_version_show(struct device *dev, struct device_attribute *attr, @@ -2655,7 +2654,7 @@ static ssize_t ipmi_version_show(struct device *dev, ipmi_version_major(&id), ipmi_version_minor(&id)); } -static DEVICE_ATTR(ipmi_version, S_IRUGO, ipmi_version_show, NULL); +static DEVICE_ATTR_RO(ipmi_version); static ssize_t add_dev_support_show(struct device *dev, struct device_attribute *attr, @@ -2688,7 +2687,7 @@ static ssize_t manufacturer_id_show(struct device *dev, return snprintf(buf, 20, "0x%6.6x\n", id.manufacturer_id); } -static DEVICE_ATTR(manufacturer_id, S_IRUGO, manufacturer_id_show, NULL); +static DEVICE_ATTR_RO(manufacturer_id); static ssize_t product_id_show(struct device *dev, struct device_attribute *attr, @@ -2704,7 +2703,7 @@ static ssize_t product_id_show(struct device *dev, return snprintf(buf, 10, "0x%4.4x\n", id.product_id); } -static DEVICE_ATTR(product_id, S_IRUGO, product_id_show, NULL); +static DEVICE_ATTR_RO(product_id); static ssize_t aux_firmware_rev_show(struct device *dev, struct device_attribute *attr, @@ -2742,7 +2741,7 @@ static ssize_t guid_show(struct device *dev, struct device_attribute *attr, return snprintf(buf, 38, "%pUl\n", guid.b); } -static DEVICE_ATTR(guid, S_IRUGO, guid_show, NULL); +static DEVICE_ATTR_RO(guid); static struct attribute *bmc_dev_attrs[] = { &dev_attr_device_id.attr, diff --git a/drivers/char/ipmi/ipmi_powernv.c b/drivers/char/ipmi/ipmi_powernv.c index 07fddbefefe4..bcf493d8e238 100644 --- a/drivers/char/ipmi/ipmi_powernv.c +++ b/drivers/char/ipmi/ipmi_powernv.c @@ -250,8 +250,9 @@ static int ipmi_powernv_probe(struct platform_device *pdev) ipmi->irq = opal_event_request(prop); } - if (request_irq(ipmi->irq, ipmi_opal_event, IRQ_TYPE_LEVEL_HIGH, - "opal-ipmi", ipmi)) { + rc = request_irq(ipmi->irq, ipmi_opal_event, IRQ_TYPE_LEVEL_HIGH, + "opal-ipmi", ipmi); + if (rc) { dev_warn(dev, "Unable to request irq\n"); goto err_dispose; } @@ -264,7 +265,6 @@ static int ipmi_powernv_probe(struct platform_device *pdev) goto err_unregister; } - /* todo: query actual ipmi_device_id */ rc = ipmi_register_smi(&ipmi_powernv_smi_handlers, ipmi, dev, 0); if (rc) { dev_warn(dev, "IPMI SMI registration failed (%d)\n", rc); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 71fad747c0c7..6768cb2dd740 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1938,8 +1938,10 @@ static void check_for_broken_irqs(struct smi_info *smi_info) static inline void stop_timer_and_thread(struct smi_info *smi_info) { - if (smi_info->thread != NULL) + if (smi_info->thread != NULL) { kthread_stop(smi_info->thread); + smi_info->thread = NULL; + } smi_info->timer_can_start = false; if (smi_info->timer_running) @@ -2045,6 +2047,7 @@ static int try_smi_init(struct smi_info *new_smi) int rv = 0; int i; char *init_name = NULL; + bool platform_device_registered = false; pr_info(PFX "Trying %s-specified %s state machine at %s address 0x%lx, slave address 0x%x, irq %d\n", ipmi_addr_src_to_str(new_smi->io.addr_source), @@ -2173,6 +2176,7 @@ static int try_smi_init(struct smi_info *new_smi) rv); goto out_err; } + platform_device_registered = true; } dev_set_drvdata(new_smi->io.dev, new_smi); @@ -2279,10 +2283,11 @@ out_err: } if (new_smi->pdev) { - platform_device_unregister(new_smi->pdev); + if (platform_device_registered) + platform_device_unregister(new_smi->pdev); + else + platform_device_put(new_smi->pdev); new_smi->pdev = NULL; - } else if (new_smi->pdev) { - platform_device_put(new_smi->pdev); } kfree(init_name); diff --git a/drivers/char/ipmi/ipmi_si_platform.c b/drivers/char/ipmi/ipmi_si_platform.c index 9573f1116450..f4214870d726 100644 --- a/drivers/char/ipmi/ipmi_si_platform.c +++ b/drivers/char/ipmi/ipmi_si_platform.c @@ -40,7 +40,7 @@ MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the" #endif #ifdef CONFIG_OF module_param_named(tryopenfirmware, si_tryopenfirmware, bool, 0); -MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the" +MODULE_PARM_DESC(tryopenfirmware, "Setting this to zero will disable the" " default scan of the interfaces identified via OpenFirmware"); #endif #ifdef CONFIG_DMI diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 3cfaec728604..f929e72bdac8 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -2071,8 +2071,7 @@ static int ssif_platform_remove(struct platform_device *dev) return 0; mutex_lock(&ssif_infos_mutex); - if (addr_info->client) - i2c_unregister_device(addr_info->client); + i2c_unregister_device(addr_info->client); list_del(&addr_info->link); kfree(addr_info); diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 76b270678b50..a58acdcf7414 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -232,7 +232,7 @@ static int set_param_str(const char *val, const struct kernel_param *kp) char valcp[16]; char *s; - strncpy(valcp, val, 16); + strncpy(valcp, val, 15); valcp[15] = '\0'; s = strstrip(valcp); @@ -298,7 +298,7 @@ module_param(pretimeout, timeout, 0644); MODULE_PARM_DESC(pretimeout, "Pretimeout value in seconds."); module_param(panic_wdt_timeout, timeout, 0644); -MODULE_PARM_DESC(timeout, "Timeout value on kernel panic in seconds."); +MODULE_PARM_DESC(panic_wdt_timeout, "Timeout value on kernel panic in seconds."); module_param_cb(action, ¶m_ops_str, action_op, 0644); MODULE_PARM_DESC(action, "Timeout action. One of: " @@ -887,15 +887,15 @@ static int ipmi_open(struct inode *ino, struct file *filep) } } -static unsigned int ipmi_poll(struct file *file, poll_table *wait) +static __poll_t ipmi_poll(struct file *file, poll_table *wait) { - unsigned int mask = 0; + __poll_t mask = 0; poll_wait(file, &read_q, wait); spin_lock(&ipmi_read_lock); if (data_to_read) - mask |= (POLLIN | POLLRDNORM); + mask |= (EPOLLIN | EPOLLRDNORM); spin_unlock(&ipmi_read_lock); return mask; diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 8249762192d5..8c4dd1a3bb6a 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -659,17 +659,31 @@ static int lp_do_ioctl(unsigned int minor, unsigned int cmd, return retval; } -static int lp_set_timeout(unsigned int minor, struct timeval *par_timeout) +static int lp_set_timeout(unsigned int minor, s64 tv_sec, long tv_usec) { long to_jiffies; /* Convert to jiffies, place in lp_table */ - if ((par_timeout->tv_sec < 0) || - (par_timeout->tv_usec < 0)) { + if (tv_sec < 0 || tv_usec < 0) return -EINVAL; + + /* + * we used to not check, so let's not make this fatal, + * but deal with user space passing a 32-bit tv_nsec in + * a 64-bit field, capping the timeout to 1 second + * worth of microseconds, and capping the total at + * MAX_JIFFY_OFFSET. + */ + if (tv_usec > 999999) + tv_usec = 999999; + + if (tv_sec >= MAX_SEC_IN_JIFFIES - 1) { + to_jiffies = MAX_JIFFY_OFFSET; + } else { + to_jiffies = DIV_ROUND_UP(tv_usec, 1000000/HZ); + to_jiffies += tv_sec * (long) HZ; } - to_jiffies = DIV_ROUND_UP(par_timeout->tv_usec, 1000000/HZ); - to_jiffies += par_timeout->tv_sec * (long) HZ; + if (to_jiffies <= 0) { return -EINVAL; } @@ -677,23 +691,43 @@ static int lp_set_timeout(unsigned int minor, struct timeval *par_timeout) return 0; } +static int lp_set_timeout32(unsigned int minor, void __user *arg) +{ + s32 karg[2]; + + if (copy_from_user(karg, arg, sizeof(karg))) + return -EFAULT; + + return lp_set_timeout(minor, karg[0], karg[1]); +} + +static int lp_set_timeout64(unsigned int minor, void __user *arg) +{ + s64 karg[2]; + + if (copy_from_user(karg, arg, sizeof(karg))) + return -EFAULT; + + return lp_set_timeout(minor, karg[0], karg[1]); +} + static long lp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { unsigned int minor; - struct timeval par_timeout; int ret; minor = iminor(file_inode(file)); mutex_lock(&lp_mutex); switch (cmd) { - case LPSETTIMEOUT: - if (copy_from_user(&par_timeout, (void __user *)arg, - sizeof (struct timeval))) { - ret = -EFAULT; + case LPSETTIMEOUT_OLD: + if (BITS_PER_LONG == 32) { + ret = lp_set_timeout32(minor, (void __user *)arg); break; } - ret = lp_set_timeout(minor, &par_timeout); + /* fallthrough for 64-bit */ + case LPSETTIMEOUT_NEW: + ret = lp_set_timeout64(minor, (void __user *)arg); break; default: ret = lp_do_ioctl(minor, cmd, arg, (void __user *)arg); @@ -709,18 +743,19 @@ static long lp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { unsigned int minor; - struct timeval par_timeout; int ret; minor = iminor(file_inode(file)); mutex_lock(&lp_mutex); switch (cmd) { - case LPSETTIMEOUT: - if (compat_get_timeval(&par_timeout, compat_ptr(arg))) { - ret = -EFAULT; + case LPSETTIMEOUT_OLD: + if (!COMPAT_USE_64BIT_TIME) { + ret = lp_set_timeout32(minor, (void __user *)arg); break; } - ret = lp_set_timeout(minor, &par_timeout); + /* fallthrough for x32 mode */ + case LPSETTIMEOUT_NEW: + ret = lp_set_timeout64(minor, (void __user *)arg); break; #ifdef LP_STATS case LPGETSTATS: @@ -865,7 +900,7 @@ static int __init lp_setup (char *str) printk(KERN_INFO "lp: too many ports, %s ignored.\n", str); } else if (!strcmp(str, "reset")) { - reset = 1; + reset = true; } return 1; } diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 6aefe5370e5b..052011bcf100 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -107,6 +107,8 @@ static ssize_t read_mem(struct file *file, char __user *buf, phys_addr_t p = *ppos; ssize_t read, sz; void *ptr; + char *bounce; + int err; if (p != *ppos) return 0; @@ -129,15 +131,22 @@ static ssize_t read_mem(struct file *file, char __user *buf, } #endif + bounce = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!bounce) + return -ENOMEM; + while (count > 0) { unsigned long remaining; int allowed; sz = size_inside_page(p, count); + err = -EPERM; allowed = page_is_allowed(p >> PAGE_SHIFT); if (!allowed) - return -EPERM; + goto failed; + + err = -EFAULT; if (allowed == 2) { /* Show zeros for restricted memory. */ remaining = clear_user(buf, sz); @@ -149,24 +158,32 @@ static ssize_t read_mem(struct file *file, char __user *buf, */ ptr = xlate_dev_mem_ptr(p); if (!ptr) - return -EFAULT; - - remaining = copy_to_user(buf, ptr, sz); + goto failed; + err = probe_kernel_read(bounce, ptr, sz); unxlate_dev_mem_ptr(p, ptr); + if (err) + goto failed; + + remaining = copy_to_user(buf, bounce, sz); } if (remaining) - return -EFAULT; + goto failed; buf += sz; p += sz; count -= sz; read += sz; } + kfree(bounce); *ppos += read; return read; + +failed: + kfree(bounce); + return err; } static ssize_t write_mem(struct file *file, const char __user *buf, diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 9a1aaf538758..f80965407d3c 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -415,17 +415,17 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf, return count; } -static unsigned int cm4040_poll(struct file *filp, poll_table *wait) +static __poll_t cm4040_poll(struct file *filp, poll_table *wait) { struct reader_dev *dev = filp->private_data; - unsigned int mask = 0; + __poll_t mask = 0; poll_wait(filp, &dev->poll_wait, wait); if (test_and_clear_bit(BS_READABLE, &dev->buffer_status)) - mask |= POLLIN | POLLRDNORM; + mask |= EPOLLIN | EPOLLRDNORM; if (test_and_clear_bit(BS_WRITABLE, &dev->buffer_status)) - mask |= POLLOUT | POLLWRNORM; + mask |= EPOLLOUT | EPOLLWRNORM; DEBUGP(2, dev, "<- cm4040_poll(%u)\n", mask); diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index d256110ba672..1ae77b41050a 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -769,14 +769,14 @@ static int pp_release(struct inode *inode, struct file *file) } /* No kernel lock held - fine */ -static unsigned int pp_poll(struct file *file, poll_table *wait) +static __poll_t pp_poll(struct file *file, poll_table *wait) { struct pp_struct *pp = file->private_data; - unsigned int mask = 0; + __poll_t mask = 0; poll_wait(file, &pp->irq_wait, wait); if (atomic_read(&pp->irqc)) - mask |= POLLIN | POLLRDNORM; + mask |= EPOLLIN | EPOLLRDNORM; return mask; } diff --git a/drivers/char/random.c b/drivers/char/random.c index ec42c8bb9b0d..e5b3d3ba4660 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -431,9 +431,9 @@ static int crng_init = 0; static int crng_init_cnt = 0; #define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE) static void _extract_crng(struct crng_state *crng, - __u8 out[CHACHA20_BLOCK_SIZE]); + __u32 out[CHACHA20_BLOCK_WORDS]); static void _crng_backtrack_protect(struct crng_state *crng, - __u8 tmp[CHACHA20_BLOCK_SIZE], int used); + __u32 tmp[CHACHA20_BLOCK_WORDS], int used); static void process_random_ready_list(void); static void _get_random_bytes(void *buf, int nbytes); @@ -817,7 +817,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r) unsigned long flags; int i, num; union { - __u8 block[CHACHA20_BLOCK_SIZE]; + __u32 block[CHACHA20_BLOCK_WORDS]; __u32 key[8]; } buf; @@ -851,7 +851,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r) } static void _extract_crng(struct crng_state *crng, - __u8 out[CHACHA20_BLOCK_SIZE]) + __u32 out[CHACHA20_BLOCK_WORDS]) { unsigned long v, flags; @@ -867,7 +867,7 @@ static void _extract_crng(struct crng_state *crng, spin_unlock_irqrestore(&crng->lock, flags); } -static void extract_crng(__u8 out[CHACHA20_BLOCK_SIZE]) +static void extract_crng(__u32 out[CHACHA20_BLOCK_WORDS]) { struct crng_state *crng = NULL; @@ -885,7 +885,7 @@ static void extract_crng(__u8 out[CHACHA20_BLOCK_SIZE]) * enough) to mutate the CRNG key to provide backtracking protection. */ static void _crng_backtrack_protect(struct crng_state *crng, - __u8 tmp[CHACHA20_BLOCK_SIZE], int used) + __u32 tmp[CHACHA20_BLOCK_WORDS], int used) { unsigned long flags; __u32 *s, *d; @@ -897,14 +897,14 @@ static void _crng_backtrack_protect(struct crng_state *crng, used = 0; } spin_lock_irqsave(&crng->lock, flags); - s = (__u32 *) &tmp[used]; + s = &tmp[used / sizeof(__u32)]; d = &crng->state[4]; for (i=0; i < 8; i++) *d++ ^= *s++; spin_unlock_irqrestore(&crng->lock, flags); } -static void crng_backtrack_protect(__u8 tmp[CHACHA20_BLOCK_SIZE], int used) +static void crng_backtrack_protect(__u32 tmp[CHACHA20_BLOCK_WORDS], int used) { struct crng_state *crng = NULL; @@ -920,7 +920,7 @@ static void crng_backtrack_protect(__u8 tmp[CHACHA20_BLOCK_SIZE], int used) static ssize_t extract_crng_user(void __user *buf, size_t nbytes) { ssize_t ret = 0, i = CHACHA20_BLOCK_SIZE; - __u8 tmp[CHACHA20_BLOCK_SIZE]; + __u32 tmp[CHACHA20_BLOCK_WORDS]; int large_request = (nbytes > 256); while (nbytes) { @@ -1507,7 +1507,7 @@ static void _warn_unseeded_randomness(const char *func_name, void *caller, */ static void _get_random_bytes(void *buf, int nbytes) { - __u8 tmp[CHACHA20_BLOCK_SIZE]; + __u32 tmp[CHACHA20_BLOCK_WORDS]; trace_get_random_bytes(nbytes, _RET_IP_); @@ -1784,18 +1784,18 @@ urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) return ret; } -static unsigned int +static __poll_t random_poll(struct file *file, poll_table * wait) { - unsigned int mask; + __poll_t mask; poll_wait(file, &random_read_wait, wait); poll_wait(file, &random_write_wait, wait); mask = 0; if (ENTROPY_BITS(&input_pool) >= random_read_wakeup_bits) - mask |= POLLIN | POLLRDNORM; + mask |= EPOLLIN | EPOLLRDNORM; if (ENTROPY_BITS(&input_pool) < random_write_wakeup_bits) - mask |= POLLOUT | POLLWRNORM; + mask |= EPOLLOUT | EPOLLWRNORM; return mask; } @@ -2114,7 +2114,7 @@ u64 get_random_u64(void) if (use_lock) read_lock_irqsave(&batched_entropy_reset_lock, flags); if (batch->position % ARRAY_SIZE(batch->entropy_u64) == 0) { - extract_crng((u8 *)batch->entropy_u64); + extract_crng((__u32 *)batch->entropy_u64); batch->position = 0; } ret = batch->entropy_u64[batch->position++]; @@ -2144,7 +2144,7 @@ u32 get_random_u32(void) if (use_lock) read_lock_irqsave(&batched_entropy_reset_lock, flags); if (batch->position % ARRAY_SIZE(batch->entropy_u32) == 0) { - extract_crng((u8 *)batch->entropy_u32); + extract_crng(batch->entropy_u32); batch->position = 0; } ret = batch->entropy_u32[batch->position++]; diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 5542a438bbd0..0c858d027bf3 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -147,7 +147,7 @@ static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg); static void rtc_get_rtc_time(struct rtc_time *rtc_tm); #ifdef RTC_IRQ -static unsigned int rtc_poll(struct file *file, poll_table *wait); +static __poll_t rtc_poll(struct file *file, poll_table *wait); #endif static void get_rtc_alm_time(struct rtc_time *alm_tm); @@ -790,7 +790,7 @@ no_irq: } #ifdef RTC_IRQ -static unsigned int rtc_poll(struct file *file, poll_table *wait) +static __poll_t rtc_poll(struct file *file, poll_table *wait) { unsigned long l; @@ -804,7 +804,7 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait) spin_unlock_irq(&rtc_lock); if (l != 0) - return POLLIN | POLLRDNORM; + return EPOLLIN | EPOLLRDNORM; return 0; } #endif diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 6aa32679fd58..5918ea7499bb 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -321,10 +321,10 @@ scdrv_write(struct file *file, const char __user *buf, return status; } -static unsigned int +static __poll_t scdrv_poll(struct file *file, struct poll_table_struct *wait) { - unsigned int mask = 0; + __poll_t mask = 0; int status = 0; struct subch_data_s *sd = (struct subch_data_s *) file->private_data; unsigned long flags; @@ -340,10 +340,10 @@ scdrv_poll(struct file *file, struct poll_table_struct *wait) if (status > 0) { if (status & SAL_IROUTER_INTR_RECV) { - mask |= POLLIN | POLLRDNORM; + mask |= EPOLLIN | EPOLLRDNORM; } if (status & SAL_IROUTER_INTR_XMIT) { - mask |= POLLOUT | POLLWRNORM; + mask |= EPOLLOUT | EPOLLWRNORM; } } diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index d3a979e25724..186689833231 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -940,11 +940,11 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf, return ret; } -static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait) +static __poll_t sonypi_misc_poll(struct file *file, poll_table *wait) { poll_wait(file, &sonypi_device.fifo_proc_list, wait); if (kfifo_len(&sonypi_device.fifo)) - return POLLIN | POLLRDNORM; + return EPOLLIN | EPOLLRDNORM; return 0; } diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index a30352202f1f..18c81cbe4704 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -26,6 +26,17 @@ menuconfig TCG_TPM if TCG_TPM +config HW_RANDOM_TPM + bool "TPM HW Random Number Generator support" + depends on TCG_TPM && HW_RANDOM && !(TCG_TPM=y && HW_RANDOM=m) + default y + ---help--- + This setting exposes the TPM's Random Number Generator as a hwrng + device. This allows the kernel to collect randomness from the TPM at + boot, and provides the TPM randomines in /dev/hwrng. + + If unsure, say Y. + config TCG_TIS_CORE tristate ---help--- diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index 34b4bcf46f43..acd758381c58 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -6,8 +6,9 @@ obj-$(CONFIG_TCG_TPM) += tpm.o tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \ tpm-dev-common.o tpmrm-dev.o tpm1_eventlog.o tpm2_eventlog.o \ tpm2-space.o -tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o -tpm-$(CONFIG_OF) += tpm_of.o +tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_eventlog_acpi.o +tpm-$(CONFIG_EFI) += tpm_eventlog_efi.o +tpm-$(CONFIG_OF) += tpm_eventlog_of.o obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o obj-$(CONFIG_TCG_TIS) += tpm_tis.o obj-$(CONFIG_TCG_TIS_SPI) += tpm_tis_spi.o diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 0eca20c5a80c..0a62c19937b6 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -26,8 +26,9 @@ #include #include #include +#include +#include #include "tpm.h" -#include "tpm_eventlog.h" DEFINE_IDR(dev_nums_idr); static DEFINE_MUTEX(idr_lock); @@ -80,21 +81,26 @@ void tpm_put_ops(struct tpm_chip *chip) EXPORT_SYMBOL_GPL(tpm_put_ops); /** - * tpm_chip_find_get() - return tpm_chip for a given chip number - * @chip_num: id to find + * tpm_chip_find_get() - find and reserve a TPM chip + * @chip: a &struct tpm_chip instance, %NULL for the default chip * - * The return'd chip has been tpm_try_get_ops'd and must be released via - * tpm_put_ops + * Finds a TPM chip and reserves its class device and operations. The chip must + * be released with tpm_chip_put_ops() after use. + * + * Return: + * A reserved &struct tpm_chip instance. + * %NULL if a chip is not found. + * %NULL if the chip is not available. */ -struct tpm_chip *tpm_chip_find_get(int chip_num) +struct tpm_chip *tpm_chip_find_get(struct tpm_chip *chip) { - struct tpm_chip *chip, *res = NULL; + struct tpm_chip *res = NULL; + int chip_num = 0; int chip_prev; mutex_lock(&idr_lock); - if (chip_num == TPM_ANY_NUM) { - chip_num = 0; + if (!chip) { do { chip_prev = chip_num; chip = idr_get_next(&dev_nums_idr, &chip_num); @@ -104,8 +110,7 @@ struct tpm_chip *tpm_chip_find_get(int chip_num) } } while (chip_prev != chip_num); } else { - chip = idr_find(&dev_nums_idr, chip_num); - if (chip && !tpm_try_get_ops(chip)) + if (!tpm_try_get_ops(chip)) res = chip; } @@ -387,6 +392,26 @@ static int tpm_add_legacy_sysfs(struct tpm_chip *chip) return 0; } + +static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) +{ + struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng); + + return tpm_get_random(chip, data, max); +} + +static int tpm_add_hwrng(struct tpm_chip *chip) +{ + if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM)) + return 0; + + snprintf(chip->hwrng_name, sizeof(chip->hwrng_name), + "tpm-rng-%d", chip->dev_num); + chip->hwrng.name = chip->hwrng_name; + chip->hwrng.read = tpm_hwrng_read; + return hwrng_register(&chip->hwrng); +} + /* * tpm_chip_register() - create a character device for the TPM chip * @chip: TPM chip to use. @@ -419,11 +444,13 @@ int tpm_chip_register(struct tpm_chip *chip) tpm_add_ppi(chip); + rc = tpm_add_hwrng(chip); + if (rc) + goto out_ppi; + rc = tpm_add_char_device(chip); - if (rc) { - tpm_bios_log_teardown(chip); - return rc; - } + if (rc) + goto out_hwrng; rc = tpm_add_legacy_sysfs(chip); if (rc) { @@ -432,6 +459,14 @@ int tpm_chip_register(struct tpm_chip *chip) } return 0; + +out_hwrng: + if (IS_ENABLED(CONFIG_HW_RANDOM_TPM)) + hwrng_unregister(&chip->hwrng); +out_ppi: + tpm_bios_log_teardown(chip); + + return rc; } EXPORT_SYMBOL_GPL(tpm_chip_register); @@ -451,6 +486,8 @@ EXPORT_SYMBOL_GPL(tpm_chip_register); void tpm_chip_unregister(struct tpm_chip *chip) { tpm_del_legacy_sysfs(chip); + if (IS_ENABLED(CONFIG_HW_RANDOM_TPM)) + hwrng_unregister(&chip->hwrng); tpm_bios_log_teardown(chip); if (chip->flags & TPM_CHIP_FLAG_TPM2) cdev_device_del(&chip->cdevs, &chip->devs); diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 1d6729be4cd6..76df4fbcf089 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -30,9 +30,9 @@ #include #include #include +#include #include "tpm.h" -#include "tpm_eventlog.h" #define TPM_MAX_ORDINAL 243 #define TSC_MAX_ORDINAL 12 @@ -328,7 +328,7 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, } EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); -static bool tpm_validate_command(struct tpm_chip *chip, +static int tpm_validate_command(struct tpm_chip *chip, struct tpm_space *space, const u8 *cmd, size_t len) @@ -340,10 +340,10 @@ static bool tpm_validate_command(struct tpm_chip *chip, unsigned int nr_handles; if (len < TPM_HEADER_SIZE) - return false; + return -EINVAL; if (!space) - return true; + return 0; if (chip->flags & TPM_CHIP_FLAG_TPM2 && chip->nr_commands) { cc = be32_to_cpu(header->ordinal); @@ -352,7 +352,7 @@ static bool tpm_validate_command(struct tpm_chip *chip, if (i < 0) { dev_dbg(&chip->dev, "0x%04X is an invalid command\n", cc); - return false; + return -EOPNOTSUPP; } attrs = chip->cc_attrs_tbl[i]; @@ -362,11 +362,11 @@ static bool tpm_validate_command(struct tpm_chip *chip, goto err_len; } - return true; + return 0; err_len: dev_dbg(&chip->dev, "%s: insufficient command length %zu", __func__, len); - return false; + return -EINVAL; } /** @@ -391,8 +391,20 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, unsigned long stop; bool need_locality; - if (!tpm_validate_command(chip, space, buf, bufsiz)) - return -EINVAL; + rc = tpm_validate_command(chip, space, buf, bufsiz); + if (rc == -EINVAL) + return rc; + /* + * If the command is not implemented by the TPM, synthesize a + * response with a TPM2_RC_COMMAND_CODE return for user-space. + */ + if (rc == -EOPNOTSUPP) { + header->length = cpu_to_be32(sizeof(*header)); + header->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS); + header->return_code = cpu_to_be32(TPM2_RC_COMMAND_CODE | + TSS2_RESMGR_TPM_RC_LAYER); + return bufsiz; + } if (bufsiz > TPM_BUFSIZE) bufsiz = TPM_BUFSIZE; @@ -413,6 +425,9 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, if (chip->dev.parent) pm_runtime_get_sync(chip->dev.parent); + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, true); + /* Store the decision as chip->locality will be changed. */ need_locality = chip->locality == -1; @@ -489,6 +504,9 @@ out: chip->locality = -1; } out_no_locality: + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, false); + if (chip->dev.parent) pm_runtime_put_sync(chip->dev.parent); @@ -809,19 +827,20 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) } /** - * tpm_is_tpm2 - is the chip a TPM2 chip? - * @chip_num: tpm idx # or ANY + * tpm_is_tpm2 - do we a have a TPM2 chip? + * @chip: a &struct tpm_chip instance, %NULL for the default chip * - * Returns < 0 on error, and 1 or 0 on success depending whether the chip - * is a TPM2 chip. + * Return: + * 1 if we have a TPM2 chip. + * 0 if we don't have a TPM2 chip. + * A negative number for system errors (errno). */ -int tpm_is_tpm2(u32 chip_num) +int tpm_is_tpm2(struct tpm_chip *chip) { - struct tpm_chip *chip; int rc; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) + chip = tpm_chip_find_get(chip); + if (!chip) return -ENODEV; rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0; @@ -833,23 +852,19 @@ int tpm_is_tpm2(u32 chip_num) EXPORT_SYMBOL_GPL(tpm_is_tpm2); /** - * tpm_pcr_read - read a pcr value - * @chip_num: tpm idx # or ANY - * @pcr_idx: pcr idx to retrieve - * @res_buf: TPM_PCR value - * size of res_buf is 20 bytes (or NULL if you don't care) + * tpm_pcr_read - read a PCR value from SHA1 bank + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @pcr_idx: the PCR to be retrieved + * @res_buf: the value of the PCR * - * The TPM driver should be built-in, but for whatever reason it - * isn't, protect against the chip disappearing, by incrementing - * the module usage count. + * Return: same as with tpm_transmit_cmd() */ -int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) +int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) { - struct tpm_chip *chip; int rc; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) + chip = tpm_chip_find_get(chip); + if (!chip) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) rc = tpm2_pcr_read(chip, pcr_idx, res_buf); @@ -889,25 +904,26 @@ static int tpm1_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash, } /** - * tpm_pcr_extend - extend pcr value with hash - * @chip_num: tpm idx # or AN& - * @pcr_idx: pcr idx to extend - * @hash: hash value used to extend pcr value + * tpm_pcr_extend - extend a PCR value in SHA1 bank. + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @pcr_idx: the PCR to be retrieved + * @hash: the hash value used to extend the PCR value * - * The TPM driver should be built-in, but for whatever reason it - * isn't, protect against the chip disappearing, by incrementing - * the module usage count. + * Note: with TPM 2.0 extends also those banks with a known digest size to the + * cryto subsystem in order to prevent malicious use of those PCR banks. In the + * future we should dynamically determine digest sizes. + * + * Return: same as with tpm_transmit_cmd() */ -int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) +int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) { int rc; - struct tpm_chip *chip; struct tpm2_digest digest_list[ARRAY_SIZE(chip->active_banks)]; u32 count = 0; int i; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) + chip = tpm_chip_find_get(chip); + if (!chip) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) { @@ -1019,82 +1035,29 @@ out: return rc; } -int tpm_send(u32 chip_num, void *cmd, size_t buflen) +/** + * tpm_send - send a TPM command + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @cmd: a TPM command buffer + * @buflen: the length of the TPM command buffer + * + * Return: same as with tpm_transmit_cmd() + */ +int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) { - struct tpm_chip *chip; int rc; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) + chip = tpm_chip_find_get(chip); + if (!chip) return -ENODEV; rc = tpm_transmit_cmd(chip, NULL, cmd, buflen, 0, 0, - "attempting tpm_cmd"); + "attempting to a send a command"); tpm_put_ops(chip); return rc; } EXPORT_SYMBOL_GPL(tpm_send); -static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, - bool check_cancel, bool *canceled) -{ - u8 status = chip->ops->status(chip); - - *canceled = false; - if ((status & mask) == mask) - return true; - if (check_cancel && chip->ops->req_canceled(chip, status)) { - *canceled = true; - return true; - } - return false; -} - -int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, - wait_queue_head_t *queue, bool check_cancel) -{ - unsigned long stop; - long rc; - u8 status; - bool canceled = false; - - /* check current status */ - status = chip->ops->status(chip); - if ((status & mask) == mask) - return 0; - - stop = jiffies + timeout; - - if (chip->flags & TPM_CHIP_FLAG_IRQ) { -again: - timeout = stop - jiffies; - if ((long)timeout <= 0) - return -ETIME; - rc = wait_event_interruptible_timeout(*queue, - wait_for_tpm_stat_cond(chip, mask, check_cancel, - &canceled), - timeout); - if (rc > 0) { - if (canceled) - return -ECANCELED; - return 0; - } - if (rc == -ERESTARTSYS && freezing(current)) { - clear_thread_flag(TIF_SIGPENDING); - goto again; - } - } else { - do { - tpm_msleep(TPM_TIMEOUT); - status = chip->ops->status(chip); - if ((status & mask) == mask) - return 0; - } while (time_before(jiffies, stop)); - } - return -ETIME; -} -EXPORT_SYMBOL_GPL(wait_for_tpm_stat); - #define TPM_ORD_SAVESTATE 152 #define SAVESTATE_RESULT_SIZE 10 @@ -1187,16 +1150,15 @@ static const struct tpm_input_header tpm_getrandom_header = { }; /** - * tpm_get_random() - Get random bytes from the tpm's RNG - * @chip_num: A specific chip number for the request or TPM_ANY_NUM - * @out: destination buffer for the random bytes - * @max: the max number of bytes to write to @out + * tpm_get_random() - get random bytes from the TPM's RNG + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @out: destination buffer for the random bytes + * @max: the max number of bytes to write to @out * - * Returns < 0 on error and the number of bytes read on success + * Return: same as with tpm_transmit_cmd() */ -int tpm_get_random(u32 chip_num, u8 *out, size_t max) +int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) { - struct tpm_chip *chip; struct tpm_cmd_t tpm_cmd; u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA), rlength; int err, total = 0, retries = 5; @@ -1205,8 +1167,8 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) return -EINVAL; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) + chip = tpm_chip_find_get(chip); + if (!chip) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) { @@ -1248,22 +1210,23 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) EXPORT_SYMBOL_GPL(tpm_get_random); /** - * tpm_seal_trusted() - seal a trusted key - * @chip_num: A specific chip number for the request or TPM_ANY_NUM - * @options: authentication values and other options - * @payload: the key data in clear and encrypted form + * tpm_seal_trusted() - seal a trusted key payload + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @options: authentication values and other options + * @payload: the key data in clear and encrypted form * - * Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips - * are supported. + * Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in + * the keyring subsystem. + * + * Return: same as with tpm_transmit_cmd() */ -int tpm_seal_trusted(u32 chip_num, struct trusted_key_payload *payload, +int tpm_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, struct trusted_key_options *options) { - struct tpm_chip *chip; int rc; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2)) + chip = tpm_chip_find_get(chip); + if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2)) return -ENODEV; rc = tpm2_seal_trusted(chip, payload, options); @@ -1275,21 +1238,23 @@ EXPORT_SYMBOL_GPL(tpm_seal_trusted); /** * tpm_unseal_trusted() - unseal a trusted key - * @chip_num: A specific chip number for the request or TPM_ANY_NUM - * @options: authentication values and other options - * @payload: the key data in clear and encrypted form + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @options: authentication values and other options + * @payload: the key data in clear and encrypted form * - * Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips - * are supported. + * Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in + * the keyring subsystem. + * + * Return: same as with tpm_transmit_cmd() */ -int tpm_unseal_trusted(u32 chip_num, struct trusted_key_payload *payload, +int tpm_unseal_trusted(struct tpm_chip *chip, + struct trusted_key_payload *payload, struct trusted_key_options *options) { - struct tpm_chip *chip; int rc; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2)) + chip = tpm_chip_find_get(chip); + if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2)) return -ENODEV; rc = tpm2_unseal_trusted(chip, payload, options); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 528cffbd49d3..f895fba4e20d 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,7 @@ #include #include #include +#include #include #ifdef CONFIG_X86 @@ -93,12 +95,17 @@ enum tpm2_structures { TPM2_ST_SESSIONS = 0x8002, }; +/* Indicates from what layer of the software stack the error comes from */ +#define TSS2_RC_LAYER_SHIFT 16 +#define TSS2_RESMGR_TPM_RC_LAYER (11 << TSS2_RC_LAYER_SHIFT) + enum tpm2_return_codes { TPM2_RC_SUCCESS = 0x0000, TPM2_RC_HASH = 0x0083, /* RC_FMT1 */ TPM2_RC_HANDLE = 0x008B, TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */ TPM2_RC_DISABLED = 0x0120, + TPM2_RC_COMMAND_CODE = 0x0143, TPM2_RC_TESTING = 0x090A, /* RC_WARN */ TPM2_RC_REFERENCE_H0 = 0x0910, }; @@ -210,6 +217,9 @@ struct tpm_chip { int dev_num; /* /dev/tpm# */ unsigned long is_open; /* only one allowed */ + char hwrng_name[64]; + struct hwrng hwrng; + struct mutex tpm_mutex; /* tpm is processing */ unsigned long timeout_a; /* jiffies */ @@ -385,10 +395,6 @@ struct tpm_cmd_t { tpm_cmd_params params; } __packed; -struct tpm2_digest { - u16 alg_id; - u8 digest[SHA512_DIGEST_SIZE]; -} __packed; /* A string buffer type for constructing TPM commands. This is based on the * ideas of string buffer code in security/keys/trusted.h but is heap based @@ -512,16 +518,14 @@ int tpm_do_selftest(struct tpm_chip *chip); unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal); int tpm_pm_suspend(struct device *dev); int tpm_pm_resume(struct device *dev); -int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, - wait_queue_head_t *queue, bool check_cancel); static inline void tpm_msleep(unsigned int delay_msec) { - usleep_range(delay_msec * 1000, - (delay_msec * 1000) + TPM_TIMEOUT_RANGE_US); + usleep_range((delay_msec * 1000) - TPM_TIMEOUT_RANGE_US, + delay_msec * 1000); }; -struct tpm_chip *tpm_chip_find_get(int chip_num); +struct tpm_chip *tpm_chip_find_get(struct tpm_chip *chip); __must_check int tpm_try_get_ops(struct tpm_chip *chip); void tpm_put_ops(struct tpm_chip *chip); @@ -575,4 +579,34 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc, u8 *cmd); int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc, u8 *buf, size_t *bufsiz); + +extern const struct seq_operations tpm2_binary_b_measurements_seqops; + +#if defined(CONFIG_ACPI) +int tpm_read_log_acpi(struct tpm_chip *chip); +#else +static inline int tpm_read_log_acpi(struct tpm_chip *chip) +{ + return -ENODEV; +} +#endif +#if defined(CONFIG_OF) +int tpm_read_log_of(struct tpm_chip *chip); +#else +static inline int tpm_read_log_of(struct tpm_chip *chip) +{ + return -ENODEV; +} +#endif +#if defined(CONFIG_EFI) +int tpm_read_log_efi(struct tpm_chip *chip); +#else +static inline int tpm_read_log_efi(struct tpm_chip *chip) +{ + return -ENODEV; +} +#endif + +int tpm_bios_log_setup(struct tpm_chip *chip); +void tpm_bios_log_teardown(struct tpm_chip *chip); #endif diff --git a/drivers/char/tpm/tpm1_eventlog.c b/drivers/char/tpm/tpm1_eventlog.c index 9a8605e500b5..add798bd69d0 100644 --- a/drivers/char/tpm/tpm1_eventlog.c +++ b/drivers/char/tpm/tpm1_eventlog.c @@ -21,13 +21,14 @@ */ #include +#include #include #include #include #include +#include #include "tpm.h" -#include "tpm_eventlog.h" static const char* tcpa_event_type_strings[] = { @@ -371,6 +372,10 @@ static int tpm_read_log(struct tpm_chip *chip) if (rc != -ENODEV) return rc; + rc = tpm_read_log_efi(chip); + if (rc != -ENODEV) + return rc; + return tpm_read_log_of(chip); } @@ -388,11 +393,13 @@ int tpm_bios_log_setup(struct tpm_chip *chip) { const char *name = dev_name(&chip->dev); unsigned int cnt; + int log_version; int rc = 0; rc = tpm_read_log(chip); - if (rc) + if (rc < 0) return rc; + log_version = rc; cnt = 0; chip->bios_dir[cnt] = securityfs_create_dir(name, NULL); @@ -404,7 +411,7 @@ int tpm_bios_log_setup(struct tpm_chip *chip) cnt++; chip->bin_log_seqops.chip = chip; - if (chip->flags & TPM_CHIP_FLAG_TPM2) + if (log_version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) chip->bin_log_seqops.seqops = &tpm2_binary_b_measurements_seqops; else diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index f40d20671a78..c17e75348a99 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -849,28 +849,26 @@ static const struct tpm_input_header tpm2_selftest_header = { static int tpm2_do_selftest(struct tpm_chip *chip) { int rc; - unsigned int delay_msec = 20; + unsigned int delay_msec = 10; long duration; struct tpm2_cmd cmd; duration = jiffies_to_msecs( tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST)); - while (duration > 0) { + while (1) { cmd.header.in = tpm2_selftest_header; cmd.params.selftest_in.full_test = 0; rc = tpm_transmit_cmd(chip, NULL, &cmd, TPM2_SELF_TEST_IN_SIZE, 0, 0, "continue selftest"); - if (rc != TPM2_RC_TESTING) + if (rc != TPM2_RC_TESTING || delay_msec >= duration) break; - tpm_msleep(delay_msec); - duration -= delay_msec; - - /* wait longer the next round */ + /* wait longer than before */ delay_msec *= 2; + tpm_msleep(delay_msec); } return rc; diff --git a/drivers/char/tpm/tpm2_eventlog.c b/drivers/char/tpm/tpm2_eventlog.c index 34a8afa69138..1ce4411292ba 100644 --- a/drivers/char/tpm/tpm2_eventlog.c +++ b/drivers/char/tpm/tpm2_eventlog.c @@ -21,9 +21,9 @@ #include #include #include +#include #include "tpm.h" -#include "tpm_eventlog.h" /* * calc_tpm2_event_size() - calculate the event size, where event diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_eventlog_acpi.c similarity index 97% rename from drivers/char/tpm/tpm_acpi.c rename to drivers/char/tpm/tpm_eventlog_acpi.c index 169edf3ce86d..66f19e93c216 100644 --- a/drivers/char/tpm/tpm_acpi.c +++ b/drivers/char/tpm/tpm_eventlog_acpi.c @@ -25,9 +25,9 @@ #include #include #include +#include #include "tpm.h" -#include "tpm_eventlog.h" struct acpi_tcpa { struct acpi_table_header hdr; @@ -102,7 +102,7 @@ int tpm_read_log_acpi(struct tpm_chip *chip) memcpy_fromio(log->bios_event_log, virt, len); acpi_os_unmap_iomem(virt, len); - return 0; + return EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; err: kfree(log->bios_event_log); diff --git a/drivers/char/tpm/tpm_eventlog_efi.c b/drivers/char/tpm/tpm_eventlog_efi.c new file mode 100644 index 000000000000..e3f9ffd341d2 --- /dev/null +++ b/drivers/char/tpm/tpm_eventlog_efi.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2017 Google + * + * Authors: + * Thiebaud Weksteen + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include + +#include "tpm.h" + +/* read binary bios log from EFI configuration table */ +int tpm_read_log_efi(struct tpm_chip *chip) +{ + + struct linux_efi_tpm_eventlog *log_tbl; + struct tpm_bios_log *log; + u32 log_size; + u8 tpm_log_version; + + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) + return -ENODEV; + + if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) + return -ENODEV; + + log = &chip->log; + + log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl), MEMREMAP_WB); + if (!log_tbl) { + pr_err("Could not map UEFI TPM log table !\n"); + return -ENOMEM; + } + + log_size = log_tbl->size; + memunmap(log_tbl); + + log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl) + log_size, + MEMREMAP_WB); + if (!log_tbl) { + pr_err("Could not map UEFI TPM log table payload!\n"); + return -ENOMEM; + } + + /* malloc EventLog space */ + log->bios_event_log = kmalloc(log_size, GFP_KERNEL); + if (!log->bios_event_log) + goto err_memunmap; + memcpy(log->bios_event_log, log_tbl->log, log_size); + log->bios_event_log_end = log->bios_event_log + log_size; + + tpm_log_version = log_tbl->version; + memunmap(log_tbl); + return tpm_log_version; + +err_memunmap: + memunmap(log_tbl); + return -ENOMEM; +} diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_eventlog_of.c similarity index 93% rename from drivers/char/tpm/tpm_of.c rename to drivers/char/tpm/tpm_eventlog_of.c index aadb7f464076..96fd5646f866 100644 --- a/drivers/char/tpm/tpm_of.c +++ b/drivers/char/tpm/tpm_eventlog_of.c @@ -17,9 +17,9 @@ #include #include +#include #include "tpm.h" -#include "tpm_eventlog.h" int tpm_read_log_of(struct tpm_chip *chip) { @@ -76,5 +76,7 @@ int tpm_read_log_of(struct tpm_chip *chip) memcpy(log->bios_event_log, __va(base), size); - return 0; + if (chip->flags & TPM_CHIP_FLAG_TPM2) + return EFI_TCG2_EVENT_LOG_FORMAT_TCG_2; + return EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; } diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index 79d6bbb58e39..c1dd39eaaeeb 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -665,9 +665,9 @@ out_err: } static const struct i2c_device_id tpm_tis_i2c_table[] = { - {"tpm_i2c_infineon", 0}, - {"slb9635tt", 0}, - {"slb9645tt", 1}, + {"tpm_i2c_infineon"}, + {"slb9635tt"}, + {"slb9645tt"}, {}, }; @@ -675,24 +675,9 @@ MODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_table); #ifdef CONFIG_OF static const struct of_device_id tpm_tis_i2c_of_match[] = { - { - .name = "tpm_i2c_infineon", - .type = "tpm", - .compatible = "infineon,tpm_i2c_infineon", - .data = (void *)0 - }, - { - .name = "slb9635tt", - .type = "tpm", - .compatible = "infineon,slb9635tt", - .data = (void *)0 - }, - { - .name = "slb9645tt", - .type = "tpm", - .compatible = "infineon,slb9645tt", - .data = (void *)1 - }, + {.compatible = "infineon,tpm_i2c_infineon"}, + {.compatible = "infineon,slb9635tt"}, + {.compatible = "infineon,slb9645tt"}, {}, }; MODULE_DEVICE_TABLE(of, tpm_tis_i2c_of_match); diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index e2d1055fb814..f08949a5f678 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -133,93 +133,14 @@ static int check_acpi_tpm2(struct device *dev) } #endif -#ifdef CONFIG_X86 -#define INTEL_LEGACY_BLK_BASE_ADDR 0xFED08000 -#define ILB_REMAP_SIZE 0x100 -#define LPC_CNTRL_REG_OFFSET 0x84 -#define LPC_CLKRUN_EN (1 << 2) - -static void __iomem *ilb_base_addr; - -static inline bool is_bsw(void) -{ - return ((boot_cpu_data.x86_model == INTEL_FAM6_ATOM_AIRMONT) ? 1 : 0); -} - -/** - * tpm_platform_begin_xfer() - clear LPC CLKRUN_EN i.e. clocks will be running - */ -static void tpm_platform_begin_xfer(void) -{ - u32 clkrun_val; - - if (!is_bsw()) - return; - - clkrun_val = ioread32(ilb_base_addr + LPC_CNTRL_REG_OFFSET); - - /* Disable LPC CLKRUN# */ - clkrun_val &= ~LPC_CLKRUN_EN; - iowrite32(clkrun_val, ilb_base_addr + LPC_CNTRL_REG_OFFSET); - - /* - * Write any random value on port 0x80 which is on LPC, to make - * sure LPC clock is running before sending any TPM command. - */ - outb(0xCC, 0x80); - -} - -/** - * tpm_platform_end_xfer() - set LPC CLKRUN_EN i.e. clocks can be turned off - */ -static void tpm_platform_end_xfer(void) -{ - u32 clkrun_val; - - if (!is_bsw()) - return; - - clkrun_val = ioread32(ilb_base_addr + LPC_CNTRL_REG_OFFSET); - - /* Enable LPC CLKRUN# */ - clkrun_val |= LPC_CLKRUN_EN; - iowrite32(clkrun_val, ilb_base_addr + LPC_CNTRL_REG_OFFSET); - - /* - * Write any random value on port 0x80 which is on LPC, to make - * sure LPC clock is running before sending any TPM command. - */ - outb(0xCC, 0x80); - -} -#else -static inline bool is_bsw(void) -{ - return false; -} - -static void tpm_platform_begin_xfer(void) -{ -} - -static void tpm_platform_end_xfer(void) -{ -} -#endif - static int tpm_tcg_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len, u8 *result) { struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); - tpm_platform_begin_xfer(); - while (len--) *result++ = ioread8(phy->iobase + addr); - tpm_platform_end_xfer(); - return 0; } @@ -228,13 +149,9 @@ static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len, { struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); - tpm_platform_begin_xfer(); - while (len--) iowrite8(*value++, phy->iobase + addr); - tpm_platform_end_xfer(); - return 0; } @@ -242,12 +159,8 @@ static int tpm_tcg_read16(struct tpm_tis_data *data, u32 addr, u16 *result) { struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); - tpm_platform_begin_xfer(); - *result = ioread16(phy->iobase + addr); - tpm_platform_end_xfer(); - return 0; } @@ -255,12 +168,8 @@ static int tpm_tcg_read32(struct tpm_tis_data *data, u32 addr, u32 *result) { struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); - tpm_platform_begin_xfer(); - *result = ioread32(phy->iobase + addr); - tpm_platform_end_xfer(); - return 0; } @@ -268,12 +177,8 @@ static int tpm_tcg_write32(struct tpm_tis_data *data, u32 addr, u32 value) { struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); - tpm_platform_begin_xfer(); - iowrite32(value, phy->iobase + addr); - tpm_platform_end_xfer(); - return 0; } @@ -461,11 +366,6 @@ static int __init init_tis(void) if (rc) goto err_force; -#ifdef CONFIG_X86 - if (is_bsw()) - ilb_base_addr = ioremap(INTEL_LEGACY_BLK_BASE_ADDR, - ILB_REMAP_SIZE); -#endif rc = platform_driver_register(&tis_drv); if (rc) goto err_platform; @@ -484,10 +384,6 @@ err_pnp: err_platform: if (force_pdev) platform_device_unregister(force_pdev); -#ifdef CONFIG_X86 - if (is_bsw()) - iounmap(ilb_base_addr); -#endif err_force: return rc; } @@ -497,10 +393,6 @@ static void __exit cleanup_tis(void) pnp_unregister_driver(&tis_pnp_driver); platform_driver_unregister(&tis_drv); -#ifdef CONFIG_X86 - if (is_bsw()) - iounmap(ilb_base_addr); -#endif if (force_pdev) platform_device_unregister(force_pdev); } diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index fdde971bc810..183a5f54d875 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -31,6 +31,74 @@ #include "tpm.h" #include "tpm_tis_core.h" +/* This is a polling delay to check for status and burstcount. + * As per ddwg input, expectation is that status check and burstcount + * check should return within few usecs. + */ +#define TPM_POLL_SLEEP 1 /* msec */ + +static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value); + +static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, + bool check_cancel, bool *canceled) +{ + u8 status = chip->ops->status(chip); + + *canceled = false; + if ((status & mask) == mask) + return true; + if (check_cancel && chip->ops->req_canceled(chip, status)) { + *canceled = true; + return true; + } + return false; +} + +static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, + unsigned long timeout, wait_queue_head_t *queue, + bool check_cancel) +{ + unsigned long stop; + long rc; + u8 status; + bool canceled = false; + + /* check current status */ + status = chip->ops->status(chip); + if ((status & mask) == mask) + return 0; + + stop = jiffies + timeout; + + if (chip->flags & TPM_CHIP_FLAG_IRQ) { +again: + timeout = stop - jiffies; + if ((long)timeout <= 0) + return -ETIME; + rc = wait_event_interruptible_timeout(*queue, + wait_for_tpm_stat_cond(chip, mask, check_cancel, + &canceled), + timeout); + if (rc > 0) { + if (canceled) + return -ECANCELED; + return 0; + } + if (rc == -ERESTARTSYS && freezing(current)) { + clear_thread_flag(TIF_SIGPENDING); + goto again; + } + } else { + do { + tpm_msleep(TPM_POLL_SLEEP); + status = chip->ops->status(chip); + if ((status & mask) == mask) + return 0; + } while (time_before(jiffies, stop)); + } + return -ETIME; +} + /* Before we attempt to access the TPM we must see that the valid bit is set. * The specification says that this bit is 0 at reset and remains 0 until the * 'TPM has gone through its self test and initialization and has established @@ -164,7 +232,7 @@ static int get_burstcount(struct tpm_chip *chip) burstcnt = (value >> 8) & 0xFFFF; if (burstcnt) return burstcnt; - tpm_msleep(TPM_TIMEOUT); + tpm_msleep(TPM_POLL_SLEEP); } while (time_before(jiffies, stop)); return -EBUSY; } @@ -421,19 +489,28 @@ static bool tpm_tis_update_timeouts(struct tpm_chip *chip, int i, rc; u32 did_vid; + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, true); + rc = tpm_tis_read32(priv, TPM_DID_VID(0), &did_vid); if (rc < 0) - return rc; + goto out; for (i = 0; i != ARRAY_SIZE(vendor_timeout_overrides); i++) { if (vendor_timeout_overrides[i].did_vid != did_vid) continue; memcpy(timeout_cap, vendor_timeout_overrides[i].timeout_us, sizeof(vendor_timeout_overrides[i].timeout_us)); - return true; + rc = true; } - return false; + rc = false; + +out: + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, false); + + return rc; } /* @@ -653,14 +730,73 @@ void tpm_tis_remove(struct tpm_chip *chip) u32 interrupt; int rc; + tpm_tis_clkrun_enable(chip, true); + rc = tpm_tis_read32(priv, reg, &interrupt); if (rc < 0) interrupt = 0; tpm_tis_write32(priv, reg, ~TPM_GLOBAL_INT_ENABLE & interrupt); + + tpm_tis_clkrun_enable(chip, false); + + if (priv->ilb_base_addr) + iounmap(priv->ilb_base_addr); } EXPORT_SYMBOL_GPL(tpm_tis_remove); +/** + * tpm_tis_clkrun_enable() - Keep clkrun protocol disabled for entire duration + * of a single TPM command + * @chip: TPM chip to use + * @value: 1 - Disable CLKRUN protocol, so that clocks are free running + * 0 - Enable CLKRUN protocol + * Call this function directly in tpm_tis_remove() in error or driver removal + * path, since the chip->ops is set to NULL in tpm_chip_unregister(). + */ +static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value) +{ + struct tpm_tis_data *data = dev_get_drvdata(&chip->dev); + u32 clkrun_val; + + if (!IS_ENABLED(CONFIG_X86) || !is_bsw() || + !data->ilb_base_addr) + return; + + if (value) { + data->clkrun_enabled++; + if (data->clkrun_enabled > 1) + return; + clkrun_val = ioread32(data->ilb_base_addr + LPC_CNTRL_OFFSET); + + /* Disable LPC CLKRUN# */ + clkrun_val &= ~LPC_CLKRUN_EN; + iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET); + + /* + * Write any random value on port 0x80 which is on LPC, to make + * sure LPC clock is running before sending any TPM command. + */ + outb(0xCC, 0x80); + } else { + data->clkrun_enabled--; + if (data->clkrun_enabled) + return; + + clkrun_val = ioread32(data->ilb_base_addr + LPC_CNTRL_OFFSET); + + /* Enable LPC CLKRUN# */ + clkrun_val |= LPC_CLKRUN_EN; + iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET); + + /* + * Write any random value on port 0x80 which is on LPC, to make + * sure LPC clock is running before sending any TPM command. + */ + outb(0xCC, 0x80); + } +} + static const struct tpm_class_ops tpm_tis = { .flags = TPM_OPS_AUTO_STARTUP, .status = tpm_tis_status, @@ -673,13 +809,17 @@ static const struct tpm_class_ops tpm_tis = { .req_canceled = tpm_tis_req_canceled, .request_locality = request_locality, .relinquish_locality = release_locality, + .clk_enable = tpm_tis_clkrun_enable, }; int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, const struct tpm_tis_phy_ops *phy_ops, acpi_handle acpi_dev_handle) { - u32 vendor, intfcaps, intmask; + u32 vendor; + u32 intfcaps; + u32 intmask; + u32 clkrun_val; u8 rid; int rc, probe; struct tpm_chip *chip; @@ -700,6 +840,23 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, priv->phy_ops = phy_ops; dev_set_drvdata(&chip->dev, priv); + if (is_bsw()) { + priv->ilb_base_addr = ioremap(INTEL_LEGACY_BLK_BASE_ADDR, + ILB_REMAP_SIZE); + if (!priv->ilb_base_addr) + return -ENOMEM; + + clkrun_val = ioread32(priv->ilb_base_addr + LPC_CNTRL_OFFSET); + /* Check if CLKRUN# is already not enabled in the LPC bus */ + if (!(clkrun_val & LPC_CLKRUN_EN)) { + iounmap(priv->ilb_base_addr); + priv->ilb_base_addr = NULL; + } + } + + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, true); + if (wait_startup(chip, 0) != 0) { rc = -ENODEV; goto out_err; @@ -790,9 +947,20 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, } } - return tpm_chip_register(chip); + rc = tpm_chip_register(chip); + if (rc) + goto out_err; + + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, false); + + return 0; out_err: + if ((chip->ops != NULL) && (chip->ops->clk_enable != NULL)) + chip->ops->clk_enable(chip, false); + tpm_tis_remove(chip); + return rc; } EXPORT_SYMBOL_GPL(tpm_tis_core_init); @@ -804,22 +972,31 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) u32 intmask; int rc; + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, true); + /* reenable interrupts that device may have lost or * BIOS/firmware may have disabled */ rc = tpm_tis_write8(priv, TPM_INT_VECTOR(priv->locality), priv->irq); if (rc < 0) - return; + goto out; rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask); if (rc < 0) - return; + goto out; intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT | TPM_GLOBAL_INT_ENABLE; tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask); + +out: + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, false); + + return; } int tpm_tis_resume(struct device *dev) diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h index 6bbac319ff3b..d5c6a2e952b3 100644 --- a/drivers/char/tpm/tpm_tis_core.h +++ b/drivers/char/tpm/tpm_tis_core.h @@ -79,6 +79,11 @@ enum tis_defaults { #define TPM_DID_VID(l) (0x0F00 | ((l) << 12)) #define TPM_RID(l) (0x0F04 | ((l) << 12)) +#define LPC_CNTRL_OFFSET 0x84 +#define LPC_CLKRUN_EN (1 << 2) +#define INTEL_LEGACY_BLK_BASE_ADDR 0xFED08000 +#define ILB_REMAP_SIZE 0x100 + enum tpm_tis_flags { TPM_TIS_ITPM_WORKAROUND = BIT(0), }; @@ -89,6 +94,8 @@ struct tpm_tis_data { int irq; bool irq_tested; unsigned int flags; + void __iomem *ilb_base_addr; + u16 clkrun_enabled; wait_queue_head_t int_queue; wait_queue_head_t read_queue; const struct tpm_tis_phy_ops *phy_ops; @@ -144,6 +151,15 @@ static inline int tpm_tis_write32(struct tpm_tis_data *data, u32 addr, return data->phy_ops->write32(data, addr, value); } +static inline bool is_bsw(void) +{ +#ifdef CONFIG_X86 + return ((boot_cpu_data.x86_model == INTEL_FAM6_ATOM_AIRMONT) ? 1 : 0); +#else + return false; +#endif +} + void tpm_tis_remove(struct tpm_chip *chip); int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, const struct tpm_tis_phy_ops *phy_ops, diff --git a/drivers/char/tpm/tpm_vtpm_proxy.c b/drivers/char/tpm/tpm_vtpm_proxy.c index 1d877cc9af97..e4f79f920450 100644 --- a/drivers/char/tpm/tpm_vtpm_proxy.c +++ b/drivers/char/tpm/tpm_vtpm_proxy.c @@ -173,22 +173,22 @@ static ssize_t vtpm_proxy_fops_write(struct file *filp, const char __user *buf, * * Return: Poll flags */ -static unsigned int vtpm_proxy_fops_poll(struct file *filp, poll_table *wait) +static __poll_t vtpm_proxy_fops_poll(struct file *filp, poll_table *wait) { struct proxy_dev *proxy_dev = filp->private_data; - unsigned ret; + __poll_t ret; poll_wait(filp, &proxy_dev->wq, wait); - ret = POLLOUT; + ret = EPOLLOUT; mutex_lock(&proxy_dev->buf_lock); if (proxy_dev->req_len) - ret |= POLLIN | POLLRDNORM; + ret |= EPOLLIN | EPOLLRDNORM; if (!(proxy_dev->state & STATE_OPENED_FLAG)) - ret |= POLLHUP; + ret |= EPOLLHUP; mutex_unlock(&proxy_dev->buf_lock); diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c index 656e8af95d52..911475d36800 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,66 @@ enum status_bits { VTPM_STATUS_CANCELED = 0x8, }; +static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, + bool check_cancel, bool *canceled) +{ + u8 status = chip->ops->status(chip); + + *canceled = false; + if ((status & mask) == mask) + return true; + if (check_cancel && chip->ops->req_canceled(chip, status)) { + *canceled = true; + return true; + } + return false; +} + +static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, + unsigned long timeout, wait_queue_head_t *queue, + bool check_cancel) +{ + unsigned long stop; + long rc; + u8 status; + bool canceled = false; + + /* check current status */ + status = chip->ops->status(chip); + if ((status & mask) == mask) + return 0; + + stop = jiffies + timeout; + + if (chip->flags & TPM_CHIP_FLAG_IRQ) { +again: + timeout = stop - jiffies; + if ((long)timeout <= 0) + return -ETIME; + rc = wait_event_interruptible_timeout(*queue, + wait_for_tpm_stat_cond(chip, mask, check_cancel, + &canceled), + timeout); + if (rc > 0) { + if (canceled) + return -ECANCELED; + return 0; + } + if (rc == -ERESTARTSYS && freezing(current)) { + clear_thread_flag(TIF_SIGPENDING); + goto again; + } + } else { + do { + tpm_msleep(TPM_TIMEOUT); + status = chip->ops->status(chip); + if ((status & mask) == mask) + return 0; + } while (time_before(jiffies, stop)); + } + return -ETIME; +} + static u8 vtpm_status(struct tpm_chip *chip) { struct tpm_private *priv = dev_get_drvdata(&chip->dev); diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index d1aed2513bd9..468f06134012 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -982,25 +982,25 @@ error_out: return ret; } -static unsigned int port_fops_poll(struct file *filp, poll_table *wait) +static __poll_t port_fops_poll(struct file *filp, poll_table *wait) { struct port *port; - unsigned int ret; + __poll_t ret; port = filp->private_data; poll_wait(filp, &port->waitqueue, wait); if (!port->guest_connected) { /* Port got unplugged */ - return POLLHUP; + return EPOLLHUP; } ret = 0; if (!will_read_block(port)) - ret |= POLLIN | POLLRDNORM; + ret |= EPOLLIN | EPOLLRDNORM; if (!will_write_block(port)) - ret |= POLLOUT; + ret |= EPOLLOUT; if (!port->host_connected) - ret |= POLLHUP; + ret |= EPOLLHUP; return ret; } diff --git a/drivers/char/xillybus/Kconfig b/drivers/char/xillybus/Kconfig index b302684d86c1..a1f16df08d32 100644 --- a/drivers/char/xillybus/Kconfig +++ b/drivers/char/xillybus/Kconfig @@ -4,7 +4,7 @@ config XILLYBUS tristate "Xillybus generic FPGA interface" - depends on PCI || (OF_ADDRESS && OF_IRQ) + depends on PCI || OF select CRC32 help Xillybus is a generic interface for peripherals designed on @@ -24,7 +24,7 @@ config XILLYBUS_PCIE config XILLYBUS_OF tristate "Xillybus over Device Tree" - depends on OF_ADDRESS && OF_IRQ && HAS_DMA + depends on OF && HAS_DMA help Set to M if you want Xillybus to find its resources from the Open Firmware Flattened Device Tree. If the target is an embedded diff --git a/drivers/char/xillybus/xillybus_core.c b/drivers/char/xillybus/xillybus_core.c index b6c9cdead7f3..a11af94e2e65 100644 --- a/drivers/char/xillybus/xillybus_core.c +++ b/drivers/char/xillybus/xillybus_core.c @@ -1736,10 +1736,10 @@ end: return pos; } -static unsigned int xillybus_poll(struct file *filp, poll_table *wait) +static __poll_t xillybus_poll(struct file *filp, poll_table *wait) { struct xilly_channel *channel = filp->private_data; - unsigned int mask = 0; + __poll_t mask = 0; unsigned long flags; poll_wait(filp, &channel->endpoint->ep_wait, wait); @@ -1758,15 +1758,15 @@ static unsigned int xillybus_poll(struct file *filp, poll_table *wait) spin_lock_irqsave(&channel->wr_spinlock, flags); if (!channel->wr_empty || channel->wr_ready) - mask |= POLLIN | POLLRDNORM; + mask |= EPOLLIN | EPOLLRDNORM; if (channel->wr_hangup) /* - * Not POLLHUP, because its behavior is in the - * mist, and POLLIN does what we want: Wake up + * Not EPOLLHUP, because its behavior is in the + * mist, and EPOLLIN does what we want: Wake up * the read file descriptor so it sees EOF. */ - mask |= POLLIN | POLLRDNORM; + mask |= EPOLLIN | EPOLLRDNORM; spin_unlock_irqrestore(&channel->wr_spinlock, flags); } @@ -1781,12 +1781,12 @@ static unsigned int xillybus_poll(struct file *filp, poll_table *wait) spin_lock_irqsave(&channel->rd_spinlock, flags); if (!channel->rd_full) - mask |= POLLOUT | POLLWRNORM; + mask |= EPOLLOUT | EPOLLWRNORM; spin_unlock_irqrestore(&channel->rd_spinlock, flags); } if (channel->endpoint->fatal_error) - mask |= POLLERR; + mask |= EPOLLERR; return mask; } diff --git a/drivers/char/xillybus/xillybus_of.c b/drivers/char/xillybus/xillybus_of.c index 78a492f5acfb..4d6625ccb48f 100644 --- a/drivers/char/xillybus/xillybus_of.c +++ b/drivers/char/xillybus/xillybus_of.c @@ -15,10 +15,6 @@ #include #include #include -#include -#include -#include -#include #include #include "xillybus.h" @@ -123,7 +119,7 @@ static int xilly_drv_probe(struct platform_device *op) struct xilly_endpoint *endpoint; int rc; int irq; - struct resource res; + struct resource *res; struct xilly_endpoint_hardware *ephw = &of_hw; if (of_property_read_bool(dev->of_node, "dma-coherent")) @@ -136,13 +132,13 @@ static int xilly_drv_probe(struct platform_device *op) dev_set_drvdata(dev, endpoint); - rc = of_address_to_resource(dev->of_node, 0, &res); - endpoint->registers = devm_ioremap_resource(dev, &res); + res = platform_get_resource(op, IORESOURCE_MEM, 0); + endpoint->registers = devm_ioremap_resource(dev, res); if (IS_ERR(endpoint->registers)) return PTR_ERR(endpoint->registers); - irq = irq_of_parse_and_map(dev->of_node, 0); + irq = platform_get_irq(op, 0); rc = devm_request_irq(dev, irq, xillybus_isr, 0, xillyname, endpoint); diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 1c4e1aa6767e..98ce9fc6e6c0 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -142,6 +142,18 @@ config COMMON_CLK_GEMINI This driver supports the SoC clocks on the Cortina Systems Gemini platform, also known as SL3516 or CS3516. +config COMMON_CLK_ASPEED + bool "Clock driver for Aspeed BMC SoCs" + depends on ARCH_ASPEED || COMPILE_TEST + default ARCH_ASPEED + select MFD_SYSCON + select RESET_CONTROLLER + ---help--- + This driver supports the SoC clocks on the Aspeed BMC platforms. + + The G4 and G5 series, including the ast2400 and ast2500, are supported + by this driver. + config COMMON_CLK_S2MPS11 tristate "Clock driver for S2MPS1X/S5M8767 MFD" depends on MFD_SEC_CORE || COMPILE_TEST @@ -236,6 +248,7 @@ source "drivers/clk/mvebu/Kconfig" source "drivers/clk/qcom/Kconfig" source "drivers/clk/renesas/Kconfig" source "drivers/clk/samsung/Kconfig" +source "drivers/clk/sprd/Kconfig" source "drivers/clk/sunxi-ng/Kconfig" source "drivers/clk/tegra/Kconfig" source "drivers/clk/ti/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index f7f761b02bed..71ec41e6364f 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o +obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o @@ -67,7 +68,7 @@ obj-$(CONFIG_ARCH_MXC) += imx/ obj-$(CONFIG_MACH_INGENIC) += ingenic/ obj-$(CONFIG_ARCH_KEYSTONE) += keystone/ obj-$(CONFIG_MACH_LOONGSON32) += loongson1/ -obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ +obj-y += mediatek/ obj-$(CONFIG_COMMON_CLK_AMLOGIC) += meson/ obj-$(CONFIG_MACH_PIC32) += microchip/ ifeq ($(CONFIG_COMMON_CLK), y) @@ -85,6 +86,7 @@ obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ obj-$(CONFIG_ARCH_SIRF) += sirf/ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ obj-$(CONFIG_PLAT_SPEAR) += spear/ +obj-$(CONFIG_ARCH_SPRD) += sprd/ obj-$(CONFIG_ARCH_STI) += st/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/ diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c index 85a449cf61e3..0e6aab1252fc 100644 --- a/drivers/clk/at91/clk-programmable.c +++ b/drivers/clk/at91/clk-programmable.c @@ -204,6 +204,8 @@ at91_clk_register_programmable(struct regmap *regmap, if (ret) { kfree(prog); hw = ERR_PTR(ret); + } else { + pmc_register_pck(id); } return hw; diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index 775af473fe11..1fa27f4ea538 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -22,6 +22,7 @@ #include "pmc.h" #define PMC_MAX_IDS 128 +#define PMC_MAX_PCKS 8 int of_at91_get_clk_range(struct device_node *np, const char *propname, struct clk_range *range) @@ -50,6 +51,7 @@ EXPORT_SYMBOL_GPL(of_at91_get_clk_range); static struct regmap *pmcreg; static u8 registered_ids[PMC_MAX_IDS]; +static u8 registered_pcks[PMC_MAX_PCKS]; static struct { @@ -66,8 +68,13 @@ static struct u32 pcr[PMC_MAX_IDS]; u32 audio_pll0; u32 audio_pll1; + u32 pckr[PMC_MAX_PCKS]; } pmc_cache; +/* + * As Peripheral ID 0 is invalid on AT91 chips, the identifier is stored + * without alteration in the table, and 0 is for unused clocks. + */ void pmc_register_id(u8 id) { int i; @@ -82,11 +89,30 @@ void pmc_register_id(u8 id) } } -static int pmc_suspend(void) +/* + * As Programmable Clock 0 is valid on AT91 chips, there is an offset + * of 1 between the stored value and the real clock ID. + */ +void pmc_register_pck(u8 pck) { int i; - regmap_read(pmcreg, AT91_PMC_IMR, &pmc_cache.scsr); + for (i = 0; i < PMC_MAX_PCKS; i++) { + if (registered_pcks[i] == 0) { + registered_pcks[i] = pck + 1; + break; + } + if (registered_pcks[i] == (pck + 1)) + break; + } +} + +static int pmc_suspend(void) +{ + int i; + u8 num; + + regmap_read(pmcreg, AT91_PMC_SCSR, &pmc_cache.scsr); regmap_read(pmcreg, AT91_PMC_PCSR, &pmc_cache.pcsr0); regmap_read(pmcreg, AT91_CKGR_UCKR, &pmc_cache.uckr); regmap_read(pmcreg, AT91_CKGR_MOR, &pmc_cache.mor); @@ -103,14 +129,29 @@ static int pmc_suspend(void) regmap_read(pmcreg, AT91_PMC_PCR, &pmc_cache.pcr[registered_ids[i]]); } + for (i = 0; registered_pcks[i]; i++) { + num = registered_pcks[i] - 1; + regmap_read(pmcreg, AT91_PMC_PCKR(num), &pmc_cache.pckr[num]); + } return 0; } +static bool pmc_ready(unsigned int mask) +{ + unsigned int status; + + regmap_read(pmcreg, AT91_PMC_SR, &status); + + return ((status & mask) == mask) ? 1 : 0; +} + static void pmc_resume(void) { - int i, ret = 0; + int i; + u8 num; u32 tmp; + u32 mask = AT91_PMC_MCKRDY | AT91_PMC_LOCKA; regmap_read(pmcreg, AT91_PMC_MCKR, &tmp); if (pmc_cache.mckr != tmp) @@ -119,7 +160,7 @@ static void pmc_resume(void) if (pmc_cache.pllar != tmp) pr_warn("PLLAR was not configured properly by the firmware\n"); - regmap_write(pmcreg, AT91_PMC_IMR, pmc_cache.scsr); + regmap_write(pmcreg, AT91_PMC_SCER, pmc_cache.scsr); regmap_write(pmcreg, AT91_PMC_PCER, pmc_cache.pcsr0); regmap_write(pmcreg, AT91_CKGR_UCKR, pmc_cache.uckr); regmap_write(pmcreg, AT91_CKGR_MOR, pmc_cache.mor); @@ -133,14 +174,16 @@ static void pmc_resume(void) pmc_cache.pcr[registered_ids[i]] | AT91_PMC_PCR_CMD); } - - if (pmc_cache.uckr & AT91_PMC_UPLLEN) { - ret = regmap_read_poll_timeout(pmcreg, AT91_PMC_SR, tmp, - !(tmp & AT91_PMC_LOCKU), - 10, 5000); - if (ret) - pr_crit("USB PLL didn't lock when resuming\n"); + for (i = 0; registered_pcks[i]; i++) { + num = registered_pcks[i] - 1; + regmap_write(pmcreg, AT91_PMC_PCKR(num), pmc_cache.pckr[num]); } + + if (pmc_cache.uckr & AT91_PMC_UPLLEN) + mask |= AT91_PMC_LOCKU; + + while (!pmc_ready(mask)) + cpu_relax(); } static struct syscore_ops pmc_syscore_ops = { diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 858e8ef7e8db..d22b1fa9ecdc 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -31,8 +31,10 @@ int of_at91_get_clk_range(struct device_node *np, const char *propname, #ifdef CONFIG_PM void pmc_register_id(u8 id); +void pmc_register_pck(u8 pck); #else static inline void pmc_register_id(u8 id) {} +static inline void pmc_register_pck(u8 pck) {} #endif #endif /* __PMC_H_ */ diff --git a/drivers/clk/bcm/clk-cygnus.c b/drivers/clk/bcm/clk-cygnus.c index 464fdc4bc66b..b8d073e4855f 100644 --- a/drivers/clk/bcm/clk-cygnus.c +++ b/drivers/clk/bcm/clk-cygnus.c @@ -269,23 +269,10 @@ static void __init cygnus_asiu_init(struct device_node *node) } CLK_OF_DECLARE(cygnus_asiu_clk, "brcm,cygnus-asiu-clk", cygnus_asiu_init); -/* - * AUDIO PLL VCO frequency parameter table - * - * PLL output frequency = ((ndiv_int + ndiv_frac / 2^20) * - * (parent clock rate / pdiv) - * - * On Cygnus, parent is the 25MHz oscillator - */ -static const struct iproc_pll_vco_param audiopll_vco_params[] = { - /* rate (Hz) ndiv_int ndiv_frac pdiv */ - { 1354750204UL, 54, 199238, 1 }, - { 1769470191UL, 70, 816639, 1 }, -}; - static const struct iproc_pll_ctrl audiopll = { .flags = IPROC_CLK_PLL_NEEDS_SW_CFG | IPROC_CLK_PLL_HAS_NDIV_FRAC | - IPROC_CLK_PLL_USER_MODE_ON | IPROC_CLK_PLL_RESET_ACTIVE_LOW, + IPROC_CLK_PLL_USER_MODE_ON | IPROC_CLK_PLL_RESET_ACTIVE_LOW | + IPROC_CLK_PLL_CALC_PARAM, .reset = RESET_VAL(0x5c, 0, 1), .dig_filter = DF_VAL(0x48, 0, 3, 6, 4, 3, 3), .sw_ctrl = SW_CTRL_VAL(0x4, 0), @@ -300,8 +287,7 @@ static const struct iproc_pll_ctrl audiopll = { static const struct iproc_clk_ctrl audiopll_clk[] = { [BCM_CYGNUS_AUDIOPLL_CH0] = { .channel = BCM_CYGNUS_AUDIOPLL_CH0, - .flags = IPROC_CLK_AON | - IPROC_CLK_MCLK_DIV_BY_2, + .flags = IPROC_CLK_AON | IPROC_CLK_MCLK_DIV_BY_2, .enable = ENABLE_VAL(0x14, 8, 10, 9), .mdiv = REG_VAL(0x14, 0, 8), }, @@ -321,9 +307,8 @@ static const struct iproc_clk_ctrl audiopll_clk[] = { static void __init cygnus_audiopll_clk_init(struct device_node *node) { - iproc_pll_clk_setup(node, &audiopll, audiopll_vco_params, - ARRAY_SIZE(audiopll_vco_params), audiopll_clk, - ARRAY_SIZE(audiopll_clk)); + iproc_pll_clk_setup(node, &audiopll, NULL, 0, + audiopll_clk, ARRAY_SIZE(audiopll_clk)); } CLK_OF_DECLARE(cygnus_audiopll, "brcm,cygnus-audiopll", cygnus_audiopll_clk_init); diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c index 375d8dd80d45..43a58ae5a89d 100644 --- a/drivers/clk/bcm/clk-iproc-pll.c +++ b/drivers/clk/bcm/clk-iproc-pll.c @@ -69,16 +69,6 @@ enum vco_freq_range { VCO_MAX = 4000000000U, }; -struct iproc_pll; - -struct iproc_clk { - struct clk_hw hw; - const char *name; - struct iproc_pll *pll; - unsigned long rate; - const struct iproc_clk_ctrl *ctrl; -}; - struct iproc_pll { void __iomem *status_base; void __iomem *control_base; @@ -88,13 +78,49 @@ struct iproc_pll { const struct iproc_pll_ctrl *ctrl; const struct iproc_pll_vco_param *vco_param; unsigned int num_vco_entries; +}; - struct clk_hw_onecell_data *clk_data; - struct iproc_clk *clks; +struct iproc_clk { + struct clk_hw hw; + struct iproc_pll *pll; + const struct iproc_clk_ctrl *ctrl; }; #define to_iproc_clk(hw) container_of(hw, struct iproc_clk, hw) +static int pll_calc_param(unsigned long target_rate, + unsigned long parent_rate, + struct iproc_pll_vco_param *vco_out) +{ + u64 ndiv_int, ndiv_frac, residual; + + ndiv_int = target_rate / parent_rate; + + if (!ndiv_int || (ndiv_int > 255)) + return -EINVAL; + + residual = target_rate - (ndiv_int * parent_rate); + residual <<= 20; + + /* + * Add half of the divisor so the result will be rounded to closest + * instead of rounded down. + */ + residual += (parent_rate / 2); + ndiv_frac = div64_u64((u64)residual, (u64)parent_rate); + + vco_out->ndiv_int = ndiv_int; + vco_out->ndiv_frac = ndiv_frac; + vco_out->pdiv = 1; + + vco_out->rate = vco_out->ndiv_int * parent_rate; + residual = (u64)vco_out->ndiv_frac * (u64)parent_rate; + residual >>= 20; + vco_out->rate += residual; + + return 0; +} + /* * Based on the target frequency, find a match from the VCO frequency parameter * table and return its index @@ -252,17 +278,51 @@ static void __pll_bring_out_reset(struct iproc_pll *pll, unsigned int kp, iproc_pll_write(pll, pll->control_base, reset->offset, val); } -static int pll_set_rate(struct iproc_clk *clk, unsigned int rate_index, +/* + * Determines if the change to be applied to the PLL is minor (just an update + * or the fractional divider). If so, then we can avoid going through a + * disruptive reset and lock sequence. + */ +static bool pll_fractional_change_only(struct iproc_pll *pll, + struct iproc_pll_vco_param *vco) +{ + const struct iproc_pll_ctrl *ctrl = pll->ctrl; + u32 val; + u32 ndiv_int; + unsigned int pdiv; + + /* PLL needs to be locked */ + val = readl(pll->status_base + ctrl->status.offset); + if ((val & (1 << ctrl->status.shift)) == 0) + return false; + + val = readl(pll->control_base + ctrl->ndiv_int.offset); + ndiv_int = (val >> ctrl->ndiv_int.shift) & + bit_mask(ctrl->ndiv_int.width); + + if (ndiv_int != vco->ndiv_int) + return false; + + val = readl(pll->control_base + ctrl->pdiv.offset); + pdiv = (val >> ctrl->pdiv.shift) & bit_mask(ctrl->pdiv.width); + + if (pdiv != vco->pdiv) + return false; + + return true; +} + +static int pll_set_rate(struct iproc_clk *clk, struct iproc_pll_vco_param *vco, unsigned long parent_rate) { struct iproc_pll *pll = clk->pll; - const struct iproc_pll_vco_param *vco = &pll->vco_param[rate_index]; const struct iproc_pll_ctrl *ctrl = pll->ctrl; int ka = 0, ki, kp, ret; unsigned long rate = vco->rate; u32 val; enum kp_band kp_index; unsigned long ref_freq; + const char *clk_name = clk_hw_get_name(&clk->hw); /* * reference frequency = parent frequency / PDIV @@ -285,22 +345,35 @@ static int pll_set_rate(struct iproc_clk *clk, unsigned int rate_index, kp_index = KP_BAND_HIGH_HIGH; } else { pr_err("%s: pll: %s has invalid rate: %lu\n", __func__, - clk->name, rate); + clk_name, rate); return -EINVAL; } kp = get_kp(ref_freq, kp_index); if (kp < 0) { - pr_err("%s: pll: %s has invalid kp\n", __func__, clk->name); + pr_err("%s: pll: %s has invalid kp\n", __func__, clk_name); return kp; } ret = __pll_enable(pll); if (ret) { - pr_err("%s: pll: %s fails to enable\n", __func__, clk->name); + pr_err("%s: pll: %s fails to enable\n", __func__, clk_name); return ret; } + if (pll_fractional_change_only(clk->pll, vco)) { + /* program fractional part of NDIV */ + if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) { + val = readl(pll->control_base + ctrl->ndiv_frac.offset); + val &= ~(bit_mask(ctrl->ndiv_frac.width) << + ctrl->ndiv_frac.shift); + val |= vco->ndiv_frac << ctrl->ndiv_frac.shift; + iproc_pll_write(pll, pll->control_base, + ctrl->ndiv_frac.offset, val); + return 0; + } + } + /* put PLL in reset */ __pll_put_in_reset(pll); @@ -354,7 +427,7 @@ static int pll_set_rate(struct iproc_clk *clk, unsigned int rate_index, ret = pll_wait_for_lock(pll); if (ret < 0) { - pr_err("%s: pll: %s failed to lock\n", __func__, clk->name); + pr_err("%s: pll: %s failed to lock\n", __func__, clk_name); return ret; } @@ -390,16 +463,15 @@ static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw, u32 val; u64 ndiv, ndiv_int, ndiv_frac; unsigned int pdiv; + unsigned long rate; if (parent_rate == 0) return 0; /* PLL needs to be locked */ val = readl(pll->status_base + ctrl->status.offset); - if ((val & (1 << ctrl->status.shift)) == 0) { - clk->rate = 0; + if ((val & (1 << ctrl->status.shift)) == 0) return 0; - } /* * PLL output frequency = @@ -421,35 +493,60 @@ static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw, val = readl(pll->control_base + ctrl->pdiv.offset); pdiv = (val >> ctrl->pdiv.shift) & bit_mask(ctrl->pdiv.width); - clk->rate = (ndiv * parent_rate) >> 20; + rate = (ndiv * parent_rate) >> 20; if (pdiv == 0) - clk->rate *= 2; + rate *= 2; else - clk->rate /= pdiv; + rate /= pdiv; - return clk->rate; + return rate; } -static long iproc_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int iproc_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - unsigned i; + unsigned int i; struct iproc_clk *clk = to_iproc_clk(hw); struct iproc_pll *pll = clk->pll; + const struct iproc_pll_ctrl *ctrl = pll->ctrl; + unsigned long diff, best_diff; + unsigned int best_idx = 0; + int ret; - if (rate == 0 || *parent_rate == 0 || !pll->vco_param) + if (req->rate == 0 || req->best_parent_rate == 0) return -EINVAL; + if (ctrl->flags & IPROC_CLK_PLL_CALC_PARAM) { + struct iproc_pll_vco_param vco_param; + + ret = pll_calc_param(req->rate, req->best_parent_rate, + &vco_param); + if (ret) + return ret; + + req->rate = vco_param.rate; + return 0; + } + + if (!pll->vco_param) + return -EINVAL; + + best_diff = ULONG_MAX; for (i = 0; i < pll->num_vco_entries; i++) { - if (rate <= pll->vco_param[i].rate) + diff = abs(req->rate - pll->vco_param[i].rate); + if (diff <= best_diff) { + best_diff = diff; + best_idx = i; + } + /* break now if perfect match */ + if (diff == 0) break; } - if (i == pll->num_vco_entries) - i--; + req->rate = pll->vco_param[best_idx].rate; - return pll->vco_param[i].rate; + return 0; } static int iproc_pll_set_rate(struct clk_hw *hw, unsigned long rate, @@ -457,13 +554,23 @@ static int iproc_pll_set_rate(struct clk_hw *hw, unsigned long rate, { struct iproc_clk *clk = to_iproc_clk(hw); struct iproc_pll *pll = clk->pll; + const struct iproc_pll_ctrl *ctrl = pll->ctrl; + struct iproc_pll_vco_param vco_param; int rate_index, ret; - rate_index = pll_get_rate_index(pll, rate); - if (rate_index < 0) - return rate_index; + if (ctrl->flags & IPROC_CLK_PLL_CALC_PARAM) { + ret = pll_calc_param(rate, parent_rate, &vco_param); + if (ret) + return ret; + } else { + rate_index = pll_get_rate_index(pll, rate); + if (rate_index < 0) + return rate_index; - ret = pll_set_rate(clk, rate_index, parent_rate); + vco_param = pll->vco_param[rate_index]; + } + + ret = pll_set_rate(clk, &vco_param, parent_rate); return ret; } @@ -471,7 +578,7 @@ static const struct clk_ops iproc_pll_ops = { .enable = iproc_pll_enable, .disable = iproc_pll_disable, .recalc_rate = iproc_pll_recalc_rate, - .round_rate = iproc_pll_round_rate, + .determine_rate = iproc_pll_determine_rate, .set_rate = iproc_pll_set_rate, }; @@ -518,6 +625,7 @@ static unsigned long iproc_clk_recalc_rate(struct clk_hw *hw, struct iproc_pll *pll = clk->pll; u32 val; unsigned int mdiv; + unsigned long rate; if (parent_rate == 0) return 0; @@ -528,32 +636,33 @@ static unsigned long iproc_clk_recalc_rate(struct clk_hw *hw, mdiv = 256; if (ctrl->flags & IPROC_CLK_MCLK_DIV_BY_2) - clk->rate = parent_rate / (mdiv * 2); + rate = parent_rate / (mdiv * 2); else - clk->rate = parent_rate / mdiv; + rate = parent_rate / mdiv; - return clk->rate; + return rate; } -static long iproc_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int iproc_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - unsigned int div; + unsigned int bestdiv; - if (rate == 0 || *parent_rate == 0) + if (req->rate == 0) return -EINVAL; + if (req->rate == req->best_parent_rate) + return 0; - if (rate == *parent_rate) - return *parent_rate; + bestdiv = DIV_ROUND_CLOSEST(req->best_parent_rate, req->rate); + if (bestdiv < 2) + req->rate = req->best_parent_rate; - div = DIV_ROUND_UP(*parent_rate, rate); - if (div < 2) - return *parent_rate; + if (bestdiv > 256) + bestdiv = 256; - if (div > 256) - div = 256; + req->rate = req->best_parent_rate / bestdiv; - return *parent_rate / div; + return 0; } static int iproc_clk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -568,10 +677,10 @@ static int iproc_clk_set_rate(struct clk_hw *hw, unsigned long rate, if (rate == 0 || parent_rate == 0) return -EINVAL; + div = DIV_ROUND_CLOSEST(parent_rate, rate); if (ctrl->flags & IPROC_CLK_MCLK_DIV_BY_2) - div = DIV_ROUND_UP(parent_rate, rate * 2); - else - div = DIV_ROUND_UP(parent_rate, rate); + div /= 2; + if (div > 256) return -EINVAL; @@ -583,10 +692,6 @@ static int iproc_clk_set_rate(struct clk_hw *hw, unsigned long rate, val |= div << ctrl->mdiv.shift; } iproc_pll_write(pll, pll->control_base, ctrl->mdiv.offset, val); - if (ctrl->flags & IPROC_CLK_MCLK_DIV_BY_2) - clk->rate = parent_rate / (div * 2); - else - clk->rate = parent_rate / div; return 0; } @@ -595,7 +700,7 @@ static const struct clk_ops iproc_clk_ops = { .enable = iproc_clk_enable, .disable = iproc_clk_disable, .recalc_rate = iproc_clk_recalc_rate, - .round_rate = iproc_clk_round_rate, + .determine_rate = iproc_clk_determine_rate, .set_rate = iproc_clk_set_rate, }; @@ -629,6 +734,8 @@ void iproc_pll_clk_setup(struct device_node *node, struct iproc_clk *iclk; struct clk_init_data init; const char *parent_name; + struct iproc_clk *iclk_array; + struct clk_hw_onecell_data *clk_data; if (WARN_ON(!pll_ctrl) || WARN_ON(!clk_ctrl)) return; @@ -637,14 +744,14 @@ void iproc_pll_clk_setup(struct device_node *node, if (WARN_ON(!pll)) return; - pll->clk_data = kzalloc(sizeof(*pll->clk_data->hws) * num_clks + - sizeof(*pll->clk_data), GFP_KERNEL); - if (WARN_ON(!pll->clk_data)) + clk_data = kzalloc(sizeof(*clk_data->hws) * num_clks + + sizeof(*clk_data), GFP_KERNEL); + if (WARN_ON(!clk_data)) goto err_clk_data; - pll->clk_data->num = num_clks; + clk_data->num = num_clks; - pll->clks = kcalloc(num_clks, sizeof(*pll->clks), GFP_KERNEL); - if (WARN_ON(!pll->clks)) + iclk_array = kcalloc(num_clks, sizeof(struct iproc_clk), GFP_KERNEL); + if (WARN_ON(!iclk_array)) goto err_clks; pll->control_base = of_iomap(node, 0); @@ -674,9 +781,8 @@ void iproc_pll_clk_setup(struct device_node *node, /* initialize and register the PLL itself */ pll->ctrl = pll_ctrl; - iclk = &pll->clks[0]; + iclk = &iclk_array[0]; iclk->pll = pll; - iclk->name = node->name; init.name = node->name; init.ops = &iproc_pll_ops; @@ -697,7 +803,7 @@ void iproc_pll_clk_setup(struct device_node *node, if (WARN_ON(ret)) goto err_pll_register; - pll->clk_data->hws[0] = &iclk->hw; + clk_data->hws[0] = &iclk->hw; /* now initialize and register all leaf clocks */ for (i = 1; i < num_clks; i++) { @@ -711,8 +817,7 @@ void iproc_pll_clk_setup(struct device_node *node, if (WARN_ON(ret)) goto err_clk_register; - iclk = &pll->clks[i]; - iclk->name = clk_name; + iclk = &iclk_array[i]; iclk->pll = pll; iclk->ctrl = &clk_ctrl[i]; @@ -727,11 +832,10 @@ void iproc_pll_clk_setup(struct device_node *node, if (WARN_ON(ret)) goto err_clk_register; - pll->clk_data->hws[i] = &iclk->hw; + clk_data->hws[i] = &iclk->hw; } - ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, - pll->clk_data); + ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); if (WARN_ON(ret)) goto err_clk_register; @@ -739,7 +843,7 @@ void iproc_pll_clk_setup(struct device_node *node, err_clk_register: while (--i >= 0) - clk_hw_unregister(pll->clk_data->hws[i]); + clk_hw_unregister(clk_data->hws[i]); err_pll_register: if (pll->status_base != pll->control_base) @@ -756,10 +860,10 @@ err_asiu_iomap: iounmap(pll->control_base); err_pll_iomap: - kfree(pll->clks); + kfree(iclk_array); err_clks: - kfree(pll->clk_data); + kfree(clk_data); err_clk_data: kfree(pll); diff --git a/drivers/clk/bcm/clk-iproc.h b/drivers/clk/bcm/clk-iproc.h index 2148b4ea9f28..a48ddd3e0b28 100644 --- a/drivers/clk/bcm/clk-iproc.h +++ b/drivers/clk/bcm/clk-iproc.h @@ -80,6 +80,11 @@ */ #define IPROC_CLK_PLL_RESET_ACTIVE_LOW BIT(9) +/* + * Calculate the PLL parameters are runtime, instead of using table + */ +#define IPROC_CLK_PLL_CALC_PARAM BIT(10) + /* * Parameters for VCO frequency configuration * diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c new file mode 100644 index 000000000000..9f7f931d6b2f --- /dev/null +++ b/drivers/clk/clk-aspeed.c @@ -0,0 +1,667 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#define pr_fmt(fmt) "clk-aspeed: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define ASPEED_NUM_CLKS 35 + +#define ASPEED_RESET_CTRL 0x04 +#define ASPEED_CLK_SELECTION 0x08 +#define ASPEED_CLK_STOP_CTRL 0x0c +#define ASPEED_MPLL_PARAM 0x20 +#define ASPEED_HPLL_PARAM 0x24 +#define AST2500_HPLL_BYPASS_EN BIT(20) +#define AST2400_HPLL_STRAPPED BIT(18) +#define AST2400_HPLL_BYPASS_EN BIT(17) +#define ASPEED_MISC_CTRL 0x2c +#define UART_DIV13_EN BIT(12) +#define ASPEED_STRAP 0x70 +#define CLKIN_25MHZ_EN BIT(23) +#define AST2400_CLK_SOURCE_SEL BIT(18) +#define ASPEED_CLK_SELECTION_2 0xd8 + +/* Globally visible clocks */ +static DEFINE_SPINLOCK(aspeed_clk_lock); + +/* Keeps track of all clocks */ +static struct clk_hw_onecell_data *aspeed_clk_data; + +static void __iomem *scu_base; + +/** + * struct aspeed_gate_data - Aspeed gated clocks + * @clock_idx: bit used to gate this clock in the clock register + * @reset_idx: bit used to reset this IP in the reset register. -1 if no + * reset is required when enabling the clock + * @name: the clock name + * @parent_name: the name of the parent clock + * @flags: standard clock framework flags + */ +struct aspeed_gate_data { + u8 clock_idx; + s8 reset_idx; + const char *name; + const char *parent_name; + unsigned long flags; +}; + +/** + * struct aspeed_clk_gate - Aspeed specific clk_gate structure + * @hw: handle between common and hardware-specific interfaces + * @reg: register controlling gate + * @clock_idx: bit used to gate this clock in the clock register + * @reset_idx: bit used to reset this IP in the reset register. -1 if no + * reset is required when enabling the clock + * @flags: hardware-specific flags + * @lock: register lock + * + * Some of the clocks in the Aspeed SoC must be put in reset before enabling. + * This modified version of clk_gate allows an optional reset bit to be + * specified. + */ +struct aspeed_clk_gate { + struct clk_hw hw; + struct regmap *map; + u8 clock_idx; + s8 reset_idx; + u8 flags; + spinlock_t *lock; +}; + +#define to_aspeed_clk_gate(_hw) container_of(_hw, struct aspeed_clk_gate, hw) + +/* TODO: ask Aspeed about the actual parent data */ +static const struct aspeed_gate_data aspeed_gates[] = { + /* clk rst name parent flags */ + [ASPEED_CLK_GATE_ECLK] = { 0, -1, "eclk-gate", "eclk", 0 }, /* Video Engine */ + [ASPEED_CLK_GATE_GCLK] = { 1, 7, "gclk-gate", NULL, 0 }, /* 2D engine */ + [ASPEED_CLK_GATE_MCLK] = { 2, -1, "mclk-gate", "mpll", CLK_IS_CRITICAL }, /* SDRAM */ + [ASPEED_CLK_GATE_VCLK] = { 3, 6, "vclk-gate", NULL, 0 }, /* Video Capture */ + [ASPEED_CLK_GATE_BCLK] = { 4, 10, "bclk-gate", "bclk", 0 }, /* PCIe/PCI */ + [ASPEED_CLK_GATE_DCLK] = { 5, -1, "dclk-gate", NULL, 0 }, /* DAC */ + [ASPEED_CLK_GATE_REFCLK] = { 6, -1, "refclk-gate", "clkin", CLK_IS_CRITICAL }, + [ASPEED_CLK_GATE_USBPORT2CLK] = { 7, 3, "usb-port2-gate", NULL, 0 }, /* USB2.0 Host port 2 */ + [ASPEED_CLK_GATE_LCLK] = { 8, 5, "lclk-gate", NULL, 0 }, /* LPC */ + [ASPEED_CLK_GATE_USBUHCICLK] = { 9, 15, "usb-uhci-gate", NULL, 0 }, /* USB1.1 (requires port 2 enabled) */ + [ASPEED_CLK_GATE_D1CLK] = { 10, 13, "d1clk-gate", NULL, 0 }, /* GFX CRT */ + [ASPEED_CLK_GATE_YCLK] = { 13, 4, "yclk-gate", NULL, 0 }, /* HAC */ + [ASPEED_CLK_GATE_USBPORT1CLK] = { 14, 14, "usb-port1-gate", NULL, 0 }, /* USB2 hub/USB2 host port 1/USB1.1 dev */ + [ASPEED_CLK_GATE_UART1CLK] = { 15, -1, "uart1clk-gate", "uart", 0 }, /* UART1 */ + [ASPEED_CLK_GATE_UART2CLK] = { 16, -1, "uart2clk-gate", "uart", 0 }, /* UART2 */ + [ASPEED_CLK_GATE_UART5CLK] = { 17, -1, "uart5clk-gate", "uart", 0 }, /* UART5 */ + [ASPEED_CLK_GATE_ESPICLK] = { 19, -1, "espiclk-gate", NULL, 0 }, /* eSPI */ + [ASPEED_CLK_GATE_MAC1CLK] = { 20, 11, "mac1clk-gate", "mac", 0 }, /* MAC1 */ + [ASPEED_CLK_GATE_MAC2CLK] = { 21, 12, "mac2clk-gate", "mac", 0 }, /* MAC2 */ + [ASPEED_CLK_GATE_RSACLK] = { 24, -1, "rsaclk-gate", NULL, 0 }, /* RSA */ + [ASPEED_CLK_GATE_UART3CLK] = { 25, -1, "uart3clk-gate", "uart", 0 }, /* UART3 */ + [ASPEED_CLK_GATE_UART4CLK] = { 26, -1, "uart4clk-gate", "uart", 0 }, /* UART4 */ + [ASPEED_CLK_GATE_SDCLKCLK] = { 27, 16, "sdclk-gate", NULL, 0 }, /* SDIO/SD */ + [ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */ +}; + +static const struct clk_div_table ast2500_mac_div_table[] = { + { 0x0, 4 }, /* Yep, really. Aspeed confirmed this is correct */ + { 0x1, 4 }, + { 0x2, 6 }, + { 0x3, 8 }, + { 0x4, 10 }, + { 0x5, 12 }, + { 0x6, 14 }, + { 0x7, 16 }, + { 0 } +}; + +static const struct clk_div_table ast2400_div_table[] = { + { 0x0, 2 }, + { 0x1, 4 }, + { 0x2, 6 }, + { 0x3, 8 }, + { 0x4, 10 }, + { 0x5, 12 }, + { 0x6, 14 }, + { 0x7, 16 }, + { 0 } +}; + +static const struct clk_div_table ast2500_div_table[] = { + { 0x0, 4 }, + { 0x1, 8 }, + { 0x2, 12 }, + { 0x3, 16 }, + { 0x4, 20 }, + { 0x5, 24 }, + { 0x6, 28 }, + { 0x7, 32 }, + { 0 } +}; + +static struct clk_hw *aspeed_ast2400_calc_pll(const char *name, u32 val) +{ + unsigned int mult, div; + + if (val & AST2400_HPLL_BYPASS_EN) { + /* Pass through mode */ + mult = div = 1; + } else { + /* F = 24Mhz * (2-OD) * [(N + 2) / (D + 1)] */ + u32 n = (val >> 5) & 0x3f; + u32 od = (val >> 4) & 0x1; + u32 d = val & 0xf; + + mult = (2 - od) * (n + 2); + div = d + 1; + } + return clk_hw_register_fixed_factor(NULL, name, "clkin", 0, + mult, div); +}; + +static struct clk_hw *aspeed_ast2500_calc_pll(const char *name, u32 val) +{ + unsigned int mult, div; + + if (val & AST2500_HPLL_BYPASS_EN) { + /* Pass through mode */ + mult = div = 1; + } else { + /* F = clkin * [(M+1) / (N+1)] / (P + 1) */ + u32 p = (val >> 13) & 0x3f; + u32 m = (val >> 5) & 0xff; + u32 n = val & 0x1f; + + mult = (m + 1) / (n + 1); + div = p + 1; + } + + return clk_hw_register_fixed_factor(NULL, name, "clkin", 0, + mult, div); +} + +struct aspeed_clk_soc_data { + const struct clk_div_table *div_table; + const struct clk_div_table *mac_div_table; + struct clk_hw *(*calc_pll)(const char *name, u32 val); +}; + +static const struct aspeed_clk_soc_data ast2500_data = { + .div_table = ast2500_div_table, + .mac_div_table = ast2500_mac_div_table, + .calc_pll = aspeed_ast2500_calc_pll, +}; + +static const struct aspeed_clk_soc_data ast2400_data = { + .div_table = ast2400_div_table, + .mac_div_table = ast2400_div_table, + .calc_pll = aspeed_ast2400_calc_pll, +}; + +static int aspeed_clk_enable(struct clk_hw *hw) +{ + struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw); + unsigned long flags; + u32 clk = BIT(gate->clock_idx); + u32 rst = BIT(gate->reset_idx); + u32 enval; + + spin_lock_irqsave(gate->lock, flags); + + if (gate->reset_idx >= 0) { + /* Put IP in reset */ + regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, rst); + + /* Delay 100us */ + udelay(100); + } + + /* Enable clock */ + enval = (gate->flags & CLK_GATE_SET_TO_DISABLE) ? 0 : clk; + regmap_update_bits(gate->map, ASPEED_CLK_STOP_CTRL, clk, enval); + + if (gate->reset_idx >= 0) { + /* A delay of 10ms is specified by the ASPEED docs */ + mdelay(10); + + /* Take IP out of reset */ + regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, 0); + } + + spin_unlock_irqrestore(gate->lock, flags); + + return 0; +} + +static void aspeed_clk_disable(struct clk_hw *hw) +{ + struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw); + unsigned long flags; + u32 clk = BIT(gate->clock_idx); + u32 enval; + + spin_lock_irqsave(gate->lock, flags); + + enval = (gate->flags & CLK_GATE_SET_TO_DISABLE) ? clk : 0; + regmap_update_bits(gate->map, ASPEED_CLK_STOP_CTRL, clk, enval); + + spin_unlock_irqrestore(gate->lock, flags); +} + +static int aspeed_clk_is_enabled(struct clk_hw *hw) +{ + struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw); + u32 clk = BIT(gate->clock_idx); + u32 reg; + + regmap_read(gate->map, ASPEED_CLK_STOP_CTRL, ®); + + return (reg & clk) ? 0 : 1; +} + +static const struct clk_ops aspeed_clk_gate_ops = { + .enable = aspeed_clk_enable, + .disable = aspeed_clk_disable, + .is_enabled = aspeed_clk_is_enabled, +}; + +/** + * struct aspeed_reset - Aspeed reset controller + * @map: regmap to access the containing system controller + * @rcdev: reset controller device + */ +struct aspeed_reset { + struct regmap *map; + struct reset_controller_dev rcdev; +}; + +#define to_aspeed_reset(p) container_of((p), struct aspeed_reset, rcdev) + +static const u8 aspeed_resets[] = { + [ASPEED_RESET_XDMA] = 25, + [ASPEED_RESET_MCTP] = 24, + [ASPEED_RESET_ADC] = 23, + [ASPEED_RESET_JTAG_MASTER] = 22, + [ASPEED_RESET_MIC] = 18, + [ASPEED_RESET_PWM] = 9, + [ASPEED_RESET_PCIVGA] = 8, + [ASPEED_RESET_I2C] = 2, + [ASPEED_RESET_AHB] = 1, +}; + +static int aspeed_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct aspeed_reset *ar = to_aspeed_reset(rcdev); + u32 rst = BIT(aspeed_resets[id]); + + return regmap_update_bits(ar->map, ASPEED_RESET_CTRL, rst, 0); +} + +static int aspeed_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct aspeed_reset *ar = to_aspeed_reset(rcdev); + u32 rst = BIT(aspeed_resets[id]); + + return regmap_update_bits(ar->map, ASPEED_RESET_CTRL, rst, rst); +} + +static int aspeed_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct aspeed_reset *ar = to_aspeed_reset(rcdev); + u32 val, rst = BIT(aspeed_resets[id]); + int ret; + + ret = regmap_read(ar->map, ASPEED_RESET_CTRL, &val); + if (ret) + return ret; + + return !!(val & rst); +} + +static const struct reset_control_ops aspeed_reset_ops = { + .assert = aspeed_reset_assert, + .deassert = aspeed_reset_deassert, + .status = aspeed_reset_status, +}; + +static struct clk_hw *aspeed_clk_hw_register_gate(struct device *dev, + const char *name, const char *parent_name, unsigned long flags, + struct regmap *map, u8 clock_idx, u8 reset_idx, + u8 clk_gate_flags, spinlock_t *lock) +{ + struct aspeed_clk_gate *gate; + struct clk_init_data init; + struct clk_hw *hw; + int ret; + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &aspeed_clk_gate_ops; + init.flags = flags; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + gate->map = map; + gate->clock_idx = clock_idx; + gate->reset_idx = reset_idx; + gate->flags = clk_gate_flags; + gate->lock = lock; + gate->hw.init = &init; + + hw = &gate->hw; + ret = clk_hw_register(dev, hw); + if (ret) { + kfree(gate); + hw = ERR_PTR(ret); + } + + return hw; +} + +static int aspeed_clk_probe(struct platform_device *pdev) +{ + const struct aspeed_clk_soc_data *soc_data; + struct device *dev = &pdev->dev; + struct aspeed_reset *ar; + struct regmap *map; + struct clk_hw *hw; + u32 val, rate; + int i, ret; + + map = syscon_node_to_regmap(dev->of_node); + if (IS_ERR(map)) { + dev_err(dev, "no syscon regmap\n"); + return PTR_ERR(map); + } + + ar = devm_kzalloc(dev, sizeof(*ar), GFP_KERNEL); + if (!ar) + return -ENOMEM; + + ar->map = map; + ar->rcdev.owner = THIS_MODULE; + ar->rcdev.nr_resets = ARRAY_SIZE(aspeed_resets); + ar->rcdev.ops = &aspeed_reset_ops; + ar->rcdev.of_node = dev->of_node; + + ret = devm_reset_controller_register(dev, &ar->rcdev); + if (ret) { + dev_err(dev, "could not register reset controller\n"); + return ret; + } + + /* SoC generations share common layouts but have different divisors */ + soc_data = of_device_get_match_data(dev); + if (!soc_data) { + dev_err(dev, "no match data for platform\n"); + return -EINVAL; + } + + /* UART clock div13 setting */ + regmap_read(map, ASPEED_MISC_CTRL, &val); + if (val & UART_DIV13_EN) + rate = 24000000 / 13; + else + rate = 24000000; + /* TODO: Find the parent data for the uart clock */ + hw = clk_hw_register_fixed_rate(dev, "uart", NULL, 0, rate); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_UART] = hw; + + /* + * Memory controller (M-PLL) PLL. This clock is configured by the + * bootloader, and is exposed to Linux as a read-only clock rate. + */ + regmap_read(map, ASPEED_MPLL_PARAM, &val); + hw = soc_data->calc_pll("mpll", val); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_MPLL] = hw; + + /* SD/SDIO clock divider (TODO: There's a gate too) */ + hw = clk_hw_register_divider_table(dev, "sdio", "hpll", 0, + scu_base + ASPEED_CLK_SELECTION, 12, 3, 0, + soc_data->div_table, + &aspeed_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_SDIO] = hw; + + /* MAC AHB bus clock divider */ + hw = clk_hw_register_divider_table(dev, "mac", "hpll", 0, + scu_base + ASPEED_CLK_SELECTION, 16, 3, 0, + soc_data->mac_div_table, + &aspeed_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_MAC] = hw; + + /* LPC Host (LHCLK) clock divider */ + hw = clk_hw_register_divider_table(dev, "lhclk", "hpll", 0, + scu_base + ASPEED_CLK_SELECTION, 20, 3, 0, + soc_data->div_table, + &aspeed_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_LHCLK] = hw; + + /* P-Bus (BCLK) clock divider */ + hw = clk_hw_register_divider_table(dev, "bclk", "hpll", 0, + scu_base + ASPEED_CLK_SELECTION_2, 0, 2, 0, + soc_data->div_table, + &aspeed_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_BCLK] = hw; + + /* + * TODO: There are a number of clocks that not included in this driver + * as more information is required: + * D2-PLL + * D-PLL + * YCLK + * RGMII + * RMII + * UART[1..5] clock source mux + * Video Engine (ECLK) mux and clock divider + */ + + for (i = 0; i < ARRAY_SIZE(aspeed_gates); i++) { + const struct aspeed_gate_data *gd = &aspeed_gates[i]; + u32 gate_flags; + + /* Special case: the USB port 1 clock (bit 14) is always + * working the opposite way from the other ones. + */ + gate_flags = (gd->clock_idx == 14) ? 0 : CLK_GATE_SET_TO_DISABLE; + hw = aspeed_clk_hw_register_gate(dev, + gd->name, + gd->parent_name, + gd->flags, + map, + gd->clock_idx, + gd->reset_idx, + gate_flags, + &aspeed_clk_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[i] = hw; + } + + return 0; +}; + +static const struct of_device_id aspeed_clk_dt_ids[] = { + { .compatible = "aspeed,ast2400-scu", .data = &ast2400_data }, + { .compatible = "aspeed,ast2500-scu", .data = &ast2500_data }, + { } +}; + +static struct platform_driver aspeed_clk_driver = { + .probe = aspeed_clk_probe, + .driver = { + .name = "aspeed-clk", + .of_match_table = aspeed_clk_dt_ids, + .suppress_bind_attrs = true, + }, +}; +builtin_platform_driver(aspeed_clk_driver); + +static void __init aspeed_ast2400_cc(struct regmap *map) +{ + struct clk_hw *hw; + u32 val, freq, div; + + /* + * CLKIN is the crystal oscillator, 24, 48 or 25MHz selected by + * strapping + */ + regmap_read(map, ASPEED_STRAP, &val); + if (val & CLKIN_25MHZ_EN) + freq = 25000000; + else if (val & AST2400_CLK_SOURCE_SEL) + freq = 48000000; + else + freq = 24000000; + hw = clk_hw_register_fixed_rate(NULL, "clkin", NULL, 0, freq); + pr_debug("clkin @%u MHz\n", freq / 1000000); + + /* + * High-speed PLL clock derived from the crystal. This the CPU clock, + * and we assume that it is enabled + */ + regmap_read(map, ASPEED_HPLL_PARAM, &val); + WARN(val & AST2400_HPLL_STRAPPED, "hpll is strapped not configured"); + aspeed_clk_data->hws[ASPEED_CLK_HPLL] = aspeed_ast2400_calc_pll("hpll", val); + + /* + * Strap bits 11:10 define the CPU/AHB clock frequency ratio (aka HCLK) + * 00: Select CPU:AHB = 1:1 + * 01: Select CPU:AHB = 2:1 + * 10: Select CPU:AHB = 4:1 + * 11: Select CPU:AHB = 3:1 + */ + regmap_read(map, ASPEED_STRAP, &val); + val = (val >> 10) & 0x3; + div = val + 1; + if (div == 3) + div = 4; + else if (div == 4) + div = 3; + hw = clk_hw_register_fixed_factor(NULL, "ahb", "hpll", 0, 1, div); + aspeed_clk_data->hws[ASPEED_CLK_AHB] = hw; + + /* APB clock clock selection register SCU08 (aka PCLK) */ + hw = clk_hw_register_divider_table(NULL, "apb", "hpll", 0, + scu_base + ASPEED_CLK_SELECTION, 23, 3, 0, + ast2400_div_table, + &aspeed_clk_lock); + aspeed_clk_data->hws[ASPEED_CLK_APB] = hw; +} + +static void __init aspeed_ast2500_cc(struct regmap *map) +{ + struct clk_hw *hw; + u32 val, freq, div; + + /* CLKIN is the crystal oscillator, 24 or 25MHz selected by strapping */ + regmap_read(map, ASPEED_STRAP, &val); + if (val & CLKIN_25MHZ_EN) + freq = 25000000; + else + freq = 24000000; + hw = clk_hw_register_fixed_rate(NULL, "clkin", NULL, 0, freq); + pr_debug("clkin @%u MHz\n", freq / 1000000); + + /* + * High-speed PLL clock derived from the crystal. This the CPU clock, + * and we assume that it is enabled + */ + regmap_read(map, ASPEED_HPLL_PARAM, &val); + aspeed_clk_data->hws[ASPEED_CLK_HPLL] = aspeed_ast2500_calc_pll("hpll", val); + + /* Strap bits 11:9 define the AXI/AHB clock frequency ratio (aka HCLK)*/ + regmap_read(map, ASPEED_STRAP, &val); + val = (val >> 9) & 0x7; + WARN(val == 0, "strapping is zero: cannot determine ahb clock"); + div = 2 * (val + 1); + hw = clk_hw_register_fixed_factor(NULL, "ahb", "hpll", 0, 1, div); + aspeed_clk_data->hws[ASPEED_CLK_AHB] = hw; + + /* APB clock clock selection register SCU08 (aka PCLK) */ + regmap_read(map, ASPEED_CLK_SELECTION, &val); + val = (val >> 23) & 0x7; + div = 4 * (val + 1); + hw = clk_hw_register_fixed_factor(NULL, "apb", "hpll", 0, 1, div); + aspeed_clk_data->hws[ASPEED_CLK_APB] = hw; +}; + +static void __init aspeed_cc_init(struct device_node *np) +{ + struct regmap *map; + u32 val; + int ret; + int i; + + scu_base = of_iomap(np, 0); + if (!scu_base) + return; + + aspeed_clk_data = kzalloc(sizeof(*aspeed_clk_data) + + sizeof(*aspeed_clk_data->hws) * ASPEED_NUM_CLKS, + GFP_KERNEL); + if (!aspeed_clk_data) + return; + + /* + * This way all clocks fetched before the platform device probes, + * except those we assign here for early use, will be deferred. + */ + for (i = 0; i < ASPEED_NUM_CLKS; i++) + aspeed_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER); + + map = syscon_node_to_regmap(np); + if (IS_ERR(map)) { + pr_err("no syscon regmap\n"); + return; + } + /* + * We check that the regmap works on this very first access, + * but as this is an MMIO-backed regmap, subsequent regmap + * access is not going to fail and we skip error checks from + * this point. + */ + ret = regmap_read(map, ASPEED_STRAP, &val); + if (ret) { + pr_err("failed to read strapping register\n"); + return; + } + + if (of_device_is_compatible(np, "aspeed,ast2400-scu")) + aspeed_ast2400_cc(map); + else if (of_device_is_compatible(np, "aspeed,ast2500-scu")) + aspeed_ast2500_cc(map); + else + pr_err("unknown platform, failed to add clocks\n"); + + aspeed_clk_data->num = ASPEED_NUM_CLKS; + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, aspeed_clk_data); + if (ret) + pr_err("failed to add DT provider: %d\n", ret); +}; +CLK_OF_DECLARE_DRIVER(aspeed_cc_g5, "aspeed,ast2500-scu", aspeed_cc_init); +CLK_OF_DECLARE_DRIVER(aspeed_cc_g4, "aspeed,ast2400-scu", aspeed_cc_init); diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c index 5e918e7afaba..48d11f2598e8 100644 --- a/drivers/clk/clk-axi-clkgen.c +++ b/drivers/clk/clk-axi-clkgen.c @@ -40,6 +40,10 @@ #define MMCM_REG_FILTER1 0x4e #define MMCM_REG_FILTER2 0x4f +#define MMCM_CLKOUT_NOCOUNT BIT(6) + +#define MMCM_CLK_DIV_NOCOUNT BIT(12) + struct axi_clkgen { void __iomem *base; struct clk_hw clk_hw; @@ -298,13 +302,17 @@ static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { unsigned int d, m, dout; + unsigned long long tmp; axi_clkgen_calc_params(*parent_rate, rate, &d, &m, &dout); if (d == 0 || dout == 0 || m == 0) return -EINVAL; - return *parent_rate / d * m / dout; + tmp = (unsigned long long)*parent_rate * m; + tmp = DIV_ROUND_CLOSEST_ULL(tmp, dout * d); + + return min_t(unsigned long long, tmp, LONG_MAX); } static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw, @@ -315,18 +323,33 @@ static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw, unsigned int reg; unsigned long long tmp; - axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_1, ®); - dout = (reg & 0x3f) + ((reg >> 6) & 0x3f); + axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_2, ®); + if (reg & MMCM_CLKOUT_NOCOUNT) { + dout = 1; + } else { + axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_1, ®); + dout = (reg & 0x3f) + ((reg >> 6) & 0x3f); + } + axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_DIV, ®); - d = (reg & 0x3f) + ((reg >> 6) & 0x3f); - axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB1, ®); - m = (reg & 0x3f) + ((reg >> 6) & 0x3f); + if (reg & MMCM_CLK_DIV_NOCOUNT) + d = 1; + else + d = (reg & 0x3f) + ((reg >> 6) & 0x3f); + + axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB2, ®); + if (reg & MMCM_CLKOUT_NOCOUNT) { + m = 1; + } else { + axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB1, ®); + m = (reg & 0x3f) + ((reg >> 6) & 0x3f); + } if (d == 0 || dout == 0) return 0; - tmp = (unsigned long long)(parent_rate / d) * m; - do_div(tmp, dout); + tmp = (unsigned long long)parent_rate * m; + tmp = DIV_ROUND_CLOSEST_ULL(tmp, dout * d); return min_t(unsigned long long, tmp, ULONG_MAX); } diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 4ed516cb7276..b49942b9fe50 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -118,12 +118,11 @@ static unsigned int _get_val(const struct clk_div_table *table, unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, unsigned int val, const struct clk_div_table *table, - unsigned long flags) + unsigned long flags, unsigned long width) { - struct clk_divider *divider = to_clk_divider(hw); unsigned int div; - div = _get_div(table, val, flags, divider->width); + div = _get_div(table, val, flags, width); if (!div) { WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO), "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", @@ -145,7 +144,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, val &= div_mask(divider->width); return divider_recalc_rate(hw, parent_rate, val, divider->table, - divider->flags); + divider->flags, divider->width); } static bool _is_valid_table_div(const struct clk_div_table *table, diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index b0ea753b8709..3a1812f65e5d 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -41,7 +41,7 @@ struct clockgen_pll_div { }; struct clockgen_pll { - struct clockgen_pll_div div[4]; + struct clockgen_pll_div div[8]; }; #define CLKSEL_VALID 1 @@ -1127,6 +1127,13 @@ static void __init create_one_pll(struct clockgen *cg, int idx) struct clk *clk; int ret; + /* + * For platform PLL, there are 8 divider clocks. + * For core PLL, there are 4 divider clocks at most. + */ + if (idx != PLATFORM_PLL && i >= 4) + break; + snprintf(pll->div[i].name, sizeof(pll->div[i].name), "cg-pll%d-div%d", idx, i + 1); diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index 20d90769cced..50e7c341e97e 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -72,7 +72,7 @@ static const char * const si5351_input_names[] = { "xtal", "clkin" }; static const char * const si5351_pll_names[] = { - "plla", "pllb", "vxco" + "si5351_plla", "si5351_pllb", "si5351_vxco" }; static const char * const si5351_msynth_names[] = { "ms0", "ms1", "ms2", "ms3", "ms4", "ms5", "ms6", "ms7" @@ -903,13 +903,42 @@ static int _si5351_clkout_set_disable_state( return 0; } +static void _si5351_clkout_reset_pll(struct si5351_driver_data *drvdata, int num) +{ + u8 val = si5351_reg_read(drvdata, SI5351_CLK0_CTRL + num); + + switch (val & SI5351_CLK_INPUT_MASK) { + case SI5351_CLK_INPUT_XTAL: + case SI5351_CLK_INPUT_CLKIN: + return; /* pll not used, no need to reset */ + } + + si5351_reg_write(drvdata, SI5351_PLL_RESET, + val & SI5351_CLK_PLL_SELECT ? SI5351_PLL_RESET_B : + SI5351_PLL_RESET_A); + + dev_dbg(&drvdata->client->dev, "%s - %s: pll = %d\n", + __func__, clk_hw_get_name(&drvdata->clkout[num].hw), + (val & SI5351_CLK_PLL_SELECT) ? 1 : 0); +} + static int si5351_clkout_prepare(struct clk_hw *hw) { struct si5351_hw_data *hwdata = container_of(hw, struct si5351_hw_data, hw); + struct si5351_platform_data *pdata = + hwdata->drvdata->client->dev.platform_data; si5351_set_bits(hwdata->drvdata, SI5351_CLK0_CTRL + hwdata->num, SI5351_CLK_POWERDOWN, 0); + + /* + * Do a pll soft reset on the parent pll -- needed to get a + * deterministic phase relationship between the output clocks. + */ + if (pdata->clkout[hwdata->num].pll_reset) + _si5351_clkout_reset_pll(hwdata->drvdata, hwdata->num); + si5351_set_bits(hwdata->drvdata, SI5351_OUTPUT_ENABLE_CTRL, (1 << hwdata->num), 0); return 0; @@ -1297,6 +1326,9 @@ static int si5351_dt_parse(struct i2c_client *client, pdata->clkout[num].pll_master = of_property_read_bool(child, "silabs,pll-master"); + + pdata->clkout[num].pll_reset = + of_property_read_bool(child, "silabs,pll-reset"); } client->dev.platform_data = pdata; @@ -1437,11 +1469,6 @@ static int si5351_i2c_probe(struct i2c_client *client, } } - if (!IS_ERR(drvdata->pxtal)) - clk_prepare_enable(drvdata->pxtal); - if (!IS_ERR(drvdata->pclkin)) - clk_prepare_enable(drvdata->pclkin); - /* register xtal input clock gate */ memset(&init, 0, sizeof(init)); init.name = si5351_input_names[0]; @@ -1456,7 +1483,7 @@ static int si5351_i2c_probe(struct i2c_client *client, ret = devm_clk_hw_register(&client->dev, &drvdata->xtal); if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - goto err_clk; + return ret; } /* register clkin input clock gate */ @@ -1474,7 +1501,7 @@ static int si5351_i2c_probe(struct i2c_client *client, if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - goto err_clk; + return ret; } } @@ -1496,7 +1523,7 @@ static int si5351_i2c_probe(struct i2c_client *client, ret = devm_clk_hw_register(&client->dev, &drvdata->pll[0].hw); if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - goto err_clk; + return ret; } /* register PLLB or VXCO (Si5351B) */ @@ -1520,7 +1547,7 @@ static int si5351_i2c_probe(struct i2c_client *client, ret = devm_clk_hw_register(&client->dev, &drvdata->pll[1].hw); if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - goto err_clk; + return ret; } /* register clk multisync and clk out divider */ @@ -1539,7 +1566,7 @@ static int si5351_i2c_probe(struct i2c_client *client, if (WARN_ON(!drvdata->msynth || !drvdata->clkout)) { ret = -ENOMEM; - goto err_clk; + return ret; } for (n = 0; n < num_clocks; n++) { @@ -1559,7 +1586,7 @@ static int si5351_i2c_probe(struct i2c_client *client, if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - goto err_clk; + return ret; } } @@ -1587,7 +1614,7 @@ static int si5351_i2c_probe(struct i2c_client *client, if (ret) { dev_err(&client->dev, "unable to register %s\n", init.name); - goto err_clk; + return ret; } /* set initial clkout rate */ @@ -1606,17 +1633,17 @@ static int si5351_i2c_probe(struct i2c_client *client, drvdata); if (ret) { dev_err(&client->dev, "unable to add clk provider\n"); - goto err_clk; + return ret; } return 0; +} -err_clk: - if (!IS_ERR(drvdata->pxtal)) - clk_disable_unprepare(drvdata->pxtal); - if (!IS_ERR(drvdata->pclkin)) - clk_disable_unprepare(drvdata->pclkin); - return ret; +static int si5351_i2c_remove(struct i2c_client *client) +{ + of_clk_del_provider(client->dev.of_node); + + return 0; } static const struct i2c_device_id si5351_i2c_ids[] = { @@ -1634,6 +1661,7 @@ static struct i2c_driver si5351_driver = { .of_match_table = of_match_ptr(si5351_dt_ids), }, .probe = si5351_i2c_probe, + .remove = si5351_i2c_remove, .id_table = si5351_i2c_ids, }; module_i2c_driver(si5351_driver); diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c index 96c6b6bc8f0e..da44f8dc1d29 100644 --- a/drivers/clk/clk-stm32f4.c +++ b/drivers/clk/clk-stm32f4.c @@ -1424,7 +1424,7 @@ static void __init stm32f4_rcc_init(struct device_node *np) base = of_iomap(np, 0); if (!base) { - pr_err("%s: unable to map resource", np->name); + pr_err("%s: unable to map resource\n", np->name); return; } diff --git a/drivers/clk/clk-stm32h7.c b/drivers/clk/clk-stm32h7.c index 61c3e40507d3..db2b162c0d4c 100644 --- a/drivers/clk/clk-stm32h7.c +++ b/drivers/clk/clk-stm32h7.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (C) Gabriel Fernandez 2017 - * Author: Gabriel Fernandez - * - * License terms: GPL V2.0. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . + * Copyright (C) STMicroelectronics 2017 + * Author: Gabriel Fernandez for STMicroelectronics. */ #include diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index b56c11f51baf..0f686a9dac3e 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "clk.h" @@ -62,6 +63,7 @@ struct clk_core { bool orphan; unsigned int enable_count; unsigned int prepare_count; + unsigned int protect_count; unsigned long min_rate; unsigned long max_rate; unsigned long accuracy; @@ -86,6 +88,7 @@ struct clk { const char *con_id; unsigned long min_rate; unsigned long max_rate; + unsigned int exclusive_count; struct hlist_node clks_node; }; @@ -141,10 +144,18 @@ static unsigned long clk_enable_lock(void) { unsigned long flags; - if (!spin_trylock_irqsave(&enable_lock, flags)) { + /* + * On UP systems, spin_trylock_irqsave() always returns true, even if + * we already hold the lock. So, in that case, we rely only on + * reference counting. + */ + if (!IS_ENABLED(CONFIG_SMP) || + !spin_trylock_irqsave(&enable_lock, flags)) { if (enable_owner == current) { enable_refcnt++; __acquire(enable_lock); + if (!IS_ENABLED(CONFIG_SMP)) + local_save_flags(flags); return flags; } spin_lock_irqsave(&enable_lock, flags); @@ -170,6 +181,11 @@ static void clk_enable_unlock(unsigned long flags) spin_unlock_irqrestore(&enable_lock, flags); } +static bool clk_core_rate_is_protected(struct clk_core *core) +{ + return core->protect_count; +} + static bool clk_core_is_prepared(struct clk_core *core) { bool ret = false; @@ -382,6 +398,11 @@ bool clk_hw_is_prepared(const struct clk_hw *hw) return clk_core_is_prepared(hw->core); } +bool clk_hw_rate_is_protected(const struct clk_hw *hw) +{ + return clk_core_rate_is_protected(hw->core); +} + bool clk_hw_is_enabled(const struct clk_hw *hw) { return clk_core_is_enabled(hw->core); @@ -520,6 +541,139 @@ EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest); /*** clk api ***/ +static void clk_core_rate_unprotect(struct clk_core *core) +{ + lockdep_assert_held(&prepare_lock); + + if (!core) + return; + + if (WARN_ON(core->protect_count == 0)) + return; + + if (--core->protect_count > 0) + return; + + clk_core_rate_unprotect(core->parent); +} + +static int clk_core_rate_nuke_protect(struct clk_core *core) +{ + int ret; + + lockdep_assert_held(&prepare_lock); + + if (!core) + return -EINVAL; + + if (core->protect_count == 0) + return 0; + + ret = core->protect_count; + core->protect_count = 1; + clk_core_rate_unprotect(core); + + return ret; +} + +/** + * clk_rate_exclusive_put - release exclusivity over clock rate control + * @clk: the clk over which the exclusivity is released + * + * clk_rate_exclusive_put() completes a critical section during which a clock + * consumer cannot tolerate any other consumer making any operation on the + * clock which could result in a rate change or rate glitch. Exclusive clocks + * cannot have their rate changed, either directly or indirectly due to changes + * further up the parent chain of clocks. As a result, clocks up parent chain + * also get under exclusive control of the calling consumer. + * + * If exlusivity is claimed more than once on clock, even by the same consumer, + * the rate effectively gets locked as exclusivity can't be preempted. + * + * Calls to clk_rate_exclusive_put() must be balanced with calls to + * clk_rate_exclusive_get(). Calls to this function may sleep, and do not return + * error status. + */ +void clk_rate_exclusive_put(struct clk *clk) +{ + if (!clk) + return; + + clk_prepare_lock(); + + /* + * if there is something wrong with this consumer protect count, stop + * here before messing with the provider + */ + if (WARN_ON(clk->exclusive_count <= 0)) + goto out; + + clk_core_rate_unprotect(clk->core); + clk->exclusive_count--; +out: + clk_prepare_unlock(); +} +EXPORT_SYMBOL_GPL(clk_rate_exclusive_put); + +static void clk_core_rate_protect(struct clk_core *core) +{ + lockdep_assert_held(&prepare_lock); + + if (!core) + return; + + if (core->protect_count == 0) + clk_core_rate_protect(core->parent); + + core->protect_count++; +} + +static void clk_core_rate_restore_protect(struct clk_core *core, int count) +{ + lockdep_assert_held(&prepare_lock); + + if (!core) + return; + + if (count == 0) + return; + + clk_core_rate_protect(core); + core->protect_count = count; +} + +/** + * clk_rate_exclusive_get - get exclusivity over the clk rate control + * @clk: the clk over which the exclusity of rate control is requested + * + * clk_rate_exlusive_get() begins a critical section during which a clock + * consumer cannot tolerate any other consumer making any operation on the + * clock which could result in a rate change or rate glitch. Exclusive clocks + * cannot have their rate changed, either directly or indirectly due to changes + * further up the parent chain of clocks. As a result, clocks up parent chain + * also get under exclusive control of the calling consumer. + * + * If exlusivity is claimed more than once on clock, even by the same consumer, + * the rate effectively gets locked as exclusivity can't be preempted. + * + * Calls to clk_rate_exclusive_get() should be balanced with calls to + * clk_rate_exclusive_put(). Calls to this function may sleep. + * Returns 0 on success, -EERROR otherwise + */ +int clk_rate_exclusive_get(struct clk *clk) +{ + if (!clk) + return 0; + + clk_prepare_lock(); + clk_core_rate_protect(clk->core); + clk->exclusive_count++; + clk_prepare_unlock(); + + return 0; +} +EXPORT_SYMBOL_GPL(clk_rate_exclusive_get); + static void clk_core_unprepare(struct clk_core *core) { lockdep_assert_held(&prepare_lock); @@ -906,10 +1060,9 @@ static int clk_disable_unused(void) } late_initcall_sync(clk_disable_unused); -static int clk_core_round_rate_nolock(struct clk_core *core, - struct clk_rate_request *req) +static int clk_core_determine_round_nolock(struct clk_core *core, + struct clk_rate_request *req) { - struct clk_core *parent; long rate; lockdep_assert_held(&prepare_lock); @@ -917,6 +1070,38 @@ static int clk_core_round_rate_nolock(struct clk_core *core, if (!core) return 0; + /* + * At this point, core protection will be disabled if + * - if the provider is not protected at all + * - if the calling consumer is the only one which has exclusivity + * over the provider + */ + if (clk_core_rate_is_protected(core)) { + req->rate = core->rate; + } else if (core->ops->determine_rate) { + return core->ops->determine_rate(core->hw, req); + } else if (core->ops->round_rate) { + rate = core->ops->round_rate(core->hw, req->rate, + &req->best_parent_rate); + if (rate < 0) + return rate; + + req->rate = rate; + } else { + return -EINVAL; + } + + return 0; +} + +static void clk_core_init_rate_req(struct clk_core * const core, + struct clk_rate_request *req) +{ + struct clk_core *parent; + + if (WARN_ON(!core || !req)) + return; + parent = core->parent; if (parent) { req->best_parent_hw = parent->hw; @@ -925,22 +1110,32 @@ static int clk_core_round_rate_nolock(struct clk_core *core, req->best_parent_hw = NULL; req->best_parent_rate = 0; } +} - if (core->ops->determine_rate) { - return core->ops->determine_rate(core->hw, req); - } else if (core->ops->round_rate) { - rate = core->ops->round_rate(core->hw, req->rate, - &req->best_parent_rate); - if (rate < 0) - return rate; +static bool clk_core_can_round(struct clk_core * const core) +{ + if (core->ops->determine_rate || core->ops->round_rate) + return true; - req->rate = rate; - } else if (core->flags & CLK_SET_RATE_PARENT) { - return clk_core_round_rate_nolock(parent, req); - } else { - req->rate = core->rate; - } + return false; +} +static int clk_core_round_rate_nolock(struct clk_core *core, + struct clk_rate_request *req) +{ + lockdep_assert_held(&prepare_lock); + + if (!core) + return 0; + + clk_core_init_rate_req(core, req); + + if (clk_core_can_round(core)) + return clk_core_determine_round_nolock(core, req); + else if (core->flags & CLK_SET_RATE_PARENT) + return clk_core_round_rate_nolock(core->parent, req); + + req->rate = core->rate; return 0; } @@ -997,10 +1192,17 @@ long clk_round_rate(struct clk *clk, unsigned long rate) clk_prepare_lock(); + if (clk->exclusive_count) + clk_core_rate_unprotect(clk->core); + clk_core_get_boundaries(clk->core, &req.min_rate, &req.max_rate); req.rate = rate; ret = clk_core_round_rate_nolock(clk->core, &req); + + if (clk->exclusive_count) + clk_core_rate_protect(clk->core); + clk_prepare_unlock(); if (ret) @@ -1433,34 +1635,23 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core, clk_core_get_boundaries(core, &min_rate, &max_rate); /* find the closest rate and parent clk/rate */ - if (core->ops->determine_rate) { + if (clk_core_can_round(core)) { struct clk_rate_request req; req.rate = rate; req.min_rate = min_rate; req.max_rate = max_rate; - if (parent) { - req.best_parent_hw = parent->hw; - req.best_parent_rate = parent->rate; - } else { - req.best_parent_hw = NULL; - req.best_parent_rate = 0; - } - ret = core->ops->determine_rate(core->hw, &req); + clk_core_init_rate_req(core, &req); + + ret = clk_core_determine_round_nolock(core, &req); if (ret < 0) return NULL; best_parent_rate = req.best_parent_rate; new_rate = req.rate; parent = req.best_parent_hw ? req.best_parent_hw->core : NULL; - } else if (core->ops->round_rate) { - ret = core->ops->round_rate(core->hw, rate, - &best_parent_rate); - if (ret < 0) - return NULL; - new_rate = ret; if (new_rate < min_rate || new_rate > max_rate) return NULL; } else if (!parent || !(core->flags & CLK_SET_RATE_PARENT)) { @@ -1642,25 +1833,58 @@ static void clk_change_rate(struct clk_core *core) clk_pm_runtime_put(core); } +static unsigned long clk_core_req_round_rate_nolock(struct clk_core *core, + unsigned long req_rate) +{ + int ret, cnt; + struct clk_rate_request req; + + lockdep_assert_held(&prepare_lock); + + if (!core) + return 0; + + /* simulate what the rate would be if it could be freely set */ + cnt = clk_core_rate_nuke_protect(core); + if (cnt < 0) + return cnt; + + clk_core_get_boundaries(core, &req.min_rate, &req.max_rate); + req.rate = req_rate; + + ret = clk_core_round_rate_nolock(core, &req); + + /* restore the protection */ + clk_core_rate_restore_protect(core, cnt); + + return ret ? 0 : req.rate; +} + static int clk_core_set_rate_nolock(struct clk_core *core, unsigned long req_rate) { struct clk_core *top, *fail_clk; - unsigned long rate = req_rate; + unsigned long rate; int ret = 0; if (!core) return 0; + rate = clk_core_req_round_rate_nolock(core, req_rate); + /* bail early if nothing to do */ if (rate == clk_core_get_rate_nolock(core)) return 0; + /* fail on a direct rate set of a protected provider */ + if (clk_core_rate_is_protected(core)) + return -EBUSY; + if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count) return -EBUSY; /* calculate new rates and get the topmost changed clock */ - top = clk_calc_new_rates(core, rate); + top = clk_calc_new_rates(core, req_rate); if (!top) return -EINVAL; @@ -1719,14 +1943,67 @@ int clk_set_rate(struct clk *clk, unsigned long rate) /* prevent racing with updates to the clock topology */ clk_prepare_lock(); + if (clk->exclusive_count) + clk_core_rate_unprotect(clk->core); + ret = clk_core_set_rate_nolock(clk->core, rate); + if (clk->exclusive_count) + clk_core_rate_protect(clk->core); + clk_prepare_unlock(); return ret; } EXPORT_SYMBOL_GPL(clk_set_rate); +/** + * clk_set_rate_exclusive - specify a new rate get exclusive control + * @clk: the clk whose rate is being changed + * @rate: the new rate for clk + * + * This is a combination of clk_set_rate() and clk_rate_exclusive_get() + * within a critical section + * + * This can be used initially to ensure that at least 1 consumer is + * statisfied when several consumers are competing for exclusivity over the + * same clock provider. + * + * The exclusivity is not applied if setting the rate failed. + * + * Calls to clk_rate_exclusive_get() should be balanced with calls to + * clk_rate_exclusive_put(). + * + * Returns 0 on success, -EERROR otherwise. + */ +int clk_set_rate_exclusive(struct clk *clk, unsigned long rate) +{ + int ret; + + if (!clk) + return 0; + + /* prevent racing with updates to the clock topology */ + clk_prepare_lock(); + + /* + * The temporary protection removal is not here, on purpose + * This function is meant to be used instead of clk_rate_protect, + * so before the consumer code path protect the clock provider + */ + + ret = clk_core_set_rate_nolock(clk->core, rate); + if (!ret) { + clk_core_rate_protect(clk->core); + clk->exclusive_count++; + } + + clk_prepare_unlock(); + + return ret; +} +EXPORT_SYMBOL_GPL(clk_set_rate_exclusive); + /** * clk_set_rate_range - set a rate range for a clock source * @clk: clock source @@ -1738,6 +2015,7 @@ EXPORT_SYMBOL_GPL(clk_set_rate); int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max) { int ret = 0; + unsigned long old_min, old_max, rate; if (!clk) return 0; @@ -1751,12 +2029,46 @@ int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max) clk_prepare_lock(); - if (min != clk->min_rate || max != clk->max_rate) { - clk->min_rate = min; - clk->max_rate = max; - ret = clk_core_set_rate_nolock(clk->core, clk->core->req_rate); + if (clk->exclusive_count) + clk_core_rate_unprotect(clk->core); + + /* Save the current values in case we need to rollback the change */ + old_min = clk->min_rate; + old_max = clk->max_rate; + clk->min_rate = min; + clk->max_rate = max; + + rate = clk_core_get_rate_nolock(clk->core); + if (rate < min || rate > max) { + /* + * FIXME: + * We are in bit of trouble here, current rate is outside the + * the requested range. We are going try to request appropriate + * range boundary but there is a catch. It may fail for the + * usual reason (clock broken, clock protected, etc) but also + * because: + * - round_rate() was not favorable and fell on the wrong + * side of the boundary + * - the determine_rate() callback does not really check for + * this corner case when determining the rate + */ + + if (rate < min) + rate = min; + else + rate = max; + + ret = clk_core_set_rate_nolock(clk->core, rate); + if (ret) { + /* rollback the changes */ + clk->min_rate = old_min; + clk->max_rate = old_max; + } } + if (clk->exclusive_count) + clk_core_rate_protect(clk->core); + clk_prepare_unlock(); return ret; @@ -1877,32 +2189,31 @@ bool clk_has_parent(struct clk *clk, struct clk *parent) } EXPORT_SYMBOL_GPL(clk_has_parent); -static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent) +static int clk_core_set_parent_nolock(struct clk_core *core, + struct clk_core *parent) { int ret = 0; int p_index = 0; unsigned long p_rate = 0; + lockdep_assert_held(&prepare_lock); + if (!core) return 0; - /* prevent racing with updates to the clock topology */ - clk_prepare_lock(); - if (core->parent == parent) - goto out; + return 0; /* verify ops for for multi-parent clks */ - if ((core->num_parents > 1) && (!core->ops->set_parent)) { - ret = -ENOSYS; - goto out; - } + if (core->num_parents > 1 && !core->ops->set_parent) + return -EPERM; /* check that we are allowed to re-parent if the clock is in use */ - if ((core->flags & CLK_SET_PARENT_GATE) && core->prepare_count) { - ret = -EBUSY; - goto out; - } + if ((core->flags & CLK_SET_PARENT_GATE) && core->prepare_count) + return -EBUSY; + + if (clk_core_rate_is_protected(core)) + return -EBUSY; /* try finding the new parent index */ if (parent) { @@ -1910,15 +2221,14 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent) if (p_index < 0) { pr_debug("%s: clk %s can not be parent of clk %s\n", __func__, parent->name, core->name); - ret = p_index; - goto out; + return p_index; } p_rate = parent->rate; } ret = clk_pm_runtime_get(core); if (ret) - goto out; + return ret; /* propagate PRE_RATE_CHANGE notifications */ ret = __clk_speculate_rates(core, p_rate); @@ -1940,8 +2250,6 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent) runtime_put: clk_pm_runtime_put(core); -out: - clk_prepare_unlock(); return ret; } @@ -1965,13 +2273,50 @@ out: */ int clk_set_parent(struct clk *clk, struct clk *parent) { + int ret; + if (!clk) return 0; - return clk_core_set_parent(clk->core, parent ? parent->core : NULL); + clk_prepare_lock(); + + if (clk->exclusive_count) + clk_core_rate_unprotect(clk->core); + + ret = clk_core_set_parent_nolock(clk->core, + parent ? parent->core : NULL); + + if (clk->exclusive_count) + clk_core_rate_protect(clk->core); + + clk_prepare_unlock(); + + return ret; } EXPORT_SYMBOL_GPL(clk_set_parent); +static int clk_core_set_phase_nolock(struct clk_core *core, int degrees) +{ + int ret = -EINVAL; + + lockdep_assert_held(&prepare_lock); + + if (!core) + return 0; + + if (clk_core_rate_is_protected(core)) + return -EBUSY; + + trace_clk_set_phase(core, degrees); + + if (core->ops->set_phase) + ret = core->ops->set_phase(core->hw, degrees); + + trace_clk_set_phase_complete(core, degrees); + + return ret; +} + /** * clk_set_phase - adjust the phase shift of a clock signal * @clk: clock signal source @@ -1994,7 +2339,7 @@ EXPORT_SYMBOL_GPL(clk_set_parent); */ int clk_set_phase(struct clk *clk, int degrees) { - int ret = -EINVAL; + int ret; if (!clk) return 0; @@ -2006,15 +2351,13 @@ int clk_set_phase(struct clk *clk, int degrees) clk_prepare_lock(); - trace_clk_set_phase(clk->core, degrees); + if (clk->exclusive_count) + clk_core_rate_unprotect(clk->core); - if (clk->core->ops->set_phase) - ret = clk->core->ops->set_phase(clk->core->hw, degrees); + ret = clk_core_set_phase_nolock(clk->core, degrees); - trace_clk_set_phase_complete(clk->core, degrees); - - if (!ret) - clk->core->phase = degrees; + if (clk->exclusive_count) + clk_core_rate_protect(clk->core); clk_prepare_unlock(); @@ -2102,11 +2445,12 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c, if (!c) return; - seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu %-3d\n", + seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %-3d\n", level * 3 + 1, "", 30 - level * 3, c->name, - c->enable_count, c->prepare_count, clk_core_get_rate(c), - clk_core_get_accuracy(c), clk_core_get_phase(c)); + c->enable_count, c->prepare_count, c->protect_count, + clk_core_get_rate(c), clk_core_get_accuracy(c), + clk_core_get_phase(c)); } static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c, @@ -2128,7 +2472,8 @@ static int clk_summary_show(struct seq_file *s, void *data) struct clk_core *c; struct hlist_head **lists = (struct hlist_head **)s->private; - seq_puts(s, " clock enable_cnt prepare_cnt rate accuracy phase\n"); + seq_puts(s, " enable prepare protect \n"); + seq_puts(s, " clock count count count rate accuracy phase\n"); seq_puts(s, "----------------------------------------------------------------------------------------\n"); clk_prepare_lock(); @@ -2164,6 +2509,7 @@ static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level) seq_printf(s, "\"%s\": { ", c->name); seq_printf(s, "\"enable_count\": %d,", c->enable_count); seq_printf(s, "\"prepare_count\": %d,", c->prepare_count); + seq_printf(s, "\"protect_count\": %d,", c->protect_count); seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c)); seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c)); seq_printf(s, "\"phase\": %d", clk_core_get_phase(c)); @@ -2223,6 +2569,58 @@ static const struct file_operations clk_dump_fops = { .release = single_release, }; +static const struct { + unsigned long flag; + const char *name; +} clk_flags[] = { +#define ENTRY(f) { f, __stringify(f) } + ENTRY(CLK_SET_RATE_GATE), + ENTRY(CLK_SET_PARENT_GATE), + ENTRY(CLK_SET_RATE_PARENT), + ENTRY(CLK_IGNORE_UNUSED), + ENTRY(CLK_IS_BASIC), + ENTRY(CLK_GET_RATE_NOCACHE), + ENTRY(CLK_SET_RATE_NO_REPARENT), + ENTRY(CLK_GET_ACCURACY_NOCACHE), + ENTRY(CLK_RECALC_NEW_RATES), + ENTRY(CLK_SET_RATE_UNGATE), + ENTRY(CLK_IS_CRITICAL), + ENTRY(CLK_OPS_PARENT_ENABLE), +#undef ENTRY +}; + +static int clk_flags_dump(struct seq_file *s, void *data) +{ + struct clk_core *core = s->private; + unsigned long flags = core->flags; + unsigned int i; + + for (i = 0; flags && i < ARRAY_SIZE(clk_flags); i++) { + if (flags & clk_flags[i].flag) { + seq_printf(s, "%s\n", clk_flags[i].name); + flags &= ~clk_flags[i].flag; + } + } + if (flags) { + /* Unknown flags */ + seq_printf(s, "0x%lx\n", flags); + } + + return 0; +} + +static int clk_flags_open(struct inode *inode, struct file *file) +{ + return single_open(file, clk_flags_dump, inode->i_private); +} + +static const struct file_operations clk_flags_fops = { + .open = clk_flags_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int possible_parents_dump(struct seq_file *s, void *data) { struct clk_core *core = s->private; @@ -2264,43 +2662,46 @@ static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) core->dentry = d; - d = debugfs_create_u32("clk_rate", S_IRUGO, core->dentry, - (u32 *)&core->rate); + d = debugfs_create_ulong("clk_rate", 0444, core->dentry, &core->rate); if (!d) goto err_out; - d = debugfs_create_u32("clk_accuracy", S_IRUGO, core->dentry, - (u32 *)&core->accuracy); + d = debugfs_create_ulong("clk_accuracy", 0444, core->dentry, + &core->accuracy); if (!d) goto err_out; - d = debugfs_create_u32("clk_phase", S_IRUGO, core->dentry, - (u32 *)&core->phase); + d = debugfs_create_u32("clk_phase", 0444, core->dentry, &core->phase); if (!d) goto err_out; - d = debugfs_create_x32("clk_flags", S_IRUGO, core->dentry, - (u32 *)&core->flags); + d = debugfs_create_file("clk_flags", 0444, core->dentry, core, + &clk_flags_fops); if (!d) goto err_out; - d = debugfs_create_u32("clk_prepare_count", S_IRUGO, core->dentry, - (u32 *)&core->prepare_count); + d = debugfs_create_u32("clk_prepare_count", 0444, core->dentry, + &core->prepare_count); if (!d) goto err_out; - d = debugfs_create_u32("clk_enable_count", S_IRUGO, core->dentry, - (u32 *)&core->enable_count); + d = debugfs_create_u32("clk_enable_count", 0444, core->dentry, + &core->enable_count); if (!d) goto err_out; - d = debugfs_create_u32("clk_notifier_count", S_IRUGO, core->dentry, - (u32 *)&core->notifier_count); + d = debugfs_create_u32("clk_protect_count", 0444, core->dentry, + &core->protect_count); + if (!d) + goto err_out; + + d = debugfs_create_u32("clk_notifier_count", 0444, core->dentry, + &core->notifier_count); if (!d) goto err_out; if (core->num_parents > 1) { - d = debugfs_create_file("clk_possible_parents", S_IRUGO, + d = debugfs_create_file("clk_possible_parents", 0444, core->dentry, core, &possible_parents_fops); if (!d) goto err_out; @@ -2336,12 +2737,8 @@ static int clk_debug_register(struct clk_core *core) mutex_lock(&clk_debug_lock); hlist_add_head(&core->debug_node, &clk_debug_list); - - if (!inited) - goto unlock; - - ret = clk_debug_create_one(core, rootdir); -unlock: + if (inited) + ret = clk_debug_create_one(core, rootdir); mutex_unlock(&clk_debug_lock); return ret; @@ -2396,22 +2793,22 @@ static int __init clk_debug_init(void) if (!rootdir) return -ENOMEM; - d = debugfs_create_file("clk_summary", S_IRUGO, rootdir, &all_lists, + d = debugfs_create_file("clk_summary", 0444, rootdir, &all_lists, &clk_summary_fops); if (!d) return -ENOMEM; - d = debugfs_create_file("clk_dump", S_IRUGO, rootdir, &all_lists, + d = debugfs_create_file("clk_dump", 0444, rootdir, &all_lists, &clk_dump_fops); if (!d) return -ENOMEM; - d = debugfs_create_file("clk_orphan_summary", S_IRUGO, rootdir, + d = debugfs_create_file("clk_orphan_summary", 0444, rootdir, &orphan_list, &clk_summary_fops); if (!d) return -ENOMEM; - d = debugfs_create_file("clk_orphan_dump", S_IRUGO, rootdir, + d = debugfs_create_file("clk_orphan_dump", 0444, rootdir, &orphan_list, &clk_dump_fops); if (!d) return -ENOMEM; @@ -2576,14 +2973,17 @@ static int __clk_core_init(struct clk_core *core) */ hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) { struct clk_core *parent = __clk_init_parent(orphan); + unsigned long flags; /* * we could call __clk_set_parent, but that would result in a * redundant call to the .set_rate op, if it exists */ if (parent) { - __clk_set_parent_before(orphan, parent); - __clk_set_parent_after(orphan, parent, NULL); + /* update the clk tree topology */ + flags = clk_enable_lock(); + clk_reparent(orphan, parent); + clk_enable_unlock(flags); __clk_recalc_accuracies(orphan); __clk_recalc_rates(orphan, 0); } @@ -2684,7 +3084,13 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) ret = -ENOMEM; goto fail_name; } + + if (WARN_ON(!hw->init->ops)) { + ret = -EINVAL; + goto fail_ops; + } core->ops = hw->init->ops; + if (dev && pm_runtime_enabled(dev)) core->dev = dev; if (dev && dev->driver) @@ -2746,6 +3152,7 @@ fail_parent_names_copy: kfree_const(core->parent_names[i]); kfree(core->parent_names); fail_parent_names: +fail_ops: kfree_const(core->name); fail_name: kfree(core); @@ -2857,7 +3264,7 @@ void clk_unregister(struct clk *clk) /* Reparent all children to the orphan list. */ hlist_for_each_entry_safe(child, t, &clk->core->children, child_node) - clk_core_set_parent(child, NULL); + clk_core_set_parent_nolock(child, NULL); } hlist_del_init(&clk->core->child_node); @@ -2865,6 +3272,11 @@ void clk_unregister(struct clk *clk) if (clk->core->prepare_count) pr_warn("%s: unregistering prepared clock: %s\n", __func__, clk->core->name); + + if (clk->core->protect_count) + pr_warn("%s: unregistering protected clock: %s\n", + __func__, clk->core->name); + kref_put(&clk->core->ref, __clk_release); unlock: clk_prepare_unlock(); @@ -3023,6 +3435,18 @@ void __clk_put(struct clk *clk) clk_prepare_lock(); + /* + * Before calling clk_put, all calls to clk_rate_exclusive_get() from a + * given user should be balanced with calls to clk_rate_exclusive_put() + * and by that same consumer + */ + if (WARN_ON(clk->exclusive_count)) { + /* We voiced our concern, let's sanitize the situation */ + clk->core->protect_count -= (clk->exclusive_count - 1); + clk_core_rate_unprotect(clk->core); + clk->exclusive_count = 0; + } + hlist_del(&clk->clks_node); if (clk->min_rate > clk->core->req_rate || clk->max_rate < clk->core->req_rate) @@ -3559,7 +3983,7 @@ static int parent_ready(struct device_node *np) * of_clk_detect_critical() - set CLK_IS_CRITICAL flag from Device Tree * @np: Device node pointer associated with clock provider * @index: clock index - * @flags: pointer to clk_core->flags + * @flags: pointer to top-level framework flags * * Detects if the clock-critical property exists and, if so, sets the * corresponding CLK_IS_CRITICAL flag. diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index 00b35a13cdf3..70c0ba6336c1 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h @@ -20,6 +20,8 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id, const char *con_id); void __clk_free_clk(struct clk *clk); +int __clk_get(struct clk *clk); +void __clk_put(struct clk *clk); #else /* All these casts to avoid ifdefs in clkdev... */ static inline struct clk * @@ -32,5 +34,7 @@ static struct clk_hw *__clk_get_hw(struct clk *clk) { return (struct clk_hw *)clk; } +static inline int __clk_get(struct clk *clk) { return 1; } +static inline void __clk_put(struct clk *clk) { } #endif diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 6b2f29df3f70..7513411140b6 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -256,7 +256,7 @@ vclkdev_alloc(struct clk_hw *hw, const char *con_id, const char *dev_fmt, { struct clk_lookup_alloc *cla; - cla = __clkdev_alloc(sizeof(*cla)); + cla = kzalloc(sizeof(*cla), GFP_KERNEL); if (!cla) return NULL; diff --git a/drivers/clk/h8300/clk-div.c b/drivers/clk/h8300/clk-div.c index 4ae624425e9d..d413ade95c99 100644 --- a/drivers/clk/h8300/clk-div.c +++ b/drivers/clk/h8300/clk-div.c @@ -24,13 +24,13 @@ static void __init h8300_div_clk_setup(struct device_node *node) num_parents = of_clk_get_parent_count(node); if (!num_parents) { - pr_err("%s: no parent found", clk_name); + pr_err("%s: no parent found\n", clk_name); return; } divcr = of_iomap(node, 0); if (divcr == NULL) { - pr_err("%s: failed to map divide register", clk_name); + pr_err("%s: failed to map divide register\n", clk_name); goto error; } offset = (unsigned long)divcr & 3; diff --git a/drivers/clk/h8300/clk-h8s2678.c b/drivers/clk/h8300/clk-h8s2678.c index fc24b0b55a3d..b68045d8b921 100644 --- a/drivers/clk/h8300/clk-h8s2678.c +++ b/drivers/clk/h8300/clk-h8s2678.c @@ -93,7 +93,7 @@ static void __init h8s2678_pll_clk_setup(struct device_node *node) num_parents = of_clk_get_parent_count(node); if (!num_parents) { - pr_err("%s: no parent found", clk_name); + pr_err("%s: no parent found\n", clk_name); return; } @@ -104,13 +104,13 @@ static void __init h8s2678_pll_clk_setup(struct device_node *node) pll_clock->sckcr = of_iomap(node, 0); if (pll_clock->sckcr == NULL) { - pr_err("%s: failed to map divide register", clk_name); + pr_err("%s: failed to map divide register\n", clk_name); goto free_clock; } pll_clock->pllcr = of_iomap(node, 1); if (pll_clock->pllcr == NULL) { - pr_err("%s: failed to map multiply register", clk_name); + pr_err("%s: failed to map multiply register\n", clk_name); goto unmap_sckcr; } diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig index 7098bfd32b1b..1bd43550e4c8 100644 --- a/drivers/clk/hisilicon/Kconfig +++ b/drivers/clk/hisilicon/Kconfig @@ -49,3 +49,9 @@ config STUB_CLK_HI6220 default ARCH_HISI help Build the Hisilicon Hi6220 stub clock driver. + +config STUB_CLK_HI3660 + bool "Hi3660 Stub Clock Driver" + depends on COMMON_CLK_HI3660 && MAILBOX + help + Build the Hisilicon Hi3660 stub clock driver. diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile index 0e55612112af..4806fc2cb4ac 100644 --- a/drivers/clk/hisilicon/Makefile +++ b/drivers/clk/hisilicon/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_COMMON_CLK_HI3798CV200) += crg-hi3798cv200.o obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o obj-$(CONFIG_RESET_HISI) += reset.o obj-$(CONFIG_STUB_CLK_HI6220) += clk-hi6220-stub.o +obj-$(CONFIG_STUB_CLK_HI3660) += clk-hi3660-stub.o diff --git a/drivers/clk/hisilicon/clk-hi3660-stub.c b/drivers/clk/hisilicon/clk-hi3660-stub.c new file mode 100644 index 000000000000..9b6c72bbddf9 --- /dev/null +++ b/drivers/clk/hisilicon/clk-hi3660-stub.c @@ -0,0 +1,185 @@ +/* + * Hisilicon clock driver + * + * Copyright (c) 2013-2017 Hisilicon Limited. + * Copyright (c) 2017 Linaro Limited. + * + * Author: Kai Zhao + * Tao Wang + * Leo Yan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HI3660_STUB_CLOCK_DATA (0x70) +#define MHZ (1000 * 1000) + +#define DEFINE_CLK_STUB(_id, _cmd, _name) \ + { \ + .id = (_id), \ + .cmd = (_cmd), \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name, \ + .ops = &hi3660_stub_clk_ops, \ + .num_parents = 0, \ + .flags = CLK_GET_RATE_NOCACHE, \ + }, \ + }, + +#define to_stub_clk(_hw) container_of(_hw, struct hi3660_stub_clk, hw) + +struct hi3660_stub_clk_chan { + struct mbox_client cl; + struct mbox_chan *mbox; +}; + +struct hi3660_stub_clk { + unsigned int id; + struct clk_hw hw; + unsigned int cmd; + unsigned int msg[8]; + unsigned int rate; +}; + +static void __iomem *freq_reg; +static struct hi3660_stub_clk_chan stub_clk_chan; + +static unsigned long hi3660_stub_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct hi3660_stub_clk *stub_clk = to_stub_clk(hw); + + /* + * LPM3 writes back the CPU frequency in shared SRAM so read + * back the frequency. + */ + stub_clk->rate = readl(freq_reg + (stub_clk->id << 2)) * MHZ; + return stub_clk->rate; +} + +static long hi3660_stub_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + /* + * LPM3 handles rate rounding so just return whatever + * rate is requested. + */ + return rate; +} + +static int hi3660_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct hi3660_stub_clk *stub_clk = to_stub_clk(hw); + + stub_clk->msg[0] = stub_clk->cmd; + stub_clk->msg[1] = rate / MHZ; + + dev_dbg(stub_clk_chan.cl.dev, "set rate msg[0]=0x%x msg[1]=0x%x\n", + stub_clk->msg[0], stub_clk->msg[1]); + + mbox_send_message(stub_clk_chan.mbox, stub_clk->msg); + mbox_client_txdone(stub_clk_chan.mbox, 0); + + stub_clk->rate = rate; + return 0; +} + +static const struct clk_ops hi3660_stub_clk_ops = { + .recalc_rate = hi3660_stub_clk_recalc_rate, + .round_rate = hi3660_stub_clk_round_rate, + .set_rate = hi3660_stub_clk_set_rate, +}; + +static struct hi3660_stub_clk hi3660_stub_clks[HI3660_CLK_STUB_NUM] = { + DEFINE_CLK_STUB(HI3660_CLK_STUB_CLUSTER0, 0x0001030A, "cpu-cluster.0") + DEFINE_CLK_STUB(HI3660_CLK_STUB_CLUSTER1, 0x0002030A, "cpu-cluster.1") + DEFINE_CLK_STUB(HI3660_CLK_STUB_GPU, 0x0003030A, "clk-g3d") + DEFINE_CLK_STUB(HI3660_CLK_STUB_DDR, 0x00040309, "clk-ddrc") +}; + +static struct clk_hw *hi3660_stub_clk_hw_get(struct of_phandle_args *clkspec, + void *data) +{ + unsigned int idx = clkspec->args[0]; + + if (idx >= HI3660_CLK_STUB_NUM) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return &hi3660_stub_clks[idx].hw; +} + +static int hi3660_stub_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + unsigned int i; + int ret; + + /* Use mailbox client without blocking */ + stub_clk_chan.cl.dev = dev; + stub_clk_chan.cl.tx_done = NULL; + stub_clk_chan.cl.tx_block = false; + stub_clk_chan.cl.knows_txdone = false; + + /* Allocate mailbox channel */ + stub_clk_chan.mbox = mbox_request_channel(&stub_clk_chan.cl, 0); + if (IS_ERR(stub_clk_chan.mbox)) + return PTR_ERR(stub_clk_chan.mbox); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + freq_reg = devm_ioremap(dev, res->start, resource_size(res)); + if (!freq_reg) + return -ENOMEM; + + freq_reg += HI3660_STUB_CLOCK_DATA; + + for (i = 0; i < HI3660_CLK_STUB_NUM; i++) { + ret = devm_clk_hw_register(&pdev->dev, &hi3660_stub_clks[i].hw); + if (ret) + return ret; + } + + return devm_of_clk_add_hw_provider(&pdev->dev, hi3660_stub_clk_hw_get, + hi3660_stub_clks); +} + +static const struct of_device_id hi3660_stub_clk_of_match[] = { + { .compatible = "hisilicon,hi3660-stub-clk", }, + {} +}; + +static struct platform_driver hi3660_stub_clk_driver = { + .probe = hi3660_stub_clk_probe, + .driver = { + .name = "hi3660-stub-clk", + .of_match_table = hi3660_stub_clk_of_match, + }, +}; + +static int __init hi3660_stub_clk_init(void) +{ + return platform_driver_register(&hi3660_stub_clk_driver); +} +subsys_initcall(hi3660_stub_clk_init); diff --git a/drivers/clk/hisilicon/clkdivider-hi6220.c b/drivers/clk/hisilicon/clkdivider-hi6220.c index a1c1f684ad58..9f46cf9dcc65 100644 --- a/drivers/clk/hisilicon/clkdivider-hi6220.c +++ b/drivers/clk/hisilicon/clkdivider-hi6220.c @@ -56,7 +56,7 @@ static unsigned long hi6220_clkdiv_recalc_rate(struct clk_hw *hw, val &= div_mask(dclk->width); return divider_recalc_rate(hw, parent_rate, val, dclk->table, - CLK_DIVIDER_ROUND_CLOSEST); + CLK_DIVIDER_ROUND_CLOSEST, dclk->width); } static long hi6220_clkdiv_round_rate(struct clk_hw *hw, unsigned long rate, diff --git a/drivers/clk/imx/clk-imx51-imx53.c b/drivers/clk/imx/clk-imx51-imx53.c index 7bcaf270db11..c864992e6983 100644 --- a/drivers/clk/imx/clk-imx51-imx53.c +++ b/drivers/clk/imx/clk-imx51-imx53.c @@ -257,10 +257,6 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base) clk[IMX5_CLK_VPU_SEL] = imx_clk_mux("vpu_sel", MXC_CCM_CBCMR, 14, 2, vpu_sel, ARRAY_SIZE(vpu_sel)); clk[IMX5_CLK_VPU_GATE] = imx_clk_gate2("vpu_gate", "vpu_sel", MXC_CCM_CCGR5, 6); clk[IMX5_CLK_VPU_REFERENCE_GATE] = imx_clk_gate2("vpu_reference_gate", "osc", MXC_CCM_CCGR5, 8); - clk[IMX5_CLK_UART4_IPG_GATE] = imx_clk_gate2("uart4_ipg_gate", "ipg", MXC_CCM_CCGR7, 8); - clk[IMX5_CLK_UART4_PER_GATE] = imx_clk_gate2("uart4_per_gate", "uart_root", MXC_CCM_CCGR7, 10); - clk[IMX5_CLK_UART5_IPG_GATE] = imx_clk_gate2("uart5_ipg_gate", "ipg", MXC_CCM_CCGR7, 12); - clk[IMX5_CLK_UART5_PER_GATE] = imx_clk_gate2("uart5_per_gate", "uart_root", MXC_CCM_CCGR7, 14); clk[IMX5_CLK_GPC_DVFS] = imx_clk_gate2("gpc_dvfs", "dummy", MXC_CCM_CCGR5, 24); clk[IMX5_CLK_SSI_APM] = imx_clk_mux("ssi_apm", MXC_CCM_CSCMR1, 8, 2, ssi_apm_sels, ARRAY_SIZE(ssi_apm_sels)); @@ -361,6 +357,10 @@ static void __init mx50_clocks_init(struct device_node *np) clk[IMX5_CLK_USB_PHY1_GATE] = imx_clk_gate2("usb_phy1_gate", "usb_phy_sel", MXC_CCM_CCGR4, 10); clk[IMX5_CLK_USB_PHY2_GATE] = imx_clk_gate2("usb_phy2_gate", "usb_phy_sel", MXC_CCM_CCGR4, 12); clk[IMX5_CLK_I2C3_GATE] = imx_clk_gate2("i2c3_gate", "per_root", MXC_CCM_CCGR1, 22); + clk[IMX5_CLK_UART4_IPG_GATE] = imx_clk_gate2("uart4_ipg_gate", "ipg", MXC_CCM_CCGR7, 8); + clk[IMX5_CLK_UART4_PER_GATE] = imx_clk_gate2("uart4_per_gate", "uart_root", MXC_CCM_CCGR7, 10); + clk[IMX5_CLK_UART5_IPG_GATE] = imx_clk_gate2("uart5_ipg_gate", "ipg", MXC_CCM_CCGR7, 12); + clk[IMX5_CLK_UART5_PER_GATE] = imx_clk_gate2("uart5_per_gate", "uart_root", MXC_CCM_CCGR7, 14); clk[IMX5_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", MXC_CCM_CCOSR, 0, 4, mx53_cko1_sel, ARRAY_SIZE(mx53_cko1_sel)); @@ -562,6 +562,10 @@ static void __init mx53_clocks_init(struct device_node *np) clk[IMX5_CLK_IEEE1588_PRED] = imx_clk_divider("ieee1588_pred", "ieee1588_sel", MXC_CCM_CSCDR2, 6, 3); clk[IMX5_CLK_IEEE1588_PODF] = imx_clk_divider("ieee1588_podf", "ieee1588_pred", MXC_CCM_CSCDR2, 0, 6); clk[IMX5_CLK_IEEE1588_GATE] = imx_clk_gate2("ieee1588_serial_gate", "ieee1588_podf", MXC_CCM_CCGR7, 6); + clk[IMX5_CLK_UART4_IPG_GATE] = imx_clk_gate2("uart4_ipg_gate", "ipg", MXC_CCM_CCGR7, 8); + clk[IMX5_CLK_UART4_PER_GATE] = imx_clk_gate2("uart4_per_gate", "uart_root", MXC_CCM_CCGR7, 10); + clk[IMX5_CLK_UART5_IPG_GATE] = imx_clk_gate2("uart5_ipg_gate", "ipg", MXC_CCM_CCGR7, 12); + clk[IMX5_CLK_UART5_PER_GATE] = imx_clk_gate2("uart5_per_gate", "uart_root", MXC_CCM_CCGR7, 14); clk[IMX5_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", MXC_CCM_CCOSR, 0, 4, mx53_cko1_sel, ARRAY_SIZE(mx53_cko1_sel)); diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile index cd47b0664c2b..1456e4cdb562 100644 --- a/drivers/clk/ingenic/Makefile +++ b/drivers/clk/ingenic/Makefile @@ -1,3 +1,4 @@ obj-y += cgu.o obj-$(CONFIG_MACH_JZ4740) += jz4740-cgu.o +obj-$(CONFIG_MACH_JZ4770) += jz4770-cgu.o obj-$(CONFIG_MACH_JZ4780) += jz4780-cgu.o diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c index ab393637f7b0..56a712c9075f 100644 --- a/drivers/clk/ingenic/cgu.c +++ b/drivers/clk/ingenic/cgu.c @@ -100,15 +100,13 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) n += pll_info->n_offset; od_enc = ctl >> pll_info->od_shift; od_enc &= GENMASK(pll_info->od_bits - 1, 0); - bypass = !!(ctl & BIT(pll_info->bypass_bit)); + bypass = !pll_info->no_bypass_bit && + !!(ctl & BIT(pll_info->bypass_bit)); enable = !!(ctl & BIT(pll_info->enable_bit)); if (bypass) return parent_rate; - if (!enable) - return 0; - for (od = 0; od < pll_info->od_max; od++) { if (pll_info->od_encoding[od] == od_enc) break; @@ -152,17 +150,25 @@ ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info, return div_u64((u64)parent_rate * m, n * od); } -static long -ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate, - unsigned long *prate) +static inline const struct ingenic_cgu_clk_info *to_clk_info( + struct ingenic_clk *ingenic_clk) { - struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); struct ingenic_cgu *cgu = ingenic_clk->cgu; const struct ingenic_cgu_clk_info *clk_info; clk_info = &cgu->clock_info[ingenic_clk->idx]; BUG_ON(clk_info->type != CGU_CLK_PLL); + return clk_info; +} + +static long +ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate, + unsigned long *prate) +{ + struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); + const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk); + return ingenic_pll_calc(clk_info, req_rate, *prate, NULL, NULL, NULL); } @@ -170,19 +176,14 @@ static int ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate, unsigned long parent_rate) { - const unsigned timeout = 100; struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); struct ingenic_cgu *cgu = ingenic_clk->cgu; - const struct ingenic_cgu_clk_info *clk_info; - const struct ingenic_cgu_pll_info *pll_info; + const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk); + const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll; unsigned long rate, flags; - unsigned m, n, od, i; + unsigned int m, n, od; u32 ctl; - clk_info = &cgu->clock_info[ingenic_clk->idx]; - BUG_ON(clk_info->type != CGU_CLK_PLL); - pll_info = &clk_info->pll; - rate = ingenic_pll_calc(clk_info, req_rate, parent_rate, &m, &n, &od); if (rate != req_rate) @@ -201,6 +202,26 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate, ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift); ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift; + writel(ctl, cgu->base + pll_info->reg); + spin_unlock_irqrestore(&cgu->lock, flags); + + return 0; +} + +static int ingenic_pll_enable(struct clk_hw *hw) +{ + struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); + struct ingenic_cgu *cgu = ingenic_clk->cgu; + const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk); + const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll; + const unsigned int timeout = 100; + unsigned long flags; + unsigned int i; + u32 ctl; + + spin_lock_irqsave(&cgu->lock, flags); + ctl = readl(cgu->base + pll_info->reg); + ctl &= ~BIT(pll_info->bypass_bit); ctl |= BIT(pll_info->enable_bit); @@ -222,10 +243,48 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate, return 0; } +static void ingenic_pll_disable(struct clk_hw *hw) +{ + struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); + struct ingenic_cgu *cgu = ingenic_clk->cgu; + const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk); + const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll; + unsigned long flags; + u32 ctl; + + spin_lock_irqsave(&cgu->lock, flags); + ctl = readl(cgu->base + pll_info->reg); + + ctl &= ~BIT(pll_info->enable_bit); + + writel(ctl, cgu->base + pll_info->reg); + spin_unlock_irqrestore(&cgu->lock, flags); +} + +static int ingenic_pll_is_enabled(struct clk_hw *hw) +{ + struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); + struct ingenic_cgu *cgu = ingenic_clk->cgu; + const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk); + const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll; + unsigned long flags; + u32 ctl; + + spin_lock_irqsave(&cgu->lock, flags); + ctl = readl(cgu->base + pll_info->reg); + spin_unlock_irqrestore(&cgu->lock, flags); + + return !!(ctl & BIT(pll_info->enable_bit)); +} + static const struct clk_ops ingenic_pll_ops = { .recalc_rate = ingenic_pll_recalc_rate, .round_rate = ingenic_pll_round_rate, .set_rate = ingenic_pll_set_rate, + + .enable = ingenic_pll_enable, + .disable = ingenic_pll_disable, + .is_enabled = ingenic_pll_is_enabled, }; /* @@ -328,6 +387,8 @@ ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) div *= clk_info->div.div; rate /= div; + } else if (clk_info->type & CGU_CLK_FIXDIV) { + rate /= clk_info->fixdiv.div; } return rate; @@ -598,6 +659,7 @@ static int ingenic_register_clock(struct ingenic_cgu *cgu, unsigned idx) } } else if (caps & CGU_CLK_PLL) { clk_init.ops = &ingenic_pll_ops; + clk_init.flags |= CLK_SET_RATE_GATE; caps &= ~CGU_CLK_PLL; diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h index e78b586536ea..9da34910bd80 100644 --- a/drivers/clk/ingenic/cgu.h +++ b/drivers/clk/ingenic/cgu.h @@ -48,6 +48,7 @@ * @bypass_bit: the index of the bypass bit in the PLL control register * @enable_bit: the index of the enable bit in the PLL control register * @stable_bit: the index of the stable bit in the PLL control register + * @no_bypass_bit: if set, the PLL has no bypass functionality */ struct ingenic_cgu_pll_info { unsigned reg; @@ -58,6 +59,7 @@ struct ingenic_cgu_pll_info { u8 bypass_bit; u8 enable_bit; u8 stable_bit; + bool no_bypass_bit; }; /** @@ -120,7 +122,7 @@ struct ingenic_cgu_gate_info { * @clk_ops: custom clock operation callbacks */ struct ingenic_cgu_custom_info { - struct clk_ops *clk_ops; + const struct clk_ops *clk_ops; }; /** diff --git a/drivers/clk/ingenic/jz4770-cgu.c b/drivers/clk/ingenic/jz4770-cgu.c new file mode 100644 index 000000000000..c78d369b9403 --- /dev/null +++ b/drivers/clk/ingenic/jz4770-cgu.c @@ -0,0 +1,483 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * JZ4770 SoC CGU driver + * Copyright 2018, Paul Cercueil + */ + +#include +#include +#include +#include +#include +#include +#include "cgu.h" + +/* + * CPM registers offset address definition + */ +#define CGU_REG_CPCCR 0x00 +#define CGU_REG_LCR 0x04 +#define CGU_REG_CPPCR0 0x10 +#define CGU_REG_CLKGR0 0x20 +#define CGU_REG_OPCR 0x24 +#define CGU_REG_CLKGR1 0x28 +#define CGU_REG_CPPCR1 0x30 +#define CGU_REG_USBPCR1 0x48 +#define CGU_REG_USBCDR 0x50 +#define CGU_REG_I2SCDR 0x60 +#define CGU_REG_LPCDR 0x64 +#define CGU_REG_MSC0CDR 0x68 +#define CGU_REG_UHCCDR 0x6c +#define CGU_REG_SSICDR 0x74 +#define CGU_REG_CIMCDR 0x7c +#define CGU_REG_GPSCDR 0x80 +#define CGU_REG_PCMCDR 0x84 +#define CGU_REG_GPUCDR 0x88 +#define CGU_REG_MSC1CDR 0xA4 +#define CGU_REG_MSC2CDR 0xA8 +#define CGU_REG_BCHCDR 0xAC + +/* bits within the LCR register */ +#define LCR_LPM BIT(0) /* Low Power Mode */ + +/* bits within the OPCR register */ +#define OPCR_SPENDH BIT(5) /* UHC PHY suspend */ +#define OPCR_SPENDN BIT(7) /* OTG PHY suspend */ + +/* bits within the USBPCR1 register */ +#define USBPCR1_UHC_POWER BIT(5) /* UHC PHY power down */ + +static struct ingenic_cgu *cgu; + +static int jz4770_uhc_phy_enable(struct clk_hw *hw) +{ + void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; + void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1; + + writel(readl(reg_opcr) & ~OPCR_SPENDH, reg_opcr); + writel(readl(reg_usbpcr1) | USBPCR1_UHC_POWER, reg_usbpcr1); + return 0; +} + +static void jz4770_uhc_phy_disable(struct clk_hw *hw) +{ + void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; + void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1; + + writel(readl(reg_usbpcr1) & ~USBPCR1_UHC_POWER, reg_usbpcr1); + writel(readl(reg_opcr) | OPCR_SPENDH, reg_opcr); +} + +static int jz4770_uhc_phy_is_enabled(struct clk_hw *hw) +{ + void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; + void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1; + + return !(readl(reg_opcr) & OPCR_SPENDH) && + (readl(reg_usbpcr1) & USBPCR1_UHC_POWER); +} + +static const struct clk_ops jz4770_uhc_phy_ops = { + .enable = jz4770_uhc_phy_enable, + .disable = jz4770_uhc_phy_disable, + .is_enabled = jz4770_uhc_phy_is_enabled, +}; + +static int jz4770_otg_phy_enable(struct clk_hw *hw) +{ + void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; + + writel(readl(reg_opcr) | OPCR_SPENDN, reg_opcr); + + /* Wait for the clock to be stable */ + udelay(50); + return 0; +} + +static void jz4770_otg_phy_disable(struct clk_hw *hw) +{ + void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; + + writel(readl(reg_opcr) & ~OPCR_SPENDN, reg_opcr); +} + +static int jz4770_otg_phy_is_enabled(struct clk_hw *hw) +{ + void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; + + return !!(readl(reg_opcr) & OPCR_SPENDN); +} + +static const struct clk_ops jz4770_otg_phy_ops = { + .enable = jz4770_otg_phy_enable, + .disable = jz4770_otg_phy_disable, + .is_enabled = jz4770_otg_phy_is_enabled, +}; + +static const s8 pll_od_encoding[8] = { + 0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3, +}; + +static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = { + + /* External clocks */ + + [JZ4770_CLK_EXT] = { "ext", CGU_CLK_EXT }, + [JZ4770_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT }, + + /* PLLs */ + + [JZ4770_CLK_PLL0] = { + "pll0", CGU_CLK_PLL, + .parents = { JZ4770_CLK_EXT }, + .pll = { + .reg = CGU_REG_CPPCR0, + .m_shift = 24, + .m_bits = 7, + .m_offset = 1, + .n_shift = 18, + .n_bits = 5, + .n_offset = 1, + .od_shift = 16, + .od_bits = 2, + .od_max = 8, + .od_encoding = pll_od_encoding, + .bypass_bit = 9, + .enable_bit = 8, + .stable_bit = 10, + }, + }, + + [JZ4770_CLK_PLL1] = { + /* TODO: PLL1 can depend on PLL0 */ + "pll1", CGU_CLK_PLL, + .parents = { JZ4770_CLK_EXT }, + .pll = { + .reg = CGU_REG_CPPCR1, + .m_shift = 24, + .m_bits = 7, + .m_offset = 1, + .n_shift = 18, + .n_bits = 5, + .n_offset = 1, + .od_shift = 16, + .od_bits = 2, + .od_max = 8, + .od_encoding = pll_od_encoding, + .enable_bit = 7, + .stable_bit = 6, + .no_bypass_bit = true, + }, + }, + + /* Main clocks */ + + [JZ4770_CLK_CCLK] = { + "cclk", CGU_CLK_DIV, + .parents = { JZ4770_CLK_PLL0, }, + .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 }, + }, + [JZ4770_CLK_H0CLK] = { + "h0clk", CGU_CLK_DIV, + .parents = { JZ4770_CLK_PLL0, }, + .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 }, + }, + [JZ4770_CLK_H1CLK] = { + "h1clk", CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { JZ4770_CLK_PLL0, }, + .div = { CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1 }, + .gate = { CGU_REG_LCR, 30 }, + }, + [JZ4770_CLK_H2CLK] = { + "h2clk", CGU_CLK_DIV, + .parents = { JZ4770_CLK_PLL0, }, + .div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 }, + }, + [JZ4770_CLK_C1CLK] = { + "c1clk", CGU_CLK_DIV, + .parents = { JZ4770_CLK_PLL0, }, + .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 }, + }, + [JZ4770_CLK_PCLK] = { + "pclk", CGU_CLK_DIV, + .parents = { JZ4770_CLK_PLL0, }, + .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 }, + }, + + /* Those divided clocks can connect to PLL0 or PLL1 */ + + [JZ4770_CLK_MMC0_MUX] = { + "mmc0_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, + .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, + .mux = { CGU_REG_MSC0CDR, 30, 1 }, + .div = { CGU_REG_MSC0CDR, 0, 1, 7, -1, -1, 31 }, + .gate = { CGU_REG_MSC0CDR, 31 }, + }, + [JZ4770_CLK_MMC1_MUX] = { + "mmc1_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, + .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, + .mux = { CGU_REG_MSC1CDR, 30, 1 }, + .div = { CGU_REG_MSC1CDR, 0, 1, 7, -1, -1, 31 }, + .gate = { CGU_REG_MSC1CDR, 31 }, + }, + [JZ4770_CLK_MMC2_MUX] = { + "mmc2_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, + .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, + .mux = { CGU_REG_MSC2CDR, 30, 1 }, + .div = { CGU_REG_MSC2CDR, 0, 1, 7, -1, -1, 31 }, + .gate = { CGU_REG_MSC2CDR, 31 }, + }, + [JZ4770_CLK_CIM] = { + "cim", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, + .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, + .mux = { CGU_REG_CIMCDR, 31, 1 }, + .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 26 }, + }, + [JZ4770_CLK_UHC] = { + "uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, + .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, + .mux = { CGU_REG_UHCCDR, 29, 1 }, + .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 24 }, + }, + [JZ4770_CLK_GPU] = { + "gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, + .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, -1 }, + .mux = { CGU_REG_GPUCDR, 31, 1 }, + .div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR1, 9 }, + }, + [JZ4770_CLK_BCH] = { + "bch", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, + .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, + .mux = { CGU_REG_BCHCDR, 31, 1 }, + .div = { CGU_REG_BCHCDR, 0, 1, 3, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 1 }, + }, + [JZ4770_CLK_LPCLK_MUX] = { + "lpclk", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, + .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, + .mux = { CGU_REG_LPCDR, 29, 1 }, + .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 28 }, + }, + [JZ4770_CLK_GPS] = { + "gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, + .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, + .mux = { CGU_REG_GPSCDR, 31, 1 }, + .div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 22 }, + }, + + /* Those divided clocks can connect to EXT, PLL0 or PLL1 */ + + [JZ4770_CLK_SSI_MUX] = { + "ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX, + .parents = { JZ4770_CLK_EXT, -1, + JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 }, + .mux = { CGU_REG_SSICDR, 30, 2 }, + .div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1 }, + }, + [JZ4770_CLK_PCM_MUX] = { + "pcm_mux", CGU_CLK_DIV | CGU_CLK_MUX, + .parents = { JZ4770_CLK_EXT, -1, + JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 }, + .mux = { CGU_REG_PCMCDR, 30, 2 }, + .div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1 }, + }, + [JZ4770_CLK_I2S] = { + "i2s", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, + .parents = { JZ4770_CLK_EXT, -1, + JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 }, + .mux = { CGU_REG_I2SCDR, 30, 2 }, + .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR1, 13 }, + }, + [JZ4770_CLK_OTG] = { + "usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, + .parents = { JZ4770_CLK_EXT, -1, + JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 }, + .mux = { CGU_REG_USBCDR, 30, 2 }, + .div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 2 }, + }, + + /* Gate-only clocks */ + + [JZ4770_CLK_SSI0] = { + "ssi0", CGU_CLK_GATE, + .parents = { JZ4770_CLK_SSI_MUX, }, + .gate = { CGU_REG_CLKGR0, 4 }, + }, + [JZ4770_CLK_SSI1] = { + "ssi1", CGU_CLK_GATE, + .parents = { JZ4770_CLK_SSI_MUX, }, + .gate = { CGU_REG_CLKGR0, 19 }, + }, + [JZ4770_CLK_SSI2] = { + "ssi2", CGU_CLK_GATE, + .parents = { JZ4770_CLK_SSI_MUX, }, + .gate = { CGU_REG_CLKGR0, 20 }, + }, + [JZ4770_CLK_PCM0] = { + "pcm0", CGU_CLK_GATE, + .parents = { JZ4770_CLK_PCM_MUX, }, + .gate = { CGU_REG_CLKGR1, 8 }, + }, + [JZ4770_CLK_PCM1] = { + "pcm1", CGU_CLK_GATE, + .parents = { JZ4770_CLK_PCM_MUX, }, + .gate = { CGU_REG_CLKGR1, 10 }, + }, + [JZ4770_CLK_DMA] = { + "dma", CGU_CLK_GATE, + .parents = { JZ4770_CLK_H2CLK, }, + .gate = { CGU_REG_CLKGR0, 21 }, + }, + [JZ4770_CLK_I2C0] = { + "i2c0", CGU_CLK_GATE, + .parents = { JZ4770_CLK_EXT, }, + .gate = { CGU_REG_CLKGR0, 5 }, + }, + [JZ4770_CLK_I2C1] = { + "i2c1", CGU_CLK_GATE, + .parents = { JZ4770_CLK_EXT, }, + .gate = { CGU_REG_CLKGR0, 6 }, + }, + [JZ4770_CLK_I2C2] = { + "i2c2", CGU_CLK_GATE, + .parents = { JZ4770_CLK_EXT, }, + .gate = { CGU_REG_CLKGR1, 15 }, + }, + [JZ4770_CLK_UART0] = { + "uart0", CGU_CLK_GATE, + .parents = { JZ4770_CLK_EXT, }, + .gate = { CGU_REG_CLKGR0, 15 }, + }, + [JZ4770_CLK_UART1] = { + "uart1", CGU_CLK_GATE, + .parents = { JZ4770_CLK_EXT, }, + .gate = { CGU_REG_CLKGR0, 16 }, + }, + [JZ4770_CLK_UART2] = { + "uart2", CGU_CLK_GATE, + .parents = { JZ4770_CLK_EXT, }, + .gate = { CGU_REG_CLKGR0, 17 }, + }, + [JZ4770_CLK_UART3] = { + "uart3", CGU_CLK_GATE, + .parents = { JZ4770_CLK_EXT, }, + .gate = { CGU_REG_CLKGR0, 18 }, + }, + [JZ4770_CLK_IPU] = { + "ipu", CGU_CLK_GATE, + .parents = { JZ4770_CLK_H0CLK, }, + .gate = { CGU_REG_CLKGR0, 29 }, + }, + [JZ4770_CLK_ADC] = { + "adc", CGU_CLK_GATE, + .parents = { JZ4770_CLK_EXT, }, + .gate = { CGU_REG_CLKGR0, 14 }, + }, + [JZ4770_CLK_AIC] = { + "aic", CGU_CLK_GATE, + .parents = { JZ4770_CLK_EXT, }, + .gate = { CGU_REG_CLKGR0, 8 }, + }, + [JZ4770_CLK_AUX] = { + "aux", CGU_CLK_GATE, + .parents = { JZ4770_CLK_C1CLK, }, + .gate = { CGU_REG_CLKGR1, 14 }, + }, + [JZ4770_CLK_VPU] = { + "vpu", CGU_CLK_GATE, + .parents = { JZ4770_CLK_H1CLK, }, + .gate = { CGU_REG_CLKGR1, 7 }, + }, + [JZ4770_CLK_MMC0] = { + "mmc0", CGU_CLK_GATE, + .parents = { JZ4770_CLK_MMC0_MUX, }, + .gate = { CGU_REG_CLKGR0, 3 }, + }, + [JZ4770_CLK_MMC1] = { + "mmc1", CGU_CLK_GATE, + .parents = { JZ4770_CLK_MMC1_MUX, }, + .gate = { CGU_REG_CLKGR0, 11 }, + }, + [JZ4770_CLK_MMC2] = { + "mmc2", CGU_CLK_GATE, + .parents = { JZ4770_CLK_MMC2_MUX, }, + .gate = { CGU_REG_CLKGR0, 12 }, + }, + + /* Custom clocks */ + + [JZ4770_CLK_UHC_PHY] = { + "uhc_phy", CGU_CLK_CUSTOM, + .parents = { JZ4770_CLK_UHC, -1, -1, -1 }, + .custom = { &jz4770_uhc_phy_ops }, + }, + [JZ4770_CLK_OTG_PHY] = { + "usb_phy", CGU_CLK_CUSTOM, + .parents = { JZ4770_CLK_OTG, -1, -1, -1 }, + .custom = { &jz4770_otg_phy_ops }, + }, + + [JZ4770_CLK_EXT512] = { + "ext/512", CGU_CLK_FIXDIV, + .parents = { JZ4770_CLK_EXT }, + .fixdiv = { 512 }, + }, + + [JZ4770_CLK_RTC] = { + "rtc", CGU_CLK_MUX, + .parents = { JZ4770_CLK_EXT512, JZ4770_CLK_OSC32K, }, + .mux = { CGU_REG_OPCR, 2, 1}, + }, +}; + +#if IS_ENABLED(CONFIG_PM_SLEEP) +static int jz4770_cgu_pm_suspend(void) +{ + u32 val; + + val = readl(cgu->base + CGU_REG_LCR); + writel(val | LCR_LPM, cgu->base + CGU_REG_LCR); + return 0; +} + +static void jz4770_cgu_pm_resume(void) +{ + u32 val; + + val = readl(cgu->base + CGU_REG_LCR); + writel(val & ~LCR_LPM, cgu->base + CGU_REG_LCR); +} + +static struct syscore_ops jz4770_cgu_pm_ops = { + .suspend = jz4770_cgu_pm_suspend, + .resume = jz4770_cgu_pm_resume, +}; +#endif /* CONFIG_PM_SLEEP */ + +static void __init jz4770_cgu_init(struct device_node *np) +{ + int retval; + + cgu = ingenic_cgu_new(jz4770_cgu_clocks, + ARRAY_SIZE(jz4770_cgu_clocks), np); + if (!cgu) + pr_err("%s: failed to initialise CGU\n", __func__); + + retval = ingenic_cgu_register_clocks(cgu); + if (retval) + pr_err("%s: failed to register CGU Clocks\n", __func__); + +#if IS_ENABLED(CONFIG_PM_SLEEP) + register_syscore_ops(&jz4770_cgu_pm_ops); +#endif +} + +/* We only probe via devicetree, no need for a platform driver */ +CLK_OF_DECLARE(jz4770_cgu, "ingenic,jz4770-cgu", jz4770_cgu_init); diff --git a/drivers/clk/ingenic/jz4780-cgu.c b/drivers/clk/ingenic/jz4780-cgu.c index ac3585ed8228..6427be117ff1 100644 --- a/drivers/clk/ingenic/jz4780-cgu.c +++ b/drivers/clk/ingenic/jz4780-cgu.c @@ -203,7 +203,7 @@ static int jz4780_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate, return 0; } -static struct clk_ops jz4780_otg_phy_ops = { +static const struct clk_ops jz4780_otg_phy_ops = { .get_parent = jz4780_otg_phy_get_parent, .set_parent = jz4780_otg_phy_set_parent, diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 59dc0aad553c..1f9ea0f21df1 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -1,136 +1,140 @@ # -# MediaTek SoC drivers +# MediaTek Clock Drivers # +menu "Clock driver for MediaTek SoC" + depends on ARCH_MEDIATEK || COMPILE_TEST + config COMMON_CLK_MEDIATEK bool + select RESET_CONTROLLER ---help--- - Mediatek SoCs' clock support. + MediaTek SoCs' clock support. config COMMON_CLK_MT2701 - bool "Clock driver for Mediatek MT2701" + bool "Clock driver for MediaTek MT2701" depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK && ARM ---help--- - This driver supports Mediatek MT2701 basic clocks. + This driver supports MediaTek MT2701 basic clocks. config COMMON_CLK_MT2701_MMSYS - bool "Clock driver for Mediatek MT2701 mmsys" + bool "Clock driver for MediaTek MT2701 mmsys" depends on COMMON_CLK_MT2701 ---help--- - This driver supports Mediatek MT2701 mmsys clocks. + This driver supports MediaTek MT2701 mmsys clocks. config COMMON_CLK_MT2701_IMGSYS - bool "Clock driver for Mediatek MT2701 imgsys" + bool "Clock driver for MediaTek MT2701 imgsys" depends on COMMON_CLK_MT2701 ---help--- - This driver supports Mediatek MT2701 imgsys clocks. + This driver supports MediaTek MT2701 imgsys clocks. config COMMON_CLK_MT2701_VDECSYS - bool "Clock driver for Mediatek MT2701 vdecsys" + bool "Clock driver for MediaTek MT2701 vdecsys" depends on COMMON_CLK_MT2701 ---help--- - This driver supports Mediatek MT2701 vdecsys clocks. + This driver supports MediaTek MT2701 vdecsys clocks. config COMMON_CLK_MT2701_HIFSYS - bool "Clock driver for Mediatek MT2701 hifsys" + bool "Clock driver for MediaTek MT2701 hifsys" depends on COMMON_CLK_MT2701 ---help--- - This driver supports Mediatek MT2701 hifsys clocks. + This driver supports MediaTek MT2701 hifsys clocks. config COMMON_CLK_MT2701_ETHSYS - bool "Clock driver for Mediatek MT2701 ethsys" + bool "Clock driver for MediaTek MT2701 ethsys" depends on COMMON_CLK_MT2701 ---help--- - This driver supports Mediatek MT2701 ethsys clocks. + This driver supports MediaTek MT2701 ethsys clocks. config COMMON_CLK_MT2701_BDPSYS - bool "Clock driver for Mediatek MT2701 bdpsys" + bool "Clock driver for MediaTek MT2701 bdpsys" depends on COMMON_CLK_MT2701 ---help--- - This driver supports Mediatek MT2701 bdpsys clocks. + This driver supports MediaTek MT2701 bdpsys clocks. config COMMON_CLK_MT2712 - bool "Clock driver for Mediatek MT2712" + bool "Clock driver for MediaTek MT2712" depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK && ARM64 ---help--- - This driver supports Mediatek MT2712 basic clocks. + This driver supports MediaTek MT2712 basic clocks. config COMMON_CLK_MT2712_BDPSYS - bool "Clock driver for Mediatek MT2712 bdpsys" + bool "Clock driver for MediaTek MT2712 bdpsys" depends on COMMON_CLK_MT2712 ---help--- - This driver supports Mediatek MT2712 bdpsys clocks. + This driver supports MediaTek MT2712 bdpsys clocks. config COMMON_CLK_MT2712_IMGSYS - bool "Clock driver for Mediatek MT2712 imgsys" + bool "Clock driver for MediaTek MT2712 imgsys" depends on COMMON_CLK_MT2712 ---help--- - This driver supports Mediatek MT2712 imgsys clocks. + This driver supports MediaTek MT2712 imgsys clocks. config COMMON_CLK_MT2712_JPGDECSYS - bool "Clock driver for Mediatek MT2712 jpgdecsys" + bool "Clock driver for MediaTek MT2712 jpgdecsys" depends on COMMON_CLK_MT2712 ---help--- - This driver supports Mediatek MT2712 jpgdecsys clocks. + This driver supports MediaTek MT2712 jpgdecsys clocks. config COMMON_CLK_MT2712_MFGCFG - bool "Clock driver for Mediatek MT2712 mfgcfg" + bool "Clock driver for MediaTek MT2712 mfgcfg" depends on COMMON_CLK_MT2712 ---help--- - This driver supports Mediatek MT2712 mfgcfg clocks. + This driver supports MediaTek MT2712 mfgcfg clocks. config COMMON_CLK_MT2712_MMSYS - bool "Clock driver for Mediatek MT2712 mmsys" + bool "Clock driver for MediaTek MT2712 mmsys" depends on COMMON_CLK_MT2712 ---help--- - This driver supports Mediatek MT2712 mmsys clocks. + This driver supports MediaTek MT2712 mmsys clocks. config COMMON_CLK_MT2712_VDECSYS - bool "Clock driver for Mediatek MT2712 vdecsys" + bool "Clock driver for MediaTek MT2712 vdecsys" depends on COMMON_CLK_MT2712 ---help--- - This driver supports Mediatek MT2712 vdecsys clocks. + This driver supports MediaTek MT2712 vdecsys clocks. config COMMON_CLK_MT2712_VENCSYS - bool "Clock driver for Mediatek MT2712 vencsys" + bool "Clock driver for MediaTek MT2712 vencsys" depends on COMMON_CLK_MT2712 ---help--- - This driver supports Mediatek MT2712 vencsys clocks. + This driver supports MediaTek MT2712 vencsys clocks. config COMMON_CLK_MT6797 - bool "Clock driver for Mediatek MT6797" + bool "Clock driver for MediaTek MT6797" depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK && ARM64 ---help--- - This driver supports Mediatek MT6797 basic clocks. + This driver supports MediaTek MT6797 basic clocks. config COMMON_CLK_MT6797_MMSYS - bool "Clock driver for Mediatek MT6797 mmsys" + bool "Clock driver for MediaTek MT6797 mmsys" depends on COMMON_CLK_MT6797 ---help--- - This driver supports Mediatek MT6797 mmsys clocks. + This driver supports MediaTek MT6797 mmsys clocks. config COMMON_CLK_MT6797_IMGSYS - bool "Clock driver for Mediatek MT6797 imgsys" + bool "Clock driver for MediaTek MT6797 imgsys" depends on COMMON_CLK_MT6797 ---help--- - This driver supports Mediatek MT6797 imgsys clocks. + This driver supports MediaTek MT6797 imgsys clocks. config COMMON_CLK_MT6797_VDECSYS - bool "Clock driver for Mediatek MT6797 vdecsys" + bool "Clock driver for MediaTek MT6797 vdecsys" depends on COMMON_CLK_MT6797 ---help--- - This driver supports Mediatek MT6797 vdecsys clocks. + This driver supports MediaTek MT6797 vdecsys clocks. config COMMON_CLK_MT6797_VENCSYS - bool "Clock driver for Mediatek MT6797 vencsys" + bool "Clock driver for MediaTek MT6797 vencsys" depends on COMMON_CLK_MT6797 ---help--- - This driver supports Mediatek MT6797 vencsys clocks. + This driver supports MediaTek MT6797 vencsys clocks. config COMMON_CLK_MT7622 bool "Clock driver for MediaTek MT7622" @@ -163,17 +167,18 @@ config COMMON_CLK_MT7622_AUDSYS to audio consumers such as I2S and TDM. config COMMON_CLK_MT8135 - bool "Clock driver for Mediatek MT8135" + bool "Clock driver for MediaTek MT8135" depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK && ARM ---help--- - This driver supports Mediatek MT8135 clocks. + This driver supports MediaTek MT8135 clocks. config COMMON_CLK_MT8173 - bool "Clock driver for Mediatek MT8173" + bool "Clock driver for MediaTek MT8173" depends on ARCH_MEDIATEK || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK ---help--- - This driver supports Mediatek MT8173 clocks. + This driver supports MediaTek MT8173 clocks. +endmenu diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index c421ffcd49ff..5160fdc4bbb8 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -1,6 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o -obj-$(CONFIG_RESET_CONTROLLER) += reset.o +obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o reset.o obj-$(CONFIG_COMMON_CLK_MT6797) += clk-mt6797.o obj-$(CONFIG_COMMON_CLK_MT6797_IMGSYS) += clk-mt6797-img.o obj-$(CONFIG_COMMON_CLK_MT6797_MMSYS) += clk-mt6797-mm.o diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index f10250dcece4..f83c2bbb677e 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -20,6 +20,7 @@ #include struct clk; +struct clk_onecell_data; #define MAX_MUX_GATE_BIT 31 #define INVALID_MUX_GATE_BIT (MAX_MUX_GATE_BIT + 1) @@ -228,14 +229,7 @@ void mtk_clk_register_plls(struct device_node *node, struct clk *mtk_clk_register_ref2usb_tx(const char *name, const char *parent_name, void __iomem *reg); -#ifdef CONFIG_RESET_CONTROLLER void mtk_register_reset_controller(struct device_node *np, unsigned int num_regs, int regofs); -#else -static inline void mtk_register_reset_controller(struct device_node *np, - unsigned int num_regs, int regofs) -{ -} -#endif #endif /* __DRV_CLK_MTK_H */ diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index d2d0174a6eca..7694302c70a4 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -19,3 +19,11 @@ config COMMON_CLK_GXBB help Support for the clock controller on AmLogic S905 devices, aka gxbb. Say Y if you want peripherals and CPU frequency scaling to work. + +config COMMON_CLK_AXG + bool + depends on COMMON_CLK_AMLOGIC + select RESET_CONTROLLER + help + Support for the clock controller on AmLogic A113D devices, aka axg. + Say Y if you want peripherals and CPU frequency scaling to work. diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index b139d41b25da..3c03ce583798 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-cpu.o clk-mpll.o clk-audio-divider.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-regmap.o gxbb-aoclk-32k.o +obj-$(CONFIG_COMMON_CLK_AXG) += axg.o diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c new file mode 100644 index 000000000000..1294f3ad7cd5 --- /dev/null +++ b/drivers/clk/meson/axg.c @@ -0,0 +1,938 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * AmLogic Meson-AXG Clock Controller Driver + * + * Copyright (c) 2016 Baylibre SAS. + * Author: Michael Turquette + * + * Copyright (c) 2017 Amlogic, inc. + * Author: Qiufang Dai + */ + +#include +#include +#include +#include +#include +#include + +#include "clkc.h" +#include "axg.h" + +static DEFINE_SPINLOCK(meson_clk_lock); + +static const struct pll_rate_table sys_pll_rate_table[] = { + PLL_RATE(24000000, 56, 1, 2), + PLL_RATE(48000000, 64, 1, 2), + PLL_RATE(72000000, 72, 1, 2), + PLL_RATE(96000000, 64, 1, 2), + PLL_RATE(120000000, 80, 1, 2), + PLL_RATE(144000000, 96, 1, 2), + PLL_RATE(168000000, 56, 1, 1), + PLL_RATE(192000000, 64, 1, 1), + PLL_RATE(216000000, 72, 1, 1), + PLL_RATE(240000000, 80, 1, 1), + PLL_RATE(264000000, 88, 1, 1), + PLL_RATE(288000000, 96, 1, 1), + PLL_RATE(312000000, 52, 1, 2), + PLL_RATE(336000000, 56, 1, 2), + PLL_RATE(360000000, 60, 1, 2), + PLL_RATE(384000000, 64, 1, 2), + PLL_RATE(408000000, 68, 1, 2), + PLL_RATE(432000000, 72, 1, 2), + PLL_RATE(456000000, 76, 1, 2), + PLL_RATE(480000000, 80, 1, 2), + PLL_RATE(504000000, 84, 1, 2), + PLL_RATE(528000000, 88, 1, 2), + PLL_RATE(552000000, 92, 1, 2), + PLL_RATE(576000000, 96, 1, 2), + PLL_RATE(600000000, 50, 1, 1), + PLL_RATE(624000000, 52, 1, 1), + PLL_RATE(648000000, 54, 1, 1), + PLL_RATE(672000000, 56, 1, 1), + PLL_RATE(696000000, 58, 1, 1), + PLL_RATE(720000000, 60, 1, 1), + PLL_RATE(744000000, 62, 1, 1), + PLL_RATE(768000000, 64, 1, 1), + PLL_RATE(792000000, 66, 1, 1), + PLL_RATE(816000000, 68, 1, 1), + PLL_RATE(840000000, 70, 1, 1), + PLL_RATE(864000000, 72, 1, 1), + PLL_RATE(888000000, 74, 1, 1), + PLL_RATE(912000000, 76, 1, 1), + PLL_RATE(936000000, 78, 1, 1), + PLL_RATE(960000000, 80, 1, 1), + PLL_RATE(984000000, 82, 1, 1), + PLL_RATE(1008000000, 84, 1, 1), + PLL_RATE(1032000000, 86, 1, 1), + PLL_RATE(1056000000, 88, 1, 1), + PLL_RATE(1080000000, 90, 1, 1), + PLL_RATE(1104000000, 92, 1, 1), + PLL_RATE(1128000000, 94, 1, 1), + PLL_RATE(1152000000, 96, 1, 1), + PLL_RATE(1176000000, 98, 1, 1), + PLL_RATE(1200000000, 50, 1, 0), + PLL_RATE(1224000000, 51, 1, 0), + PLL_RATE(1248000000, 52, 1, 0), + PLL_RATE(1272000000, 53, 1, 0), + PLL_RATE(1296000000, 54, 1, 0), + PLL_RATE(1320000000, 55, 1, 0), + PLL_RATE(1344000000, 56, 1, 0), + PLL_RATE(1368000000, 57, 1, 0), + PLL_RATE(1392000000, 58, 1, 0), + PLL_RATE(1416000000, 59, 1, 0), + PLL_RATE(1440000000, 60, 1, 0), + PLL_RATE(1464000000, 61, 1, 0), + PLL_RATE(1488000000, 62, 1, 0), + PLL_RATE(1512000000, 63, 1, 0), + PLL_RATE(1536000000, 64, 1, 0), + PLL_RATE(1560000000, 65, 1, 0), + PLL_RATE(1584000000, 66, 1, 0), + PLL_RATE(1608000000, 67, 1, 0), + PLL_RATE(1632000000, 68, 1, 0), + PLL_RATE(1656000000, 68, 1, 0), + PLL_RATE(1680000000, 68, 1, 0), + PLL_RATE(1704000000, 68, 1, 0), + PLL_RATE(1728000000, 69, 1, 0), + PLL_RATE(1752000000, 69, 1, 0), + PLL_RATE(1776000000, 69, 1, 0), + PLL_RATE(1800000000, 69, 1, 0), + PLL_RATE(1824000000, 70, 1, 0), + PLL_RATE(1848000000, 70, 1, 0), + PLL_RATE(1872000000, 70, 1, 0), + PLL_RATE(1896000000, 70, 1, 0), + PLL_RATE(1920000000, 71, 1, 0), + PLL_RATE(1944000000, 71, 1, 0), + PLL_RATE(1968000000, 71, 1, 0), + PLL_RATE(1992000000, 71, 1, 0), + PLL_RATE(2016000000, 72, 1, 0), + PLL_RATE(2040000000, 72, 1, 0), + PLL_RATE(2064000000, 72, 1, 0), + PLL_RATE(2088000000, 72, 1, 0), + PLL_RATE(2112000000, 73, 1, 0), + { /* sentinel */ }, +}; + +static struct meson_clk_pll axg_fixed_pll = { + .m = { + .reg_off = HHI_MPLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_MPLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + }, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &meson_clk_pll_ro_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + }, +}; + +static struct meson_clk_pll axg_sys_pll = { + .m = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 10, + .width = 2, + }, + .rate_table = sys_pll_rate_table, + .rate_count = ARRAY_SIZE(sys_pll_rate_table), + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &meson_clk_pll_ro_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static const struct pll_rate_table axg_gp0_pll_rate_table[] = { + PLL_RATE(240000000, 40, 1, 2), + PLL_RATE(246000000, 41, 1, 2), + PLL_RATE(252000000, 42, 1, 2), + PLL_RATE(258000000, 43, 1, 2), + PLL_RATE(264000000, 44, 1, 2), + PLL_RATE(270000000, 45, 1, 2), + PLL_RATE(276000000, 46, 1, 2), + PLL_RATE(282000000, 47, 1, 2), + PLL_RATE(288000000, 48, 1, 2), + PLL_RATE(294000000, 49, 1, 2), + PLL_RATE(300000000, 50, 1, 2), + PLL_RATE(306000000, 51, 1, 2), + PLL_RATE(312000000, 52, 1, 2), + PLL_RATE(318000000, 53, 1, 2), + PLL_RATE(324000000, 54, 1, 2), + PLL_RATE(330000000, 55, 1, 2), + PLL_RATE(336000000, 56, 1, 2), + PLL_RATE(342000000, 57, 1, 2), + PLL_RATE(348000000, 58, 1, 2), + PLL_RATE(354000000, 59, 1, 2), + PLL_RATE(360000000, 60, 1, 2), + PLL_RATE(366000000, 61, 1, 2), + PLL_RATE(372000000, 62, 1, 2), + PLL_RATE(378000000, 63, 1, 2), + PLL_RATE(384000000, 64, 1, 2), + PLL_RATE(390000000, 65, 1, 3), + PLL_RATE(396000000, 66, 1, 3), + PLL_RATE(402000000, 67, 1, 3), + PLL_RATE(408000000, 68, 1, 3), + PLL_RATE(480000000, 40, 1, 1), + PLL_RATE(492000000, 41, 1, 1), + PLL_RATE(504000000, 42, 1, 1), + PLL_RATE(516000000, 43, 1, 1), + PLL_RATE(528000000, 44, 1, 1), + PLL_RATE(540000000, 45, 1, 1), + PLL_RATE(552000000, 46, 1, 1), + PLL_RATE(564000000, 47, 1, 1), + PLL_RATE(576000000, 48, 1, 1), + PLL_RATE(588000000, 49, 1, 1), + PLL_RATE(600000000, 50, 1, 1), + PLL_RATE(612000000, 51, 1, 1), + PLL_RATE(624000000, 52, 1, 1), + PLL_RATE(636000000, 53, 1, 1), + PLL_RATE(648000000, 54, 1, 1), + PLL_RATE(660000000, 55, 1, 1), + PLL_RATE(672000000, 56, 1, 1), + PLL_RATE(684000000, 57, 1, 1), + PLL_RATE(696000000, 58, 1, 1), + PLL_RATE(708000000, 59, 1, 1), + PLL_RATE(720000000, 60, 1, 1), + PLL_RATE(732000000, 61, 1, 1), + PLL_RATE(744000000, 62, 1, 1), + PLL_RATE(756000000, 63, 1, 1), + PLL_RATE(768000000, 64, 1, 1), + PLL_RATE(780000000, 65, 1, 1), + PLL_RATE(792000000, 66, 1, 1), + PLL_RATE(804000000, 67, 1, 1), + PLL_RATE(816000000, 68, 1, 1), + PLL_RATE(960000000, 40, 1, 0), + PLL_RATE(984000000, 41, 1, 0), + PLL_RATE(1008000000, 42, 1, 0), + PLL_RATE(1032000000, 43, 1, 0), + PLL_RATE(1056000000, 44, 1, 0), + PLL_RATE(1080000000, 45, 1, 0), + PLL_RATE(1104000000, 46, 1, 0), + PLL_RATE(1128000000, 47, 1, 0), + PLL_RATE(1152000000, 48, 1, 0), + PLL_RATE(1176000000, 49, 1, 0), + PLL_RATE(1200000000, 50, 1, 0), + PLL_RATE(1224000000, 51, 1, 0), + PLL_RATE(1248000000, 52, 1, 0), + PLL_RATE(1272000000, 53, 1, 0), + PLL_RATE(1296000000, 54, 1, 0), + PLL_RATE(1320000000, 55, 1, 0), + PLL_RATE(1344000000, 56, 1, 0), + PLL_RATE(1368000000, 57, 1, 0), + PLL_RATE(1392000000, 58, 1, 0), + PLL_RATE(1416000000, 59, 1, 0), + PLL_RATE(1440000000, 60, 1, 0), + PLL_RATE(1464000000, 61, 1, 0), + PLL_RATE(1488000000, 62, 1, 0), + PLL_RATE(1512000000, 63, 1, 0), + PLL_RATE(1536000000, 64, 1, 0), + PLL_RATE(1560000000, 65, 1, 0), + PLL_RATE(1584000000, 66, 1, 0), + PLL_RATE(1608000000, 67, 1, 0), + PLL_RATE(1632000000, 68, 1, 0), + { /* sentinel */ }, +}; + +static struct pll_params_table axg_gp0_params_table[] = { + PLL_PARAM(HHI_GP0_PLL_CNTL, 0x40010250), + PLL_PARAM(HHI_GP0_PLL_CNTL1, 0xc084a000), + PLL_PARAM(HHI_GP0_PLL_CNTL2, 0xb75020be), + PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a59a288), + PLL_PARAM(HHI_GP0_PLL_CNTL4, 0xc000004d), + PLL_PARAM(HHI_GP0_PLL_CNTL5, 0x00078000), +}; + +static struct meson_clk_pll axg_gp0_pll = { + .m = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .params = { + .params_table = axg_gp0_params_table, + .params_count = ARRAY_SIZE(axg_gp0_params_table), + .no_init_reset = true, + .reset_lock_loop = true, + }, + .rate_table = axg_gp0_pll_rate_table, + .rate_count = ARRAY_SIZE(axg_gp0_pll_rate_table), + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &meson_clk_pll_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + }, +}; + + +static struct clk_fixed_factor axg_fclk_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_fclk_div3 = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_fclk_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_fclk_div5 = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_fclk_div7 = { + .mult = 1, + .div = 7, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct meson_clk_mpll axg_mpll0 = { + .sdm = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 16, + .width = 9, + }, + .en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 14, + .width = 1, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL, + .shift = 25, + .width = 1, + }, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &meson_clk_mpll_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct meson_clk_mpll axg_mpll1 = { + .sdm = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 16, + .width = 9, + }, + .en = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 14, + .width = 1, + }, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &meson_clk_mpll_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct meson_clk_mpll axg_mpll2 = { + .sdm = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 16, + .width = 9, + }, + .en = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 14, + .width = 1, + }, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &meson_clk_mpll_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct meson_clk_mpll axg_mpll3 = { + .sdm = { + .reg_off = HHI_MPLL3_CNTL0, + .shift = 12, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL3_CNTL0, + .shift = 11, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL3_CNTL0, + .shift = 2, + .width = 9, + }, + .en = { + .reg_off = HHI_MPLL3_CNTL0, + .shift = 0, + .width = 1, + }, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mpll3", + .ops = &meson_clk_mpll_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +/* + * FIXME The legacy composite clocks (e.g. clk81) are both PLL post-dividers + * and should be modeled with their respective PLLs via the forthcoming + * coordinated clock rates feature + */ +static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; +static const char * const clk81_parent_names[] = { + "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", + "fclk_div3", "fclk_div5" +}; + +static struct clk_mux axg_mpeg_clk_sel = { + .reg = (void *)HHI_MPEG_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .flags = CLK_MUX_READ_ONLY, + .table = mux_table_clk81, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mpeg_clk_sel", + .ops = &clk_mux_ro_ops, + .parent_names = clk81_parent_names, + .num_parents = ARRAY_SIZE(clk81_parent_names), + }, +}; + +static struct clk_divider axg_mpeg_clk_div = { + .reg = (void *)HHI_MPEG_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "mpeg_clk_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "mpeg_clk_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_gate axg_clk81 = { + .reg = (void *)HHI_MPEG_CLK_CNTL, + .bit_idx = 7, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "clk81", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "mpeg_clk_div" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), + }, +}; + +static const char * const axg_sd_emmc_clk0_parent_names[] = { + "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7", + + /* + * Following these parent clocks, we should also have had mpll2, mpll3 + * and gp0_pll but these clocks are too precious to be used here. All + * the necessary rates for MMC and NAND operation can be acheived using + * xtal or fclk_div clocks + */ +}; + +/* SDcard clock */ +static struct clk_mux axg_sd_emmc_b_clk0_sel = { + .reg = (void *)HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_sel", + .ops = &clk_mux_ops, + .parent_names = axg_sd_emmc_clk0_parent_names, + .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_divider axg_sd_emmc_b_clk0_div = { + .reg = (void *)HHI_SD_EMMC_CLK_CNTL, + .shift = 16, + .width = 7, + .lock = &meson_clk_lock, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_gate axg_sd_emmc_b_clk0 = { + .reg = (void *)HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 23, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_b_clk0", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* EMMC/NAND clock */ +static struct clk_mux axg_sd_emmc_c_clk0_sel = { + .reg = (void *)HHI_NAND_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_sel", + .ops = &clk_mux_ops, + .parent_names = axg_sd_emmc_clk0_parent_names, + .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_divider axg_sd_emmc_c_clk0_div = { + .reg = (void *)HHI_NAND_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &meson_clk_lock, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_gate axg_sd_emmc_c_clk0 = { + .reg = (void *)HHI_NAND_CLK_CNTL, + .bit_idx = 7, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_c_clk0", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Everything Else (EE) domain gates */ +static MESON_GATE(axg_ddr, HHI_GCLK_MPEG0, 0); +static MESON_GATE(axg_audio_locker, HHI_GCLK_MPEG0, 2); +static MESON_GATE(axg_mipi_dsi_host, HHI_GCLK_MPEG0, 3); +static MESON_GATE(axg_isa, HHI_GCLK_MPEG0, 5); +static MESON_GATE(axg_pl301, HHI_GCLK_MPEG0, 6); +static MESON_GATE(axg_periphs, HHI_GCLK_MPEG0, 7); +static MESON_GATE(axg_spicc_0, HHI_GCLK_MPEG0, 8); +static MESON_GATE(axg_i2c, HHI_GCLK_MPEG0, 9); +static MESON_GATE(axg_rng0, HHI_GCLK_MPEG0, 12); +static MESON_GATE(axg_uart0, HHI_GCLK_MPEG0, 13); +static MESON_GATE(axg_mipi_dsi_phy, HHI_GCLK_MPEG0, 14); +static MESON_GATE(axg_spicc_1, HHI_GCLK_MPEG0, 15); +static MESON_GATE(axg_pcie_a, HHI_GCLK_MPEG0, 16); +static MESON_GATE(axg_pcie_b, HHI_GCLK_MPEG0, 17); +static MESON_GATE(axg_hiu_reg, HHI_GCLK_MPEG0, 19); +static MESON_GATE(axg_assist_misc, HHI_GCLK_MPEG0, 23); +static MESON_GATE(axg_emmc_b, HHI_GCLK_MPEG0, 25); +static MESON_GATE(axg_emmc_c, HHI_GCLK_MPEG0, 26); +static MESON_GATE(axg_dma, HHI_GCLK_MPEG0, 27); +static MESON_GATE(axg_spi, HHI_GCLK_MPEG0, 30); + +static MESON_GATE(axg_audio, HHI_GCLK_MPEG1, 0); +static MESON_GATE(axg_eth_core, HHI_GCLK_MPEG1, 3); +static MESON_GATE(axg_uart1, HHI_GCLK_MPEG1, 16); +static MESON_GATE(axg_g2d, HHI_GCLK_MPEG1, 20); +static MESON_GATE(axg_usb0, HHI_GCLK_MPEG1, 21); +static MESON_GATE(axg_usb1, HHI_GCLK_MPEG1, 22); +static MESON_GATE(axg_reset, HHI_GCLK_MPEG1, 23); +static MESON_GATE(axg_usb_general, HHI_GCLK_MPEG1, 26); +static MESON_GATE(axg_ahb_arb0, HHI_GCLK_MPEG1, 29); +static MESON_GATE(axg_efuse, HHI_GCLK_MPEG1, 30); +static MESON_GATE(axg_boot_rom, HHI_GCLK_MPEG1, 31); + +static MESON_GATE(axg_ahb_data_bus, HHI_GCLK_MPEG2, 1); +static MESON_GATE(axg_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); +static MESON_GATE(axg_usb1_to_ddr, HHI_GCLK_MPEG2, 8); +static MESON_GATE(axg_usb0_to_ddr, HHI_GCLK_MPEG2, 9); +static MESON_GATE(axg_mmc_pclk, HHI_GCLK_MPEG2, 11); +static MESON_GATE(axg_vpu_intr, HHI_GCLK_MPEG2, 25); +static MESON_GATE(axg_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); +static MESON_GATE(axg_gic, HHI_GCLK_MPEG2, 30); + +/* Always On (AO) domain gates */ + +static MESON_GATE(axg_ao_media_cpu, HHI_GCLK_AO, 0); +static MESON_GATE(axg_ao_ahb_sram, HHI_GCLK_AO, 1); +static MESON_GATE(axg_ao_ahb_bus, HHI_GCLK_AO, 2); +static MESON_GATE(axg_ao_iface, HHI_GCLK_AO, 3); +static MESON_GATE(axg_ao_i2c, HHI_GCLK_AO, 4); + +/* Array of all clocks provided by this provider */ + +static struct clk_hw_onecell_data axg_hw_onecell_data = { + .hws = { + [CLKID_SYS_PLL] = &axg_sys_pll.hw, + [CLKID_FIXED_PLL] = &axg_fixed_pll.hw, + [CLKID_FCLK_DIV2] = &axg_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &axg_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &axg_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &axg_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &axg_fclk_div7.hw, + [CLKID_GP0_PLL] = &axg_gp0_pll.hw, + [CLKID_MPEG_SEL] = &axg_mpeg_clk_sel.hw, + [CLKID_MPEG_DIV] = &axg_mpeg_clk_div.hw, + [CLKID_CLK81] = &axg_clk81.hw, + [CLKID_MPLL0] = &axg_mpll0.hw, + [CLKID_MPLL1] = &axg_mpll1.hw, + [CLKID_MPLL2] = &axg_mpll2.hw, + [CLKID_MPLL3] = &axg_mpll3.hw, + [CLKID_DDR] = &axg_ddr.hw, + [CLKID_AUDIO_LOCKER] = &axg_audio_locker.hw, + [CLKID_MIPI_DSI_HOST] = &axg_mipi_dsi_host.hw, + [CLKID_ISA] = &axg_isa.hw, + [CLKID_PL301] = &axg_pl301.hw, + [CLKID_PERIPHS] = &axg_periphs.hw, + [CLKID_SPICC0] = &axg_spicc_0.hw, + [CLKID_I2C] = &axg_i2c.hw, + [CLKID_RNG0] = &axg_rng0.hw, + [CLKID_UART0] = &axg_uart0.hw, + [CLKID_MIPI_DSI_PHY] = &axg_mipi_dsi_phy.hw, + [CLKID_SPICC1] = &axg_spicc_1.hw, + [CLKID_PCIE_A] = &axg_pcie_a.hw, + [CLKID_PCIE_B] = &axg_pcie_b.hw, + [CLKID_HIU_IFACE] = &axg_hiu_reg.hw, + [CLKID_ASSIST_MISC] = &axg_assist_misc.hw, + [CLKID_SD_EMMC_B] = &axg_emmc_b.hw, + [CLKID_SD_EMMC_C] = &axg_emmc_c.hw, + [CLKID_DMA] = &axg_dma.hw, + [CLKID_SPI] = &axg_spi.hw, + [CLKID_AUDIO] = &axg_audio.hw, + [CLKID_ETH] = &axg_eth_core.hw, + [CLKID_UART1] = &axg_uart1.hw, + [CLKID_G2D] = &axg_g2d.hw, + [CLKID_USB0] = &axg_usb0.hw, + [CLKID_USB1] = &axg_usb1.hw, + [CLKID_RESET] = &axg_reset.hw, + [CLKID_USB] = &axg_usb_general.hw, + [CLKID_AHB_ARB0] = &axg_ahb_arb0.hw, + [CLKID_EFUSE] = &axg_efuse.hw, + [CLKID_BOOT_ROM] = &axg_boot_rom.hw, + [CLKID_AHB_DATA_BUS] = &axg_ahb_data_bus.hw, + [CLKID_AHB_CTRL_BUS] = &axg_ahb_ctrl_bus.hw, + [CLKID_USB1_DDR_BRIDGE] = &axg_usb1_to_ddr.hw, + [CLKID_USB0_DDR_BRIDGE] = &axg_usb0_to_ddr.hw, + [CLKID_MMC_PCLK] = &axg_mmc_pclk.hw, + [CLKID_VPU_INTR] = &axg_vpu_intr.hw, + [CLKID_SEC_AHB_AHB3_BRIDGE] = &axg_sec_ahb_ahb3_bridge.hw, + [CLKID_GIC] = &axg_gic.hw, + [CLKID_AO_MEDIA_CPU] = &axg_ao_media_cpu.hw, + [CLKID_AO_AHB_SRAM] = &axg_ao_ahb_sram.hw, + [CLKID_AO_AHB_BUS] = &axg_ao_ahb_bus.hw, + [CLKID_AO_IFACE] = &axg_ao_iface.hw, + [CLKID_AO_I2C] = &axg_ao_i2c.hw, + [CLKID_SD_EMMC_B_CLK0_SEL] = &axg_sd_emmc_b_clk0_sel.hw, + [CLKID_SD_EMMC_B_CLK0_DIV] = &axg_sd_emmc_b_clk0_div.hw, + [CLKID_SD_EMMC_B_CLK0] = &axg_sd_emmc_b_clk0.hw, + [CLKID_SD_EMMC_C_CLK0_SEL] = &axg_sd_emmc_c_clk0_sel.hw, + [CLKID_SD_EMMC_C_CLK0_DIV] = &axg_sd_emmc_c_clk0_div.hw, + [CLKID_SD_EMMC_C_CLK0] = &axg_sd_emmc_c_clk0.hw, + [NR_CLKS] = NULL, + }, + .num = NR_CLKS, +}; + +/* Convenience tables to populate base addresses in .probe */ + +static struct meson_clk_pll *const axg_clk_plls[] = { + &axg_fixed_pll, + &axg_sys_pll, + &axg_gp0_pll, +}; + +static struct meson_clk_mpll *const axg_clk_mplls[] = { + &axg_mpll0, + &axg_mpll1, + &axg_mpll2, + &axg_mpll3, +}; + +static struct clk_gate *const axg_clk_gates[] = { + &axg_clk81, + &axg_ddr, + &axg_audio_locker, + &axg_mipi_dsi_host, + &axg_isa, + &axg_pl301, + &axg_periphs, + &axg_spicc_0, + &axg_i2c, + &axg_rng0, + &axg_uart0, + &axg_mipi_dsi_phy, + &axg_spicc_1, + &axg_pcie_a, + &axg_pcie_b, + &axg_hiu_reg, + &axg_assist_misc, + &axg_emmc_b, + &axg_emmc_c, + &axg_dma, + &axg_spi, + &axg_audio, + &axg_eth_core, + &axg_uart1, + &axg_g2d, + &axg_usb0, + &axg_usb1, + &axg_reset, + &axg_usb_general, + &axg_ahb_arb0, + &axg_efuse, + &axg_boot_rom, + &axg_ahb_data_bus, + &axg_ahb_ctrl_bus, + &axg_usb1_to_ddr, + &axg_usb0_to_ddr, + &axg_mmc_pclk, + &axg_vpu_intr, + &axg_sec_ahb_ahb3_bridge, + &axg_gic, + &axg_ao_media_cpu, + &axg_ao_ahb_sram, + &axg_ao_ahb_bus, + &axg_ao_iface, + &axg_ao_i2c, + &axg_sd_emmc_b_clk0, + &axg_sd_emmc_c_clk0, +}; + +static struct clk_mux *const axg_clk_muxes[] = { + &axg_mpeg_clk_sel, + &axg_sd_emmc_b_clk0_sel, + &axg_sd_emmc_c_clk0_sel, +}; + +static struct clk_divider *const axg_clk_dividers[] = { + &axg_mpeg_clk_div, + &axg_sd_emmc_b_clk0_div, + &axg_sd_emmc_c_clk0_div, +}; + +struct clkc_data { + struct clk_gate *const *clk_gates; + unsigned int clk_gates_count; + struct meson_clk_mpll *const *clk_mplls; + unsigned int clk_mplls_count; + struct meson_clk_pll *const *clk_plls; + unsigned int clk_plls_count; + struct clk_mux *const *clk_muxes; + unsigned int clk_muxes_count; + struct clk_divider *const *clk_dividers; + unsigned int clk_dividers_count; + struct clk_hw_onecell_data *hw_onecell_data; +}; + +static const struct clkc_data axg_clkc_data = { + .clk_gates = axg_clk_gates, + .clk_gates_count = ARRAY_SIZE(axg_clk_gates), + .clk_mplls = axg_clk_mplls, + .clk_mplls_count = ARRAY_SIZE(axg_clk_mplls), + .clk_plls = axg_clk_plls, + .clk_plls_count = ARRAY_SIZE(axg_clk_plls), + .clk_muxes = axg_clk_muxes, + .clk_muxes_count = ARRAY_SIZE(axg_clk_muxes), + .clk_dividers = axg_clk_dividers, + .clk_dividers_count = ARRAY_SIZE(axg_clk_dividers), + .hw_onecell_data = &axg_hw_onecell_data, +}; + +static const struct of_device_id clkc_match_table[] = { + { .compatible = "amlogic,axg-clkc", .data = &axg_clkc_data }, + {} +}; + +static int axg_clkc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct clkc_data *clkc_data; + struct resource *res; + void __iomem *clk_base; + int ret, clkid, i; + + clkc_data = of_device_get_match_data(&pdev->dev); + if (!clkc_data) + return -EINVAL; + + /* Generic clocks and PLLs */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + clk_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!clk_base) { + dev_err(&pdev->dev, "Unable to map clk base\n"); + return -ENXIO; + } + + /* Populate base address for PLLs */ + for (i = 0; i < clkc_data->clk_plls_count; i++) + clkc_data->clk_plls[i]->base = clk_base; + + /* Populate base address for MPLLs */ + for (i = 0; i < clkc_data->clk_mplls_count; i++) + clkc_data->clk_mplls[i]->base = clk_base; + + /* Populate base address for gates */ + for (i = 0; i < clkc_data->clk_gates_count; i++) + clkc_data->clk_gates[i]->reg = clk_base + + (u64)clkc_data->clk_gates[i]->reg; + + /* Populate base address for muxes */ + for (i = 0; i < clkc_data->clk_muxes_count; i++) + clkc_data->clk_muxes[i]->reg = clk_base + + (u64)clkc_data->clk_muxes[i]->reg; + + /* Populate base address for dividers */ + for (i = 0; i < clkc_data->clk_dividers_count; i++) + clkc_data->clk_dividers[i]->reg = clk_base + + (u64)clkc_data->clk_dividers[i]->reg; + + for (clkid = 0; clkid < clkc_data->hw_onecell_data->num; clkid++) { + /* array might be sparse */ + if (!clkc_data->hw_onecell_data->hws[clkid]) + continue; + + ret = devm_clk_hw_register(dev, + clkc_data->hw_onecell_data->hws[clkid]); + if (ret) { + dev_err(&pdev->dev, "Clock registration failed\n"); + return ret; + } + } + + return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, + clkc_data->hw_onecell_data); +} + +static struct platform_driver axg_driver = { + .probe = axg_clkc_probe, + .driver = { + .name = "axg-clkc", + .of_match_table = clkc_match_table, + }, +}; + +builtin_platform_driver(axg_driver); diff --git a/drivers/clk/meson/axg.h b/drivers/clk/meson/axg.h new file mode 100644 index 000000000000..ce0bafdb6b28 --- /dev/null +++ b/drivers/clk/meson/axg.h @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* + * Copyright (c) 2016 AmLogic, Inc. + * Author: Michael Turquette + * + * Copyright (c) 2017 Amlogic, inc. + * Author: Qiufang Dai + * + */ +#ifndef __AXG_H +#define __AXG_H + +/* + * Clock controller register offsets + * + * Register offsets from the data sheet must be multiplied by 4 before + * adding them to the base address to get the right value. + */ +#define HHI_GP0_PLL_CNTL 0x40 +#define HHI_GP0_PLL_CNTL2 0x44 +#define HHI_GP0_PLL_CNTL3 0x48 +#define HHI_GP0_PLL_CNTL4 0x4c +#define HHI_GP0_PLL_CNTL5 0x50 +#define HHI_GP0_PLL_STS 0x54 +#define HHI_GP0_PLL_CNTL1 0x58 +#define HHI_HIFI_PLL_CNTL 0x80 +#define HHI_HIFI_PLL_CNTL2 0x84 +#define HHI_HIFI_PLL_CNTL3 0x88 +#define HHI_HIFI_PLL_CNTL4 0x8C +#define HHI_HIFI_PLL_CNTL5 0x90 +#define HHI_HIFI_PLL_STS 0x94 +#define HHI_HIFI_PLL_CNTL1 0x98 + +#define HHI_XTAL_DIVN_CNTL 0xbc +#define HHI_GCLK2_MPEG0 0xc0 +#define HHI_GCLK2_MPEG1 0xc4 +#define HHI_GCLK2_MPEG2 0xc8 +#define HHI_GCLK2_OTHER 0xd0 +#define HHI_GCLK2_AO 0xd4 +#define HHI_PCIE_PLL_CNTL 0xd8 +#define HHI_PCIE_PLL_CNTL1 0xdC +#define HHI_PCIE_PLL_CNTL2 0xe0 +#define HHI_PCIE_PLL_CNTL3 0xe4 +#define HHI_PCIE_PLL_CNTL4 0xe8 +#define HHI_PCIE_PLL_CNTL5 0xec +#define HHI_PCIE_PLL_CNTL6 0xf0 +#define HHI_PCIE_PLL_STS 0xf4 + +#define HHI_MEM_PD_REG0 0x100 +#define HHI_VPU_MEM_PD_REG0 0x104 +#define HHI_VIID_CLK_DIV 0x128 +#define HHI_VIID_CLK_CNTL 0x12c + +#define HHI_GCLK_MPEG0 0x140 +#define HHI_GCLK_MPEG1 0x144 +#define HHI_GCLK_MPEG2 0x148 +#define HHI_GCLK_OTHER 0x150 +#define HHI_GCLK_AO 0x154 +#define HHI_SYS_CPU_CLK_CNTL1 0x15c +#define HHI_SYS_CPU_RESET_CNTL 0x160 +#define HHI_VID_CLK_DIV 0x164 +#define HHI_SPICC_HCLK_CNTL 0x168 + +#define HHI_MPEG_CLK_CNTL 0x174 +#define HHI_VID_CLK_CNTL 0x17c +#define HHI_TS_CLK_CNTL 0x190 +#define HHI_VID_CLK_CNTL2 0x194 +#define HHI_SYS_CPU_CLK_CNTL0 0x19c +#define HHI_VID_PLL_CLK_DIV 0x1a0 +#define HHI_VPU_CLK_CNTL 0x1bC + +#define HHI_VAPBCLK_CNTL 0x1F4 + +#define HHI_GEN_CLK_CNTL 0x228 + +#define HHI_VDIN_MEAS_CLK_CNTL 0x250 +#define HHI_NAND_CLK_CNTL 0x25C +#define HHI_SD_EMMC_CLK_CNTL 0x264 + +#define HHI_MPLL_CNTL 0x280 +#define HHI_MPLL_CNTL2 0x284 +#define HHI_MPLL_CNTL3 0x288 +#define HHI_MPLL_CNTL4 0x28C +#define HHI_MPLL_CNTL5 0x290 +#define HHI_MPLL_CNTL6 0x294 +#define HHI_MPLL_CNTL7 0x298 +#define HHI_MPLL_CNTL8 0x29C +#define HHI_MPLL_CNTL9 0x2A0 +#define HHI_MPLL_CNTL10 0x2A4 + +#define HHI_MPLL3_CNTL0 0x2E0 +#define HHI_MPLL3_CNTL1 0x2E4 +#define HHI_PLL_TOP_MISC 0x2E8 + +#define HHI_SYS_PLL_CNTL1 0x2FC +#define HHI_SYS_PLL_CNTL 0x300 +#define HHI_SYS_PLL_CNTL2 0x304 +#define HHI_SYS_PLL_CNTL3 0x308 +#define HHI_SYS_PLL_CNTL4 0x30c +#define HHI_SYS_PLL_CNTL5 0x310 +#define HHI_SYS_PLL_STS 0x314 +#define HHI_DPLL_TOP_I 0x318 +#define HHI_DPLL_TOP2_I 0x31C + +/* + * CLKID index values + * + * These indices are entirely contrived and do not map onto the hardware. + * It has now been decided to expose everything by default in the DT header: + * include/dt-bindings/clock/axg-clkc.h. Only the clocks ids we don't want + * to expose, such as the internal muxes and dividers of composite clocks, + * will remain defined here. + */ +#define CLKID_MPEG_SEL 8 +#define CLKID_MPEG_DIV 9 +#define CLKID_SD_EMMC_B_CLK0_SEL 61 +#define CLKID_SD_EMMC_B_CLK0_DIV 62 +#define CLKID_SD_EMMC_C_CLK0_SEL 63 +#define CLKID_SD_EMMC_C_CLK0_DIV 64 + +#define NR_CLKS 65 + +/* include the CLKIDs that have been made part of the DT binding */ +#include + +#endif /* __AXG_H */ diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c index 44a5a535ca63..5144360e2c80 100644 --- a/drivers/clk/meson/clk-mpll.c +++ b/drivers/clk/meson/clk-mpll.c @@ -98,7 +98,7 @@ static void params_from_rate(unsigned long requested_rate, *sdm = SDM_DEN - 1; } else { *n2 = div; - *sdm = DIV_ROUND_UP(rem * SDM_DEN, requested_rate); + *sdm = DIV_ROUND_UP_ULL((u64)rem * SDM_DEN, requested_rate); } } diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 1629da9b4141..c2ff0520ce53 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -134,7 +134,7 @@ struct meson_clk_audio_divider { struct clk_gate _name = { \ .reg = (void __iomem *) _reg, \ .bit_idx = (_bit), \ - .lock = &clk_lock, \ + .lock = &meson_clk_lock, \ .hw.init = &(struct clk_init_data) { \ .name = #_name, \ .ops = &clk_gate_ops, \ diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index ae385310e980..af24455af5b4 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -27,7 +27,7 @@ #include "clkc.h" #include "gxbb.h" -static DEFINE_SPINLOCK(clk_lock); +static DEFINE_SPINLOCK(meson_clk_lock); static const struct pll_rate_table sys_pll_rate_table[] = { PLL_RATE(24000000, 56, 1, 2), @@ -294,7 +294,7 @@ static struct meson_clk_pll gxbb_fixed_pll = { .shift = 16, .width = 2, }, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "fixed_pll", .ops = &meson_clk_pll_ro_ops, @@ -330,7 +330,7 @@ static struct meson_clk_pll gxbb_hdmi_pll = { .shift = 22, .width = 2, }, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "hdmi_pll", .ops = &meson_clk_pll_ro_ops, @@ -358,7 +358,7 @@ static struct meson_clk_pll gxbb_sys_pll = { }, .rate_table = sys_pll_rate_table, .rate_count = ARRAY_SIZE(sys_pll_rate_table), - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sys_pll", .ops = &meson_clk_pll_ro_ops, @@ -399,7 +399,7 @@ static struct meson_clk_pll gxbb_gp0_pll = { }, .rate_table = gxbb_gp0_pll_rate_table, .rate_count = ARRAY_SIZE(gxbb_gp0_pll_rate_table), - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "gp0_pll", .ops = &meson_clk_pll_ops, @@ -442,7 +442,7 @@ static struct meson_clk_pll gxl_gp0_pll = { }, .rate_table = gxl_gp0_pll_rate_table, .rate_count = ARRAY_SIZE(gxl_gp0_pll_rate_table), - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "gp0_pll", .ops = &meson_clk_pll_ops, @@ -533,7 +533,7 @@ static struct meson_clk_mpll gxbb_mpll0 = { .shift = 25, .width = 1, }, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll0", .ops = &meson_clk_mpll_ops, @@ -563,7 +563,7 @@ static struct meson_clk_mpll gxbb_mpll1 = { .shift = 14, .width = 1, }, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll1", .ops = &meson_clk_mpll_ops, @@ -593,7 +593,7 @@ static struct meson_clk_mpll gxbb_mpll2 = { .shift = 14, .width = 1, }, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll2", .ops = &meson_clk_mpll_ops, @@ -620,7 +620,7 @@ static struct clk_mux gxbb_mpeg_clk_sel = { .shift = 12, .flags = CLK_MUX_READ_ONLY, .table = mux_table_clk81, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_sel", .ops = &clk_mux_ro_ops, @@ -639,7 +639,7 @@ static struct clk_divider gxbb_mpeg_clk_div = { .reg = (void *)HHI_MPEG_CLK_CNTL, .shift = 0, .width = 7, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_div", .ops = &clk_divider_ops, @@ -653,7 +653,7 @@ static struct clk_divider gxbb_mpeg_clk_div = { static struct clk_gate gxbb_clk81 = { .reg = (void *)HHI_MPEG_CLK_CNTL, .bit_idx = 7, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "clk81", .ops = &clk_gate_ops, @@ -667,7 +667,7 @@ static struct clk_mux gxbb_sar_adc_clk_sel = { .reg = (void *)HHI_SAR_CLK_CNTL, .mask = 0x3, .shift = 9, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sar_adc_clk_sel", .ops = &clk_mux_ops, @@ -681,7 +681,7 @@ static struct clk_divider gxbb_sar_adc_clk_div = { .reg = (void *)HHI_SAR_CLK_CNTL, .shift = 0, .width = 8, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sar_adc_clk_div", .ops = &clk_divider_ops, @@ -693,7 +693,7 @@ static struct clk_divider gxbb_sar_adc_clk_div = { static struct clk_gate gxbb_sar_adc_clk = { .reg = (void *)HHI_SAR_CLK_CNTL, .bit_idx = 8, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sar_adc_clk", .ops = &clk_gate_ops, @@ -719,7 +719,7 @@ static struct clk_mux gxbb_mali_0_sel = { .mask = 0x7, .shift = 9, .table = mux_table_mali_0_1, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mali_0_sel", .ops = &clk_mux_ops, @@ -738,7 +738,7 @@ static struct clk_divider gxbb_mali_0_div = { .reg = (void *)HHI_MALI_CLK_CNTL, .shift = 0, .width = 7, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mali_0_div", .ops = &clk_divider_ops, @@ -751,7 +751,7 @@ static struct clk_divider gxbb_mali_0_div = { static struct clk_gate gxbb_mali_0 = { .reg = (void *)HHI_MALI_CLK_CNTL, .bit_idx = 8, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mali_0", .ops = &clk_gate_ops, @@ -766,7 +766,7 @@ static struct clk_mux gxbb_mali_1_sel = { .mask = 0x7, .shift = 25, .table = mux_table_mali_0_1, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mali_1_sel", .ops = &clk_mux_ops, @@ -785,7 +785,7 @@ static struct clk_divider gxbb_mali_1_div = { .reg = (void *)HHI_MALI_CLK_CNTL, .shift = 16, .width = 7, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mali_1_div", .ops = &clk_divider_ops, @@ -798,7 +798,7 @@ static struct clk_divider gxbb_mali_1_div = { static struct clk_gate gxbb_mali_1 = { .reg = (void *)HHI_MALI_CLK_CNTL, .bit_idx = 24, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mali_1", .ops = &clk_gate_ops, @@ -818,7 +818,7 @@ static struct clk_mux gxbb_mali = { .mask = 1, .shift = 31, .table = mux_table_mali, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mali", .ops = &clk_mux_ops, @@ -834,7 +834,7 @@ static struct clk_mux gxbb_cts_amclk_sel = { .shift = 9, /* Default parent unknown (register reset value: 0) */ .table = (u32[]){ 1, 2, 3 }, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "cts_amclk_sel", .ops = &clk_mux_ops, @@ -851,7 +851,7 @@ static struct meson_clk_audio_divider gxbb_cts_amclk_div = { .width = 8, }, .flags = CLK_DIVIDER_ROUND_CLOSEST, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "cts_amclk_div", .ops = &meson_clk_audio_divider_ops, @@ -864,7 +864,7 @@ static struct meson_clk_audio_divider gxbb_cts_amclk_div = { static struct clk_gate gxbb_cts_amclk = { .reg = (void *) HHI_AUD_CLK_CNTL, .bit_idx = 8, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "cts_amclk", .ops = &clk_gate_ops, @@ -880,7 +880,7 @@ static struct clk_mux gxbb_cts_mclk_i958_sel = { .shift = 25, /* Default parent unknown (register reset value: 0) */ .table = (u32[]){ 1, 2, 3 }, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data) { .name = "cts_mclk_i958_sel", .ops = &clk_mux_ops, @@ -894,7 +894,7 @@ static struct clk_divider gxbb_cts_mclk_i958_div = { .reg = (void *)HHI_AUD_CLK_CNTL2, .shift = 16, .width = 8, - .lock = &clk_lock, + .lock = &meson_clk_lock, .flags = CLK_DIVIDER_ROUND_CLOSEST, .hw.init = &(struct clk_init_data) { .name = "cts_mclk_i958_div", @@ -908,7 +908,7 @@ static struct clk_divider gxbb_cts_mclk_i958_div = { static struct clk_gate gxbb_cts_mclk_i958 = { .reg = (void *)HHI_AUD_CLK_CNTL2, .bit_idx = 24, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "cts_mclk_i958", .ops = &clk_gate_ops, @@ -922,7 +922,7 @@ static struct clk_mux gxbb_cts_i958 = { .reg = (void *)HHI_AUD_CLK_CNTL2, .mask = 0x1, .shift = 27, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "cts_i958", .ops = &clk_mux_ops, @@ -940,7 +940,7 @@ static struct clk_divider gxbb_32k_clk_div = { .reg = (void *)HHI_32K_CLK_CNTL, .shift = 0, .width = 14, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "32k_clk_div", .ops = &clk_divider_ops, @@ -953,7 +953,7 @@ static struct clk_divider gxbb_32k_clk_div = { static struct clk_gate gxbb_32k_clk = { .reg = (void *)HHI_32K_CLK_CNTL, .bit_idx = 15, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "32k_clk", .ops = &clk_gate_ops, @@ -971,7 +971,7 @@ static struct clk_mux gxbb_32k_clk_sel = { .reg = (void *)HHI_32K_CLK_CNTL, .mask = 0x3, .shift = 16, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "32k_clk_sel", .ops = &clk_mux_ops, @@ -997,7 +997,7 @@ static struct clk_mux gxbb_sd_emmc_a_clk0_sel = { .reg = (void *)HHI_SD_EMMC_CLK_CNTL, .mask = 0x7, .shift = 9, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_a_clk0_sel", .ops = &clk_mux_ops, @@ -1011,7 +1011,7 @@ static struct clk_divider gxbb_sd_emmc_a_clk0_div = { .reg = (void *)HHI_SD_EMMC_CLK_CNTL, .shift = 0, .width = 7, - .lock = &clk_lock, + .lock = &meson_clk_lock, .flags = CLK_DIVIDER_ROUND_CLOSEST, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_a_clk0_div", @@ -1025,23 +1025,13 @@ static struct clk_divider gxbb_sd_emmc_a_clk0_div = { static struct clk_gate gxbb_sd_emmc_a_clk0 = { .reg = (void *)HHI_SD_EMMC_CLK_CNTL, .bit_idx = 7, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_a_clk0", .ops = &clk_gate_ops, .parent_names = (const char *[]){ "sd_emmc_a_clk0_div" }, .num_parents = 1, - - /* - * FIXME: - * We need CLK_IGNORE_UNUSED because mmc DT node point to xtal - * instead of this clock. CCF would gate this on boot, killing - * the mmc controller. Please remove this flag once DT properly - * point to this clock instead of xtal - * - * Same goes for emmc B and C clocks - */ - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -1050,7 +1040,7 @@ static struct clk_mux gxbb_sd_emmc_b_clk0_sel = { .reg = (void *)HHI_SD_EMMC_CLK_CNTL, .mask = 0x7, .shift = 25, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_sel", .ops = &clk_mux_ops, @@ -1064,7 +1054,7 @@ static struct clk_divider gxbb_sd_emmc_b_clk0_div = { .reg = (void *)HHI_SD_EMMC_CLK_CNTL, .shift = 16, .width = 7, - .lock = &clk_lock, + .lock = &meson_clk_lock, .flags = CLK_DIVIDER_ROUND_CLOSEST, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_div", @@ -1078,13 +1068,13 @@ static struct clk_divider gxbb_sd_emmc_b_clk0_div = { static struct clk_gate gxbb_sd_emmc_b_clk0 = { .reg = (void *)HHI_SD_EMMC_CLK_CNTL, .bit_idx = 23, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_b_clk0", .ops = &clk_gate_ops, .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -1093,7 +1083,7 @@ static struct clk_mux gxbb_sd_emmc_c_clk0_sel = { .reg = (void *)HHI_NAND_CLK_CNTL, .mask = 0x7, .shift = 9, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_sel", .ops = &clk_mux_ops, @@ -1107,7 +1097,7 @@ static struct clk_divider gxbb_sd_emmc_c_clk0_div = { .reg = (void *)HHI_NAND_CLK_CNTL, .shift = 0, .width = 7, - .lock = &clk_lock, + .lock = &meson_clk_lock, .flags = CLK_DIVIDER_ROUND_CLOSEST, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_div", @@ -1121,13 +1111,13 @@ static struct clk_divider gxbb_sd_emmc_c_clk0_div = { static struct clk_gate gxbb_sd_emmc_c_clk0 = { .reg = (void *)HHI_NAND_CLK_CNTL, .bit_idx = 7, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_c_clk0", .ops = &clk_gate_ops, .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -1142,7 +1132,7 @@ static struct clk_mux gxbb_vpu_0_sel = { .reg = (void *)HHI_VPU_CLK_CNTL, .mask = 0x3, .shift = 9, - .lock = &clk_lock, + .lock = &meson_clk_lock, .table = mux_table_vpu, .hw.init = &(struct clk_init_data){ .name = "vpu_0_sel", @@ -1161,7 +1151,7 @@ static struct clk_divider gxbb_vpu_0_div = { .reg = (void *)HHI_VPU_CLK_CNTL, .shift = 0, .width = 7, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "vpu_0_div", .ops = &clk_divider_ops, @@ -1174,7 +1164,7 @@ static struct clk_divider gxbb_vpu_0_div = { static struct clk_gate gxbb_vpu_0 = { .reg = (void *)HHI_VPU_CLK_CNTL, .bit_idx = 8, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data) { .name = "vpu_0", .ops = &clk_gate_ops, @@ -1188,7 +1178,7 @@ static struct clk_mux gxbb_vpu_1_sel = { .reg = (void *)HHI_VPU_CLK_CNTL, .mask = 0x3, .shift = 25, - .lock = &clk_lock, + .lock = &meson_clk_lock, .table = mux_table_vpu, .hw.init = &(struct clk_init_data){ .name = "vpu_1_sel", @@ -1207,7 +1197,7 @@ static struct clk_divider gxbb_vpu_1_div = { .reg = (void *)HHI_VPU_CLK_CNTL, .shift = 16, .width = 7, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "vpu_1_div", .ops = &clk_divider_ops, @@ -1220,7 +1210,7 @@ static struct clk_divider gxbb_vpu_1_div = { static struct clk_gate gxbb_vpu_1 = { .reg = (void *)HHI_VPU_CLK_CNTL, .bit_idx = 24, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data) { .name = "vpu_1", .ops = &clk_gate_ops, @@ -1234,7 +1224,7 @@ static struct clk_mux gxbb_vpu = { .reg = (void *)HHI_VPU_CLK_CNTL, .mask = 1, .shift = 31, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "vpu", .ops = &clk_mux_ops, @@ -1259,7 +1249,7 @@ static struct clk_mux gxbb_vapb_0_sel = { .reg = (void *)HHI_VAPBCLK_CNTL, .mask = 0x3, .shift = 9, - .lock = &clk_lock, + .lock = &meson_clk_lock, .table = mux_table_vapb, .hw.init = &(struct clk_init_data){ .name = "vapb_0_sel", @@ -1278,7 +1268,7 @@ static struct clk_divider gxbb_vapb_0_div = { .reg = (void *)HHI_VAPBCLK_CNTL, .shift = 0, .width = 7, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "vapb_0_div", .ops = &clk_divider_ops, @@ -1291,7 +1281,7 @@ static struct clk_divider gxbb_vapb_0_div = { static struct clk_gate gxbb_vapb_0 = { .reg = (void *)HHI_VAPBCLK_CNTL, .bit_idx = 8, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data) { .name = "vapb_0", .ops = &clk_gate_ops, @@ -1305,7 +1295,7 @@ static struct clk_mux gxbb_vapb_1_sel = { .reg = (void *)HHI_VAPBCLK_CNTL, .mask = 0x3, .shift = 25, - .lock = &clk_lock, + .lock = &meson_clk_lock, .table = mux_table_vapb, .hw.init = &(struct clk_init_data){ .name = "vapb_1_sel", @@ -1324,7 +1314,7 @@ static struct clk_divider gxbb_vapb_1_div = { .reg = (void *)HHI_VAPBCLK_CNTL, .shift = 16, .width = 7, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "vapb_1_div", .ops = &clk_divider_ops, @@ -1337,7 +1327,7 @@ static struct clk_divider gxbb_vapb_1_div = { static struct clk_gate gxbb_vapb_1 = { .reg = (void *)HHI_VAPBCLK_CNTL, .bit_idx = 24, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data) { .name = "vapb_1", .ops = &clk_gate_ops, @@ -1351,7 +1341,7 @@ static struct clk_mux gxbb_vapb_sel = { .reg = (void *)HHI_VAPBCLK_CNTL, .mask = 1, .shift = 31, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "vapb_sel", .ops = &clk_mux_ops, @@ -1368,7 +1358,7 @@ static struct clk_mux gxbb_vapb_sel = { static struct clk_gate gxbb_vapb = { .reg = (void *)HHI_VAPBCLK_CNTL, .bit_idx = 30, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data) { .name = "vapb", .ops = &clk_gate_ops, @@ -1386,7 +1376,7 @@ static MESON_GATE(gxbb_pl301, HHI_GCLK_MPEG0, 6); static MESON_GATE(gxbb_periphs, HHI_GCLK_MPEG0, 7); static MESON_GATE(gxbb_spicc, HHI_GCLK_MPEG0, 8); static MESON_GATE(gxbb_i2c, HHI_GCLK_MPEG0, 9); -static MESON_GATE(gxbb_sar_adc, HHI_GCLK_MPEG0, 10); +static MESON_GATE(gxbb_sana, HHI_GCLK_MPEG0, 10); static MESON_GATE(gxbb_smart_card, HHI_GCLK_MPEG0, 11); static MESON_GATE(gxbb_rng0, HHI_GCLK_MPEG0, 12); static MESON_GATE(gxbb_uart0, HHI_GCLK_MPEG0, 13); @@ -1437,7 +1427,7 @@ static MESON_GATE(gxbb_usb0_ddr_bridge, HHI_GCLK_MPEG2, 9); static MESON_GATE(gxbb_mmc_pclk, HHI_GCLK_MPEG2, 11); static MESON_GATE(gxbb_dvin, HHI_GCLK_MPEG2, 12); static MESON_GATE(gxbb_uart2, HHI_GCLK_MPEG2, 15); -static MESON_GATE(gxbb_sana, HHI_GCLK_MPEG2, 22); +static MESON_GATE(gxbb_sar_adc, HHI_GCLK_MPEG2, 22); static MESON_GATE(gxbb_vpu_intr, HHI_GCLK_MPEG2, 25); static MESON_GATE(gxbb_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); static MESON_GATE(gxbb_clk81_a53, HHI_GCLK_MPEG2, 29); diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 20ab7190d328..3ffea80c1308 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -32,7 +32,7 @@ #include "clkc.h" #include "meson8b.h" -static DEFINE_SPINLOCK(clk_lock); +static DEFINE_SPINLOCK(meson_clk_lock); static void __iomem *clk_base; @@ -136,7 +136,7 @@ static struct meson_clk_pll meson8b_fixed_pll = { .shift = 16, .width = 2, }, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "fixed_pll", .ops = &meson_clk_pll_ro_ops, @@ -162,7 +162,7 @@ static struct meson_clk_pll meson8b_vid_pll = { .shift = 16, .width = 2, }, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "vid_pll", .ops = &meson_clk_pll_ro_ops, @@ -190,7 +190,7 @@ static struct meson_clk_pll meson8b_sys_pll = { }, .rate_table = sys_pll_rate_table, .rate_count = ARRAY_SIZE(sys_pll_rate_table), - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sys_pll", .ops = &meson_clk_pll_ops, @@ -281,7 +281,7 @@ static struct meson_clk_mpll meson8b_mpll0 = { .shift = 25, .width = 1, }, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll0", .ops = &meson_clk_mpll_ops, @@ -311,7 +311,7 @@ static struct meson_clk_mpll meson8b_mpll1 = { .shift = 14, .width = 1, }, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll1", .ops = &meson_clk_mpll_ops, @@ -341,7 +341,7 @@ static struct meson_clk_mpll meson8b_mpll2 = { .shift = 14, .width = 1, }, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll2", .ops = &meson_clk_mpll_ops, @@ -375,7 +375,7 @@ struct clk_mux meson8b_mpeg_clk_sel = { .shift = 12, .flags = CLK_MUX_READ_ONLY, .table = mux_table_clk81, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_sel", .ops = &clk_mux_ro_ops, @@ -395,7 +395,7 @@ struct clk_divider meson8b_mpeg_clk_div = { .reg = (void *)HHI_MPEG_CLK_CNTL, .shift = 0, .width = 7, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_div", .ops = &clk_divider_ops, @@ -408,7 +408,7 @@ struct clk_divider meson8b_mpeg_clk_div = { struct clk_gate meson8b_clk81 = { .reg = (void *)HHI_MPEG_CLK_CNTL, .bit_idx = 7, - .lock = &clk_lock, + .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "clk81", .ops = &clk_gate_ops, @@ -773,7 +773,7 @@ static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev, reset = &meson8b_clk_reset_bits[id]; - spin_lock_irqsave(&clk_lock, flags); + spin_lock_irqsave(&meson_clk_lock, flags); val = readl(meson8b_clk_reset->base + reset->reg); if (assert) @@ -782,7 +782,7 @@ static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev, val &= ~BIT(reset->bit_idx); writel(val, meson8b_clk_reset->base + reset->reg); - spin_unlock_irqrestore(&clk_lock, flags); + spin_unlock_irqrestore(&meson_clk_lock, flags); return 0; } diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c index cecb0fdfaef6..87213ea7fc84 100644 --- a/drivers/clk/mvebu/armada-37xx-periph.c +++ b/drivers/clk/mvebu/armada-37xx-periph.c @@ -21,9 +21,11 @@ */ #include +#include #include #include #include +#include #include #define TBG_SEL 0x0 @@ -33,6 +35,26 @@ #define CLK_SEL 0x10 #define CLK_DIS 0x14 +#define LOAD_LEVEL_NR 4 + +#define ARMADA_37XX_NB_L0L1 0x18 +#define ARMADA_37XX_NB_L2L3 0x1C +#define ARMADA_37XX_NB_TBG_DIV_OFF 13 +#define ARMADA_37XX_NB_TBG_DIV_MASK 0x7 +#define ARMADA_37XX_NB_CLK_SEL_OFF 11 +#define ARMADA_37XX_NB_CLK_SEL_MASK 0x1 +#define ARMADA_37XX_NB_TBG_SEL_OFF 9 +#define ARMADA_37XX_NB_TBG_SEL_MASK 0x3 +#define ARMADA_37XX_NB_CONFIG_SHIFT 16 +#define ARMADA_37XX_NB_DYN_MOD 0x24 +#define ARMADA_37XX_NB_DFS_EN 31 +#define ARMADA_37XX_NB_CPU_LOAD 0x30 +#define ARMADA_37XX_NB_CPU_LOAD_MASK 0x3 +#define ARMADA_37XX_DVFS_LOAD_0 0 +#define ARMADA_37XX_DVFS_LOAD_1 1 +#define ARMADA_37XX_DVFS_LOAD_2 2 +#define ARMADA_37XX_DVFS_LOAD_3 3 + struct clk_periph_driver_data { struct clk_hw_onecell_data *hw_data; spinlock_t lock; @@ -46,7 +68,18 @@ struct clk_double_div { u8 shift2; }; +struct clk_pm_cpu { + struct clk_hw hw; + void __iomem *reg_mux; + u8 shift_mux; + u32 mask_mux; + void __iomem *reg_div; + u8 shift_div; + struct regmap *nb_pm_base; +}; + #define to_clk_double_div(_hw) container_of(_hw, struct clk_double_div, hw) +#define to_clk_pm_cpu(_hw) container_of(_hw, struct clk_pm_cpu, hw) struct clk_periph_data { const char *name; @@ -55,6 +88,7 @@ struct clk_periph_data { struct clk_hw *mux_hw; struct clk_hw *rate_hw; struct clk_hw *gate_hw; + struct clk_hw *muxrate_hw; bool is_double_div; }; @@ -79,7 +113,9 @@ static const struct clk_div_table clk_table2[] = { { .val = 1, .div = 4, }, { .val = 0, .div = 0, }, /* last entry */ }; + static const struct clk_ops clk_double_div_ops; +static const struct clk_ops clk_pm_cpu_ops; #define PERIPH_GATE(_name, _bit) \ struct clk_gate gate_##_name = { \ @@ -121,6 +157,18 @@ struct clk_divider rate_##_name = { \ } \ }; +#define PERIPH_PM_CPU(_name, _shift1, _reg, _shift2) \ +struct clk_pm_cpu muxrate_##_name = { \ + .reg_mux = (void *)TBG_SEL, \ + .mask_mux = 3, \ + .shift_mux = _shift1, \ + .reg_div = (void *)_reg, \ + .shift_div = _shift2, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_pm_cpu_ops, \ + } \ +}; + #define PERIPH_CLK_FULL_DD(_name, _bit, _shift, _reg1, _reg2, _shift1, _shift2)\ static PERIPH_GATE(_name, _bit); \ static PERIPH_MUX(_name, _shift); \ @@ -135,10 +183,6 @@ static PERIPH_DIV(_name, _reg, _shift1, _table); static PERIPH_GATE(_name, _bit); \ static PERIPH_DIV(_name, _reg, _shift, _table); -#define PERIPH_CLK_MUX_DIV(_name, _shift, _reg, _shift_div, _table) \ -static PERIPH_MUX(_name, _shift); \ -static PERIPH_DIV(_name, _reg, _shift_div, _table); - #define PERIPH_CLK_MUX_DD(_name, _shift, _reg1, _reg2, _shift1, _shift2)\ static PERIPH_MUX(_name, _shift); \ static PERIPH_DOUBLEDIV(_name, _reg1, _reg2, _shift1, _shift2); @@ -179,13 +223,12 @@ static PERIPH_DOUBLEDIV(_name, _reg1, _reg2, _shift1, _shift2); .rate_hw = &rate_##_name.hw, \ } -#define REF_CLK_MUX_DIV(_name) \ +#define REF_CLK_PM_CPU(_name) \ { .name = #_name, \ .parent_names = (const char *[]){ "TBG-A-P", \ "TBG-B-P", "TBG-A-S", "TBG-B-S"}, \ .num_parents = 4, \ - .mux_hw = &mux_##_name.hw, \ - .rate_hw = &rate_##_name.hw, \ + .muxrate_hw = &muxrate_##_name.hw, \ } #define REF_CLK_MUX_DD(_name) \ @@ -215,9 +258,9 @@ PERIPH_CLK_FULL_DD(ddr_fclk, 21, 16, DIV_SEL0, DIV_SEL0, 15, 12); PERIPH_CLK_FULL(trace, 22, 18, DIV_SEL0, 20, clk_table6); PERIPH_CLK_FULL(counter, 23, 20, DIV_SEL0, 23, clk_table6); PERIPH_CLK_FULL_DD(eip97, 24, 24, DIV_SEL2, DIV_SEL2, 22, 19); -PERIPH_CLK_MUX_DIV(cpu, 22, DIV_SEL0, 28, clk_table6); +static PERIPH_PM_CPU(cpu, 22, DIV_SEL0, 28); -static struct clk_periph_data data_nb[] ={ +static struct clk_periph_data data_nb[] = { REF_CLK_FULL_DD(mmc), REF_CLK_FULL_DD(sata_host), REF_CLK_FULL_DD(sec_at), @@ -234,7 +277,7 @@ static struct clk_periph_data data_nb[] ={ REF_CLK_FULL(trace), REF_CLK_FULL(counter), REF_CLK_FULL_DD(eip97), - REF_CLK_MUX_DIV(cpu), + REF_CLK_PM_CPU(cpu), { }, }; @@ -281,7 +324,7 @@ static unsigned int get_div(void __iomem *reg, int shift) } static unsigned long clk_double_div_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) + unsigned long parent_rate) { struct clk_double_div *double_div = to_clk_double_div(hw); unsigned int div; @@ -296,6 +339,222 @@ static const struct clk_ops clk_double_div_ops = { .recalc_rate = clk_double_div_recalc_rate, }; +static void armada_3700_pm_dvfs_update_regs(unsigned int load_level, + unsigned int *reg, + unsigned int *offset) +{ + if (load_level <= ARMADA_37XX_DVFS_LOAD_1) + *reg = ARMADA_37XX_NB_L0L1; + else + *reg = ARMADA_37XX_NB_L2L3; + + if (load_level == ARMADA_37XX_DVFS_LOAD_0 || + load_level == ARMADA_37XX_DVFS_LOAD_2) + *offset += ARMADA_37XX_NB_CONFIG_SHIFT; +} + +static bool armada_3700_pm_dvfs_is_enabled(struct regmap *base) +{ + unsigned int val, reg = ARMADA_37XX_NB_DYN_MOD; + + if (IS_ERR(base)) + return false; + + regmap_read(base, reg, &val); + + return !!(val & BIT(ARMADA_37XX_NB_DFS_EN)); +} + +static unsigned int armada_3700_pm_dvfs_get_cpu_div(struct regmap *base) +{ + unsigned int reg = ARMADA_37XX_NB_CPU_LOAD; + unsigned int offset = ARMADA_37XX_NB_TBG_DIV_OFF; + unsigned int load_level, div; + + /* + * This function is always called after the function + * armada_3700_pm_dvfs_is_enabled, so no need to check again + * if the base is valid. + */ + regmap_read(base, reg, &load_level); + + /* + * The register and the offset inside this register accessed to + * read the current divider depend on the load level + */ + load_level &= ARMADA_37XX_NB_CPU_LOAD_MASK; + armada_3700_pm_dvfs_update_regs(load_level, ®, &offset); + + regmap_read(base, reg, &div); + + return (div >> offset) & ARMADA_37XX_NB_TBG_DIV_MASK; +} + +static unsigned int armada_3700_pm_dvfs_get_cpu_parent(struct regmap *base) +{ + unsigned int reg = ARMADA_37XX_NB_CPU_LOAD; + unsigned int offset = ARMADA_37XX_NB_TBG_SEL_OFF; + unsigned int load_level, sel; + + /* + * This function is always called after the function + * armada_3700_pm_dvfs_is_enabled, so no need to check again + * if the base is valid + */ + regmap_read(base, reg, &load_level); + + /* + * The register and the offset inside this register accessed to + * read the current divider depend on the load level + */ + load_level &= ARMADA_37XX_NB_CPU_LOAD_MASK; + armada_3700_pm_dvfs_update_regs(load_level, ®, &offset); + + regmap_read(base, reg, &sel); + + return (sel >> offset) & ARMADA_37XX_NB_TBG_SEL_MASK; +} + +static u8 clk_pm_cpu_get_parent(struct clk_hw *hw) +{ + struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw); + int num_parents = clk_hw_get_num_parents(hw); + u32 val; + + if (armada_3700_pm_dvfs_is_enabled(pm_cpu->nb_pm_base)) { + val = armada_3700_pm_dvfs_get_cpu_parent(pm_cpu->nb_pm_base); + } else { + val = readl(pm_cpu->reg_mux) >> pm_cpu->shift_mux; + val &= pm_cpu->mask_mux; + } + + if (val >= num_parents) + return -EINVAL; + + return val; +} + +static int clk_pm_cpu_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw); + struct regmap *base = pm_cpu->nb_pm_base; + int load_level; + + /* + * We set the clock parent only if the DVFS is available but + * not enabled. + */ + if (IS_ERR(base) || armada_3700_pm_dvfs_is_enabled(base)) + return -EINVAL; + + /* Set the parent clock for all the load level */ + for (load_level = 0; load_level < LOAD_LEVEL_NR; load_level++) { + unsigned int reg, mask, val, + offset = ARMADA_37XX_NB_TBG_SEL_OFF; + + armada_3700_pm_dvfs_update_regs(load_level, ®, &offset); + + val = index << offset; + mask = ARMADA_37XX_NB_TBG_SEL_MASK << offset; + regmap_update_bits(base, reg, mask, val); + } + return 0; +} + +static unsigned long clk_pm_cpu_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw); + unsigned int div; + + if (armada_3700_pm_dvfs_is_enabled(pm_cpu->nb_pm_base)) + div = armada_3700_pm_dvfs_get_cpu_div(pm_cpu->nb_pm_base); + else + div = get_div(pm_cpu->reg_div, pm_cpu->shift_div); + return DIV_ROUND_UP_ULL((u64)parent_rate, div); +} + +static long clk_pm_cpu_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw); + struct regmap *base = pm_cpu->nb_pm_base; + unsigned int div = *parent_rate / rate; + unsigned int load_level; + /* only available when DVFS is enabled */ + if (!armada_3700_pm_dvfs_is_enabled(base)) + return -EINVAL; + + for (load_level = 0; load_level < LOAD_LEVEL_NR; load_level++) { + unsigned int reg, val, offset = ARMADA_37XX_NB_TBG_DIV_OFF; + + armada_3700_pm_dvfs_update_regs(load_level, ®, &offset); + + regmap_read(base, reg, &val); + + val >>= offset; + val &= ARMADA_37XX_NB_TBG_DIV_MASK; + if (val == div) + /* + * We found a load level matching the target + * divider, switch to this load level and + * return. + */ + return *parent_rate / div; + } + + /* We didn't find any valid divider */ + return -EINVAL; +} + +static int clk_pm_cpu_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw); + struct regmap *base = pm_cpu->nb_pm_base; + unsigned int div = parent_rate / rate; + unsigned int load_level; + + /* only available when DVFS is enabled */ + if (!armada_3700_pm_dvfs_is_enabled(base)) + return -EINVAL; + + for (load_level = 0; load_level < LOAD_LEVEL_NR; load_level++) { + unsigned int reg, mask, val, + offset = ARMADA_37XX_NB_TBG_DIV_OFF; + + armada_3700_pm_dvfs_update_regs(load_level, ®, &offset); + + regmap_read(base, reg, &val); + val >>= offset; + val &= ARMADA_37XX_NB_TBG_DIV_MASK; + + if (val == div) { + /* + * We found a load level matching the target + * divider, switch to this load level and + * return. + */ + reg = ARMADA_37XX_NB_CPU_LOAD; + mask = ARMADA_37XX_NB_CPU_LOAD_MASK; + regmap_update_bits(base, reg, mask, load_level); + + return rate; + } + } + + /* We didn't find any valid divider */ + return -EINVAL; +} + +static const struct clk_ops clk_pm_cpu_ops = { + .get_parent = clk_pm_cpu_get_parent, + .set_parent = clk_pm_cpu_set_parent, + .round_rate = clk_pm_cpu_round_rate, + .set_rate = clk_pm_cpu_set_rate, + .recalc_rate = clk_pm_cpu_recalc_rate, +}; + static const struct of_device_id armada_3700_periph_clock_of_match[] = { { .compatible = "marvell,armada-3700-periph-clock-nb", .data = data_nb, }, @@ -303,6 +562,7 @@ static const struct of_device_id armada_3700_periph_clock_of_match[] = { .data = data_sb, }, { } }; + static int armada_3700_add_composite_clk(const struct clk_periph_data *data, void __iomem *reg, spinlock_t *lock, struct device *dev, struct clk_hw **hw) @@ -354,15 +614,31 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data, } } + if (data->muxrate_hw) { + struct clk_pm_cpu *pmcpu_clk; + struct clk_hw *muxrate_hw = data->muxrate_hw; + struct regmap *map; + + pmcpu_clk = to_clk_pm_cpu(muxrate_hw); + pmcpu_clk->reg_mux = reg + (u64)pmcpu_clk->reg_mux; + pmcpu_clk->reg_div = reg + (u64)pmcpu_clk->reg_div; + + mux_hw = muxrate_hw; + rate_hw = muxrate_hw; + mux_ops = muxrate_hw->init->ops; + rate_ops = muxrate_hw->init->ops; + + map = syscon_regmap_lookup_by_compatible( + "marvell,armada-3700-nb-pm"); + pmcpu_clk->nb_pm_base = map; + } + *hw = clk_hw_register_composite(dev, data->name, data->parent_names, - data->num_parents, mux_hw, - mux_ops, rate_hw, rate_ops, - gate_hw, gate_ops, CLK_IGNORE_UNUSED); + data->num_parents, mux_hw, + mux_ops, rate_hw, rate_ops, + gate_hw, gate_ops, CLK_IGNORE_UNUSED); - if (IS_ERR(*hw)) - return PTR_ERR(*hw); - - return 0; + return PTR_ERR_OR_ZERO(*hw); } static int armada_3700_periph_clock_probe(struct platform_device *pdev) @@ -406,12 +682,11 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev) if (armada_3700_add_composite_clk(&data[i], reg, &driver_data->lock, dev, hw)) dev_err(dev, "Can't register periph clock %s\n", - data[i].name); - + data[i].name); } ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, - driver_data->hw_data); + driver_data->hw_data); if (ret) { for (i = 0; i < num_periph; i++) clk_hw_unregister(driver_data->hw_data->hws[i]); diff --git a/drivers/clk/nxp/clk-lpc32xx.c b/drivers/clk/nxp/clk-lpc32xx.c index 7b359afd620e..f5d815f577e0 100644 --- a/drivers/clk/nxp/clk-lpc32xx.c +++ b/drivers/clk/nxp/clk-lpc32xx.c @@ -526,7 +526,7 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, !(pll_is_valid(parent_rate, 1, 1000000, 20000000) && pll_is_valid(cco_rate, 1, 156000000, 320000000) && pll_is_valid(ref_rate, 1, 1000000, 27000000))) - pr_err("%s: PLL clocks are not in valid ranges: %lu/%lu/%lu", + pr_err("%s: PLL clocks are not in valid ranges: %lu/%lu/%lu\n", clk_hw_get_name(hw), parent_rate, cco_rate, ref_rate); @@ -956,7 +956,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, val &= div_mask(divider->width); return divider_recalc_rate(hw, parent_rate, val, divider->table, - divider->flags); + divider->flags, divider->width); } static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, @@ -1505,7 +1505,7 @@ static void __init lpc32xx_clk_init(struct device_node *np) return; } if (clk_get_rate(clk_32k) != 32768) { - pr_err("invalid clock rate of external 32KHz oscillator"); + pr_err("invalid clock rate of external 32KHz oscillator\n"); return; } diff --git a/drivers/clk/pxa/clk-pxa3xx.c b/drivers/clk/pxa/clk-pxa3xx.c index 42bdaa772be0..2d126df2bccd 100644 --- a/drivers/clk/pxa/clk-pxa3xx.c +++ b/drivers/clk/pxa/clk-pxa3xx.c @@ -329,12 +329,16 @@ static void __init pxa3xx_dummy_clocks_init(void) static void __init pxa3xx_base_clocks_init(void) { + struct clk *clk; + pxa3xx_register_plls(); pxa3xx_register_core(); clk_register_clk_pxa3xx_system_bus(); clk_register_clk_pxa3xx_ac97(); clk_register_clk_pxa3xx_smemc(); - clk_register_gate(NULL, "CLK_POUT", "osc_13mhz", 0, OSCC, 11, 0, NULL); + clk = clk_register_gate(NULL, "CLK_POUT", + "osc_13mhz", 0, OSCC, 11, 0, NULL); + clk_register_clkdev(clk, "CLK_POUT", NULL); clkdev_pxa_register(CLK_OSTIMER, "OSTIMER0", NULL, clk_register_fixed_factor(NULL, "os-timer0", "osc_13mhz", 0, 1, 4)); diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 9f6c278deead..fbf4532f94b8 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -12,6 +12,27 @@ config COMMON_CLK_QCOM select REGMAP_MMIO select RESET_CONTROLLER +config QCOM_A53PLL + tristate "MSM8916 A53 PLL" + depends on COMMON_CLK_QCOM + default ARCH_QCOM + help + Support for the A53 PLL on MSM8916 devices. It provides + the CPU with frequencies above 1GHz. + Say Y if you want to support higher CPU frequencies on MSM8916 + devices. + +config QCOM_CLK_APCS_MSM8916 + tristate "MSM8916 APCS Clock Controller" + depends on COMMON_CLK_QCOM + depends on QCOM_APCS_IPC || COMPILE_TEST + default ARCH_QCOM + help + Support for the APCS Clock Controller on msm8916 devices. The + APCS is managing the mux and divider which feeds the CPUs. + Say Y if you want to support CPU frequency scaling on devices + such as msm8916. + config QCOM_CLK_RPM tristate "RPM based Clock Controller" depends on COMMON_CLK_QCOM && MFD_QCOM_RPM @@ -196,3 +217,12 @@ config MSM_MMCC_8996 Support for the multimedia clock controller on msm8996 devices. Say Y if you want to support multimedia devices such as display, graphics, video encode/decode, camera, etc. + +config SPMI_PMIC_CLKDIV + tristate "SPMI PMIC clkdiv Support" + depends on (COMMON_CLK_QCOM && SPMI) || COMPILE_TEST + help + This driver supports the clkdiv functionality on the Qualcomm + Technologies, Inc. SPMI PMIC. It configures the frequency of + clkdiv outputs of the PMIC. These clocks are typically wired + through alternate functions on GPIO pins. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 26410d31446b..230332cf317e 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -10,6 +10,7 @@ clk-qcom-y += clk-rcg2.o clk-qcom-y += clk-branch.o clk-qcom-y += clk-regmap-divider.o clk-qcom-y += clk-regmap-mux.o +clk-qcom-y += clk-regmap-mux-div.o clk-qcom-y += reset.o clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o @@ -32,5 +33,8 @@ obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o +obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o +obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o +obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o diff --git a/drivers/clk/qcom/a53-pll.c b/drivers/clk/qcom/a53-pll.c new file mode 100644 index 000000000000..45cfc57bff92 --- /dev/null +++ b/drivers/clk/qcom/a53-pll.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Qualcomm A53 PLL driver + * + * Copyright (c) 2017, Linaro Limited + * Author: Georgi Djakov + */ + +#include +#include +#include +#include +#include + +#include "clk-pll.h" +#include "clk-regmap.h" + +static const struct pll_freq_tbl a53pll_freq[] = { + { 998400000, 52, 0x0, 0x1, 0 }, + { 1094400000, 57, 0x0, 0x1, 0 }, + { 1152000000, 62, 0x0, 0x1, 0 }, + { 1209600000, 63, 0x0, 0x1, 0 }, + { 1248000000, 65, 0x0, 0x1, 0 }, + { 1363200000, 71, 0x0, 0x1, 0 }, + { 1401600000, 73, 0x0, 0x1, 0 }, + { } +}; + +static const struct regmap_config a53pll_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x40, + .fast_io = true, +}; + +static int qcom_a53pll_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct regmap *regmap; + struct resource *res; + struct clk_pll *pll; + void __iomem *base; + struct clk_init_data init = { }; + int ret; + + pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); + if (!pll) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + regmap = devm_regmap_init_mmio(dev, base, &a53pll_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + pll->l_reg = 0x04; + pll->m_reg = 0x08; + pll->n_reg = 0x0c; + pll->config_reg = 0x14; + pll->mode_reg = 0x00; + pll->status_reg = 0x1c; + pll->status_bit = 16; + pll->freq_tbl = a53pll_freq; + + init.name = "a53pll"; + init.parent_names = (const char *[]){ "xo" }; + init.num_parents = 1; + init.ops = &clk_pll_sr2_ops; + init.flags = CLK_IS_CRITICAL; + pll->clkr.hw.init = &init; + + ret = devm_clk_register_regmap(dev, &pll->clkr); + if (ret) { + dev_err(dev, "failed to register regmap clock: %d\n", ret); + return ret; + } + + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, + &pll->clkr.hw); + if (ret) { + dev_err(dev, "failed to add clock provider: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct of_device_id qcom_a53pll_match_table[] = { + { .compatible = "qcom,msm8916-a53pll" }, + { } +}; + +static struct platform_driver qcom_a53pll_driver = { + .probe = qcom_a53pll_probe, + .driver = { + .name = "qcom-a53pll", + .of_match_table = qcom_a53pll_match_table, + }, +}; +module_platform_driver(qcom_a53pll_driver); + +MODULE_DESCRIPTION("Qualcomm A53 PLL Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/qcom/apcs-msm8916.c b/drivers/clk/qcom/apcs-msm8916.c new file mode 100644 index 000000000000..246957f1a413 --- /dev/null +++ b/drivers/clk/qcom/apcs-msm8916.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Qualcomm APCS clock controller driver + * + * Copyright (c) 2017, Linaro Limited + * Author: Georgi Djakov + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clk-regmap.h" +#include "clk-regmap-mux-div.h" + +static const u32 gpll0_a53cc_map[] = { 4, 5 }; + +static const char * const gpll0_a53cc[] = { + "gpll0_vote", + "a53pll", +}; + +/* + * We use the notifier function for switching to a temporary safe configuration + * (mux and divider), while the A53 PLL is reconfigured. + */ +static int a53cc_notifier_cb(struct notifier_block *nb, unsigned long event, + void *data) +{ + int ret = 0; + struct clk_regmap_mux_div *md = container_of(nb, + struct clk_regmap_mux_div, + clk_nb); + if (event == PRE_RATE_CHANGE) + /* set the mux and divider to safe frequency (400mhz) */ + ret = mux_div_set_src_div(md, 4, 3); + + return notifier_from_errno(ret); +} + +static int qcom_apcs_msm8916_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device *parent = dev->parent; + struct clk_regmap_mux_div *a53cc; + struct regmap *regmap; + struct clk_init_data init = { }; + int ret; + + regmap = dev_get_regmap(parent, NULL); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(dev, "failed to get regmap: %d\n", ret); + return ret; + } + + a53cc = devm_kzalloc(dev, sizeof(*a53cc), GFP_KERNEL); + if (!a53cc) + return -ENOMEM; + + init.name = "a53mux"; + init.parent_names = gpll0_a53cc; + init.num_parents = ARRAY_SIZE(gpll0_a53cc); + init.ops = &clk_regmap_mux_div_ops; + init.flags = CLK_SET_RATE_PARENT; + + a53cc->clkr.hw.init = &init; + a53cc->clkr.regmap = regmap; + a53cc->reg_offset = 0x50; + a53cc->hid_width = 5; + a53cc->hid_shift = 0; + a53cc->src_width = 3; + a53cc->src_shift = 8; + a53cc->parent_map = gpll0_a53cc_map; + + a53cc->pclk = devm_clk_get(parent, NULL); + if (IS_ERR(a53cc->pclk)) { + ret = PTR_ERR(a53cc->pclk); + dev_err(dev, "failed to get clk: %d\n", ret); + return ret; + } + + a53cc->clk_nb.notifier_call = a53cc_notifier_cb; + ret = clk_notifier_register(a53cc->pclk, &a53cc->clk_nb); + if (ret) { + dev_err(dev, "failed to register clock notifier: %d\n", ret); + return ret; + } + + ret = devm_clk_register_regmap(dev, &a53cc->clkr); + if (ret) { + dev_err(dev, "failed to register regmap clock: %d\n", ret); + goto err; + } + + ret = of_clk_add_hw_provider(parent->of_node, of_clk_hw_simple_get, + &a53cc->clkr.hw); + if (ret) { + dev_err(dev, "failed to add clock provider: %d\n", ret); + goto err; + } + + platform_set_drvdata(pdev, a53cc); + + return 0; + +err: + clk_notifier_unregister(a53cc->pclk, &a53cc->clk_nb); + return ret; +} + +static int qcom_apcs_msm8916_clk_remove(struct platform_device *pdev) +{ + struct clk_regmap_mux_div *a53cc = platform_get_drvdata(pdev); + struct device *parent = pdev->dev.parent; + + clk_notifier_unregister(a53cc->pclk, &a53cc->clk_nb); + of_clk_del_provider(parent->of_node); + + return 0; +} + +static struct platform_driver qcom_apcs_msm8916_clk_driver = { + .probe = qcom_apcs_msm8916_clk_probe, + .remove = qcom_apcs_msm8916_clk_remove, + .driver = { + .name = "qcom-apcs-msm8916-clk", + }, +}; +module_platform_driver(qcom_apcs_msm8916_clk_driver); + +MODULE_AUTHOR("Georgi Djakov "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Qualcomm MSM8916 APCS clock driver"); diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 47a1da3739ce..6d04cd96482a 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -20,7 +20,7 @@ #include "clk-alpha-pll.h" #include "common.h" -#define PLL_MODE 0x00 +#define PLL_MODE(p) ((p)->offset + 0x0) # define PLL_OUTCTRL BIT(0) # define PLL_BYPASSNL BIT(1) # define PLL_RESET_N BIT(2) @@ -32,35 +32,87 @@ # define PLL_VOTE_FSM_ENA BIT(20) # define PLL_FSM_ENA BIT(20) # define PLL_VOTE_FSM_RESET BIT(21) +# define PLL_UPDATE BIT(22) +# define PLL_UPDATE_BYPASS BIT(23) # define PLL_OFFLINE_ACK BIT(28) +# define ALPHA_PLL_ACK_LATCH BIT(29) # define PLL_ACTIVE_FLAG BIT(30) # define PLL_LOCK_DET BIT(31) -#define PLL_L_VAL 0x04 -#define PLL_ALPHA_VAL 0x08 -#define PLL_ALPHA_VAL_U 0x0c +#define PLL_L_VAL(p) ((p)->offset + (p)->regs[PLL_OFF_L_VAL]) +#define PLL_ALPHA_VAL(p) ((p)->offset + (p)->regs[PLL_OFF_ALPHA_VAL]) +#define PLL_ALPHA_VAL_U(p) ((p)->offset + (p)->regs[PLL_OFF_ALPHA_VAL_U]) -#define PLL_USER_CTL 0x10 +#define PLL_USER_CTL(p) ((p)->offset + (p)->regs[PLL_OFF_USER_CTL]) # define PLL_POST_DIV_SHIFT 8 -# define PLL_POST_DIV_MASK 0xf +# define PLL_POST_DIV_MASK(p) GENMASK((p)->width, 0) # define PLL_ALPHA_EN BIT(24) +# define PLL_ALPHA_MODE BIT(25) # define PLL_VCO_SHIFT 20 # define PLL_VCO_MASK 0x3 -#define PLL_USER_CTL_U 0x14 +#define PLL_USER_CTL_U(p) ((p)->offset + (p)->regs[PLL_OFF_USER_CTL_U]) -#define PLL_CONFIG_CTL 0x18 -#define PLL_CONFIG_CTL_U 0x20 -#define PLL_TEST_CTL 0x1c -#define PLL_TEST_CTL_U 0x20 -#define PLL_STATUS 0x24 +#define PLL_CONFIG_CTL(p) ((p)->offset + (p)->regs[PLL_OFF_CONFIG_CTL]) +#define PLL_CONFIG_CTL_U(p) ((p)->offset + (p)->regs[PLL_OFF_CONFIG_CTL_U]) +#define PLL_TEST_CTL(p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL]) +#define PLL_TEST_CTL_U(p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL_U]) +#define PLL_STATUS(p) ((p)->offset + (p)->regs[PLL_OFF_STATUS]) + +const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { + [CLK_ALPHA_PLL_TYPE_DEFAULT] = { + [PLL_OFF_L_VAL] = 0x04, + [PLL_OFF_ALPHA_VAL] = 0x08, + [PLL_OFF_ALPHA_VAL_U] = 0x0c, + [PLL_OFF_USER_CTL] = 0x10, + [PLL_OFF_USER_CTL_U] = 0x14, + [PLL_OFF_CONFIG_CTL] = 0x18, + [PLL_OFF_TEST_CTL] = 0x1c, + [PLL_OFF_TEST_CTL_U] = 0x20, + [PLL_OFF_STATUS] = 0x24, + }, + [CLK_ALPHA_PLL_TYPE_HUAYRA] = { + [PLL_OFF_L_VAL] = 0x04, + [PLL_OFF_ALPHA_VAL] = 0x08, + [PLL_OFF_USER_CTL] = 0x10, + [PLL_OFF_CONFIG_CTL] = 0x14, + [PLL_OFF_CONFIG_CTL_U] = 0x18, + [PLL_OFF_TEST_CTL] = 0x1c, + [PLL_OFF_TEST_CTL_U] = 0x20, + [PLL_OFF_STATUS] = 0x24, + }, + [CLK_ALPHA_PLL_TYPE_BRAMMO] = { + [PLL_OFF_L_VAL] = 0x04, + [PLL_OFF_ALPHA_VAL] = 0x08, + [PLL_OFF_ALPHA_VAL_U] = 0x0c, + [PLL_OFF_USER_CTL] = 0x10, + [PLL_OFF_CONFIG_CTL] = 0x18, + [PLL_OFF_TEST_CTL] = 0x1c, + [PLL_OFF_STATUS] = 0x24, + }, +}; +EXPORT_SYMBOL_GPL(clk_alpha_pll_regs); /* * Even though 40 bits are present, use only 32 for ease of calculation. */ #define ALPHA_REG_BITWIDTH 40 -#define ALPHA_BITWIDTH 32 -#define ALPHA_16BIT_MASK 0xffff +#define ALPHA_REG_16BIT_WIDTH 16 +#define ALPHA_BITWIDTH 32U +#define ALPHA_SHIFT(w) min(w, ALPHA_BITWIDTH) + +#define PLL_HUAYRA_M_WIDTH 8 +#define PLL_HUAYRA_M_SHIFT 8 +#define PLL_HUAYRA_M_MASK 0xff +#define PLL_HUAYRA_N_SHIFT 0 +#define PLL_HUAYRA_N_MASK 0xff +#define PLL_HUAYRA_ALPHA_WIDTH 16 + +#define pll_alpha_width(p) \ + ((PLL_ALPHA_VAL_U(p) - PLL_ALPHA_VAL(p) == 4) ? \ + ALPHA_REG_BITWIDTH : ALPHA_REG_16BIT_WIDTH) + +#define pll_has_64bit_config(p) ((PLL_CONFIG_CTL_U(p) - PLL_CONFIG_CTL(p)) == 4) #define to_clk_alpha_pll(_hw) container_of(to_clk_regmap(_hw), \ struct clk_alpha_pll, clkr) @@ -71,18 +123,17 @@ static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse, const char *action) { - u32 val, off; + u32 val; int count; int ret; const char *name = clk_hw_get_name(&pll->clkr.hw); - off = pll->offset; - ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); + ret = regmap_read(pll->clkr.regmap, PLL_MODE(pll), &val); if (ret) return ret; for (count = 100; count > 0; count--) { - ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); + ret = regmap_read(pll->clkr.regmap, PLL_MODE(pll), &val); if (ret) return ret; if (inverse && !(val & mask)) @@ -109,16 +160,30 @@ static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse, #define wait_for_pll_offline(pll) \ wait_for_pll(pll, PLL_OFFLINE_ACK, 0, "offline") +#define wait_for_pll_update(pll) \ + wait_for_pll(pll, PLL_UPDATE, 1, "update") + +#define wait_for_pll_update_ack_set(pll) \ + wait_for_pll(pll, ALPHA_PLL_ACK_LATCH, 0, "update_ack_set") + +#define wait_for_pll_update_ack_clear(pll) \ + wait_for_pll(pll, ALPHA_PLL_ACK_LATCH, 1, "update_ack_clear") + void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config) { u32 val, mask; - u32 off = pll->offset; - regmap_write(regmap, off + PLL_L_VAL, config->l); - regmap_write(regmap, off + PLL_ALPHA_VAL, config->alpha); - regmap_write(regmap, off + PLL_CONFIG_CTL, config->config_ctl_val); - regmap_write(regmap, off + PLL_CONFIG_CTL_U, config->config_ctl_hi_val); + regmap_write(regmap, PLL_L_VAL(pll), config->l); + regmap_write(regmap, PLL_ALPHA_VAL(pll), config->alpha); + regmap_write(regmap, PLL_CONFIG_CTL(pll), config->config_ctl_val); + + if (pll_has_64bit_config(pll)) + regmap_write(regmap, PLL_CONFIG_CTL_U(pll), + config->config_ctl_hi_val); + + if (pll_alpha_width(pll) > 32) + regmap_write(regmap, PLL_ALPHA_VAL_U(pll), config->alpha_hi); val = config->main_output_mask; val |= config->aux_output_mask; @@ -127,6 +192,8 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, val |= config->pre_div_val; val |= config->post_div_val; val |= config->vco_val; + val |= config->alpha_en_mask; + val |= config->alpha_mode_mask; mask = config->main_output_mask; mask |= config->aux_output_mask; @@ -136,20 +203,19 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, mask |= config->post_div_mask; mask |= config->vco_mask; - regmap_update_bits(regmap, off + PLL_USER_CTL, mask, val); + regmap_update_bits(regmap, PLL_USER_CTL(pll), mask, val); if (pll->flags & SUPPORTS_FSM_MODE) - qcom_pll_set_fsm_mode(regmap, off + PLL_MODE, 6, 0); + qcom_pll_set_fsm_mode(regmap, PLL_MODE(pll), 6, 0); } static int clk_alpha_pll_hwfsm_enable(struct clk_hw *hw) { int ret; - u32 val, off; struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 val; - off = pll->offset; - ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); + ret = regmap_read(pll->clkr.regmap, PLL_MODE(pll), &val); if (ret) return ret; @@ -158,7 +224,7 @@ static int clk_alpha_pll_hwfsm_enable(struct clk_hw *hw) if (pll->flags & SUPPORTS_OFFLINE_REQ) val &= ~PLL_OFFLINE_REQ; - ret = regmap_write(pll->clkr.regmap, off + PLL_MODE, val); + ret = regmap_write(pll->clkr.regmap, PLL_MODE(pll), val); if (ret) return ret; @@ -171,16 +237,15 @@ static int clk_alpha_pll_hwfsm_enable(struct clk_hw *hw) static void clk_alpha_pll_hwfsm_disable(struct clk_hw *hw) { int ret; - u32 val, off; struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 val; - off = pll->offset; - ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); + ret = regmap_read(pll->clkr.regmap, PLL_MODE(pll), &val); if (ret) return; if (pll->flags & SUPPORTS_OFFLINE_REQ) { - ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, + ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_OFFLINE_REQ, PLL_OFFLINE_REQ); if (ret) return; @@ -191,7 +256,7 @@ static void clk_alpha_pll_hwfsm_disable(struct clk_hw *hw) } /* Disable hwfsm */ - ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, + ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_FSM_ENA, 0); if (ret) return; @@ -202,11 +267,10 @@ static void clk_alpha_pll_hwfsm_disable(struct clk_hw *hw) static int pll_is_enabled(struct clk_hw *hw, u32 mask) { int ret; - u32 val, off; struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 val; - off = pll->offset; - ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); + ret = regmap_read(pll->clkr.regmap, PLL_MODE(pll), &val); if (ret) return ret; @@ -227,12 +291,10 @@ static int clk_alpha_pll_enable(struct clk_hw *hw) { int ret; struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); - u32 val, mask, off; - - off = pll->offset; + u32 val, mask; mask = PLL_OUTCTRL | PLL_RESET_N | PLL_BYPASSNL; - ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); + ret = regmap_read(pll->clkr.regmap, PLL_MODE(pll), &val); if (ret) return ret; @@ -248,7 +310,7 @@ static int clk_alpha_pll_enable(struct clk_hw *hw) if ((val & mask) == mask) return 0; - ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, + ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_BYPASSNL, PLL_BYPASSNL); if (ret) return ret; @@ -260,7 +322,7 @@ static int clk_alpha_pll_enable(struct clk_hw *hw) mb(); udelay(5); - ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, + ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N); if (ret) return ret; @@ -269,7 +331,7 @@ static int clk_alpha_pll_enable(struct clk_hw *hw) if (ret) return ret; - ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, + ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_OUTCTRL, PLL_OUTCTRL); /* Ensure that the write above goes through before returning. */ @@ -281,11 +343,9 @@ static void clk_alpha_pll_disable(struct clk_hw *hw) { int ret; struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); - u32 val, mask, off; + u32 val, mask; - off = pll->offset; - - ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); + ret = regmap_read(pll->clkr.regmap, PLL_MODE(pll), &val); if (ret) return; @@ -296,23 +356,25 @@ static void clk_alpha_pll_disable(struct clk_hw *hw) } mask = PLL_OUTCTRL; - regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, mask, 0); + regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), mask, 0); /* Delay of 2 output clock ticks required until output is disabled */ mb(); udelay(1); mask = PLL_RESET_N | PLL_BYPASSNL; - regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, mask, 0); -} - -static unsigned long alpha_pll_calc_rate(u64 prate, u32 l, u32 a) -{ - return (prate * l) + ((prate * a) >> ALPHA_BITWIDTH); + regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), mask, 0); } static unsigned long -alpha_pll_round_rate(unsigned long rate, unsigned long prate, u32 *l, u64 *a) +alpha_pll_calc_rate(u64 prate, u32 l, u32 a, u32 alpha_width) +{ + return (prate * l) + ((prate * a) >> ALPHA_SHIFT(alpha_width)); +} + +static unsigned long +alpha_pll_round_rate(unsigned long rate, unsigned long prate, u32 *l, u64 *a, + u32 alpha_width) { u64 remainder; u64 quotient; @@ -327,14 +389,15 @@ alpha_pll_round_rate(unsigned long rate, unsigned long prate, u32 *l, u64 *a) } /* Upper ALPHA_BITWIDTH bits of Alpha */ - quotient = remainder << ALPHA_BITWIDTH; + quotient = remainder << ALPHA_SHIFT(alpha_width); + remainder = do_div(quotient, prate); if (remainder) quotient++; *a = quotient; - return alpha_pll_calc_rate(prate, *l, *a); + return alpha_pll_calc_rate(prate, *l, *a, alpha_width); } static const struct pll_vco * @@ -356,71 +419,138 @@ clk_alpha_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) u32 l, low, high, ctl; u64 a = 0, prate = parent_rate; struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); - u32 off = pll->offset; + u32 alpha_width = pll_alpha_width(pll); - regmap_read(pll->clkr.regmap, off + PLL_L_VAL, &l); + regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); - regmap_read(pll->clkr.regmap, off + PLL_USER_CTL, &ctl); + regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl); if (ctl & PLL_ALPHA_EN) { - regmap_read(pll->clkr.regmap, off + PLL_ALPHA_VAL, &low); - if (pll->flags & SUPPORTS_16BIT_ALPHA) { - a = low & ALPHA_16BIT_MASK; - } else { - regmap_read(pll->clkr.regmap, off + PLL_ALPHA_VAL_U, + regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &low); + if (alpha_width > 32) { + regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), &high); a = (u64)high << 32 | low; - a >>= ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH; + } else { + a = low & GENMASK(alpha_width - 1, 0); } + + if (alpha_width > ALPHA_BITWIDTH) + a >>= alpha_width - ALPHA_BITWIDTH; } - return alpha_pll_calc_rate(prate, l, a); + return alpha_pll_calc_rate(prate, l, a, alpha_width); +} + +static int clk_alpha_pll_update_latch(struct clk_alpha_pll *pll, + int (*is_enabled)(struct clk_hw *)) +{ + int ret; + u32 mode; + + if (!is_enabled(&pll->clkr.hw) || + !(pll->flags & SUPPORTS_DYNAMIC_UPDATE)) + return 0; + + regmap_read(pll->clkr.regmap, PLL_MODE(pll), &mode); + + /* Latch the input to the PLL */ + regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_UPDATE, + PLL_UPDATE); + + /* Wait for 2 reference cycle before checking ACK bit */ + udelay(1); + + /* + * PLL will latch the new L, Alpha and freq control word. + * PLL will respond by raising PLL_ACK_LATCH output when new programming + * has been latched in and PLL is being updated. When + * UPDATE_LOGIC_BYPASS bit is not set, PLL_UPDATE will be cleared + * automatically by hardware when PLL_ACK_LATCH is asserted by PLL. + */ + if (mode & PLL_UPDATE_BYPASS) { + ret = wait_for_pll_update_ack_set(pll); + if (ret) + return ret; + + regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_UPDATE, 0); + } else { + ret = wait_for_pll_update(pll); + if (ret) + return ret; + } + + ret = wait_for_pll_update_ack_clear(pll); + if (ret) + return ret; + + /* Wait for PLL output to stabilize */ + udelay(10); + + return 0; +} + +static int __clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long prate, + int (*is_enabled)(struct clk_hw *)) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + const struct pll_vco *vco; + u32 l, alpha_width = pll_alpha_width(pll); + u64 a; + + rate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width); + vco = alpha_pll_find_vco(pll, rate); + if (pll->vco_table && !vco) { + pr_err("alpha pll not in a valid vco range\n"); + return -EINVAL; + } + + regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); + + if (alpha_width > ALPHA_BITWIDTH) + a <<= alpha_width - ALPHA_BITWIDTH; + + if (alpha_width > 32) + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), a >> 32); + + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a); + + if (vco) { + regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll), + PLL_VCO_MASK << PLL_VCO_SHIFT, + vco->val << PLL_VCO_SHIFT); + } + + regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll), + PLL_ALPHA_EN, PLL_ALPHA_EN); + + return clk_alpha_pll_update_latch(pll, is_enabled); } static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate) { - struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); - const struct pll_vco *vco; - u32 l, off = pll->offset; - u64 a; + return __clk_alpha_pll_set_rate(hw, rate, prate, + clk_alpha_pll_is_enabled); +} - rate = alpha_pll_round_rate(rate, prate, &l, &a); - vco = alpha_pll_find_vco(pll, rate); - if (!vco) { - pr_err("alpha pll not in a valid vco range\n"); - return -EINVAL; - } - - regmap_write(pll->clkr.regmap, off + PLL_L_VAL, l); - - if (pll->flags & SUPPORTS_16BIT_ALPHA) { - regmap_write(pll->clkr.regmap, off + PLL_ALPHA_VAL, - a & ALPHA_16BIT_MASK); - } else { - a <<= (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH); - regmap_write(pll->clkr.regmap, off + PLL_ALPHA_VAL_U, a >> 32); - } - - regmap_update_bits(pll->clkr.regmap, off + PLL_USER_CTL, - PLL_VCO_MASK << PLL_VCO_SHIFT, - vco->val << PLL_VCO_SHIFT); - - regmap_update_bits(pll->clkr.regmap, off + PLL_USER_CTL, PLL_ALPHA_EN, - PLL_ALPHA_EN); - - return 0; +static int clk_alpha_pll_hwfsm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long prate) +{ + return __clk_alpha_pll_set_rate(hw, rate, prate, + clk_alpha_pll_hwfsm_is_enabled); } static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); - u32 l; + u32 l, alpha_width = pll_alpha_width(pll); u64 a; unsigned long min_freq, max_freq; - rate = alpha_pll_round_rate(rate, *prate, &l, &a); - if (alpha_pll_find_vco(pll, rate)) + rate = alpha_pll_round_rate(rate, *prate, &l, &a, alpha_width); + if (!pll->vco_table || alpha_pll_find_vco(pll, rate)) return rate; min_freq = pll->vco_table[0].min_freq; @@ -429,6 +559,158 @@ static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate, return clamp(rate, min_freq, max_freq); } +static unsigned long +alpha_huayra_pll_calc_rate(u64 prate, u32 l, u32 a) +{ + /* + * a contains 16 bit alpha_val in two’s compliment number in the range + * of [-0.5, 0.5). + */ + if (a >= BIT(PLL_HUAYRA_ALPHA_WIDTH - 1)) + l -= 1; + + return (prate * l) + (prate * a >> PLL_HUAYRA_ALPHA_WIDTH); +} + +static unsigned long +alpha_huayra_pll_round_rate(unsigned long rate, unsigned long prate, + u32 *l, u32 *a) +{ + u64 remainder; + u64 quotient; + + quotient = rate; + remainder = do_div(quotient, prate); + *l = quotient; + + if (!remainder) { + *a = 0; + return rate; + } + + quotient = remainder << PLL_HUAYRA_ALPHA_WIDTH; + remainder = do_div(quotient, prate); + + if (remainder) + quotient++; + + /* + * alpha_val should be in two’s compliment number in the range + * of [-0.5, 0.5) so if quotient >= 0.5 then increment the l value + * since alpha value will be subtracted in this case. + */ + if (quotient >= BIT(PLL_HUAYRA_ALPHA_WIDTH - 1)) + *l += 1; + + *a = quotient; + return alpha_huayra_pll_calc_rate(prate, *l, *a); +} + +static unsigned long +alpha_pll_huayra_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + u64 rate = parent_rate, tmp; + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 l, alpha = 0, ctl, alpha_m, alpha_n; + + regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); + regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl); + + if (ctl & PLL_ALPHA_EN) { + regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &alpha); + /* + * Depending upon alpha_mode, it can be treated as M/N value or + * as a two’s compliment number. When alpha_mode=1, + * pll_alpha_val<15:8>=M and pll_apla_val<7:0>=N + * + * Fout=FIN*(L+(M/N)) + * + * M is a signed number (-128 to 127) and N is unsigned + * (0 to 255). M/N has to be within +/-0.5. + * + * When alpha_mode=0, it is a two’s compliment number in the + * range [-0.5, 0.5). + * + * Fout=FIN*(L+(alpha_val)/2^16) + * + * where alpha_val is two’s compliment number. + */ + if (!(ctl & PLL_ALPHA_MODE)) + return alpha_huayra_pll_calc_rate(rate, l, alpha); + + alpha_m = alpha >> PLL_HUAYRA_M_SHIFT & PLL_HUAYRA_M_MASK; + alpha_n = alpha >> PLL_HUAYRA_N_SHIFT & PLL_HUAYRA_N_MASK; + + rate *= l; + tmp = parent_rate; + if (alpha_m >= BIT(PLL_HUAYRA_M_WIDTH - 1)) { + alpha_m = BIT(PLL_HUAYRA_M_WIDTH) - alpha_m; + tmp *= alpha_m; + do_div(tmp, alpha_n); + rate -= tmp; + } else { + tmp *= alpha_m; + do_div(tmp, alpha_n); + rate += tmp; + } + + return rate; + } + + return alpha_huayra_pll_calc_rate(rate, l, alpha); +} + +static int alpha_pll_huayra_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long prate) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 l, a, ctl, cur_alpha = 0; + + rate = alpha_huayra_pll_round_rate(rate, prate, &l, &a); + + regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl); + + if (ctl & PLL_ALPHA_EN) + regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &cur_alpha); + + /* + * Huayra PLL supports PLL dynamic programming. User can change L_VAL, + * without having to go through the power on sequence. + */ + if (clk_alpha_pll_is_enabled(hw)) { + if (cur_alpha != a) { + pr_err("clock needs to be gated %s\n", + clk_hw_get_name(hw)); + return -EBUSY; + } + + regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); + /* Ensure that the write above goes to detect L val change. */ + mb(); + return wait_for_pll_enable_lock(pll); + } + + regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a); + + if (a == 0) + regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll), + PLL_ALPHA_EN, 0x0); + else + regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll), + PLL_ALPHA_EN | PLL_ALPHA_MODE, PLL_ALPHA_EN); + + return 0; +} + +static long alpha_pll_huayra_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + u32 l, a; + + return alpha_huayra_pll_round_rate(rate, *prate, &l, &a); +} + const struct clk_ops clk_alpha_pll_ops = { .enable = clk_alpha_pll_enable, .disable = clk_alpha_pll_disable, @@ -439,13 +721,23 @@ const struct clk_ops clk_alpha_pll_ops = { }; EXPORT_SYMBOL_GPL(clk_alpha_pll_ops); +const struct clk_ops clk_alpha_pll_huayra_ops = { + .enable = clk_alpha_pll_enable, + .disable = clk_alpha_pll_disable, + .is_enabled = clk_alpha_pll_is_enabled, + .recalc_rate = alpha_pll_huayra_recalc_rate, + .round_rate = alpha_pll_huayra_round_rate, + .set_rate = alpha_pll_huayra_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_alpha_pll_huayra_ops); + const struct clk_ops clk_alpha_pll_hwfsm_ops = { .enable = clk_alpha_pll_hwfsm_enable, .disable = clk_alpha_pll_hwfsm_disable, .is_enabled = clk_alpha_pll_hwfsm_is_enabled, .recalc_rate = clk_alpha_pll_recalc_rate, .round_rate = clk_alpha_pll_round_rate, - .set_rate = clk_alpha_pll_set_rate, + .set_rate = clk_alpha_pll_hwfsm_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_hwfsm_ops); @@ -455,10 +747,10 @@ clk_alpha_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); u32 ctl; - regmap_read(pll->clkr.regmap, pll->offset + PLL_USER_CTL, &ctl); + regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl); ctl >>= PLL_POST_DIV_SHIFT; - ctl &= PLL_POST_DIV_MASK; + ctl &= PLL_POST_DIV_MASK(pll); return parent_rate >> fls(ctl); } @@ -472,16 +764,48 @@ static const struct clk_div_table clk_alpha_div_table[] = { { } }; +static const struct clk_div_table clk_alpha_2bit_div_table[] = { + { 0x0, 1 }, + { 0x1, 2 }, + { 0x3, 4 }, + { } +}; + static long clk_alpha_pll_postdiv_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); + const struct clk_div_table *table; - return divider_round_rate(hw, rate, prate, clk_alpha_div_table, + if (pll->width == 2) + table = clk_alpha_2bit_div_table; + else + table = clk_alpha_div_table; + + return divider_round_rate(hw, rate, prate, table, pll->width, CLK_DIVIDER_POWER_OF_TWO); } +static long +clk_alpha_pll_postdiv_round_ro_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); + u32 ctl, div; + + regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl); + + ctl >>= PLL_POST_DIV_SHIFT; + ctl &= BIT(pll->width) - 1; + div = 1 << fls(ctl); + + if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) + *prate = clk_hw_round_rate(clk_hw_get_parent(hw), div * rate); + + return DIV_ROUND_UP_ULL((u64)*prate, div); +} + static int clk_alpha_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { @@ -491,8 +815,8 @@ static int clk_alpha_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, /* 16 -> 0xf, 8 -> 0x7, 4 -> 0x3, 2 -> 0x1, 1 -> 0x0 */ div = DIV_ROUND_UP_ULL((u64)parent_rate, rate) - 1; - return regmap_update_bits(pll->clkr.regmap, pll->offset + PLL_USER_CTL, - PLL_POST_DIV_MASK << PLL_POST_DIV_SHIFT, + return regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll), + PLL_POST_DIV_MASK(pll) << PLL_POST_DIV_SHIFT, div << PLL_POST_DIV_SHIFT); } @@ -502,3 +826,9 @@ const struct clk_ops clk_alpha_pll_postdiv_ops = { .set_rate = clk_alpha_pll_postdiv_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_ops); + +const struct clk_ops clk_alpha_pll_postdiv_ro_ops = { + .round_rate = clk_alpha_pll_postdiv_round_ro_rate, + .recalc_rate = clk_alpha_pll_postdiv_recalc_rate, +}; +EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_ro_ops); diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h index d6e1ee2c7348..7593e8a56cf2 100644 --- a/drivers/clk/qcom/clk-alpha-pll.h +++ b/drivers/clk/qcom/clk-alpha-pll.h @@ -17,6 +17,30 @@ #include #include "clk-regmap.h" +/* Alpha PLL types */ +enum { + CLK_ALPHA_PLL_TYPE_DEFAULT, + CLK_ALPHA_PLL_TYPE_HUAYRA, + CLK_ALPHA_PLL_TYPE_BRAMMO, + CLK_ALPHA_PLL_TYPE_MAX, +}; + +enum { + PLL_OFF_L_VAL, + PLL_OFF_ALPHA_VAL, + PLL_OFF_ALPHA_VAL_U, + PLL_OFF_USER_CTL, + PLL_OFF_USER_CTL_U, + PLL_OFF_CONFIG_CTL, + PLL_OFF_CONFIG_CTL_U, + PLL_OFF_TEST_CTL, + PLL_OFF_TEST_CTL_U, + PLL_OFF_STATUS, + PLL_OFF_MAX_REGS +}; + +extern const u8 clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_MAX][PLL_OFF_MAX_REGS]; + struct pll_vco { unsigned long min_freq; unsigned long max_freq; @@ -27,16 +51,18 @@ struct pll_vco { * struct clk_alpha_pll - phase locked loop (PLL) * @offset: base address of registers * @vco_table: array of VCO settings + * @regs: alpha pll register map (see @clk_alpha_pll_regs) * @clkr: regmap clock handle */ struct clk_alpha_pll { u32 offset; + const u8 *regs; const struct pll_vco *vco_table; size_t num_vco; #define SUPPORTS_OFFLINE_REQ BIT(0) -#define SUPPORTS_16BIT_ALPHA BIT(1) #define SUPPORTS_FSM_MODE BIT(2) +#define SUPPORTS_DYNAMIC_UPDATE BIT(3) u8 flags; struct clk_regmap clkr; @@ -45,12 +71,14 @@ struct clk_alpha_pll { /** * struct clk_alpha_pll_postdiv - phase locked loop (PLL) post-divider * @offset: base address of registers + * @regs: alpha pll register map (see @clk_alpha_pll_regs) * @width: width of post-divider * @clkr: regmap clock handle */ struct clk_alpha_pll_postdiv { u32 offset; u8 width; + const u8 *regs; struct clk_regmap clkr; }; @@ -58,12 +86,15 @@ struct clk_alpha_pll_postdiv { struct alpha_pll_config { u32 l; u32 alpha; + u32 alpha_hi; u32 config_ctl_val; u32 config_ctl_hi_val; u32 main_output_mask; u32 aux_output_mask; u32 aux2_output_mask; u32 early_output_mask; + u32 alpha_en_mask; + u32 alpha_mode_mask; u32 pre_div_val; u32 pre_div_mask; u32 post_div_val; @@ -75,6 +106,8 @@ struct alpha_pll_config { extern const struct clk_ops clk_alpha_pll_ops; extern const struct clk_ops clk_alpha_pll_hwfsm_ops; extern const struct clk_ops clk_alpha_pll_postdiv_ops; +extern const struct clk_ops clk_alpha_pll_huayra_ops; +extern const struct clk_ops clk_alpha_pll_postdiv_ro_ops; void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config); diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index a2495457e564..2a7489a84e69 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -25,16 +25,6 @@ struct freq_tbl { u16 n; }; -/** - * struct parent_map - map table for PLL source select configuration values - * @src: source PLL - * @cfg: configuration value - */ -struct parent_map { - u8 src; - u8 cfg; -}; - /** * struct mn - M/N:D counter * @mnctr_en_bit: bit to enable mn counter diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c index 53484912301e..4e9b8c2c8980 100644 --- a/drivers/clk/qcom/clk-regmap-divider.c +++ b/drivers/clk/qcom/clk-regmap-divider.c @@ -23,6 +23,29 @@ static inline struct clk_regmap_div *to_clk_regmap_div(struct clk_hw *hw) return container_of(to_clk_regmap(hw), struct clk_regmap_div, clkr); } +static long div_round_ro_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_regmap_div *divider = to_clk_regmap_div(hw); + struct clk_regmap *clkr = ÷r->clkr; + u32 div; + struct clk_hw *hw_parent = clk_hw_get_parent(hw); + + regmap_read(clkr->regmap, divider->reg, &div); + div >>= divider->shift; + div &= BIT(divider->width) - 1; + div += 1; + + if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { + if (!hw_parent) + return -EINVAL; + + *prate = clk_hw_round_rate(hw_parent, rate * div); + } + + return DIV_ROUND_UP_ULL((u64)*prate, div); +} + static long div_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { @@ -59,7 +82,7 @@ static unsigned long div_recalc_rate(struct clk_hw *hw, div &= BIT(divider->width) - 1; return divider_recalc_rate(hw, parent_rate, div, NULL, - CLK_DIVIDER_ROUND_CLOSEST); + CLK_DIVIDER_ROUND_CLOSEST, divider->width); } const struct clk_ops clk_regmap_div_ops = { @@ -68,3 +91,9 @@ const struct clk_ops clk_regmap_div_ops = { .recalc_rate = div_recalc_rate, }; EXPORT_SYMBOL_GPL(clk_regmap_div_ops); + +const struct clk_ops clk_regmap_div_ro_ops = { + .round_rate = div_round_ro_rate, + .recalc_rate = div_recalc_rate, +}; +EXPORT_SYMBOL_GPL(clk_regmap_div_ro_ops); diff --git a/drivers/clk/qcom/clk-regmap-divider.h b/drivers/clk/qcom/clk-regmap-divider.h index fc4492e3a827..8c39c2703caf 100644 --- a/drivers/clk/qcom/clk-regmap-divider.h +++ b/drivers/clk/qcom/clk-regmap-divider.h @@ -25,5 +25,6 @@ struct clk_regmap_div { }; extern const struct clk_ops clk_regmap_div_ops; +extern const struct clk_ops clk_regmap_div_ro_ops; #endif diff --git a/drivers/clk/qcom/clk-regmap-mux-div.c b/drivers/clk/qcom/clk-regmap-mux-div.c new file mode 100644 index 000000000000..6044839da85a --- /dev/null +++ b/drivers/clk/qcom/clk-regmap-mux-div.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017, Linaro Limited + * Author: Georgi Djakov + */ + +#include +#include +#include +#include + +#include "clk-regmap-mux-div.h" + +#define CMD_RCGR 0x0 +#define CMD_RCGR_UPDATE BIT(0) +#define CMD_RCGR_DIRTY_CFG BIT(4) +#define CMD_RCGR_ROOT_OFF BIT(31) +#define CFG_RCGR 0x4 + +#define to_clk_regmap_mux_div(_hw) \ + container_of(to_clk_regmap(_hw), struct clk_regmap_mux_div, clkr) + +int mux_div_set_src_div(struct clk_regmap_mux_div *md, u32 src, u32 div) +{ + int ret, count; + u32 val, mask; + const char *name = clk_hw_get_name(&md->clkr.hw); + + val = (div << md->hid_shift) | (src << md->src_shift); + mask = ((BIT(md->hid_width) - 1) << md->hid_shift) | + ((BIT(md->src_width) - 1) << md->src_shift); + + ret = regmap_update_bits(md->clkr.regmap, CFG_RCGR + md->reg_offset, + mask, val); + if (ret) + return ret; + + ret = regmap_update_bits(md->clkr.regmap, CMD_RCGR + md->reg_offset, + CMD_RCGR_UPDATE, CMD_RCGR_UPDATE); + if (ret) + return ret; + + /* Wait for update to take effect */ + for (count = 500; count > 0; count--) { + ret = regmap_read(md->clkr.regmap, CMD_RCGR + md->reg_offset, + &val); + if (ret) + return ret; + if (!(val & CMD_RCGR_UPDATE)) + return 0; + udelay(1); + } + + pr_err("%s: RCG did not update its configuration", name); + return -EBUSY; +} +EXPORT_SYMBOL_GPL(mux_div_set_src_div); + +static void mux_div_get_src_div(struct clk_regmap_mux_div *md, u32 *src, + u32 *div) +{ + u32 val, d, s; + const char *name = clk_hw_get_name(&md->clkr.hw); + + regmap_read(md->clkr.regmap, CMD_RCGR + md->reg_offset, &val); + + if (val & CMD_RCGR_DIRTY_CFG) { + pr_err("%s: RCG configuration is pending\n", name); + return; + } + + regmap_read(md->clkr.regmap, CFG_RCGR + md->reg_offset, &val); + s = (val >> md->src_shift); + s &= BIT(md->src_width) - 1; + *src = s; + + d = (val >> md->hid_shift); + d &= BIT(md->hid_width) - 1; + *div = d; +} + +static inline bool is_better_rate(unsigned long req, unsigned long best, + unsigned long new) +{ + return (req <= new && new < best) || (best < req && best < new); +} + +static int mux_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw); + unsigned int i, div, max_div; + unsigned long actual_rate, best_rate = 0; + unsigned long req_rate = req->rate; + + for (i = 0; i < clk_hw_get_num_parents(hw); i++) { + struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i); + unsigned long parent_rate = clk_hw_get_rate(parent); + + max_div = BIT(md->hid_width) - 1; + for (div = 1; div < max_div; div++) { + parent_rate = mult_frac(req_rate, div, 2); + parent_rate = clk_hw_round_rate(parent, parent_rate); + actual_rate = mult_frac(parent_rate, 2, div); + + if (is_better_rate(req_rate, best_rate, actual_rate)) { + best_rate = actual_rate; + req->rate = best_rate; + req->best_parent_rate = parent_rate; + req->best_parent_hw = parent; + } + + if (actual_rate < req_rate || best_rate <= req_rate) + break; + } + } + + if (!best_rate) + return -EINVAL; + + return 0; +} + +static int __mux_div_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long prate, u32 src) +{ + struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw); + int ret; + u32 div, max_div, best_src = 0, best_div = 0; + unsigned int i; + unsigned long actual_rate, best_rate = 0; + + for (i = 0; i < clk_hw_get_num_parents(hw); i++) { + struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i); + unsigned long parent_rate = clk_hw_get_rate(parent); + + max_div = BIT(md->hid_width) - 1; + for (div = 1; div < max_div; div++) { + parent_rate = mult_frac(rate, div, 2); + parent_rate = clk_hw_round_rate(parent, parent_rate); + actual_rate = mult_frac(parent_rate, 2, div); + + if (is_better_rate(rate, best_rate, actual_rate)) { + best_rate = actual_rate; + best_src = md->parent_map[i]; + best_div = div - 1; + } + + if (actual_rate < rate || best_rate <= rate) + break; + } + } + + ret = mux_div_set_src_div(md, best_src, best_div); + if (!ret) { + md->div = best_div; + md->src = best_src; + } + + return ret; +} + +static u8 mux_div_get_parent(struct clk_hw *hw) +{ + struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw); + const char *name = clk_hw_get_name(hw); + u32 i, div, src = 0; + + mux_div_get_src_div(md, &src, &div); + + for (i = 0; i < clk_hw_get_num_parents(hw); i++) + if (src == md->parent_map[i]) + return i; + + pr_err("%s: Can't find parent with src %d\n", name, src); + return 0; +} + +static int mux_div_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw); + + return mux_div_set_src_div(md, md->parent_map[index], md->div); +} + +static int mux_div_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long prate) +{ + struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw); + + return __mux_div_set_rate_and_parent(hw, rate, prate, md->src); +} + +static int mux_div_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long prate, u8 index) +{ + struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw); + + return __mux_div_set_rate_and_parent(hw, rate, prate, + md->parent_map[index]); +} + +static unsigned long mux_div_recalc_rate(struct clk_hw *hw, unsigned long prate) +{ + struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw); + u32 div, src; + int i, num_parents = clk_hw_get_num_parents(hw); + const char *name = clk_hw_get_name(hw); + + mux_div_get_src_div(md, &src, &div); + for (i = 0; i < num_parents; i++) + if (src == md->parent_map[i]) { + struct clk_hw *p = clk_hw_get_parent_by_index(hw, i); + unsigned long parent_rate = clk_hw_get_rate(p); + + return mult_frac(parent_rate, 2, div + 1); + } + + pr_err("%s: Can't find parent %d\n", name, src); + return 0; +} + +const struct clk_ops clk_regmap_mux_div_ops = { + .get_parent = mux_div_get_parent, + .set_parent = mux_div_set_parent, + .set_rate = mux_div_set_rate, + .set_rate_and_parent = mux_div_set_rate_and_parent, + .determine_rate = mux_div_determine_rate, + .recalc_rate = mux_div_recalc_rate, +}; +EXPORT_SYMBOL_GPL(clk_regmap_mux_div_ops); diff --git a/drivers/clk/qcom/clk-regmap-mux-div.h b/drivers/clk/qcom/clk-regmap-mux-div.h new file mode 100644 index 000000000000..6cd6261be7ac --- /dev/null +++ b/drivers/clk/qcom/clk-regmap-mux-div.h @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017, Linaro Limited + * Author: Georgi Djakov + */ + +#ifndef __QCOM_CLK_REGMAP_MUX_DIV_H__ +#define __QCOM_CLK_REGMAP_MUX_DIV_H__ + +#include +#include "clk-regmap.h" + +/** + * struct mux_div_clk - combined mux/divider clock + * @reg_offset: offset of the mux/divider register + * @hid_width: number of bits in half integer divider + * @hid_shift: lowest bit of hid value field + * @src_width: number of bits in source select + * @src_shift: lowest bit of source select field + * @div: the divider raw configuration value + * @src: the mux index which will be used if the clock is enabled + * @parent_map: map from parent_names index to src_sel field + * @clkr: handle between common and hardware-specific interfaces + * @pclk: the input PLL clock + * @clk_nb: clock notifier for rate changes of the input PLL + */ +struct clk_regmap_mux_div { + u32 reg_offset; + u32 hid_width; + u32 hid_shift; + u32 src_width; + u32 src_shift; + u32 div; + u32 src; + const u32 *parent_map; + struct clk_regmap clkr; + struct clk *pclk; + struct notifier_block clk_nb; +}; + +extern const struct clk_ops clk_regmap_mux_div_ops; +extern int mux_div_set_src_div(struct clk_regmap_mux_div *md, u32 src, u32 div); + +#endif diff --git a/drivers/clk/qcom/clk-regmap-mux.c b/drivers/clk/qcom/clk-regmap-mux.c index cae3071f384c..0f3a1bda3e91 100644 --- a/drivers/clk/qcom/clk-regmap-mux.c +++ b/drivers/clk/qcom/clk-regmap-mux.c @@ -35,6 +35,9 @@ static u8 mux_get_parent(struct clk_hw *hw) val >>= mux->shift; val &= mask; + if (mux->parent_map) + return qcom_find_src_index(hw, mux->parent_map, val); + return val; } @@ -45,6 +48,9 @@ static int mux_set_parent(struct clk_hw *hw, u8 index) unsigned int mask = GENMASK(mux->width + mux->shift - 1, mux->shift); unsigned int val; + if (mux->parent_map) + index = mux->parent_map[index].cfg; + val = index; val <<= mux->shift; diff --git a/drivers/clk/qcom/clk-regmap-mux.h b/drivers/clk/qcom/clk-regmap-mux.h index 5cec76154fda..7797cddabe6b 100644 --- a/drivers/clk/qcom/clk-regmap-mux.h +++ b/drivers/clk/qcom/clk-regmap-mux.h @@ -16,11 +16,13 @@ #include #include "clk-regmap.h" +#include "common.h" struct clk_regmap_mux { u32 reg; u32 shift; u32 width; + const struct parent_map *parent_map; struct clk_regmap clkr; }; diff --git a/drivers/clk/qcom/clk-spmi-pmic-div.c b/drivers/clk/qcom/clk-spmi-pmic-div.c new file mode 100644 index 000000000000..8672ab84746f --- /dev/null +++ b/drivers/clk/qcom/clk-spmi-pmic-div.c @@ -0,0 +1,302 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_DIV_CTL1 0x43 +#define DIV_CTL1_DIV_FACTOR_MASK GENMASK(2, 0) + +#define REG_EN_CTL 0x46 +#define REG_EN_MASK BIT(7) + +struct clkdiv { + struct regmap *regmap; + u16 base; + spinlock_t lock; + + struct clk_hw hw; + unsigned int cxo_period_ns; +}; + +static inline struct clkdiv *to_clkdiv(struct clk_hw *hw) +{ + return container_of(hw, struct clkdiv, hw); +} + +static inline unsigned int div_factor_to_div(unsigned int div_factor) +{ + if (!div_factor) + div_factor = 1; + + return 1 << (div_factor - 1); +} + +static inline unsigned int div_to_div_factor(unsigned int div) +{ + return min(ilog2(div) + 1, 7); +} + +static bool is_spmi_pmic_clkdiv_enabled(struct clkdiv *clkdiv) +{ + unsigned int val = 0; + + regmap_read(clkdiv->regmap, clkdiv->base + REG_EN_CTL, &val); + + return val & REG_EN_MASK; +} + +static int +__spmi_pmic_clkdiv_set_enable_state(struct clkdiv *clkdiv, bool enable, + unsigned int div_factor) +{ + int ret; + unsigned int ns = clkdiv->cxo_period_ns; + unsigned int div = div_factor_to_div(div_factor); + + ret = regmap_update_bits(clkdiv->regmap, clkdiv->base + REG_EN_CTL, + REG_EN_MASK, enable ? REG_EN_MASK : 0); + if (ret) + return ret; + + if (enable) + ndelay((2 + 3 * div) * ns); + else + ndelay(3 * div * ns); + + return 0; +} + +static int spmi_pmic_clkdiv_set_enable_state(struct clkdiv *clkdiv, bool enable) +{ + unsigned int div_factor; + + regmap_read(clkdiv->regmap, clkdiv->base + REG_DIV_CTL1, &div_factor); + div_factor &= DIV_CTL1_DIV_FACTOR_MASK; + + return __spmi_pmic_clkdiv_set_enable_state(clkdiv, enable, div_factor); +} + +static int clk_spmi_pmic_div_enable(struct clk_hw *hw) +{ + struct clkdiv *clkdiv = to_clkdiv(hw); + unsigned long flags; + int ret; + + spin_lock_irqsave(&clkdiv->lock, flags); + ret = spmi_pmic_clkdiv_set_enable_state(clkdiv, true); + spin_unlock_irqrestore(&clkdiv->lock, flags); + + return ret; +} + +static void clk_spmi_pmic_div_disable(struct clk_hw *hw) +{ + struct clkdiv *clkdiv = to_clkdiv(hw); + unsigned long flags; + + spin_lock_irqsave(&clkdiv->lock, flags); + spmi_pmic_clkdiv_set_enable_state(clkdiv, false); + spin_unlock_irqrestore(&clkdiv->lock, flags); +} + +static long clk_spmi_pmic_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned int div, div_factor; + + div = DIV_ROUND_UP(*parent_rate, rate); + div_factor = div_to_div_factor(div); + div = div_factor_to_div(div_factor); + + return *parent_rate / div; +} + +static unsigned long +clk_spmi_pmic_div_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct clkdiv *clkdiv = to_clkdiv(hw); + unsigned int div_factor; + + regmap_read(clkdiv->regmap, clkdiv->base + REG_DIV_CTL1, &div_factor); + div_factor &= DIV_CTL1_DIV_FACTOR_MASK; + + return parent_rate / div_factor_to_div(div_factor); +} + +static int clk_spmi_pmic_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clkdiv *clkdiv = to_clkdiv(hw); + unsigned int div_factor = div_to_div_factor(parent_rate / rate); + unsigned long flags; + bool enabled; + int ret; + + spin_lock_irqsave(&clkdiv->lock, flags); + enabled = is_spmi_pmic_clkdiv_enabled(clkdiv); + if (enabled) { + ret = spmi_pmic_clkdiv_set_enable_state(clkdiv, false); + if (ret) + goto unlock; + } + + ret = regmap_update_bits(clkdiv->regmap, clkdiv->base + REG_DIV_CTL1, + DIV_CTL1_DIV_FACTOR_MASK, div_factor); + if (ret) + goto unlock; + + if (enabled) + ret = __spmi_pmic_clkdiv_set_enable_state(clkdiv, true, + div_factor); + +unlock: + spin_unlock_irqrestore(&clkdiv->lock, flags); + + return ret; +} + +static const struct clk_ops clk_spmi_pmic_div_ops = { + .enable = clk_spmi_pmic_div_enable, + .disable = clk_spmi_pmic_div_disable, + .set_rate = clk_spmi_pmic_div_set_rate, + .recalc_rate = clk_spmi_pmic_div_recalc_rate, + .round_rate = clk_spmi_pmic_div_round_rate, +}; + +struct spmi_pmic_div_clk_cc { + int nclks; + struct clkdiv clks[]; +}; + +static struct clk_hw * +spmi_pmic_div_clk_hw_get(struct of_phandle_args *clkspec, void *data) +{ + struct spmi_pmic_div_clk_cc *cc = data; + int idx = clkspec->args[0] - 1; /* Start at 1 instead of 0 */ + + if (idx < 0 || idx >= cc->nclks) { + pr_err("%s: index value %u is invalid; allowed range [1, %d]\n", + __func__, clkspec->args[0], cc->nclks); + return ERR_PTR(-EINVAL); + } + + return &cc->clks[idx].hw; +} + +static int spmi_pmic_clkdiv_probe(struct platform_device *pdev) +{ + struct spmi_pmic_div_clk_cc *cc; + struct clk_init_data init = {}; + struct clkdiv *clkdiv; + struct clk *cxo; + struct regmap *regmap; + struct device *dev = &pdev->dev; + struct device_node *of_node = dev->of_node; + const char *parent_name; + int nclks, i, ret, cxo_hz; + char name[20]; + u32 start; + + ret = of_property_read_u32(of_node, "reg", &start); + if (ret < 0) { + dev_err(dev, "reg property reading failed\n"); + return ret; + } + + regmap = dev_get_regmap(dev->parent, NULL); + if (!regmap) { + dev_err(dev, "Couldn't get parent's regmap\n"); + return -EINVAL; + } + + ret = of_property_read_u32(of_node, "qcom,num-clkdivs", &nclks); + if (ret < 0) { + dev_err(dev, "qcom,num-clkdivs property reading failed, ret=%d\n", + ret); + return ret; + } + + if (!nclks) + return -EINVAL; + + cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*cc->clks) * nclks, + GFP_KERNEL); + if (!cc) + return -ENOMEM; + cc->nclks = nclks; + + cxo = clk_get(dev, "xo"); + if (IS_ERR(cxo)) { + ret = PTR_ERR(cxo); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get xo clock\n"); + return ret; + } + cxo_hz = clk_get_rate(cxo); + clk_put(cxo); + + parent_name = of_clk_get_parent_name(of_node, 0); + if (!parent_name) { + dev_err(dev, "missing parent clock\n"); + return -ENODEV; + } + + init.name = name; + init.parent_names = &parent_name; + init.num_parents = 1; + init.ops = &clk_spmi_pmic_div_ops; + + for (i = 0, clkdiv = cc->clks; i < nclks; i++) { + snprintf(name, sizeof(name), "div_clk%d", i + 1); + + spin_lock_init(&clkdiv[i].lock); + clkdiv[i].base = start + i * 0x100; + clkdiv[i].regmap = regmap; + clkdiv[i].cxo_period_ns = NSEC_PER_SEC / cxo_hz; + clkdiv[i].hw.init = &init; + + ret = devm_clk_hw_register(dev, &clkdiv[i].hw); + if (ret) + return ret; + } + + return devm_of_clk_add_hw_provider(dev, spmi_pmic_div_clk_hw_get, cc); +} + +static const struct of_device_id spmi_pmic_clkdiv_match_table[] = { + { .compatible = "qcom,spmi-clkdiv" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, spmi_pmic_clkdiv_match_table); + +static struct platform_driver spmi_pmic_clkdiv_driver = { + .driver = { + .name = "qcom,spmi-pmic-clkdiv", + .of_match_table = spmi_pmic_clkdiv_match_table, + }, + .probe = spmi_pmic_clkdiv_probe, +}; +module_platform_driver(spmi_pmic_clkdiv_driver); + +MODULE_DESCRIPTION("QCOM SPMI PMIC clkdiv driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h index 23c1927669ba..00196ee15e73 100644 --- a/drivers/clk/qcom/common.h +++ b/drivers/clk/qcom/common.h @@ -20,7 +20,6 @@ struct qcom_reset_map; struct regmap; struct freq_tbl; struct clk_hw; -struct parent_map; #define PLL_LOCK_COUNT_SHIFT 8 #define PLL_LOCK_COUNT_MASK 0x3f @@ -39,6 +38,16 @@ struct qcom_cc_desc { size_t num_gdscs; }; +/** + * struct parent_map - map table for source select configuration values + * @src: source + * @cfg: configuration value + */ +struct parent_map { + u8 src; + u8 cfg; +}; + extern const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate); extern const struct freq_tbl *qcom_find_freq_floor(const struct freq_tbl *f, diff --git a/drivers/clk/qcom/gcc-ipq8074.c b/drivers/clk/qcom/gcc-ipq8074.c index 0f735d37690f..0462f4a8c932 100644 --- a/drivers/clk/qcom/gcc-ipq8074.c +++ b/drivers/clk/qcom/gcc-ipq8074.c @@ -28,6 +28,8 @@ #include "clk-rcg.h" #include "clk-branch.h" #include "clk-alpha-pll.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" #include "reset.h" #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } @@ -36,6 +38,24 @@ enum { P_XO, P_GPLL0, P_GPLL0_DIV2, + P_GPLL2, + P_GPLL4, + P_GPLL6, + P_SLEEP_CLK, + P_PCIE20_PHY0_PIPE, + P_PCIE20_PHY1_PIPE, + P_USB3PHY_0_PIPE, + P_USB3PHY_1_PIPE, + P_UBI32_PLL, + P_NSS_CRYPTO_PLL, + P_BIAS_PLL, + P_BIAS_PLL_NSS_NOC, + P_UNIPHY0_RX, + P_UNIPHY0_TX, + P_UNIPHY1_RX, + P_UNIPHY1_TX, + P_UNIPHY2_RX, + P_UNIPHY2_TX, }; static const char * const gcc_xo_gpll0_gpll0_out_main_div2[] = { @@ -50,8 +70,345 @@ static const struct parent_map gcc_xo_gpll0_gpll0_out_main_div2_map[] = { { P_GPLL0_DIV2, 4 }, }; +static const char * const gcc_xo_gpll0[] = { + "xo", + "gpll0", +}; + +static const struct parent_map gcc_xo_gpll0_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, +}; + +static const char * const gcc_xo_gpll0_gpll2_gpll0_out_main_div2[] = { + "xo", + "gpll0", + "gpll2", + "gpll0_out_main_div2", +}; + +static const struct parent_map gcc_xo_gpll0_gpll2_gpll0_out_main_div2_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL2, 2 }, + { P_GPLL0_DIV2, 4 }, +}; + +static const char * const gcc_xo_gpll0_sleep_clk[] = { + "xo", + "gpll0", + "sleep_clk", +}; + +static const struct parent_map gcc_xo_gpll0_sleep_clk_map[] = { + { P_XO, 0 }, + { P_GPLL0, 2 }, + { P_SLEEP_CLK, 6 }, +}; + +static const char * const gcc_xo_gpll6_gpll0_gpll0_out_main_div2[] = { + "xo", + "gpll6", + "gpll0", + "gpll0_out_main_div2", +}; + +static const struct parent_map gcc_xo_gpll6_gpll0_gpll0_out_main_div2_map[] = { + { P_XO, 0 }, + { P_GPLL6, 1 }, + { P_GPLL0, 3 }, + { P_GPLL0_DIV2, 4 }, +}; + +static const char * const gcc_xo_gpll0_out_main_div2_gpll0[] = { + "xo", + "gpll0_out_main_div2", + "gpll0", +}; + +static const struct parent_map gcc_xo_gpll0_out_main_div2_gpll0_map[] = { + { P_XO, 0 }, + { P_GPLL0_DIV2, 2 }, + { P_GPLL0, 1 }, +}; + +static const char * const gcc_usb3phy_0_cc_pipe_clk_xo[] = { + "usb3phy_0_cc_pipe_clk", + "xo", +}; + +static const struct parent_map gcc_usb3phy_0_cc_pipe_clk_xo_map[] = { + { P_USB3PHY_0_PIPE, 0 }, + { P_XO, 2 }, +}; + +static const char * const gcc_usb3phy_1_cc_pipe_clk_xo[] = { + "usb3phy_1_cc_pipe_clk", + "xo", +}; + +static const struct parent_map gcc_usb3phy_1_cc_pipe_clk_xo_map[] = { + { P_USB3PHY_1_PIPE, 0 }, + { P_XO, 2 }, +}; + +static const char * const gcc_pcie20_phy0_pipe_clk_xo[] = { + "pcie20_phy0_pipe_clk", + "xo", +}; + +static const struct parent_map gcc_pcie20_phy0_pipe_clk_xo_map[] = { + { P_PCIE20_PHY0_PIPE, 0 }, + { P_XO, 2 }, +}; + +static const char * const gcc_pcie20_phy1_pipe_clk_xo[] = { + "pcie20_phy1_pipe_clk", + "xo", +}; + +static const struct parent_map gcc_pcie20_phy1_pipe_clk_xo_map[] = { + { P_PCIE20_PHY1_PIPE, 0 }, + { P_XO, 2 }, +}; + +static const char * const gcc_xo_gpll0_gpll6_gpll0_div2[] = { + "xo", + "gpll0", + "gpll6", + "gpll0_out_main_div2", +}; + +static const struct parent_map gcc_xo_gpll0_gpll6_gpll0_div2_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL6, 2 }, + { P_GPLL0_DIV2, 4 }, +}; + +static const char * const gcc_xo_gpll0_gpll6_gpll0_out_main_div2[] = { + "xo", + "gpll0", + "gpll6", + "gpll0_out_main_div2", +}; + +static const struct parent_map gcc_xo_gpll0_gpll6_gpll0_out_main_div2_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL6, 2 }, + { P_GPLL0_DIV2, 3 }, +}; + +static const char * const gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2[] = { + "xo", + "bias_pll_nss_noc_clk", + "gpll0", + "gpll2", +}; + +static const struct parent_map gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2_map[] = { + { P_XO, 0 }, + { P_BIAS_PLL_NSS_NOC, 1 }, + { P_GPLL0, 2 }, + { P_GPLL2, 3 }, +}; + +static const char * const gcc_xo_nss_crypto_pll_gpll0[] = { + "xo", + "nss_crypto_pll", + "gpll0", +}; + +static const struct parent_map gcc_xo_nss_crypto_pll_gpll0_map[] = { + { P_XO, 0 }, + { P_NSS_CRYPTO_PLL, 1 }, + { P_GPLL0, 2 }, +}; + +static const char * const gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6[] = { + "xo", + "ubi32_pll", + "gpll0", + "gpll2", + "gpll4", + "gpll6", +}; + +static const struct parent_map gcc_xo_ubi32_gpll0_gpll2_gpll4_gpll6_map[] = { + { P_XO, 0 }, + { P_UBI32_PLL, 1 }, + { P_GPLL0, 2 }, + { P_GPLL2, 3 }, + { P_GPLL4, 4 }, + { P_GPLL6, 5 }, +}; + +static const char * const gcc_xo_gpll0_out_main_div2[] = { + "xo", + "gpll0_out_main_div2", +}; + +static const struct parent_map gcc_xo_gpll0_out_main_div2_map[] = { + { P_XO, 0 }, + { P_GPLL0_DIV2, 1 }, +}; + +static const char * const gcc_xo_bias_gpll0_gpll4_nss_ubi32[] = { + "xo", + "bias_pll_cc_clk", + "gpll0", + "gpll4", + "nss_crypto_pll", + "ubi32_pll", +}; + +static const struct parent_map gcc_xo_bias_gpll0_gpll4_nss_ubi32_map[] = { + { P_XO, 0 }, + { P_BIAS_PLL, 1 }, + { P_GPLL0, 2 }, + { P_GPLL4, 3 }, + { P_NSS_CRYPTO_PLL, 4 }, + { P_UBI32_PLL, 5 }, +}; + +static const char * const gcc_xo_gpll0_gpll4[] = { + "xo", + "gpll0", + "gpll4", +}; + +static const struct parent_map gcc_xo_gpll0_gpll4_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL4, 2 }, +}; + +static const char * const gcc_xo_uniphy0_rx_tx_ubi32_bias[] = { + "xo", + "uniphy0_gcc_rx_clk", + "uniphy0_gcc_tx_clk", + "ubi32_pll", + "bias_pll_cc_clk", +}; + +static const struct parent_map gcc_xo_uniphy0_rx_tx_ubi32_bias_map[] = { + { P_XO, 0 }, + { P_UNIPHY0_RX, 1 }, + { P_UNIPHY0_TX, 2 }, + { P_UBI32_PLL, 5 }, + { P_BIAS_PLL, 6 }, +}; + +static const char * const gcc_xo_uniphy0_tx_rx_ubi32_bias[] = { + "xo", + "uniphy0_gcc_tx_clk", + "uniphy0_gcc_rx_clk", + "ubi32_pll", + "bias_pll_cc_clk", +}; + +static const struct parent_map gcc_xo_uniphy0_tx_rx_ubi32_bias_map[] = { + { P_XO, 0 }, + { P_UNIPHY0_TX, 1 }, + { P_UNIPHY0_RX, 2 }, + { P_UBI32_PLL, 5 }, + { P_BIAS_PLL, 6 }, +}; + +static const char * const gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias[] = { + "xo", + "uniphy0_gcc_rx_clk", + "uniphy0_gcc_tx_clk", + "uniphy1_gcc_rx_clk", + "uniphy1_gcc_tx_clk", + "ubi32_pll", + "bias_pll_cc_clk", +}; + +static const struct parent_map +gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias_map[] = { + { P_XO, 0 }, + { P_UNIPHY0_RX, 1 }, + { P_UNIPHY0_TX, 2 }, + { P_UNIPHY1_RX, 3 }, + { P_UNIPHY1_TX, 4 }, + { P_UBI32_PLL, 5 }, + { P_BIAS_PLL, 6 }, +}; + +static const char * const gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias[] = { + "xo", + "uniphy0_gcc_tx_clk", + "uniphy0_gcc_rx_clk", + "uniphy1_gcc_tx_clk", + "uniphy1_gcc_rx_clk", + "ubi32_pll", + "bias_pll_cc_clk", +}; + +static const struct parent_map +gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias_map[] = { + { P_XO, 0 }, + { P_UNIPHY0_TX, 1 }, + { P_UNIPHY0_RX, 2 }, + { P_UNIPHY1_TX, 3 }, + { P_UNIPHY1_RX, 4 }, + { P_UBI32_PLL, 5 }, + { P_BIAS_PLL, 6 }, +}; + +static const char * const gcc_xo_uniphy2_rx_tx_ubi32_bias[] = { + "xo", + "uniphy2_gcc_rx_clk", + "uniphy2_gcc_tx_clk", + "ubi32_pll", + "bias_pll_cc_clk", +}; + +static const struct parent_map gcc_xo_uniphy2_rx_tx_ubi32_bias_map[] = { + { P_XO, 0 }, + { P_UNIPHY2_RX, 1 }, + { P_UNIPHY2_TX, 2 }, + { P_UBI32_PLL, 5 }, + { P_BIAS_PLL, 6 }, +}; + +static const char * const gcc_xo_uniphy2_tx_rx_ubi32_bias[] = { + "xo", + "uniphy2_gcc_tx_clk", + "uniphy2_gcc_rx_clk", + "ubi32_pll", + "bias_pll_cc_clk", +}; + +static const struct parent_map gcc_xo_uniphy2_tx_rx_ubi32_bias_map[] = { + { P_XO, 0 }, + { P_UNIPHY2_TX, 1 }, + { P_UNIPHY2_RX, 2 }, + { P_UBI32_PLL, 5 }, + { P_BIAS_PLL, 6 }, +}; + +static const char * const gcc_xo_gpll0_gpll6_gpll0_sleep_clk[] = { + "xo", + "gpll0", + "gpll6", + "gpll0_out_main_div2", + "sleep_clk", +}; + +static const struct parent_map gcc_xo_gpll0_gpll6_gpll0_sleep_clk_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL6, 2 }, + { P_GPLL0_DIV2, 4 }, + { P_SLEEP_CLK, 6 }, +}; + static struct clk_alpha_pll gpll0_main = { .offset = 0x21000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .clkr = { .enable_reg = 0x0b000, .enable_mask = BIT(0), @@ -82,13 +439,194 @@ static struct clk_fixed_factor gpll0_out_main_div2 = { static struct clk_alpha_pll_postdiv gpll0 = { .offset = 0x21000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .width = 4, .clkr.hw.init = &(struct clk_init_data){ .name = "gpll0", .parent_names = (const char *[]){ "gpll0_main" }, .num_parents = 1, - .ops = &clk_alpha_pll_postdiv_ops, + .ops = &clk_alpha_pll_postdiv_ro_ops, + }, +}; + +static struct clk_alpha_pll gpll2_main = { + .offset = 0x4a000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .clkr = { + .enable_reg = 0x0b000, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "gpll2_main", + .parent_names = (const char *[]){ + "xo" + }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + .flags = CLK_IS_CRITICAL, + }, + }, +}; + +static struct clk_alpha_pll_postdiv gpll2 = { + .offset = 0x4a000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll2", + .parent_names = (const char *[]){ + "gpll2_main" + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_alpha_pll gpll4_main = { + .offset = 0x24000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .clkr = { + .enable_reg = 0x0b000, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data){ + .name = "gpll4_main", + .parent_names = (const char *[]){ + "xo" + }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + .flags = CLK_IS_CRITICAL, + }, + }, +}; + +static struct clk_alpha_pll_postdiv gpll4 = { + .offset = 0x24000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll4", + .parent_names = (const char *[]){ + "gpll4_main" + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_alpha_pll gpll6_main = { + .offset = 0x37000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_BRAMMO], + .flags = SUPPORTS_DYNAMIC_UPDATE, + .clkr = { + .enable_reg = 0x0b000, + .enable_mask = BIT(7), + .hw.init = &(struct clk_init_data){ + .name = "gpll6_main", + .parent_names = (const char *[]){ + "xo" + }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + .flags = CLK_IS_CRITICAL, + }, + }, +}; + +static struct clk_alpha_pll_postdiv gpll6 = { + .offset = 0x37000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_BRAMMO], + .width = 2, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll6", + .parent_names = (const char *[]){ + "gpll6_main" + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor gpll6_out_main_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "gpll6_out_main_div2", + .parent_names = (const char *[]){ + "gpll6_main" + }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_alpha_pll ubi32_pll_main = { + .offset = 0x25000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_HUAYRA], + .flags = SUPPORTS_DYNAMIC_UPDATE, + .clkr = { + .enable_reg = 0x0b000, + .enable_mask = BIT(6), + .hw.init = &(struct clk_init_data){ + .name = "ubi32_pll_main", + .parent_names = (const char *[]){ + "xo" + }, + .num_parents = 1, + .ops = &clk_alpha_pll_huayra_ops, + }, + }, +}; + +static struct clk_alpha_pll_postdiv ubi32_pll = { + .offset = 0x25000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_HUAYRA], + .width = 2, + .clkr.hw.init = &(struct clk_init_data){ + .name = "ubi32_pll", + .parent_names = (const char *[]){ + "ubi32_pll_main" + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_alpha_pll nss_crypto_pll_main = { + .offset = 0x22000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .clkr = { + .enable_reg = 0x0b000, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "nss_crypto_pll_main", + .parent_names = (const char *[]){ + "xo" + }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + }, + }, +}; + +static struct clk_alpha_pll_postdiv nss_crypto_pll = { + .offset = 0x22000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_crypto_pll", + .parent_names = (const char *[]){ + "nss_crypto_pll_main" + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -428,6 +966,1063 @@ static struct clk_rcg2 blsp1_uart6_apps_clk_src = { }, }; +static const struct freq_tbl ftbl_pcie_axi_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + { } +}; + +static struct clk_rcg2 pcie0_axi_clk_src = { + .cmd_rcgr = 0x75054, + .freq_tbl = ftbl_pcie_axi_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pcie0_axi_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_pcie_aux_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), +}; + +static struct clk_rcg2 pcie0_aux_clk_src = { + .cmd_rcgr = 0x75024, + .freq_tbl = ftbl_pcie_aux_clk_src, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_sleep_clk_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pcie0_aux_clk_src", + .parent_names = gcc_xo_gpll0_sleep_clk, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_mux pcie0_pipe_clk_src = { + .reg = 0x7501c, + .shift = 8, + .width = 2, + .parent_map = gcc_pcie20_phy0_pipe_clk_xo_map, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "pcie0_pipe_clk_src", + .parent_names = gcc_pcie20_phy0_pipe_clk_xo, + .num_parents = 2, + .ops = &clk_regmap_mux_closest_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg2 pcie1_axi_clk_src = { + .cmd_rcgr = 0x76054, + .freq_tbl = ftbl_pcie_axi_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pcie1_axi_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 pcie1_aux_clk_src = { + .cmd_rcgr = 0x76024, + .freq_tbl = ftbl_pcie_aux_clk_src, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_sleep_clk_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pcie1_aux_clk_src", + .parent_names = gcc_xo_gpll0_sleep_clk, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_mux pcie1_pipe_clk_src = { + .reg = 0x7601c, + .shift = 8, + .width = 2, + .parent_map = gcc_pcie20_phy1_pipe_clk_xo_map, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "pcie1_pipe_clk_src", + .parent_names = gcc_pcie20_phy1_pipe_clk_xo, + .num_parents = 2, + .ops = &clk_regmap_mux_closest_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl ftbl_sdcc_apps_clk_src[] = { + F(144000, P_XO, 16, 3, 25), + F(400000, P_XO, 12, 1, 4), + F(24000000, P_GPLL2, 12, 1, 4), + F(48000000, P_GPLL2, 12, 1, 2), + F(96000000, P_GPLL2, 12, 0, 0), + F(177777778, P_GPLL0, 4.5, 0, 0), + F(192000000, P_GPLL2, 6, 0, 0), + F(384000000, P_GPLL2, 3, 0, 0), + { } +}; + +static struct clk_rcg2 sdcc1_apps_clk_src = { + .cmd_rcgr = 0x42004, + .freq_tbl = ftbl_sdcc_apps_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll2_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "sdcc1_apps_clk_src", + .parent_names = gcc_xo_gpll0_gpll2_gpll0_out_main_div2, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_sdcc_ice_core_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(160000000, P_GPLL0, 5, 0, 0), + F(308570000, P_GPLL6, 3.5, 0, 0), +}; + +static struct clk_rcg2 sdcc1_ice_core_clk_src = { + .cmd_rcgr = 0x5d000, + .freq_tbl = ftbl_sdcc_ice_core_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll6_gpll0_div2_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "sdcc1_ice_core_clk_src", + .parent_names = gcc_xo_gpll0_gpll6_gpll0_div2, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 sdcc2_apps_clk_src = { + .cmd_rcgr = 0x43004, + .freq_tbl = ftbl_sdcc_apps_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll2_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "sdcc2_apps_clk_src", + .parent_names = gcc_xo_gpll0_gpll2_gpll0_out_main_div2, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_usb_master_clk_src[] = { + F(80000000, P_GPLL0_DIV2, 5, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + F(133330000, P_GPLL0, 6, 0, 0), + { } +}; + +static struct clk_rcg2 usb0_master_clk_src = { + .cmd_rcgr = 0x3e00c, + .freq_tbl = ftbl_usb_master_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_out_main_div2_gpll0_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "usb0_master_clk_src", + .parent_names = gcc_xo_gpll0_out_main_div2_gpll0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_usb_aux_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 usb0_aux_clk_src = { + .cmd_rcgr = 0x3e05c, + .freq_tbl = ftbl_usb_aux_clk_src, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_sleep_clk_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "usb0_aux_clk_src", + .parent_names = gcc_xo_gpll0_sleep_clk, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_usb_mock_utmi_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(20000000, P_GPLL6, 6, 1, 9), + F(60000000, P_GPLL6, 6, 1, 3), + { } +}; + +static struct clk_rcg2 usb0_mock_utmi_clk_src = { + .cmd_rcgr = 0x3e020, + .freq_tbl = ftbl_usb_mock_utmi_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll6_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "usb0_mock_utmi_clk_src", + .parent_names = gcc_xo_gpll6_gpll0_gpll0_out_main_div2, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_mux usb0_pipe_clk_src = { + .reg = 0x3e048, + .shift = 8, + .width = 2, + .parent_map = gcc_usb3phy_0_cc_pipe_clk_xo_map, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "usb0_pipe_clk_src", + .parent_names = gcc_usb3phy_0_cc_pipe_clk_xo, + .num_parents = 2, + .ops = &clk_regmap_mux_closest_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg2 usb1_master_clk_src = { + .cmd_rcgr = 0x3f00c, + .freq_tbl = ftbl_usb_master_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_out_main_div2_gpll0_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "usb1_master_clk_src", + .parent_names = gcc_xo_gpll0_out_main_div2_gpll0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 usb1_aux_clk_src = { + .cmd_rcgr = 0x3f05c, + .freq_tbl = ftbl_usb_aux_clk_src, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_sleep_clk_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "usb1_aux_clk_src", + .parent_names = gcc_xo_gpll0_sleep_clk, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 usb1_mock_utmi_clk_src = { + .cmd_rcgr = 0x3f020, + .freq_tbl = ftbl_usb_mock_utmi_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll6_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "usb1_mock_utmi_clk_src", + .parent_names = gcc_xo_gpll6_gpll0_gpll0_out_main_div2, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_mux usb1_pipe_clk_src = { + .reg = 0x3f048, + .shift = 8, + .width = 2, + .parent_map = gcc_usb3phy_1_cc_pipe_clk_xo_map, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "usb1_pipe_clk_src", + .parent_names = gcc_usb3phy_1_cc_pipe_clk_xo, + .num_parents = 2, + .ops = &clk_regmap_mux_closest_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_xo_clk_src = { + .halt_reg = 0x30018, + .clkr = { + .enable_reg = 0x30018, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_xo_clk_src", + .parent_names = (const char *[]){ + "xo" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_fixed_factor gcc_xo_div4_clk_src = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "gcc_xo_div4_clk_src", + .parent_names = (const char *[]){ + "gcc_xo_clk_src" + }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct freq_tbl ftbl_system_noc_bfdcd_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(50000000, P_GPLL0_DIV2, 8, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + F(133333333, P_GPLL0, 6, 0, 0), + F(160000000, P_GPLL0, 5, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + F(266666667, P_GPLL0, 3, 0, 0), + { } +}; + +static struct clk_rcg2 system_noc_bfdcd_clk_src = { + .cmd_rcgr = 0x26004, + .freq_tbl = ftbl_system_noc_bfdcd_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll6_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "system_noc_bfdcd_clk_src", + .parent_names = gcc_xo_gpll0_gpll6_gpll0_out_main_div2, + .num_parents = 4, + .ops = &clk_rcg2_ops, + .flags = CLK_IS_CRITICAL, + }, +}; + +static struct clk_fixed_factor system_noc_clk_src = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "system_noc_clk_src", + .parent_names = (const char *[]){ + "system_noc_bfdcd_clk_src" + }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct freq_tbl ftbl_nss_ce_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + { } +}; + +static struct clk_rcg2 nss_ce_clk_src = { + .cmd_rcgr = 0x68098, + .freq_tbl = ftbl_nss_ce_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_ce_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_nss_noc_bfdcd_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(461500000, P_BIAS_PLL_NSS_NOC, 1, 0, 0), + { } +}; + +static struct clk_rcg2 nss_noc_bfdcd_clk_src = { + .cmd_rcgr = 0x68088, + .freq_tbl = ftbl_nss_noc_bfdcd_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_noc_bfdcd_clk_src", + .parent_names = gcc_xo_bias_pll_nss_noc_clk_gpll0_gpll2, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_fixed_factor nss_noc_clk_src = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "nss_noc_clk_src", + .parent_names = (const char *[]){ + "nss_noc_bfdcd_clk_src" + }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct freq_tbl ftbl_nss_crypto_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(600000000, P_NSS_CRYPTO_PLL, 1, 0, 0), + { } +}; + +static struct clk_rcg2 nss_crypto_clk_src = { + .cmd_rcgr = 0x68144, + .freq_tbl = ftbl_nss_crypto_clk_src, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_nss_crypto_pll_gpll0_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_crypto_clk_src", + .parent_names = gcc_xo_nss_crypto_pll_gpll0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_nss_ubi_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(187200000, P_UBI32_PLL, 8, 0, 0), + F(748800000, P_UBI32_PLL, 2, 0, 0), + F(1497600000, P_UBI32_PLL, 1, 0, 0), + F(1689600000, P_UBI32_PLL, 1, 0, 0), + { } +}; + +static struct clk_rcg2 nss_ubi0_clk_src = { + .cmd_rcgr = 0x68104, + .freq_tbl = ftbl_nss_ubi_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_ubi32_gpll0_gpll2_gpll4_gpll6_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_ubi0_clk_src", + .parent_names = gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6, + .num_parents = 6, + .ops = &clk_rcg2_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap_div nss_ubi0_div_clk_src = { + .reg = 0x68118, + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "nss_ubi0_div_clk_src", + .parent_names = (const char *[]){ + "nss_ubi0_clk_src" + }, + .num_parents = 1, + .ops = &clk_regmap_div_ro_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg2 nss_ubi1_clk_src = { + .cmd_rcgr = 0x68124, + .freq_tbl = ftbl_nss_ubi_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_ubi32_gpll0_gpll2_gpll4_gpll6_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_ubi1_clk_src", + .parent_names = gcc_xo_ubi32_pll_gpll0_gpll2_gpll4_gpll6, + .num_parents = 6, + .ops = &clk_rcg2_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap_div nss_ubi1_div_clk_src = { + .reg = 0x68138, + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "nss_ubi1_div_clk_src", + .parent_names = (const char *[]){ + "nss_ubi1_clk_src" + }, + .num_parents = 1, + .ops = &clk_regmap_div_ro_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl ftbl_ubi_mpt_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(25000000, P_GPLL0_DIV2, 16, 0, 0), + { } +}; + +static struct clk_rcg2 ubi_mpt_clk_src = { + .cmd_rcgr = 0x68090, + .freq_tbl = ftbl_ubi_mpt_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "ubi_mpt_clk_src", + .parent_names = gcc_xo_gpll0_out_main_div2, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_nss_imem_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(400000000, P_GPLL0, 2, 0, 0), + { } +}; + +static struct clk_rcg2 nss_imem_clk_src = { + .cmd_rcgr = 0x68158, + .freq_tbl = ftbl_nss_imem_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll4_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_imem_clk_src", + .parent_names = gcc_xo_gpll0_gpll4, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_nss_ppe_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(300000000, P_BIAS_PLL, 1, 0, 0), + { } +}; + +static struct clk_rcg2 nss_ppe_clk_src = { + .cmd_rcgr = 0x68080, + .freq_tbl = ftbl_nss_ppe_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_bias_gpll0_gpll4_nss_ubi32_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_ppe_clk_src", + .parent_names = gcc_xo_bias_gpll0_gpll4_nss_ubi32, + .num_parents = 6, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_fixed_factor nss_ppe_cdiv_clk_src = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "nss_ppe_cdiv_clk_src", + .parent_names = (const char *[]){ + "nss_ppe_clk_src" + }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct freq_tbl ftbl_nss_port1_rx_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(25000000, P_UNIPHY0_RX, 5, 0, 0), + F(125000000, P_UNIPHY0_RX, 1, 0, 0), + { } +}; + +static struct clk_rcg2 nss_port1_rx_clk_src = { + .cmd_rcgr = 0x68020, + .freq_tbl = ftbl_nss_port1_rx_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_uniphy0_rx_tx_ubi32_bias_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_port1_rx_clk_src", + .parent_names = gcc_xo_uniphy0_rx_tx_ubi32_bias, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_div nss_port1_rx_div_clk_src = { + .reg = 0x68400, + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "nss_port1_rx_div_clk_src", + .parent_names = (const char *[]){ + "nss_port1_rx_clk_src" + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl ftbl_nss_port1_tx_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(25000000, P_UNIPHY0_TX, 5, 0, 0), + F(125000000, P_UNIPHY0_TX, 1, 0, 0), + { } +}; + +static struct clk_rcg2 nss_port1_tx_clk_src = { + .cmd_rcgr = 0x68028, + .freq_tbl = ftbl_nss_port1_tx_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_uniphy0_tx_rx_ubi32_bias_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_port1_tx_clk_src", + .parent_names = gcc_xo_uniphy0_tx_rx_ubi32_bias, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_div nss_port1_tx_div_clk_src = { + .reg = 0x68404, + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "nss_port1_tx_div_clk_src", + .parent_names = (const char *[]){ + "nss_port1_tx_clk_src" + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg2 nss_port2_rx_clk_src = { + .cmd_rcgr = 0x68030, + .freq_tbl = ftbl_nss_port1_rx_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_uniphy0_rx_tx_ubi32_bias_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_port2_rx_clk_src", + .parent_names = gcc_xo_uniphy0_rx_tx_ubi32_bias, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_div nss_port2_rx_div_clk_src = { + .reg = 0x68410, + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "nss_port2_rx_div_clk_src", + .parent_names = (const char *[]){ + "nss_port2_rx_clk_src" + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg2 nss_port2_tx_clk_src = { + .cmd_rcgr = 0x68038, + .freq_tbl = ftbl_nss_port1_tx_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_uniphy0_tx_rx_ubi32_bias_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_port2_tx_clk_src", + .parent_names = gcc_xo_uniphy0_tx_rx_ubi32_bias, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_div nss_port2_tx_div_clk_src = { + .reg = 0x68414, + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "nss_port2_tx_div_clk_src", + .parent_names = (const char *[]){ + "nss_port2_tx_clk_src" + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg2 nss_port3_rx_clk_src = { + .cmd_rcgr = 0x68040, + .freq_tbl = ftbl_nss_port1_rx_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_uniphy0_rx_tx_ubi32_bias_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_port3_rx_clk_src", + .parent_names = gcc_xo_uniphy0_rx_tx_ubi32_bias, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_div nss_port3_rx_div_clk_src = { + .reg = 0x68420, + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "nss_port3_rx_div_clk_src", + .parent_names = (const char *[]){ + "nss_port3_rx_clk_src" + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg2 nss_port3_tx_clk_src = { + .cmd_rcgr = 0x68048, + .freq_tbl = ftbl_nss_port1_tx_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_uniphy0_tx_rx_ubi32_bias_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_port3_tx_clk_src", + .parent_names = gcc_xo_uniphy0_tx_rx_ubi32_bias, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_div nss_port3_tx_div_clk_src = { + .reg = 0x68424, + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "nss_port3_tx_div_clk_src", + .parent_names = (const char *[]){ + "nss_port3_tx_clk_src" + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg2 nss_port4_rx_clk_src = { + .cmd_rcgr = 0x68050, + .freq_tbl = ftbl_nss_port1_rx_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_uniphy0_rx_tx_ubi32_bias_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_port4_rx_clk_src", + .parent_names = gcc_xo_uniphy0_rx_tx_ubi32_bias, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_div nss_port4_rx_div_clk_src = { + .reg = 0x68430, + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "nss_port4_rx_div_clk_src", + .parent_names = (const char *[]){ + "nss_port4_rx_clk_src" + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg2 nss_port4_tx_clk_src = { + .cmd_rcgr = 0x68058, + .freq_tbl = ftbl_nss_port1_tx_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_uniphy0_tx_rx_ubi32_bias_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_port4_tx_clk_src", + .parent_names = gcc_xo_uniphy0_tx_rx_ubi32_bias, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_div nss_port4_tx_div_clk_src = { + .reg = 0x68434, + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "nss_port4_tx_div_clk_src", + .parent_names = (const char *[]){ + "nss_port4_tx_clk_src" + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl ftbl_nss_port5_rx_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(25000000, P_UNIPHY1_RX, 12.5, 0, 0), + F(78125000, P_UNIPHY1_RX, 4, 0, 0), + F(125000000, P_UNIPHY1_RX, 2.5, 0, 0), + F(156250000, P_UNIPHY1_RX, 2, 0, 0), + F(312500000, P_UNIPHY1_RX, 1, 0, 0), + { } +}; + +static struct clk_rcg2 nss_port5_rx_clk_src = { + .cmd_rcgr = 0x68060, + .freq_tbl = ftbl_nss_port5_rx_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_port5_rx_clk_src", + .parent_names = gcc_xo_uniphy0_rx_tx_uniphy1_rx_tx_ubi32_bias, + .num_parents = 7, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_div nss_port5_rx_div_clk_src = { + .reg = 0x68440, + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "nss_port5_rx_div_clk_src", + .parent_names = (const char *[]){ + "nss_port5_rx_clk_src" + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl ftbl_nss_port5_tx_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(25000000, P_UNIPHY1_TX, 12.5, 0, 0), + F(78125000, P_UNIPHY1_TX, 4, 0, 0), + F(125000000, P_UNIPHY1_TX, 2.5, 0, 0), + F(156250000, P_UNIPHY1_TX, 2, 0, 0), + F(312500000, P_UNIPHY1_TX, 1, 0, 0), + { } +}; + +static struct clk_rcg2 nss_port5_tx_clk_src = { + .cmd_rcgr = 0x68068, + .freq_tbl = ftbl_nss_port5_tx_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_port5_tx_clk_src", + .parent_names = gcc_xo_uniphy0_tx_rx_uniphy1_tx_rx_ubi32_bias, + .num_parents = 7, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_div nss_port5_tx_div_clk_src = { + .reg = 0x68444, + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "nss_port5_tx_div_clk_src", + .parent_names = (const char *[]){ + "nss_port5_tx_clk_src" + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl ftbl_nss_port6_rx_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(25000000, P_UNIPHY2_RX, 12.5, 0, 0), + F(78125000, P_UNIPHY2_RX, 4, 0, 0), + F(125000000, P_UNIPHY2_RX, 2.5, 0, 0), + F(156250000, P_UNIPHY2_RX, 2, 0, 0), + F(312500000, P_UNIPHY2_RX, 1, 0, 0), + { } +}; + +static struct clk_rcg2 nss_port6_rx_clk_src = { + .cmd_rcgr = 0x68070, + .freq_tbl = ftbl_nss_port6_rx_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_uniphy2_rx_tx_ubi32_bias_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_port6_rx_clk_src", + .parent_names = gcc_xo_uniphy2_rx_tx_ubi32_bias, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_div nss_port6_rx_div_clk_src = { + .reg = 0x68450, + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "nss_port6_rx_div_clk_src", + .parent_names = (const char *[]){ + "nss_port6_rx_clk_src" + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl ftbl_nss_port6_tx_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(25000000, P_UNIPHY2_TX, 12.5, 0, 0), + F(78125000, P_UNIPHY2_TX, 4, 0, 0), + F(125000000, P_UNIPHY2_TX, 2.5, 0, 0), + F(156250000, P_UNIPHY2_TX, 2, 0, 0), + F(312500000, P_UNIPHY2_TX, 1, 0, 0), + { } +}; + +static struct clk_rcg2 nss_port6_tx_clk_src = { + .cmd_rcgr = 0x68078, + .freq_tbl = ftbl_nss_port6_tx_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_uniphy2_tx_rx_ubi32_bias_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "nss_port6_tx_clk_src", + .parent_names = gcc_xo_uniphy2_tx_rx_ubi32_bias, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_div nss_port6_tx_div_clk_src = { + .reg = 0x68454, + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "nss_port6_tx_div_clk_src", + .parent_names = (const char *[]){ + "nss_port6_tx_clk_src" + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct freq_tbl ftbl_crypto_clk_src[] = { + F(40000000, P_GPLL0_DIV2, 10, 0, 0), + F(80000000, P_GPLL0, 10, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + F(160000000, P_GPLL0, 5, 0, 0), + { } +}; + +static struct clk_rcg2 crypto_clk_src = { + .cmd_rcgr = 0x16004, + .freq_tbl = ftbl_crypto_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "crypto_clk_src", + .parent_names = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_gp_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gp1_clk_src = { + .cmd_rcgr = 0x08004, + .freq_tbl = ftbl_gp_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll6_gpll0_sleep_clk_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gp1_clk_src", + .parent_names = gcc_xo_gpll0_gpll6_gpll0_sleep_clk, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gp2_clk_src = { + .cmd_rcgr = 0x09004, + .freq_tbl = ftbl_gp_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll6_gpll0_sleep_clk_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gp2_clk_src", + .parent_names = gcc_xo_gpll0_gpll6_gpll0_sleep_clk, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gp3_clk_src = { + .cmd_rcgr = 0x0a004, + .freq_tbl = ftbl_gp_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll6_gpll0_sleep_clk_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gp3_clk_src", + .parent_names = gcc_xo_gpll0_gpll6_gpll0_sleep_clk, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + static struct clk_branch gcc_blsp1_ahb_clk = { .halt_reg = 0x01008, .clkr = { @@ -803,14 +2398,1957 @@ static struct clk_branch gcc_qpic_clk = { }, }; +static struct clk_branch gcc_pcie0_ahb_clk = { + .halt_reg = 0x75010, + .clkr = { + .enable_reg = 0x75010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie0_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie0_aux_clk = { + .halt_reg = 0x75014, + .clkr = { + .enable_reg = 0x75014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie0_aux_clk", + .parent_names = (const char *[]){ + "pcie0_aux_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie0_axi_m_clk = { + .halt_reg = 0x75008, + .clkr = { + .enable_reg = 0x75008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie0_axi_m_clk", + .parent_names = (const char *[]){ + "pcie0_axi_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie0_axi_s_clk = { + .halt_reg = 0x7500c, + .clkr = { + .enable_reg = 0x7500c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie0_axi_s_clk", + .parent_names = (const char *[]){ + "pcie0_axi_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie0_pipe_clk = { + .halt_reg = 0x75018, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x75018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie0_pipe_clk", + .parent_names = (const char *[]){ + "pcie0_pipe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_pcie0_axi_clk = { + .halt_reg = 0x26048, + .clkr = { + .enable_reg = 0x26048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sys_noc_pcie0_axi_clk", + .parent_names = (const char *[]){ + "pcie0_axi_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie1_ahb_clk = { + .halt_reg = 0x76010, + .clkr = { + .enable_reg = 0x76010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie1_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie1_aux_clk = { + .halt_reg = 0x76014, + .clkr = { + .enable_reg = 0x76014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie1_aux_clk", + .parent_names = (const char *[]){ + "pcie1_aux_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie1_axi_m_clk = { + .halt_reg = 0x76008, + .clkr = { + .enable_reg = 0x76008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie1_axi_m_clk", + .parent_names = (const char *[]){ + "pcie1_axi_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie1_axi_s_clk = { + .halt_reg = 0x7600c, + .clkr = { + .enable_reg = 0x7600c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie1_axi_s_clk", + .parent_names = (const char *[]){ + "pcie1_axi_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie1_pipe_clk = { + .halt_reg = 0x76018, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x76018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie1_pipe_clk", + .parent_names = (const char *[]){ + "pcie1_pipe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_pcie1_axi_clk = { + .halt_reg = 0x2604c, + .clkr = { + .enable_reg = 0x2604c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sys_noc_pcie1_axi_clk", + .parent_names = (const char *[]){ + "pcie1_axi_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb0_aux_clk = { + .halt_reg = 0x3e044, + .clkr = { + .enable_reg = 0x3e044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb0_aux_clk", + .parent_names = (const char *[]){ + "usb0_aux_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_usb0_axi_clk = { + .halt_reg = 0x26040, + .clkr = { + .enable_reg = 0x26040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sys_noc_usb0_axi_clk", + .parent_names = (const char *[]){ + "usb0_master_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb0_master_clk = { + .halt_reg = 0x3e000, + .clkr = { + .enable_reg = 0x3e000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb0_master_clk", + .parent_names = (const char *[]){ + "usb0_master_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb0_mock_utmi_clk = { + .halt_reg = 0x3e008, + .clkr = { + .enable_reg = 0x3e008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb0_mock_utmi_clk", + .parent_names = (const char *[]){ + "usb0_mock_utmi_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb0_phy_cfg_ahb_clk = { + .halt_reg = 0x3e080, + .clkr = { + .enable_reg = 0x3e080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb0_phy_cfg_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb0_pipe_clk = { + .halt_reg = 0x3e040, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x3e040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb0_pipe_clk", + .parent_names = (const char *[]){ + "usb0_pipe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb0_sleep_clk = { + .halt_reg = 0x3e004, + .clkr = { + .enable_reg = 0x3e004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb0_sleep_clk", + .parent_names = (const char *[]){ + "gcc_sleep_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb1_aux_clk = { + .halt_reg = 0x3f044, + .clkr = { + .enable_reg = 0x3f044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb1_aux_clk", + .parent_names = (const char *[]){ + "usb1_aux_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_usb1_axi_clk = { + .halt_reg = 0x26044, + .clkr = { + .enable_reg = 0x26044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sys_noc_usb1_axi_clk", + .parent_names = (const char *[]){ + "usb1_master_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb1_master_clk = { + .halt_reg = 0x3f000, + .clkr = { + .enable_reg = 0x3f000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb1_master_clk", + .parent_names = (const char *[]){ + "usb1_master_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb1_mock_utmi_clk = { + .halt_reg = 0x3f008, + .clkr = { + .enable_reg = 0x3f008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb1_mock_utmi_clk", + .parent_names = (const char *[]){ + "usb1_mock_utmi_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb1_phy_cfg_ahb_clk = { + .halt_reg = 0x3f080, + .clkr = { + .enable_reg = 0x3f080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb1_phy_cfg_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb1_pipe_clk = { + .halt_reg = 0x3f040, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x3f040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb1_pipe_clk", + .parent_names = (const char *[]){ + "usb1_pipe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb1_sleep_clk = { + .halt_reg = 0x3f004, + .clkr = { + .enable_reg = 0x3f004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb1_sleep_clk", + .parent_names = (const char *[]){ + "gcc_sleep_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ahb_clk = { + .halt_reg = 0x4201c, + .clkr = { + .enable_reg = 0x4201c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_apps_clk = { + .halt_reg = 0x42018, + .clkr = { + .enable_reg = 0x42018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_apps_clk", + .parent_names = (const char *[]){ + "sdcc1_apps_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ice_core_clk = { + .halt_reg = 0x5d014, + .clkr = { + .enable_reg = 0x5d014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ice_core_clk", + .parent_names = (const char *[]){ + "sdcc1_ice_core_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_ahb_clk = { + .halt_reg = 0x4301c, + .clkr = { + .enable_reg = 0x4301c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc2_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_apps_clk = { + .halt_reg = 0x43018, + .clkr = { + .enable_reg = 0x43018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc2_apps_clk", + .parent_names = (const char *[]){ + "sdcc2_apps_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mem_noc_nss_axi_clk = { + .halt_reg = 0x1d03c, + .clkr = { + .enable_reg = 0x1d03c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mem_noc_nss_axi_clk", + .parent_names = (const char *[]){ + "nss_noc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_ce_apb_clk = { + .halt_reg = 0x68174, + .clkr = { + .enable_reg = 0x68174, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_ce_apb_clk", + .parent_names = (const char *[]){ + "nss_ce_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_ce_axi_clk = { + .halt_reg = 0x68170, + .clkr = { + .enable_reg = 0x68170, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_ce_axi_clk", + .parent_names = (const char *[]){ + "nss_ce_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_cfg_clk = { + .halt_reg = 0x68160, + .clkr = { + .enable_reg = 0x68160, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_cfg_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_crypto_clk = { + .halt_reg = 0x68164, + .clkr = { + .enable_reg = 0x68164, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_crypto_clk", + .parent_names = (const char *[]){ + "nss_crypto_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_csr_clk = { + .halt_reg = 0x68318, + .clkr = { + .enable_reg = 0x68318, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_csr_clk", + .parent_names = (const char *[]){ + "nss_ce_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_edma_cfg_clk = { + .halt_reg = 0x6819c, + .clkr = { + .enable_reg = 0x6819c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_edma_cfg_clk", + .parent_names = (const char *[]){ + "nss_ppe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_edma_clk = { + .halt_reg = 0x68198, + .clkr = { + .enable_reg = 0x68198, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_edma_clk", + .parent_names = (const char *[]){ + "nss_ppe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_imem_clk = { + .halt_reg = 0x68178, + .clkr = { + .enable_reg = 0x68178, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_imem_clk", + .parent_names = (const char *[]){ + "nss_imem_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_noc_clk = { + .halt_reg = 0x68168, + .clkr = { + .enable_reg = 0x68168, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_noc_clk", + .parent_names = (const char *[]){ + "nss_noc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_ppe_btq_clk = { + .halt_reg = 0x6833c, + .clkr = { + .enable_reg = 0x6833c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_ppe_btq_clk", + .parent_names = (const char *[]){ + "nss_ppe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_ppe_cfg_clk = { + .halt_reg = 0x68194, + .clkr = { + .enable_reg = 0x68194, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_ppe_cfg_clk", + .parent_names = (const char *[]){ + "nss_ppe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_ppe_clk = { + .halt_reg = 0x68190, + .clkr = { + .enable_reg = 0x68190, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_ppe_clk", + .parent_names = (const char *[]){ + "nss_ppe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_ppe_ipe_clk = { + .halt_reg = 0x68338, + .clkr = { + .enable_reg = 0x68338, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_ppe_ipe_clk", + .parent_names = (const char *[]){ + "nss_ppe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_ptp_ref_clk = { + .halt_reg = 0x6816c, + .clkr = { + .enable_reg = 0x6816c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_ptp_ref_clk", + .parent_names = (const char *[]){ + "nss_ppe_cdiv_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_ce_apb_clk = { + .halt_reg = 0x6830c, + .clkr = { + .enable_reg = 0x6830c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nssnoc_ce_apb_clk", + .parent_names = (const char *[]){ + "nss_ce_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_ce_axi_clk = { + .halt_reg = 0x68308, + .clkr = { + .enable_reg = 0x68308, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nssnoc_ce_axi_clk", + .parent_names = (const char *[]){ + "nss_ce_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_crypto_clk = { + .halt_reg = 0x68314, + .clkr = { + .enable_reg = 0x68314, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nssnoc_crypto_clk", + .parent_names = (const char *[]){ + "nss_crypto_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_ppe_cfg_clk = { + .halt_reg = 0x68304, + .clkr = { + .enable_reg = 0x68304, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nssnoc_ppe_cfg_clk", + .parent_names = (const char *[]){ + "nss_ppe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_ppe_clk = { + .halt_reg = 0x68300, + .clkr = { + .enable_reg = 0x68300, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nssnoc_ppe_clk", + .parent_names = (const char *[]){ + "nss_ppe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_qosgen_ref_clk = { + .halt_reg = 0x68180, + .clkr = { + .enable_reg = 0x68180, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nssnoc_qosgen_ref_clk", + .parent_names = (const char *[]){ + "gcc_xo_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_snoc_clk = { + .halt_reg = 0x68188, + .clkr = { + .enable_reg = 0x68188, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nssnoc_snoc_clk", + .parent_names = (const char *[]){ + "system_noc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_timeout_ref_clk = { + .halt_reg = 0x68184, + .clkr = { + .enable_reg = 0x68184, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nssnoc_timeout_ref_clk", + .parent_names = (const char *[]){ + "gcc_xo_div4_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_ubi0_ahb_clk = { + .halt_reg = 0x68270, + .clkr = { + .enable_reg = 0x68270, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nssnoc_ubi0_ahb_clk", + .parent_names = (const char *[]){ + "nss_ce_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_ubi1_ahb_clk = { + .halt_reg = 0x68274, + .clkr = { + .enable_reg = 0x68274, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nssnoc_ubi1_ahb_clk", + .parent_names = (const char *[]){ + "nss_ce_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ubi0_ahb_clk = { + .halt_reg = 0x6820c, + .clkr = { + .enable_reg = 0x6820c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ubi0_ahb_clk", + .parent_names = (const char *[]){ + "nss_ce_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ubi0_axi_clk = { + .halt_reg = 0x68200, + .clkr = { + .enable_reg = 0x68200, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ubi0_axi_clk", + .parent_names = (const char *[]){ + "nss_noc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ubi0_nc_axi_clk = { + .halt_reg = 0x68204, + .clkr = { + .enable_reg = 0x68204, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ubi0_nc_axi_clk", + .parent_names = (const char *[]){ + "nss_noc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ubi0_core_clk = { + .halt_reg = 0x68210, + .clkr = { + .enable_reg = 0x68210, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ubi0_core_clk", + .parent_names = (const char *[]){ + "nss_ubi0_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ubi0_mpt_clk = { + .halt_reg = 0x68208, + .clkr = { + .enable_reg = 0x68208, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ubi0_mpt_clk", + .parent_names = (const char *[]){ + "ubi_mpt_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ubi1_ahb_clk = { + .halt_reg = 0x6822c, + .clkr = { + .enable_reg = 0x6822c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ubi1_ahb_clk", + .parent_names = (const char *[]){ + "nss_ce_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ubi1_axi_clk = { + .halt_reg = 0x68220, + .clkr = { + .enable_reg = 0x68220, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ubi1_axi_clk", + .parent_names = (const char *[]){ + "nss_noc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ubi1_nc_axi_clk = { + .halt_reg = 0x68224, + .clkr = { + .enable_reg = 0x68224, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ubi1_nc_axi_clk", + .parent_names = (const char *[]){ + "nss_noc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ubi1_core_clk = { + .halt_reg = 0x68230, + .clkr = { + .enable_reg = 0x68230, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ubi1_core_clk", + .parent_names = (const char *[]){ + "nss_ubi1_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ubi1_mpt_clk = { + .halt_reg = 0x68228, + .clkr = { + .enable_reg = 0x68228, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ubi1_mpt_clk", + .parent_names = (const char *[]){ + "ubi_mpt_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cmn_12gpll_ahb_clk = { + .halt_reg = 0x56308, + .clkr = { + .enable_reg = 0x56308, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cmn_12gpll_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cmn_12gpll_sys_clk = { + .halt_reg = 0x5630c, + .clkr = { + .enable_reg = 0x5630c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cmn_12gpll_sys_clk", + .parent_names = (const char *[]){ + "gcc_xo_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mdio_ahb_clk = { + .halt_reg = 0x58004, + .clkr = { + .enable_reg = 0x58004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mdio_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy0_ahb_clk = { + .halt_reg = 0x56008, + .clkr = { + .enable_reg = 0x56008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy0_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy0_sys_clk = { + .halt_reg = 0x5600c, + .clkr = { + .enable_reg = 0x5600c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy0_sys_clk", + .parent_names = (const char *[]){ + "gcc_xo_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy1_ahb_clk = { + .halt_reg = 0x56108, + .clkr = { + .enable_reg = 0x56108, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy1_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy1_sys_clk = { + .halt_reg = 0x5610c, + .clkr = { + .enable_reg = 0x5610c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy1_sys_clk", + .parent_names = (const char *[]){ + "gcc_xo_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy2_ahb_clk = { + .halt_reg = 0x56208, + .clkr = { + .enable_reg = 0x56208, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy2_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy2_sys_clk = { + .halt_reg = 0x5620c, + .clkr = { + .enable_reg = 0x5620c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy2_sys_clk", + .parent_names = (const char *[]){ + "gcc_xo_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_port1_rx_clk = { + .halt_reg = 0x68240, + .clkr = { + .enable_reg = 0x68240, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_port1_rx_clk", + .parent_names = (const char *[]){ + "nss_port1_rx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_port1_tx_clk = { + .halt_reg = 0x68244, + .clkr = { + .enable_reg = 0x68244, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_port1_tx_clk", + .parent_names = (const char *[]){ + "nss_port1_tx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_port2_rx_clk = { + .halt_reg = 0x68248, + .clkr = { + .enable_reg = 0x68248, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_port2_rx_clk", + .parent_names = (const char *[]){ + "nss_port2_rx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_port2_tx_clk = { + .halt_reg = 0x6824c, + .clkr = { + .enable_reg = 0x6824c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_port2_tx_clk", + .parent_names = (const char *[]){ + "nss_port2_tx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_port3_rx_clk = { + .halt_reg = 0x68250, + .clkr = { + .enable_reg = 0x68250, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_port3_rx_clk", + .parent_names = (const char *[]){ + "nss_port3_rx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_port3_tx_clk = { + .halt_reg = 0x68254, + .clkr = { + .enable_reg = 0x68254, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_port3_tx_clk", + .parent_names = (const char *[]){ + "nss_port3_tx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_port4_rx_clk = { + .halt_reg = 0x68258, + .clkr = { + .enable_reg = 0x68258, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_port4_rx_clk", + .parent_names = (const char *[]){ + "nss_port4_rx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_port4_tx_clk = { + .halt_reg = 0x6825c, + .clkr = { + .enable_reg = 0x6825c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_port4_tx_clk", + .parent_names = (const char *[]){ + "nss_port4_tx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_port5_rx_clk = { + .halt_reg = 0x68260, + .clkr = { + .enable_reg = 0x68260, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_port5_rx_clk", + .parent_names = (const char *[]){ + "nss_port5_rx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_port5_tx_clk = { + .halt_reg = 0x68264, + .clkr = { + .enable_reg = 0x68264, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_port5_tx_clk", + .parent_names = (const char *[]){ + "nss_port5_tx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_port6_rx_clk = { + .halt_reg = 0x68268, + .clkr = { + .enable_reg = 0x68268, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_port6_rx_clk", + .parent_names = (const char *[]){ + "nss_port6_rx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_port6_tx_clk = { + .halt_reg = 0x6826c, + .clkr = { + .enable_reg = 0x6826c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_nss_port6_tx_clk", + .parent_names = (const char *[]){ + "nss_port6_tx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_port1_mac_clk = { + .halt_reg = 0x68320, + .clkr = { + .enable_reg = 0x68320, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_port1_mac_clk", + .parent_names = (const char *[]){ + "nss_ppe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_port2_mac_clk = { + .halt_reg = 0x68324, + .clkr = { + .enable_reg = 0x68324, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_port2_mac_clk", + .parent_names = (const char *[]){ + "nss_ppe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_port3_mac_clk = { + .halt_reg = 0x68328, + .clkr = { + .enable_reg = 0x68328, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_port3_mac_clk", + .parent_names = (const char *[]){ + "nss_ppe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_port4_mac_clk = { + .halt_reg = 0x6832c, + .clkr = { + .enable_reg = 0x6832c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_port4_mac_clk", + .parent_names = (const char *[]){ + "nss_ppe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_port5_mac_clk = { + .halt_reg = 0x68330, + .clkr = { + .enable_reg = 0x68330, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_port5_mac_clk", + .parent_names = (const char *[]){ + "nss_ppe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_port6_mac_clk = { + .halt_reg = 0x68334, + .clkr = { + .enable_reg = 0x68334, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_port6_mac_clk", + .parent_names = (const char *[]){ + "nss_ppe_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy0_port1_rx_clk = { + .halt_reg = 0x56010, + .clkr = { + .enable_reg = 0x56010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy0_port1_rx_clk", + .parent_names = (const char *[]){ + "nss_port1_rx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy0_port1_tx_clk = { + .halt_reg = 0x56014, + .clkr = { + .enable_reg = 0x56014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy0_port1_tx_clk", + .parent_names = (const char *[]){ + "nss_port1_tx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy0_port2_rx_clk = { + .halt_reg = 0x56018, + .clkr = { + .enable_reg = 0x56018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy0_port2_rx_clk", + .parent_names = (const char *[]){ + "nss_port2_rx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy0_port2_tx_clk = { + .halt_reg = 0x5601c, + .clkr = { + .enable_reg = 0x5601c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy0_port2_tx_clk", + .parent_names = (const char *[]){ + "nss_port2_tx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy0_port3_rx_clk = { + .halt_reg = 0x56020, + .clkr = { + .enable_reg = 0x56020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy0_port3_rx_clk", + .parent_names = (const char *[]){ + "nss_port3_rx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy0_port3_tx_clk = { + .halt_reg = 0x56024, + .clkr = { + .enable_reg = 0x56024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy0_port3_tx_clk", + .parent_names = (const char *[]){ + "nss_port3_tx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy0_port4_rx_clk = { + .halt_reg = 0x56028, + .clkr = { + .enable_reg = 0x56028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy0_port4_rx_clk", + .parent_names = (const char *[]){ + "nss_port4_rx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy0_port4_tx_clk = { + .halt_reg = 0x5602c, + .clkr = { + .enable_reg = 0x5602c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy0_port4_tx_clk", + .parent_names = (const char *[]){ + "nss_port4_tx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy0_port5_rx_clk = { + .halt_reg = 0x56030, + .clkr = { + .enable_reg = 0x56030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy0_port5_rx_clk", + .parent_names = (const char *[]){ + "nss_port5_rx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy0_port5_tx_clk = { + .halt_reg = 0x56034, + .clkr = { + .enable_reg = 0x56034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy0_port5_tx_clk", + .parent_names = (const char *[]){ + "nss_port5_tx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy1_port5_rx_clk = { + .halt_reg = 0x56110, + .clkr = { + .enable_reg = 0x56110, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy1_port5_rx_clk", + .parent_names = (const char *[]){ + "nss_port5_rx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy1_port5_tx_clk = { + .halt_reg = 0x56114, + .clkr = { + .enable_reg = 0x56114, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy1_port5_tx_clk", + .parent_names = (const char *[]){ + "nss_port5_tx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy2_port6_rx_clk = { + .halt_reg = 0x56210, + .clkr = { + .enable_reg = 0x56210, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy2_port6_rx_clk", + .parent_names = (const char *[]){ + "nss_port6_rx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy2_port6_tx_clk = { + .halt_reg = 0x56214, + .clkr = { + .enable_reg = 0x56214, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_uniphy2_port6_tx_clk", + .parent_names = (const char *[]){ + "nss_port6_tx_div_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_crypto_ahb_clk = { + .halt_reg = 0x16024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x0b004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_crypto_ahb_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_crypto_axi_clk = { + .halt_reg = 0x16020, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x0b004, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_crypto_axi_clk", + .parent_names = (const char *[]){ + "pcnoc_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_crypto_clk = { + .halt_reg = 0x1601c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x0b004, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "gcc_crypto_clk", + .parent_names = (const char *[]){ + "crypto_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x08000, + .clkr = { + .enable_reg = 0x08000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp1_clk", + .parent_names = (const char *[]){ + "gp1_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp2_clk = { + .halt_reg = 0x09000, + .clkr = { + .enable_reg = 0x09000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp2_clk", + .parent_names = (const char *[]){ + "gp2_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp3_clk = { + .halt_reg = 0x0a000, + .clkr = { + .enable_reg = 0x0a000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp3_clk", + .parent_names = (const char *[]){ + "gp3_clk_src" + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_hw *gcc_ipq8074_hws[] = { &gpll0_out_main_div2.hw, + &gpll6_out_main_div2.hw, &pcnoc_clk_src.hw, + &system_noc_clk_src.hw, + &gcc_xo_div4_clk_src.hw, + &nss_noc_clk_src.hw, + &nss_ppe_cdiv_clk_src.hw, }; static struct clk_regmap *gcc_ipq8074_clks[] = { [GPLL0_MAIN] = &gpll0_main.clkr, [GPLL0] = &gpll0.clkr, + [GPLL2_MAIN] = &gpll2_main.clkr, + [GPLL2] = &gpll2.clkr, + [GPLL4_MAIN] = &gpll4_main.clkr, + [GPLL4] = &gpll4.clkr, + [GPLL6_MAIN] = &gpll6_main.clkr, + [GPLL6] = &gpll6.clkr, + [UBI32_PLL_MAIN] = &ubi32_pll_main.clkr, + [UBI32_PLL] = &ubi32_pll.clkr, + [NSS_CRYPTO_PLL_MAIN] = &nss_crypto_pll_main.clkr, + [NSS_CRYPTO_PLL] = &nss_crypto_pll.clkr, [PCNOC_BFDCD_CLK_SRC] = &pcnoc_bfdcd_clk_src.clkr, [GCC_SLEEP_CLK_SRC] = &gcc_sleep_clk_src.clkr, [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr, @@ -831,6 +4369,63 @@ static struct clk_regmap *gcc_ipq8074_clks[] = { [BLSP1_UART4_APPS_CLK_SRC] = &blsp1_uart4_apps_clk_src.clkr, [BLSP1_UART5_APPS_CLK_SRC] = &blsp1_uart5_apps_clk_src.clkr, [BLSP1_UART6_APPS_CLK_SRC] = &blsp1_uart6_apps_clk_src.clkr, + [PCIE0_AXI_CLK_SRC] = &pcie0_axi_clk_src.clkr, + [PCIE0_AUX_CLK_SRC] = &pcie0_aux_clk_src.clkr, + [PCIE0_PIPE_CLK_SRC] = &pcie0_pipe_clk_src.clkr, + [PCIE1_AXI_CLK_SRC] = &pcie1_axi_clk_src.clkr, + [PCIE1_AUX_CLK_SRC] = &pcie1_aux_clk_src.clkr, + [PCIE1_PIPE_CLK_SRC] = &pcie1_pipe_clk_src.clkr, + [SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr, + [SDCC1_ICE_CORE_CLK_SRC] = &sdcc1_ice_core_clk_src.clkr, + [SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr, + [USB0_MASTER_CLK_SRC] = &usb0_master_clk_src.clkr, + [USB0_AUX_CLK_SRC] = &usb0_aux_clk_src.clkr, + [USB0_MOCK_UTMI_CLK_SRC] = &usb0_mock_utmi_clk_src.clkr, + [USB0_PIPE_CLK_SRC] = &usb0_pipe_clk_src.clkr, + [USB1_MASTER_CLK_SRC] = &usb1_master_clk_src.clkr, + [USB1_AUX_CLK_SRC] = &usb1_aux_clk_src.clkr, + [USB1_MOCK_UTMI_CLK_SRC] = &usb1_mock_utmi_clk_src.clkr, + [USB1_PIPE_CLK_SRC] = &usb1_pipe_clk_src.clkr, + [GCC_XO_CLK_SRC] = &gcc_xo_clk_src.clkr, + [SYSTEM_NOC_BFDCD_CLK_SRC] = &system_noc_bfdcd_clk_src.clkr, + [NSS_CE_CLK_SRC] = &nss_ce_clk_src.clkr, + [NSS_NOC_BFDCD_CLK_SRC] = &nss_noc_bfdcd_clk_src.clkr, + [NSS_CRYPTO_CLK_SRC] = &nss_crypto_clk_src.clkr, + [NSS_UBI0_CLK_SRC] = &nss_ubi0_clk_src.clkr, + [NSS_UBI0_DIV_CLK_SRC] = &nss_ubi0_div_clk_src.clkr, + [NSS_UBI1_CLK_SRC] = &nss_ubi1_clk_src.clkr, + [NSS_UBI1_DIV_CLK_SRC] = &nss_ubi1_div_clk_src.clkr, + [UBI_MPT_CLK_SRC] = &ubi_mpt_clk_src.clkr, + [NSS_IMEM_CLK_SRC] = &nss_imem_clk_src.clkr, + [NSS_PPE_CLK_SRC] = &nss_ppe_clk_src.clkr, + [NSS_PORT1_RX_CLK_SRC] = &nss_port1_rx_clk_src.clkr, + [NSS_PORT1_RX_DIV_CLK_SRC] = &nss_port1_rx_div_clk_src.clkr, + [NSS_PORT1_TX_CLK_SRC] = &nss_port1_tx_clk_src.clkr, + [NSS_PORT1_TX_DIV_CLK_SRC] = &nss_port1_tx_div_clk_src.clkr, + [NSS_PORT2_RX_CLK_SRC] = &nss_port2_rx_clk_src.clkr, + [NSS_PORT2_RX_DIV_CLK_SRC] = &nss_port2_rx_div_clk_src.clkr, + [NSS_PORT2_TX_CLK_SRC] = &nss_port2_tx_clk_src.clkr, + [NSS_PORT2_TX_DIV_CLK_SRC] = &nss_port2_tx_div_clk_src.clkr, + [NSS_PORT3_RX_CLK_SRC] = &nss_port3_rx_clk_src.clkr, + [NSS_PORT3_RX_DIV_CLK_SRC] = &nss_port3_rx_div_clk_src.clkr, + [NSS_PORT3_TX_CLK_SRC] = &nss_port3_tx_clk_src.clkr, + [NSS_PORT3_TX_DIV_CLK_SRC] = &nss_port3_tx_div_clk_src.clkr, + [NSS_PORT4_RX_CLK_SRC] = &nss_port4_rx_clk_src.clkr, + [NSS_PORT4_RX_DIV_CLK_SRC] = &nss_port4_rx_div_clk_src.clkr, + [NSS_PORT4_TX_CLK_SRC] = &nss_port4_tx_clk_src.clkr, + [NSS_PORT4_TX_DIV_CLK_SRC] = &nss_port4_tx_div_clk_src.clkr, + [NSS_PORT5_RX_CLK_SRC] = &nss_port5_rx_clk_src.clkr, + [NSS_PORT5_RX_DIV_CLK_SRC] = &nss_port5_rx_div_clk_src.clkr, + [NSS_PORT5_TX_CLK_SRC] = &nss_port5_tx_clk_src.clkr, + [NSS_PORT5_TX_DIV_CLK_SRC] = &nss_port5_tx_div_clk_src.clkr, + [NSS_PORT6_RX_CLK_SRC] = &nss_port6_rx_clk_src.clkr, + [NSS_PORT6_RX_DIV_CLK_SRC] = &nss_port6_rx_div_clk_src.clkr, + [NSS_PORT6_TX_CLK_SRC] = &nss_port6_tx_clk_src.clkr, + [NSS_PORT6_TX_DIV_CLK_SRC] = &nss_port6_tx_div_clk_src.clkr, + [CRYPTO_CLK_SRC] = &crypto_clk_src.clkr, + [GP1_CLK_SRC] = &gp1_clk_src.clkr, + [GP2_CLK_SRC] = &gp2_clk_src.clkr, + [GP3_CLK_SRC] = &gp3_clk_src.clkr, [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr, [GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr, [GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr, @@ -853,6 +4448,119 @@ static struct clk_regmap *gcc_ipq8074_clks[] = { [GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr, [GCC_QPIC_AHB_CLK] = &gcc_qpic_ahb_clk.clkr, [GCC_QPIC_CLK] = &gcc_qpic_clk.clkr, + [GCC_PCIE0_AHB_CLK] = &gcc_pcie0_ahb_clk.clkr, + [GCC_PCIE0_AUX_CLK] = &gcc_pcie0_aux_clk.clkr, + [GCC_PCIE0_AXI_M_CLK] = &gcc_pcie0_axi_m_clk.clkr, + [GCC_PCIE0_AXI_S_CLK] = &gcc_pcie0_axi_s_clk.clkr, + [GCC_PCIE0_PIPE_CLK] = &gcc_pcie0_pipe_clk.clkr, + [GCC_SYS_NOC_PCIE0_AXI_CLK] = &gcc_sys_noc_pcie0_axi_clk.clkr, + [GCC_PCIE1_AHB_CLK] = &gcc_pcie1_ahb_clk.clkr, + [GCC_PCIE1_AUX_CLK] = &gcc_pcie1_aux_clk.clkr, + [GCC_PCIE1_AXI_M_CLK] = &gcc_pcie1_axi_m_clk.clkr, + [GCC_PCIE1_AXI_S_CLK] = &gcc_pcie1_axi_s_clk.clkr, + [GCC_PCIE1_PIPE_CLK] = &gcc_pcie1_pipe_clk.clkr, + [GCC_SYS_NOC_PCIE1_AXI_CLK] = &gcc_sys_noc_pcie1_axi_clk.clkr, + [GCC_USB0_AUX_CLK] = &gcc_usb0_aux_clk.clkr, + [GCC_SYS_NOC_USB0_AXI_CLK] = &gcc_sys_noc_usb0_axi_clk.clkr, + [GCC_USB0_MASTER_CLK] = &gcc_usb0_master_clk.clkr, + [GCC_USB0_MOCK_UTMI_CLK] = &gcc_usb0_mock_utmi_clk.clkr, + [GCC_USB0_PHY_CFG_AHB_CLK] = &gcc_usb0_phy_cfg_ahb_clk.clkr, + [GCC_USB0_PIPE_CLK] = &gcc_usb0_pipe_clk.clkr, + [GCC_USB0_SLEEP_CLK] = &gcc_usb0_sleep_clk.clkr, + [GCC_USB1_AUX_CLK] = &gcc_usb1_aux_clk.clkr, + [GCC_SYS_NOC_USB1_AXI_CLK] = &gcc_sys_noc_usb1_axi_clk.clkr, + [GCC_USB1_MASTER_CLK] = &gcc_usb1_master_clk.clkr, + [GCC_USB1_MOCK_UTMI_CLK] = &gcc_usb1_mock_utmi_clk.clkr, + [GCC_USB1_PHY_CFG_AHB_CLK] = &gcc_usb1_phy_cfg_ahb_clk.clkr, + [GCC_USB1_PIPE_CLK] = &gcc_usb1_pipe_clk.clkr, + [GCC_USB1_SLEEP_CLK] = &gcc_usb1_sleep_clk.clkr, + [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr, + [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr, + [GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr, + [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr, + [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr, + [GCC_MEM_NOC_NSS_AXI_CLK] = &gcc_mem_noc_nss_axi_clk.clkr, + [GCC_NSS_CE_APB_CLK] = &gcc_nss_ce_apb_clk.clkr, + [GCC_NSS_CE_AXI_CLK] = &gcc_nss_ce_axi_clk.clkr, + [GCC_NSS_CFG_CLK] = &gcc_nss_cfg_clk.clkr, + [GCC_NSS_CRYPTO_CLK] = &gcc_nss_crypto_clk.clkr, + [GCC_NSS_CSR_CLK] = &gcc_nss_csr_clk.clkr, + [GCC_NSS_EDMA_CFG_CLK] = &gcc_nss_edma_cfg_clk.clkr, + [GCC_NSS_EDMA_CLK] = &gcc_nss_edma_clk.clkr, + [GCC_NSS_IMEM_CLK] = &gcc_nss_imem_clk.clkr, + [GCC_NSS_NOC_CLK] = &gcc_nss_noc_clk.clkr, + [GCC_NSS_PPE_BTQ_CLK] = &gcc_nss_ppe_btq_clk.clkr, + [GCC_NSS_PPE_CFG_CLK] = &gcc_nss_ppe_cfg_clk.clkr, + [GCC_NSS_PPE_CLK] = &gcc_nss_ppe_clk.clkr, + [GCC_NSS_PPE_IPE_CLK] = &gcc_nss_ppe_ipe_clk.clkr, + [GCC_NSS_PTP_REF_CLK] = &gcc_nss_ptp_ref_clk.clkr, + [GCC_NSSNOC_CE_APB_CLK] = &gcc_nssnoc_ce_apb_clk.clkr, + [GCC_NSSNOC_CE_AXI_CLK] = &gcc_nssnoc_ce_axi_clk.clkr, + [GCC_NSSNOC_CRYPTO_CLK] = &gcc_nssnoc_crypto_clk.clkr, + [GCC_NSSNOC_PPE_CFG_CLK] = &gcc_nssnoc_ppe_cfg_clk.clkr, + [GCC_NSSNOC_PPE_CLK] = &gcc_nssnoc_ppe_clk.clkr, + [GCC_NSSNOC_QOSGEN_REF_CLK] = &gcc_nssnoc_qosgen_ref_clk.clkr, + [GCC_NSSNOC_SNOC_CLK] = &gcc_nssnoc_snoc_clk.clkr, + [GCC_NSSNOC_TIMEOUT_REF_CLK] = &gcc_nssnoc_timeout_ref_clk.clkr, + [GCC_NSSNOC_UBI0_AHB_CLK] = &gcc_nssnoc_ubi0_ahb_clk.clkr, + [GCC_NSSNOC_UBI1_AHB_CLK] = &gcc_nssnoc_ubi1_ahb_clk.clkr, + [GCC_UBI0_AHB_CLK] = &gcc_ubi0_ahb_clk.clkr, + [GCC_UBI0_AXI_CLK] = &gcc_ubi0_axi_clk.clkr, + [GCC_UBI0_NC_AXI_CLK] = &gcc_ubi0_nc_axi_clk.clkr, + [GCC_UBI0_CORE_CLK] = &gcc_ubi0_core_clk.clkr, + [GCC_UBI0_MPT_CLK] = &gcc_ubi0_mpt_clk.clkr, + [GCC_UBI1_AHB_CLK] = &gcc_ubi1_ahb_clk.clkr, + [GCC_UBI1_AXI_CLK] = &gcc_ubi1_axi_clk.clkr, + [GCC_UBI1_NC_AXI_CLK] = &gcc_ubi1_nc_axi_clk.clkr, + [GCC_UBI1_CORE_CLK] = &gcc_ubi1_core_clk.clkr, + [GCC_UBI1_MPT_CLK] = &gcc_ubi1_mpt_clk.clkr, + [GCC_CMN_12GPLL_AHB_CLK] = &gcc_cmn_12gpll_ahb_clk.clkr, + [GCC_CMN_12GPLL_SYS_CLK] = &gcc_cmn_12gpll_sys_clk.clkr, + [GCC_MDIO_AHB_CLK] = &gcc_mdio_ahb_clk.clkr, + [GCC_UNIPHY0_AHB_CLK] = &gcc_uniphy0_ahb_clk.clkr, + [GCC_UNIPHY0_SYS_CLK] = &gcc_uniphy0_sys_clk.clkr, + [GCC_UNIPHY1_AHB_CLK] = &gcc_uniphy1_ahb_clk.clkr, + [GCC_UNIPHY1_SYS_CLK] = &gcc_uniphy1_sys_clk.clkr, + [GCC_UNIPHY2_AHB_CLK] = &gcc_uniphy2_ahb_clk.clkr, + [GCC_UNIPHY2_SYS_CLK] = &gcc_uniphy2_sys_clk.clkr, + [GCC_NSS_PORT1_RX_CLK] = &gcc_nss_port1_rx_clk.clkr, + [GCC_NSS_PORT1_TX_CLK] = &gcc_nss_port1_tx_clk.clkr, + [GCC_NSS_PORT2_RX_CLK] = &gcc_nss_port2_rx_clk.clkr, + [GCC_NSS_PORT2_TX_CLK] = &gcc_nss_port2_tx_clk.clkr, + [GCC_NSS_PORT3_RX_CLK] = &gcc_nss_port3_rx_clk.clkr, + [GCC_NSS_PORT3_TX_CLK] = &gcc_nss_port3_tx_clk.clkr, + [GCC_NSS_PORT4_RX_CLK] = &gcc_nss_port4_rx_clk.clkr, + [GCC_NSS_PORT4_TX_CLK] = &gcc_nss_port4_tx_clk.clkr, + [GCC_NSS_PORT5_RX_CLK] = &gcc_nss_port5_rx_clk.clkr, + [GCC_NSS_PORT5_TX_CLK] = &gcc_nss_port5_tx_clk.clkr, + [GCC_NSS_PORT6_RX_CLK] = &gcc_nss_port6_rx_clk.clkr, + [GCC_NSS_PORT6_TX_CLK] = &gcc_nss_port6_tx_clk.clkr, + [GCC_PORT1_MAC_CLK] = &gcc_port1_mac_clk.clkr, + [GCC_PORT2_MAC_CLK] = &gcc_port2_mac_clk.clkr, + [GCC_PORT3_MAC_CLK] = &gcc_port3_mac_clk.clkr, + [GCC_PORT4_MAC_CLK] = &gcc_port4_mac_clk.clkr, + [GCC_PORT5_MAC_CLK] = &gcc_port5_mac_clk.clkr, + [GCC_PORT6_MAC_CLK] = &gcc_port6_mac_clk.clkr, + [GCC_UNIPHY0_PORT1_RX_CLK] = &gcc_uniphy0_port1_rx_clk.clkr, + [GCC_UNIPHY0_PORT1_TX_CLK] = &gcc_uniphy0_port1_tx_clk.clkr, + [GCC_UNIPHY0_PORT2_RX_CLK] = &gcc_uniphy0_port2_rx_clk.clkr, + [GCC_UNIPHY0_PORT2_TX_CLK] = &gcc_uniphy0_port2_tx_clk.clkr, + [GCC_UNIPHY0_PORT3_RX_CLK] = &gcc_uniphy0_port3_rx_clk.clkr, + [GCC_UNIPHY0_PORT3_TX_CLK] = &gcc_uniphy0_port3_tx_clk.clkr, + [GCC_UNIPHY0_PORT4_RX_CLK] = &gcc_uniphy0_port4_rx_clk.clkr, + [GCC_UNIPHY0_PORT4_TX_CLK] = &gcc_uniphy0_port4_tx_clk.clkr, + [GCC_UNIPHY0_PORT5_RX_CLK] = &gcc_uniphy0_port5_rx_clk.clkr, + [GCC_UNIPHY0_PORT5_TX_CLK] = &gcc_uniphy0_port5_tx_clk.clkr, + [GCC_UNIPHY1_PORT5_RX_CLK] = &gcc_uniphy1_port5_rx_clk.clkr, + [GCC_UNIPHY1_PORT5_TX_CLK] = &gcc_uniphy1_port5_tx_clk.clkr, + [GCC_UNIPHY2_PORT6_RX_CLK] = &gcc_uniphy2_port6_rx_clk.clkr, + [GCC_UNIPHY2_PORT6_TX_CLK] = &gcc_uniphy2_port6_tx_clk.clkr, + [GCC_CRYPTO_AHB_CLK] = &gcc_crypto_ahb_clk.clkr, + [GCC_CRYPTO_AXI_CLK] = &gcc_crypto_axi_clk.clkr, + [GCC_CRYPTO_CLK] = &gcc_crypto_clk.clkr, + [GCC_GP1_CLK] = &gcc_gp1_clk.clkr, + [GCC_GP2_CLK] = &gcc_gp2_clk.clkr, + [GCC_GP3_CLK] = &gcc_gp3_clk.clkr, }; static const struct qcom_reset_map gcc_ipq8074_resets[] = { @@ -945,6 +4653,48 @@ static const struct qcom_reset_map gcc_ipq8074_resets[] = { [GCC_APC0_VOLTAGE_DROOP_DETECTOR_BCR] = { 0x78000, 0 }, [GCC_APC1_VOLTAGE_DROOP_DETECTOR_BCR] = { 0x79000, 0 }, [GCC_SMMU_CATS_BCR] = { 0x7c000, 0 }, + [GCC_UBI0_AXI_ARES] = { 0x68010, 0 }, + [GCC_UBI0_AHB_ARES] = { 0x68010, 1 }, + [GCC_UBI0_NC_AXI_ARES] = { 0x68010, 2 }, + [GCC_UBI0_DBG_ARES] = { 0x68010, 3 }, + [GCC_UBI0_CORE_CLAMP_ENABLE] = { 0x68010, 4 }, + [GCC_UBI0_CLKRST_CLAMP_ENABLE] = { 0x68010, 5 }, + [GCC_UBI1_AXI_ARES] = { 0x68010, 8 }, + [GCC_UBI1_AHB_ARES] = { 0x68010, 9 }, + [GCC_UBI1_NC_AXI_ARES] = { 0x68010, 10 }, + [GCC_UBI1_DBG_ARES] = { 0x68010, 11 }, + [GCC_UBI1_CORE_CLAMP_ENABLE] = { 0x68010, 12 }, + [GCC_UBI1_CLKRST_CLAMP_ENABLE] = { 0x68010, 13 }, + [GCC_NSS_CFG_ARES] = { 0x68010, 16 }, + [GCC_NSS_IMEM_ARES] = { 0x68010, 17 }, + [GCC_NSS_NOC_ARES] = { 0x68010, 18 }, + [GCC_NSS_CRYPTO_ARES] = { 0x68010, 19 }, + [GCC_NSS_CSR_ARES] = { 0x68010, 20 }, + [GCC_NSS_CE_APB_ARES] = { 0x68010, 21 }, + [GCC_NSS_CE_AXI_ARES] = { 0x68010, 22 }, + [GCC_NSSNOC_CE_APB_ARES] = { 0x68010, 23 }, + [GCC_NSSNOC_CE_AXI_ARES] = { 0x68010, 24 }, + [GCC_NSSNOC_UBI0_AHB_ARES] = { 0x68010, 25 }, + [GCC_NSSNOC_UBI1_AHB_ARES] = { 0x68010, 26 }, + [GCC_NSSNOC_SNOC_ARES] = { 0x68010, 27 }, + [GCC_NSSNOC_CRYPTO_ARES] = { 0x68010, 28 }, + [GCC_NSSNOC_ATB_ARES] = { 0x68010, 29 }, + [GCC_NSSNOC_QOSGEN_REF_ARES] = { 0x68010, 30 }, + [GCC_NSSNOC_TIMEOUT_REF_ARES] = { 0x68010, 31 }, + [GCC_PCIE0_PIPE_ARES] = { 0x75040, 0 }, + [GCC_PCIE0_SLEEP_ARES] = { 0x75040, 1 }, + [GCC_PCIE0_CORE_STICKY_ARES] = { 0x75040, 2 }, + [GCC_PCIE0_AXI_MASTER_ARES] = { 0x75040, 3 }, + [GCC_PCIE0_AXI_SLAVE_ARES] = { 0x75040, 4 }, + [GCC_PCIE0_AHB_ARES] = { 0x75040, 5 }, + [GCC_PCIE0_AXI_MASTER_STICKY_ARES] = { 0x75040, 6 }, + [GCC_PCIE1_PIPE_ARES] = { 0x76040, 0 }, + [GCC_PCIE1_SLEEP_ARES] = { 0x76040, 1 }, + [GCC_PCIE1_CORE_STICKY_ARES] = { 0x76040, 2 }, + [GCC_PCIE1_AXI_MASTER_ARES] = { 0x76040, 3 }, + [GCC_PCIE1_AXI_SLAVE_ARES] = { 0x76040, 4 }, + [GCC_PCIE1_AHB_ARES] = { 0x76040, 5 }, + [GCC_PCIE1_AXI_MASTER_STICKY_ARES] = { 0x76040, 6 }, }; static const struct of_device_id gcc_ipq8074_match_table[] = { diff --git a/drivers/clk/qcom/gcc-msm8916.c b/drivers/clk/qcom/gcc-msm8916.c index 3410ee68d4bc..d6c7f50ba86a 100644 --- a/drivers/clk/qcom/gcc-msm8916.c +++ b/drivers/clk/qcom/gcc-msm8916.c @@ -1259,20 +1259,25 @@ static struct clk_branch gcc_ultaudio_ahbfabric_ixfabric_lpm_clk = { }; static const struct freq_tbl ftbl_gcc_ultaudio_lpaif_i2s_clk[] = { + F(128000, P_XO, 10, 1, 15), F(256000, P_XO, 5, 1, 15), + F(384000, P_XO, 5, 1, 10), F(512000, P_XO, 5, 2, 15), + F(576000, P_XO, 5, 3, 20), F(705600, P_GPLL1, 16, 1, 80), F(768000, P_XO, 5, 1, 5), F(800000, P_XO, 5, 5, 24), - F(1024000, P_GPLL1, 14, 1, 63), + F(1024000, P_XO, 5, 4, 15), F(1152000, P_XO, 1, 3, 50), F(1411200, P_GPLL1, 16, 1, 40), F(1536000, P_XO, 1, 2, 25), F(1600000, P_XO, 12, 0, 0), - F(2048000, P_GPLL1, 9, 1, 49), + F(1728000, P_XO, 5, 9, 20), + F(2048000, P_XO, 5, 8, 15), + F(2304000, P_XO, 5, 3, 5), F(2400000, P_XO, 8, 0, 0), F(2822400, P_GPLL1, 16, 1, 20), - F(3072000, P_GPLL1, 14, 1, 21), + F(3072000, P_XO, 5, 4, 5), F(4096000, P_GPLL1, 9, 2, 49), F(4800000, P_XO, 4, 0, 0), F(5644800, P_GPLL1, 16, 1, 10), @@ -1431,6 +1436,7 @@ static struct clk_branch gcc_ultaudio_stc_xo_clk = { static const struct freq_tbl ftbl_codec_clk[] = { F(9600000, P_XO, 2, 0, 0), + F(12288000, P_XO, 1, 16, 25), F(19200000, P_XO, 1, 0, 0), F(11289600, P_EXT_MCLK, 1, 0, 0), { } @@ -1438,6 +1444,7 @@ static const struct freq_tbl ftbl_codec_clk[] = { static struct clk_rcg2 codec_digcodec_clk_src = { .cmd_rcgr = 0x1c09c, + .mnd_width = 8, .hid_width = 5, .parent_map = gcc_xo_gpll1_emclk_sleep_map, .freq_tbl = ftbl_codec_clk, diff --git a/drivers/clk/qcom/gcc-msm8994.c b/drivers/clk/qcom/gcc-msm8994.c index 7983288d9141..1e38efc37180 100644 --- a/drivers/clk/qcom/gcc-msm8994.c +++ b/drivers/clk/qcom/gcc-msm8994.c @@ -73,6 +73,7 @@ static struct clk_fixed_factor xo = { static struct clk_alpha_pll gpll0_early = { .offset = 0x00000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .clkr = { .enable_reg = 0x1480, .enable_mask = BIT(0), @@ -88,6 +89,7 @@ static struct clk_alpha_pll gpll0_early = { static struct clk_alpha_pll_postdiv gpll0 = { .offset = 0x00000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .clkr.hw.init = &(struct clk_init_data) { .name = "gpll0", @@ -99,6 +101,7 @@ static struct clk_alpha_pll_postdiv gpll0 = { static struct clk_alpha_pll gpll4_early = { .offset = 0x1dc0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .clkr = { .enable_reg = 0x1480, .enable_mask = BIT(4), @@ -114,6 +117,7 @@ static struct clk_alpha_pll gpll4_early = { static struct clk_alpha_pll_postdiv gpll4 = { .offset = 0x1dc0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .clkr.hw.init = &(struct clk_init_data) { .name = "gpll4", diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index 7ddec886fcd3..5d7451209206 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -227,6 +227,7 @@ static struct clk_fixed_factor xo = { static struct clk_alpha_pll gpll0_early = { .offset = 0x00000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .clkr = { .enable_reg = 0x52000, .enable_mask = BIT(0), @@ -252,6 +253,7 @@ static struct clk_fixed_factor gpll0_early_div = { static struct clk_alpha_pll_postdiv gpll0 = { .offset = 0x00000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .clkr.hw.init = &(struct clk_init_data){ .name = "gpll0", .parent_names = (const char *[]){ "gpll0_early" }, @@ -262,6 +264,7 @@ static struct clk_alpha_pll_postdiv gpll0 = { static struct clk_alpha_pll gpll4_early = { .offset = 0x77000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .clkr = { .enable_reg = 0x52000, .enable_mask = BIT(4), @@ -276,6 +279,7 @@ static struct clk_alpha_pll gpll4_early = { static struct clk_alpha_pll_postdiv gpll4 = { .offset = 0x77000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .clkr.hw.init = &(struct clk_init_data){ .name = "gpll4", .parent_names = (const char *[]){ "gpll4_early" }, diff --git a/drivers/clk/qcom/mmcc-msm8996.c b/drivers/clk/qcom/mmcc-msm8996.c index 352394d8fd8c..66a2fa4ec93c 100644 --- a/drivers/clk/qcom/mmcc-msm8996.c +++ b/drivers/clk/qcom/mmcc-msm8996.c @@ -267,6 +267,7 @@ static struct pll_vco mmpll_t_vco[] = { static struct clk_alpha_pll mmpll0_early = { .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .vco_table = mmpll_p_vco, .num_vco = ARRAY_SIZE(mmpll_p_vco), .clkr = { @@ -283,6 +284,7 @@ static struct clk_alpha_pll mmpll0_early = { static struct clk_alpha_pll_postdiv mmpll0 = { .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .width = 4, .clkr.hw.init = &(struct clk_init_data){ .name = "mmpll0", @@ -295,6 +297,7 @@ static struct clk_alpha_pll_postdiv mmpll0 = { static struct clk_alpha_pll mmpll1_early = { .offset = 0x30, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .vco_table = mmpll_p_vco, .num_vco = ARRAY_SIZE(mmpll_p_vco), .clkr = { @@ -311,6 +314,7 @@ static struct clk_alpha_pll mmpll1_early = { static struct clk_alpha_pll_postdiv mmpll1 = { .offset = 0x30, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .width = 4, .clkr.hw.init = &(struct clk_init_data){ .name = "mmpll1", @@ -323,6 +327,7 @@ static struct clk_alpha_pll_postdiv mmpll1 = { static struct clk_alpha_pll mmpll2_early = { .offset = 0x4100, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .vco_table = mmpll_gfx_vco, .num_vco = ARRAY_SIZE(mmpll_gfx_vco), .clkr.hw.init = &(struct clk_init_data){ @@ -335,6 +340,7 @@ static struct clk_alpha_pll mmpll2_early = { static struct clk_alpha_pll_postdiv mmpll2 = { .offset = 0x4100, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .width = 4, .clkr.hw.init = &(struct clk_init_data){ .name = "mmpll2", @@ -347,6 +353,7 @@ static struct clk_alpha_pll_postdiv mmpll2 = { static struct clk_alpha_pll mmpll3_early = { .offset = 0x60, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .vco_table = mmpll_p_vco, .num_vco = ARRAY_SIZE(mmpll_p_vco), .clkr.hw.init = &(struct clk_init_data){ @@ -359,6 +366,7 @@ static struct clk_alpha_pll mmpll3_early = { static struct clk_alpha_pll_postdiv mmpll3 = { .offset = 0x60, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .width = 4, .clkr.hw.init = &(struct clk_init_data){ .name = "mmpll3", @@ -371,6 +379,7 @@ static struct clk_alpha_pll_postdiv mmpll3 = { static struct clk_alpha_pll mmpll4_early = { .offset = 0x90, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .vco_table = mmpll_t_vco, .num_vco = ARRAY_SIZE(mmpll_t_vco), .clkr.hw.init = &(struct clk_init_data){ @@ -383,6 +392,7 @@ static struct clk_alpha_pll mmpll4_early = { static struct clk_alpha_pll_postdiv mmpll4 = { .offset = 0x90, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .width = 2, .clkr.hw.init = &(struct clk_init_data){ .name = "mmpll4", @@ -395,6 +405,7 @@ static struct clk_alpha_pll_postdiv mmpll4 = { static struct clk_alpha_pll mmpll5_early = { .offset = 0xc0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .vco_table = mmpll_p_vco, .num_vco = ARRAY_SIZE(mmpll_p_vco), .clkr.hw.init = &(struct clk_init_data){ @@ -407,6 +418,7 @@ static struct clk_alpha_pll mmpll5_early = { static struct clk_alpha_pll_postdiv mmpll5 = { .offset = 0xc0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .width = 4, .clkr.hw.init = &(struct clk_init_data){ .name = "mmpll5", @@ -419,6 +431,7 @@ static struct clk_alpha_pll_postdiv mmpll5 = { static struct clk_alpha_pll mmpll8_early = { .offset = 0x4130, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .vco_table = mmpll_gfx_vco, .num_vco = ARRAY_SIZE(mmpll_gfx_vco), .clkr.hw.init = &(struct clk_init_data){ @@ -431,6 +444,7 @@ static struct clk_alpha_pll mmpll8_early = { static struct clk_alpha_pll_postdiv mmpll8 = { .offset = 0x4130, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .width = 4, .clkr.hw.init = &(struct clk_init_data){ .name = "mmpll8", @@ -443,6 +457,7 @@ static struct clk_alpha_pll_postdiv mmpll8 = { static struct clk_alpha_pll mmpll9_early = { .offset = 0x4200, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .vco_table = mmpll_t_vco, .num_vco = ARRAY_SIZE(mmpll_t_vco), .clkr.hw.init = &(struct clk_init_data){ @@ -455,6 +470,7 @@ static struct clk_alpha_pll mmpll9_early = { static struct clk_alpha_pll_postdiv mmpll9 = { .offset = 0x4200, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .width = 2, .clkr.hw.init = &(struct clk_init_data){ .name = "mmpll9", diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c index c944cc421e30..858c24d4da8f 100644 --- a/drivers/clk/renesas/clk-mstp.c +++ b/drivers/clk/renesas/clk-mstp.c @@ -341,7 +341,7 @@ void __init cpg_mstp_add_clk_domain(struct device_node *np) return; pd->name = np->name; - pd->flags = GENPD_FLAG_PM_CLK; + pd->flags = GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP; pd->attach_dev = cpg_mstp_attach_dev; pd->detach_dev = cpg_mstp_detach_dev; pm_genpd_init(pd, &pm_domain_always_on_gov, false); diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index b3767472088a..41e29734126b 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -115,6 +115,7 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { }; static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = { + DEF_MOD("fdp1-0", 119, R8A7796_CLK_S0D1), DEF_MOD("scif5", 202, R8A7796_CLK_S3D4), DEF_MOD("scif4", 203, R8A7796_CLK_S3D4), DEF_MOD("scif3", 204, R8A7796_CLK_S3D4), diff --git a/drivers/clk/renesas/r8a77970-cpg-mssr.c b/drivers/clk/renesas/r8a77970-cpg-mssr.c index 72f98527473a..f55842917e8d 100644 --- a/drivers/clk/renesas/r8a77970-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77970-cpg-mssr.c @@ -105,6 +105,7 @@ static const struct mssr_mod_clk r8a77970_mod_clks[] __initconst = { DEF_MOD("vspd0", 623, R8A77970_CLK_S2D1), DEF_MOD("csi40", 716, R8A77970_CLK_CSI0), DEF_MOD("du0", 724, R8A77970_CLK_S2D1), + DEF_MOD("lvds", 727, R8A77970_CLK_S2D1), DEF_MOD("vin3", 808, R8A77970_CLK_S2D1), DEF_MOD("vin2", 809, R8A77970_CLK_S2D1), DEF_MOD("vin1", 810, R8A77970_CLK_S2D1), diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index e3d03ffea4bc..e3cc72c81311 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -513,7 +513,7 @@ static int __init cpg_mssr_add_clk_domain(struct device *dev, genpd = &pd->genpd; genpd->name = np->name; - genpd->flags = GENPD_FLAG_PM_CLK; + genpd->flags = GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP; genpd->attach_dev = cpg_mssr_attach_dev; genpd->detach_dev = cpg_mssr_detach_dev; pm_genpd_init(genpd, &pm_domain_always_on_gov, false); diff --git a/drivers/clk/spear/clk-frac-synth.c b/drivers/clk/spear/clk-frac-synth.c index 229c96daece6..f5be02205ac6 100644 --- a/drivers/clk/spear/clk-frac-synth.c +++ b/drivers/clk/spear/clk-frac-synth.c @@ -131,7 +131,7 @@ struct clk *clk_register_frac(const char *name, const char *parent_name, struct clk *clk; if (!name || !parent_name || !reg || !rtbl || !rtbl_cnt) { - pr_err("Invalid arguments passed"); + pr_err("Invalid arguments passed\n"); return ERR_PTR(-EINVAL); } diff --git a/drivers/clk/spear/clk-gpt-synth.c b/drivers/clk/spear/clk-gpt-synth.c index 28262f422562..6ed406d943ba 100644 --- a/drivers/clk/spear/clk-gpt-synth.c +++ b/drivers/clk/spear/clk-gpt-synth.c @@ -120,7 +120,7 @@ struct clk *clk_register_gpt(const char *name, const char *parent_name, unsigned struct clk *clk; if (!name || !parent_name || !reg || !rtbl || !rtbl_cnt) { - pr_err("Invalid arguments passed"); + pr_err("Invalid arguments passed\n"); return ERR_PTR(-EINVAL); } diff --git a/drivers/clk/sprd/Kconfig b/drivers/clk/sprd/Kconfig new file mode 100644 index 000000000000..87892471eb96 --- /dev/null +++ b/drivers/clk/sprd/Kconfig @@ -0,0 +1,14 @@ +config SPRD_COMMON_CLK + tristate "Clock support for Spreadtrum SoCs" + depends on ARCH_SPRD || COMPILE_TEST + default ARCH_SPRD + +if SPRD_COMMON_CLK + +# SoC Drivers + +config SPRD_SC9860_CLK + tristate "Support for the Spreadtrum SC9860 clocks" + depends on (ARM64 && ARCH_SPRD) || COMPILE_TEST + default ARM64 && ARCH_SPRD +endif diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile new file mode 100644 index 000000000000..b0d81e541ebd --- /dev/null +++ b/drivers/clk/sprd/Makefile @@ -0,0 +1,11 @@ +obj-$(CONFIG_SPRD_COMMON_CLK) += clk-sprd.o + +clk-sprd-y += common.o +clk-sprd-y += gate.o +clk-sprd-y += mux.o +clk-sprd-y += div.o +clk-sprd-y += composite.o +clk-sprd-y += pll.o + +## SoC support +obj-$(CONFIG_SPRD_SC9860_CLK) += sc9860-clk.o diff --git a/drivers/clk/sprd/common.c b/drivers/clk/sprd/common.c new file mode 100644 index 000000000000..e038b0447206 --- /dev/null +++ b/drivers/clk/sprd/common.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Spreadtrum clock infrastructure +// +// Copyright (C) 2017 Spreadtrum, Inc. +// Author: Chunyan Zhang + +#include +#include +#include +#include +#include + +#include "common.h" + +static const struct regmap_config sprdclk_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xffff, + .fast_io = true, +}; + +static void sprd_clk_set_regmap(const struct sprd_clk_desc *desc, + struct regmap *regmap) +{ + int i; + struct sprd_clk_common *cclk; + + for (i = 0; i < desc->num_clk_clks; i++) { + cclk = desc->clk_clks[i]; + if (!cclk) + continue; + + cclk->regmap = regmap; + } +} + +int sprd_clk_regmap_init(struct platform_device *pdev, + const struct sprd_clk_desc *desc) +{ + void __iomem *base; + struct device_node *node = pdev->dev.of_node; + struct regmap *regmap; + + if (of_find_property(node, "sprd,syscon", NULL)) { + regmap = syscon_regmap_lookup_by_phandle(node, "sprd,syscon"); + if (IS_ERR_OR_NULL(regmap)) { + pr_err("%s: failed to get syscon regmap\n", __func__); + return PTR_ERR(regmap); + } + } else { + base = of_iomap(node, 0); + regmap = devm_regmap_init_mmio(&pdev->dev, base, + &sprdclk_regmap_config); + if (IS_ERR_OR_NULL(regmap)) { + pr_err("failed to init regmap\n"); + return PTR_ERR(regmap); + } + } + + sprd_clk_set_regmap(desc, regmap); + + return 0; +} +EXPORT_SYMBOL_GPL(sprd_clk_regmap_init); + +int sprd_clk_probe(struct device *dev, struct clk_hw_onecell_data *clkhw) +{ + int i, ret; + struct clk_hw *hw; + + for (i = 0; i < clkhw->num; i++) { + + hw = clkhw->hws[i]; + + if (!hw) + continue; + + ret = devm_clk_hw_register(dev, hw); + if (ret) { + dev_err(dev, "Couldn't register clock %d - %s\n", + i, hw->init->name); + return ret; + } + } + + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clkhw); + if (ret) + dev_err(dev, "Failed to add clock provider\n"); + + return ret; +} +EXPORT_SYMBOL_GPL(sprd_clk_probe); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/sprd/common.h b/drivers/clk/sprd/common.h new file mode 100644 index 000000000000..abd9ff5ef448 --- /dev/null +++ b/drivers/clk/sprd/common.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Spreadtrum clock infrastructure +// +// Copyright (C) 2017 Spreadtrum, Inc. +// Author: Chunyan Zhang + +#ifndef _SPRD_CLK_COMMON_H_ +#define _SPRD_CLK_COMMON_H_ + +#include +#include +#include + +struct device_node; + +struct sprd_clk_common { + struct regmap *regmap; + u32 reg; + struct clk_hw hw; +}; + +struct sprd_clk_desc { + struct sprd_clk_common **clk_clks; + unsigned long num_clk_clks; + struct clk_hw_onecell_data *hw_clks; +}; + +static inline struct sprd_clk_common * + hw_to_sprd_clk_common(const struct clk_hw *hw) +{ + return container_of(hw, struct sprd_clk_common, hw); +} +int sprd_clk_regmap_init(struct platform_device *pdev, + const struct sprd_clk_desc *desc); +int sprd_clk_probe(struct device *dev, struct clk_hw_onecell_data *clkhw); + +#endif /* _SPRD_CLK_COMMON_H_ */ diff --git a/drivers/clk/sprd/composite.c b/drivers/clk/sprd/composite.c new file mode 100644 index 000000000000..ebb644820b1e --- /dev/null +++ b/drivers/clk/sprd/composite.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Spreadtrum composite clock driver +// +// Copyright (C) 2017 Spreadtrum, Inc. +// Author: Chunyan Zhang + +#include + +#include "composite.h" + +static long sprd_comp_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct sprd_comp *cc = hw_to_sprd_comp(hw); + + return sprd_div_helper_round_rate(&cc->common, &cc->div, + rate, parent_rate); +} + +static unsigned long sprd_comp_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct sprd_comp *cc = hw_to_sprd_comp(hw); + + return sprd_div_helper_recalc_rate(&cc->common, &cc->div, parent_rate); +} + +static int sprd_comp_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct sprd_comp *cc = hw_to_sprd_comp(hw); + + return sprd_div_helper_set_rate(&cc->common, &cc->div, + rate, parent_rate); +} + +static u8 sprd_comp_get_parent(struct clk_hw *hw) +{ + struct sprd_comp *cc = hw_to_sprd_comp(hw); + + return sprd_mux_helper_get_parent(&cc->common, &cc->mux); +} + +static int sprd_comp_set_parent(struct clk_hw *hw, u8 index) +{ + struct sprd_comp *cc = hw_to_sprd_comp(hw); + + return sprd_mux_helper_set_parent(&cc->common, &cc->mux, index); +} + +const struct clk_ops sprd_comp_ops = { + .get_parent = sprd_comp_get_parent, + .set_parent = sprd_comp_set_parent, + + .round_rate = sprd_comp_round_rate, + .recalc_rate = sprd_comp_recalc_rate, + .set_rate = sprd_comp_set_rate, +}; +EXPORT_SYMBOL_GPL(sprd_comp_ops); diff --git a/drivers/clk/sprd/composite.h b/drivers/clk/sprd/composite.h new file mode 100644 index 000000000000..0984e9e252dc --- /dev/null +++ b/drivers/clk/sprd/composite.h @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Spreadtrum composite clock driver +// +// Copyright (C) 2017 Spreadtrum, Inc. +// Author: Chunyan Zhang + +#ifndef _SPRD_COMPOSITE_H_ +#define _SPRD_COMPOSITE_H_ + +#include "common.h" +#include "mux.h" +#include "div.h" + +struct sprd_comp { + struct sprd_mux_ssel mux; + struct sprd_div_internal div; + struct sprd_clk_common common; +}; + +#define SPRD_COMP_CLK_TABLE(_struct, _name, _parent, _reg, _table, \ + _mshift, _mwidth, _dshift, _dwidth, _flags) \ + struct sprd_comp _struct = { \ + .mux = _SPRD_MUX_CLK(_mshift, _mwidth, _table), \ + .div = _SPRD_DIV_CLK(_dshift, _dwidth), \ + .common = { \ + .regmap = NULL, \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT_PARENTS(_name, \ + _parent, \ + &sprd_comp_ops, \ + _flags), \ + } \ + } + +#define SPRD_COMP_CLK(_struct, _name, _parent, _reg, _mshift, \ + _mwidth, _dshift, _dwidth, _flags) \ + SPRD_COMP_CLK_TABLE(_struct, _name, _parent, _reg, \ + NULL, _mshift, _mwidth, \ + _dshift, _dwidth, _flags) + +static inline struct sprd_comp *hw_to_sprd_comp(const struct clk_hw *hw) +{ + struct sprd_clk_common *common = hw_to_sprd_clk_common(hw); + + return container_of(common, struct sprd_comp, common); +} + +extern const struct clk_ops sprd_comp_ops; + +#endif /* _SPRD_COMPOSITE_H_ */ diff --git a/drivers/clk/sprd/div.c b/drivers/clk/sprd/div.c new file mode 100644 index 000000000000..7621a1d1ab9c --- /dev/null +++ b/drivers/clk/sprd/div.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Spreadtrum divider clock driver +// +// Copyright (C) 2017 Spreadtrum, Inc. +// Author: Chunyan Zhang + +#include + +#include "div.h" + +long sprd_div_helper_round_rate(struct sprd_clk_common *common, + const struct sprd_div_internal *div, + unsigned long rate, + unsigned long *parent_rate) +{ + return divider_round_rate(&common->hw, rate, parent_rate, + NULL, div->width, 0); +} +EXPORT_SYMBOL_GPL(sprd_div_helper_round_rate); + +static long sprd_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct sprd_div *cd = hw_to_sprd_div(hw); + + return sprd_div_helper_round_rate(&cd->common, &cd->div, + rate, parent_rate); +} + +unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common, + const struct sprd_div_internal *div, + unsigned long parent_rate) +{ + unsigned long val; + unsigned int reg; + + regmap_read(common->regmap, common->reg, ®); + val = reg >> div->shift; + val &= (1 << div->width) - 1; + + return divider_recalc_rate(&common->hw, parent_rate, val, NULL, 0, + div->width); +} +EXPORT_SYMBOL_GPL(sprd_div_helper_recalc_rate); + +static unsigned long sprd_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct sprd_div *cd = hw_to_sprd_div(hw); + + return sprd_div_helper_recalc_rate(&cd->common, &cd->div, parent_rate); +} + +int sprd_div_helper_set_rate(const struct sprd_clk_common *common, + const struct sprd_div_internal *div, + unsigned long rate, + unsigned long parent_rate) +{ + unsigned long val; + unsigned int reg; + + val = divider_get_val(rate, parent_rate, NULL, + div->width, 0); + + regmap_read(common->regmap, common->reg, ®); + reg &= ~GENMASK(div->width + div->shift - 1, div->shift); + + regmap_write(common->regmap, common->reg, + reg | (val << div->shift)); + + return 0; + +} +EXPORT_SYMBOL_GPL(sprd_div_helper_set_rate); + +static int sprd_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct sprd_div *cd = hw_to_sprd_div(hw); + + return sprd_div_helper_set_rate(&cd->common, &cd->div, + rate, parent_rate); +} + +const struct clk_ops sprd_div_ops = { + .recalc_rate = sprd_div_recalc_rate, + .round_rate = sprd_div_round_rate, + .set_rate = sprd_div_set_rate, +}; +EXPORT_SYMBOL_GPL(sprd_div_ops); diff --git a/drivers/clk/sprd/div.h b/drivers/clk/sprd/div.h new file mode 100644 index 000000000000..b3033d24d431 --- /dev/null +++ b/drivers/clk/sprd/div.h @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Spreadtrum divider clock driver +// +// Copyright (C) 2017 Spreadtrum, Inc. +// Author: Chunyan Zhang + +#ifndef _SPRD_DIV_H_ +#define _SPRD_DIV_H_ + +#include "common.h" + +/** + * struct sprd_div_internal - Internal divider description + * @shift: Bit offset of the divider in its register + * @width: Width of the divider field in its register + * + * That structure represents a single divider, and is meant to be + * embedded in other structures representing the various clock + * classes. + */ +struct sprd_div_internal { + u8 shift; + u8 width; +}; + +#define _SPRD_DIV_CLK(_shift, _width) \ + { \ + .shift = _shift, \ + .width = _width, \ + } + +struct sprd_div { + struct sprd_div_internal div; + struct sprd_clk_common common; +}; + +#define SPRD_DIV_CLK(_struct, _name, _parent, _reg, \ + _shift, _width, _flags) \ + struct sprd_div _struct = { \ + .div = _SPRD_DIV_CLK(_shift, _width), \ + .common = { \ + .regmap = NULL, \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT(_name, \ + _parent, \ + &sprd_div_ops, \ + _flags), \ + } \ + } + +static inline struct sprd_div *hw_to_sprd_div(const struct clk_hw *hw) +{ + struct sprd_clk_common *common = hw_to_sprd_clk_common(hw); + + return container_of(common, struct sprd_div, common); +} + +long sprd_div_helper_round_rate(struct sprd_clk_common *common, + const struct sprd_div_internal *div, + unsigned long rate, + unsigned long *parent_rate); + +unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common, + const struct sprd_div_internal *div, + unsigned long parent_rate); + +int sprd_div_helper_set_rate(const struct sprd_clk_common *common, + const struct sprd_div_internal *div, + unsigned long rate, + unsigned long parent_rate); + +extern const struct clk_ops sprd_div_ops; + +#endif /* _SPRD_DIV_H_ */ diff --git a/drivers/clk/sprd/gate.c b/drivers/clk/sprd/gate.c new file mode 100644 index 000000000000..f59d1936b412 --- /dev/null +++ b/drivers/clk/sprd/gate.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Spreadtrum gate clock driver +// +// Copyright (C) 2017 Spreadtrum, Inc. +// Author: Chunyan Zhang + +#include +#include + +#include "gate.h" + +static void clk_gate_toggle(const struct sprd_gate *sg, bool en) +{ + const struct sprd_clk_common *common = &sg->common; + unsigned int reg; + bool set = sg->flags & CLK_GATE_SET_TO_DISABLE ? true : false; + + set ^= en; + + regmap_read(common->regmap, common->reg, ®); + + if (set) + reg |= sg->enable_mask; + else + reg &= ~sg->enable_mask; + + regmap_write(common->regmap, common->reg, reg); +} + +static void clk_sc_gate_toggle(const struct sprd_gate *sg, bool en) +{ + const struct sprd_clk_common *common = &sg->common; + bool set = sg->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; + unsigned int offset; + + set ^= en; + + /* + * Each set/clear gate clock has three registers: + * common->reg - base register + * common->reg + offset - set register + * common->reg + 2 * offset - clear register + */ + offset = set ? sg->sc_offset : sg->sc_offset * 2; + + regmap_write(common->regmap, common->reg + offset, + sg->enable_mask); +} + +static void sprd_gate_disable(struct clk_hw *hw) +{ + struct sprd_gate *sg = hw_to_sprd_gate(hw); + + clk_gate_toggle(sg, false); +} + +static int sprd_gate_enable(struct clk_hw *hw) +{ + struct sprd_gate *sg = hw_to_sprd_gate(hw); + + clk_gate_toggle(sg, true); + + return 0; +} + +static void sprd_sc_gate_disable(struct clk_hw *hw) +{ + struct sprd_gate *sg = hw_to_sprd_gate(hw); + + clk_sc_gate_toggle(sg, false); +} + +static int sprd_sc_gate_enable(struct clk_hw *hw) +{ + struct sprd_gate *sg = hw_to_sprd_gate(hw); + + clk_sc_gate_toggle(sg, true); + + return 0; +} +static int sprd_gate_is_enabled(struct clk_hw *hw) +{ + struct sprd_gate *sg = hw_to_sprd_gate(hw); + struct sprd_clk_common *common = &sg->common; + unsigned int reg; + + regmap_read(common->regmap, common->reg, ®); + + if (sg->flags & CLK_GATE_SET_TO_DISABLE) + reg ^= sg->enable_mask; + + reg &= sg->enable_mask; + + return reg ? 1 : 0; +} + +const struct clk_ops sprd_gate_ops = { + .disable = sprd_gate_disable, + .enable = sprd_gate_enable, + .is_enabled = sprd_gate_is_enabled, +}; +EXPORT_SYMBOL_GPL(sprd_gate_ops); + +const struct clk_ops sprd_sc_gate_ops = { + .disable = sprd_sc_gate_disable, + .enable = sprd_sc_gate_enable, + .is_enabled = sprd_gate_is_enabled, +}; +EXPORT_SYMBOL_GPL(sprd_sc_gate_ops); + diff --git a/drivers/clk/sprd/gate.h b/drivers/clk/sprd/gate.h new file mode 100644 index 000000000000..2e582c68a08b --- /dev/null +++ b/drivers/clk/sprd/gate.h @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Spreadtrum gate clock driver +// +// Copyright (C) 2017 Spreadtrum, Inc. +// Author: Chunyan Zhang + +#ifndef _SPRD_GATE_H_ +#define _SPRD_GATE_H_ + +#include "common.h" + +struct sprd_gate { + u32 enable_mask; + u16 flags; + u16 sc_offset; + + struct sprd_clk_common common; +}; + +#define SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, _sc_offset, \ + _enable_mask, _flags, _gate_flags, _ops) \ + struct sprd_gate _struct = { \ + .enable_mask = _enable_mask, \ + .sc_offset = _sc_offset, \ + .flags = _gate_flags, \ + .common = { \ + .regmap = NULL, \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT(_name, \ + _parent, \ + _ops, \ + _flags), \ + } \ + } + +#define SPRD_GATE_CLK(_struct, _name, _parent, _reg, \ + _enable_mask, _flags, _gate_flags) \ + SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, 0, \ + _enable_mask, _flags, _gate_flags, \ + &sprd_gate_ops) + +#define SPRD_SC_GATE_CLK(_struct, _name, _parent, _reg, _sc_offset, \ + _enable_mask, _flags, _gate_flags) \ + SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, _sc_offset, \ + _enable_mask, _flags, _gate_flags, \ + &sprd_sc_gate_ops) + +static inline struct sprd_gate *hw_to_sprd_gate(const struct clk_hw *hw) +{ + struct sprd_clk_common *common = hw_to_sprd_clk_common(hw); + + return container_of(common, struct sprd_gate, common); +} + +extern const struct clk_ops sprd_gate_ops; +extern const struct clk_ops sprd_sc_gate_ops; + +#endif /* _SPRD_GATE_H_ */ diff --git a/drivers/clk/sprd/mux.c b/drivers/clk/sprd/mux.c new file mode 100644 index 000000000000..624041b60358 --- /dev/null +++ b/drivers/clk/sprd/mux.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Spreadtrum multiplexer clock driver +// +// Copyright (C) 2017 Spreadtrum, Inc. +// Author: Chunyan Zhang + +#include +#include +#include + +#include "mux.h" + +u8 sprd_mux_helper_get_parent(const struct sprd_clk_common *common, + const struct sprd_mux_ssel *mux) +{ + unsigned int reg; + u8 parent; + int num_parents; + int i; + + regmap_read(common->regmap, common->reg, ®); + parent = reg >> mux->shift; + parent &= (1 << mux->width) - 1; + + if (!mux->table) + return parent; + + num_parents = clk_hw_get_num_parents(&common->hw); + + for (i = 0; i < num_parents - 1; i++) + if (parent >= mux->table[i] && parent < mux->table[i + 1]) + return i; + + return num_parents - 1; +} +EXPORT_SYMBOL_GPL(sprd_mux_helper_get_parent); + +static u8 sprd_mux_get_parent(struct clk_hw *hw) +{ + struct sprd_mux *cm = hw_to_sprd_mux(hw); + + return sprd_mux_helper_get_parent(&cm->common, &cm->mux); +} + +int sprd_mux_helper_set_parent(const struct sprd_clk_common *common, + const struct sprd_mux_ssel *mux, + u8 index) +{ + unsigned int reg; + + if (mux->table) + index = mux->table[index]; + + regmap_read(common->regmap, common->reg, ®); + reg &= ~GENMASK(mux->width + mux->shift - 1, mux->shift); + regmap_write(common->regmap, common->reg, + reg | (index << mux->shift)); + + return 0; +} +EXPORT_SYMBOL_GPL(sprd_mux_helper_set_parent); + +static int sprd_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct sprd_mux *cm = hw_to_sprd_mux(hw); + + return sprd_mux_helper_set_parent(&cm->common, &cm->mux, index); +} + +const struct clk_ops sprd_mux_ops = { + .get_parent = sprd_mux_get_parent, + .set_parent = sprd_mux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; +EXPORT_SYMBOL_GPL(sprd_mux_ops); diff --git a/drivers/clk/sprd/mux.h b/drivers/clk/sprd/mux.h new file mode 100644 index 000000000000..548cfa0f145c --- /dev/null +++ b/drivers/clk/sprd/mux.h @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Spreadtrum multiplexer clock driver +// +// Copyright (C) 2017 Spreadtrum, Inc. +// Author: Chunyan Zhang + +#ifndef _SPRD_MUX_H_ +#define _SPRD_MUX_H_ + +#include "common.h" + +/** + * struct sprd_mux_ssel - Mux clock's source select bits in its register + * @shift: Bit offset of the divider in its register + * @width: Width of the divider field in its register + * @table: For some mux clocks, not all sources are used on some special + * chips, this matches the value of mux clock's register and the + * sources which are used for this mux clock + */ +struct sprd_mux_ssel { + u8 shift; + u8 width; + const u8 *table; +}; + +struct sprd_mux { + struct sprd_mux_ssel mux; + struct sprd_clk_common common; +}; + +#define _SPRD_MUX_CLK(_shift, _width, _table) \ + { \ + .shift = _shift, \ + .width = _width, \ + .table = _table, \ + } + +#define SPRD_MUX_CLK_TABLE(_struct, _name, _parents, _table, \ + _reg, _shift, _width, \ + _flags) \ + struct sprd_mux _struct = { \ + .mux = _SPRD_MUX_CLK(_shift, _width, _table), \ + .common = { \ + .regmap = NULL, \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT_PARENTS(_name, \ + _parents, \ + &sprd_mux_ops, \ + _flags), \ + } \ + } + +#define SPRD_MUX_CLK(_struct, _name, _parents, _reg, \ + _shift, _width, _flags) \ + SPRD_MUX_CLK_TABLE(_struct, _name, _parents, NULL, \ + _reg, _shift, _width, _flags) + +static inline struct sprd_mux *hw_to_sprd_mux(const struct clk_hw *hw) +{ + struct sprd_clk_common *common = hw_to_sprd_clk_common(hw); + + return container_of(common, struct sprd_mux, common); +} + +extern const struct clk_ops sprd_mux_ops; + +u8 sprd_mux_helper_get_parent(const struct sprd_clk_common *common, + const struct sprd_mux_ssel *mux); +int sprd_mux_helper_set_parent(const struct sprd_clk_common *common, + const struct sprd_mux_ssel *mux, + u8 index); + +#endif /* _SPRD_MUX_H_ */ diff --git a/drivers/clk/sprd/pll.c b/drivers/clk/sprd/pll.c new file mode 100644 index 000000000000..36b4402bf09e --- /dev/null +++ b/drivers/clk/sprd/pll.c @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Spreadtrum pll clock driver +// +// Copyright (C) 2015~2017 Spreadtrum, Inc. +// Author: Chunyan Zhang + +#include +#include +#include +#include + +#include "pll.h" + +#define CLK_PLL_1M 1000000 +#define CLK_PLL_10M (CLK_PLL_1M * 10) + +#define pindex(pll, member) \ + (pll->factors[member].shift / (8 * sizeof(pll->regs_num))) + +#define pshift(pll, member) \ + (pll->factors[member].shift % (8 * sizeof(pll->regs_num))) + +#define pwidth(pll, member) \ + pll->factors[member].width + +#define pmask(pll, member) \ + ((pwidth(pll, member)) ? \ + GENMASK(pwidth(pll, member) + pshift(pll, member) - 1, \ + pshift(pll, member)) : 0) + +#define pinternal(pll, cfg, member) \ + (cfg[pindex(pll, member)] & pmask(pll, member)) + +#define pinternal_val(pll, cfg, member) \ + (pinternal(pll, cfg, member) >> pshift(pll, member)) + +static inline unsigned int +sprd_pll_read(const struct sprd_pll *pll, u8 index) +{ + const struct sprd_clk_common *common = &pll->common; + unsigned int val = 0; + + if (WARN_ON(index >= pll->regs_num)) + return 0; + + regmap_read(common->regmap, common->reg + index * 4, &val); + + return val; +} + +static inline void +sprd_pll_write(const struct sprd_pll *pll, u8 index, + u32 msk, u32 val) +{ + const struct sprd_clk_common *common = &pll->common; + unsigned int offset, reg; + int ret = 0; + + if (WARN_ON(index >= pll->regs_num)) + return; + + offset = common->reg + index * 4; + ret = regmap_read(common->regmap, offset, ®); + if (!ret) + regmap_write(common->regmap, offset, (reg & ~msk) | val); +} + +static unsigned long pll_get_refin(const struct sprd_pll *pll) +{ + u32 shift, mask, index, refin_id = 3; + const unsigned long refin[4] = { 2, 4, 13, 26 }; + + if (pwidth(pll, PLL_REFIN)) { + index = pindex(pll, PLL_REFIN); + shift = pshift(pll, PLL_REFIN); + mask = pmask(pll, PLL_REFIN); + refin_id = (sprd_pll_read(pll, index) & mask) >> shift; + if (refin_id > 3) + refin_id = 3; + } + + return refin[refin_id]; +} + +static u32 pll_get_ibias(u64 rate, const u64 *table) +{ + u32 i, num = table[0]; + + for (i = 1; i < num + 1; i++) + if (rate <= table[i]) + break; + + return (i == num + 1) ? num : i; +} + +static unsigned long _sprd_pll_recalc_rate(const struct sprd_pll *pll, + unsigned long parent_rate) +{ + u32 *cfg; + u32 i, mask, regs_num = pll->regs_num; + unsigned long rate, nint, kint = 0; + u64 refin; + u16 k1, k2; + + cfg = kcalloc(regs_num, sizeof(*cfg), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + for (i = 0; i < regs_num; i++) + cfg[i] = sprd_pll_read(pll, i); + + refin = pll_get_refin(pll); + + if (pinternal(pll, cfg, PLL_PREDIV)) + refin = refin * 2; + + if (pwidth(pll, PLL_POSTDIV) && + ((pll->fflag == 1 && pinternal(pll, cfg, PLL_POSTDIV)) || + (!pll->fflag && !pinternal(pll, cfg, PLL_POSTDIV)))) + refin = refin / 2; + + if (!pinternal(pll, cfg, PLL_DIV_S)) { + rate = refin * pinternal_val(pll, cfg, PLL_N) * CLK_PLL_10M; + } else { + nint = pinternal_val(pll, cfg, PLL_NINT); + if (pinternal(pll, cfg, PLL_SDM_EN)) + kint = pinternal_val(pll, cfg, PLL_KINT); + + mask = pmask(pll, PLL_KINT); + + k1 = pll->k1; + k2 = pll->k2; + rate = DIV_ROUND_CLOSEST_ULL(refin * kint * k1, + ((mask >> __ffs(mask)) + 1)) * + k2 + refin * nint * CLK_PLL_1M; + } + + return rate; +} + +#define SPRD_PLL_WRITE_CHECK(pll, i, mask, val) \ + (((sprd_pll_read(pll, i) & mask) == val) ? 0 : (-EFAULT)) + +static int _sprd_pll_set_rate(const struct sprd_pll *pll, + unsigned long rate, + unsigned long parent_rate) +{ + struct reg_cfg *cfg; + int ret = 0; + u32 mask, shift, width, ibias_val, index; + u32 regs_num = pll->regs_num, i = 0; + unsigned long kint, nint; + u64 tmp, refin, fvco = rate; + + cfg = kcalloc(regs_num, sizeof(*cfg), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + refin = pll_get_refin(pll); + + mask = pmask(pll, PLL_PREDIV); + index = pindex(pll, PLL_PREDIV); + width = pwidth(pll, PLL_PREDIV); + if (width && (sprd_pll_read(pll, index) & mask)) + refin = refin * 2; + + mask = pmask(pll, PLL_POSTDIV); + index = pindex(pll, PLL_POSTDIV); + width = pwidth(pll, PLL_POSTDIV); + cfg[index].msk = mask; + if (width && ((pll->fflag == 1 && fvco <= pll->fvco) || + (pll->fflag == 0 && fvco > pll->fvco))) + cfg[index].val |= mask; + + if (width && fvco <= pll->fvco) + fvco = fvco * 2; + + mask = pmask(pll, PLL_DIV_S); + index = pindex(pll, PLL_DIV_S); + cfg[index].val |= mask; + cfg[index].msk |= mask; + + mask = pmask(pll, PLL_SDM_EN); + index = pindex(pll, PLL_SDM_EN); + cfg[index].val |= mask; + cfg[index].msk |= mask; + + nint = do_div(fvco, refin * CLK_PLL_1M); + mask = pmask(pll, PLL_NINT); + index = pindex(pll, PLL_NINT); + shift = pshift(pll, PLL_NINT); + cfg[index].val |= (nint << shift) & mask; + cfg[index].msk |= mask; + + mask = pmask(pll, PLL_KINT); + index = pindex(pll, PLL_KINT); + width = pwidth(pll, PLL_KINT); + shift = pshift(pll, PLL_KINT); + tmp = fvco - refin * nint * CLK_PLL_1M; + tmp = do_div(tmp, 10000) * ((mask >> shift) + 1); + kint = DIV_ROUND_CLOSEST_ULL(tmp, refin * 100); + cfg[index].val |= (kint << shift) & mask; + cfg[index].msk |= mask; + + ibias_val = pll_get_ibias(fvco, pll->itable); + + mask = pmask(pll, PLL_IBIAS); + index = pindex(pll, PLL_IBIAS); + shift = pshift(pll, PLL_IBIAS); + cfg[index].val |= ibias_val << shift & mask; + cfg[index].msk |= mask; + + for (i = 0; i < regs_num; i++) { + if (cfg[i].msk) { + sprd_pll_write(pll, i, cfg[i].msk, cfg[i].val); + ret |= SPRD_PLL_WRITE_CHECK(pll, i, cfg[i].msk, + cfg[i].val); + } + } + + if (!ret) + udelay(pll->udelay); + + return ret; +} + +static unsigned long sprd_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct sprd_pll *pll = hw_to_sprd_pll(hw); + + return _sprd_pll_recalc_rate(pll, parent_rate); +} + +static int sprd_pll_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct sprd_pll *pll = hw_to_sprd_pll(hw); + + return _sprd_pll_set_rate(pll, rate, parent_rate); +} + +static int sprd_pll_clk_prepare(struct clk_hw *hw) +{ + struct sprd_pll *pll = hw_to_sprd_pll(hw); + + udelay(pll->udelay); + + return 0; +} + +static long sprd_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + return rate; +} + +const struct clk_ops sprd_pll_ops = { + .prepare = sprd_pll_clk_prepare, + .recalc_rate = sprd_pll_recalc_rate, + .round_rate = sprd_pll_round_rate, + .set_rate = sprd_pll_set_rate, +}; +EXPORT_SYMBOL_GPL(sprd_pll_ops); diff --git a/drivers/clk/sprd/pll.h b/drivers/clk/sprd/pll.h new file mode 100644 index 000000000000..514175621099 --- /dev/null +++ b/drivers/clk/sprd/pll.h @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Spreadtrum pll clock driver +// +// Copyright (C) 2015~2017 Spreadtrum, Inc. +// Author: Chunyan Zhang + +#ifndef _SPRD_PLL_H_ +#define _SPRD_PLL_H_ + +#include "common.h" + +struct reg_cfg { + u32 val; + u32 msk; +}; + +struct clk_bit_field { + u8 shift; + u8 width; +}; + +enum { + PLL_LOCK_DONE, + PLL_DIV_S, + PLL_MOD_EN, + PLL_SDM_EN, + PLL_REFIN, + PLL_IBIAS, + PLL_N, + PLL_NINT, + PLL_KINT, + PLL_PREDIV, + PLL_POSTDIV, + + PLL_FACT_MAX +}; + +/* + * struct sprd_pll - definition of adjustable pll clock + * + * @reg: registers used to set the configuration of pll clock, + * reg[0] shows how many registers this pll clock uses. + * @itable: pll ibias table, itable[0] means how many items this + * table includes + * @udelay delay time after setting rate + * @factors used to calculate the pll clock rate + * @fvco: fvco threshold rate + * @fflag: fvco flag + */ +struct sprd_pll { + u32 regs_num; + const u64 *itable; + const struct clk_bit_field *factors; + u16 udelay; + u16 k1; + u16 k2; + u16 fflag; + u64 fvco; + + struct sprd_clk_common common; +}; + +#define SPRD_PLL_WITH_ITABLE_K_FVCO(_struct, _name, _parent, _reg, \ + _regs_num, _itable, _factors, \ + _udelay, _k1, _k2, _fflag, _fvco) \ + struct sprd_pll _struct = { \ + .regs_num = _regs_num, \ + .itable = _itable, \ + .factors = _factors, \ + .udelay = _udelay, \ + .k1 = _k1, \ + .k2 = _k2, \ + .fflag = _fflag, \ + .fvco = _fvco, \ + .common = { \ + .regmap = NULL, \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT(_name, \ + _parent, \ + &sprd_pll_ops, \ + 0), \ + }, \ + } + +#define SPRD_PLL_WITH_ITABLE_K(_struct, _name, _parent, _reg, \ + _regs_num, _itable, _factors, \ + _udelay, _k1, _k2) \ + SPRD_PLL_WITH_ITABLE_K_FVCO(_struct, _name, _parent, _reg, \ + _regs_num, _itable, _factors, \ + _udelay, _k1, _k2, 0, 0) + +#define SPRD_PLL_WITH_ITABLE_1K(_struct, _name, _parent, _reg, \ + _regs_num, _itable, _factors, _udelay) \ + SPRD_PLL_WITH_ITABLE_K_FVCO(_struct, _name, _parent, _reg, \ + _regs_num, _itable, _factors, \ + _udelay, 1000, 1000, 0, 0) + +static inline struct sprd_pll *hw_to_sprd_pll(struct clk_hw *hw) +{ + struct sprd_clk_common *common = hw_to_sprd_clk_common(hw); + + return container_of(common, struct sprd_pll, common); +} + +extern const struct clk_ops sprd_pll_ops; + +#endif /* _SPRD_PLL_H_ */ diff --git a/drivers/clk/sprd/sc9860-clk.c b/drivers/clk/sprd/sc9860-clk.c new file mode 100644 index 000000000000..ed5c027df0f4 --- /dev/null +++ b/drivers/clk/sprd/sc9860-clk.c @@ -0,0 +1,1974 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Spreatrum SC9860 clock driver +// +// Copyright (C) 2017 Spreadtrum, Inc. +// Author: Chunyan Zhang + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" +#include "composite.h" +#include "div.h" +#include "gate.h" +#include "mux.h" +#include "pll.h" + +static CLK_FIXED_FACTOR(fac_4m, "fac-4m", "ext-26m", + 6, 1, 0); +static CLK_FIXED_FACTOR(fac_2m, "fac-2m", "ext-26m", + 13, 1, 0); +static CLK_FIXED_FACTOR(fac_1m, "fac-1m", "ext-26m", + 26, 1, 0); +static CLK_FIXED_FACTOR(fac_250k, "fac-250k", "ext-26m", + 104, 1, 0); +static CLK_FIXED_FACTOR(fac_rpll0_26m, "rpll0-26m", "ext-26m", + 1, 1, 0); +static CLK_FIXED_FACTOR(fac_rpll1_26m, "rpll1-26m", "ext-26m", + 1, 1, 0); +static CLK_FIXED_FACTOR(fac_rco_25m, "rco-25m", "ext-rc0-100m", + 4, 1, 0); +static CLK_FIXED_FACTOR(fac_rco_4m, "rco-4m", "ext-rc0-100m", + 25, 1, 0); +static CLK_FIXED_FACTOR(fac_rco_2m, "rco-2m", "ext-rc0-100m", + 50, 1, 0); +static CLK_FIXED_FACTOR(fac_3k2, "fac-3k2", "ext-32k", + 10, 1, 0); +static CLK_FIXED_FACTOR(fac_1k, "fac-1k", "ext-32k", + 32, 1, 0); + +static SPRD_SC_GATE_CLK(mpll0_gate, "mpll0-gate", "ext-26m", 0xb0, + 0x1000, BIT(2), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(mpll1_gate, "mpll1-gate", "ext-26m", 0xb0, + 0x1000, BIT(18), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(dpll0_gate, "dpll0-gate", "ext-26m", 0xb4, + 0x1000, BIT(2), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(dpll1_gate, "dpll1-gate", "ext-26m", 0xb4, + 0x1000, BIT(18), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ltepll0_gate, "ltepll0-gate", "ext-26m", 0xb8, + 0x1000, BIT(2), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(twpll_gate, "twpll-gate", "ext-26m", 0xbc, + 0x1000, BIT(2), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ltepll1_gate, "ltepll1-gate", "ext-26m", 0x10c, + 0x1000, BIT(2), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(rpll0_gate, "rpll0-gate", "ext-26m", 0x16c, + 0x1000, BIT(2), 0, 0); +static SPRD_SC_GATE_CLK(rpll1_gate, "rpll1-gate", "ext-26m", 0x16c, + 0x1000, BIT(18), 0, 0); +static SPRD_SC_GATE_CLK(cppll_gate, "cppll-gate", "ext-26m", 0x2b4, + 0x1000, BIT(2), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(gpll_gate, "gpll-gate", "ext-26m", 0x32c, + 0x1000, BIT(0), CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE); + +static struct sprd_clk_common *sc9860_pmu_gate_clks[] = { + /* address base is 0x402b0000 */ + &mpll0_gate.common, + &mpll1_gate.common, + &dpll0_gate.common, + &dpll1_gate.common, + <epll0_gate.common, + &twpll_gate.common, + <epll1_gate.common, + &rpll0_gate.common, + &rpll1_gate.common, + &cppll_gate.common, + &gpll_gate.common, +}; + +static struct clk_hw_onecell_data sc9860_pmu_gate_hws = { + .hws = { + [CLK_FAC_4M] = &fac_4m.hw, + [CLK_FAC_2M] = &fac_2m.hw, + [CLK_FAC_1M] = &fac_1m.hw, + [CLK_FAC_250K] = &fac_250k.hw, + [CLK_FAC_RPLL0_26M] = &fac_rpll0_26m.hw, + [CLK_FAC_RPLL1_26M] = &fac_rpll1_26m.hw, + [CLK_FAC_RCO25M] = &fac_rco_25m.hw, + [CLK_FAC_RCO4M] = &fac_rco_4m.hw, + [CLK_FAC_RCO2M] = &fac_rco_2m.hw, + [CLK_FAC_3K2] = &fac_3k2.hw, + [CLK_FAC_1K] = &fac_1k.hw, + [CLK_MPLL0_GATE] = &mpll0_gate.common.hw, + [CLK_MPLL1_GATE] = &mpll1_gate.common.hw, + [CLK_DPLL0_GATE] = &dpll0_gate.common.hw, + [CLK_DPLL1_GATE] = &dpll1_gate.common.hw, + [CLK_LTEPLL0_GATE] = <epll0_gate.common.hw, + [CLK_TWPLL_GATE] = &twpll_gate.common.hw, + [CLK_LTEPLL1_GATE] = <epll1_gate.common.hw, + [CLK_RPLL0_GATE] = &rpll0_gate.common.hw, + [CLK_RPLL1_GATE] = &rpll1_gate.common.hw, + [CLK_CPPLL_GATE] = &cppll_gate.common.hw, + [CLK_GPLL_GATE] = &gpll_gate.common.hw, + }, + .num = CLK_PMU_GATE_NUM, +}; + +static const struct sprd_clk_desc sc9860_pmu_gate_desc = { + .clk_clks = sc9860_pmu_gate_clks, + .num_clk_clks = ARRAY_SIZE(sc9860_pmu_gate_clks), + .hw_clks = &sc9860_pmu_gate_hws, +}; + +/* GPLL/LPLL/DPLL/RPLL/CPLL */ +static const u64 itable1[4] = {3, 780000000, 988000000, 1196000000}; + +/* TWPLL/MPLL0/MPLL1 */ +static const u64 itable2[4] = {3, 1638000000, 2080000000, 2600000000UL}; + +static const struct clk_bit_field f_mpll0[PLL_FACT_MAX] = { + { .shift = 20, .width = 1 }, /* lock_done */ + { .shift = 19, .width = 1 }, /* div_s */ + { .shift = 18, .width = 1 }, /* mod_en */ + { .shift = 17, .width = 1 }, /* sdm_en */ + { .shift = 0, .width = 0 }, /* refin */ + { .shift = 11, .width = 2 }, /* ibias */ + { .shift = 0, .width = 7 }, /* n */ + { .shift = 57, .width = 7 }, /* nint */ + { .shift = 32, .width = 23}, /* kint */ + { .shift = 0, .width = 0 }, /* prediv */ + { .shift = 56, .width = 1 }, /* postdiv */ +}; +static SPRD_PLL_WITH_ITABLE_K_FVCO(mpll0_clk, "mpll0", "mpll0-gate", 0x24, + 2, itable2, f_mpll0, 200, + 1000, 1000, 1, 1300000000); + +static const struct clk_bit_field f_mpll1[PLL_FACT_MAX] = { + { .shift = 20, .width = 1 }, /* lock_done */ + { .shift = 19, .width = 1 }, /* div_s */ + { .shift = 18, .width = 1 }, /* mod_en */ + { .shift = 17, .width = 1 }, /* sdm_en */ + { .shift = 0, .width = 0 }, /* refin */ + { .shift = 11, .width = 2 }, /* ibias */ + { .shift = 0, .width = 7 }, /* n */ + { .shift = 57, .width = 7 }, /* nint */ + { .shift = 32, .width = 23}, /* kint */ + { .shift = 56, .width = 1 }, /* prediv */ + { .shift = 0, .width = 0 }, /* postdiv */ +}; +static SPRD_PLL_WITH_ITABLE_1K(mpll1_clk, "mpll1", "mpll1-gate", 0x2c, + 2, itable2, f_mpll1, 200); + +static const struct clk_bit_field f_dpll[PLL_FACT_MAX] = { + { .shift = 16, .width = 1 }, /* lock_done */ + { .shift = 15, .width = 1 }, /* div_s */ + { .shift = 14, .width = 1 }, /* mod_en */ + { .shift = 13, .width = 1 }, /* sdm_en */ + { .shift = 0, .width = 0 }, /* refin */ + { .shift = 8, .width = 2 }, /* ibias */ + { .shift = 0, .width = 7 }, /* n */ + { .shift = 57, .width = 7 }, /* nint */ + { .shift = 32, .width = 23}, /* kint */ + { .shift = 0, .width = 0 }, /* prediv */ + { .shift = 0, .width = 0 }, /* postdiv */ +}; +static SPRD_PLL_WITH_ITABLE_1K(dpll0_clk, "dpll0", "dpll0-gate", 0x34, + 2, itable1, f_dpll, 200); + +static SPRD_PLL_WITH_ITABLE_1K(dpll1_clk, "dpll1", "dpll1-gate", 0x3c, + 2, itable1, f_dpll, 200); + +static const struct clk_bit_field f_rpll[PLL_FACT_MAX] = { + { .shift = 0, .width = 1 }, /* lock_done */ + { .shift = 3, .width = 1 }, /* div_s */ + { .shift = 80, .width = 1 }, /* mod_en */ + { .shift = 81, .width = 1 }, /* sdm_en */ + { .shift = 0, .width = 0 }, /* refin */ + { .shift = 14, .width = 2 }, /* ibias */ + { .shift = 16, .width = 7 }, /* n */ + { .shift = 4, .width = 7 }, /* nint */ + { .shift = 32, .width = 23}, /* kint */ + { .shift = 0, .width = 0 }, /* prediv */ + { .shift = 0, .width = 0 }, /* postdiv */ +}; +static SPRD_PLL_WITH_ITABLE_1K(rpll0_clk, "rpll0", "rpll0-gate", 0x44, + 3, itable1, f_rpll, 200); + +static SPRD_PLL_WITH_ITABLE_1K(rpll1_clk, "rpll1", "rpll1-gate", 0x50, + 3, itable1, f_rpll, 200); + +static const struct clk_bit_field f_twpll[PLL_FACT_MAX] = { + { .shift = 21, .width = 1 }, /* lock_done */ + { .shift = 20, .width = 1 }, /* div_s */ + { .shift = 19, .width = 1 }, /* mod_en */ + { .shift = 18, .width = 1 }, /* sdm_en */ + { .shift = 0, .width = 0 }, /* refin */ + { .shift = 13, .width = 2 }, /* ibias */ + { .shift = 0, .width = 7 }, /* n */ + { .shift = 57, .width = 7 }, /* nint */ + { .shift = 32, .width = 23}, /* kint */ + { .shift = 0, .width = 0 }, /* prediv */ + { .shift = 0, .width = 0 }, /* postdiv */ +}; +static SPRD_PLL_WITH_ITABLE_1K(twpll_clk, "twpll", "twpll-gate", 0x5c, + 2, itable2, f_twpll, 200); + +static const struct clk_bit_field f_ltepll[PLL_FACT_MAX] = { + { .shift = 31, .width = 1 }, /* lock_done */ + { .shift = 27, .width = 1 }, /* div_s */ + { .shift = 26, .width = 1 }, /* mod_en */ + { .shift = 25, .width = 1 }, /* sdm_en */ + { .shift = 0, .width = 0 }, /* refin */ + { .shift = 20, .width = 2 }, /* ibias */ + { .shift = 0, .width = 7 }, /* n */ + { .shift = 57, .width = 7 }, /* nint */ + { .shift = 32, .width = 23}, /* kint */ + { .shift = 0, .width = 0 }, /* prediv */ + { .shift = 0, .width = 0 }, /* postdiv */ +}; +static SPRD_PLL_WITH_ITABLE_1K(ltepll0_clk, "ltepll0", "ltepll0-gate", + 0x64, 2, itable1, + f_ltepll, 200); +static SPRD_PLL_WITH_ITABLE_1K(ltepll1_clk, "ltepll1", "ltepll1-gate", + 0x6c, 2, itable1, + f_ltepll, 200); + +static const struct clk_bit_field f_gpll[PLL_FACT_MAX] = { + { .shift = 18, .width = 1 }, /* lock_done */ + { .shift = 15, .width = 1 }, /* div_s */ + { .shift = 14, .width = 1 }, /* mod_en */ + { .shift = 13, .width = 1 }, /* sdm_en */ + { .shift = 0, .width = 0 }, /* refin */ + { .shift = 8, .width = 2 }, /* ibias */ + { .shift = 0, .width = 7 }, /* n */ + { .shift = 57, .width = 7 }, /* nint */ + { .shift = 32, .width = 23}, /* kint */ + { .shift = 0, .width = 0 }, /* prediv */ + { .shift = 17, .width = 1 }, /* postdiv */ +}; +static SPRD_PLL_WITH_ITABLE_K_FVCO(gpll_clk, "gpll", "gpll-gate", 0x9c, + 2, itable1, f_gpll, 200, + 1000, 1000, 1, 600000000); + +static const struct clk_bit_field f_cppll[PLL_FACT_MAX] = { + { .shift = 17, .width = 1 }, /* lock_done */ + { .shift = 15, .width = 1 }, /* div_s */ + { .shift = 14, .width = 1 }, /* mod_en */ + { .shift = 13, .width = 1 }, /* sdm_en */ + { .shift = 0, .width = 0 }, /* refin */ + { .shift = 8, .width = 2 }, /* ibias */ + { .shift = 0, .width = 7 }, /* n */ + { .shift = 57, .width = 7 }, /* nint */ + { .shift = 32, .width = 23}, /* kint */ + { .shift = 0, .width = 0 }, /* prediv */ + { .shift = 0, .width = 0 }, /* postdiv */ +}; +static SPRD_PLL_WITH_ITABLE_1K(cppll_clk, "cppll", "cppll-gate", 0xc4, + 2, itable1, f_cppll, 200); + +static CLK_FIXED_FACTOR(gpll_42m5, "gpll-42m5", "gpll", 20, 1, 0); +static CLK_FIXED_FACTOR(twpll_768m, "twpll-768m", "twpll", 2, 1, 0); +static CLK_FIXED_FACTOR(twpll_384m, "twpll-384m", "twpll", 4, 1, 0); +static CLK_FIXED_FACTOR(twpll_192m, "twpll-192m", "twpll", 8, 1, 0); +static CLK_FIXED_FACTOR(twpll_96m, "twpll-96m", "twpll", 16, 1, 0); +static CLK_FIXED_FACTOR(twpll_48m, "twpll-48m", "twpll", 32, 1, 0); +static CLK_FIXED_FACTOR(twpll_24m, "twpll-24m", "twpll", 64, 1, 0); +static CLK_FIXED_FACTOR(twpll_12m, "twpll-12m", "twpll", 128, 1, 0); +static CLK_FIXED_FACTOR(twpll_512m, "twpll-512m", "twpll", 3, 1, 0); +static CLK_FIXED_FACTOR(twpll_256m, "twpll-256m", "twpll", 6, 1, 0); +static CLK_FIXED_FACTOR(twpll_128m, "twpll-128m", "twpll", 12, 1, 0); +static CLK_FIXED_FACTOR(twpll_64m, "twpll-64m", "twpll", 24, 1, 0); +static CLK_FIXED_FACTOR(twpll_307m2, "twpll-307m2", "twpll", 5, 1, 0); +static CLK_FIXED_FACTOR(twpll_153m6, "twpll-153m6", "twpll", 10, 1, 0); +static CLK_FIXED_FACTOR(twpll_76m8, "twpll-76m8", "twpll", 20, 1, 0); +static CLK_FIXED_FACTOR(twpll_51m2, "twpll-51m2", "twpll", 30, 1, 0); +static CLK_FIXED_FACTOR(twpll_38m4, "twpll-38m4", "twpll", 40, 1, 0); +static CLK_FIXED_FACTOR(twpll_19m2, "twpll-19m2", "twpll", 80, 1, 0); +static CLK_FIXED_FACTOR(l0_614m4, "l0-614m4", "ltepll0", 2, 1, 0); +static CLK_FIXED_FACTOR(l0_409m6, "l0-409m6", "ltepll0", 3, 1, 0); +static CLK_FIXED_FACTOR(l0_38m, "l0-38m", "ltepll0", 32, 1, 0); +static CLK_FIXED_FACTOR(l1_38m, "l1-38m", "ltepll1", 32, 1, 0); +static CLK_FIXED_FACTOR(rpll0_192m, "rpll0-192m", "rpll0", 6, 1, 0); +static CLK_FIXED_FACTOR(rpll0_96m, "rpll0-96m", "rpll0", 12, 1, 0); +static CLK_FIXED_FACTOR(rpll0_48m, "rpll0-48m", "rpll0", 24, 1, 0); +static CLK_FIXED_FACTOR(rpll1_468m, "rpll1-468m", "rpll1", 2, 1, 0); +static CLK_FIXED_FACTOR(rpll1_192m, "rpll1-192m", "rpll1", 6, 1, 0); +static CLK_FIXED_FACTOR(rpll1_96m, "rpll1-96m", "rpll1", 12, 1, 0); +static CLK_FIXED_FACTOR(rpll1_64m, "rpll1-64m", "rpll1", 18, 1, 0); +static CLK_FIXED_FACTOR(rpll1_48m, "rpll1-48m", "rpll1", 24, 1, 0); +static CLK_FIXED_FACTOR(dpll0_50m, "dpll0-50m", "dpll0", 16, 1, 0); +static CLK_FIXED_FACTOR(dpll1_50m, "dpll1-50m", "dpll1", 16, 1, 0); +static CLK_FIXED_FACTOR(cppll_50m, "cppll-50m", "cppll", 18, 1, 0); +static CLK_FIXED_FACTOR(m0_39m, "m0-39m", "mpll0", 32, 1, 0); +static CLK_FIXED_FACTOR(m1_63m, "m1-63m", "mpll1", 32, 1, 0); + +static struct sprd_clk_common *sc9860_pll_clks[] = { + /* address base is 0x40400000 */ + &mpll0_clk.common, + &mpll1_clk.common, + &dpll0_clk.common, + &dpll1_clk.common, + &rpll0_clk.common, + &rpll1_clk.common, + &twpll_clk.common, + <epll0_clk.common, + <epll1_clk.common, + &gpll_clk.common, + &cppll_clk.common, +}; + +static struct clk_hw_onecell_data sc9860_pll_hws = { + .hws = { + [CLK_MPLL0] = &mpll0_clk.common.hw, + [CLK_MPLL1] = &mpll1_clk.common.hw, + [CLK_DPLL0] = &dpll0_clk.common.hw, + [CLK_DPLL1] = &dpll1_clk.common.hw, + [CLK_RPLL0] = &rpll0_clk.common.hw, + [CLK_RPLL1] = &rpll1_clk.common.hw, + [CLK_TWPLL] = &twpll_clk.common.hw, + [CLK_LTEPLL0] = <epll0_clk.common.hw, + [CLK_LTEPLL1] = <epll1_clk.common.hw, + [CLK_GPLL] = &gpll_clk.common.hw, + [CLK_CPPLL] = &cppll_clk.common.hw, + [CLK_GPLL_42M5] = &gpll_42m5.hw, + [CLK_TWPLL_768M] = &twpll_768m.hw, + [CLK_TWPLL_384M] = &twpll_384m.hw, + [CLK_TWPLL_192M] = &twpll_192m.hw, + [CLK_TWPLL_96M] = &twpll_96m.hw, + [CLK_TWPLL_48M] = &twpll_48m.hw, + [CLK_TWPLL_24M] = &twpll_24m.hw, + [CLK_TWPLL_12M] = &twpll_12m.hw, + [CLK_TWPLL_512M] = &twpll_512m.hw, + [CLK_TWPLL_256M] = &twpll_256m.hw, + [CLK_TWPLL_128M] = &twpll_128m.hw, + [CLK_TWPLL_64M] = &twpll_64m.hw, + [CLK_TWPLL_307M2] = &twpll_307m2.hw, + [CLK_TWPLL_153M6] = &twpll_153m6.hw, + [CLK_TWPLL_76M8] = &twpll_76m8.hw, + [CLK_TWPLL_51M2] = &twpll_51m2.hw, + [CLK_TWPLL_38M4] = &twpll_38m4.hw, + [CLK_TWPLL_19M2] = &twpll_19m2.hw, + [CLK_L0_614M4] = &l0_614m4.hw, + [CLK_L0_409M6] = &l0_409m6.hw, + [CLK_L0_38M] = &l0_38m.hw, + [CLK_L1_38M] = &l1_38m.hw, + [CLK_RPLL0_192M] = &rpll0_192m.hw, + [CLK_RPLL0_96M] = &rpll0_96m.hw, + [CLK_RPLL0_48M] = &rpll0_48m.hw, + [CLK_RPLL1_468M] = &rpll1_468m.hw, + [CLK_RPLL1_192M] = &rpll1_192m.hw, + [CLK_RPLL1_96M] = &rpll1_96m.hw, + [CLK_RPLL1_64M] = &rpll1_64m.hw, + [CLK_RPLL1_48M] = &rpll1_48m.hw, + [CLK_DPLL0_50M] = &dpll0_50m.hw, + [CLK_DPLL1_50M] = &dpll1_50m.hw, + [CLK_CPPLL_50M] = &cppll_50m.hw, + [CLK_M0_39M] = &m0_39m.hw, + [CLK_M1_63M] = &m1_63m.hw, + }, + .num = CLK_PLL_NUM, +}; + +static const struct sprd_clk_desc sc9860_pll_desc = { + .clk_clks = sc9860_pll_clks, + .num_clk_clks = ARRAY_SIZE(sc9860_pll_clks), + .hw_clks = &sc9860_pll_hws, +}; + +#define SC9860_MUX_FLAG \ + (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_NO_REPARENT) + +static const char * const ap_apb_parents[] = { "ext-26m", "twpll-64m", + "twpll-96m", "twpll-128m" }; +static SPRD_MUX_CLK(ap_apb, "ap-apb", ap_apb_parents, + 0x20, 0, 1, SC9860_MUX_FLAG); + +static const char * const ap_apb_usb3[] = { "ext-32k", "twpll-24m" }; +static SPRD_MUX_CLK(ap_usb3, "ap-usb3", ap_apb_usb3, + 0x2c, 0, 1, SC9860_MUX_FLAG); + +static const char * const uart_parents[] = { "ext-26m", "twpll-48m", + "twpll-51m2", "twpll-96m" }; +static SPRD_COMP_CLK(uart0_clk, "uart0", uart_parents, 0x30, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK(uart1_clk, "uart1", uart_parents, 0x34, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK(uart2_clk, "uart2", uart_parents, 0x38, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK(uart3_clk, "uart3", uart_parents, 0x3c, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK(uart4_clk, "uart4", uart_parents, 0x40, + 0, 2, 8, 3, 0); + +static const char * const i2c_parents[] = { "ext-26m", "twpll-48m", + "twpll-51m2", "twpll-153m6" }; +static SPRD_COMP_CLK(i2c0_clk, "i2c0", i2c_parents, 0x44, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK(i2c1_clk, "i2c1", i2c_parents, 0x48, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK(i2c2_clk, "i2c2", i2c_parents, 0x4c, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK(i2c3_clk, "i2c3", i2c_parents, 0x50, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK(i2c4_clk, "i2c4", i2c_parents, 0x54, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK(i2c5_clk, "i2c5", i2c_parents, 0x58, + 0, 2, 8, 3, 0); + +static const char * const spi_parents[] = { "ext-26m", "twpll-128m", + "twpll-153m6", "twpll-192m" }; +static SPRD_COMP_CLK(spi0_clk, "spi0", spi_parents, 0x5c, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK(spi1_clk, "spi1", spi_parents, 0x60, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK(spi2_clk, "spi2", spi_parents, 0x64, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK(spi3_clk, "spi3", spi_parents, 0x68, + 0, 2, 8, 3, 0); + +static const char * const iis_parents[] = { "ext-26m", + "twpll-128m", + "twpll-153m6" }; +static SPRD_COMP_CLK(iis0_clk, "iis0", iis_parents, 0x6c, + 0, 2, 8, 6, 0); +static SPRD_COMP_CLK(iis1_clk, "iis1", iis_parents, 0x70, + 0, 2, 8, 6, 0); +static SPRD_COMP_CLK(iis2_clk, "iis2", iis_parents, 0x74, + 0, 2, 8, 6, 0); +static SPRD_COMP_CLK(iis3_clk, "iis3", iis_parents, 0x78, + 0, 2, 8, 6, 0); + +static struct sprd_clk_common *sc9860_ap_clks[] = { + /* address base is 0x20000000 */ + &ap_apb.common, + &ap_usb3.common, + &uart0_clk.common, + &uart1_clk.common, + &uart2_clk.common, + &uart3_clk.common, + &uart4_clk.common, + &i2c0_clk.common, + &i2c1_clk.common, + &i2c2_clk.common, + &i2c3_clk.common, + &i2c4_clk.common, + &i2c5_clk.common, + &spi0_clk.common, + &spi1_clk.common, + &spi2_clk.common, + &spi3_clk.common, + &iis0_clk.common, + &iis1_clk.common, + &iis2_clk.common, + &iis3_clk.common, +}; + +static struct clk_hw_onecell_data sc9860_ap_clk_hws = { + .hws = { + [CLK_AP_APB] = &ap_apb.common.hw, + [CLK_AP_USB3] = &ap_usb3.common.hw, + [CLK_UART0] = &uart0_clk.common.hw, + [CLK_UART1] = &uart1_clk.common.hw, + [CLK_UART2] = &uart2_clk.common.hw, + [CLK_UART3] = &uart3_clk.common.hw, + [CLK_UART4] = &uart4_clk.common.hw, + [CLK_I2C0] = &i2c0_clk.common.hw, + [CLK_I2C1] = &i2c1_clk.common.hw, + [CLK_I2C2] = &i2c2_clk.common.hw, + [CLK_I2C3] = &i2c3_clk.common.hw, + [CLK_I2C4] = &i2c4_clk.common.hw, + [CLK_I2C5] = &i2c5_clk.common.hw, + [CLK_SPI0] = &spi0_clk.common.hw, + [CLK_SPI1] = &spi1_clk.common.hw, + [CLK_SPI2] = &spi2_clk.common.hw, + [CLK_SPI3] = &spi3_clk.common.hw, + [CLK_IIS0] = &iis0_clk.common.hw, + [CLK_IIS1] = &iis1_clk.common.hw, + [CLK_IIS2] = &iis2_clk.common.hw, + [CLK_IIS3] = &iis3_clk.common.hw, + }, + .num = CLK_AP_CLK_NUM, +}; + +static const struct sprd_clk_desc sc9860_ap_clk_desc = { + .clk_clks = sc9860_ap_clks, + .num_clk_clks = ARRAY_SIZE(sc9860_ap_clks), + .hw_clks = &sc9860_ap_clk_hws, +}; + +static const char * const aon_apb_parents[] = { "rco-25m", "ext-26m", + "ext-rco-100m", "twpll-96m", + "twpll-128m", + "twpll-153m6" }; +static SPRD_COMP_CLK(aon_apb, "aon-apb", aon_apb_parents, 0x230, + 0, 3, 8, 2, 0); + +static const char * const aux_parents[] = { "ext-32k", "rpll0-26m", + "rpll1-26m", "ext-26m", + "cppll-50m", "rco-25m", + "dpll0-50m", "dpll1-50m", + "gpll-42m5", "twpll-48m", + "m0-39m", "m1-63m", + "l0-38m", "l1-38m" }; + +static SPRD_COMP_CLK(aux0_clk, "aux0", aux_parents, 0x238, + 0, 5, 8, 4, 0); +static SPRD_COMP_CLK(aux1_clk, "aux1", aux_parents, 0x23c, + 0, 5, 8, 4, 0); +static SPRD_COMP_CLK(aux2_clk, "aux2", aux_parents, 0x240, + 0, 5, 8, 4, 0); +static SPRD_COMP_CLK(probe_clk, "probe", aux_parents, 0x244, + 0, 5, 8, 4, 0); + +static const char * const sp_ahb_parents[] = { "rco-4m", "ext-26m", + "ext-rco-100m", "twpll-96m", + "twpll-128m", + "twpll-153m6" }; +static SPRD_COMP_CLK(sp_ahb, "sp-ahb", sp_ahb_parents, 0x2d0, + 0, 3, 8, 2, 0); + +static const char * const cci_parents[] = { "ext-26m", "twpll-384m", + "l0-614m4", "twpll-768m" }; +static SPRD_COMP_CLK(cci_clk, "cci", cci_parents, 0x300, + 0, 2, 8, 2, 0); +static SPRD_COMP_CLK(gic_clk, "gic", cci_parents, 0x304, + 0, 2, 8, 2, 0); +static SPRD_COMP_CLK(cssys_clk, "cssys", cci_parents, 0x310, + 0, 2, 8, 2, 0); + +static const char * const sdio_2x_parents[] = { "fac-1m", "ext-26m", + "twpll-307m2", "twpll-384m", + "l0-409m6" }; +static SPRD_COMP_CLK(sdio0_2x, "sdio0-2x", sdio_2x_parents, 0x328, + 0, 3, 8, 4, 0); +static SPRD_COMP_CLK(sdio1_2x, "sdio1-2x", sdio_2x_parents, 0x330, + 0, 3, 8, 4, 0); +static SPRD_COMP_CLK(sdio2_2x, "sdio2-2x", sdio_2x_parents, 0x338, + 0, 3, 8, 4, 0); +static SPRD_COMP_CLK(emmc_2x, "emmc-2x", sdio_2x_parents, 0x340, + 0, 3, 8, 4, 0); + +static SPRD_DIV_CLK(sdio0_1x, "sdio0-1x", "sdio0-2x", 0x32c, + 8, 1, 0); +static SPRD_DIV_CLK(sdio1_1x, "sdio1-1x", "sdio1-2x", 0x334, + 8, 1, 0); +static SPRD_DIV_CLK(sdio2_1x, "sdio2-1x", "sdio2-2x", 0x33c, + 8, 1, 0); +static SPRD_DIV_CLK(emmc_1x, "emmc-1x", "emmc-2x", 0x344, + 8, 1, 0); + +static const char * const adi_parents[] = { "rco-4m", "ext-26m", + "rco-25m", "twpll-38m4", + "twpll-51m2" }; +static SPRD_MUX_CLK(adi_clk, "adi", adi_parents, 0x234, + 0, 3, SC9860_MUX_FLAG); + +static const char * const pwm_parents[] = { "ext-32k", "ext-26m", + "rco-4m", "rco-25m", + "twpll-48m" }; +static SPRD_MUX_CLK(pwm0_clk, "pwm0", pwm_parents, 0x248, + 0, 3, SC9860_MUX_FLAG); +static SPRD_MUX_CLK(pwm1_clk, "pwm1", pwm_parents, 0x24c, + 0, 3, SC9860_MUX_FLAG); +static SPRD_MUX_CLK(pwm2_clk, "pwm2", pwm_parents, 0x250, + 0, 3, SC9860_MUX_FLAG); +static SPRD_MUX_CLK(pwm3_clk, "pwm3", pwm_parents, 0x254, + 0, 3, SC9860_MUX_FLAG); + +static const char * const efuse_parents[] = { "rco-25m", "ext-26m" }; +static SPRD_MUX_CLK(efuse_clk, "efuse", efuse_parents, 0x258, + 0, 1, SC9860_MUX_FLAG); + +static const char * const cm3_uart_parents[] = { "rco-4m", "ext-26m", + "rco-100m", "twpll-48m", + "twpll-51m2", "twpll-96m", + "twpll-128m" }; +static SPRD_MUX_CLK(cm3_uart0, "cm3-uart0", cm3_uart_parents, 0x25c, + 0, 3, SC9860_MUX_FLAG); +static SPRD_MUX_CLK(cm3_uart1, "cm3-uart1", cm3_uart_parents, 0x260, + 0, 3, SC9860_MUX_FLAG); + +static const char * const thm_parents[] = { "ext-32k", "fac-250k" }; +static SPRD_MUX_CLK(thm_clk, "thm", thm_parents, 0x270, + 0, 1, SC9860_MUX_FLAG); + +static const char * const cm3_i2c_parents[] = { "rco-4m", + "ext-26m", + "rco-100m", + "twpll-48m", + "twpll-51m2", + "twpll-153m6" }; +static SPRD_MUX_CLK(cm3_i2c0, "cm3-i2c0", cm3_i2c_parents, 0x274, + 0, 3, SC9860_MUX_FLAG); +static SPRD_MUX_CLK(cm3_i2c1, "cm3-i2c1", cm3_i2c_parents, 0x278, + 0, 3, SC9860_MUX_FLAG); +static SPRD_MUX_CLK(aon_i2c, "aon-i2c", cm3_i2c_parents, 0x280, + 0, 3, SC9860_MUX_FLAG); + +static const char * const cm4_spi_parents[] = { "ext-26m", "twpll-96m", + "rco-100m", "twpll-128m", + "twpll-153m6", "twpll-192m" }; +static SPRD_MUX_CLK(cm4_spi, "cm4-spi", cm4_spi_parents, 0x27c, + 0, 3, SC9860_MUX_FLAG); + +static SPRD_MUX_CLK(avs_clk, "avs", uart_parents, 0x284, + 0, 2, SC9860_MUX_FLAG); + +static const char * const ca53_dap_parents[] = { "ext-26m", "rco-4m", + "rco-100m", "twpll-76m8", + "twpll-128m", "twpll-153m6" }; +static SPRD_MUX_CLK(ca53_dap, "ca53-dap", ca53_dap_parents, 0x288, + 0, 3, SC9860_MUX_FLAG); + +static const char * const ca53_ts_parents[] = { "ext-32k", "ext-26m", + "clk-twpll-128m", + "clk-twpll-153m6" }; +static SPRD_MUX_CLK(ca53_ts, "ca53-ts", ca53_ts_parents, 0x290, + 0, 2, SC9860_MUX_FLAG); + +static const char * const djtag_tck_parents[] = { "rco-4m", "ext-26m" }; +static SPRD_MUX_CLK(djtag_tck, "djtag-tck", djtag_tck_parents, 0x2c8, + 0, 1, SC9860_MUX_FLAG); + +static const char * const pmu_parents[] = { "ext-32k", "rco-4m", "clk-4m" }; +static SPRD_MUX_CLK(pmu_clk, "pmu", pmu_parents, 0x2e0, + 0, 2, SC9860_MUX_FLAG); + +static const char * const pmu_26m_parents[] = { "rco-25m", "ext-26m" }; +static SPRD_MUX_CLK(pmu_26m, "pmu-26m", pmu_26m_parents, 0x2e4, + 0, 1, SC9860_MUX_FLAG); + +static const char * const debounce_parents[] = { "ext-32k", "rco-4m", + "rco-25m", "ext-26m" }; +static SPRD_MUX_CLK(debounce_clk, "debounce", debounce_parents, 0x2e8, + 0, 2, SC9860_MUX_FLAG); + +static const char * const otg2_ref_parents[] = { "twpll-12m", "twpll-24m" }; +static SPRD_MUX_CLK(otg2_ref, "otg2-ref", otg2_ref_parents, 0x2f4, + 0, 1, SC9860_MUX_FLAG); + +static const char * const usb3_ref_parents[] = { "twpll-24m", "twpll-19m2", + "twpll-48m" }; +static SPRD_MUX_CLK(usb3_ref, "usb3-ref", usb3_ref_parents, 0x2f8, + 0, 2, SC9860_MUX_FLAG); + +static const char * const ap_axi_parents[] = { "ext-26m", "twpll-76m8", + "twpll-128m", "twpll-256m" }; +static SPRD_MUX_CLK(ap_axi, "ap-axi", ap_axi_parents, 0x324, + 0, 2, SC9860_MUX_FLAG); + +static struct sprd_clk_common *sc9860_aon_prediv[] = { + /* address base is 0x402d0000 */ + &aon_apb.common, + &aux0_clk.common, + &aux1_clk.common, + &aux2_clk.common, + &probe_clk.common, + &sp_ahb.common, + &cci_clk.common, + &gic_clk.common, + &cssys_clk.common, + &sdio0_2x.common, + &sdio1_2x.common, + &sdio2_2x.common, + &emmc_2x.common, + &sdio0_1x.common, + &sdio1_1x.common, + &sdio2_1x.common, + &emmc_1x.common, + &adi_clk.common, + &pwm0_clk.common, + &pwm1_clk.common, + &pwm2_clk.common, + &pwm3_clk.common, + &efuse_clk.common, + &cm3_uart0.common, + &cm3_uart1.common, + &thm_clk.common, + &cm3_i2c0.common, + &cm3_i2c1.common, + &cm4_spi.common, + &aon_i2c.common, + &avs_clk.common, + &ca53_dap.common, + &ca53_ts.common, + &djtag_tck.common, + &pmu_clk.common, + &pmu_26m.common, + &debounce_clk.common, + &otg2_ref.common, + &usb3_ref.common, + &ap_axi.common, +}; + +static struct clk_hw_onecell_data sc9860_aon_prediv_hws = { + .hws = { + [CLK_AON_APB] = &aon_apb.common.hw, + [CLK_AUX0] = &aux0_clk.common.hw, + [CLK_AUX1] = &aux1_clk.common.hw, + [CLK_AUX2] = &aux2_clk.common.hw, + [CLK_PROBE] = &probe_clk.common.hw, + [CLK_SP_AHB] = &sp_ahb.common.hw, + [CLK_CCI] = &cci_clk.common.hw, + [CLK_GIC] = &gic_clk.common.hw, + [CLK_CSSYS] = &cssys_clk.common.hw, + [CLK_SDIO0_2X] = &sdio0_2x.common.hw, + [CLK_SDIO1_2X] = &sdio1_2x.common.hw, + [CLK_SDIO2_2X] = &sdio2_2x.common.hw, + [CLK_EMMC_2X] = &emmc_2x.common.hw, + [CLK_SDIO0_1X] = &sdio0_1x.common.hw, + [CLK_SDIO1_1X] = &sdio1_1x.common.hw, + [CLK_SDIO2_1X] = &sdio2_1x.common.hw, + [CLK_EMMC_1X] = &emmc_1x.common.hw, + [CLK_ADI] = &adi_clk.common.hw, + [CLK_PWM0] = &pwm0_clk.common.hw, + [CLK_PWM1] = &pwm1_clk.common.hw, + [CLK_PWM2] = &pwm2_clk.common.hw, + [CLK_PWM3] = &pwm3_clk.common.hw, + [CLK_EFUSE] = &efuse_clk.common.hw, + [CLK_CM3_UART0] = &cm3_uart0.common.hw, + [CLK_CM3_UART1] = &cm3_uart1.common.hw, + [CLK_THM] = &thm_clk.common.hw, + [CLK_CM3_I2C0] = &cm3_i2c0.common.hw, + [CLK_CM3_I2C1] = &cm3_i2c1.common.hw, + [CLK_CM4_SPI] = &cm4_spi.common.hw, + [CLK_AON_I2C] = &aon_i2c.common.hw, + [CLK_AVS] = &avs_clk.common.hw, + [CLK_CA53_DAP] = &ca53_dap.common.hw, + [CLK_CA53_TS] = &ca53_ts.common.hw, + [CLK_DJTAG_TCK] = &djtag_tck.common.hw, + [CLK_PMU] = &pmu_clk.common.hw, + [CLK_PMU_26M] = &pmu_26m.common.hw, + [CLK_DEBOUNCE] = &debounce_clk.common.hw, + [CLK_OTG2_REF] = &otg2_ref.common.hw, + [CLK_USB3_REF] = &usb3_ref.common.hw, + [CLK_AP_AXI] = &ap_axi.common.hw, + }, + .num = CLK_AON_PREDIV_NUM, +}; + +static const struct sprd_clk_desc sc9860_aon_prediv_desc = { + .clk_clks = sc9860_aon_prediv, + .num_clk_clks = ARRAY_SIZE(sc9860_aon_prediv), + .hw_clks = &sc9860_aon_prediv_hws, +}; + +static SPRD_SC_GATE_CLK(usb3_eb, "usb3-eb", "ap-axi", 0x0, + 0x1000, BIT(2), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(usb3_suspend, "usb3-suspend", "ap-axi", 0x0, + 0x1000, BIT(3), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(usb3_ref_eb, "usb3-ref-eb", "ap-axi", 0x0, + 0x1000, BIT(4), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(dma_eb, "dma-eb", "ap-axi", 0x0, + 0x1000, BIT(5), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(sdio0_eb, "sdio0-eb", "ap-axi", 0x0, + 0x1000, BIT(7), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(sdio1_eb, "sdio1-eb", "ap-axi", 0x0, + 0x1000, BIT(8), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(sdio2_eb, "sdio2-eb", "ap-axi", 0x0, + 0x1000, BIT(9), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(emmc_eb, "emmc-eb", "ap-axi", 0x0, + 0x1000, BIT(10), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(rom_eb, "rom-eb", "ap-axi", 0x0, + 0x1000, BIT(12), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(busmon_eb, "busmon-eb", "ap-axi", 0x0, + 0x1000, BIT(13), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(cc63s_eb, "cc63s-eb", "ap-axi", 0x0, + 0x1000, BIT(22), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(cc63p_eb, "cc63p-eb", "ap-axi", 0x0, + 0x1000, BIT(23), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ce0_eb, "ce0-eb", "ap-axi", 0x0, + 0x1000, BIT(24), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ce1_eb, "ce1-eb", "ap-axi", 0x0, + 0x1000, BIT(25), CLK_IGNORE_UNUSED, 0); + +static struct sprd_clk_common *sc9860_apahb_gate[] = { + /* address base is 0x20210000 */ + &usb3_eb.common, + &usb3_suspend.common, + &usb3_ref_eb.common, + &dma_eb.common, + &sdio0_eb.common, + &sdio1_eb.common, + &sdio2_eb.common, + &emmc_eb.common, + &rom_eb.common, + &busmon_eb.common, + &cc63s_eb.common, + &cc63p_eb.common, + &ce0_eb.common, + &ce1_eb.common, +}; + +static struct clk_hw_onecell_data sc9860_apahb_gate_hws = { + .hws = { + [CLK_USB3_EB] = &usb3_eb.common.hw, + [CLK_USB3_SUSPEND_EB] = &usb3_suspend.common.hw, + [CLK_USB3_REF_EB] = &usb3_ref_eb.common.hw, + [CLK_DMA_EB] = &dma_eb.common.hw, + [CLK_SDIO0_EB] = &sdio0_eb.common.hw, + [CLK_SDIO1_EB] = &sdio1_eb.common.hw, + [CLK_SDIO2_EB] = &sdio2_eb.common.hw, + [CLK_EMMC_EB] = &emmc_eb.common.hw, + [CLK_ROM_EB] = &rom_eb.common.hw, + [CLK_BUSMON_EB] = &busmon_eb.common.hw, + [CLK_CC63S_EB] = &cc63s_eb.common.hw, + [CLK_CC63P_EB] = &cc63p_eb.common.hw, + [CLK_CE0_EB] = &ce0_eb.common.hw, + [CLK_CE1_EB] = &ce1_eb.common.hw, + }, + .num = CLK_APAHB_GATE_NUM, +}; + +static const struct sprd_clk_desc sc9860_apahb_gate_desc = { + .clk_clks = sc9860_apahb_gate, + .num_clk_clks = ARRAY_SIZE(sc9860_apahb_gate), + .hw_clks = &sc9860_apahb_gate_hws, +}; + +static SPRD_SC_GATE_CLK(avs_lit_eb, "avs-lit-eb", "aon-apb", 0x0, + 0x1000, BIT(0), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(avs_big_eb, "avs-big-eb", "aon-apb", 0x0, + 0x1000, BIT(1), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_intc5_eb, "ap-intc5-eb", "aon-apb", 0x0, + 0x1000, BIT(2), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(gpio_eb, "gpio-eb", "aon-apb", 0x0, + 0x1000, BIT(3), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(pwm0_eb, "pwm0-eb", "aon-apb", 0x0, + 0x1000, BIT(4), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(pwm1_eb, "pwm1-eb", "aon-apb", 0x0, + 0x1000, BIT(5), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(pwm2_eb, "pwm2-eb", "aon-apb", 0x0, + 0x1000, BIT(6), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(pwm3_eb, "pwm3-eb", "aon-apb", 0x0, + 0x1000, BIT(7), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(kpd_eb, "kpd-eb", "aon-apb", 0x0, + 0x1000, BIT(8), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(aon_sys_eb, "aon-sys-eb", "aon-apb", 0x0, + 0x1000, BIT(9), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_sys_eb, "ap-sys-eb", "aon-apb", 0x0, + 0x1000, BIT(10), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(aon_tmr_eb, "aon-tmr-eb", "aon-apb", 0x0, + 0x1000, BIT(11), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_tmr0_eb, "ap-tmr0-eb", "aon-apb", 0x0, + 0x1000, BIT(12), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(efuse_eb, "efuse-eb", "aon-apb", 0x0, + 0x1000, BIT(13), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(eic_eb, "eic-eb", "aon-apb", 0x0, + 0x1000, BIT(14), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(pub1_reg_eb, "pub1-reg-eb", "aon-apb", 0x0, + 0x1000, BIT(15), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(adi_eb, "adi-eb", "aon-apb", 0x0, + 0x1000, BIT(16), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_intc0_eb, "ap-intc0-eb", "aon-apb", 0x0, + 0x1000, BIT(17), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_intc1_eb, "ap-intc1-eb", "aon-apb", 0x0, + 0x1000, BIT(18), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_intc2_eb, "ap-intc2-eb", "aon-apb", 0x0, + 0x1000, BIT(19), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_intc3_eb, "ap-intc3-eb", "aon-apb", 0x0, + 0x1000, BIT(20), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_intc4_eb, "ap-intc4-eb", "aon-apb", 0x0, + 0x1000, BIT(21), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(splk_eb, "splk-eb", "aon-apb", 0x0, + 0x1000, BIT(22), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(mspi_eb, "mspi-eb", "aon-apb", 0x0, + 0x1000, BIT(23), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(pub0_reg_eb, "pub0-reg-eb", "aon-apb", 0x0, + 0x1000, BIT(24), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(pin_eb, "pin-eb", "aon-apb", 0x0, + 0x1000, BIT(25), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(aon_ckg_eb, "aon-ckg-eb", "aon-apb", 0x0, + 0x1000, BIT(26), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(gpu_eb, "gpu-eb", "aon-apb", 0x0, + 0x1000, BIT(27), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(apcpu_ts0_eb, "apcpu-ts0-eb", "aon-apb", 0x0, + 0x1000, BIT(28), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(apcpu_ts1_eb, "apcpu-ts1-eb", "aon-apb", 0x0, + 0x1000, BIT(29), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(dap_eb, "dap-eb", "aon-apb", 0x0, + 0x1000, BIT(30), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(i2c_eb, "i2c-eb", "aon-apb", 0x0, + 0x1000, BIT(31), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(pmu_eb, "pmu-eb", "aon-apb", 0x4, + 0x1000, BIT(0), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(thm_eb, "thm-eb", "aon-apb", 0x4, + 0x1000, BIT(1), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(aux0_eb, "aux0-eb", "aon-apb", 0x4, + 0x1000, BIT(2), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(aux1_eb, "aux1-eb", "aon-apb", 0x4, + 0x1000, BIT(3), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(aux2_eb, "aux2-eb", "aon-apb", 0x4, + 0x1000, BIT(4), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(probe_eb, "probe-eb", "aon-apb", 0x4, + 0x1000, BIT(5), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(gpu0_avs_eb, "gpu0-avs-eb", "aon-apb", 0x4, + 0x1000, BIT(6), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(gpu1_avs_eb, "gpu1-avs-eb", "aon-apb", 0x4, + 0x1000, BIT(7), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(apcpu_wdg_eb, "apcpu-wdg-eb", "aon-apb", 0x4, + 0x1000, BIT(8), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_tmr1_eb, "ap-tmr1-eb", "aon-apb", 0x4, + 0x1000, BIT(9), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_tmr2_eb, "ap-tmr2-eb", "aon-apb", 0x4, + 0x1000, BIT(10), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(disp_emc_eb, "disp-emc-eb", "aon-apb", 0x4, + 0x1000, BIT(11), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(zip_emc_eb, "zip-emc-eb", "aon-apb", 0x4, + 0x1000, BIT(12), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(gsp_emc_eb, "gsp-emc-eb", "aon-apb", 0x4, + 0x1000, BIT(13), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(osc_aon_eb, "osc-aon-eb", "aon-apb", 0x4, + 0x1000, BIT(14), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(lvds_trx_eb, "lvds-trx-eb", "aon-apb", 0x4, + 0x1000, BIT(15), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(lvds_tcxo_eb, "lvds-tcxo-eb", "aon-apb", 0x4, + 0x1000, BIT(16), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(mdar_eb, "mdar-eb", "aon-apb", 0x4, + 0x1000, BIT(17), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(rtc4m0_cal_eb, "rtc4m0-cal-eb", "aon-apb", 0x4, + 0x1000, BIT(18), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(rct100m_cal_eb, "rct100m-cal-eb", "aon-apb", 0x4, + 0x1000, BIT(19), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(djtag_eb, "djtag-eb", "aon-apb", 0x4, + 0x1000, BIT(20), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(mbox_eb, "mbox-eb", "aon-apb", 0x4, + 0x1000, BIT(21), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(aon_dma_eb, "aon-dma-eb", "aon-apb", 0x4, + 0x1000, BIT(22), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(dbg_emc_eb, "dbg-emc-eb", "aon-apb", 0x4, + 0x1000, BIT(23), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(lvds_pll_div_en, "lvds-pll-div-en", "aon-apb", 0x4, + 0x1000, BIT(24), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(def_eb, "def-eb", "aon-apb", 0x4, + 0x1000, BIT(25), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(aon_apb_rsv0, "aon-apb-rsv0", "aon-apb", 0x4, + 0x1000, BIT(26), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(orp_jtag_eb, "orp-jtag-eb", "aon-apb", 0x4, + 0x1000, BIT(27), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(vsp_eb, "vsp-eb", "aon-apb", 0x4, + 0x1000, BIT(28), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(cam_eb, "cam-eb", "aon-apb", 0x4, + 0x1000, BIT(29), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(disp_eb, "disp-eb", "aon-apb", 0x4, + 0x1000, BIT(30), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(dbg_axi_if_eb, "dbg-axi-if-eb", "aon-apb", 0x4, + 0x1000, BIT(31), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(sdio0_2x_en, "sdio0-2x-en", "aon-apb", 0x13c, + 0x1000, BIT(2), 0, 0); +static SPRD_SC_GATE_CLK(sdio1_2x_en, "sdio1-2x-en", "aon-apb", 0x13c, + 0x1000, BIT(4), 0, 0); +static SPRD_SC_GATE_CLK(sdio2_2x_en, "sdio2-2x-en", "aon-apb", 0x13c, + 0x1000, BIT(6), 0, 0); +static SPRD_SC_GATE_CLK(emmc_2x_en, "emmc-2x-en", "aon-apb", 0x13c, + 0x1000, BIT(9), 0, 0); + +static struct sprd_clk_common *sc9860_aon_gate[] = { + /* address base is 0x402e0000 */ + &avs_lit_eb.common, + &avs_big_eb.common, + &ap_intc5_eb.common, + &gpio_eb.common, + &pwm0_eb.common, + &pwm1_eb.common, + &pwm2_eb.common, + &pwm3_eb.common, + &kpd_eb.common, + &aon_sys_eb.common, + &ap_sys_eb.common, + &aon_tmr_eb.common, + &ap_tmr0_eb.common, + &efuse_eb.common, + &eic_eb.common, + &pub1_reg_eb.common, + &adi_eb.common, + &ap_intc0_eb.common, + &ap_intc1_eb.common, + &ap_intc2_eb.common, + &ap_intc3_eb.common, + &ap_intc4_eb.common, + &splk_eb.common, + &mspi_eb.common, + &pub0_reg_eb.common, + &pin_eb.common, + &aon_ckg_eb.common, + &gpu_eb.common, + &apcpu_ts0_eb.common, + &apcpu_ts1_eb.common, + &dap_eb.common, + &i2c_eb.common, + &pmu_eb.common, + &thm_eb.common, + &aux0_eb.common, + &aux1_eb.common, + &aux2_eb.common, + &probe_eb.common, + &gpu0_avs_eb.common, + &gpu1_avs_eb.common, + &apcpu_wdg_eb.common, + &ap_tmr1_eb.common, + &ap_tmr2_eb.common, + &disp_emc_eb.common, + &zip_emc_eb.common, + &gsp_emc_eb.common, + &osc_aon_eb.common, + &lvds_trx_eb.common, + &lvds_tcxo_eb.common, + &mdar_eb.common, + &rtc4m0_cal_eb.common, + &rct100m_cal_eb.common, + &djtag_eb.common, + &mbox_eb.common, + &aon_dma_eb.common, + &dbg_emc_eb.common, + &lvds_pll_div_en.common, + &def_eb.common, + &aon_apb_rsv0.common, + &orp_jtag_eb.common, + &vsp_eb.common, + &cam_eb.common, + &disp_eb.common, + &dbg_axi_if_eb.common, + &sdio0_2x_en.common, + &sdio1_2x_en.common, + &sdio2_2x_en.common, + &emmc_2x_en.common, +}; + +static struct clk_hw_onecell_data sc9860_aon_gate_hws = { + .hws = { + [CLK_AVS_LIT_EB] = &avs_lit_eb.common.hw, + [CLK_AVS_BIG_EB] = &avs_big_eb.common.hw, + [CLK_AP_INTC5_EB] = &ap_intc5_eb.common.hw, + [CLK_GPIO_EB] = &gpio_eb.common.hw, + [CLK_PWM0_EB] = &pwm0_eb.common.hw, + [CLK_PWM1_EB] = &pwm1_eb.common.hw, + [CLK_PWM2_EB] = &pwm2_eb.common.hw, + [CLK_PWM3_EB] = &pwm3_eb.common.hw, + [CLK_KPD_EB] = &kpd_eb.common.hw, + [CLK_AON_SYS_EB] = &aon_sys_eb.common.hw, + [CLK_AP_SYS_EB] = &ap_sys_eb.common.hw, + [CLK_AON_TMR_EB] = &aon_tmr_eb.common.hw, + [CLK_AP_TMR0_EB] = &ap_tmr0_eb.common.hw, + [CLK_EFUSE_EB] = &efuse_eb.common.hw, + [CLK_EIC_EB] = &eic_eb.common.hw, + [CLK_PUB1_REG_EB] = &pub1_reg_eb.common.hw, + [CLK_ADI_EB] = &adi_eb.common.hw, + [CLK_AP_INTC0_EB] = &ap_intc0_eb.common.hw, + [CLK_AP_INTC1_EB] = &ap_intc1_eb.common.hw, + [CLK_AP_INTC2_EB] = &ap_intc2_eb.common.hw, + [CLK_AP_INTC3_EB] = &ap_intc3_eb.common.hw, + [CLK_AP_INTC4_EB] = &ap_intc4_eb.common.hw, + [CLK_SPLK_EB] = &splk_eb.common.hw, + [CLK_MSPI_EB] = &mspi_eb.common.hw, + [CLK_PUB0_REG_EB] = &pub0_reg_eb.common.hw, + [CLK_PIN_EB] = &pin_eb.common.hw, + [CLK_AON_CKG_EB] = &aon_ckg_eb.common.hw, + [CLK_GPU_EB] = &gpu_eb.common.hw, + [CLK_APCPU_TS0_EB] = &apcpu_ts0_eb.common.hw, + [CLK_APCPU_TS1_EB] = &apcpu_ts1_eb.common.hw, + [CLK_DAP_EB] = &dap_eb.common.hw, + [CLK_I2C_EB] = &i2c_eb.common.hw, + [CLK_PMU_EB] = &pmu_eb.common.hw, + [CLK_THM_EB] = &thm_eb.common.hw, + [CLK_AUX0_EB] = &aux0_eb.common.hw, + [CLK_AUX1_EB] = &aux1_eb.common.hw, + [CLK_AUX2_EB] = &aux2_eb.common.hw, + [CLK_PROBE_EB] = &probe_eb.common.hw, + [CLK_GPU0_AVS_EB] = &gpu0_avs_eb.common.hw, + [CLK_GPU1_AVS_EB] = &gpu1_avs_eb.common.hw, + [CLK_APCPU_WDG_EB] = &apcpu_wdg_eb.common.hw, + [CLK_AP_TMR1_EB] = &ap_tmr1_eb.common.hw, + [CLK_AP_TMR2_EB] = &ap_tmr2_eb.common.hw, + [CLK_DISP_EMC_EB] = &disp_emc_eb.common.hw, + [CLK_ZIP_EMC_EB] = &zip_emc_eb.common.hw, + [CLK_GSP_EMC_EB] = &gsp_emc_eb.common.hw, + [CLK_OSC_AON_EB] = &osc_aon_eb.common.hw, + [CLK_LVDS_TRX_EB] = &lvds_trx_eb.common.hw, + [CLK_LVDS_TCXO_EB] = &lvds_tcxo_eb.common.hw, + [CLK_MDAR_EB] = &mdar_eb.common.hw, + [CLK_RTC4M0_CAL_EB] = &rtc4m0_cal_eb.common.hw, + [CLK_RCT100M_CAL_EB] = &rct100m_cal_eb.common.hw, + [CLK_DJTAG_EB] = &djtag_eb.common.hw, + [CLK_MBOX_EB] = &mbox_eb.common.hw, + [CLK_AON_DMA_EB] = &aon_dma_eb.common.hw, + [CLK_DBG_EMC_EB] = &dbg_emc_eb.common.hw, + [CLK_LVDS_PLL_DIV_EN] = &lvds_pll_div_en.common.hw, + [CLK_DEF_EB] = &def_eb.common.hw, + [CLK_AON_APB_RSV0] = &aon_apb_rsv0.common.hw, + [CLK_ORP_JTAG_EB] = &orp_jtag_eb.common.hw, + [CLK_VSP_EB] = &vsp_eb.common.hw, + [CLK_CAM_EB] = &cam_eb.common.hw, + [CLK_DISP_EB] = &disp_eb.common.hw, + [CLK_DBG_AXI_IF_EB] = &dbg_axi_if_eb.common.hw, + [CLK_SDIO0_2X_EN] = &sdio0_2x_en.common.hw, + [CLK_SDIO1_2X_EN] = &sdio1_2x_en.common.hw, + [CLK_SDIO2_2X_EN] = &sdio2_2x_en.common.hw, + [CLK_EMMC_2X_EN] = &emmc_2x_en.common.hw, + }, + .num = CLK_AON_GATE_NUM, +}; + +static const struct sprd_clk_desc sc9860_aon_gate_desc = { + .clk_clks = sc9860_aon_gate, + .num_clk_clks = ARRAY_SIZE(sc9860_aon_gate), + .hw_clks = &sc9860_aon_gate_hws, +}; + +static const u8 mcu_table[] = { 0, 1, 2, 3, 4, 8 }; +static const char * const lit_mcu_parents[] = { "ext-26m", "twpll-512m", + "twpll-768m", "ltepll0", + "twpll", "mpll0" }; +static SPRD_COMP_CLK_TABLE(lit_mcu, "lit-mcu", lit_mcu_parents, 0x20, + mcu_table, 0, 4, 4, 3, 0); + +static const char * const big_mcu_parents[] = { "ext-26m", "twpll-512m", + "twpll-768m", "ltepll0", + "twpll", "mpll1" }; +static SPRD_COMP_CLK_TABLE(big_mcu, "big-mcu", big_mcu_parents, 0x24, + mcu_table, 0, 4, 4, 3, 0); + +static struct sprd_clk_common *sc9860_aonsecure_clk[] = { + /* address base is 0x40880000 */ + &lit_mcu.common, + &big_mcu.common, +}; + +static struct clk_hw_onecell_data sc9860_aonsecure_clk_hws = { + .hws = { + [CLK_LIT_MCU] = &lit_mcu.common.hw, + [CLK_BIG_MCU] = &big_mcu.common.hw, + }, + .num = CLK_AONSECURE_NUM, +}; + +static const struct sprd_clk_desc sc9860_aonsecure_clk_desc = { + .clk_clks = sc9860_aonsecure_clk, + .num_clk_clks = ARRAY_SIZE(sc9860_aonsecure_clk), + .hw_clks = &sc9860_aonsecure_clk_hws, +}; + +static SPRD_SC_GATE_CLK(agcp_iis0_eb, "agcp-iis0-eb", "aon-apb", + 0x0, 0x100, BIT(0), 0, 0); +static SPRD_SC_GATE_CLK(agcp_iis1_eb, "agcp-iis1-eb", "aon-apb", + 0x0, 0x100, BIT(1), 0, 0); +static SPRD_SC_GATE_CLK(agcp_iis2_eb, "agcp-iis2-eb", "aon-apb", + 0x0, 0x100, BIT(2), 0, 0); +static SPRD_SC_GATE_CLK(agcp_iis3_eb, "agcp-iis3-eb", "aon-apb", + 0x0, 0x100, BIT(3), 0, 0); +static SPRD_SC_GATE_CLK(agcp_uart_eb, "agcp-uart-eb", "aon-apb", + 0x0, 0x100, BIT(4), 0, 0); +static SPRD_SC_GATE_CLK(agcp_dmacp_eb, "agcp-dmacp-eb", "aon-apb", + 0x0, 0x100, BIT(5), 0, 0); +static SPRD_SC_GATE_CLK(agcp_dmaap_eb, "agcp-dmaap-eb", "aon-apb", + 0x0, 0x100, BIT(6), 0, 0); +static SPRD_SC_GATE_CLK(agcp_arc48k_eb, "agcp-arc48k-eb", "aon-apb", + 0x0, 0x100, BIT(10), 0, 0); +static SPRD_SC_GATE_CLK(agcp_src44p1k_eb, "agcp-src44p1k-eb", "aon-apb", + 0x0, 0x100, BIT(11), 0, 0); +static SPRD_SC_GATE_CLK(agcp_mcdt_eb, "agcp-mcdt-eb", "aon-apb", + 0x0, 0x100, BIT(12), 0, 0); +static SPRD_SC_GATE_CLK(agcp_vbcifd_eb, "agcp-vbcifd-eb", "aon-apb", + 0x0, 0x100, BIT(13), 0, 0); +static SPRD_SC_GATE_CLK(agcp_vbc_eb, "agcp-vbc-eb", "aon-apb", + 0x0, 0x100, BIT(14), 0, 0); +static SPRD_SC_GATE_CLK(agcp_spinlock_eb, "agcp-spinlock-eb", "aon-apb", + 0x0, 0x100, BIT(15), 0, 0); +static SPRD_SC_GATE_CLK(agcp_icu_eb, "agcp-icu-eb", "aon-apb", + 0x0, 0x100, BIT(16), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(agcp_ap_ashb_eb, "agcp-ap-ashb-eb", "aon-apb", + 0x0, 0x100, BIT(17), 0, 0); +static SPRD_SC_GATE_CLK(agcp_cp_ashb_eb, "agcp-cp-ashb-eb", "aon-apb", + 0x0, 0x100, BIT(18), 0, 0); +static SPRD_SC_GATE_CLK(agcp_aud_eb, "agcp-aud-eb", "aon-apb", + 0x0, 0x100, BIT(19), 0, 0); +static SPRD_SC_GATE_CLK(agcp_audif_eb, "agcp-audif-eb", "aon-apb", + 0x0, 0x100, BIT(20), 0, 0); + +static struct sprd_clk_common *sc9860_agcp_gate[] = { + /* address base is 0x415e0000 */ + &agcp_iis0_eb.common, + &agcp_iis1_eb.common, + &agcp_iis2_eb.common, + &agcp_iis3_eb.common, + &agcp_uart_eb.common, + &agcp_dmacp_eb.common, + &agcp_dmaap_eb.common, + &agcp_arc48k_eb.common, + &agcp_src44p1k_eb.common, + &agcp_mcdt_eb.common, + &agcp_vbcifd_eb.common, + &agcp_vbc_eb.common, + &agcp_spinlock_eb.common, + &agcp_icu_eb.common, + &agcp_ap_ashb_eb.common, + &agcp_cp_ashb_eb.common, + &agcp_aud_eb.common, + &agcp_audif_eb.common, +}; + +static struct clk_hw_onecell_data sc9860_agcp_gate_hws = { + .hws = { + [CLK_AGCP_IIS0_EB] = &agcp_iis0_eb.common.hw, + [CLK_AGCP_IIS1_EB] = &agcp_iis1_eb.common.hw, + [CLK_AGCP_IIS2_EB] = &agcp_iis2_eb.common.hw, + [CLK_AGCP_IIS3_EB] = &agcp_iis3_eb.common.hw, + [CLK_AGCP_UART_EB] = &agcp_uart_eb.common.hw, + [CLK_AGCP_DMACP_EB] = &agcp_dmacp_eb.common.hw, + [CLK_AGCP_DMAAP_EB] = &agcp_dmaap_eb.common.hw, + [CLK_AGCP_ARC48K_EB] = &agcp_arc48k_eb.common.hw, + [CLK_AGCP_SRC44P1K_EB] = &agcp_src44p1k_eb.common.hw, + [CLK_AGCP_MCDT_EB] = &agcp_mcdt_eb.common.hw, + [CLK_AGCP_VBCIFD_EB] = &agcp_vbcifd_eb.common.hw, + [CLK_AGCP_VBC_EB] = &agcp_vbc_eb.common.hw, + [CLK_AGCP_SPINLOCK_EB] = &agcp_spinlock_eb.common.hw, + [CLK_AGCP_ICU_EB] = &agcp_icu_eb.common.hw, + [CLK_AGCP_AP_ASHB_EB] = &agcp_ap_ashb_eb.common.hw, + [CLK_AGCP_CP_ASHB_EB] = &agcp_cp_ashb_eb.common.hw, + [CLK_AGCP_AUD_EB] = &agcp_aud_eb.common.hw, + [CLK_AGCP_AUDIF_EB] = &agcp_audif_eb.common.hw, + }, + .num = CLK_AGCP_GATE_NUM, +}; + +static const struct sprd_clk_desc sc9860_agcp_gate_desc = { + .clk_clks = sc9860_agcp_gate, + .num_clk_clks = ARRAY_SIZE(sc9860_agcp_gate), + .hw_clks = &sc9860_agcp_gate_hws, +}; + +static const char * const gpu_parents[] = { "twpll-512m", + "twpll-768m", + "gpll" }; +static SPRD_COMP_CLK(gpu_clk, "gpu", gpu_parents, 0x20, + 0, 2, 8, 4, 0); + +static struct sprd_clk_common *sc9860_gpu_clk[] = { + /* address base is 0x60200000 */ + &gpu_clk.common, +}; + +static struct clk_hw_onecell_data sc9860_gpu_clk_hws = { + .hws = { + [CLK_GPU] = &gpu_clk.common.hw, + }, + .num = CLK_GPU_NUM, +}; + +static const struct sprd_clk_desc sc9860_gpu_clk_desc = { + .clk_clks = sc9860_gpu_clk, + .num_clk_clks = ARRAY_SIZE(sc9860_gpu_clk), + .hw_clks = &sc9860_gpu_clk_hws, +}; + +static const char * const ahb_parents[] = { "ext-26m", "twpll-96m", + "twpll-128m", "twpll-153m6" }; +static SPRD_MUX_CLK(ahb_vsp, "ahb-vsp", ahb_parents, 0x20, + 0, 2, SC9860_MUX_FLAG); + +static const char * const vsp_parents[] = { "twpll-76m8", "twpll-128m", + "twpll-256m", "twpll-307m2", + "twpll-384m" }; +static SPRD_COMP_CLK(vsp_clk, "vsp", vsp_parents, 0x24, 0, 3, 8, 2, 0); + +static const char * const dispc_parents[] = { "twpll-76m8", "twpll-128m", + "twpll-256m", "twpll-307m2" }; +static SPRD_COMP_CLK(vsp_enc, "vsp-enc", dispc_parents, 0x28, 0, 2, 8, 2, 0); + +static const char * const vpp_parents[] = { "twpll-96m", "twpll-153m6", + "twpll-192m", "twpll-256m" }; +static SPRD_MUX_CLK(vpp_clk, "vpp", vpp_parents, 0x2c, + 0, 2, SC9860_MUX_FLAG); +static const char * const vsp_26m_parents[] = { "ext-26m" }; +static SPRD_MUX_CLK(vsp_26m, "vsp-26m", vsp_26m_parents, 0x30, + 0, 1, SC9860_MUX_FLAG); + +static struct sprd_clk_common *sc9860_vsp_clk[] = { + /* address base is 0x61000000 */ + &ahb_vsp.common, + &vsp_clk.common, + &vsp_enc.common, + &vpp_clk.common, + &vsp_26m.common, +}; + +static struct clk_hw_onecell_data sc9860_vsp_clk_hws = { + .hws = { + [CLK_AHB_VSP] = &ahb_vsp.common.hw, + [CLK_VSP] = &vsp_clk.common.hw, + [CLK_VSP_ENC] = &vsp_enc.common.hw, + [CLK_VPP] = &vpp_clk.common.hw, + [CLK_VSP_26M] = &vsp_26m.common.hw, + }, + .num = CLK_VSP_NUM, +}; + +static const struct sprd_clk_desc sc9860_vsp_clk_desc = { + .clk_clks = sc9860_vsp_clk, + .num_clk_clks = ARRAY_SIZE(sc9860_vsp_clk), + .hw_clks = &sc9860_vsp_clk_hws, +}; + +static SPRD_SC_GATE_CLK(vsp_dec_eb, "vsp-dec-eb", "ahb-vsp", 0x0, + 0x1000, BIT(0), 0, 0); +static SPRD_SC_GATE_CLK(vsp_ckg_eb, "vsp-ckg-eb", "ahb-vsp", 0x0, + 0x1000, BIT(1), 0, 0); +static SPRD_SC_GATE_CLK(vsp_mmu_eb, "vsp-mmu-eb", "ahb-vsp", 0x0, + 0x1000, BIT(2), 0, 0); +static SPRD_SC_GATE_CLK(vsp_enc_eb, "vsp-enc-eb", "ahb-vsp", 0x0, + 0x1000, BIT(3), 0, 0); +static SPRD_SC_GATE_CLK(vpp_eb, "vpp-eb", "ahb-vsp", 0x0, + 0x1000, BIT(4), 0, 0); +static SPRD_SC_GATE_CLK(vsp_26m_eb, "vsp-26m-eb", "ahb-vsp", 0x0, + 0x1000, BIT(5), 0, 0); +static SPRD_GATE_CLK(vsp_axi_gate, "vsp-axi-gate", "ahb-vsp", 0x8, + BIT(0), 0, 0); +static SPRD_GATE_CLK(vsp_enc_gate, "vsp-enc-gate", "ahb-vsp", 0x8, + BIT(1), 0, 0); +static SPRD_GATE_CLK(vpp_axi_gate, "vpp-axi-gate", "ahb-vsp", 0x8, + BIT(2), 0, 0); +static SPRD_GATE_CLK(vsp_bm_gate, "vsp-bm-gate", "ahb-vsp", 0x8, + BIT(8), 0, 0); +static SPRD_GATE_CLK(vsp_enc_bm_gate, "vsp-enc-bm-gate", "ahb-vsp", 0x8, + BIT(9), 0, 0); +static SPRD_GATE_CLK(vpp_bm_gate, "vpp-bm-gate", "ahb-vsp", 0x8, + BIT(10), 0, 0); + +static struct sprd_clk_common *sc9860_vsp_gate[] = { + /* address base is 0x61100000 */ + &vsp_dec_eb.common, + &vsp_ckg_eb.common, + &vsp_mmu_eb.common, + &vsp_enc_eb.common, + &vpp_eb.common, + &vsp_26m_eb.common, + &vsp_axi_gate.common, + &vsp_enc_gate.common, + &vpp_axi_gate.common, + &vsp_bm_gate.common, + &vsp_enc_bm_gate.common, + &vpp_bm_gate.common, +}; + +static struct clk_hw_onecell_data sc9860_vsp_gate_hws = { + .hws = { + [CLK_VSP_DEC_EB] = &vsp_dec_eb.common.hw, + [CLK_VSP_CKG_EB] = &vsp_ckg_eb.common.hw, + [CLK_VSP_MMU_EB] = &vsp_mmu_eb.common.hw, + [CLK_VSP_ENC_EB] = &vsp_enc_eb.common.hw, + [CLK_VPP_EB] = &vpp_eb.common.hw, + [CLK_VSP_26M_EB] = &vsp_26m_eb.common.hw, + [CLK_VSP_AXI_GATE] = &vsp_axi_gate.common.hw, + [CLK_VSP_ENC_GATE] = &vsp_enc_gate.common.hw, + [CLK_VPP_AXI_GATE] = &vpp_axi_gate.common.hw, + [CLK_VSP_BM_GATE] = &vsp_bm_gate.common.hw, + [CLK_VSP_ENC_BM_GATE] = &vsp_enc_bm_gate.common.hw, + [CLK_VPP_BM_GATE] = &vpp_bm_gate.common.hw, + }, + .num = CLK_VSP_GATE_NUM, +}; + +static const struct sprd_clk_desc sc9860_vsp_gate_desc = { + .clk_clks = sc9860_vsp_gate, + .num_clk_clks = ARRAY_SIZE(sc9860_vsp_gate), + .hw_clks = &sc9860_vsp_gate_hws, +}; + +static SPRD_MUX_CLK(ahb_cam, "ahb-cam", ahb_parents, 0x20, + 0, 2, SC9860_MUX_FLAG); +static const char * const sensor_parents[] = { "ext-26m", "twpll-48m", + "twpll-76m8", "twpll-96m" }; +static SPRD_COMP_CLK(sensor0_clk, "sensor0", sensor_parents, 0x24, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK(sensor1_clk, "sensor1", sensor_parents, 0x28, + 0, 2, 8, 3, 0); +static SPRD_COMP_CLK(sensor2_clk, "sensor2", sensor_parents, 0x2c, + 0, 2, 8, 3, 0); +static SPRD_GATE_CLK(mipi_csi0_eb, "mipi-csi0-eb", "ahb-cam", 0x4c, + BIT(16), 0, 0); +static SPRD_GATE_CLK(mipi_csi1_eb, "mipi-csi1-eb", "ahb-cam", 0x50, + BIT(16), 0, 0); + +static struct sprd_clk_common *sc9860_cam_clk[] = { + /* address base is 0x62000000 */ + &ahb_cam.common, + &sensor0_clk.common, + &sensor1_clk.common, + &sensor2_clk.common, + &mipi_csi0_eb.common, + &mipi_csi1_eb.common, +}; + +static struct clk_hw_onecell_data sc9860_cam_clk_hws = { + .hws = { + [CLK_AHB_CAM] = &ahb_cam.common.hw, + [CLK_SENSOR0] = &sensor0_clk.common.hw, + [CLK_SENSOR1] = &sensor1_clk.common.hw, + [CLK_SENSOR2] = &sensor2_clk.common.hw, + [CLK_MIPI_CSI0_EB] = &mipi_csi0_eb.common.hw, + [CLK_MIPI_CSI1_EB] = &mipi_csi1_eb.common.hw, + }, + .num = CLK_CAM_NUM, +}; + +static const struct sprd_clk_desc sc9860_cam_clk_desc = { + .clk_clks = sc9860_cam_clk, + .num_clk_clks = ARRAY_SIZE(sc9860_cam_clk), + .hw_clks = &sc9860_cam_clk_hws, +}; + +static SPRD_SC_GATE_CLK(dcam0_eb, "dcam0-eb", "ahb-cam", 0x0, + 0x1000, BIT(0), 0, 0); +static SPRD_SC_GATE_CLK(dcam1_eb, "dcam1-eb", "ahb-cam", 0x0, + 0x1000, BIT(1), 0, 0); +static SPRD_SC_GATE_CLK(isp0_eb, "isp0-eb", "ahb-cam", 0x0, + 0x1000, BIT(2), 0, 0); +static SPRD_SC_GATE_CLK(csi0_eb, "csi0-eb", "ahb-cam", 0x0, + 0x1000, BIT(3), 0, 0); +static SPRD_SC_GATE_CLK(csi1_eb, "csi1-eb", "ahb-cam", 0x0, + 0x1000, BIT(4), 0, 0); +static SPRD_SC_GATE_CLK(jpg0_eb, "jpg0-eb", "ahb-cam", 0x0, + 0x1000, BIT(5), 0, 0); +static SPRD_SC_GATE_CLK(jpg1_eb, "jpg1-eb", "ahb-cam", 0x0, + 0x1000, BIT(6), 0, 0); +static SPRD_SC_GATE_CLK(cam_ckg_eb, "cam-ckg-eb", "ahb-cam", 0x0, + 0x1000, BIT(7), 0, 0); +static SPRD_SC_GATE_CLK(cam_mmu_eb, "cam-mmu-eb", "ahb-cam", 0x0, + 0x1000, BIT(8), 0, 0); +static SPRD_SC_GATE_CLK(isp1_eb, "isp1-eb", "ahb-cam", 0x0, + 0x1000, BIT(9), 0, 0); +static SPRD_SC_GATE_CLK(cpp_eb, "cpp-eb", "ahb-cam", 0x0, + 0x1000, BIT(10), 0, 0); +static SPRD_SC_GATE_CLK(mmu_pf_eb, "mmu-pf-eb", "ahb-cam", 0x0, + 0x1000, BIT(11), 0, 0); +static SPRD_SC_GATE_CLK(isp2_eb, "isp2-eb", "ahb-cam", 0x0, + 0x1000, BIT(12), 0, 0); +static SPRD_SC_GATE_CLK(dcam2isp_if_eb, "dcam2isp-if-eb", "ahb-cam", 0x0, + 0x1000, BIT(13), 0, 0); +static SPRD_SC_GATE_CLK(isp2dcam_if_eb, "isp2dcam-if-eb", "ahb-cam", 0x0, + 0x1000, BIT(14), 0, 0); +static SPRD_SC_GATE_CLK(isp_lclk_eb, "isp-lclk-eb", "ahb-cam", 0x0, + 0x1000, BIT(15), 0, 0); +static SPRD_SC_GATE_CLK(isp_iclk_eb, "isp-iclk-eb", "ahb-cam", 0x0, + 0x1000, BIT(16), 0, 0); +static SPRD_SC_GATE_CLK(isp_mclk_eb, "isp-mclk-eb", "ahb-cam", 0x0, + 0x1000, BIT(17), 0, 0); +static SPRD_SC_GATE_CLK(isp_pclk_eb, "isp-pclk-eb", "ahb-cam", 0x0, + 0x1000, BIT(18), 0, 0); +static SPRD_SC_GATE_CLK(isp_isp2dcam_eb, "isp-isp2dcam-eb", "ahb-cam", 0x0, + 0x1000, BIT(19), 0, 0); +static SPRD_SC_GATE_CLK(dcam0_if_eb, "dcam0-if-eb", "ahb-cam", 0x0, + 0x1000, BIT(20), 0, 0); +static SPRD_SC_GATE_CLK(clk26m_if_eb, "clk26m-if-eb", "ahb-cam", 0x0, + 0x1000, BIT(21), 0, 0); +static SPRD_GATE_CLK(cphy0_gate, "cphy0-gate", "ahb-cam", 0x8, + BIT(0), 0, 0); +static SPRD_GATE_CLK(mipi_csi0_gate, "mipi-csi0-gate", "ahb-cam", 0x8, + BIT(1), 0, 0); +static SPRD_GATE_CLK(cphy1_gate, "cphy1-gate", "ahb-cam", 0x8, + BIT(2), 0, 0); +static SPRD_GATE_CLK(mipi_csi1, "mipi-csi1", "ahb-cam", 0x8, + BIT(3), 0, 0); +static SPRD_GATE_CLK(dcam0_axi_gate, "dcam0-axi-gate", "ahb-cam", 0x8, + BIT(4), 0, 0); +static SPRD_GATE_CLK(dcam1_axi_gate, "dcam1-axi-gate", "ahb-cam", 0x8, + BIT(5), 0, 0); +static SPRD_GATE_CLK(sensor0_gate, "sensor0-gate", "ahb-cam", 0x8, + BIT(6), 0, 0); +static SPRD_GATE_CLK(sensor1_gate, "sensor1-gate", "ahb-cam", 0x8, + BIT(7), 0, 0); +static SPRD_GATE_CLK(jpg0_axi_gate, "jpg0-axi-gate", "ahb-cam", 0x8, + BIT(8), 0, 0); +static SPRD_GATE_CLK(gpg1_axi_gate, "gpg1-axi-gate", "ahb-cam", 0x8, + BIT(9), 0, 0); +static SPRD_GATE_CLK(isp0_axi_gate, "isp0-axi-gate", "ahb-cam", 0x8, + BIT(10), 0, 0); +static SPRD_GATE_CLK(isp1_axi_gate, "isp1-axi-gate", "ahb-cam", 0x8, + BIT(11), 0, 0); +static SPRD_GATE_CLK(isp2_axi_gate, "isp2-axi-gate", "ahb-cam", 0x8, + BIT(12), 0, 0); +static SPRD_GATE_CLK(cpp_axi_gate, "cpp-axi-gate", "ahb-cam", 0x8, + BIT(13), 0, 0); +static SPRD_GATE_CLK(d0_if_axi_gate, "d0-if-axi-gate", "ahb-cam", 0x8, + BIT(14), 0, 0); +static SPRD_GATE_CLK(d2i_if_axi_gate, "d2i-if-axi-gate", "ahb-cam", 0x8, + BIT(15), 0, 0); +static SPRD_GATE_CLK(i2d_if_axi_gate, "i2d-if-axi-gate", "ahb-cam", 0x8, + BIT(16), 0, 0); +static SPRD_GATE_CLK(spare_axi_gate, "spare-axi-gate", "ahb-cam", 0x8, + BIT(17), 0, 0); +static SPRD_GATE_CLK(sensor2_gate, "sensor2-gate", "ahb-cam", 0x8, + BIT(18), 0, 0); +static SPRD_SC_GATE_CLK(d0if_in_d_en, "d0if-in-d-en", "ahb-cam", 0x28, + 0x1000, BIT(0), 0, 0); +static SPRD_SC_GATE_CLK(d1if_in_d_en, "d1if-in-d-en", "ahb-cam", 0x28, + 0x1000, BIT(1), 0, 0); +static SPRD_SC_GATE_CLK(d0if_in_d2i_en, "d0if-in-d2i-en", "ahb-cam", 0x28, + 0x1000, BIT(2), 0, 0); +static SPRD_SC_GATE_CLK(d1if_in_d2i_en, "d1if-in-d2i-en", "ahb-cam", 0x28, + 0x1000, BIT(3), 0, 0); +static SPRD_SC_GATE_CLK(ia_in_d2i_en, "ia-in-d2i-en", "ahb-cam", 0x28, + 0x1000, BIT(4), 0, 0); +static SPRD_SC_GATE_CLK(ib_in_d2i_en, "ib-in-d2i-en", "ahb-cam", 0x28, + 0x1000, BIT(5), 0, 0); +static SPRD_SC_GATE_CLK(ic_in_d2i_en, "ic-in-d2i-en", "ahb-cam", 0x28, + 0x1000, BIT(6), 0, 0); +static SPRD_SC_GATE_CLK(ia_in_i_en, "ia-in-i-en", "ahb-cam", 0x28, + 0x1000, BIT(7), 0, 0); +static SPRD_SC_GATE_CLK(ib_in_i_en, "ib-in-i-en", "ahb-cam", 0x28, + 0x1000, BIT(8), 0, 0); +static SPRD_SC_GATE_CLK(ic_in_i_en, "ic-in-i-en", "ahb-cam", 0x28, + 0x1000, BIT(9), 0, 0); + +static struct sprd_clk_common *sc9860_cam_gate[] = { + /* address base is 0x62100000 */ + &dcam0_eb.common, + &dcam1_eb.common, + &isp0_eb.common, + &csi0_eb.common, + &csi1_eb.common, + &jpg0_eb.common, + &jpg1_eb.common, + &cam_ckg_eb.common, + &cam_mmu_eb.common, + &isp1_eb.common, + &cpp_eb.common, + &mmu_pf_eb.common, + &isp2_eb.common, + &dcam2isp_if_eb.common, + &isp2dcam_if_eb.common, + &isp_lclk_eb.common, + &isp_iclk_eb.common, + &isp_mclk_eb.common, + &isp_pclk_eb.common, + &isp_isp2dcam_eb.common, + &dcam0_if_eb.common, + &clk26m_if_eb.common, + &cphy0_gate.common, + &mipi_csi0_gate.common, + &cphy1_gate.common, + &mipi_csi1.common, + &dcam0_axi_gate.common, + &dcam1_axi_gate.common, + &sensor0_gate.common, + &sensor1_gate.common, + &jpg0_axi_gate.common, + &gpg1_axi_gate.common, + &isp0_axi_gate.common, + &isp1_axi_gate.common, + &isp2_axi_gate.common, + &cpp_axi_gate.common, + &d0_if_axi_gate.common, + &d2i_if_axi_gate.common, + &i2d_if_axi_gate.common, + &spare_axi_gate.common, + &sensor2_gate.common, + &d0if_in_d_en.common, + &d1if_in_d_en.common, + &d0if_in_d2i_en.common, + &d1if_in_d2i_en.common, + &ia_in_d2i_en.common, + &ib_in_d2i_en.common, + &ic_in_d2i_en.common, + &ia_in_i_en.common, + &ib_in_i_en.common, + &ic_in_i_en.common, +}; + +static struct clk_hw_onecell_data sc9860_cam_gate_hws = { + .hws = { + [CLK_DCAM0_EB] = &dcam0_eb.common.hw, + [CLK_DCAM1_EB] = &dcam1_eb.common.hw, + [CLK_ISP0_EB] = &isp0_eb.common.hw, + [CLK_CSI0_EB] = &csi0_eb.common.hw, + [CLK_CSI1_EB] = &csi1_eb.common.hw, + [CLK_JPG0_EB] = &jpg0_eb.common.hw, + [CLK_JPG1_EB] = &jpg1_eb.common.hw, + [CLK_CAM_CKG_EB] = &cam_ckg_eb.common.hw, + [CLK_CAM_MMU_EB] = &cam_mmu_eb.common.hw, + [CLK_ISP1_EB] = &isp1_eb.common.hw, + [CLK_CPP_EB] = &cpp_eb.common.hw, + [CLK_MMU_PF_EB] = &mmu_pf_eb.common.hw, + [CLK_ISP2_EB] = &isp2_eb.common.hw, + [CLK_DCAM2ISP_IF_EB] = &dcam2isp_if_eb.common.hw, + [CLK_ISP2DCAM_IF_EB] = &isp2dcam_if_eb.common.hw, + [CLK_ISP_LCLK_EB] = &isp_lclk_eb.common.hw, + [CLK_ISP_ICLK_EB] = &isp_iclk_eb.common.hw, + [CLK_ISP_MCLK_EB] = &isp_mclk_eb.common.hw, + [CLK_ISP_PCLK_EB] = &isp_pclk_eb.common.hw, + [CLK_ISP_ISP2DCAM_EB] = &isp_isp2dcam_eb.common.hw, + [CLK_DCAM0_IF_EB] = &dcam0_if_eb.common.hw, + [CLK_CLK26M_IF_EB] = &clk26m_if_eb.common.hw, + [CLK_CPHY0_GATE] = &cphy0_gate.common.hw, + [CLK_MIPI_CSI0_GATE] = &mipi_csi0_gate.common.hw, + [CLK_CPHY1_GATE] = &cphy1_gate.common.hw, + [CLK_MIPI_CSI1] = &mipi_csi1.common.hw, + [CLK_DCAM0_AXI_GATE] = &dcam0_axi_gate.common.hw, + [CLK_DCAM1_AXI_GATE] = &dcam1_axi_gate.common.hw, + [CLK_SENSOR0_GATE] = &sensor0_gate.common.hw, + [CLK_SENSOR1_GATE] = &sensor1_gate.common.hw, + [CLK_JPG0_AXI_GATE] = &jpg0_axi_gate.common.hw, + [CLK_GPG1_AXI_GATE] = &gpg1_axi_gate.common.hw, + [CLK_ISP0_AXI_GATE] = &isp0_axi_gate.common.hw, + [CLK_ISP1_AXI_GATE] = &isp1_axi_gate.common.hw, + [CLK_ISP2_AXI_GATE] = &isp2_axi_gate.common.hw, + [CLK_CPP_AXI_GATE] = &cpp_axi_gate.common.hw, + [CLK_D0_IF_AXI_GATE] = &d0_if_axi_gate.common.hw, + [CLK_D2I_IF_AXI_GATE] = &d2i_if_axi_gate.common.hw, + [CLK_I2D_IF_AXI_GATE] = &i2d_if_axi_gate.common.hw, + [CLK_SPARE_AXI_GATE] = &spare_axi_gate.common.hw, + [CLK_SENSOR2_GATE] = &sensor2_gate.common.hw, + [CLK_D0IF_IN_D_EN] = &d0if_in_d_en.common.hw, + [CLK_D1IF_IN_D_EN] = &d1if_in_d_en.common.hw, + [CLK_D0IF_IN_D2I_EN] = &d0if_in_d2i_en.common.hw, + [CLK_D1IF_IN_D2I_EN] = &d1if_in_d2i_en.common.hw, + [CLK_IA_IN_D2I_EN] = &ia_in_d2i_en.common.hw, + [CLK_IB_IN_D2I_EN] = &ib_in_d2i_en.common.hw, + [CLK_IC_IN_D2I_EN] = &ic_in_d2i_en.common.hw, + [CLK_IA_IN_I_EN] = &ia_in_i_en.common.hw, + [CLK_IB_IN_I_EN] = &ib_in_i_en.common.hw, + [CLK_IC_IN_I_EN] = &ic_in_i_en.common.hw, + }, + .num = CLK_CAM_GATE_NUM, +}; + +static const struct sprd_clk_desc sc9860_cam_gate_desc = { + .clk_clks = sc9860_cam_gate, + .num_clk_clks = ARRAY_SIZE(sc9860_cam_gate), + .hw_clks = &sc9860_cam_gate_hws, +}; + +static SPRD_MUX_CLK(ahb_disp, "ahb-disp", ahb_parents, 0x20, + 0, 2, SC9860_MUX_FLAG); +static SPRD_COMP_CLK(dispc0_dpi, "dispc0-dpi", dispc_parents, 0x34, + 0, 2, 8, 2, 0); +static SPRD_COMP_CLK(dispc1_dpi, "dispc1-dpi", dispc_parents, 0x40, + 0, 2, 8, 2, 0); + +static struct sprd_clk_common *sc9860_disp_clk[] = { + /* address base is 0x63000000 */ + &ahb_disp.common, + &dispc0_dpi.common, + &dispc1_dpi.common, +}; + +static struct clk_hw_onecell_data sc9860_disp_clk_hws = { + .hws = { + [CLK_AHB_DISP] = &ahb_disp.common.hw, + [CLK_DISPC0_DPI] = &dispc0_dpi.common.hw, + [CLK_DISPC1_DPI] = &dispc1_dpi.common.hw, + }, + .num = CLK_DISP_NUM, +}; + +static const struct sprd_clk_desc sc9860_disp_clk_desc = { + .clk_clks = sc9860_disp_clk, + .num_clk_clks = ARRAY_SIZE(sc9860_disp_clk), + .hw_clks = &sc9860_disp_clk_hws, +}; + +static SPRD_SC_GATE_CLK(dispc0_eb, "dispc0-eb", "ahb-disp", 0x0, + 0x1000, BIT(0), 0, 0); +static SPRD_SC_GATE_CLK(dispc1_eb, "dispc1-eb", "ahb-disp", 0x0, + 0x1000, BIT(1), 0, 0); +static SPRD_SC_GATE_CLK(dispc_mmu_eb, "dispc-mmu-eb", "ahb-disp", 0x0, + 0x1000, BIT(2), 0, 0); +static SPRD_SC_GATE_CLK(gsp0_eb, "gsp0-eb", "ahb-disp", 0x0, + 0x1000, BIT(3), 0, 0); +static SPRD_SC_GATE_CLK(gsp1_eb, "gsp1-eb", "ahb-disp", 0x0, + 0x1000, BIT(4), 0, 0); +static SPRD_SC_GATE_CLK(gsp0_mmu_eb, "gsp0-mmu-eb", "ahb-disp", 0x0, + 0x1000, BIT(5), 0, 0); +static SPRD_SC_GATE_CLK(gsp1_mmu_eb, "gsp1-mmu-eb", "ahb-disp", 0x0, + 0x1000, BIT(6), 0, 0); +static SPRD_SC_GATE_CLK(dsi0_eb, "dsi0-eb", "ahb-disp", 0x0, + 0x1000, BIT(7), 0, 0); +static SPRD_SC_GATE_CLK(dsi1_eb, "dsi1-eb", "ahb-disp", 0x0, + 0x1000, BIT(8), 0, 0); +static SPRD_SC_GATE_CLK(disp_ckg_eb, "disp-ckg-eb", "ahb-disp", 0x0, + 0x1000, BIT(9), 0, 0); +static SPRD_SC_GATE_CLK(disp_gpu_eb, "disp-gpu-eb", "ahb-disp", 0x0, + 0x1000, BIT(10), 0, 0); +static SPRD_SC_GATE_CLK(gpu_mtx_eb, "gpu-mtx-eb", "ahb-disp", 0x0, + 0x1000, BIT(13), 0, 0); +static SPRD_SC_GATE_CLK(gsp_mtx_eb, "gsp-mtx-eb", "ahb-disp", 0x0, + 0x1000, BIT(14), 0, 0); +static SPRD_SC_GATE_CLK(tmc_mtx_eb, "tmc-mtx-eb", "ahb-disp", 0x0, + 0x1000, BIT(15), 0, 0); +static SPRD_SC_GATE_CLK(dispc_mtx_eb, "dispc-mtx-eb", "ahb-disp", 0x0, + 0x1000, BIT(16), 0, 0); +static SPRD_GATE_CLK(dphy0_gate, "dphy0-gate", "ahb-disp", 0x8, + BIT(0), 0, 0); +static SPRD_GATE_CLK(dphy1_gate, "dphy1-gate", "ahb-disp", 0x8, + BIT(1), 0, 0); +static SPRD_GATE_CLK(gsp0_a_gate, "gsp0-a-gate", "ahb-disp", 0x8, + BIT(2), 0, 0); +static SPRD_GATE_CLK(gsp1_a_gate, "gsp1-a-gate", "ahb-disp", 0x8, + BIT(3), 0, 0); +static SPRD_GATE_CLK(gsp0_f_gate, "gsp0-f-gate", "ahb-disp", 0x8, + BIT(4), 0, 0); +static SPRD_GATE_CLK(gsp1_f_gate, "gsp1-f-gate", "ahb-disp", 0x8, + BIT(5), 0, 0); +static SPRD_GATE_CLK(d_mtx_f_gate, "d-mtx-f-gate", "ahb-disp", 0x8, + BIT(6), 0, 0); +static SPRD_GATE_CLK(d_mtx_a_gate, "d-mtx-a-gate", "ahb-disp", 0x8, + BIT(7), 0, 0); +static SPRD_GATE_CLK(d_noc_f_gate, "d-noc-f-gate", "ahb-disp", 0x8, + BIT(8), 0, 0); +static SPRD_GATE_CLK(d_noc_a_gate, "d-noc-a-gate", "ahb-disp", 0x8, + BIT(9), 0, 0); +static SPRD_GATE_CLK(gsp_mtx_f_gate, "gsp-mtx-f-gate", "ahb-disp", 0x8, + BIT(10), 0, 0); +static SPRD_GATE_CLK(gsp_mtx_a_gate, "gsp-mtx-a-gate", "ahb-disp", 0x8, + BIT(11), 0, 0); +static SPRD_GATE_CLK(gsp_noc_f_gate, "gsp-noc-f-gate", "ahb-disp", 0x8, + BIT(12), 0, 0); +static SPRD_GATE_CLK(gsp_noc_a_gate, "gsp-noc-a-gate", "ahb-disp", 0x8, + BIT(13), 0, 0); +static SPRD_GATE_CLK(dispm0idle_gate, "dispm0idle-gate", "ahb-disp", 0x8, + BIT(14), 0, 0); +static SPRD_GATE_CLK(gspm0idle_gate, "gspm0idle-gate", "ahb-disp", 0x8, + BIT(15), 0, 0); + +static struct sprd_clk_common *sc9860_disp_gate[] = { + /* address base is 0x63100000 */ + &dispc0_eb.common, + &dispc1_eb.common, + &dispc_mmu_eb.common, + &gsp0_eb.common, + &gsp1_eb.common, + &gsp0_mmu_eb.common, + &gsp1_mmu_eb.common, + &dsi0_eb.common, + &dsi1_eb.common, + &disp_ckg_eb.common, + &disp_gpu_eb.common, + &gpu_mtx_eb.common, + &gsp_mtx_eb.common, + &tmc_mtx_eb.common, + &dispc_mtx_eb.common, + &dphy0_gate.common, + &dphy1_gate.common, + &gsp0_a_gate.common, + &gsp1_a_gate.common, + &gsp0_f_gate.common, + &gsp1_f_gate.common, + &d_mtx_f_gate.common, + &d_mtx_a_gate.common, + &d_noc_f_gate.common, + &d_noc_a_gate.common, + &gsp_mtx_f_gate.common, + &gsp_mtx_a_gate.common, + &gsp_noc_f_gate.common, + &gsp_noc_a_gate.common, + &dispm0idle_gate.common, + &gspm0idle_gate.common, +}; + +static struct clk_hw_onecell_data sc9860_disp_gate_hws = { + .hws = { + [CLK_DISPC0_EB] = &dispc0_eb.common.hw, + [CLK_DISPC1_EB] = &dispc1_eb.common.hw, + [CLK_DISPC_MMU_EB] = &dispc_mmu_eb.common.hw, + [CLK_GSP0_EB] = &gsp0_eb.common.hw, + [CLK_GSP1_EB] = &gsp1_eb.common.hw, + [CLK_GSP0_MMU_EB] = &gsp0_mmu_eb.common.hw, + [CLK_GSP1_MMU_EB] = &gsp1_mmu_eb.common.hw, + [CLK_DSI0_EB] = &dsi0_eb.common.hw, + [CLK_DSI1_EB] = &dsi1_eb.common.hw, + [CLK_DISP_CKG_EB] = &disp_ckg_eb.common.hw, + [CLK_DISP_GPU_EB] = &disp_gpu_eb.common.hw, + [CLK_GPU_MTX_EB] = &gpu_mtx_eb.common.hw, + [CLK_GSP_MTX_EB] = &gsp_mtx_eb.common.hw, + [CLK_TMC_MTX_EB] = &tmc_mtx_eb.common.hw, + [CLK_DISPC_MTX_EB] = &dispc_mtx_eb.common.hw, + [CLK_DPHY0_GATE] = &dphy0_gate.common.hw, + [CLK_DPHY1_GATE] = &dphy1_gate.common.hw, + [CLK_GSP0_A_GATE] = &gsp0_a_gate.common.hw, + [CLK_GSP1_A_GATE] = &gsp1_a_gate.common.hw, + [CLK_GSP0_F_GATE] = &gsp0_f_gate.common.hw, + [CLK_GSP1_F_GATE] = &gsp1_f_gate.common.hw, + [CLK_D_MTX_F_GATE] = &d_mtx_f_gate.common.hw, + [CLK_D_MTX_A_GATE] = &d_mtx_a_gate.common.hw, + [CLK_D_NOC_F_GATE] = &d_noc_f_gate.common.hw, + [CLK_D_NOC_A_GATE] = &d_noc_a_gate.common.hw, + [CLK_GSP_MTX_F_GATE] = &gsp_mtx_f_gate.common.hw, + [CLK_GSP_MTX_A_GATE] = &gsp_mtx_a_gate.common.hw, + [CLK_GSP_NOC_F_GATE] = &gsp_noc_f_gate.common.hw, + [CLK_GSP_NOC_A_GATE] = &gsp_noc_a_gate.common.hw, + [CLK_DISPM0IDLE_GATE] = &dispm0idle_gate.common.hw, + [CLK_GSPM0IDLE_GATE] = &gspm0idle_gate.common.hw, + }, + .num = CLK_DISP_GATE_NUM, +}; + +static const struct sprd_clk_desc sc9860_disp_gate_desc = { + .clk_clks = sc9860_disp_gate, + .num_clk_clks = ARRAY_SIZE(sc9860_disp_gate), + .hw_clks = &sc9860_disp_gate_hws, +}; + +static SPRD_SC_GATE_CLK(sim0_eb, "sim0-eb", "ap-apb", 0x0, + 0x1000, BIT(0), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(iis0_eb, "iis0-eb", "ap-apb", 0x0, + 0x1000, BIT(1), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(iis1_eb, "iis1-eb", "ap-apb", 0x0, + 0x1000, BIT(2), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(iis2_eb, "iis2-eb", "ap-apb", 0x0, + 0x1000, BIT(3), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(iis3_eb, "iis3-eb", "ap-apb", 0x0, + 0x1000, BIT(4), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(spi0_eb, "spi0-eb", "ap-apb", 0x0, + 0x1000, BIT(5), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(spi1_eb, "spi1-eb", "ap-apb", 0x0, + 0x1000, BIT(6), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(spi2_eb, "spi2-eb", "ap-apb", 0x0, + 0x1000, BIT(7), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(i2c0_eb, "i2c0-eb", "ap-apb", 0x0, + 0x1000, BIT(8), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(i2c1_eb, "i2c1-eb", "ap-apb", 0x0, + 0x1000, BIT(9), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(i2c2_eb, "i2c2-eb", "ap-apb", 0x0, + 0x1000, BIT(10), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(i2c3_eb, "i2c3-eb", "ap-apb", 0x0, + 0x1000, BIT(11), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(i2c4_eb, "i2c4-eb", "ap-apb", 0x0, + 0x1000, BIT(12), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(i2c5_eb, "i2c5-eb", "ap-apb", 0x0, + 0x1000, BIT(13), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(uart0_eb, "uart0-eb", "ap-apb", 0x0, + 0x1000, BIT(14), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(uart1_eb, "uart1-eb", "ap-apb", 0x0, + 0x1000, BIT(15), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(uart2_eb, "uart2-eb", "ap-apb", 0x0, + 0x1000, BIT(16), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(uart3_eb, "uart3-eb", "ap-apb", 0x0, + 0x1000, BIT(17), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(uart4_eb, "uart4-eb", "ap-apb", 0x0, + 0x1000, BIT(18), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_ckg_eb, "ap-ckg-eb", "ap-apb", 0x0, + 0x1000, BIT(19), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(spi3_eb, "spi3-eb", "ap-apb", 0x0, + 0x1000, BIT(20), CLK_IGNORE_UNUSED, 0); + +static struct sprd_clk_common *sc9860_apapb_gate[] = { + /* address base is 0x70b00000 */ + &sim0_eb.common, + &iis0_eb.common, + &iis1_eb.common, + &iis2_eb.common, + &iis3_eb.common, + &spi0_eb.common, + &spi1_eb.common, + &spi2_eb.common, + &i2c0_eb.common, + &i2c1_eb.common, + &i2c2_eb.common, + &i2c3_eb.common, + &i2c4_eb.common, + &i2c5_eb.common, + &uart0_eb.common, + &uart1_eb.common, + &uart2_eb.common, + &uart3_eb.common, + &uart4_eb.common, + &ap_ckg_eb.common, + &spi3_eb.common, +}; + +static struct clk_hw_onecell_data sc9860_apapb_gate_hws = { + .hws = { + [CLK_SIM0_EB] = &sim0_eb.common.hw, + [CLK_IIS0_EB] = &iis0_eb.common.hw, + [CLK_IIS1_EB] = &iis1_eb.common.hw, + [CLK_IIS2_EB] = &iis2_eb.common.hw, + [CLK_IIS3_EB] = &iis3_eb.common.hw, + [CLK_SPI0_EB] = &spi0_eb.common.hw, + [CLK_SPI1_EB] = &spi1_eb.common.hw, + [CLK_SPI2_EB] = &spi2_eb.common.hw, + [CLK_I2C0_EB] = &i2c0_eb.common.hw, + [CLK_I2C1_EB] = &i2c1_eb.common.hw, + [CLK_I2C2_EB] = &i2c2_eb.common.hw, + [CLK_I2C3_EB] = &i2c3_eb.common.hw, + [CLK_I2C4_EB] = &i2c4_eb.common.hw, + [CLK_I2C5_EB] = &i2c5_eb.common.hw, + [CLK_UART0_EB] = &uart0_eb.common.hw, + [CLK_UART1_EB] = &uart1_eb.common.hw, + [CLK_UART2_EB] = &uart2_eb.common.hw, + [CLK_UART3_EB] = &uart3_eb.common.hw, + [CLK_UART4_EB] = &uart4_eb.common.hw, + [CLK_AP_CKG_EB] = &ap_ckg_eb.common.hw, + [CLK_SPI3_EB] = &spi3_eb.common.hw, + }, + .num = CLK_APAPB_GATE_NUM, +}; + +static const struct sprd_clk_desc sc9860_apapb_gate_desc = { + .clk_clks = sc9860_apapb_gate, + .num_clk_clks = ARRAY_SIZE(sc9860_apapb_gate), + .hw_clks = &sc9860_apapb_gate_hws, +}; + +static const struct of_device_id sprd_sc9860_clk_ids[] = { + { .compatible = "sprd,sc9860-pmu-gate", /* 0x402b */ + .data = &sc9860_pmu_gate_desc }, + { .compatible = "sprd,sc9860-pll", /* 0x4040 */ + .data = &sc9860_pll_desc }, + { .compatible = "sprd,sc9860-ap-clk", /* 0x2000 */ + .data = &sc9860_ap_clk_desc }, + { .compatible = "sprd,sc9860-aon-prediv", /* 0x402d */ + .data = &sc9860_aon_prediv_desc }, + { .compatible = "sprd,sc9860-apahb-gate", /* 0x2021 */ + .data = &sc9860_apahb_gate_desc }, + { .compatible = "sprd,sc9860-aon-gate", /* 0x402e */ + .data = &sc9860_aon_gate_desc }, + { .compatible = "sprd,sc9860-aonsecure-clk", /* 0x4088 */ + .data = &sc9860_aonsecure_clk_desc }, + { .compatible = "sprd,sc9860-agcp-gate", /* 0x415e */ + .data = &sc9860_agcp_gate_desc }, + { .compatible = "sprd,sc9860-gpu-clk", /* 0x6020 */ + .data = &sc9860_gpu_clk_desc }, + { .compatible = "sprd,sc9860-vsp-clk", /* 0x6100 */ + .data = &sc9860_vsp_clk_desc }, + { .compatible = "sprd,sc9860-vsp-gate", /* 0x6110 */ + .data = &sc9860_vsp_gate_desc }, + { .compatible = "sprd,sc9860-cam-clk", /* 0x6200 */ + .data = &sc9860_cam_clk_desc }, + { .compatible = "sprd,sc9860-cam-gate", /* 0x6210 */ + .data = &sc9860_cam_gate_desc }, + { .compatible = "sprd,sc9860-disp-clk", /* 0x6300 */ + .data = &sc9860_disp_clk_desc }, + { .compatible = "sprd,sc9860-disp-gate", /* 0x6310 */ + .data = &sc9860_disp_gate_desc }, + { .compatible = "sprd,sc9860-apapb-gate", /* 0x70b0 */ + .data = &sc9860_apapb_gate_desc }, + { } +}; +MODULE_DEVICE_TABLE(of, sprd_sc9860_clk_ids); + +static int sc9860_clk_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + const struct sprd_clk_desc *desc; + + match = of_match_node(sprd_sc9860_clk_ids, pdev->dev.of_node); + if (!match) { + pr_err("%s: of_match_node() failed", __func__); + return -ENODEV; + } + + desc = match->data; + sprd_clk_regmap_init(pdev, desc); + + return sprd_clk_probe(&pdev->dev, desc->hw_clks); +} + +static struct platform_driver sc9860_clk_driver = { + .probe = sc9860_clk_probe, + .driver = { + .name = "sc9860-clk", + .of_match_table = sprd_sc9860_clk_ids, + }, +}; +module_platform_driver(sc9860_clk_driver); + +MODULE_DESCRIPTION("Spreadtrum SC9860 Clock Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:sc9860-clk"); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c index 2bb4cabf802f..ee9c12cf3f08 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c @@ -400,28 +400,45 @@ static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", mod0_default_parents, 0x080, BIT(31), /* gate */ 0); +/* + * MMC clocks are the new timing mode (see A83T & H3) variety, but without + * the mode switch. This means they have a 2x post divider between the clock + * and the MMC module. This is not documented in the manual, but is taken + * into consideration when setting the mmc module clocks in the BSP kernel. + * Without it, MMC performance is degraded. + * + * We model it here to be consistent with other SoCs supporting this mode. + * The alternative would be to add the 2x multiplier when setting the MMC + * module clock in the MMC driver, just for the A64. + */ static const char * const mmc_default_parents[] = { "osc24M", "pll-periph0-2x", "pll-periph1-2x" }; -static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc_default_parents, 0x088, - 0, 4, /* M */ - 16, 2, /* P */ - 24, 2, /* mux */ - BIT(31), /* gate */ - 0); +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc0_clk, "mmc0", + mmc_default_parents, 0x088, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 2, /* post-div */ + 0); -static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc_default_parents, 0x08c, - 0, 4, /* M */ - 16, 2, /* P */ - 24, 2, /* mux */ - BIT(31), /* gate */ - 0); +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc1_clk, "mmc1", + mmc_default_parents, 0x08c, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 2, /* post-div */ + 0); -static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc_default_parents, 0x090, - 0, 4, /* M */ - 16, 2, /* P */ - 24, 2, /* mux */ - BIT(31), /* gate */ - 0); +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2", + mmc_default_parents, 0x090, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 2, /* post-div */ + 0); static const char * const ts_parents[] = { "osc24M", "pll-periph0", }; static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x098, diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c index 5cedcd0d8be8..7d08015b980d 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c @@ -76,15 +76,26 @@ static struct ccu_mult pll_c1cpux_clk = { */ #define SUN8I_A83T_PLL_AUDIO_REG 0x008 +/* clock rates doubled for post divider */ +static struct ccu_sdm_setting pll_audio_sdm_table[] = { + { .rate = 45158400, .pattern = 0xc00121ff, .m = 29, .n = 54 }, + { .rate = 49152000, .pattern = 0xc000e147, .m = 30, .n = 61 }, +}; + static struct ccu_nm pll_audio_clk = { .enable = BIT(31), .lock = BIT(2), .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0), .m = _SUNXI_CCU_DIV(0, 6), + .fixed_post_div = 2, + .sdm = _SUNXI_CCU_SDM(pll_audio_sdm_table, BIT(24), + 0x284, BIT(31)), .common = { .reg = SUN8I_A83T_PLL_AUDIO_REG, .lock_reg = CCU_SUN8I_A83T_LOCK_REG, - .features = CCU_FEATURE_LOCK_REG, + .features = CCU_FEATURE_LOCK_REG | + CCU_FEATURE_FIXED_POSTDIV | + CCU_FEATURE_SIGMA_DELTA_MOD, .hw.init = CLK_HW_INIT("pll-audio", "osc24M", &ccu_nm_ops, CLK_SET_RATE_UNGATE), }, @@ -493,8 +504,8 @@ static SUNXI_CCU_MUX_WITH_GATE(tcon0_clk, "tcon0", tcon0_parents, 0x118, 24, 3, BIT(31), CLK_SET_RATE_PARENT); static const char * const tcon1_parents[] = { "pll-video1" }; -static SUNXI_CCU_MUX_WITH_GATE(tcon1_clk, "tcon1", tcon1_parents, - 0x11c, 24, 3, BIT(31), CLK_SET_RATE_PARENT); +static SUNXI_CCU_M_WITH_MUX_GATE(tcon1_clk, "tcon1", tcon1_parents, + 0x11c, 0, 4, 24, 2, BIT(31), CLK_SET_RATE_PARENT); static SUNXI_CCU_GATE(csi_misc_clk, "csi-misc", "osc24M", 0x130, BIT(16), 0); @@ -889,9 +900,10 @@ static int sun8i_a83t_ccu_probe(struct platform_device *pdev) if (IS_ERR(reg)) return PTR_ERR(reg); - /* Enforce d1 = 0, d2 = 0 for Audio PLL */ + /* Enforce d1 = 0, d2 = 1 for Audio PLL */ val = readl(reg + SUN8I_A83T_PLL_AUDIO_REG); - val &= ~(BIT(16) | BIT(18)); + val &= ~BIT(16); + val |= BIT(18); writel(val, reg + SUN8I_A83T_PLL_AUDIO_REG); /* Enforce P = 1 for both CPU cluster PLLs */ diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index 5cc9d9952121..468d1abaf0ee 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -41,6 +41,8 @@ static SUNXI_CCU_GATE(wb_clk, "wb", "wb-div", static SUNXI_CCU_M(mixer0_div_clk, "mixer0-div", "de", 0x0c, 0, 4, CLK_SET_RATE_PARENT); +static SUNXI_CCU_M(mixer1_div_clk, "mixer1-div", "de", 0x0c, 4, 4, + CLK_SET_RATE_PARENT); static SUNXI_CCU_M(wb_div_clk, "wb-div", "de", 0x0c, 8, 4, CLK_SET_RATE_PARENT); @@ -65,6 +67,20 @@ static struct ccu_common *sun8i_a83t_de2_clks[] = { &wb_div_a83_clk.common, }; +static struct ccu_common *sun8i_h3_de2_clks[] = { + &mixer0_clk.common, + &mixer1_clk.common, + &wb_clk.common, + + &bus_mixer0_clk.common, + &bus_mixer1_clk.common, + &bus_wb_clk.common, + + &mixer0_div_clk.common, + &mixer1_div_clk.common, + &wb_div_clk.common, +}; + static struct ccu_common *sun8i_v3s_de2_clks[] = { &mixer0_clk.common, &wb_clk.common, @@ -93,6 +109,23 @@ static struct clk_hw_onecell_data sun8i_a83t_de2_hw_clks = { .num = CLK_NUMBER, }; +static struct clk_hw_onecell_data sun8i_h3_de2_hw_clks = { + .hws = { + [CLK_MIXER0] = &mixer0_clk.common.hw, + [CLK_MIXER1] = &mixer1_clk.common.hw, + [CLK_WB] = &wb_clk.common.hw, + + [CLK_BUS_MIXER0] = &bus_mixer0_clk.common.hw, + [CLK_BUS_MIXER1] = &bus_mixer1_clk.common.hw, + [CLK_BUS_WB] = &bus_wb_clk.common.hw, + + [CLK_MIXER0_DIV] = &mixer0_div_clk.common.hw, + [CLK_MIXER1_DIV] = &mixer1_div_clk.common.hw, + [CLK_WB_DIV] = &wb_div_clk.common.hw, + }, + .num = CLK_NUMBER, +}; + static struct clk_hw_onecell_data sun8i_v3s_de2_hw_clks = { .hws = { [CLK_MIXER0] = &mixer0_clk.common.hw, @@ -133,11 +166,21 @@ static const struct sunxi_ccu_desc sun8i_a83t_de2_clk_desc = { .num_resets = ARRAY_SIZE(sun8i_a83t_de2_resets), }; -static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = { - .ccu_clks = sun8i_a83t_de2_clks, - .num_ccu_clks = ARRAY_SIZE(sun8i_a83t_de2_clks), +static const struct sunxi_ccu_desc sun8i_h3_de2_clk_desc = { + .ccu_clks = sun8i_h3_de2_clks, + .num_ccu_clks = ARRAY_SIZE(sun8i_h3_de2_clks), - .hw_clks = &sun8i_a83t_de2_hw_clks, + .hw_clks = &sun8i_h3_de2_hw_clks, + + .resets = sun8i_a83t_de2_resets, + .num_resets = ARRAY_SIZE(sun8i_a83t_de2_resets), +}; + +static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = { + .ccu_clks = sun8i_h3_de2_clks, + .num_ccu_clks = ARRAY_SIZE(sun8i_h3_de2_clks), + + .hw_clks = &sun8i_h3_de2_hw_clks, .resets = sun50i_a64_de2_resets, .num_resets = ARRAY_SIZE(sun50i_a64_de2_resets), @@ -237,6 +280,10 @@ static const struct of_device_id sunxi_de2_clk_ids[] = { .compatible = "allwinner,sun8i-a83t-de2-clk", .data = &sun8i_a83t_de2_clk_desc, }, + { + .compatible = "allwinner,sun8i-h3-de2-clk", + .data = &sun8i_h3_de2_clk_desc, + }, { .compatible = "allwinner,sun8i-v3s-de2-clk", .data = &sun8i_v3s_de2_clk_desc, diff --git a/drivers/clk/sunxi-ng/ccu_common.h b/drivers/clk/sunxi-ng/ccu_common.h index 5d684ce77c54..568cfaed0813 100644 --- a/drivers/clk/sunxi-ng/ccu_common.h +++ b/drivers/clk/sunxi-ng/ccu_common.h @@ -31,35 +31,6 @@ struct device_node; -#define CLK_HW_INIT(_name, _parent, _ops, _flags) \ - &(struct clk_init_data) { \ - .flags = _flags, \ - .name = _name, \ - .parent_names = (const char *[]) { _parent }, \ - .num_parents = 1, \ - .ops = _ops, \ - } - -#define CLK_HW_INIT_PARENTS(_name, _parents, _ops, _flags) \ - &(struct clk_init_data) { \ - .flags = _flags, \ - .name = _name, \ - .parent_names = _parents, \ - .num_parents = ARRAY_SIZE(_parents), \ - .ops = _ops, \ - } - -#define CLK_FIXED_FACTOR(_struct, _name, _parent, \ - _div, _mult, _flags) \ - struct clk_fixed_factor _struct = { \ - .div = _div, \ - .mult = _mult, \ - .hw.init = CLK_HW_INIT(_name, \ - _parent, \ - &clk_fixed_factor_ops, \ - _flags), \ - } - struct ccu_common { void __iomem *base; u16 reg; diff --git a/drivers/clk/sunxi-ng/ccu_div.c b/drivers/clk/sunxi-ng/ccu_div.c index baa3cf96507b..302a18efd39f 100644 --- a/drivers/clk/sunxi-ng/ccu_div.c +++ b/drivers/clk/sunxi-ng/ccu_div.c @@ -71,7 +71,7 @@ static unsigned long ccu_div_recalc_rate(struct clk_hw *hw, parent_rate); val = divider_recalc_rate(hw, parent_rate, val, cd->div.table, - cd->div.flags); + cd->div.flags, cd->div.width); if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV) val /= cd->fixed_post_div; diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c index 688855e7dc8c..5d0af4051737 100644 --- a/drivers/clk/sunxi-ng/ccu_mp.c +++ b/drivers/clk/sunxi-ng/ccu_mp.c @@ -50,12 +50,19 @@ static unsigned long ccu_mp_round_rate(struct ccu_mux_internal *mux, unsigned int max_m, max_p; unsigned int m, p; + if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate *= cmp->fixed_post_div; + max_m = cmp->m.max ?: 1 << cmp->m.width; max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1); ccu_mp_find_best(*parent_rate, rate, max_m, max_p, &m, &p); + rate = *parent_rate / p / m; - return *parent_rate / p / m; + if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= cmp->fixed_post_div; + + return rate; } static void ccu_mp_disable(struct clk_hw *hw) @@ -83,6 +90,7 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct ccu_mp *cmp = hw_to_ccu_mp(hw); + unsigned long rate; unsigned int m, p; u32 reg; @@ -101,7 +109,11 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw, p = reg >> cmp->p.shift; p &= (1 << cmp->p.width) - 1; - return (parent_rate >> p) / m; + rate = (parent_rate >> p) / m; + if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= cmp->fixed_post_div; + + return rate; } static int ccu_mp_determine_rate(struct clk_hw *hw, @@ -129,6 +141,10 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate, max_m = cmp->m.max ?: 1 << cmp->m.width; max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1); + /* Adjust target rate according to post-dividers */ + if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate = rate * cmp->fixed_post_div; + ccu_mp_find_best(parent_rate, rate, max_m, max_p, &m, &p); spin_lock_irqsave(cmp->common.lock, flags); diff --git a/drivers/clk/sunxi-ng/ccu_mp.h b/drivers/clk/sunxi-ng/ccu_mp.h index aaef11d747ea..5107635e61de 100644 --- a/drivers/clk/sunxi-ng/ccu_mp.h +++ b/drivers/clk/sunxi-ng/ccu_mp.h @@ -33,9 +33,33 @@ struct ccu_mp { struct ccu_div_internal m; struct ccu_div_internal p; struct ccu_mux_internal mux; + + unsigned int fixed_post_div; + struct ccu_common common; }; +#define SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(_struct, _name, _parents, _reg, \ + _mshift, _mwidth, \ + _pshift, _pwidth, \ + _muxshift, _muxwidth, \ + _gate, _postdiv, _flags) \ + struct ccu_mp _struct = { \ + .enable = _gate, \ + .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \ + .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \ + .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ + .fixed_post_div = _postdiv, \ + .common = { \ + .reg = _reg, \ + .features = CCU_FEATURE_FIXED_POSTDIV, \ + .hw.init = CLK_HW_INIT_PARENTS(_name, \ + _parents, \ + &ccu_mp_ops, \ + _flags), \ + } \ + } + #define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ _mshift, _mwidth, \ _pshift, _pwidth, \ diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c index 7620aa973a6e..a16de092bf94 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.c +++ b/drivers/clk/sunxi-ng/ccu_nm.c @@ -70,11 +70,18 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct ccu_nm *nm = hw_to_ccu_nm(hw); + unsigned long rate; unsigned long n, m; u32 reg; - if (ccu_frac_helper_is_enabled(&nm->common, &nm->frac)) - return ccu_frac_helper_read_rate(&nm->common, &nm->frac); + if (ccu_frac_helper_is_enabled(&nm->common, &nm->frac)) { + rate = ccu_frac_helper_read_rate(&nm->common, &nm->frac); + + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nm->fixed_post_div; + + return rate; + } reg = readl(nm->common.base + nm->common.reg); @@ -90,15 +97,15 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw, if (!m) m++; - if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm)) { - unsigned long rate = - ccu_sdm_helper_read_rate(&nm->common, &nm->sdm, - m, n); - if (rate) - return rate; - } + if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm)) + rate = ccu_sdm_helper_read_rate(&nm->common, &nm->sdm, m, n); + else + rate = parent_rate * n / m; - return parent_rate * n / m; + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nm->fixed_post_div; + + return rate; } static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, @@ -107,11 +114,20 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, struct ccu_nm *nm = hw_to_ccu_nm(hw); struct _ccu_nm _nm; - if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) - return rate; + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate *= nm->fixed_post_div; - if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate)) + if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) { + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nm->fixed_post_div; return rate; + } + + if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate)) { + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nm->fixed_post_div; + return rate; + } _nm.min_n = nm->n.min ?: 1; _nm.max_n = nm->n.max ?: 1 << nm->n.width; @@ -119,8 +135,12 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, _nm.max_m = nm->m.max ?: 1 << nm->m.width; ccu_nm_find_best(*parent_rate, rate, &_nm); + rate = *parent_rate * _nm.n / _nm.m; - return *parent_rate * _nm.n / _nm.m; + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nm->fixed_post_div; + + return rate; } static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate, @@ -131,6 +151,10 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long flags; u32 reg; + /* Adjust target rate according to post-dividers */ + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate = rate * nm->fixed_post_div; + if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) { spin_lock_irqsave(nm->common.lock, flags); diff --git a/drivers/clk/sunxi-ng/ccu_nm.h b/drivers/clk/sunxi-ng/ccu_nm.h index c623b0c7a23c..eba586b4c7d0 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.h +++ b/drivers/clk/sunxi-ng/ccu_nm.h @@ -36,6 +36,8 @@ struct ccu_nm { struct ccu_frac_internal frac; struct ccu_sdm_internal sdm; + unsigned int fixed_post_div; + struct ccu_common common; }; diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index 856fef65433b..661a73284e9f 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c @@ -176,10 +176,10 @@ static const struct clk_ops clk_factors_ops = { .set_rate = clk_factors_set_rate, }; -struct clk *sunxi_factors_register(struct device_node *node, - const struct factors_data *data, - spinlock_t *lock, - void __iomem *reg) +static struct clk *__sunxi_factors_register(struct device_node *node, + const struct factors_data *data, + spinlock_t *lock, void __iomem *reg, + unsigned long flags) { struct clk *clk; struct clk_factors *factors; @@ -249,7 +249,7 @@ struct clk *sunxi_factors_register(struct device_node *node, parents, i, mux_hw, &clk_mux_ops, &factors->hw, &clk_factors_ops, - gate_hw, &clk_gate_ops, 0); + gate_hw, &clk_gate_ops, CLK_IS_CRITICAL); if (IS_ERR(clk)) goto err_register; @@ -272,6 +272,22 @@ err_factors: return NULL; } +struct clk *sunxi_factors_register(struct device_node *node, + const struct factors_data *data, + spinlock_t *lock, + void __iomem *reg) +{ + return __sunxi_factors_register(node, data, lock, reg, 0); +} + +struct clk *sunxi_factors_register_critical(struct device_node *node, + const struct factors_data *data, + spinlock_t *lock, + void __iomem *reg) +{ + return __sunxi_factors_register(node, data, lock, reg, CLK_IS_CRITICAL); +} + void sunxi_factors_unregister(struct device_node *node, struct clk *clk) { struct clk_hw *hw = __clk_get_hw(clk); diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h index 824f746b2567..7ad2ca924d0d 100644 --- a/drivers/clk/sunxi/clk-factors.h +++ b/drivers/clk/sunxi/clk-factors.h @@ -55,6 +55,10 @@ struct clk *sunxi_factors_register(struct device_node *node, const struct factors_data *data, spinlock_t *lock, void __iomem *reg); +struct clk *sunxi_factors_register_critical(struct device_node *node, + const struct factors_data *data, + spinlock_t *lock, + void __iomem *reg); void sunxi_factors_unregister(struct device_node *node, struct clk *clk); diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c index 4417ae129ac7..a27c264cc9b4 100644 --- a/drivers/clk/sunxi/clk-mod0.c +++ b/drivers/clk/sunxi/clk-mod0.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include @@ -155,7 +154,6 @@ static DEFINE_SPINLOCK(sun5i_a13_mbus_lock); static void __init sun5i_a13_mbus_setup(struct device_node *node) { - struct clk *mbus; void __iomem *reg; reg = of_iomap(node, 0); @@ -164,12 +162,9 @@ static void __init sun5i_a13_mbus_setup(struct device_node *node) return; } - mbus = sunxi_factors_register(node, &sun4i_a10_mod0_data, - &sun5i_a13_mbus_lock, reg); - /* The MBUS clocks needs to be always enabled */ - __clk_get(mbus); - clk_prepare_enable(mbus); + sunxi_factors_register_critical(node, &sun4i_a10_mod0_data, + &sun5i_a13_mbus_lock, reg); } CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup); diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c index ea1eed24778c..d5c31804ee54 100644 --- a/drivers/clk/sunxi/clk-sun8i-apb0.c +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c @@ -98,10 +98,7 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev) return PTR_ERR(reg); clk = sun8i_a23_apb0_register(np, reg); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - return 0; + return PTR_ERR_OR_ZERO(clk); } static const struct of_device_id sun8i_a23_apb0_clk_dt_ids[] = { diff --git a/drivers/clk/sunxi/clk-sun8i-mbus.c b/drivers/clk/sunxi/clk-sun8i-mbus.c index b200ebf159ee..56db89b6979f 100644 --- a/drivers/clk/sunxi/clk-sun8i-mbus.c +++ b/drivers/clk/sunxi/clk-sun8i-mbus.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include @@ -82,11 +81,12 @@ static void __init sun8i_a23_mbus_setup(struct device_node *node) mux->mask = SUN8I_MBUS_MUX_MASK; mux->lock = &sun8i_a23_mbus_lock; + /* The MBUS clocks needs to be always enabled */ clk = clk_register_composite(NULL, clk_name, parents, num_parents, &mux->hw, &clk_mux_ops, &div->hw, &clk_divider_ops, &gate->hw, &clk_gate_ops, - 0); + CLK_IS_CRITICAL); if (IS_ERR(clk)) goto err_free_gate; @@ -95,9 +95,6 @@ static void __init sun8i_a23_mbus_setup(struct device_node *node) goto err_unregister_clk; kfree(parents); /* parents is deep copied */ - /* The MBUS clocks needs to be always enabled */ - __clk_get(clk); - clk_prepare_enable(clk); return; diff --git a/drivers/clk/sunxi/clk-sun9i-core.c b/drivers/clk/sunxi/clk-sun9i-core.c index 43f014f85803..e9295c286d5d 100644 --- a/drivers/clk/sunxi/clk-sun9i-core.c +++ b/drivers/clk/sunxi/clk-sun9i-core.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include @@ -140,7 +139,6 @@ static DEFINE_SPINLOCK(sun9i_a80_gt_lock); static void __init sun9i_a80_gt_setup(struct device_node *node) { void __iomem *reg; - struct clk *gt; reg = of_io_request_and_map(node, 0, of_node_full_name(node)); if (IS_ERR(reg)) { @@ -149,12 +147,9 @@ static void __init sun9i_a80_gt_setup(struct device_node *node) return; } - gt = sunxi_factors_register(node, &sun9i_a80_gt_data, - &sun9i_a80_gt_lock, reg); - /* The GT bus clock needs to be always enabled */ - __clk_get(gt); - clk_prepare_enable(gt); + sunxi_factors_register_critical(node, &sun9i_a80_gt_data, + &sun9i_a80_gt_lock, reg); } CLK_OF_DECLARE(sun9i_a80_gt, "allwinner,sun9i-a80-gt-clk", sun9i_a80_gt_setup); diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index aa4add580516..012714d94b42 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -656,7 +656,8 @@ static const struct mux_data sun8i_h3_ahb2_mux_data __initconst = { }; static struct clk * __init sunxi_mux_clk_setup(struct device_node *node, - const struct mux_data *data) + const struct mux_data *data, + unsigned long flags) { struct clk *clk; const char *clk_name = node->name; @@ -678,7 +679,7 @@ static struct clk * __init sunxi_mux_clk_setup(struct device_node *node, } clk = clk_register_mux(NULL, clk_name, parents, i, - CLK_SET_RATE_PARENT, reg, + CLK_SET_RATE_PARENT | flags, reg, data->shift, SUNXI_MUX_GATE_WIDTH, 0, &clk_lock); @@ -703,29 +704,22 @@ out_unmap: static void __init sun4i_cpu_clk_setup(struct device_node *node) { - struct clk *clk; - - clk = sunxi_mux_clk_setup(node, &sun4i_cpu_mux_data); - if (!clk) - return; - /* Protect CPU clock */ - __clk_get(clk); - clk_prepare_enable(clk); + sunxi_mux_clk_setup(node, &sun4i_cpu_mux_data, CLK_IS_CRITICAL); } CLK_OF_DECLARE(sun4i_cpu, "allwinner,sun4i-a10-cpu-clk", sun4i_cpu_clk_setup); static void __init sun6i_ahb1_mux_clk_setup(struct device_node *node) { - sunxi_mux_clk_setup(node, &sun6i_a31_ahb1_mux_data); + sunxi_mux_clk_setup(node, &sun6i_a31_ahb1_mux_data, 0); } CLK_OF_DECLARE(sun6i_ahb1_mux, "allwinner,sun6i-a31-ahb1-mux-clk", sun6i_ahb1_mux_clk_setup); static void __init sun8i_ahb2_clk_setup(struct device_node *node) { - sunxi_mux_clk_setup(node, &sun8i_h3_ahb2_mux_data); + sunxi_mux_clk_setup(node, &sun8i_h3_ahb2_mux_data, 0); } CLK_OF_DECLARE(sun8i_ahb2, "allwinner,sun8i-h3-ahb2-clk", sun8i_ahb2_clk_setup); @@ -900,6 +894,7 @@ struct divs_data { u8 shift; /* otherwise it's a normal divisor with this shift */ u8 pow; /* is it power-of-two based? */ u8 gate; /* is it independently gateable? */ + bool critical; } div[SUNXI_DIVS_MAX_QTY]; }; @@ -915,7 +910,8 @@ static const struct divs_data pll5_divs_data __initconst = { .factors = &sun4i_pll5_data, .ndivs = 2, .div = { - { .shift = 0, .pow = 0, }, /* M, DDR */ + /* Protect PLL5_DDR */ + { .shift = 0, .pow = 0, .critical = true }, /* M, DDR */ { .shift = 16, .pow = 1, }, /* P, other */ /* No output for the base factor clock */ } @@ -1089,7 +1085,9 @@ static struct clk ** __init sunxi_divs_clk_setup(struct device_node *node, NULL, NULL, rate_hw, rate_ops, gate_hw, &clk_gate_ops, - clkflags); + clkflags | + data->div[i].critical ? + CLK_IS_CRITICAL : 0); WARN_ON(IS_ERR(clk_data->clks[i])); } @@ -1117,15 +1115,7 @@ out_unmap: static void __init sun4i_pll5_clk_setup(struct device_node *node) { - struct clk **clks; - - clks = sunxi_divs_clk_setup(node, &pll5_divs_data); - if (!clks) - return; - - /* Protect PLL5_DDR */ - __clk_get(clks[0]); - clk_prepare_enable(clks[0]); + sunxi_divs_clk_setup(node, &pll5_divs_data); } CLK_OF_DECLARE(sun4i_pll5, "allwinner,sun4i-a10-pll5-clk", sun4i_pll5_clk_setup); diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile index a2293ee09440..5ab295d2a3cb 100644 --- a/drivers/clk/ti/Makefile +++ b/drivers/clk/ti/Makefile @@ -19,10 +19,6 @@ obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \ clk-dra7-atl.o dpll3xxx.o dpll44xx.o obj-$(CONFIG_SOC_AM43XX) += $(clk-common) dpll3xxx.o clk-43xx.o -ifdef CONFIG_ATAGS -obj-$(CONFIG_ARCH_OMAP3) += clk-3xxx-legacy.o -endif - endif # CONFIG_ARCH_OMAP2PLUS obj-$(CONFIG_COMMON_CLK_TI_ADPLL) += adpll.o diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c index 83b148f8037c..9498e9363b57 100644 --- a/drivers/clk/ti/apll.c +++ b/drivers/clk/ti/apll.c @@ -133,9 +133,10 @@ static const struct clk_ops apll_ck_ops = { .get_parent = &dra7_init_apll_parent, }; -static void __init omap_clk_register_apll(struct clk_hw *hw, +static void __init omap_clk_register_apll(void *user, struct device_node *node) { + struct clk_hw *hw = user; struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw); struct dpll_data *ad = clk_hw->dpll_data; struct clk *clk; diff --git a/drivers/clk/ti/clk-33xx.c b/drivers/clk/ti/clk-33xx.c index 0e47d95faf49..612491a26070 100644 --- a/drivers/clk/ti/clk-33xx.c +++ b/drivers/clk/ti/clk-33xx.c @@ -19,98 +19,201 @@ #include #include #include +#include #include "clock.h" +static const char * const am3_gpio1_dbclk_parents[] __initconst = { + "l4_per_cm:clk:0138:0", + NULL, +}; + +static const struct omap_clkctrl_bit_data am3_gpio2_bit_data[] __initconst = { + { 18, TI_CLK_GATE, am3_gpio1_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data am3_gpio3_bit_data[] __initconst = { + { 18, TI_CLK_GATE, am3_gpio1_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data am3_gpio4_bit_data[] __initconst = { + { 18, TI_CLK_GATE, am3_gpio1_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data am3_l4_per_clkctrl_regs[] __initconst = { + { AM3_CPGMAC0_CLKCTRL, NULL, CLKF_SW_SUP, "cpsw_125mhz_gclk", "cpsw_125mhz_clkdm" }, + { AM3_LCDC_CLKCTRL, NULL, CLKF_SW_SUP, "lcd_gclk", "lcdc_clkdm" }, + { AM3_USB_OTG_HS_CLKCTRL, NULL, CLKF_SW_SUP, "usbotg_fck", "l3s_clkdm" }, + { AM3_TPTC0_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" }, + { AM3_EMIF_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_ddr_m2_div2_ck", "l3_clkdm" }, + { AM3_OCMCRAM_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" }, + { AM3_GPMC_CLKCTRL, NULL, CLKF_SW_SUP, "l3s_gclk", "l3s_clkdm" }, + { AM3_MCASP0_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp0_fck", "l3s_clkdm" }, + { AM3_UART6_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM3_MMC1_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" }, + { AM3_ELM_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM3_I2C3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM3_I2C2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM3_SPI0_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM3_SPI1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM3_L4_LS_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM3_MCASP1_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp1_fck", "l3s_clkdm" }, + { AM3_UART2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM3_UART3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM3_UART4_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM3_UART5_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM3_TIMER7_CLKCTRL, NULL, CLKF_SW_SUP, "timer7_fck" }, + { AM3_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "timer2_fck" }, + { AM3_TIMER3_CLKCTRL, NULL, CLKF_SW_SUP, "timer3_fck" }, + { AM3_TIMER4_CLKCTRL, NULL, CLKF_SW_SUP, "timer4_fck" }, + { AM3_RNG_CLKCTRL, NULL, CLKF_SW_SUP, "rng_fck" }, + { AM3_AES_CLKCTRL, NULL, CLKF_SW_SUP, "aes0_fck", "l3_clkdm" }, + { AM3_SHAM_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" }, + { AM3_GPIO2_CLKCTRL, am3_gpio2_bit_data, CLKF_SW_SUP, "l4ls_gclk" }, + { AM3_GPIO3_CLKCTRL, am3_gpio3_bit_data, CLKF_SW_SUP, "l4ls_gclk" }, + { AM3_GPIO4_CLKCTRL, am3_gpio4_bit_data, CLKF_SW_SUP, "l4ls_gclk" }, + { AM3_TPCC_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" }, + { AM3_D_CAN0_CLKCTRL, NULL, CLKF_SW_SUP, "dcan0_fck" }, + { AM3_D_CAN1_CLKCTRL, NULL, CLKF_SW_SUP, "dcan1_fck" }, + { AM3_EPWMSS1_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM3_EPWMSS0_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM3_EPWMSS2_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM3_L3_INSTR_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" }, + { AM3_L3_MAIN_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" }, + { AM3_PRUSS_CLKCTRL, NULL, CLKF_SW_SUP, "pruss_ocp_gclk", "pruss_ocp_clkdm" }, + { AM3_TIMER5_CLKCTRL, NULL, CLKF_SW_SUP, "timer5_fck" }, + { AM3_TIMER6_CLKCTRL, NULL, CLKF_SW_SUP, "timer6_fck" }, + { AM3_MMC2_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" }, + { AM3_MMC3_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk", "l3s_clkdm" }, + { AM3_TPTC1_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" }, + { AM3_TPTC2_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" }, + { AM3_SPINLOCK_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM3_MAILBOX_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM3_L4_HS_CLKCTRL, NULL, CLKF_SW_SUP, "l4hs_gclk", "l4hs_clkdm" }, + { AM3_OCPWP_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM3_CLKDIV32K_CLKCTRL, NULL, CLKF_SW_SUP, "clkdiv32k_ck", "clk_24mhz_clkdm" }, + { 0 }, +}; + +static const char * const am3_gpio0_dbclk_parents[] __initconst = { + "gpio0_dbclk_mux_ck", + NULL, +}; + +static const struct omap_clkctrl_bit_data am3_gpio1_bit_data[] __initconst = { + { 18, TI_CLK_GATE, am3_gpio0_dbclk_parents, NULL }, + { 0 }, +}; + +static const char * const am3_dbg_sysclk_ck_parents[] __initconst = { + "sys_clkin_ck", + NULL, +}; + +static const char * const am3_trace_pmd_clk_mux_ck_parents[] __initconst = { + "l4_wkup_cm:clk:0010:19", + "l4_wkup_cm:clk:0010:30", + NULL, +}; + +static const char * const am3_trace_clk_div_ck_parents[] __initconst = { + "l4_wkup_cm:clk:0010:20", + NULL, +}; + +static const struct omap_clkctrl_div_data am3_trace_clk_div_ck_data __initconst = { + .max_div = 64, + .flags = CLK_DIVIDER_POWER_OF_TWO, +}; + +static const char * const am3_stm_clk_div_ck_parents[] __initconst = { + "l4_wkup_cm:clk:0010:22", + NULL, +}; + +static const struct omap_clkctrl_div_data am3_stm_clk_div_ck_data __initconst = { + .max_div = 64, + .flags = CLK_DIVIDER_POWER_OF_TWO, +}; + +static const char * const am3_dbg_clka_ck_parents[] __initconst = { + "dpll_core_m4_ck", + NULL, +}; + +static const struct omap_clkctrl_bit_data am3_debugss_bit_data[] __initconst = { + { 19, TI_CLK_GATE, am3_dbg_sysclk_ck_parents, NULL }, + { 20, TI_CLK_MUX, am3_trace_pmd_clk_mux_ck_parents, NULL }, + { 22, TI_CLK_MUX, am3_trace_pmd_clk_mux_ck_parents, NULL }, + { 24, TI_CLK_DIVIDER, am3_trace_clk_div_ck_parents, &am3_trace_clk_div_ck_data }, + { 27, TI_CLK_DIVIDER, am3_stm_clk_div_ck_parents, &am3_stm_clk_div_ck_data }, + { 30, TI_CLK_GATE, am3_dbg_clka_ck_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data am3_l4_wkup_clkctrl_regs[] __initconst = { + { AM3_CONTROL_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_core_m4_div2_ck" }, + { AM3_GPIO1_CLKCTRL, am3_gpio1_bit_data, CLKF_SW_SUP, "dpll_core_m4_div2_ck" }, + { AM3_L4_WKUP_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_core_m4_div2_ck" }, + { AM3_DEBUGSS_CLKCTRL, am3_debugss_bit_data, CLKF_SW_SUP, "l4_wkup_cm:clk:0010:24", "l3_aon_clkdm" }, + { AM3_WKUP_M3_CLKCTRL, NULL, CLKF_NO_IDLEST, "dpll_core_m4_div2_ck", "l4_wkup_aon_clkdm" }, + { AM3_UART1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_wkupdm_ck" }, + { AM3_I2C1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_wkupdm_ck" }, + { AM3_ADC_TSC_CLKCTRL, NULL, CLKF_SW_SUP, "adc_tsc_fck" }, + { AM3_SMARTREFLEX0_CLKCTRL, NULL, CLKF_SW_SUP, "smartreflex0_fck" }, + { AM3_TIMER1_CLKCTRL, NULL, CLKF_SW_SUP, "timer1_fck" }, + { AM3_SMARTREFLEX1_CLKCTRL, NULL, CLKF_SW_SUP, "smartreflex1_fck" }, + { AM3_WD_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "wdt1_fck" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data am3_mpu_clkctrl_regs[] __initconst = { + { AM3_MPU_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_mpu_m2_ck" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data am3_l4_rtc_clkctrl_regs[] __initconst = { + { AM3_RTC_CLKCTRL, NULL, CLKF_SW_SUP, "clk_32768_ck" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data am3_gfx_l3_clkctrl_regs[] __initconst = { + { AM3_GFX_CLKCTRL, NULL, CLKF_SW_SUP, "gfx_fck_div_ck" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data am3_l4_cefuse_clkctrl_regs[] __initconst = { + { AM3_CEFUSE_CLKCTRL, NULL, CLKF_SW_SUP, "sys_clkin_ck" }, + { 0 }, +}; + +const struct omap_clkctrl_data am3_clkctrl_data[] __initconst = { + { 0x44e00014, am3_l4_per_clkctrl_regs }, + { 0x44e00404, am3_l4_wkup_clkctrl_regs }, + { 0x44e00604, am3_mpu_clkctrl_regs }, + { 0x44e00800, am3_l4_rtc_clkctrl_regs }, + { 0x44e00904, am3_gfx_l3_clkctrl_regs }, + { 0x44e00a20, am3_l4_cefuse_clkctrl_regs }, + { 0 }, +}; + static struct ti_dt_clk am33xx_clks[] = { - DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"), - DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"), - DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), - DT_CLK(NULL, "virt_24000000_ck", "virt_24000000_ck"), - DT_CLK(NULL, "virt_25000000_ck", "virt_25000000_ck"), - DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), - DT_CLK(NULL, "sys_clkin_ck", "sys_clkin_ck"), - DT_CLK(NULL, "tclkin_ck", "tclkin_ck"), - DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), - DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), - DT_CLK(NULL, "dpll_core_m4_ck", "dpll_core_m4_ck"), - DT_CLK(NULL, "dpll_core_m5_ck", "dpll_core_m5_ck"), - DT_CLK(NULL, "dpll_core_m6_ck", "dpll_core_m6_ck"), - DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), - DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), - DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"), - DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"), - DT_CLK(NULL, "dpll_ddr_m2_div2_ck", "dpll_ddr_m2_div2_ck"), - DT_CLK(NULL, "dpll_disp_ck", "dpll_disp_ck"), - DT_CLK(NULL, "dpll_disp_m2_ck", "dpll_disp_m2_ck"), - DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), - DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), - DT_CLK(NULL, "dpll_per_m2_div4_wkupdm_ck", "dpll_per_m2_div4_wkupdm_ck"), - DT_CLK(NULL, "dpll_per_m2_div4_ck", "dpll_per_m2_div4_ck"), - DT_CLK(NULL, "adc_tsc_fck", "adc_tsc_fck"), - DT_CLK(NULL, "cefuse_fck", "cefuse_fck"), - DT_CLK(NULL, "clkdiv32k_ck", "clkdiv32k_ck"), - DT_CLK(NULL, "clkdiv32k_ick", "clkdiv32k_ick"), - DT_CLK(NULL, "dcan0_fck", "dcan0_fck"), - DT_CLK("481cc000.d_can", NULL, "dcan0_fck"), - DT_CLK(NULL, "dcan1_fck", "dcan1_fck"), - DT_CLK("481d0000.d_can", NULL, "dcan1_fck"), - DT_CLK(NULL, "pruss_ocp_gclk", "pruss_ocp_gclk"), - DT_CLK(NULL, "mcasp0_fck", "mcasp0_fck"), - DT_CLK(NULL, "mcasp1_fck", "mcasp1_fck"), - DT_CLK(NULL, "mmu_fck", "mmu_fck"), - DT_CLK(NULL, "smartreflex0_fck", "smartreflex0_fck"), - DT_CLK(NULL, "smartreflex1_fck", "smartreflex1_fck"), - DT_CLK(NULL, "sha0_fck", "sha0_fck"), - DT_CLK(NULL, "aes0_fck", "aes0_fck"), - DT_CLK(NULL, "rng_fck", "rng_fck"), - DT_CLK(NULL, "timer1_fck", "timer1_fck"), - DT_CLK(NULL, "timer2_fck", "timer2_fck"), - DT_CLK(NULL, "timer3_fck", "timer3_fck"), - DT_CLK(NULL, "timer4_fck", "timer4_fck"), - DT_CLK(NULL, "timer5_fck", "timer5_fck"), - DT_CLK(NULL, "timer6_fck", "timer6_fck"), - DT_CLK(NULL, "timer7_fck", "timer7_fck"), - DT_CLK(NULL, "usbotg_fck", "usbotg_fck"), - DT_CLK(NULL, "ieee5000_fck", "ieee5000_fck"), - DT_CLK(NULL, "wdt1_fck", "wdt1_fck"), - DT_CLK(NULL, "l4_rtc_gclk", "l4_rtc_gclk"), - DT_CLK(NULL, "l3_gclk", "l3_gclk"), - DT_CLK(NULL, "dpll_core_m4_div2_ck", "dpll_core_m4_div2_ck"), - DT_CLK(NULL, "l4hs_gclk", "l4hs_gclk"), - DT_CLK(NULL, "l3s_gclk", "l3s_gclk"), - DT_CLK(NULL, "l4fw_gclk", "l4fw_gclk"), - DT_CLK(NULL, "l4ls_gclk", "l4ls_gclk"), - DT_CLK(NULL, "clk_24mhz", "clk_24mhz"), - DT_CLK(NULL, "sysclk_div_ck", "sysclk_div_ck"), - DT_CLK(NULL, "cpsw_125mhz_gclk", "cpsw_125mhz_gclk"), - DT_CLK(NULL, "cpsw_cpts_rft_clk", "cpsw_cpts_rft_clk"), - DT_CLK(NULL, "gpio0_dbclk_mux_ck", "gpio0_dbclk_mux_ck"), - DT_CLK(NULL, "gpio0_dbclk", "gpio0_dbclk"), - DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), - DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), - DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), - DT_CLK(NULL, "lcd_gclk", "lcd_gclk"), - DT_CLK(NULL, "mmc_clk", "mmc_clk"), - DT_CLK(NULL, "gfx_fclk_clksel_ck", "gfx_fclk_clksel_ck"), - DT_CLK(NULL, "gfx_fck_div_ck", "gfx_fck_div_ck"), - DT_CLK(NULL, "sysclkout_pre_ck", "sysclkout_pre_ck"), - DT_CLK(NULL, "clkout2_div_ck", "clkout2_div_ck"), - DT_CLK(NULL, "timer_32k_ck", "clkdiv32k_ick"), + DT_CLK(NULL, "timer_32k_ck", "l4_per_cm:0138:0"), DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"), - DT_CLK(NULL, "dbg_sysclk_ck", "dbg_sysclk_ck"), - DT_CLK(NULL, "dbg_clka_ck", "dbg_clka_ck"), - DT_CLK(NULL, "stm_pmd_clock_mux_ck", "stm_pmd_clock_mux_ck"), - DT_CLK(NULL, "trace_pmd_clk_mux_ck", "trace_pmd_clk_mux_ck"), - DT_CLK(NULL, "stm_clk_div_ck", "stm_clk_div_ck"), - DT_CLK(NULL, "trace_clk_div_ck", "trace_clk_div_ck"), - DT_CLK(NULL, "clkout2_ck", "clkout2_ck"), - DT_CLK("48300200.ehrpwm", "tbclk", "ehrpwm0_tbclk"), - DT_CLK("48302200.ehrpwm", "tbclk", "ehrpwm1_tbclk"), - DT_CLK("48304200.ehrpwm", "tbclk", "ehrpwm2_tbclk"), - DT_CLK("48300200.pwm", "tbclk", "ehrpwm0_tbclk"), - DT_CLK("48302200.pwm", "tbclk", "ehrpwm1_tbclk"), - DT_CLK("48304200.pwm", "tbclk", "ehrpwm2_tbclk"), + DT_CLK(NULL, "clkdiv32k_ick", "l4_per_cm:0138:0"), + DT_CLK(NULL, "dbg_clka_ck", "l4_wkup_cm:0010:30"), + DT_CLK(NULL, "dbg_sysclk_ck", "l4_wkup_cm:0010:19"), + DT_CLK(NULL, "gpio0_dbclk", "l4_wkup_cm:0004:18"), + DT_CLK(NULL, "gpio1_dbclk", "l4_per_cm:0098:18"), + DT_CLK(NULL, "gpio2_dbclk", "l4_per_cm:009c:18"), + DT_CLK(NULL, "gpio3_dbclk", "l4_per_cm:00a0:18"), + DT_CLK(NULL, "stm_clk_div_ck", "l4_wkup_cm:0010:27"), + DT_CLK(NULL, "stm_pmd_clock_mux_ck", "l4_wkup_cm:0010:22"), + DT_CLK(NULL, "trace_clk_div_ck", "l4_wkup_cm:0010:24"), + DT_CLK(NULL, "trace_pmd_clk_mux_ck", "l4_wkup_cm:0010:20"), { .node_name = NULL }, }; @@ -133,6 +236,8 @@ int __init am33xx_dt_clk_init(void) omap2_clk_disable_autoidle_all(); + ti_clk_add_aliases(); + omap2_clk_enable_init_clocks(enable_init_clks, ARRAY_SIZE(enable_init_clks)); diff --git a/drivers/clk/ti/clk-3xxx-legacy.c b/drivers/clk/ti/clk-3xxx-legacy.c deleted file mode 100644 index 0fbf8a917955..000000000000 --- a/drivers/clk/ti/clk-3xxx-legacy.c +++ /dev/null @@ -1,4656 +0,0 @@ -/* - * OMAP3 Legacy clock data - * - * Copyright (C) 2014 Texas Instruments, Inc - * Tero Kristo (t-kristo@ti.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include - -#include "clock.h" - -static struct ti_clk_fixed virt_12m_ck_data = { - .frequency = 12000000, -}; - -static struct ti_clk virt_12m_ck = { - .name = "virt_12m_ck", - .type = TI_CLK_FIXED, - .data = &virt_12m_ck_data, -}; - -static struct ti_clk_fixed virt_13m_ck_data = { - .frequency = 13000000, -}; - -static struct ti_clk virt_13m_ck = { - .name = "virt_13m_ck", - .type = TI_CLK_FIXED, - .data = &virt_13m_ck_data, -}; - -static struct ti_clk_fixed virt_19200000_ck_data = { - .frequency = 19200000, -}; - -static struct ti_clk virt_19200000_ck = { - .name = "virt_19200000_ck", - .type = TI_CLK_FIXED, - .data = &virt_19200000_ck_data, -}; - -static struct ti_clk_fixed virt_26000000_ck_data = { - .frequency = 26000000, -}; - -static struct ti_clk virt_26000000_ck = { - .name = "virt_26000000_ck", - .type = TI_CLK_FIXED, - .data = &virt_26000000_ck_data, -}; - -static struct ti_clk_fixed virt_38_4m_ck_data = { - .frequency = 38400000, -}; - -static struct ti_clk virt_38_4m_ck = { - .name = "virt_38_4m_ck", - .type = TI_CLK_FIXED, - .data = &virt_38_4m_ck_data, -}; - -static struct ti_clk_fixed virt_16_8m_ck_data = { - .frequency = 16800000, -}; - -static struct ti_clk virt_16_8m_ck = { - .name = "virt_16_8m_ck", - .type = TI_CLK_FIXED, - .data = &virt_16_8m_ck_data, -}; - -static const char *osc_sys_ck_parents[] = { - "virt_12m_ck", - "virt_13m_ck", - "virt_19200000_ck", - "virt_26000000_ck", - "virt_38_4m_ck", - "virt_16_8m_ck", -}; - -static struct ti_clk_mux osc_sys_ck_data = { - .num_parents = ARRAY_SIZE(osc_sys_ck_parents), - .reg = 0xd40, - .module = TI_CLKM_PRM, - .parents = osc_sys_ck_parents, -}; - -static struct ti_clk osc_sys_ck = { - .name = "osc_sys_ck", - .type = TI_CLK_MUX, - .data = &osc_sys_ck_data, -}; - -static struct ti_clk_divider sys_ck_data = { - .parent = "osc_sys_ck", - .bit_shift = 6, - .max_div = 3, - .reg = 0x1270, - .module = TI_CLKM_PRM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk sys_ck = { - .name = "sys_ck", - .type = TI_CLK_DIVIDER, - .data = &sys_ck_data, -}; - -static const char *dpll3_ck_parents[] = { - "sys_ck", - "sys_ck", -}; - -static struct ti_clk_dpll dpll3_ck_data = { - .num_parents = ARRAY_SIZE(dpll3_ck_parents), - .control_reg = 0xd00, - .idlest_reg = 0xd20, - .mult_div1_reg = 0xd40, - .autoidle_reg = 0xd30, - .module = TI_CLKM_CM, - .parents = dpll3_ck_parents, - .flags = CLKF_CORE, - .freqsel_mask = 0xf0, - .div1_mask = 0x7f00, - .idlest_mask = 0x1, - .auto_recal_bit = 0x3, - .max_divider = 0x80, - .min_divider = 0x1, - .recal_en_bit = 0x5, - .max_multiplier = 0x7ff, - .enable_mask = 0x7, - .mult_mask = 0x7ff0000, - .recal_st_bit = 0x5, - .autoidle_mask = 0x7, -}; - -static struct ti_clk dpll3_ck = { - .name = "dpll3_ck", - .clkdm_name = "dpll3_clkdm", - .type = TI_CLK_DPLL, - .data = &dpll3_ck_data, -}; - -static struct ti_clk_divider dpll3_m2_ck_data = { - .parent = "dpll3_ck", - .bit_shift = 27, - .max_div = 31, - .reg = 0xd40, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk dpll3_m2_ck = { - .name = "dpll3_m2_ck", - .type = TI_CLK_DIVIDER, - .data = &dpll3_m2_ck_data, -}; - -static struct ti_clk_fixed_factor core_ck_data = { - .parent = "dpll3_m2_ck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk core_ck = { - .name = "core_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &core_ck_data, -}; - -static struct ti_clk_divider l3_ick_data = { - .parent = "core_ck", - .max_div = 3, - .reg = 0xa40, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk l3_ick = { - .name = "l3_ick", - .type = TI_CLK_DIVIDER, - .data = &l3_ick_data, -}; - -static struct ti_clk_fixed_factor security_l3_ick_data = { - .parent = "l3_ick", - .div = 1, - .mult = 1, -}; - -static struct ti_clk security_l3_ick = { - .name = "security_l3_ick", - .type = TI_CLK_FIXED_FACTOR, - .data = &security_l3_ick_data, -}; - -static struct ti_clk_fixed_factor wkup_l4_ick_data = { - .parent = "sys_ck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk wkup_l4_ick = { - .name = "wkup_l4_ick", - .type = TI_CLK_FIXED_FACTOR, - .data = &wkup_l4_ick_data, -}; - -static struct ti_clk_gate usim_ick_data = { - .parent = "wkup_l4_ick", - .bit_shift = 9, - .reg = 0xc10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk usim_ick = { - .name = "usim_ick", - .clkdm_name = "wkup_clkdm", - .type = TI_CLK_GATE, - .data = &usim_ick_data, -}; - -static struct ti_clk_gate dss2_alwon_fck_data = { - .parent = "sys_ck", - .bit_shift = 1, - .reg = 0xe00, - .module = TI_CLKM_CM, -}; - -static struct ti_clk dss2_alwon_fck = { - .name = "dss2_alwon_fck", - .clkdm_name = "dss_clkdm", - .type = TI_CLK_GATE, - .data = &dss2_alwon_fck_data, -}; - -static struct ti_clk_divider l4_ick_data = { - .parent = "l3_ick", - .bit_shift = 2, - .max_div = 3, - .reg = 0xa40, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk l4_ick = { - .name = "l4_ick", - .type = TI_CLK_DIVIDER, - .data = &l4_ick_data, -}; - -static struct ti_clk_fixed_factor core_l4_ick_data = { - .parent = "l4_ick", - .div = 1, - .mult = 1, -}; - -static struct ti_clk core_l4_ick = { - .name = "core_l4_ick", - .type = TI_CLK_FIXED_FACTOR, - .data = &core_l4_ick_data, -}; - -static struct ti_clk_gate mmchs2_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 25, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk mmchs2_ick = { - .name = "mmchs2_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mmchs2_ick_data, -}; - -static const char *dpll4_ck_parents[] = { - "sys_ck", - "sys_ck", -}; - -static struct ti_clk_dpll dpll4_ck_data = { - .num_parents = ARRAY_SIZE(dpll4_ck_parents), - .control_reg = 0xd00, - .idlest_reg = 0xd20, - .mult_div1_reg = 0xd44, - .autoidle_reg = 0xd30, - .module = TI_CLKM_CM, - .parents = dpll4_ck_parents, - .flags = CLKF_PER, - .freqsel_mask = 0xf00000, - .modes = 0x82, - .div1_mask = 0x7f, - .idlest_mask = 0x2, - .auto_recal_bit = 0x13, - .max_divider = 0x80, - .min_divider = 0x1, - .recal_en_bit = 0x6, - .max_multiplier = 0x7ff, - .enable_mask = 0x70000, - .mult_mask = 0x7ff00, - .recal_st_bit = 0x6, - .autoidle_mask = 0x38, -}; - -static struct ti_clk dpll4_ck = { - .name = "dpll4_ck", - .clkdm_name = "dpll4_clkdm", - .type = TI_CLK_DPLL, - .data = &dpll4_ck_data, -}; - -static struct ti_clk_divider dpll4_m2_ck_data = { - .parent = "dpll4_ck", - .max_div = 63, - .reg = 0xd48, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk dpll4_m2_ck = { - .name = "dpll4_m2_ck", - .type = TI_CLK_DIVIDER, - .data = &dpll4_m2_ck_data, -}; - -static struct ti_clk_fixed_factor dpll4_m2x2_mul_ck_data = { - .parent = "dpll4_m2_ck", - .div = 1, - .mult = 2, -}; - -static struct ti_clk dpll4_m2x2_mul_ck = { - .name = "dpll4_m2x2_mul_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &dpll4_m2x2_mul_ck_data, -}; - -static struct ti_clk_gate dpll4_m2x2_ck_data = { - .parent = "dpll4_m2x2_mul_ck", - .bit_shift = 0x1b, - .reg = 0xd00, - .module = TI_CLKM_CM, - .flags = CLKF_SET_BIT_TO_DISABLE, -}; - -static struct ti_clk dpll4_m2x2_ck = { - .name = "dpll4_m2x2_ck", - .type = TI_CLK_GATE, - .data = &dpll4_m2x2_ck_data, -}; - -static struct ti_clk_fixed_factor omap_96m_alwon_fck_data = { - .parent = "dpll4_m2x2_ck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk omap_96m_alwon_fck = { - .name = "omap_96m_alwon_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &omap_96m_alwon_fck_data, -}; - -static struct ti_clk_fixed_factor cm_96m_fck_data = { - .parent = "omap_96m_alwon_fck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk cm_96m_fck = { - .name = "cm_96m_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &cm_96m_fck_data, -}; - -static const char *omap_96m_fck_parents[] = { - "cm_96m_fck", - "sys_ck", -}; - -static struct ti_clk_mux omap_96m_fck_data = { - .bit_shift = 6, - .num_parents = ARRAY_SIZE(omap_96m_fck_parents), - .reg = 0xd40, - .module = TI_CLKM_CM, - .parents = omap_96m_fck_parents, -}; - -static struct ti_clk omap_96m_fck = { - .name = "omap_96m_fck", - .type = TI_CLK_MUX, - .data = &omap_96m_fck_data, -}; - -static struct ti_clk_fixed_factor core_96m_fck_data = { - .parent = "omap_96m_fck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk core_96m_fck = { - .name = "core_96m_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &core_96m_fck_data, -}; - -static struct ti_clk_gate mspro_fck_data = { - .parent = "core_96m_fck", - .bit_shift = 23, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk mspro_fck = { - .name = "mspro_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mspro_fck_data, -}; - -static struct ti_clk_gate dss_ick_3430es2_data = { - .parent = "l4_ick", - .bit_shift = 0, - .reg = 0xe10, - .module = TI_CLKM_CM, - .flags = CLKF_DSS | CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk dss_ick_3430es2 = { - .name = "dss_ick", - .clkdm_name = "dss_clkdm", - .type = TI_CLK_GATE, - .data = &dss_ick_3430es2_data, -}; - -static struct ti_clk_gate uart4_ick_am35xx_data = { - .parent = "core_l4_ick", - .bit_shift = 23, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk uart4_ick_am35xx = { - .name = "uart4_ick_am35xx", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &uart4_ick_am35xx_data, -}; - -static struct ti_clk_fixed_factor security_l4_ick2_data = { - .parent = "l4_ick", - .div = 1, - .mult = 1, -}; - -static struct ti_clk security_l4_ick2 = { - .name = "security_l4_ick2", - .type = TI_CLK_FIXED_FACTOR, - .data = &security_l4_ick2_data, -}; - -static struct ti_clk_gate aes1_ick_data = { - .parent = "security_l4_ick2", - .bit_shift = 3, - .reg = 0xa14, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk aes1_ick = { - .name = "aes1_ick", - .type = TI_CLK_GATE, - .data = &aes1_ick_data, -}; - -static const char *dpll5_ck_parents[] = { - "sys_ck", - "sys_ck", -}; - -static struct ti_clk_dpll dpll5_ck_data = { - .num_parents = ARRAY_SIZE(dpll5_ck_parents), - .control_reg = 0xd04, - .idlest_reg = 0xd24, - .mult_div1_reg = 0xd4c, - .autoidle_reg = 0xd34, - .module = TI_CLKM_CM, - .parents = dpll5_ck_parents, - .freqsel_mask = 0xf0, - .modes = 0x82, - .div1_mask = 0x7f, - .idlest_mask = 0x1, - .auto_recal_bit = 0x3, - .max_divider = 0x80, - .min_divider = 0x1, - .recal_en_bit = 0x19, - .max_multiplier = 0x7ff, - .enable_mask = 0x7, - .mult_mask = 0x7ff00, - .recal_st_bit = 0x19, - .autoidle_mask = 0x7, -}; - -static struct ti_clk dpll5_ck = { - .name = "dpll5_ck", - .clkdm_name = "dpll5_clkdm", - .type = TI_CLK_DPLL, - .data = &dpll5_ck_data, -}; - -static struct ti_clk_divider dpll5_m2_ck_data = { - .parent = "dpll5_ck", - .max_div = 31, - .reg = 0xd50, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk dpll5_m2_ck = { - .name = "dpll5_m2_ck", - .type = TI_CLK_DIVIDER, - .data = &dpll5_m2_ck_data, -}; - -static struct ti_clk_gate usbhost_120m_fck_data = { - .parent = "dpll5_m2_ck", - .bit_shift = 1, - .reg = 0x1400, - .module = TI_CLKM_CM, -}; - -static struct ti_clk usbhost_120m_fck = { - .name = "usbhost_120m_fck", - .clkdm_name = "usbhost_clkdm", - .type = TI_CLK_GATE, - .data = &usbhost_120m_fck_data, -}; - -static struct ti_clk_fixed_factor cm_96m_d2_fck_data = { - .parent = "cm_96m_fck", - .div = 2, - .mult = 1, -}; - -static struct ti_clk cm_96m_d2_fck = { - .name = "cm_96m_d2_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &cm_96m_d2_fck_data, -}; - -static struct ti_clk_fixed sys_altclk_data = { - .frequency = 0x0, -}; - -static struct ti_clk sys_altclk = { - .name = "sys_altclk", - .type = TI_CLK_FIXED, - .data = &sys_altclk_data, -}; - -static const char *omap_48m_fck_parents[] = { - "cm_96m_d2_fck", - "sys_altclk", -}; - -static struct ti_clk_mux omap_48m_fck_data = { - .bit_shift = 3, - .num_parents = ARRAY_SIZE(omap_48m_fck_parents), - .reg = 0xd40, - .module = TI_CLKM_CM, - .parents = omap_48m_fck_parents, -}; - -static struct ti_clk omap_48m_fck = { - .name = "omap_48m_fck", - .type = TI_CLK_MUX, - .data = &omap_48m_fck_data, -}; - -static struct ti_clk_fixed_factor core_48m_fck_data = { - .parent = "omap_48m_fck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk core_48m_fck = { - .name = "core_48m_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &core_48m_fck_data, -}; - -static struct ti_clk_fixed mcbsp_clks_data = { - .frequency = 0x0, -}; - -static struct ti_clk mcbsp_clks = { - .name = "mcbsp_clks", - .type = TI_CLK_FIXED, - .data = &mcbsp_clks_data, -}; - -static struct ti_clk_gate mcbsp2_gate_fck_data = { - .parent = "mcbsp_clks", - .bit_shift = 0, - .reg = 0x1000, - .module = TI_CLKM_CM, -}; - -static struct ti_clk_fixed_factor per_96m_fck_data = { - .parent = "omap_96m_alwon_fck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk per_96m_fck = { - .name = "per_96m_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &per_96m_fck_data, -}; - -static const char *mcbsp2_mux_fck_parents[] = { - "per_96m_fck", - "mcbsp_clks", -}; - -static struct ti_clk_mux mcbsp2_mux_fck_data = { - .bit_shift = 6, - .num_parents = ARRAY_SIZE(mcbsp2_mux_fck_parents), - .reg = 0x274, - .module = TI_CLKM_SCRM, - .parents = mcbsp2_mux_fck_parents, -}; - -static struct ti_clk_composite mcbsp2_fck_data = { - .mux = &mcbsp2_mux_fck_data, - .gate = &mcbsp2_gate_fck_data, -}; - -static struct ti_clk mcbsp2_fck = { - .name = "mcbsp2_fck", - .type = TI_CLK_COMPOSITE, - .data = &mcbsp2_fck_data, -}; - -static struct ti_clk_fixed_factor dpll3_m2x2_ck_data = { - .parent = "dpll3_m2_ck", - .div = 1, - .mult = 2, -}; - -static struct ti_clk dpll3_m2x2_ck = { - .name = "dpll3_m2x2_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &dpll3_m2x2_ck_data, -}; - -static struct ti_clk_fixed_factor corex2_fck_data = { - .parent = "dpll3_m2x2_ck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk corex2_fck = { - .name = "corex2_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &corex2_fck_data, -}; - -static struct ti_clk_gate ssi_ssr_gate_fck_3430es1_data = { - .parent = "corex2_fck", - .bit_shift = 0, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_NO_WAIT, -}; - -static int ssi_ssr_div_fck_3430es1_divs[] = { - 0, - 1, - 2, - 3, - 4, - 0, - 6, - 0, - 8, -}; - -static struct ti_clk_divider ssi_ssr_div_fck_3430es1_data = { - .num_dividers = ARRAY_SIZE(ssi_ssr_div_fck_3430es1_divs), - .parent = "corex2_fck", - .bit_shift = 8, - .dividers = ssi_ssr_div_fck_3430es1_divs, - .reg = 0xa40, - .module = TI_CLKM_CM, -}; - -static struct ti_clk_composite ssi_ssr_fck_3430es1_data = { - .gate = &ssi_ssr_gate_fck_3430es1_data, - .divider = &ssi_ssr_div_fck_3430es1_data, -}; - -static struct ti_clk ssi_ssr_fck_3430es1 = { - .name = "ssi_ssr_fck", - .type = TI_CLK_COMPOSITE, - .data = &ssi_ssr_fck_3430es1_data, -}; - -static struct ti_clk_fixed_factor ssi_sst_fck_3430es1_data = { - .parent = "ssi_ssr_fck", - .div = 2, - .mult = 1, -}; - -static struct ti_clk ssi_sst_fck_3430es1 = { - .name = "ssi_sst_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &ssi_sst_fck_3430es1_data, -}; - -static struct ti_clk_fixed omap_32k_fck_data = { - .frequency = 32768, -}; - -static struct ti_clk omap_32k_fck = { - .name = "omap_32k_fck", - .type = TI_CLK_FIXED, - .data = &omap_32k_fck_data, -}; - -static struct ti_clk_fixed_factor per_32k_alwon_fck_data = { - .parent = "omap_32k_fck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk per_32k_alwon_fck = { - .name = "per_32k_alwon_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &per_32k_alwon_fck_data, -}; - -static struct ti_clk_gate gpio5_dbck_data = { - .parent = "per_32k_alwon_fck", - .bit_shift = 16, - .reg = 0x1000, - .module = TI_CLKM_CM, -}; - -static struct ti_clk gpio5_dbck = { - .name = "gpio5_dbck", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpio5_dbck_data, -}; - -static struct ti_clk_gate gpt1_ick_data = { - .parent = "wkup_l4_ick", - .bit_shift = 0, - .reg = 0xc10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpt1_ick = { - .name = "gpt1_ick", - .clkdm_name = "wkup_clkdm", - .type = TI_CLK_GATE, - .data = &gpt1_ick_data, -}; - -static struct ti_clk_gate mcspi3_fck_data = { - .parent = "core_48m_fck", - .bit_shift = 20, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk mcspi3_fck = { - .name = "mcspi3_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mcspi3_fck_data, -}; - -static struct ti_clk_gate gpt2_gate_fck_data = { - .parent = "sys_ck", - .bit_shift = 3, - .reg = 0x1000, - .module = TI_CLKM_CM, -}; - -static const char *gpt2_mux_fck_parents[] = { - "omap_32k_fck", - "sys_ck", -}; - -static struct ti_clk_mux gpt2_mux_fck_data = { - .num_parents = ARRAY_SIZE(gpt2_mux_fck_parents), - .reg = 0x1040, - .module = TI_CLKM_CM, - .parents = gpt2_mux_fck_parents, -}; - -static struct ti_clk_composite gpt2_fck_data = { - .mux = &gpt2_mux_fck_data, - .gate = &gpt2_gate_fck_data, -}; - -static struct ti_clk gpt2_fck = { - .name = "gpt2_fck", - .type = TI_CLK_COMPOSITE, - .data = &gpt2_fck_data, -}; - -static struct ti_clk_gate gpt10_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 11, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpt10_ick = { - .name = "gpt10_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &gpt10_ick_data, -}; - -static struct ti_clk_gate uart2_fck_data = { - .parent = "core_48m_fck", - .bit_shift = 14, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk uart2_fck = { - .name = "uart2_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &uart2_fck_data, -}; - -static struct ti_clk_fixed_factor sr_l4_ick_data = { - .parent = "l4_ick", - .div = 1, - .mult = 1, -}; - -static struct ti_clk sr_l4_ick = { - .name = "sr_l4_ick", - .type = TI_CLK_FIXED_FACTOR, - .data = &sr_l4_ick_data, -}; - -static struct ti_clk_fixed_factor omap_96m_d8_fck_data = { - .parent = "omap_96m_fck", - .div = 8, - .mult = 1, -}; - -static struct ti_clk omap_96m_d8_fck = { - .name = "omap_96m_d8_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &omap_96m_d8_fck_data, -}; - -static struct ti_clk_divider dpll4_m5_ck_data = { - .parent = "dpll4_ck", - .max_div = 63, - .reg = 0xf40, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk dpll4_m5_ck = { - .name = "dpll4_m5_ck", - .type = TI_CLK_DIVIDER, - .data = &dpll4_m5_ck_data, -}; - -static struct ti_clk_fixed_factor dpll4_m5x2_mul_ck_data = { - .parent = "dpll4_m5_ck", - .div = 1, - .mult = 2, - .flags = CLKF_SET_RATE_PARENT, -}; - -static struct ti_clk dpll4_m5x2_mul_ck = { - .name = "dpll4_m5x2_mul_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &dpll4_m5x2_mul_ck_data, -}; - -static struct ti_clk_gate dpll4_m5x2_ck_data = { - .parent = "dpll4_m5x2_mul_ck", - .bit_shift = 0x1e, - .reg = 0xd00, - .module = TI_CLKM_CM, - .flags = CLKF_SET_BIT_TO_DISABLE, -}; - -static struct ti_clk dpll4_m5x2_ck = { - .name = "dpll4_m5x2_ck", - .type = TI_CLK_GATE, - .data = &dpll4_m5x2_ck_data, -}; - -static struct ti_clk_gate cam_mclk_data = { - .parent = "dpll4_m5x2_ck", - .bit_shift = 0, - .reg = 0xf00, - .module = TI_CLKM_CM, - .flags = CLKF_SET_RATE_PARENT, -}; - -static struct ti_clk cam_mclk = { - .name = "cam_mclk", - .type = TI_CLK_GATE, - .data = &cam_mclk_data, -}; - -static struct ti_clk_gate mcbsp3_gate_fck_data = { - .parent = "mcbsp_clks", - .bit_shift = 1, - .reg = 0x1000, - .module = TI_CLKM_CM, -}; - -static const char *mcbsp3_mux_fck_parents[] = { - "per_96m_fck", - "mcbsp_clks", -}; - -static struct ti_clk_mux mcbsp3_mux_fck_data = { - .num_parents = ARRAY_SIZE(mcbsp3_mux_fck_parents), - .reg = 0x2d8, - .module = TI_CLKM_SCRM, - .parents = mcbsp3_mux_fck_parents, -}; - -static struct ti_clk_composite mcbsp3_fck_data = { - .mux = &mcbsp3_mux_fck_data, - .gate = &mcbsp3_gate_fck_data, -}; - -static struct ti_clk mcbsp3_fck = { - .name = "mcbsp3_fck", - .type = TI_CLK_COMPOSITE, - .data = &mcbsp3_fck_data, -}; - -static struct ti_clk_gate csi2_96m_fck_data = { - .parent = "core_96m_fck", - .bit_shift = 1, - .reg = 0xf00, - .module = TI_CLKM_CM, -}; - -static struct ti_clk csi2_96m_fck = { - .name = "csi2_96m_fck", - .clkdm_name = "cam_clkdm", - .type = TI_CLK_GATE, - .data = &csi2_96m_fck_data, -}; - -static struct ti_clk_gate gpt9_gate_fck_data = { - .parent = "sys_ck", - .bit_shift = 10, - .reg = 0x1000, - .module = TI_CLKM_CM, -}; - -static const char *gpt9_mux_fck_parents[] = { - "omap_32k_fck", - "sys_ck", -}; - -static struct ti_clk_mux gpt9_mux_fck_data = { - .bit_shift = 7, - .num_parents = ARRAY_SIZE(gpt9_mux_fck_parents), - .reg = 0x1040, - .module = TI_CLKM_CM, - .parents = gpt9_mux_fck_parents, -}; - -static struct ti_clk_composite gpt9_fck_data = { - .mux = &gpt9_mux_fck_data, - .gate = &gpt9_gate_fck_data, -}; - -static struct ti_clk gpt9_fck = { - .name = "gpt9_fck", - .type = TI_CLK_COMPOSITE, - .data = &gpt9_fck_data, -}; - -static struct ti_clk_divider dpll3_m3_ck_data = { - .parent = "dpll3_ck", - .bit_shift = 16, - .max_div = 31, - .reg = 0x1140, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk dpll3_m3_ck = { - .name = "dpll3_m3_ck", - .type = TI_CLK_DIVIDER, - .data = &dpll3_m3_ck_data, -}; - -static struct ti_clk_fixed_factor dpll3_m3x2_mul_ck_data = { - .parent = "dpll3_m3_ck", - .div = 1, - .mult = 2, -}; - -static struct ti_clk dpll3_m3x2_mul_ck = { - .name = "dpll3_m3x2_mul_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &dpll3_m3x2_mul_ck_data, -}; - -static struct ti_clk_gate sr2_fck_data = { - .parent = "sys_ck", - .bit_shift = 7, - .reg = 0xc00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk sr2_fck = { - .name = "sr2_fck", - .clkdm_name = "wkup_clkdm", - .type = TI_CLK_GATE, - .data = &sr2_fck_data, -}; - -static struct ti_clk_fixed pclk_ck_data = { - .frequency = 27000000, -}; - -static struct ti_clk pclk_ck = { - .name = "pclk_ck", - .type = TI_CLK_FIXED, - .data = &pclk_ck_data, -}; - -static struct ti_clk_gate wdt2_ick_data = { - .parent = "wkup_l4_ick", - .bit_shift = 5, - .reg = 0xc10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk wdt2_ick = { - .name = "wdt2_ick", - .clkdm_name = "wkup_clkdm", - .type = TI_CLK_GATE, - .data = &wdt2_ick_data, -}; - -static struct ti_clk_fixed_factor core_l3_ick_data = { - .parent = "l3_ick", - .div = 1, - .mult = 1, -}; - -static struct ti_clk core_l3_ick = { - .name = "core_l3_ick", - .type = TI_CLK_FIXED_FACTOR, - .data = &core_l3_ick_data, -}; - -static struct ti_clk_gate mcspi4_fck_data = { - .parent = "core_48m_fck", - .bit_shift = 21, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk mcspi4_fck = { - .name = "mcspi4_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mcspi4_fck_data, -}; - -static struct ti_clk_fixed_factor per_48m_fck_data = { - .parent = "omap_48m_fck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk per_48m_fck = { - .name = "per_48m_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &per_48m_fck_data, -}; - -static struct ti_clk_gate uart4_fck_data = { - .parent = "per_48m_fck", - .bit_shift = 18, - .reg = 0x1000, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk uart4_fck = { - .name = "uart4_fck", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &uart4_fck_data, -}; - -static struct ti_clk_fixed_factor omap_96m_d10_fck_data = { - .parent = "omap_96m_fck", - .div = 10, - .mult = 1, -}; - -static struct ti_clk omap_96m_d10_fck = { - .name = "omap_96m_d10_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &omap_96m_d10_fck_data, -}; - -static struct ti_clk_gate usim_gate_fck_data = { - .parent = "omap_96m_fck", - .bit_shift = 9, - .reg = 0xc00, - .module = TI_CLKM_CM, -}; - -static struct ti_clk_fixed_factor per_l4_ick_data = { - .parent = "l4_ick", - .div = 1, - .mult = 1, -}; - -static struct ti_clk per_l4_ick = { - .name = "per_l4_ick", - .type = TI_CLK_FIXED_FACTOR, - .data = &per_l4_ick_data, -}; - -static struct ti_clk_gate gpt5_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 6, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpt5_ick = { - .name = "gpt5_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpt5_ick_data, -}; - -static struct ti_clk_gate mcspi2_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 19, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk mcspi2_ick = { - .name = "mcspi2_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mcspi2_ick_data, -}; - -static struct ti_clk_fixed_factor ssi_l4_ick_data = { - .parent = "l4_ick", - .div = 1, - .mult = 1, -}; - -static struct ti_clk ssi_l4_ick = { - .name = "ssi_l4_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_FIXED_FACTOR, - .data = &ssi_l4_ick_data, -}; - -static struct ti_clk_gate ssi_ick_3430es1_data = { - .parent = "ssi_l4_ick", - .bit_shift = 0, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_NO_WAIT | CLKF_INTERFACE, -}; - -static struct ti_clk ssi_ick_3430es1 = { - .name = "ssi_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &ssi_ick_3430es1_data, -}; - -static struct ti_clk_gate i2c2_fck_data = { - .parent = "core_96m_fck", - .bit_shift = 16, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk i2c2_fck = { - .name = "i2c2_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &i2c2_fck_data, -}; - -static struct ti_clk_divider dpll1_fck_data = { - .parent = "core_ck", - .bit_shift = 19, - .max_div = 7, - .reg = 0x940, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk dpll1_fck = { - .name = "dpll1_fck", - .type = TI_CLK_DIVIDER, - .data = &dpll1_fck_data, -}; - -static const char *dpll1_ck_parents[] = { - "sys_ck", - "dpll1_fck", -}; - -static struct ti_clk_dpll dpll1_ck_data = { - .num_parents = ARRAY_SIZE(dpll1_ck_parents), - .control_reg = 0x904, - .idlest_reg = 0x924, - .mult_div1_reg = 0x940, - .autoidle_reg = 0x934, - .module = TI_CLKM_CM, - .parents = dpll1_ck_parents, - .freqsel_mask = 0xf0, - .modes = 0xa0, - .div1_mask = 0x7f, - .idlest_mask = 0x1, - .auto_recal_bit = 0x3, - .max_divider = 0x80, - .min_divider = 0x1, - .recal_en_bit = 0x7, - .max_multiplier = 0x7ff, - .enable_mask = 0x7, - .mult_mask = 0x7ff00, - .recal_st_bit = 0x7, - .autoidle_mask = 0x7, -}; - -static struct ti_clk dpll1_ck = { - .name = "dpll1_ck", - .clkdm_name = "dpll1_clkdm", - .type = TI_CLK_DPLL, - .data = &dpll1_ck_data, -}; - -static struct ti_clk_fixed secure_32k_fck_data = { - .frequency = 32768, -}; - -static struct ti_clk secure_32k_fck = { - .name = "secure_32k_fck", - .type = TI_CLK_FIXED, - .data = &secure_32k_fck_data, -}; - -static struct ti_clk_gate gpio5_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 16, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpio5_ick = { - .name = "gpio5_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpio5_ick_data, -}; - -static struct ti_clk_divider dpll4_m4_ck_data = { - .parent = "dpll4_ck", - .max_div = 32, - .reg = 0xe40, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk dpll4_m4_ck = { - .name = "dpll4_m4_ck", - .type = TI_CLK_DIVIDER, - .data = &dpll4_m4_ck_data, -}; - -static struct ti_clk_fixed_factor dpll4_m4x2_mul_ck_data = { - .parent = "dpll4_m4_ck", - .div = 1, - .mult = 2, - .flags = CLKF_SET_RATE_PARENT, -}; - -static struct ti_clk dpll4_m4x2_mul_ck = { - .name = "dpll4_m4x2_mul_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &dpll4_m4x2_mul_ck_data, -}; - -static struct ti_clk_gate dpll4_m4x2_ck_data = { - .parent = "dpll4_m4x2_mul_ck", - .bit_shift = 0x1d, - .reg = 0xd00, - .module = TI_CLKM_CM, - .flags = CLKF_SET_RATE_PARENT | CLKF_SET_BIT_TO_DISABLE, -}; - -static struct ti_clk dpll4_m4x2_ck = { - .name = "dpll4_m4x2_ck", - .type = TI_CLK_GATE, - .data = &dpll4_m4x2_ck_data, -}; - -static struct ti_clk_gate dss1_alwon_fck_3430es2_data = { - .parent = "dpll4_m4x2_ck", - .bit_shift = 0, - .reg = 0xe00, - .module = TI_CLKM_CM, - .flags = CLKF_DSS | CLKF_SET_RATE_PARENT, -}; - -static struct ti_clk dss1_alwon_fck_3430es2 = { - .name = "dss1_alwon_fck", - .clkdm_name = "dss_clkdm", - .type = TI_CLK_GATE, - .data = &dss1_alwon_fck_3430es2_data, -}; - -static struct ti_clk_gate uart3_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 11, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk uart3_ick = { - .name = "uart3_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &uart3_ick_data, -}; - -static struct ti_clk_divider dpll4_m3_ck_data = { - .parent = "dpll4_ck", - .bit_shift = 8, - .max_div = 32, - .reg = 0xe40, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk dpll4_m3_ck = { - .name = "dpll4_m3_ck", - .type = TI_CLK_DIVIDER, - .data = &dpll4_m3_ck_data, -}; - -static struct ti_clk_gate mcbsp3_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 1, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk mcbsp3_ick = { - .name = "mcbsp3_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &mcbsp3_ick_data, -}; - -static struct ti_clk_gate gpio3_dbck_data = { - .parent = "per_32k_alwon_fck", - .bit_shift = 14, - .reg = 0x1000, - .module = TI_CLKM_CM, -}; - -static struct ti_clk gpio3_dbck = { - .name = "gpio3_dbck", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpio3_dbck_data, -}; - -static struct ti_clk_gate fac_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 8, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk fac_ick = { - .name = "fac_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &fac_ick_data, -}; - -static struct ti_clk_gate clkout2_src_gate_ck_data = { - .parent = "core_ck", - .bit_shift = 7, - .reg = 0xd70, - .module = TI_CLKM_CM, - .flags = CLKF_NO_WAIT, -}; - -static struct ti_clk_fixed_factor dpll4_m3x2_mul_ck_data = { - .parent = "dpll4_m3_ck", - .div = 1, - .mult = 2, -}; - -static struct ti_clk dpll4_m3x2_mul_ck = { - .name = "dpll4_m3x2_mul_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &dpll4_m3x2_mul_ck_data, -}; - -static struct ti_clk_gate dpll4_m3x2_ck_data = { - .parent = "dpll4_m3x2_mul_ck", - .bit_shift = 0x1c, - .reg = 0xd00, - .module = TI_CLKM_CM, - .flags = CLKF_SET_BIT_TO_DISABLE, -}; - -static struct ti_clk dpll4_m3x2_ck = { - .name = "dpll4_m3x2_ck", - .type = TI_CLK_GATE, - .data = &dpll4_m3x2_ck_data, -}; - -static const char *omap_54m_fck_parents[] = { - "dpll4_m3x2_ck", - "sys_altclk", -}; - -static struct ti_clk_mux omap_54m_fck_data = { - .bit_shift = 5, - .num_parents = ARRAY_SIZE(omap_54m_fck_parents), - .reg = 0xd40, - .module = TI_CLKM_CM, - .parents = omap_54m_fck_parents, -}; - -static struct ti_clk omap_54m_fck = { - .name = "omap_54m_fck", - .type = TI_CLK_MUX, - .data = &omap_54m_fck_data, -}; - -static const char *clkout2_src_mux_ck_parents[] = { - "core_ck", - "sys_ck", - "cm_96m_fck", - "omap_54m_fck", -}; - -static struct ti_clk_mux clkout2_src_mux_ck_data = { - .num_parents = ARRAY_SIZE(clkout2_src_mux_ck_parents), - .reg = 0xd70, - .module = TI_CLKM_CM, - .parents = clkout2_src_mux_ck_parents, -}; - -static struct ti_clk_composite clkout2_src_ck_data = { - .mux = &clkout2_src_mux_ck_data, - .gate = &clkout2_src_gate_ck_data, -}; - -static struct ti_clk clkout2_src_ck = { - .name = "clkout2_src_ck", - .type = TI_CLK_COMPOSITE, - .data = &clkout2_src_ck_data, -}; - -static struct ti_clk_gate i2c1_fck_data = { - .parent = "core_96m_fck", - .bit_shift = 15, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk i2c1_fck = { - .name = "i2c1_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &i2c1_fck_data, -}; - -static struct ti_clk_gate wdt3_fck_data = { - .parent = "per_32k_alwon_fck", - .bit_shift = 12, - .reg = 0x1000, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk wdt3_fck = { - .name = "wdt3_fck", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &wdt3_fck_data, -}; - -static struct ti_clk_gate gpt7_gate_fck_data = { - .parent = "sys_ck", - .bit_shift = 8, - .reg = 0x1000, - .module = TI_CLKM_CM, -}; - -static const char *gpt7_mux_fck_parents[] = { - "omap_32k_fck", - "sys_ck", -}; - -static struct ti_clk_mux gpt7_mux_fck_data = { - .bit_shift = 5, - .num_parents = ARRAY_SIZE(gpt7_mux_fck_parents), - .reg = 0x1040, - .module = TI_CLKM_CM, - .parents = gpt7_mux_fck_parents, -}; - -static struct ti_clk_composite gpt7_fck_data = { - .mux = &gpt7_mux_fck_data, - .gate = &gpt7_gate_fck_data, -}; - -static struct ti_clk gpt7_fck = { - .name = "gpt7_fck", - .type = TI_CLK_COMPOSITE, - .data = &gpt7_fck_data, -}; - -static struct ti_clk_gate usb_l4_gate_ick_data = { - .parent = "l4_ick", - .bit_shift = 5, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_INTERFACE, -}; - -static struct ti_clk_divider usb_l4_div_ick_data = { - .parent = "l4_ick", - .bit_shift = 4, - .max_div = 1, - .reg = 0xa40, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk_composite usb_l4_ick_data = { - .gate = &usb_l4_gate_ick_data, - .divider = &usb_l4_div_ick_data, -}; - -static struct ti_clk usb_l4_ick = { - .name = "usb_l4_ick", - .type = TI_CLK_COMPOSITE, - .data = &usb_l4_ick_data, -}; - -static struct ti_clk_gate uart4_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 18, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk uart4_ick = { - .name = "uart4_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &uart4_ick_data, -}; - -static struct ti_clk_fixed dummy_ck_data = { - .frequency = 0, -}; - -static struct ti_clk dummy_ck = { - .name = "dummy_ck", - .type = TI_CLK_FIXED, - .data = &dummy_ck_data, -}; - -static const char *gpt3_mux_fck_parents[] = { - "omap_32k_fck", - "sys_ck", -}; - -static struct ti_clk_mux gpt3_mux_fck_data = { - .bit_shift = 1, - .num_parents = ARRAY_SIZE(gpt3_mux_fck_parents), - .reg = 0x1040, - .module = TI_CLKM_CM, - .parents = gpt3_mux_fck_parents, -}; - -static struct ti_clk_gate gpt9_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 10, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpt9_ick = { - .name = "gpt9_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpt9_ick_data, -}; - -static struct ti_clk_gate gpt10_gate_fck_data = { - .parent = "sys_ck", - .bit_shift = 11, - .reg = 0xa00, - .module = TI_CLKM_CM, -}; - -static struct ti_clk_gate dss_ick_3430es1_data = { - .parent = "l4_ick", - .bit_shift = 0, - .reg = 0xe10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_NO_WAIT | CLKF_INTERFACE, -}; - -static struct ti_clk dss_ick_3430es1 = { - .name = "dss_ick", - .clkdm_name = "dss_clkdm", - .type = TI_CLK_GATE, - .data = &dss_ick_3430es1_data, -}; - -static struct ti_clk_gate gpt11_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 12, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpt11_ick = { - .name = "gpt11_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &gpt11_ick_data, -}; - -static struct ti_clk_divider dpll2_fck_data = { - .parent = "core_ck", - .bit_shift = 19, - .max_div = 7, - .reg = 0x40, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk dpll2_fck = { - .name = "dpll2_fck", - .type = TI_CLK_DIVIDER, - .data = &dpll2_fck_data, -}; - -static struct ti_clk_gate uart1_fck_data = { - .parent = "core_48m_fck", - .bit_shift = 13, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk uart1_fck = { - .name = "uart1_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &uart1_fck_data, -}; - -static struct ti_clk_gate hsotgusb_ick_3430es1_data = { - .parent = "core_l3_ick", - .bit_shift = 4, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_NO_WAIT | CLKF_INTERFACE, -}; - -static struct ti_clk hsotgusb_ick_3430es1 = { - .name = "hsotgusb_ick_3430es1", - .clkdm_name = "core_l3_clkdm", - .type = TI_CLK_GATE, - .data = &hsotgusb_ick_3430es1_data, -}; - -static struct ti_clk_gate gpio2_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 13, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpio2_ick = { - .name = "gpio2_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpio2_ick_data, -}; - -static struct ti_clk_gate mmchs1_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 24, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk mmchs1_ick = { - .name = "mmchs1_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mmchs1_ick_data, -}; - -static struct ti_clk_gate modem_fck_data = { - .parent = "sys_ck", - .bit_shift = 31, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk modem_fck = { - .name = "modem_fck", - .clkdm_name = "d2d_clkdm", - .type = TI_CLK_GATE, - .data = &modem_fck_data, -}; - -static struct ti_clk_gate mcbsp4_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 2, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk mcbsp4_ick = { - .name = "mcbsp4_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &mcbsp4_ick_data, -}; - -static struct ti_clk_gate gpio1_ick_data = { - .parent = "wkup_l4_ick", - .bit_shift = 3, - .reg = 0xc10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpio1_ick = { - .name = "gpio1_ick", - .clkdm_name = "wkup_clkdm", - .type = TI_CLK_GATE, - .data = &gpio1_ick_data, -}; - -static const char *gpt6_mux_fck_parents[] = { - "omap_32k_fck", - "sys_ck", -}; - -static struct ti_clk_mux gpt6_mux_fck_data = { - .bit_shift = 4, - .num_parents = ARRAY_SIZE(gpt6_mux_fck_parents), - .reg = 0x1040, - .module = TI_CLKM_CM, - .parents = gpt6_mux_fck_parents, -}; - -static struct ti_clk_fixed_factor dpll1_x2_ck_data = { - .parent = "dpll1_ck", - .div = 1, - .mult = 2, -}; - -static struct ti_clk dpll1_x2_ck = { - .name = "dpll1_x2_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &dpll1_x2_ck_data, -}; - -static struct ti_clk_divider dpll1_x2m2_ck_data = { - .parent = "dpll1_x2_ck", - .max_div = 31, - .reg = 0x944, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk dpll1_x2m2_ck = { - .name = "dpll1_x2m2_ck", - .type = TI_CLK_DIVIDER, - .data = &dpll1_x2m2_ck_data, -}; - -static struct ti_clk_fixed_factor mpu_ck_data = { - .parent = "dpll1_x2m2_ck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk mpu_ck = { - .name = "mpu_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &mpu_ck_data, -}; - -static struct ti_clk_divider arm_fck_data = { - .parent = "mpu_ck", - .max_div = 2, - .reg = 0x924, - .module = TI_CLKM_CM, -}; - -static struct ti_clk arm_fck = { - .name = "arm_fck", - .type = TI_CLK_DIVIDER, - .data = &arm_fck_data, -}; - -static struct ti_clk_fixed_factor core_d3_ck_data = { - .parent = "core_ck", - .div = 3, - .mult = 1, -}; - -static struct ti_clk core_d3_ck = { - .name = "core_d3_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &core_d3_ck_data, -}; - -static struct ti_clk_gate gpt11_gate_fck_data = { - .parent = "sys_ck", - .bit_shift = 12, - .reg = 0xa00, - .module = TI_CLKM_CM, -}; - -static const char *gpt11_mux_fck_parents[] = { - "omap_32k_fck", - "sys_ck", -}; - -static struct ti_clk_mux gpt11_mux_fck_data = { - .bit_shift = 7, - .num_parents = ARRAY_SIZE(gpt11_mux_fck_parents), - .reg = 0xa40, - .module = TI_CLKM_CM, - .parents = gpt11_mux_fck_parents, -}; - -static struct ti_clk_composite gpt11_fck_data = { - .mux = &gpt11_mux_fck_data, - .gate = &gpt11_gate_fck_data, -}; - -static struct ti_clk gpt11_fck = { - .name = "gpt11_fck", - .type = TI_CLK_COMPOSITE, - .data = &gpt11_fck_data, -}; - -static struct ti_clk_fixed_factor core_d6_ck_data = { - .parent = "core_ck", - .div = 6, - .mult = 1, -}; - -static struct ti_clk core_d6_ck = { - .name = "core_d6_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &core_d6_ck_data, -}; - -static struct ti_clk_gate uart4_fck_am35xx_data = { - .parent = "core_48m_fck", - .bit_shift = 23, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk uart4_fck_am35xx = { - .name = "uart4_fck_am35xx", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &uart4_fck_am35xx_data, -}; - -static struct ti_clk_gate dpll3_m3x2_ck_data = { - .parent = "dpll3_m3x2_mul_ck", - .bit_shift = 0xc, - .reg = 0xd00, - .module = TI_CLKM_CM, - .flags = CLKF_SET_BIT_TO_DISABLE, -}; - -static struct ti_clk dpll3_m3x2_ck = { - .name = "dpll3_m3x2_ck", - .type = TI_CLK_GATE, - .data = &dpll3_m3x2_ck_data, -}; - -static struct ti_clk_fixed_factor emu_core_alwon_ck_data = { - .parent = "dpll3_m3x2_ck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk emu_core_alwon_ck = { - .name = "emu_core_alwon_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &emu_core_alwon_ck_data, -}; - -static struct ti_clk_divider dpll4_m6_ck_data = { - .parent = "dpll4_ck", - .bit_shift = 24, - .max_div = 63, - .reg = 0x1140, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk dpll4_m6_ck = { - .name = "dpll4_m6_ck", - .type = TI_CLK_DIVIDER, - .data = &dpll4_m6_ck_data, -}; - -static struct ti_clk_fixed_factor dpll4_m6x2_mul_ck_data = { - .parent = "dpll4_m6_ck", - .div = 1, - .mult = 2, -}; - -static struct ti_clk dpll4_m6x2_mul_ck = { - .name = "dpll4_m6x2_mul_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &dpll4_m6x2_mul_ck_data, -}; - -static struct ti_clk_gate dpll4_m6x2_ck_data = { - .parent = "dpll4_m6x2_mul_ck", - .bit_shift = 0x1f, - .reg = 0xd00, - .module = TI_CLKM_CM, - .flags = CLKF_SET_BIT_TO_DISABLE, -}; - -static struct ti_clk dpll4_m6x2_ck = { - .name = "dpll4_m6x2_ck", - .type = TI_CLK_GATE, - .data = &dpll4_m6x2_ck_data, -}; - -static struct ti_clk_fixed_factor emu_per_alwon_ck_data = { - .parent = "dpll4_m6x2_ck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk emu_per_alwon_ck = { - .name = "emu_per_alwon_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &emu_per_alwon_ck_data, -}; - -static struct ti_clk_fixed_factor emu_mpu_alwon_ck_data = { - .parent = "mpu_ck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk emu_mpu_alwon_ck = { - .name = "emu_mpu_alwon_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &emu_mpu_alwon_ck_data, -}; - -static const char *emu_src_mux_ck_parents[] = { - "sys_ck", - "emu_core_alwon_ck", - "emu_per_alwon_ck", - "emu_mpu_alwon_ck", -}; - -static struct ti_clk_mux emu_src_mux_ck_data = { - .num_parents = ARRAY_SIZE(emu_src_mux_ck_parents), - .reg = 0x1140, - .module = TI_CLKM_CM, - .parents = emu_src_mux_ck_parents, -}; - -static struct ti_clk emu_src_mux_ck = { - .name = "emu_src_mux_ck", - .type = TI_CLK_MUX, - .data = &emu_src_mux_ck_data, -}; - -static struct ti_clk_gate emu_src_ck_data = { - .parent = "emu_src_mux_ck", - .flags = CLKF_CLKDM, -}; - -static struct ti_clk emu_src_ck = { - .name = "emu_src_ck", - .clkdm_name = "emu_clkdm", - .type = TI_CLK_GATE, - .data = &emu_src_ck_data, -}; - -static struct ti_clk_divider atclk_fck_data = { - .parent = "emu_src_ck", - .bit_shift = 4, - .max_div = 3, - .reg = 0x1140, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk atclk_fck = { - .name = "atclk_fck", - .type = TI_CLK_DIVIDER, - .data = &atclk_fck_data, -}; - -static struct ti_clk_gate ipss_ick_data = { - .parent = "core_l3_ick", - .bit_shift = 4, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_AM35XX | CLKF_INTERFACE, -}; - -static struct ti_clk ipss_ick = { - .name = "ipss_ick", - .clkdm_name = "core_l3_clkdm", - .type = TI_CLK_GATE, - .data = &ipss_ick_data, -}; - -static struct ti_clk_gate emac_ick_data = { - .parent = "ipss_ick", - .bit_shift = 1, - .reg = 0x59c, - .module = TI_CLKM_SCRM, - .flags = CLKF_AM35XX, -}; - -static struct ti_clk emac_ick = { - .name = "emac_ick", - .clkdm_name = "core_l3_clkdm", - .type = TI_CLK_GATE, - .data = &emac_ick_data, -}; - -static struct ti_clk_gate vpfe_ick_data = { - .parent = "ipss_ick", - .bit_shift = 2, - .reg = 0x59c, - .module = TI_CLKM_SCRM, - .flags = CLKF_AM35XX, -}; - -static struct ti_clk vpfe_ick = { - .name = "vpfe_ick", - .clkdm_name = "core_l3_clkdm", - .type = TI_CLK_GATE, - .data = &vpfe_ick_data, -}; - -static const char *dpll2_ck_parents[] = { - "sys_ck", - "dpll2_fck", -}; - -static struct ti_clk_dpll dpll2_ck_data = { - .num_parents = ARRAY_SIZE(dpll2_ck_parents), - .control_reg = 0x4, - .idlest_reg = 0x24, - .mult_div1_reg = 0x40, - .autoidle_reg = 0x34, - .module = TI_CLKM_CM, - .parents = dpll2_ck_parents, - .freqsel_mask = 0xf0, - .modes = 0xa2, - .div1_mask = 0x7f, - .idlest_mask = 0x1, - .auto_recal_bit = 0x3, - .max_divider = 0x80, - .min_divider = 0x1, - .recal_en_bit = 0x8, - .max_multiplier = 0x7ff, - .enable_mask = 0x7, - .mult_mask = 0x7ff00, - .recal_st_bit = 0x8, - .autoidle_mask = 0x7, -}; - -static struct ti_clk dpll2_ck = { - .name = "dpll2_ck", - .clkdm_name = "dpll2_clkdm", - .type = TI_CLK_DPLL, - .data = &dpll2_ck_data, -}; - -static struct ti_clk_divider dpll2_m2_ck_data = { - .parent = "dpll2_ck", - .max_div = 31, - .reg = 0x44, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk dpll2_m2_ck = { - .name = "dpll2_m2_ck", - .type = TI_CLK_DIVIDER, - .data = &dpll2_m2_ck_data, -}; - -static const char *mcbsp4_mux_fck_parents[] = { - "per_96m_fck", - "mcbsp_clks", -}; - -static struct ti_clk_mux mcbsp4_mux_fck_data = { - .bit_shift = 2, - .num_parents = ARRAY_SIZE(mcbsp4_mux_fck_parents), - .reg = 0x2d8, - .module = TI_CLKM_SCRM, - .parents = mcbsp4_mux_fck_parents, -}; - -static const char *mcbsp1_mux_fck_parents[] = { - "core_96m_fck", - "mcbsp_clks", -}; - -static struct ti_clk_mux mcbsp1_mux_fck_data = { - .bit_shift = 2, - .num_parents = ARRAY_SIZE(mcbsp1_mux_fck_parents), - .reg = 0x274, - .module = TI_CLKM_SCRM, - .parents = mcbsp1_mux_fck_parents, -}; - -static struct ti_clk_gate gpt8_gate_fck_data = { - .parent = "sys_ck", - .bit_shift = 9, - .reg = 0x1000, - .module = TI_CLKM_CM, -}; - -static struct ti_clk_gate gpt8_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 9, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpt8_ick = { - .name = "gpt8_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpt8_ick_data, -}; - -static const char *gpt10_mux_fck_parents[] = { - "omap_32k_fck", - "sys_ck", -}; - -static struct ti_clk_mux gpt10_mux_fck_data = { - .bit_shift = 6, - .num_parents = ARRAY_SIZE(gpt10_mux_fck_parents), - .reg = 0xa40, - .module = TI_CLKM_CM, - .parents = gpt10_mux_fck_parents, -}; - -static struct ti_clk_gate mmchs3_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 30, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk mmchs3_ick = { - .name = "mmchs3_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mmchs3_ick_data, -}; - -static struct ti_clk_gate gpio3_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 14, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpio3_ick = { - .name = "gpio3_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpio3_ick_data, -}; - -static const char *traceclk_src_fck_parents[] = { - "sys_ck", - "emu_core_alwon_ck", - "emu_per_alwon_ck", - "emu_mpu_alwon_ck", -}; - -static struct ti_clk_mux traceclk_src_fck_data = { - .bit_shift = 2, - .num_parents = ARRAY_SIZE(traceclk_src_fck_parents), - .reg = 0x1140, - .module = TI_CLKM_CM, - .parents = traceclk_src_fck_parents, -}; - -static struct ti_clk traceclk_src_fck = { - .name = "traceclk_src_fck", - .type = TI_CLK_MUX, - .data = &traceclk_src_fck_data, -}; - -static struct ti_clk_divider traceclk_fck_data = { - .parent = "traceclk_src_fck", - .bit_shift = 11, - .max_div = 7, - .reg = 0x1140, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk traceclk_fck = { - .name = "traceclk_fck", - .type = TI_CLK_DIVIDER, - .data = &traceclk_fck_data, -}; - -static struct ti_clk_gate mcbsp5_gate_fck_data = { - .parent = "mcbsp_clks", - .bit_shift = 10, - .reg = 0xa00, - .module = TI_CLKM_CM, -}; - -static struct ti_clk_gate sad2d_ick_data = { - .parent = "l3_ick", - .bit_shift = 3, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk sad2d_ick = { - .name = "sad2d_ick", - .clkdm_name = "d2d_clkdm", - .type = TI_CLK_GATE, - .data = &sad2d_ick_data, -}; - -static const char *gpt1_mux_fck_parents[] = { - "omap_32k_fck", - "sys_ck", -}; - -static struct ti_clk_mux gpt1_mux_fck_data = { - .num_parents = ARRAY_SIZE(gpt1_mux_fck_parents), - .reg = 0xc40, - .module = TI_CLKM_CM, - .parents = gpt1_mux_fck_parents, -}; - -static struct ti_clk_gate hecc_ck_data = { - .parent = "sys_ck", - .bit_shift = 3, - .reg = 0x59c, - .module = TI_CLKM_SCRM, - .flags = CLKF_AM35XX, -}; - -static struct ti_clk hecc_ck = { - .name = "hecc_ck", - .clkdm_name = "core_l3_clkdm", - .type = TI_CLK_GATE, - .data = &hecc_ck_data, -}; - -static struct ti_clk_gate gpt1_gate_fck_data = { - .parent = "sys_ck", - .bit_shift = 0, - .reg = 0xc00, - .module = TI_CLKM_CM, -}; - -static struct ti_clk_composite gpt1_fck_data = { - .mux = &gpt1_mux_fck_data, - .gate = &gpt1_gate_fck_data, -}; - -static struct ti_clk gpt1_fck = { - .name = "gpt1_fck", - .type = TI_CLK_COMPOSITE, - .data = &gpt1_fck_data, -}; - -static struct ti_clk_gate dpll4_m2x2_ck_omap36xx_data = { - .parent = "dpll4_m2x2_mul_ck", - .bit_shift = 0x1b, - .reg = 0xd00, - .module = TI_CLKM_CM, - .flags = CLKF_HSDIV | CLKF_SET_BIT_TO_DISABLE, -}; - -static struct ti_clk dpll4_m2x2_ck_omap36xx = { - .name = "dpll4_m2x2_ck", - .type = TI_CLK_GATE, - .data = &dpll4_m2x2_ck_omap36xx_data, - .patch = &dpll4_m2x2_ck, -}; - -static struct ti_clk_divider gfx_l3_fck_data = { - .parent = "l3_ick", - .max_div = 7, - .reg = 0xb40, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk gfx_l3_fck = { - .name = "gfx_l3_fck", - .type = TI_CLK_DIVIDER, - .data = &gfx_l3_fck_data, -}; - -static struct ti_clk_gate gfx_cg1_ck_data = { - .parent = "gfx_l3_fck", - .bit_shift = 1, - .reg = 0xb00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk gfx_cg1_ck = { - .name = "gfx_cg1_ck", - .clkdm_name = "gfx_3430es1_clkdm", - .type = TI_CLK_GATE, - .data = &gfx_cg1_ck_data, -}; - -static struct ti_clk_gate mailboxes_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 7, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk mailboxes_ick = { - .name = "mailboxes_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mailboxes_ick_data, -}; - -static struct ti_clk_gate sha11_ick_data = { - .parent = "security_l4_ick2", - .bit_shift = 1, - .reg = 0xa14, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk sha11_ick = { - .name = "sha11_ick", - .type = TI_CLK_GATE, - .data = &sha11_ick_data, -}; - -static struct ti_clk_gate hsotgusb_ick_am35xx_data = { - .parent = "ipss_ick", - .bit_shift = 0, - .reg = 0x59c, - .module = TI_CLKM_SCRM, - .flags = CLKF_AM35XX, -}; - -static struct ti_clk hsotgusb_ick_am35xx = { - .name = "hsotgusb_ick_am35xx", - .clkdm_name = "core_l3_clkdm", - .type = TI_CLK_GATE, - .data = &hsotgusb_ick_am35xx_data, -}; - -static struct ti_clk_gate mmchs3_fck_data = { - .parent = "core_96m_fck", - .bit_shift = 30, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk mmchs3_fck = { - .name = "mmchs3_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mmchs3_fck_data, -}; - -static struct ti_clk_divider pclk_fck_data = { - .parent = "emu_src_ck", - .bit_shift = 8, - .max_div = 7, - .reg = 0x1140, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk pclk_fck = { - .name = "pclk_fck", - .type = TI_CLK_DIVIDER, - .data = &pclk_fck_data, -}; - -static const char *dpll4_ck_omap36xx_parents[] = { - "sys_ck", - "sys_ck", -}; - -static struct ti_clk_dpll dpll4_ck_omap36xx_data = { - .num_parents = ARRAY_SIZE(dpll4_ck_omap36xx_parents), - .control_reg = 0xd00, - .idlest_reg = 0xd20, - .mult_div1_reg = 0xd44, - .autoidle_reg = 0xd30, - .module = TI_CLKM_CM, - .parents = dpll4_ck_omap36xx_parents, - .modes = 0x82, - .div1_mask = 0x7f, - .idlest_mask = 0x2, - .auto_recal_bit = 0x13, - .max_divider = 0x80, - .min_divider = 0x1, - .recal_en_bit = 0x6, - .max_multiplier = 0xfff, - .enable_mask = 0x70000, - .mult_mask = 0xfff00, - .recal_st_bit = 0x6, - .autoidle_mask = 0x38, - .sddiv_mask = 0xff000000, - .dco_mask = 0xe00000, - .flags = CLKF_PER | CLKF_J_TYPE, -}; - -static struct ti_clk dpll4_ck_omap36xx = { - .name = "dpll4_ck", - .type = TI_CLK_DPLL, - .data = &dpll4_ck_omap36xx_data, - .patch = &dpll4_ck, -}; - -static struct ti_clk_gate uart3_fck_data = { - .parent = "per_48m_fck", - .bit_shift = 11, - .reg = 0x1000, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk uart3_fck = { - .name = "uart3_fck", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &uart3_fck_data, -}; - -static struct ti_clk_fixed_factor wkup_32k_fck_data = { - .parent = "omap_32k_fck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk wkup_32k_fck = { - .name = "wkup_32k_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &wkup_32k_fck_data, -}; - -static struct ti_clk_gate sys_clkout1_data = { - .parent = "osc_sys_ck", - .bit_shift = 7, - .reg = 0xd70, - .module = TI_CLKM_PRM, -}; - -static struct ti_clk sys_clkout1 = { - .name = "sys_clkout1", - .type = TI_CLK_GATE, - .data = &sys_clkout1_data, -}; - -static struct ti_clk_fixed_factor gpmc_fck_data = { - .parent = "core_l3_ick", - .div = 1, - .mult = 1, -}; - -static struct ti_clk gpmc_fck = { - .name = "gpmc_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &gpmc_fck_data, -}; - -static struct ti_clk_fixed_factor dpll5_m2_d20_ck_data = { - .parent = "dpll5_m2_ck", - .div = 20, - .mult = 1, -}; - -static struct ti_clk dpll5_m2_d20_ck = { - .name = "dpll5_m2_d20_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &dpll5_m2_d20_ck_data, -}; - -static struct ti_clk_gate dpll4_m5x2_ck_omap36xx_data = { - .parent = "dpll4_m5x2_mul_ck", - .bit_shift = 0x1e, - .reg = 0xd00, - .module = TI_CLKM_CM, - .flags = CLKF_HSDIV | CLKF_SET_RATE_PARENT | CLKF_SET_BIT_TO_DISABLE, -}; - -static struct ti_clk dpll4_m5x2_ck_omap36xx = { - .name = "dpll4_m5x2_ck", - .type = TI_CLK_GATE, - .data = &dpll4_m5x2_ck_omap36xx_data, - .patch = &dpll4_m5x2_ck, -}; - -static struct ti_clk_gate ssi_ssr_gate_fck_3430es2_data = { - .parent = "corex2_fck", - .bit_shift = 0, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_NO_WAIT, -}; - -static struct ti_clk_gate uart1_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 13, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk uart1_ick = { - .name = "uart1_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &uart1_ick_data, -}; - -static struct ti_clk_gate iva2_ck_data = { - .parent = "dpll2_m2_ck", - .bit_shift = 0, - .reg = 0x0, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk iva2_ck = { - .name = "iva2_ck", - .clkdm_name = "iva2_clkdm", - .type = TI_CLK_GATE, - .data = &iva2_ck_data, -}; - -static struct ti_clk_gate pka_ick_data = { - .parent = "security_l3_ick", - .bit_shift = 4, - .reg = 0xa14, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk pka_ick = { - .name = "pka_ick", - .type = TI_CLK_GATE, - .data = &pka_ick_data, -}; - -static struct ti_clk_gate gpt12_ick_data = { - .parent = "wkup_l4_ick", - .bit_shift = 1, - .reg = 0xc10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpt12_ick = { - .name = "gpt12_ick", - .clkdm_name = "wkup_clkdm", - .type = TI_CLK_GATE, - .data = &gpt12_ick_data, -}; - -static const char *mcbsp5_mux_fck_parents[] = { - "core_96m_fck", - "mcbsp_clks", -}; - -static struct ti_clk_mux mcbsp5_mux_fck_data = { - .bit_shift = 4, - .num_parents = ARRAY_SIZE(mcbsp5_mux_fck_parents), - .reg = 0x2d8, - .module = TI_CLKM_SCRM, - .parents = mcbsp5_mux_fck_parents, -}; - -static struct ti_clk_composite mcbsp5_fck_data = { - .mux = &mcbsp5_mux_fck_data, - .gate = &mcbsp5_gate_fck_data, -}; - -static struct ti_clk mcbsp5_fck = { - .name = "mcbsp5_fck", - .type = TI_CLK_COMPOSITE, - .data = &mcbsp5_fck_data, -}; - -static struct ti_clk_gate usbhost_48m_fck_data = { - .parent = "omap_48m_fck", - .bit_shift = 0, - .reg = 0x1400, - .module = TI_CLKM_CM, - .flags = CLKF_DSS, -}; - -static struct ti_clk usbhost_48m_fck = { - .name = "usbhost_48m_fck", - .clkdm_name = "usbhost_clkdm", - .type = TI_CLK_GATE, - .data = &usbhost_48m_fck_data, -}; - -static struct ti_clk_gate des1_ick_data = { - .parent = "security_l4_ick2", - .bit_shift = 0, - .reg = 0xa14, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk des1_ick = { - .name = "des1_ick", - .type = TI_CLK_GATE, - .data = &des1_ick_data, -}; - -static struct ti_clk_gate sgx_gate_fck_data = { - .parent = "core_ck", - .bit_shift = 1, - .reg = 0xb00, - .module = TI_CLKM_CM, -}; - -static struct ti_clk_fixed_factor core_d4_ck_data = { - .parent = "core_ck", - .div = 4, - .mult = 1, -}; - -static struct ti_clk core_d4_ck = { - .name = "core_d4_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &core_d4_ck_data, -}; - -static struct ti_clk_fixed_factor omap_192m_alwon_fck_data = { - .parent = "dpll4_m2x2_ck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk omap_192m_alwon_fck = { - .name = "omap_192m_alwon_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &omap_192m_alwon_fck_data, -}; - -static struct ti_clk_fixed_factor core_d2_ck_data = { - .parent = "core_ck", - .div = 2, - .mult = 1, -}; - -static struct ti_clk core_d2_ck = { - .name = "core_d2_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &core_d2_ck_data, -}; - -static struct ti_clk_fixed_factor corex2_d3_fck_data = { - .parent = "corex2_fck", - .div = 3, - .mult = 1, -}; - -static struct ti_clk corex2_d3_fck = { - .name = "corex2_d3_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &corex2_d3_fck_data, -}; - -static struct ti_clk_fixed_factor corex2_d5_fck_data = { - .parent = "corex2_fck", - .div = 5, - .mult = 1, -}; - -static struct ti_clk corex2_d5_fck = { - .name = "corex2_d5_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &corex2_d5_fck_data, -}; - -static const char *sgx_mux_fck_parents[] = { - "core_d3_ck", - "core_d4_ck", - "core_d6_ck", - "cm_96m_fck", - "omap_192m_alwon_fck", - "core_d2_ck", - "corex2_d3_fck", - "corex2_d5_fck", -}; - -static struct ti_clk_mux sgx_mux_fck_data = { - .num_parents = ARRAY_SIZE(sgx_mux_fck_parents), - .reg = 0xb40, - .module = TI_CLKM_CM, - .parents = sgx_mux_fck_parents, -}; - -static struct ti_clk_composite sgx_fck_data = { - .mux = &sgx_mux_fck_data, - .gate = &sgx_gate_fck_data, -}; - -static struct ti_clk sgx_fck = { - .name = "sgx_fck", - .type = TI_CLK_COMPOSITE, - .data = &sgx_fck_data, -}; - -static struct ti_clk_gate mcspi1_fck_data = { - .parent = "core_48m_fck", - .bit_shift = 18, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk mcspi1_fck = { - .name = "mcspi1_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mcspi1_fck_data, -}; - -static struct ti_clk_gate mmchs2_fck_data = { - .parent = "core_96m_fck", - .bit_shift = 25, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk mmchs2_fck = { - .name = "mmchs2_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mmchs2_fck_data, -}; - -static struct ti_clk_gate mcspi2_fck_data = { - .parent = "core_48m_fck", - .bit_shift = 19, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk mcspi2_fck = { - .name = "mcspi2_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mcspi2_fck_data, -}; - -static struct ti_clk_gate vpfe_fck_data = { - .parent = "pclk_ck", - .bit_shift = 10, - .reg = 0x59c, - .module = TI_CLKM_SCRM, -}; - -static struct ti_clk vpfe_fck = { - .name = "vpfe_fck", - .type = TI_CLK_GATE, - .data = &vpfe_fck_data, -}; - -static struct ti_clk_gate gpt4_gate_fck_data = { - .parent = "sys_ck", - .bit_shift = 5, - .reg = 0x1000, - .module = TI_CLKM_CM, -}; - -static struct ti_clk_gate mcbsp1_gate_fck_data = { - .parent = "mcbsp_clks", - .bit_shift = 9, - .reg = 0xa00, - .module = TI_CLKM_CM, -}; - -static struct ti_clk_gate gpt5_gate_fck_data = { - .parent = "sys_ck", - .bit_shift = 6, - .reg = 0x1000, - .module = TI_CLKM_CM, -}; - -static const char *gpt5_mux_fck_parents[] = { - "omap_32k_fck", - "sys_ck", -}; - -static struct ti_clk_mux gpt5_mux_fck_data = { - .bit_shift = 3, - .num_parents = ARRAY_SIZE(gpt5_mux_fck_parents), - .reg = 0x1040, - .module = TI_CLKM_CM, - .parents = gpt5_mux_fck_parents, -}; - -static struct ti_clk_composite gpt5_fck_data = { - .mux = &gpt5_mux_fck_data, - .gate = &gpt5_gate_fck_data, -}; - -static struct ti_clk gpt5_fck = { - .name = "gpt5_fck", - .type = TI_CLK_COMPOSITE, - .data = &gpt5_fck_data, -}; - -static struct ti_clk_gate ts_fck_data = { - .parent = "omap_32k_fck", - .bit_shift = 1, - .reg = 0xa08, - .module = TI_CLKM_CM, -}; - -static struct ti_clk ts_fck = { - .name = "ts_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &ts_fck_data, -}; - -static struct ti_clk_fixed_factor wdt1_fck_data = { - .parent = "secure_32k_fck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk wdt1_fck = { - .name = "wdt1_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &wdt1_fck_data, -}; - -static struct ti_clk_gate dpll4_m6x2_ck_omap36xx_data = { - .parent = "dpll4_m6x2_mul_ck", - .bit_shift = 0x1f, - .reg = 0xd00, - .module = TI_CLKM_CM, - .flags = CLKF_HSDIV | CLKF_SET_BIT_TO_DISABLE, -}; - -static struct ti_clk dpll4_m6x2_ck_omap36xx = { - .name = "dpll4_m6x2_ck", - .type = TI_CLK_GATE, - .data = &dpll4_m6x2_ck_omap36xx_data, - .patch = &dpll4_m6x2_ck, -}; - -static const char *gpt4_mux_fck_parents[] = { - "omap_32k_fck", - "sys_ck", -}; - -static struct ti_clk_mux gpt4_mux_fck_data = { - .bit_shift = 2, - .num_parents = ARRAY_SIZE(gpt4_mux_fck_parents), - .reg = 0x1040, - .module = TI_CLKM_CM, - .parents = gpt4_mux_fck_parents, -}; - -static struct ti_clk_gate usbhost_ick_data = { - .parent = "l4_ick", - .bit_shift = 0, - .reg = 0x1410, - .module = TI_CLKM_CM, - .flags = CLKF_DSS | CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk usbhost_ick = { - .name = "usbhost_ick", - .clkdm_name = "usbhost_clkdm", - .type = TI_CLK_GATE, - .data = &usbhost_ick_data, -}; - -static struct ti_clk_gate mcbsp2_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 0, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk mcbsp2_ick = { - .name = "mcbsp2_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &mcbsp2_ick_data, -}; - -static struct ti_clk_gate omapctrl_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 6, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk omapctrl_ick = { - .name = "omapctrl_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &omapctrl_ick_data, -}; - -static struct ti_clk_fixed_factor omap_96m_d4_fck_data = { - .parent = "omap_96m_fck", - .div = 4, - .mult = 1, -}; - -static struct ti_clk omap_96m_d4_fck = { - .name = "omap_96m_d4_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &omap_96m_d4_fck_data, -}; - -static struct ti_clk_gate gpt6_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 7, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpt6_ick = { - .name = "gpt6_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpt6_ick_data, -}; - -static struct ti_clk_gate dpll3_m3x2_ck_omap36xx_data = { - .parent = "dpll3_m3x2_mul_ck", - .bit_shift = 0xc, - .reg = 0xd00, - .module = TI_CLKM_CM, - .flags = CLKF_HSDIV | CLKF_SET_BIT_TO_DISABLE, -}; - -static struct ti_clk dpll3_m3x2_ck_omap36xx = { - .name = "dpll3_m3x2_ck", - .type = TI_CLK_GATE, - .data = &dpll3_m3x2_ck_omap36xx_data, - .patch = &dpll3_m3x2_ck, -}; - -static struct ti_clk_gate i2c3_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 17, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk i2c3_ick = { - .name = "i2c3_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &i2c3_ick_data, -}; - -static struct ti_clk_gate gpio6_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 17, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpio6_ick = { - .name = "gpio6_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpio6_ick_data, -}; - -static struct ti_clk_gate mspro_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 23, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk mspro_ick = { - .name = "mspro_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mspro_ick_data, -}; - -static struct ti_clk_composite mcbsp1_fck_data = { - .mux = &mcbsp1_mux_fck_data, - .gate = &mcbsp1_gate_fck_data, -}; - -static struct ti_clk mcbsp1_fck = { - .name = "mcbsp1_fck", - .type = TI_CLK_COMPOSITE, - .data = &mcbsp1_fck_data, -}; - -static struct ti_clk_gate gpt3_gate_fck_data = { - .parent = "sys_ck", - .bit_shift = 4, - .reg = 0x1000, - .module = TI_CLKM_CM, -}; - -static struct ti_clk_fixed rmii_ck_data = { - .frequency = 50000000, -}; - -static struct ti_clk rmii_ck = { - .name = "rmii_ck", - .type = TI_CLK_FIXED, - .data = &rmii_ck_data, -}; - -static struct ti_clk_gate gpt6_gate_fck_data = { - .parent = "sys_ck", - .bit_shift = 7, - .reg = 0x1000, - .module = TI_CLKM_CM, -}; - -static struct ti_clk_composite gpt6_fck_data = { - .mux = &gpt6_mux_fck_data, - .gate = &gpt6_gate_fck_data, -}; - -static struct ti_clk gpt6_fck = { - .name = "gpt6_fck", - .type = TI_CLK_COMPOSITE, - .data = &gpt6_fck_data, -}; - -static struct ti_clk_fixed_factor dpll5_m2_d4_ck_data = { - .parent = "dpll5_m2_ck", - .div = 4, - .mult = 1, -}; - -static struct ti_clk dpll5_m2_d4_ck = { - .name = "dpll5_m2_d4_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &dpll5_m2_d4_ck_data, -}; - -static struct ti_clk_fixed_factor sys_d2_ck_data = { - .parent = "sys_ck", - .div = 2, - .mult = 1, -}; - -static struct ti_clk sys_d2_ck = { - .name = "sys_d2_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &sys_d2_ck_data, -}; - -static struct ti_clk_fixed_factor omap_96m_d2_fck_data = { - .parent = "omap_96m_fck", - .div = 2, - .mult = 1, -}; - -static struct ti_clk omap_96m_d2_fck = { - .name = "omap_96m_d2_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &omap_96m_d2_fck_data, -}; - -static struct ti_clk_fixed_factor dpll5_m2_d8_ck_data = { - .parent = "dpll5_m2_ck", - .div = 8, - .mult = 1, -}; - -static struct ti_clk dpll5_m2_d8_ck = { - .name = "dpll5_m2_d8_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &dpll5_m2_d8_ck_data, -}; - -static struct ti_clk_fixed_factor dpll5_m2_d16_ck_data = { - .parent = "dpll5_m2_ck", - .div = 16, - .mult = 1, -}; - -static struct ti_clk dpll5_m2_d16_ck = { - .name = "dpll5_m2_d16_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &dpll5_m2_d16_ck_data, -}; - -static const char *usim_mux_fck_parents[] = { - "sys_ck", - "sys_d2_ck", - "omap_96m_d2_fck", - "omap_96m_d4_fck", - "omap_96m_d8_fck", - "omap_96m_d10_fck", - "dpll5_m2_d4_ck", - "dpll5_m2_d8_ck", - "dpll5_m2_d16_ck", - "dpll5_m2_d20_ck", -}; - -static struct ti_clk_mux usim_mux_fck_data = { - .bit_shift = 3, - .num_parents = ARRAY_SIZE(usim_mux_fck_parents), - .reg = 0xc40, - .module = TI_CLKM_CM, - .parents = usim_mux_fck_parents, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk_composite usim_fck_data = { - .mux = &usim_mux_fck_data, - .gate = &usim_gate_fck_data, -}; - -static struct ti_clk usim_fck = { - .name = "usim_fck", - .type = TI_CLK_COMPOSITE, - .data = &usim_fck_data, -}; - -static int ssi_ssr_div_fck_3430es2_divs[] = { - 0, - 1, - 2, - 3, - 4, - 0, - 6, - 0, - 8, -}; - -static struct ti_clk_divider ssi_ssr_div_fck_3430es2_data = { - .num_dividers = ARRAY_SIZE(ssi_ssr_div_fck_3430es2_divs), - .parent = "corex2_fck", - .bit_shift = 8, - .dividers = ssi_ssr_div_fck_3430es2_divs, - .reg = 0xa40, - .module = TI_CLKM_CM, -}; - -static struct ti_clk_composite ssi_ssr_fck_3430es2_data = { - .gate = &ssi_ssr_gate_fck_3430es2_data, - .divider = &ssi_ssr_div_fck_3430es2_data, -}; - -static struct ti_clk ssi_ssr_fck_3430es2 = { - .name = "ssi_ssr_fck", - .type = TI_CLK_COMPOSITE, - .data = &ssi_ssr_fck_3430es2_data, -}; - -static struct ti_clk_gate dss1_alwon_fck_3430es1_data = { - .parent = "dpll4_m4x2_ck", - .bit_shift = 0, - .reg = 0xe00, - .module = TI_CLKM_CM, - .flags = CLKF_SET_RATE_PARENT, -}; - -static struct ti_clk dss1_alwon_fck_3430es1 = { - .name = "dss1_alwon_fck", - .clkdm_name = "dss_clkdm", - .type = TI_CLK_GATE, - .data = &dss1_alwon_fck_3430es1_data, -}; - -static struct ti_clk_gate gpt3_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 4, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpt3_ick = { - .name = "gpt3_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpt3_ick_data, -}; - -static struct ti_clk_fixed_factor omap_12m_fck_data = { - .parent = "omap_48m_fck", - .div = 4, - .mult = 1, -}; - -static struct ti_clk omap_12m_fck = { - .name = "omap_12m_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &omap_12m_fck_data, -}; - -static struct ti_clk_fixed_factor core_12m_fck_data = { - .parent = "omap_12m_fck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk core_12m_fck = { - .name = "core_12m_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &core_12m_fck_data, -}; - -static struct ti_clk_gate hdq_fck_data = { - .parent = "core_12m_fck", - .bit_shift = 22, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk hdq_fck = { - .name = "hdq_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &hdq_fck_data, -}; - -static struct ti_clk_gate usbtll_fck_data = { - .parent = "dpll5_m2_ck", - .bit_shift = 2, - .reg = 0xa08, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk usbtll_fck = { - .name = "usbtll_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &usbtll_fck_data, -}; - -static struct ti_clk_gate hsotgusb_fck_am35xx_data = { - .parent = "sys_ck", - .bit_shift = 8, - .reg = 0x59c, - .module = TI_CLKM_SCRM, -}; - -static struct ti_clk hsotgusb_fck_am35xx = { - .name = "hsotgusb_fck_am35xx", - .clkdm_name = "core_l3_clkdm", - .type = TI_CLK_GATE, - .data = &hsotgusb_fck_am35xx_data, -}; - -static struct ti_clk_gate hsotgusb_ick_3430es2_data = { - .parent = "core_l3_ick", - .bit_shift = 4, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_HSOTGUSB | CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk hsotgusb_ick_3430es2 = { - .name = "hsotgusb_ick_3430es2", - .clkdm_name = "core_l3_clkdm", - .type = TI_CLK_GATE, - .data = &hsotgusb_ick_3430es2_data, -}; - -static struct ti_clk_gate gfx_l3_ck_data = { - .parent = "l3_ick", - .bit_shift = 0, - .reg = 0xb10, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk gfx_l3_ck = { - .name = "gfx_l3_ck", - .clkdm_name = "gfx_3430es1_clkdm", - .type = TI_CLK_GATE, - .data = &gfx_l3_ck_data, -}; - -static struct ti_clk_fixed_factor gfx_l3_ick_data = { - .parent = "gfx_l3_ck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk gfx_l3_ick = { - .name = "gfx_l3_ick", - .type = TI_CLK_FIXED_FACTOR, - .data = &gfx_l3_ick_data, -}; - -static struct ti_clk_gate mcbsp1_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 9, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk mcbsp1_ick = { - .name = "mcbsp1_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mcbsp1_ick_data, -}; - -static struct ti_clk_fixed_factor gpt12_fck_data = { - .parent = "secure_32k_fck", - .div = 1, - .mult = 1, -}; - -static struct ti_clk gpt12_fck = { - .name = "gpt12_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &gpt12_fck_data, -}; - -static struct ti_clk_gate gfx_cg2_ck_data = { - .parent = "gfx_l3_fck", - .bit_shift = 2, - .reg = 0xb00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk gfx_cg2_ck = { - .name = "gfx_cg2_ck", - .clkdm_name = "gfx_3430es1_clkdm", - .type = TI_CLK_GATE, - .data = &gfx_cg2_ck_data, -}; - -static struct ti_clk_gate i2c2_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 16, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk i2c2_ick = { - .name = "i2c2_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &i2c2_ick_data, -}; - -static struct ti_clk_gate gpio4_dbck_data = { - .parent = "per_32k_alwon_fck", - .bit_shift = 15, - .reg = 0x1000, - .module = TI_CLKM_CM, -}; - -static struct ti_clk gpio4_dbck = { - .name = "gpio4_dbck", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpio4_dbck_data, -}; - -static struct ti_clk_gate i2c3_fck_data = { - .parent = "core_96m_fck", - .bit_shift = 17, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk i2c3_fck = { - .name = "i2c3_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &i2c3_fck_data, -}; - -static struct ti_clk_composite gpt3_fck_data = { - .mux = &gpt3_mux_fck_data, - .gate = &gpt3_gate_fck_data, -}; - -static struct ti_clk gpt3_fck = { - .name = "gpt3_fck", - .type = TI_CLK_COMPOSITE, - .data = &gpt3_fck_data, -}; - -static struct ti_clk_gate i2c1_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 15, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk i2c1_ick = { - .name = "i2c1_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &i2c1_ick_data, -}; - -static struct ti_clk_gate omap_32ksync_ick_data = { - .parent = "wkup_l4_ick", - .bit_shift = 2, - .reg = 0xc10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk omap_32ksync_ick = { - .name = "omap_32ksync_ick", - .clkdm_name = "wkup_clkdm", - .type = TI_CLK_GATE, - .data = &omap_32ksync_ick_data, -}; - -static struct ti_clk_gate aes2_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 28, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk aes2_ick = { - .name = "aes2_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &aes2_ick_data, -}; - -static const char *gpt8_mux_fck_parents[] = { - "omap_32k_fck", - "sys_ck", -}; - -static struct ti_clk_mux gpt8_mux_fck_data = { - .bit_shift = 6, - .num_parents = ARRAY_SIZE(gpt8_mux_fck_parents), - .reg = 0x1040, - .module = TI_CLKM_CM, - .parents = gpt8_mux_fck_parents, -}; - -static struct ti_clk_composite gpt8_fck_data = { - .mux = &gpt8_mux_fck_data, - .gate = &gpt8_gate_fck_data, -}; - -static struct ti_clk gpt8_fck = { - .name = "gpt8_fck", - .type = TI_CLK_COMPOSITE, - .data = &gpt8_fck_data, -}; - -static struct ti_clk_gate mcbsp4_gate_fck_data = { - .parent = "mcbsp_clks", - .bit_shift = 2, - .reg = 0x1000, - .module = TI_CLKM_CM, -}; - -static struct ti_clk_composite mcbsp4_fck_data = { - .mux = &mcbsp4_mux_fck_data, - .gate = &mcbsp4_gate_fck_data, -}; - -static struct ti_clk mcbsp4_fck = { - .name = "mcbsp4_fck", - .type = TI_CLK_COMPOSITE, - .data = &mcbsp4_fck_data, -}; - -static struct ti_clk_gate gpio2_dbck_data = { - .parent = "per_32k_alwon_fck", - .bit_shift = 13, - .reg = 0x1000, - .module = TI_CLKM_CM, -}; - -static struct ti_clk gpio2_dbck = { - .name = "gpio2_dbck", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpio2_dbck_data, -}; - -static struct ti_clk_gate usbtll_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 2, - .reg = 0xa18, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk usbtll_ick = { - .name = "usbtll_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &usbtll_ick_data, -}; - -static struct ti_clk_gate mcspi4_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 21, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk mcspi4_ick = { - .name = "mcspi4_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mcspi4_ick_data, -}; - -static struct ti_clk_gate dss_96m_fck_data = { - .parent = "omap_96m_fck", - .bit_shift = 2, - .reg = 0xe00, - .module = TI_CLKM_CM, -}; - -static struct ti_clk dss_96m_fck = { - .name = "dss_96m_fck", - .clkdm_name = "dss_clkdm", - .type = TI_CLK_GATE, - .data = &dss_96m_fck_data, -}; - -static struct ti_clk_divider rm_ick_data = { - .parent = "l4_ick", - .bit_shift = 1, - .max_div = 3, - .reg = 0xc40, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk rm_ick = { - .name = "rm_ick", - .type = TI_CLK_DIVIDER, - .data = &rm_ick_data, -}; - -static struct ti_clk_gate hdq_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 22, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk hdq_ick = { - .name = "hdq_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &hdq_ick_data, -}; - -static struct ti_clk_fixed_factor dpll3_x2_ck_data = { - .parent = "dpll3_ck", - .div = 1, - .mult = 2, -}; - -static struct ti_clk dpll3_x2_ck = { - .name = "dpll3_x2_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &dpll3_x2_ck_data, -}; - -static struct ti_clk_gate mad2d_ick_data = { - .parent = "l3_ick", - .bit_shift = 3, - .reg = 0xa18, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk mad2d_ick = { - .name = "mad2d_ick", - .clkdm_name = "d2d_clkdm", - .type = TI_CLK_GATE, - .data = &mad2d_ick_data, -}; - -static struct ti_clk_gate fshostusb_fck_data = { - .parent = "core_48m_fck", - .bit_shift = 5, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk fshostusb_fck = { - .name = "fshostusb_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &fshostusb_fck_data, -}; - -static struct ti_clk_gate sr1_fck_data = { - .parent = "sys_ck", - .bit_shift = 6, - .reg = 0xc00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk sr1_fck = { - .name = "sr1_fck", - .clkdm_name = "wkup_clkdm", - .type = TI_CLK_GATE, - .data = &sr1_fck_data, -}; - -static struct ti_clk_gate des2_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 26, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk des2_ick = { - .name = "des2_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &des2_ick_data, -}; - -static struct ti_clk_gate sdrc_ick_data = { - .parent = "core_l3_ick", - .bit_shift = 1, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk sdrc_ick = { - .name = "sdrc_ick", - .clkdm_name = "core_l3_clkdm", - .type = TI_CLK_GATE, - .data = &sdrc_ick_data, -}; - -static struct ti_clk_composite gpt4_fck_data = { - .mux = &gpt4_mux_fck_data, - .gate = &gpt4_gate_fck_data, -}; - -static struct ti_clk gpt4_fck = { - .name = "gpt4_fck", - .type = TI_CLK_COMPOSITE, - .data = &gpt4_fck_data, -}; - -static struct ti_clk_gate dpll4_m3x2_ck_omap36xx_data = { - .parent = "dpll4_m3x2_mul_ck", - .bit_shift = 0x1c, - .reg = 0xd00, - .module = TI_CLKM_CM, - .flags = CLKF_HSDIV | CLKF_SET_BIT_TO_DISABLE, -}; - -static struct ti_clk dpll4_m3x2_ck_omap36xx = { - .name = "dpll4_m3x2_ck", - .type = TI_CLK_GATE, - .data = &dpll4_m3x2_ck_omap36xx_data, - .patch = &dpll4_m3x2_ck, -}; - -static struct ti_clk_gate cpefuse_fck_data = { - .parent = "sys_ck", - .bit_shift = 0, - .reg = 0xa08, - .module = TI_CLKM_CM, -}; - -static struct ti_clk cpefuse_fck = { - .name = "cpefuse_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &cpefuse_fck_data, -}; - -static struct ti_clk_gate mcspi3_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 20, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk mcspi3_ick = { - .name = "mcspi3_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mcspi3_ick_data, -}; - -static struct ti_clk_fixed_factor ssi_sst_fck_3430es2_data = { - .parent = "ssi_ssr_fck", - .div = 2, - .mult = 1, -}; - -static struct ti_clk ssi_sst_fck_3430es2 = { - .name = "ssi_sst_fck", - .type = TI_CLK_FIXED_FACTOR, - .data = &ssi_sst_fck_3430es2_data, -}; - -static struct ti_clk_gate gpio1_dbck_data = { - .parent = "wkup_32k_fck", - .bit_shift = 3, - .reg = 0xc00, - .module = TI_CLKM_CM, -}; - -static struct ti_clk gpio1_dbck = { - .name = "gpio1_dbck", - .clkdm_name = "wkup_clkdm", - .type = TI_CLK_GATE, - .data = &gpio1_dbck_data, -}; - -static struct ti_clk_gate gpt4_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 5, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpt4_ick = { - .name = "gpt4_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpt4_ick_data, -}; - -static struct ti_clk_gate gpt2_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 3, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpt2_ick = { - .name = "gpt2_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpt2_ick_data, -}; - -static struct ti_clk_gate mmchs1_fck_data = { - .parent = "core_96m_fck", - .bit_shift = 24, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk mmchs1_fck = { - .name = "mmchs1_fck", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mmchs1_fck_data, -}; - -static struct ti_clk_fixed dummy_apb_pclk_data = { - .frequency = 0x0, -}; - -static struct ti_clk dummy_apb_pclk = { - .name = "dummy_apb_pclk", - .type = TI_CLK_FIXED, - .data = &dummy_apb_pclk_data, -}; - -static struct ti_clk_gate gpio6_dbck_data = { - .parent = "per_32k_alwon_fck", - .bit_shift = 17, - .reg = 0x1000, - .module = TI_CLKM_CM, -}; - -static struct ti_clk gpio6_dbck = { - .name = "gpio6_dbck", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpio6_dbck_data, -}; - -static struct ti_clk_gate uart2_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 14, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk uart2_ick = { - .name = "uart2_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &uart2_ick_data, -}; - -static struct ti_clk_fixed_factor dpll4_x2_ck_data = { - .parent = "dpll4_ck", - .div = 1, - .mult = 2, -}; - -static struct ti_clk dpll4_x2_ck = { - .name = "dpll4_x2_ck", - .type = TI_CLK_FIXED_FACTOR, - .data = &dpll4_x2_ck_data, -}; - -static struct ti_clk_gate gpt7_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 8, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpt7_ick = { - .name = "gpt7_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpt7_ick_data, -}; - -static struct ti_clk_gate dss_tv_fck_data = { - .parent = "omap_54m_fck", - .bit_shift = 2, - .reg = 0xe00, - .module = TI_CLKM_CM, -}; - -static struct ti_clk dss_tv_fck = { - .name = "dss_tv_fck", - .clkdm_name = "dss_clkdm", - .type = TI_CLK_GATE, - .data = &dss_tv_fck_data, -}; - -static struct ti_clk_gate mcbsp5_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 10, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk mcbsp5_ick = { - .name = "mcbsp5_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mcbsp5_ick_data, -}; - -static struct ti_clk_gate mcspi1_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 18, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk mcspi1_ick = { - .name = "mcspi1_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &mcspi1_ick_data, -}; - -static struct ti_clk_gate d2d_26m_fck_data = { - .parent = "sys_ck", - .bit_shift = 3, - .reg = 0xa00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk d2d_26m_fck = { - .name = "d2d_26m_fck", - .clkdm_name = "d2d_clkdm", - .type = TI_CLK_GATE, - .data = &d2d_26m_fck_data, -}; - -static struct ti_clk_gate wdt3_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 12, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk wdt3_ick = { - .name = "wdt3_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &wdt3_ick_data, -}; - -static struct ti_clk_divider pclkx2_fck_data = { - .parent = "emu_src_ck", - .bit_shift = 6, - .max_div = 3, - .reg = 0x1140, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_STARTS_AT_ONE, -}; - -static struct ti_clk pclkx2_fck = { - .name = "pclkx2_fck", - .type = TI_CLK_DIVIDER, - .data = &pclkx2_fck_data, -}; - -static struct ti_clk_gate sha12_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 27, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk sha12_ick = { - .name = "sha12_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &sha12_ick_data, -}; - -static struct ti_clk_gate emac_fck_data = { - .parent = "rmii_ck", - .bit_shift = 9, - .reg = 0x59c, - .module = TI_CLKM_SCRM, -}; - -static struct ti_clk emac_fck = { - .name = "emac_fck", - .type = TI_CLK_GATE, - .data = &emac_fck_data, -}; - -static struct ti_clk_composite gpt10_fck_data = { - .mux = &gpt10_mux_fck_data, - .gate = &gpt10_gate_fck_data, -}; - -static struct ti_clk gpt10_fck = { - .name = "gpt10_fck", - .type = TI_CLK_COMPOSITE, - .data = &gpt10_fck_data, -}; - -static struct ti_clk_gate wdt2_fck_data = { - .parent = "wkup_32k_fck", - .bit_shift = 5, - .reg = 0xc00, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk wdt2_fck = { - .name = "wdt2_fck", - .clkdm_name = "wkup_clkdm", - .type = TI_CLK_GATE, - .data = &wdt2_fck_data, -}; - -static struct ti_clk_gate cam_ick_data = { - .parent = "l4_ick", - .bit_shift = 0, - .reg = 0xf10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_NO_WAIT | CLKF_INTERFACE, -}; - -static struct ti_clk cam_ick = { - .name = "cam_ick", - .clkdm_name = "cam_clkdm", - .type = TI_CLK_GATE, - .data = &cam_ick_data, -}; - -static struct ti_clk_gate ssi_ick_3430es2_data = { - .parent = "ssi_l4_ick", - .bit_shift = 0, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_SSI | CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk ssi_ick_3430es2 = { - .name = "ssi_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &ssi_ick_3430es2_data, -}; - -static struct ti_clk_gate gpio4_ick_data = { - .parent = "per_l4_ick", - .bit_shift = 15, - .reg = 0x1010, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk gpio4_ick = { - .name = "gpio4_ick", - .clkdm_name = "per_clkdm", - .type = TI_CLK_GATE, - .data = &gpio4_ick_data, -}; - -static struct ti_clk_gate wdt1_ick_data = { - .parent = "wkup_l4_ick", - .bit_shift = 4, - .reg = 0xc10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk wdt1_ick = { - .name = "wdt1_ick", - .clkdm_name = "wkup_clkdm", - .type = TI_CLK_GATE, - .data = &wdt1_ick_data, -}; - -static struct ti_clk_gate rng_ick_data = { - .parent = "security_l4_ick2", - .bit_shift = 2, - .reg = 0xa14, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk rng_ick = { - .name = "rng_ick", - .type = TI_CLK_GATE, - .data = &rng_ick_data, -}; - -static struct ti_clk_gate icr_ick_data = { - .parent = "core_l4_ick", - .bit_shift = 29, - .reg = 0xa10, - .module = TI_CLKM_CM, - .flags = CLKF_OMAP3 | CLKF_INTERFACE, -}; - -static struct ti_clk icr_ick = { - .name = "icr_ick", - .clkdm_name = "core_l4_clkdm", - .type = TI_CLK_GATE, - .data = &icr_ick_data, -}; - -static struct ti_clk_gate sgx_ick_data = { - .parent = "l3_ick", - .bit_shift = 0, - .reg = 0xb10, - .module = TI_CLKM_CM, - .flags = CLKF_WAIT, -}; - -static struct ti_clk sgx_ick = { - .name = "sgx_ick", - .clkdm_name = "sgx_clkdm", - .type = TI_CLK_GATE, - .data = &sgx_ick_data, -}; - -static struct ti_clk_divider sys_clkout2_data = { - .parent = "clkout2_src_ck", - .bit_shift = 3, - .max_div = 64, - .reg = 0xd70, - .module = TI_CLKM_CM, - .flags = CLKF_INDEX_POWER_OF_TWO, -}; - -static struct ti_clk sys_clkout2 = { - .name = "sys_clkout2", - .type = TI_CLK_DIVIDER, - .data = &sys_clkout2_data, -}; - -static struct ti_clk_alias omap34xx_omap36xx_clks[] = { - CLK(NULL, "security_l4_ick2", &security_l4_ick2), - CLK(NULL, "aes1_ick", &aes1_ick), - CLK("omap_rng", "ick", &rng_ick), - CLK("omap3-rom-rng", "ick", &rng_ick), - CLK(NULL, "sha11_ick", &sha11_ick), - CLK(NULL, "des1_ick", &des1_ick), - CLK(NULL, "cam_mclk", &cam_mclk), - CLK(NULL, "cam_ick", &cam_ick), - CLK(NULL, "csi2_96m_fck", &csi2_96m_fck), - CLK(NULL, "security_l3_ick", &security_l3_ick), - CLK(NULL, "pka_ick", &pka_ick), - CLK(NULL, "icr_ick", &icr_ick), - CLK(NULL, "des2_ick", &des2_ick), - CLK(NULL, "mspro_ick", &mspro_ick), - CLK(NULL, "mailboxes_ick", &mailboxes_ick), - CLK(NULL, "ssi_l4_ick", &ssi_l4_ick), - CLK(NULL, "sr1_fck", &sr1_fck), - CLK(NULL, "sr2_fck", &sr2_fck), - CLK(NULL, "sr_l4_ick", &sr_l4_ick), - CLK(NULL, "dpll2_fck", &dpll2_fck), - CLK(NULL, "dpll2_ck", &dpll2_ck), - CLK(NULL, "dpll2_m2_ck", &dpll2_m2_ck), - CLK(NULL, "iva2_ck", &iva2_ck), - CLK(NULL, "modem_fck", &modem_fck), - CLK(NULL, "sad2d_ick", &sad2d_ick), - CLK(NULL, "mad2d_ick", &mad2d_ick), - CLK(NULL, "mspro_fck", &mspro_fck), - { NULL }, -}; - -static struct ti_clk_alias omap36xx_omap3430es2plus_clks[] = { - CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck_3430es2), - CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es2), - CLK("musb-omap2430", "ick", &hsotgusb_ick_3430es2), - CLK(NULL, "hsotgusb_ick", &hsotgusb_ick_3430es2), - CLK(NULL, "ssi_ick", &ssi_ick_3430es2), - CLK(NULL, "sys_d2_ck", &sys_d2_ck), - CLK(NULL, "omap_96m_d2_fck", &omap_96m_d2_fck), - CLK(NULL, "omap_96m_d4_fck", &omap_96m_d4_fck), - CLK(NULL, "omap_96m_d8_fck", &omap_96m_d8_fck), - CLK(NULL, "omap_96m_d10_fck", &omap_96m_d10_fck), - CLK(NULL, "dpll5_m2_d4_ck", &dpll5_m2_d4_ck), - CLK(NULL, "dpll5_m2_d8_ck", &dpll5_m2_d8_ck), - CLK(NULL, "dpll5_m2_d16_ck", &dpll5_m2_d16_ck), - CLK(NULL, "dpll5_m2_d20_ck", &dpll5_m2_d20_ck), - CLK(NULL, "usim_fck", &usim_fck), - CLK(NULL, "usim_ick", &usim_ick), - { NULL }, -}; - -static struct ti_clk_alias omap3xxx_clks[] = { - CLK(NULL, "apb_pclk", &dummy_apb_pclk), - CLK(NULL, "omap_32k_fck", &omap_32k_fck), - CLK(NULL, "virt_12m_ck", &virt_12m_ck), - CLK(NULL, "virt_13m_ck", &virt_13m_ck), - CLK(NULL, "virt_19200000_ck", &virt_19200000_ck), - CLK(NULL, "virt_26000000_ck", &virt_26000000_ck), - CLK(NULL, "virt_38_4m_ck", &virt_38_4m_ck), - CLK(NULL, "virt_16_8m_ck", &virt_16_8m_ck), - CLK(NULL, "osc_sys_ck", &osc_sys_ck), - CLK("twl", "fck", &osc_sys_ck), - CLK(NULL, "sys_ck", &sys_ck), - CLK(NULL, "timer_sys_ck", &sys_ck), - CLK(NULL, "dpll4_ck", &dpll4_ck), - CLK(NULL, "dpll4_m2_ck", &dpll4_m2_ck), - CLK(NULL, "dpll4_m2x2_mul_ck", &dpll4_m2x2_mul_ck), - CLK(NULL, "dpll4_m2x2_ck", &dpll4_m2x2_ck), - CLK(NULL, "omap_96m_alwon_fck", &omap_96m_alwon_fck), - CLK(NULL, "dpll3_ck", &dpll3_ck), - CLK(NULL, "dpll3_m3_ck", &dpll3_m3_ck), - CLK(NULL, "dpll3_m3x2_mul_ck", &dpll3_m3x2_mul_ck), - CLK(NULL, "dpll3_m3x2_ck", &dpll3_m3x2_ck), - CLK("etb", "emu_core_alwon_ck", &emu_core_alwon_ck), - CLK(NULL, "sys_altclk", &sys_altclk), - CLK(NULL, "sys_clkout1", &sys_clkout1), - CLK(NULL, "dpll3_m2_ck", &dpll3_m2_ck), - CLK(NULL, "core_ck", &core_ck), - CLK(NULL, "dpll1_fck", &dpll1_fck), - CLK(NULL, "dpll1_ck", &dpll1_ck), - CLK(NULL, "cpufreq_ck", &dpll1_ck), - CLK(NULL, "dpll1_x2_ck", &dpll1_x2_ck), - CLK(NULL, "dpll1_x2m2_ck", &dpll1_x2m2_ck), - CLK(NULL, "dpll3_x2_ck", &dpll3_x2_ck), - CLK(NULL, "dpll3_m2x2_ck", &dpll3_m2x2_ck), - CLK(NULL, "dpll4_x2_ck", &dpll4_x2_ck), - CLK(NULL, "cm_96m_fck", &cm_96m_fck), - CLK(NULL, "omap_96m_fck", &omap_96m_fck), - CLK(NULL, "dpll4_m3_ck", &dpll4_m3_ck), - CLK(NULL, "dpll4_m3x2_mul_ck", &dpll4_m3x2_mul_ck), - CLK(NULL, "dpll4_m3x2_ck", &dpll4_m3x2_ck), - CLK(NULL, "omap_54m_fck", &omap_54m_fck), - CLK(NULL, "cm_96m_d2_fck", &cm_96m_d2_fck), - CLK(NULL, "omap_48m_fck", &omap_48m_fck), - CLK(NULL, "omap_12m_fck", &omap_12m_fck), - CLK(NULL, "dpll4_m4_ck", &dpll4_m4_ck), - CLK(NULL, "dpll4_m4x2_mul_ck", &dpll4_m4x2_mul_ck), - CLK(NULL, "dpll4_m4x2_ck", &dpll4_m4x2_ck), - CLK(NULL, "dpll4_m5_ck", &dpll4_m5_ck), - CLK(NULL, "dpll4_m5x2_mul_ck", &dpll4_m5x2_mul_ck), - CLK(NULL, "dpll4_m5x2_ck", &dpll4_m5x2_ck), - CLK(NULL, "dpll4_m6_ck", &dpll4_m6_ck), - CLK(NULL, "dpll4_m6x2_mul_ck", &dpll4_m6x2_mul_ck), - CLK(NULL, "dpll4_m6x2_ck", &dpll4_m6x2_ck), - CLK("etb", "emu_per_alwon_ck", &emu_per_alwon_ck), - CLK(NULL, "clkout2_src_ck", &clkout2_src_ck), - CLK(NULL, "sys_clkout2", &sys_clkout2), - CLK(NULL, "corex2_fck", &corex2_fck), - CLK(NULL, "mpu_ck", &mpu_ck), - CLK(NULL, "arm_fck", &arm_fck), - CLK("etb", "emu_mpu_alwon_ck", &emu_mpu_alwon_ck), - CLK(NULL, "l3_ick", &l3_ick), - CLK(NULL, "l4_ick", &l4_ick), - CLK(NULL, "rm_ick", &rm_ick), - CLK(NULL, "timer_32k_ck", &omap_32k_fck), - CLK(NULL, "gpt10_fck", &gpt10_fck), - CLK(NULL, "gpt11_fck", &gpt11_fck), - CLK(NULL, "core_96m_fck", &core_96m_fck), - CLK(NULL, "mmchs2_fck", &mmchs2_fck), - CLK(NULL, "mmchs1_fck", &mmchs1_fck), - CLK(NULL, "i2c3_fck", &i2c3_fck), - CLK(NULL, "i2c2_fck", &i2c2_fck), - CLK(NULL, "i2c1_fck", &i2c1_fck), - CLK(NULL, "core_48m_fck", &core_48m_fck), - CLK(NULL, "mcspi4_fck", &mcspi4_fck), - CLK(NULL, "mcspi3_fck", &mcspi3_fck), - CLK(NULL, "mcspi2_fck", &mcspi2_fck), - CLK(NULL, "mcspi1_fck", &mcspi1_fck), - CLK(NULL, "uart2_fck", &uart2_fck), - CLK(NULL, "uart1_fck", &uart1_fck), - CLK(NULL, "core_12m_fck", &core_12m_fck), - CLK("omap_hdq.0", "fck", &hdq_fck), - CLK(NULL, "hdq_fck", &hdq_fck), - CLK(NULL, "core_l3_ick", &core_l3_ick), - CLK(NULL, "sdrc_ick", &sdrc_ick), - CLK(NULL, "gpmc_fck", &gpmc_fck), - CLK(NULL, "core_l4_ick", &core_l4_ick), - CLK("omap_hsmmc.1", "ick", &mmchs2_ick), - CLK("omap_hsmmc.0", "ick", &mmchs1_ick), - CLK(NULL, "mmchs2_ick", &mmchs2_ick), - CLK(NULL, "mmchs1_ick", &mmchs1_ick), - CLK("omap_hdq.0", "ick", &hdq_ick), - CLK(NULL, "hdq_ick", &hdq_ick), - CLK("omap2_mcspi.4", "ick", &mcspi4_ick), - CLK("omap2_mcspi.3", "ick", &mcspi3_ick), - CLK("omap2_mcspi.2", "ick", &mcspi2_ick), - CLK("omap2_mcspi.1", "ick", &mcspi1_ick), - CLK(NULL, "mcspi4_ick", &mcspi4_ick), - CLK(NULL, "mcspi3_ick", &mcspi3_ick), - CLK(NULL, "mcspi2_ick", &mcspi2_ick), - CLK(NULL, "mcspi1_ick", &mcspi1_ick), - CLK("omap_i2c.3", "ick", &i2c3_ick), - CLK("omap_i2c.2", "ick", &i2c2_ick), - CLK("omap_i2c.1", "ick", &i2c1_ick), - CLK(NULL, "i2c3_ick", &i2c3_ick), - CLK(NULL, "i2c2_ick", &i2c2_ick), - CLK(NULL, "i2c1_ick", &i2c1_ick), - CLK(NULL, "uart2_ick", &uart2_ick), - CLK(NULL, "uart1_ick", &uart1_ick), - CLK(NULL, "gpt11_ick", &gpt11_ick), - CLK(NULL, "gpt10_ick", &gpt10_ick), - CLK(NULL, "mcbsp5_ick", &mcbsp5_ick), - CLK(NULL, "mcbsp1_ick", &mcbsp1_ick), - CLK(NULL, "omapctrl_ick", &omapctrl_ick), - CLK(NULL, "dss_tv_fck", &dss_tv_fck), - CLK(NULL, "dss_96m_fck", &dss_96m_fck), - CLK(NULL, "dss2_alwon_fck", &dss2_alwon_fck), - CLK(NULL, "init_60m_fclk", &dummy_ck), - CLK(NULL, "gpt1_fck", &gpt1_fck), - CLK(NULL, "aes2_ick", &aes2_ick), - CLK(NULL, "wkup_32k_fck", &wkup_32k_fck), - CLK(NULL, "gpio1_dbck", &gpio1_dbck), - CLK(NULL, "sha12_ick", &sha12_ick), - CLK(NULL, "wdt2_fck", &wdt2_fck), - CLK(NULL, "wkup_l4_ick", &wkup_l4_ick), - CLK("omap_wdt", "ick", &wdt2_ick), - CLK(NULL, "wdt2_ick", &wdt2_ick), - CLK(NULL, "wdt1_ick", &wdt1_ick), - CLK(NULL, "gpio1_ick", &gpio1_ick), - CLK(NULL, "omap_32ksync_ick", &omap_32ksync_ick), - CLK(NULL, "gpt12_ick", &gpt12_ick), - CLK(NULL, "gpt1_ick", &gpt1_ick), - CLK(NULL, "per_96m_fck", &per_96m_fck), - CLK(NULL, "per_48m_fck", &per_48m_fck), - CLK(NULL, "uart3_fck", &uart3_fck), - CLK(NULL, "gpt2_fck", &gpt2_fck), - CLK(NULL, "gpt3_fck", &gpt3_fck), - CLK(NULL, "gpt4_fck", &gpt4_fck), - CLK(NULL, "gpt5_fck", &gpt5_fck), - CLK(NULL, "gpt6_fck", &gpt6_fck), - CLK(NULL, "gpt7_fck", &gpt7_fck), - CLK(NULL, "gpt8_fck", &gpt8_fck), - CLK(NULL, "gpt9_fck", &gpt9_fck), - CLK(NULL, "per_32k_alwon_fck", &per_32k_alwon_fck), - CLK(NULL, "gpio6_dbck", &gpio6_dbck), - CLK(NULL, "gpio5_dbck", &gpio5_dbck), - CLK(NULL, "gpio4_dbck", &gpio4_dbck), - CLK(NULL, "gpio3_dbck", &gpio3_dbck), - CLK(NULL, "gpio2_dbck", &gpio2_dbck), - CLK(NULL, "wdt3_fck", &wdt3_fck), - CLK(NULL, "per_l4_ick", &per_l4_ick), - CLK(NULL, "gpio6_ick", &gpio6_ick), - CLK(NULL, "gpio5_ick", &gpio5_ick), - CLK(NULL, "gpio4_ick", &gpio4_ick), - CLK(NULL, "gpio3_ick", &gpio3_ick), - CLK(NULL, "gpio2_ick", &gpio2_ick), - CLK(NULL, "wdt3_ick", &wdt3_ick), - CLK(NULL, "uart3_ick", &uart3_ick), - CLK(NULL, "uart4_ick", &uart4_ick), - CLK(NULL, "gpt9_ick", &gpt9_ick), - CLK(NULL, "gpt8_ick", &gpt8_ick), - CLK(NULL, "gpt7_ick", &gpt7_ick), - CLK(NULL, "gpt6_ick", &gpt6_ick), - CLK(NULL, "gpt5_ick", &gpt5_ick), - CLK(NULL, "gpt4_ick", &gpt4_ick), - CLK(NULL, "gpt3_ick", &gpt3_ick), - CLK(NULL, "gpt2_ick", &gpt2_ick), - CLK(NULL, "mcbsp_clks", &mcbsp_clks), - CLK("omap-mcbsp.1", "ick", &mcbsp1_ick), - CLK("omap-mcbsp.2", "ick", &mcbsp2_ick), - CLK("omap-mcbsp.3", "ick", &mcbsp3_ick), - CLK("omap-mcbsp.4", "ick", &mcbsp4_ick), - CLK("omap-mcbsp.5", "ick", &mcbsp5_ick), - CLK(NULL, "mcbsp1_ick", &mcbsp1_ick), - CLK(NULL, "mcbsp2_ick", &mcbsp2_ick), - CLK(NULL, "mcbsp3_ick", &mcbsp3_ick), - CLK(NULL, "mcbsp4_ick", &mcbsp4_ick), - CLK(NULL, "mcbsp5_ick", &mcbsp5_ick), - CLK(NULL, "mcbsp1_fck", &mcbsp1_fck), - CLK(NULL, "mcbsp2_fck", &mcbsp2_fck), - CLK(NULL, "mcbsp3_fck", &mcbsp3_fck), - CLK(NULL, "mcbsp4_fck", &mcbsp4_fck), - CLK(NULL, "mcbsp5_fck", &mcbsp5_fck), - CLK(NULL, "emu_src_mux_ck", &emu_src_mux_ck), - CLK("etb", "emu_src_ck", &emu_src_ck), - CLK(NULL, "emu_src_mux_ck", &emu_src_mux_ck), - CLK(NULL, "emu_src_ck", &emu_src_ck), - CLK(NULL, "pclk_fck", &pclk_fck), - CLK(NULL, "pclkx2_fck", &pclkx2_fck), - CLK(NULL, "atclk_fck", &atclk_fck), - CLK(NULL, "traceclk_src_fck", &traceclk_src_fck), - CLK(NULL, "traceclk_fck", &traceclk_fck), - CLK(NULL, "secure_32k_fck", &secure_32k_fck), - CLK(NULL, "gpt12_fck", &gpt12_fck), - CLK(NULL, "wdt1_fck", &wdt1_fck), - { NULL }, -}; - -static struct ti_clk_alias omap36xx_am35xx_omap3430es2plus_clks[] = { - CLK(NULL, "dpll5_ck", &dpll5_ck), - CLK(NULL, "dpll5_m2_ck", &dpll5_m2_ck), - CLK(NULL, "core_d3_ck", &core_d3_ck), - CLK(NULL, "core_d4_ck", &core_d4_ck), - CLK(NULL, "core_d6_ck", &core_d6_ck), - CLK(NULL, "omap_192m_alwon_fck", &omap_192m_alwon_fck), - CLK(NULL, "core_d2_ck", &core_d2_ck), - CLK(NULL, "corex2_d3_fck", &corex2_d3_fck), - CLK(NULL, "corex2_d5_fck", &corex2_d5_fck), - CLK(NULL, "sgx_fck", &sgx_fck), - CLK(NULL, "sgx_ick", &sgx_ick), - CLK(NULL, "cpefuse_fck", &cpefuse_fck), - CLK(NULL, "ts_fck", &ts_fck), - CLK(NULL, "usbtll_fck", &usbtll_fck), - CLK(NULL, "usbtll_ick", &usbtll_ick), - CLK("omap_hsmmc.2", "ick", &mmchs3_ick), - CLK(NULL, "mmchs3_ick", &mmchs3_ick), - CLK(NULL, "mmchs3_fck", &mmchs3_fck), - CLK(NULL, "dss1_alwon_fck", &dss1_alwon_fck_3430es2), - CLK("omapdss_dss", "ick", &dss_ick_3430es2), - CLK(NULL, "dss_ick", &dss_ick_3430es2), - CLK(NULL, "usbhost_120m_fck", &usbhost_120m_fck), - CLK(NULL, "usbhost_48m_fck", &usbhost_48m_fck), - CLK(NULL, "usbhost_ick", &usbhost_ick), - { NULL }, -}; - -static struct ti_clk_alias omap3430es1_clks[] = { - CLK(NULL, "gfx_l3_ck", &gfx_l3_ck), - CLK(NULL, "gfx_l3_fck", &gfx_l3_fck), - CLK(NULL, "gfx_l3_ick", &gfx_l3_ick), - CLK(NULL, "gfx_cg1_ck", &gfx_cg1_ck), - CLK(NULL, "gfx_cg2_ck", &gfx_cg2_ck), - CLK(NULL, "d2d_26m_fck", &d2d_26m_fck), - CLK(NULL, "fshostusb_fck", &fshostusb_fck), - CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck_3430es1), - CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es1), - CLK("musb-omap2430", "ick", &hsotgusb_ick_3430es1), - CLK(NULL, "hsotgusb_ick", &hsotgusb_ick_3430es1), - CLK(NULL, "fac_ick", &fac_ick), - CLK(NULL, "ssi_ick", &ssi_ick_3430es1), - CLK(NULL, "usb_l4_ick", &usb_l4_ick), - CLK(NULL, "dss1_alwon_fck", &dss1_alwon_fck_3430es1), - CLK("omapdss_dss", "ick", &dss_ick_3430es1), - CLK(NULL, "dss_ick", &dss_ick_3430es1), - { NULL }, -}; - -static struct ti_clk_alias omap36xx_clks[] = { - CLK(NULL, "uart4_fck", &uart4_fck), - { NULL }, -}; - -static struct ti_clk_alias am35xx_clks[] = { - CLK(NULL, "ipss_ick", &ipss_ick), - CLK(NULL, "rmii_ck", &rmii_ck), - CLK(NULL, "pclk_ck", &pclk_ck), - CLK(NULL, "emac_ick", &emac_ick), - CLK(NULL, "emac_fck", &emac_fck), - CLK("davinci_emac.0", NULL, &emac_ick), - CLK("davinci_mdio.0", NULL, &emac_fck), - CLK("vpfe-capture", "master", &vpfe_ick), - CLK("vpfe-capture", "slave", &vpfe_fck), - CLK(NULL, "hsotgusb_ick", &hsotgusb_ick_am35xx), - CLK(NULL, "hsotgusb_fck", &hsotgusb_fck_am35xx), - CLK(NULL, "hecc_ck", &hecc_ck), - CLK(NULL, "uart4_ick", &uart4_ick_am35xx), - CLK(NULL, "uart4_fck", &uart4_fck_am35xx), - { NULL }, -}; - -static struct ti_clk *omap36xx_clk_patches[] = { - &dpll4_m3x2_ck_omap36xx, - &dpll3_m3x2_ck_omap36xx, - &dpll4_m6x2_ck_omap36xx, - &dpll4_m2x2_ck_omap36xx, - &dpll4_m5x2_ck_omap36xx, - &dpll4_ck_omap36xx, - NULL, -}; - -static const char *enable_init_clks[] = { - "sdrc_ick", - "gpmc_fck", - "omapctrl_ick", -}; - -static void __init omap3_clk_legacy_common_init(void) -{ - omap2_clk_disable_autoidle_all(); - - omap2_clk_enable_init_clocks(enable_init_clks, - ARRAY_SIZE(enable_init_clks)); - - pr_info("Clocking rate (Crystal/Core/MPU): %ld.%01ld/%ld/%ld MHz\n", - (clk_get_rate(osc_sys_ck.clk) / 1000000), - (clk_get_rate(osc_sys_ck.clk) / 100000) % 10, - (clk_get_rate(core_ck.clk) / 1000000), - (clk_get_rate(arm_fck.clk) / 1000000)); -} - -int __init omap3430es1_clk_legacy_init(void) -{ - int r; - - r = ti_clk_register_legacy_clks(omap3430es1_clks); - r |= ti_clk_register_legacy_clks(omap34xx_omap36xx_clks); - r |= ti_clk_register_legacy_clks(omap3xxx_clks); - - omap3_clk_legacy_common_init(); - - return r; -} - -int __init omap3430_clk_legacy_init(void) -{ - int r; - - r = ti_clk_register_legacy_clks(omap34xx_omap36xx_clks); - r |= ti_clk_register_legacy_clks(omap36xx_omap3430es2plus_clks); - r |= ti_clk_register_legacy_clks(omap36xx_am35xx_omap3430es2plus_clks); - r |= ti_clk_register_legacy_clks(omap3xxx_clks); - - omap3_clk_legacy_common_init(); - omap3_clk_lock_dpll5(); - - return r; -} - -int __init omap36xx_clk_legacy_init(void) -{ - int r; - - ti_clk_patch_legacy_clks(omap36xx_clk_patches); - r = ti_clk_register_legacy_clks(omap36xx_clks); - r |= ti_clk_register_legacy_clks(omap36xx_omap3430es2plus_clks); - r |= ti_clk_register_legacy_clks(omap34xx_omap36xx_clks); - r |= ti_clk_register_legacy_clks(omap36xx_am35xx_omap3430es2plus_clks); - r |= ti_clk_register_legacy_clks(omap3xxx_clks); - - omap3_clk_legacy_common_init(); - omap3_clk_lock_dpll5(); - - return r; -} - -int __init am35xx_clk_legacy_init(void) -{ - int r; - - r = ti_clk_register_legacy_clks(am35xx_clks); - r |= ti_clk_register_legacy_clks(omap36xx_am35xx_omap3430es2plus_clks); - r |= ti_clk_register_legacy_clks(omap3xxx_clks); - - omap3_clk_legacy_common_init(); - omap3_clk_lock_dpll5(); - - return r; -} diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c index b1251cae98b8..8aa5f5793835 100644 --- a/drivers/clk/ti/clk-3xxx.c +++ b/drivers/clk/ti/clk-3xxx.c @@ -224,296 +224,43 @@ const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait = { }; static struct ti_dt_clk omap3xxx_clks[] = { - DT_CLK(NULL, "apb_pclk", "dummy_apb_pclk"), - DT_CLK(NULL, "omap_32k_fck", "omap_32k_fck"), - DT_CLK(NULL, "virt_12m_ck", "virt_12m_ck"), - DT_CLK(NULL, "virt_13m_ck", "virt_13m_ck"), - DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), - DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), - DT_CLK(NULL, "virt_38_4m_ck", "virt_38_4m_ck"), - DT_CLK(NULL, "osc_sys_ck", "osc_sys_ck"), - DT_CLK("twl", "fck", "osc_sys_ck"), - DT_CLK(NULL, "sys_ck", "sys_ck"), - DT_CLK(NULL, "omap_96m_alwon_fck", "omap_96m_alwon_fck"), - DT_CLK("etb", "emu_core_alwon_ck", "emu_core_alwon_ck"), - DT_CLK(NULL, "sys_altclk", "sys_altclk"), - DT_CLK(NULL, "sys_clkout1", "sys_clkout1"), - DT_CLK(NULL, "dpll1_ck", "dpll1_ck"), - DT_CLK(NULL, "dpll1_x2_ck", "dpll1_x2_ck"), - DT_CLK(NULL, "dpll1_x2m2_ck", "dpll1_x2m2_ck"), - DT_CLK(NULL, "dpll3_ck", "dpll3_ck"), - DT_CLK(NULL, "core_ck", "core_ck"), - DT_CLK(NULL, "dpll3_x2_ck", "dpll3_x2_ck"), - DT_CLK(NULL, "dpll3_m2_ck", "dpll3_m2_ck"), - DT_CLK(NULL, "dpll3_m2x2_ck", "dpll3_m2x2_ck"), - DT_CLK(NULL, "dpll3_m3_ck", "dpll3_m3_ck"), - DT_CLK(NULL, "dpll3_m3x2_ck", "dpll3_m3x2_ck"), - DT_CLK(NULL, "dpll4_ck", "dpll4_ck"), - DT_CLK(NULL, "dpll4_x2_ck", "dpll4_x2_ck"), - DT_CLK(NULL, "omap_96m_fck", "omap_96m_fck"), - DT_CLK(NULL, "cm_96m_fck", "cm_96m_fck"), - DT_CLK(NULL, "omap_54m_fck", "omap_54m_fck"), - DT_CLK(NULL, "omap_48m_fck", "omap_48m_fck"), - DT_CLK(NULL, "omap_12m_fck", "omap_12m_fck"), - DT_CLK(NULL, "dpll4_m2_ck", "dpll4_m2_ck"), - DT_CLK(NULL, "dpll4_m2x2_ck", "dpll4_m2x2_ck"), - DT_CLK(NULL, "dpll4_m3_ck", "dpll4_m3_ck"), - DT_CLK(NULL, "dpll4_m3x2_ck", "dpll4_m3x2_ck"), - DT_CLK(NULL, "dpll4_m4_ck", "dpll4_m4_ck"), - DT_CLK(NULL, "dpll4_m4x2_ck", "dpll4_m4x2_ck"), - DT_CLK(NULL, "dpll4_m5_ck", "dpll4_m5_ck"), - DT_CLK(NULL, "dpll4_m5x2_ck", "dpll4_m5x2_ck"), - DT_CLK(NULL, "dpll4_m6_ck", "dpll4_m6_ck"), - DT_CLK(NULL, "dpll4_m6x2_ck", "dpll4_m6x2_ck"), - DT_CLK("etb", "emu_per_alwon_ck", "emu_per_alwon_ck"), - DT_CLK(NULL, "clkout2_src_ck", "clkout2_src_ck"), - DT_CLK(NULL, "sys_clkout2", "sys_clkout2"), - DT_CLK(NULL, "corex2_fck", "corex2_fck"), - DT_CLK(NULL, "dpll1_fck", "dpll1_fck"), - DT_CLK(NULL, "mpu_ck", "mpu_ck"), - DT_CLK(NULL, "arm_fck", "arm_fck"), - DT_CLK("etb", "emu_mpu_alwon_ck", "emu_mpu_alwon_ck"), - DT_CLK(NULL, "l3_ick", "l3_ick"), - DT_CLK(NULL, "l4_ick", "l4_ick"), - DT_CLK(NULL, "rm_ick", "rm_ick"), - DT_CLK(NULL, "gpt10_fck", "gpt10_fck"), - DT_CLK(NULL, "gpt11_fck", "gpt11_fck"), - DT_CLK(NULL, "core_96m_fck", "core_96m_fck"), - DT_CLK(NULL, "mmchs2_fck", "mmchs2_fck"), - DT_CLK(NULL, "mmchs1_fck", "mmchs1_fck"), - DT_CLK(NULL, "i2c3_fck", "i2c3_fck"), - DT_CLK(NULL, "i2c2_fck", "i2c2_fck"), - DT_CLK(NULL, "i2c1_fck", "i2c1_fck"), - DT_CLK(NULL, "core_48m_fck", "core_48m_fck"), - DT_CLK(NULL, "mcspi4_fck", "mcspi4_fck"), - DT_CLK(NULL, "mcspi3_fck", "mcspi3_fck"), - DT_CLK(NULL, "mcspi2_fck", "mcspi2_fck"), - DT_CLK(NULL, "mcspi1_fck", "mcspi1_fck"), - DT_CLK(NULL, "uart2_fck", "uart2_fck"), - DT_CLK(NULL, "uart1_fck", "uart1_fck"), - DT_CLK(NULL, "core_12m_fck", "core_12m_fck"), - DT_CLK("omap_hdq.0", "fck", "hdq_fck"), - DT_CLK(NULL, "hdq_fck", "hdq_fck"), - DT_CLK(NULL, "core_l3_ick", "core_l3_ick"), - DT_CLK(NULL, "sdrc_ick", "sdrc_ick"), - DT_CLK(NULL, "gpmc_fck", "gpmc_fck"), - DT_CLK(NULL, "core_l4_ick", "core_l4_ick"), - DT_CLK("omap_hsmmc.1", "ick", "mmchs2_ick"), - DT_CLK("omap_hsmmc.0", "ick", "mmchs1_ick"), - DT_CLK(NULL, "mmchs2_ick", "mmchs2_ick"), - DT_CLK(NULL, "mmchs1_ick", "mmchs1_ick"), - DT_CLK("omap_hdq.0", "ick", "hdq_ick"), - DT_CLK(NULL, "hdq_ick", "hdq_ick"), - DT_CLK("omap2_mcspi.4", "ick", "mcspi4_ick"), - DT_CLK("omap2_mcspi.3", "ick", "mcspi3_ick"), - DT_CLK("omap2_mcspi.2", "ick", "mcspi2_ick"), - DT_CLK("omap2_mcspi.1", "ick", "mcspi1_ick"), - DT_CLK(NULL, "mcspi4_ick", "mcspi4_ick"), - DT_CLK(NULL, "mcspi3_ick", "mcspi3_ick"), - DT_CLK(NULL, "mcspi2_ick", "mcspi2_ick"), - DT_CLK(NULL, "mcspi1_ick", "mcspi1_ick"), - DT_CLK("omap_i2c.3", "ick", "i2c3_ick"), - DT_CLK("omap_i2c.2", "ick", "i2c2_ick"), - DT_CLK("omap_i2c.1", "ick", "i2c1_ick"), - DT_CLK(NULL, "i2c3_ick", "i2c3_ick"), - DT_CLK(NULL, "i2c2_ick", "i2c2_ick"), - DT_CLK(NULL, "i2c1_ick", "i2c1_ick"), - DT_CLK(NULL, "uart2_ick", "uart2_ick"), - DT_CLK(NULL, "uart1_ick", "uart1_ick"), - DT_CLK(NULL, "gpt11_ick", "gpt11_ick"), - DT_CLK(NULL, "gpt10_ick", "gpt10_ick"), - DT_CLK(NULL, "omapctrl_ick", "omapctrl_ick"), - DT_CLK(NULL, "dss_tv_fck", "dss_tv_fck"), - DT_CLK(NULL, "dss_96m_fck", "dss_96m_fck"), - DT_CLK(NULL, "dss2_alwon_fck", "dss2_alwon_fck"), - DT_CLK(NULL, "init_60m_fclk", "dummy_ck"), - DT_CLK(NULL, "gpt1_fck", "gpt1_fck"), - DT_CLK(NULL, "aes2_ick", "aes2_ick"), - DT_CLK(NULL, "wkup_32k_fck", "wkup_32k_fck"), - DT_CLK(NULL, "gpio1_dbck", "gpio1_dbck"), - DT_CLK(NULL, "sha12_ick", "sha12_ick"), - DT_CLK(NULL, "wdt2_fck", "wdt2_fck"), - DT_CLK("omap_wdt", "ick", "wdt2_ick"), - DT_CLK(NULL, "wdt2_ick", "wdt2_ick"), - DT_CLK(NULL, "wdt1_ick", "wdt1_ick"), - DT_CLK(NULL, "gpio1_ick", "gpio1_ick"), - DT_CLK(NULL, "omap_32ksync_ick", "omap_32ksync_ick"), - DT_CLK(NULL, "gpt12_ick", "gpt12_ick"), - DT_CLK(NULL, "gpt1_ick", "gpt1_ick"), - DT_CLK(NULL, "per_96m_fck", "per_96m_fck"), - DT_CLK(NULL, "per_48m_fck", "per_48m_fck"), - DT_CLK(NULL, "uart3_fck", "uart3_fck"), - DT_CLK(NULL, "gpt2_fck", "gpt2_fck"), - DT_CLK(NULL, "gpt3_fck", "gpt3_fck"), - DT_CLK(NULL, "gpt4_fck", "gpt4_fck"), - DT_CLK(NULL, "gpt5_fck", "gpt5_fck"), - DT_CLK(NULL, "gpt6_fck", "gpt6_fck"), - DT_CLK(NULL, "gpt7_fck", "gpt7_fck"), - DT_CLK(NULL, "gpt8_fck", "gpt8_fck"), - DT_CLK(NULL, "gpt9_fck", "gpt9_fck"), - DT_CLK(NULL, "per_32k_alwon_fck", "per_32k_alwon_fck"), - DT_CLK(NULL, "gpio6_dbck", "gpio6_dbck"), - DT_CLK(NULL, "gpio5_dbck", "gpio5_dbck"), - DT_CLK(NULL, "gpio4_dbck", "gpio4_dbck"), - DT_CLK(NULL, "gpio3_dbck", "gpio3_dbck"), - DT_CLK(NULL, "gpio2_dbck", "gpio2_dbck"), - DT_CLK(NULL, "wdt3_fck", "wdt3_fck"), - DT_CLK(NULL, "per_l4_ick", "per_l4_ick"), - DT_CLK(NULL, "gpio6_ick", "gpio6_ick"), - DT_CLK(NULL, "gpio5_ick", "gpio5_ick"), - DT_CLK(NULL, "gpio4_ick", "gpio4_ick"), - DT_CLK(NULL, "gpio3_ick", "gpio3_ick"), - DT_CLK(NULL, "gpio2_ick", "gpio2_ick"), - DT_CLK(NULL, "wdt3_ick", "wdt3_ick"), - DT_CLK(NULL, "uart3_ick", "uart3_ick"), - DT_CLK(NULL, "gpt9_ick", "gpt9_ick"), - DT_CLK(NULL, "gpt8_ick", "gpt8_ick"), - DT_CLK(NULL, "gpt7_ick", "gpt7_ick"), - DT_CLK(NULL, "gpt6_ick", "gpt6_ick"), - DT_CLK(NULL, "gpt5_ick", "gpt5_ick"), - DT_CLK(NULL, "gpt4_ick", "gpt4_ick"), - DT_CLK(NULL, "gpt3_ick", "gpt3_ick"), - DT_CLK(NULL, "gpt2_ick", "gpt2_ick"), - DT_CLK(NULL, "mcbsp_clks", "mcbsp_clks"), - DT_CLK(NULL, "mcbsp1_ick", "mcbsp1_ick"), - DT_CLK(NULL, "mcbsp2_ick", "mcbsp2_ick"), - DT_CLK(NULL, "mcbsp3_ick", "mcbsp3_ick"), - DT_CLK(NULL, "mcbsp4_ick", "mcbsp4_ick"), - DT_CLK(NULL, "mcbsp5_ick", "mcbsp5_ick"), - DT_CLK(NULL, "mcbsp1_fck", "mcbsp1_fck"), - DT_CLK(NULL, "mcbsp2_fck", "mcbsp2_fck"), - DT_CLK(NULL, "mcbsp3_fck", "mcbsp3_fck"), - DT_CLK(NULL, "mcbsp4_fck", "mcbsp4_fck"), - DT_CLK(NULL, "mcbsp5_fck", "mcbsp5_fck"), - DT_CLK("etb", "emu_src_ck", "emu_src_ck"), - DT_CLK(NULL, "emu_src_ck", "emu_src_ck"), - DT_CLK(NULL, "pclk_fck", "pclk_fck"), - DT_CLK(NULL, "pclkx2_fck", "pclkx2_fck"), - DT_CLK(NULL, "atclk_fck", "atclk_fck"), - DT_CLK(NULL, "traceclk_src_fck", "traceclk_src_fck"), - DT_CLK(NULL, "traceclk_fck", "traceclk_fck"), - DT_CLK(NULL, "secure_32k_fck", "secure_32k_fck"), - DT_CLK(NULL, "gpt12_fck", "gpt12_fck"), - DT_CLK(NULL, "wdt1_fck", "wdt1_fck"), DT_CLK(NULL, "timer_32k_ck", "omap_32k_fck"), DT_CLK(NULL, "timer_sys_ck", "sys_ck"), - DT_CLK(NULL, "cpufreq_ck", "dpll1_ck"), - { .node_name = NULL }, -}; - -static struct ti_dt_clk omap34xx_omap36xx_clks[] = { - DT_CLK(NULL, "aes1_ick", "aes1_ick"), - DT_CLK("omap_rng", "ick", "rng_ick"), - DT_CLK("omap3-rom-rng", "ick", "rng_ick"), - DT_CLK(NULL, "sha11_ick", "sha11_ick"), - DT_CLK(NULL, "des1_ick", "des1_ick"), - DT_CLK(NULL, "cam_mclk", "cam_mclk"), - DT_CLK(NULL, "cam_ick", "cam_ick"), - DT_CLK(NULL, "csi2_96m_fck", "csi2_96m_fck"), - DT_CLK(NULL, "security_l3_ick", "security_l3_ick"), - DT_CLK(NULL, "pka_ick", "pka_ick"), - DT_CLK(NULL, "icr_ick", "icr_ick"), - DT_CLK("omap-aes", "ick", "aes2_ick"), - DT_CLK("omap-sham", "ick", "sha12_ick"), - DT_CLK(NULL, "des2_ick", "des2_ick"), - DT_CLK(NULL, "mspro_ick", "mspro_ick"), - DT_CLK(NULL, "mailboxes_ick", "mailboxes_ick"), - DT_CLK(NULL, "ssi_l4_ick", "ssi_l4_ick"), - DT_CLK(NULL, "sr1_fck", "sr1_fck"), - DT_CLK(NULL, "sr2_fck", "sr2_fck"), - DT_CLK(NULL, "sr_l4_ick", "sr_l4_ick"), - DT_CLK(NULL, "security_l4_ick2", "security_l4_ick2"), - DT_CLK(NULL, "wkup_l4_ick", "wkup_l4_ick"), - DT_CLK(NULL, "dpll2_fck", "dpll2_fck"), - DT_CLK(NULL, "iva2_ck", "iva2_ck"), - DT_CLK(NULL, "modem_fck", "modem_fck"), - DT_CLK(NULL, "sad2d_ick", "sad2d_ick"), - DT_CLK(NULL, "mad2d_ick", "mad2d_ick"), - DT_CLK(NULL, "mspro_fck", "mspro_fck"), - DT_CLK(NULL, "dpll2_ck", "dpll2_ck"), - DT_CLK(NULL, "dpll2_m2_ck", "dpll2_m2_ck"), { .node_name = NULL }, }; static struct ti_dt_clk omap36xx_omap3430es2plus_clks[] = { DT_CLK(NULL, "ssi_ssr_fck", "ssi_ssr_fck_3430es2"), DT_CLK(NULL, "ssi_sst_fck", "ssi_sst_fck_3430es2"), - DT_CLK("musb-omap2430", "ick", "hsotgusb_ick_3430es2"), DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_3430es2"), DT_CLK(NULL, "ssi_ick", "ssi_ick_3430es2"), - DT_CLK(NULL, "usim_fck", "usim_fck"), - DT_CLK(NULL, "usim_ick", "usim_ick"), { .node_name = NULL }, }; static struct ti_dt_clk omap3430es1_clks[] = { - DT_CLK(NULL, "gfx_l3_ck", "gfx_l3_ck"), - DT_CLK(NULL, "gfx_l3_fck", "gfx_l3_fck"), - DT_CLK(NULL, "gfx_l3_ick", "gfx_l3_ick"), - DT_CLK(NULL, "gfx_cg1_ck", "gfx_cg1_ck"), - DT_CLK(NULL, "gfx_cg2_ck", "gfx_cg2_ck"), - DT_CLK(NULL, "d2d_26m_fck", "d2d_26m_fck"), - DT_CLK(NULL, "fshostusb_fck", "fshostusb_fck"), DT_CLK(NULL, "ssi_ssr_fck", "ssi_ssr_fck_3430es1"), DT_CLK(NULL, "ssi_sst_fck", "ssi_sst_fck_3430es1"), - DT_CLK("musb-omap2430", "ick", "hsotgusb_ick_3430es1"), DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_3430es1"), - DT_CLK(NULL, "fac_ick", "fac_ick"), DT_CLK(NULL, "ssi_ick", "ssi_ick_3430es1"), - DT_CLK(NULL, "usb_l4_ick", "usb_l4_ick"), DT_CLK(NULL, "dss1_alwon_fck", "dss1_alwon_fck_3430es1"), - DT_CLK("omapdss_dss", "ick", "dss_ick_3430es1"), DT_CLK(NULL, "dss_ick", "dss_ick_3430es1"), { .node_name = NULL }, }; static struct ti_dt_clk omap36xx_am35xx_omap3430es2plus_clks[] = { - DT_CLK(NULL, "virt_16_8m_ck", "virt_16_8m_ck"), - DT_CLK(NULL, "dpll5_ck", "dpll5_ck"), - DT_CLK(NULL, "dpll5_m2_ck", "dpll5_m2_ck"), - DT_CLK(NULL, "sgx_fck", "sgx_fck"), - DT_CLK(NULL, "sgx_ick", "sgx_ick"), - DT_CLK(NULL, "cpefuse_fck", "cpefuse_fck"), - DT_CLK(NULL, "ts_fck", "ts_fck"), - DT_CLK(NULL, "usbtll_fck", "usbtll_fck"), - DT_CLK(NULL, "usbtll_ick", "usbtll_ick"), - DT_CLK("omap_hsmmc.2", "ick", "mmchs3_ick"), - DT_CLK(NULL, "mmchs3_ick", "mmchs3_ick"), - DT_CLK(NULL, "mmchs3_fck", "mmchs3_fck"), DT_CLK(NULL, "dss1_alwon_fck", "dss1_alwon_fck_3430es2"), - DT_CLK("omapdss_dss", "ick", "dss_ick_3430es2"), DT_CLK(NULL, "dss_ick", "dss_ick_3430es2"), - DT_CLK(NULL, "usbhost_120m_fck", "usbhost_120m_fck"), - DT_CLK(NULL, "usbhost_48m_fck", "usbhost_48m_fck"), - DT_CLK(NULL, "usbhost_ick", "usbhost_ick"), { .node_name = NULL }, }; static struct ti_dt_clk am35xx_clks[] = { - DT_CLK(NULL, "ipss_ick", "ipss_ick"), - DT_CLK(NULL, "rmii_ck", "rmii_ck"), - DT_CLK(NULL, "pclk_ck", "pclk_ck"), - DT_CLK(NULL, "emac_ick", "emac_ick"), - DT_CLK(NULL, "emac_fck", "emac_fck"), - DT_CLK("davinci_emac.0", NULL, "emac_ick"), - DT_CLK("davinci_mdio.0", NULL, "emac_fck"), - DT_CLK("vpfe-capture", "master", "vpfe_ick"), - DT_CLK("vpfe-capture", "slave", "vpfe_fck"), DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_am35xx"), DT_CLK(NULL, "hsotgusb_fck", "hsotgusb_fck_am35xx"), - DT_CLK(NULL, "hecc_ck", "hecc_ck"), DT_CLK(NULL, "uart4_ick", "uart4_ick_am35xx"), DT_CLK(NULL, "uart4_fck", "uart4_fck_am35xx"), { .node_name = NULL }, }; -static struct ti_dt_clk omap36xx_clks[] = { - DT_CLK(NULL, "omap_192m_alwon_fck", "omap_192m_alwon_fck"), - DT_CLK(NULL, "uart4_fck", "uart4_fck"), - DT_CLK(NULL, "uart4_ick", "uart4_ick"), - { .node_name = NULL }, -}; - static const char *enable_init_clks[] = { "sdrc_ick", "gpmc_fck", @@ -579,16 +326,10 @@ static int __init omap3xxx_dt_clk_init(int soc_type) soc_type == OMAP3_SOC_OMAP3630) ti_dt_clocks_register(omap36xx_omap3430es2plus_clks); - if (soc_type == OMAP3_SOC_OMAP3430_ES1 || - soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS || - soc_type == OMAP3_SOC_OMAP3630) - ti_dt_clocks_register(omap34xx_omap36xx_clks); - - if (soc_type == OMAP3_SOC_OMAP3630) - ti_dt_clocks_register(omap36xx_clks); - omap2_clk_disable_autoidle_all(); + ti_clk_add_aliases(); + omap2_clk_enable_init_clocks(enable_init_clks, ARRAY_SIZE(enable_init_clks)); diff --git a/drivers/clk/ti/clk-43xx.c b/drivers/clk/ti/clk-43xx.c index e816a7500e43..2b7c2e017665 100644 --- a/drivers/clk/ti/clk-43xx.c +++ b/drivers/clk/ti/clk-43xx.c @@ -19,109 +19,208 @@ #include #include #include +#include #include "clock.h" +static const char * const am4_synctimer_32kclk_parents[] __initconst = { + "mux_synctimer32k_ck", + NULL, +}; + +static const struct omap_clkctrl_bit_data am4_counter_32k_bit_data[] __initconst = { + { 8, TI_CLK_GATE, am4_synctimer_32kclk_parents, NULL }, + { 0 }, +}; + +static const char * const am4_gpio0_dbclk_parents[] __initconst = { + "gpio0_dbclk_mux_ck", + NULL, +}; + +static const struct omap_clkctrl_bit_data am4_gpio1_bit_data[] __initconst = { + { 8, TI_CLK_GATE, am4_gpio0_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data am4_l4_wkup_clkctrl_regs[] __initconst = { + { AM4_ADC_TSC_CLKCTRL, NULL, CLKF_SW_SUP, "adc_tsc_fck", "l3s_tsc_clkdm" }, + { AM4_L4_WKUP_CLKCTRL, NULL, CLKF_SW_SUP, "sys_clkin_ck", "l4_wkup_clkdm" }, + { AM4_WKUP_M3_CLKCTRL, NULL, CLKF_NO_IDLEST, "sys_clkin_ck" }, + { AM4_COUNTER_32K_CLKCTRL, am4_counter_32k_bit_data, CLKF_SW_SUP, "l4_wkup_cm:clk:0210:8" }, + { AM4_TIMER1_CLKCTRL, NULL, CLKF_SW_SUP, "timer1_fck", "l4_wkup_clkdm" }, + { AM4_WD_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "wdt1_fck", "l4_wkup_clkdm" }, + { AM4_I2C1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_wkupdm_ck", "l4_wkup_clkdm" }, + { AM4_UART1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_wkupdm_ck", "l4_wkup_clkdm" }, + { AM4_SMARTREFLEX0_CLKCTRL, NULL, CLKF_SW_SUP, "smartreflex0_fck", "l4_wkup_clkdm" }, + { AM4_SMARTREFLEX1_CLKCTRL, NULL, CLKF_SW_SUP, "smartreflex1_fck", "l4_wkup_clkdm" }, + { AM4_CONTROL_CLKCTRL, NULL, CLKF_SW_SUP, "sys_clkin_ck", "l4_wkup_clkdm" }, + { AM4_GPIO1_CLKCTRL, am4_gpio1_bit_data, CLKF_SW_SUP, "sys_clkin_ck", "l4_wkup_clkdm" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data am4_mpu_clkctrl_regs[] __initconst = { + { AM4_MPU_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_mpu_m2_ck" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data am4_gfx_l3_clkctrl_regs[] __initconst = { + { AM4_GFX_CLKCTRL, NULL, CLKF_SW_SUP, "gfx_fck_div_ck" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data am4_l4_rtc_clkctrl_regs[] __initconst = { + { AM4_RTC_CLKCTRL, NULL, CLKF_SW_SUP, "clk_32768_ck" }, + { 0 }, +}; + +static const char * const am4_usb_otg_ss0_refclk960m_parents[] __initconst = { + "dpll_per_clkdcoldo", + NULL, +}; + +static const struct omap_clkctrl_bit_data am4_usb_otg_ss0_bit_data[] __initconst = { + { 8, TI_CLK_GATE, am4_usb_otg_ss0_refclk960m_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data am4_usb_otg_ss1_bit_data[] __initconst = { + { 8, TI_CLK_GATE, am4_usb_otg_ss0_refclk960m_parents, NULL }, + { 0 }, +}; + +static const char * const am4_gpio1_dbclk_parents[] __initconst = { + "clkdiv32k_ick", + NULL, +}; + +static const struct omap_clkctrl_bit_data am4_gpio2_bit_data[] __initconst = { + { 8, TI_CLK_GATE, am4_gpio1_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data am4_gpio3_bit_data[] __initconst = { + { 8, TI_CLK_GATE, am4_gpio1_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data am4_gpio4_bit_data[] __initconst = { + { 8, TI_CLK_GATE, am4_gpio1_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data am4_gpio5_bit_data[] __initconst = { + { 8, TI_CLK_GATE, am4_gpio1_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data am4_gpio6_bit_data[] __initconst = { + { 8, TI_CLK_GATE, am4_gpio1_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data am4_l4_per_clkctrl_regs[] __initconst = { + { AM4_L3_MAIN_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" }, + { AM4_AES_CLKCTRL, NULL, CLKF_SW_SUP, "aes0_fck", "l3_clkdm" }, + { AM4_DES_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" }, + { AM4_L3_INSTR_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" }, + { AM4_OCMCRAM_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" }, + { AM4_SHAM_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" }, + { AM4_VPFE0_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3s_clkdm" }, + { AM4_VPFE1_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3s_clkdm" }, + { AM4_TPCC_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" }, + { AM4_TPTC0_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" }, + { AM4_TPTC1_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" }, + { AM4_TPTC2_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" }, + { AM4_L4_HS_CLKCTRL, NULL, CLKF_SW_SUP, "l4hs_gclk", "l3_clkdm" }, + { AM4_GPMC_CLKCTRL, NULL, CLKF_SW_SUP, "l3s_gclk", "l3s_clkdm" }, + { AM4_MCASP0_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp0_fck", "l3s_clkdm" }, + { AM4_MCASP1_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp1_fck", "l3s_clkdm" }, + { AM4_MMC3_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk", "l3s_clkdm" }, + { AM4_QSPI_CLKCTRL, NULL, CLKF_SW_SUP, "l3s_gclk", "l3s_clkdm" }, + { AM4_USB_OTG_SS0_CLKCTRL, am4_usb_otg_ss0_bit_data, CLKF_SW_SUP, "l3s_gclk", "l3s_clkdm" }, + { AM4_USB_OTG_SS1_CLKCTRL, am4_usb_otg_ss1_bit_data, CLKF_SW_SUP, "l3s_gclk", "l3s_clkdm" }, + { AM4_PRUSS_CLKCTRL, NULL, CLKF_SW_SUP, "pruss_ocp_gclk", "pruss_ocp_clkdm" }, + { AM4_L4_LS_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM4_D_CAN0_CLKCTRL, NULL, CLKF_SW_SUP, "dcan0_fck" }, + { AM4_D_CAN1_CLKCTRL, NULL, CLKF_SW_SUP, "dcan1_fck" }, + { AM4_EPWMSS0_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM4_EPWMSS1_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM4_EPWMSS2_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM4_EPWMSS3_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM4_EPWMSS4_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM4_EPWMSS5_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM4_ELM_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM4_GPIO2_CLKCTRL, am4_gpio2_bit_data, CLKF_SW_SUP, "l4ls_gclk" }, + { AM4_GPIO3_CLKCTRL, am4_gpio3_bit_data, CLKF_SW_SUP, "l4ls_gclk" }, + { AM4_GPIO4_CLKCTRL, am4_gpio4_bit_data, CLKF_SW_SUP, "l4ls_gclk" }, + { AM4_GPIO5_CLKCTRL, am4_gpio5_bit_data, CLKF_SW_SUP, "l4ls_gclk" }, + { AM4_GPIO6_CLKCTRL, am4_gpio6_bit_data, CLKF_SW_SUP, "l4ls_gclk" }, + { AM4_HDQ1W_CLKCTRL, NULL, CLKF_SW_SUP, "func_12m_clk" }, + { AM4_I2C2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM4_I2C3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM4_MAILBOX_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM4_MMC1_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" }, + { AM4_MMC2_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" }, + { AM4_RNG_CLKCTRL, NULL, CLKF_SW_SUP, "rng_fck" }, + { AM4_SPI0_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM4_SPI1_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM4_SPI2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM4_SPI3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM4_SPI4_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM4_SPINLOCK_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM4_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "timer2_fck" }, + { AM4_TIMER3_CLKCTRL, NULL, CLKF_SW_SUP, "timer3_fck" }, + { AM4_TIMER4_CLKCTRL, NULL, CLKF_SW_SUP, "timer4_fck" }, + { AM4_TIMER5_CLKCTRL, NULL, CLKF_SW_SUP, "timer5_fck" }, + { AM4_TIMER6_CLKCTRL, NULL, CLKF_SW_SUP, "timer6_fck" }, + { AM4_TIMER7_CLKCTRL, NULL, CLKF_SW_SUP, "timer7_fck" }, + { AM4_TIMER8_CLKCTRL, NULL, CLKF_SW_SUP, "timer8_fck" }, + { AM4_TIMER9_CLKCTRL, NULL, CLKF_SW_SUP, "timer9_fck" }, + { AM4_TIMER10_CLKCTRL, NULL, CLKF_SW_SUP, "timer10_fck" }, + { AM4_TIMER11_CLKCTRL, NULL, CLKF_SW_SUP, "timer11_fck" }, + { AM4_UART2_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM4_UART3_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM4_UART4_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM4_UART5_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM4_UART6_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_per_m2_div4_ck" }, + { AM4_OCP2SCP0_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM4_OCP2SCP1_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" }, + { AM4_EMIF_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_ddr_m2_ck", "emif_clkdm" }, + { AM4_DSS_CORE_CLKCTRL, NULL, CLKF_SW_SUP, "disp_clk", "dss_clkdm" }, + { AM4_CPGMAC0_CLKCTRL, NULL, CLKF_SW_SUP, "cpsw_125mhz_gclk", "cpsw_125mhz_clkdm" }, + { 0 }, +}; + +const struct omap_clkctrl_data am4_clkctrl_data[] __initconst = { + { 0x44df2820, am4_l4_wkup_clkctrl_regs }, + { 0x44df8320, am4_mpu_clkctrl_regs }, + { 0x44df8420, am4_gfx_l3_clkctrl_regs }, + { 0x44df8520, am4_l4_rtc_clkctrl_regs }, + { 0x44df8820, am4_l4_per_clkctrl_regs }, + { 0 }, +}; + +const struct omap_clkctrl_data am438x_clkctrl_data[] __initconst = { + { 0x44df2820, am4_l4_wkup_clkctrl_regs }, + { 0x44df8320, am4_mpu_clkctrl_regs }, + { 0x44df8420, am4_gfx_l3_clkctrl_regs }, + { 0x44df8820, am4_l4_per_clkctrl_regs }, + { 0 }, +}; + static struct ti_dt_clk am43xx_clks[] = { - DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"), - DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"), - DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), - DT_CLK(NULL, "virt_24000000_ck", "virt_24000000_ck"), - DT_CLK(NULL, "virt_25000000_ck", "virt_25000000_ck"), - DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), - DT_CLK(NULL, "sys_clkin_ck", "sys_clkin_ck"), - DT_CLK(NULL, "tclkin_ck", "tclkin_ck"), - DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), - DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), - DT_CLK(NULL, "dpll_core_m4_ck", "dpll_core_m4_ck"), - DT_CLK(NULL, "dpll_core_m5_ck", "dpll_core_m5_ck"), - DT_CLK(NULL, "dpll_core_m6_ck", "dpll_core_m6_ck"), - DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), - DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), - DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"), - DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"), - DT_CLK(NULL, "dpll_disp_ck", "dpll_disp_ck"), - DT_CLK(NULL, "dpll_disp_m2_ck", "dpll_disp_m2_ck"), - DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), - DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), - DT_CLK(NULL, "dpll_per_m2_div4_wkupdm_ck", "dpll_per_m2_div4_wkupdm_ck"), - DT_CLK(NULL, "dpll_per_m2_div4_ck", "dpll_per_m2_div4_ck"), - DT_CLK(NULL, "adc_tsc_fck", "adc_tsc_fck"), - DT_CLK(NULL, "clkdiv32k_ck", "clkdiv32k_ck"), - DT_CLK(NULL, "clkdiv32k_ick", "clkdiv32k_ick"), - DT_CLK(NULL, "dcan0_fck", "dcan0_fck"), - DT_CLK(NULL, "dcan1_fck", "dcan1_fck"), - DT_CLK(NULL, "pruss_ocp_gclk", "pruss_ocp_gclk"), - DT_CLK(NULL, "mcasp0_fck", "mcasp0_fck"), - DT_CLK(NULL, "mcasp1_fck", "mcasp1_fck"), - DT_CLK(NULL, "smartreflex0_fck", "smartreflex0_fck"), - DT_CLK(NULL, "smartreflex1_fck", "smartreflex1_fck"), - DT_CLK(NULL, "sha0_fck", "sha0_fck"), - DT_CLK(NULL, "aes0_fck", "aes0_fck"), - DT_CLK(NULL, "rng_fck", "rng_fck"), - DT_CLK(NULL, "timer1_fck", "timer1_fck"), - DT_CLK(NULL, "timer2_fck", "timer2_fck"), - DT_CLK(NULL, "timer3_fck", "timer3_fck"), - DT_CLK(NULL, "timer4_fck", "timer4_fck"), - DT_CLK(NULL, "timer5_fck", "timer5_fck"), - DT_CLK(NULL, "timer6_fck", "timer6_fck"), - DT_CLK(NULL, "timer7_fck", "timer7_fck"), - DT_CLK(NULL, "wdt1_fck", "wdt1_fck"), - DT_CLK(NULL, "l3_gclk", "l3_gclk"), - DT_CLK(NULL, "dpll_core_m4_div2_ck", "dpll_core_m4_div2_ck"), - DT_CLK(NULL, "l4hs_gclk", "l4hs_gclk"), - DT_CLK(NULL, "l3s_gclk", "l3s_gclk"), - DT_CLK(NULL, "l4ls_gclk", "l4ls_gclk"), - DT_CLK(NULL, "clk_24mhz", "clk_24mhz"), - DT_CLK(NULL, "cpsw_125mhz_gclk", "cpsw_125mhz_gclk"), - DT_CLK(NULL, "cpsw_cpts_rft_clk", "cpsw_cpts_rft_clk"), - DT_CLK(NULL, "dpll_clksel_mac_clk", "dpll_clksel_mac_clk"), - DT_CLK(NULL, "gpio0_dbclk_mux_ck", "gpio0_dbclk_mux_ck"), - DT_CLK(NULL, "gpio0_dbclk", "gpio0_dbclk"), - DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), - DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), - DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), - DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"), - DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"), - DT_CLK(NULL, "mmc_clk", "mmc_clk"), - DT_CLK(NULL, "gfx_fclk_clksel_ck", "gfx_fclk_clksel_ck"), - DT_CLK(NULL, "gfx_fck_div_ck", "gfx_fck_div_ck"), DT_CLK(NULL, "timer_32k_ck", "clkdiv32k_ick"), DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"), - DT_CLK(NULL, "sysclk_div", "sysclk_div"), - DT_CLK(NULL, "disp_clk", "disp_clk"), - DT_CLK(NULL, "clk_32k_mosc_ck", "clk_32k_mosc_ck"), - DT_CLK(NULL, "clk_32k_tpm_ck", "clk_32k_tpm_ck"), - DT_CLK(NULL, "dpll_extdev_ck", "dpll_extdev_ck"), - DT_CLK(NULL, "dpll_extdev_m2_ck", "dpll_extdev_m2_ck"), - DT_CLK(NULL, "mux_synctimer32k_ck", "mux_synctimer32k_ck"), - DT_CLK(NULL, "synctimer_32kclk", "synctimer_32kclk"), - DT_CLK(NULL, "timer8_fck", "timer8_fck"), - DT_CLK(NULL, "timer9_fck", "timer9_fck"), - DT_CLK(NULL, "timer10_fck", "timer10_fck"), - DT_CLK(NULL, "timer11_fck", "timer11_fck"), - DT_CLK(NULL, "cpsw_50m_clkdiv", "cpsw_50m_clkdiv"), - DT_CLK(NULL, "cpsw_5m_clkdiv", "cpsw_5m_clkdiv"), - DT_CLK(NULL, "dpll_ddr_x2_ck", "dpll_ddr_x2_ck"), - DT_CLK(NULL, "dpll_ddr_m4_ck", "dpll_ddr_m4_ck"), - DT_CLK(NULL, "dpll_per_clkdcoldo", "dpll_per_clkdcoldo"), - DT_CLK(NULL, "dll_aging_clk_div", "dll_aging_clk_div"), - DT_CLK(NULL, "div_core_25m_ck", "div_core_25m_ck"), - DT_CLK(NULL, "func_12m_clk", "func_12m_clk"), - DT_CLK(NULL, "vtp_clk_div", "vtp_clk_div"), - DT_CLK(NULL, "usbphy_32khz_clkmux", "usbphy_32khz_clkmux"), - DT_CLK("48300200.ehrpwm", "tbclk", "ehrpwm0_tbclk"), - DT_CLK("48302200.ehrpwm", "tbclk", "ehrpwm1_tbclk"), - DT_CLK("48304200.ehrpwm", "tbclk", "ehrpwm2_tbclk"), - DT_CLK("48306200.ehrpwm", "tbclk", "ehrpwm3_tbclk"), - DT_CLK("48308200.ehrpwm", "tbclk", "ehrpwm4_tbclk"), - DT_CLK("4830a200.ehrpwm", "tbclk", "ehrpwm5_tbclk"), - DT_CLK("48300200.pwm", "tbclk", "ehrpwm0_tbclk"), - DT_CLK("48302200.pwm", "tbclk", "ehrpwm1_tbclk"), - DT_CLK("48304200.pwm", "tbclk", "ehrpwm2_tbclk"), - DT_CLK("48306200.pwm", "tbclk", "ehrpwm3_tbclk"), - DT_CLK("48308200.pwm", "tbclk", "ehrpwm4_tbclk"), - DT_CLK("4830a200.pwm", "tbclk", "ehrpwm5_tbclk"), + DT_CLK(NULL, "gpio0_dbclk", "l4_wkup_cm:0348:8"), + DT_CLK(NULL, "gpio1_dbclk", "l4_per_cm:0458:8"), + DT_CLK(NULL, "gpio2_dbclk", "l4_per_cm:0460:8"), + DT_CLK(NULL, "gpio3_dbclk", "l4_per_cm:0468:8"), + DT_CLK(NULL, "gpio4_dbclk", "l4_per_cm:0470:8"), + DT_CLK(NULL, "gpio5_dbclk", "l4_per_cm:0478:8"), + DT_CLK(NULL, "synctimer_32kclk", "l4_wkup_cm:0210:8"), + DT_CLK(NULL, "usb_otg_ss0_refclk960m", "l4_per_cm:0240:8"), + DT_CLK(NULL, "usb_otg_ss1_refclk960m", "l4_per_cm:0248:8"), { .node_name = NULL }, }; @@ -133,6 +232,8 @@ int __init am43xx_dt_clk_init(void) omap2_clk_disable_autoidle_all(); + ti_clk_add_aliases(); + /* * cpsw_cpts_rft_clk has got the choice of 3 clocksources * dpll_core_m4_ck, dpll_core_m5_ck and dpll_disp_m2_ck. diff --git a/drivers/clk/ti/clk-44xx.c b/drivers/clk/ti/clk-44xx.c index 2005f032c02f..339d30d64ebb 100644 --- a/drivers/clk/ti/clk-44xx.c +++ b/drivers/clk/ti/clk-44xx.c @@ -35,7 +35,7 @@ #define OMAP4_DPLL_USB_DEFFREQ 960000000 static const struct omap_clkctrl_reg_data omap4_mpuss_clkctrl_regs[] __initconst = { - { OMAP4_MPU_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_mpu_m2_ck" }, + { OMAP4_MPU_CLKCTRL, NULL, 0, "dpll_mpu_m2_ck" }, { 0 }, }; @@ -59,7 +59,7 @@ static const struct omap_clkctrl_bit_data omap4_aess_bit_data[] __initconst = { }; static const char * const omap4_func_dmic_abe_gfclk_parents[] __initconst = { - "dmic_sync_mux_ck", + "abe_cm:clk:0018:26", "pad_clks_ck", "slimbus_clk", NULL, @@ -79,7 +79,7 @@ static const struct omap_clkctrl_bit_data omap4_dmic_bit_data[] __initconst = { }; static const char * const omap4_func_mcasp_abe_gfclk_parents[] __initconst = { - "mcasp_sync_mux_ck", + "abe_cm:clk:0020:26", "pad_clks_ck", "slimbus_clk", NULL, @@ -92,7 +92,7 @@ static const struct omap_clkctrl_bit_data omap4_mcasp_bit_data[] __initconst = { }; static const char * const omap4_func_mcbsp1_gfclk_parents[] __initconst = { - "mcbsp1_sync_mux_ck", + "abe_cm:clk:0028:26", "pad_clks_ck", "slimbus_clk", NULL, @@ -105,7 +105,7 @@ static const struct omap_clkctrl_bit_data omap4_mcbsp1_bit_data[] __initconst = }; static const char * const omap4_func_mcbsp2_gfclk_parents[] __initconst = { - "mcbsp2_sync_mux_ck", + "abe_cm:clk:0030:26", "pad_clks_ck", "slimbus_clk", NULL, @@ -118,7 +118,7 @@ static const struct omap_clkctrl_bit_data omap4_mcbsp2_bit_data[] __initconst = }; static const char * const omap4_func_mcbsp3_gfclk_parents[] __initconst = { - "mcbsp3_sync_mux_ck", + "abe_cm:clk:0038:26", "pad_clks_ck", "slimbus_clk", NULL, @@ -186,18 +186,18 @@ static const struct omap_clkctrl_bit_data omap4_timer8_bit_data[] __initconst = static const struct omap_clkctrl_reg_data omap4_abe_clkctrl_regs[] __initconst = { { OMAP4_L4_ABE_CLKCTRL, NULL, 0, "ocp_abe_iclk" }, - { OMAP4_AESS_CLKCTRL, omap4_aess_bit_data, CLKF_SW_SUP, "aess_fclk" }, + { OMAP4_AESS_CLKCTRL, omap4_aess_bit_data, CLKF_SW_SUP, "abe_cm:clk:0008:24" }, { OMAP4_MCPDM_CLKCTRL, NULL, CLKF_SW_SUP, "pad_clks_ck" }, - { OMAP4_DMIC_CLKCTRL, omap4_dmic_bit_data, CLKF_SW_SUP, "func_dmic_abe_gfclk" }, - { OMAP4_MCASP_CLKCTRL, omap4_mcasp_bit_data, CLKF_SW_SUP, "func_mcasp_abe_gfclk" }, - { OMAP4_MCBSP1_CLKCTRL, omap4_mcbsp1_bit_data, CLKF_SW_SUP, "func_mcbsp1_gfclk" }, - { OMAP4_MCBSP2_CLKCTRL, omap4_mcbsp2_bit_data, CLKF_SW_SUP, "func_mcbsp2_gfclk" }, - { OMAP4_MCBSP3_CLKCTRL, omap4_mcbsp3_bit_data, CLKF_SW_SUP, "func_mcbsp3_gfclk" }, - { OMAP4_SLIMBUS1_CLKCTRL, omap4_slimbus1_bit_data, CLKF_SW_SUP, "slimbus1_fclk_0" }, - { OMAP4_TIMER5_CLKCTRL, omap4_timer5_bit_data, CLKF_SW_SUP, "timer5_sync_mux" }, - { OMAP4_TIMER6_CLKCTRL, omap4_timer6_bit_data, CLKF_SW_SUP, "timer6_sync_mux" }, - { OMAP4_TIMER7_CLKCTRL, omap4_timer7_bit_data, CLKF_SW_SUP, "timer7_sync_mux" }, - { OMAP4_TIMER8_CLKCTRL, omap4_timer8_bit_data, CLKF_SW_SUP, "timer8_sync_mux" }, + { OMAP4_DMIC_CLKCTRL, omap4_dmic_bit_data, CLKF_SW_SUP, "abe_cm:clk:0018:24" }, + { OMAP4_MCASP_CLKCTRL, omap4_mcasp_bit_data, CLKF_SW_SUP, "abe_cm:clk:0020:24" }, + { OMAP4_MCBSP1_CLKCTRL, omap4_mcbsp1_bit_data, CLKF_SW_SUP, "abe_cm:clk:0028:24" }, + { OMAP4_MCBSP2_CLKCTRL, omap4_mcbsp2_bit_data, CLKF_SW_SUP, "abe_cm:clk:0030:24" }, + { OMAP4_MCBSP3_CLKCTRL, omap4_mcbsp3_bit_data, CLKF_SW_SUP, "abe_cm:clk:0038:24" }, + { OMAP4_SLIMBUS1_CLKCTRL, omap4_slimbus1_bit_data, CLKF_SW_SUP, "abe_cm:clk:0040:8" }, + { OMAP4_TIMER5_CLKCTRL, omap4_timer5_bit_data, CLKF_SW_SUP, "abe_cm:clk:0048:24" }, + { OMAP4_TIMER6_CLKCTRL, omap4_timer6_bit_data, CLKF_SW_SUP, "abe_cm:clk:0050:24" }, + { OMAP4_TIMER7_CLKCTRL, omap4_timer7_bit_data, CLKF_SW_SUP, "abe_cm:clk:0058:24" }, + { OMAP4_TIMER8_CLKCTRL, omap4_timer8_bit_data, CLKF_SW_SUP, "abe_cm:clk:0060:24" }, { OMAP4_WD_TIMER3_CLKCTRL, NULL, CLKF_SW_SUP, "sys_32k_ck" }, { 0 }, }; @@ -280,6 +280,7 @@ static const char * const omap4_fdif_fck_parents[] __initconst = { static const struct omap_clkctrl_div_data omap4_fdif_fck_data __initconst = { .max_div = 4, + .flags = CLK_DIVIDER_POWER_OF_TWO, }; static const struct omap_clkctrl_bit_data omap4_fdif_bit_data[] __initconst = { @@ -289,7 +290,7 @@ static const struct omap_clkctrl_bit_data omap4_fdif_bit_data[] __initconst = { static const struct omap_clkctrl_reg_data omap4_iss_clkctrl_regs[] __initconst = { { OMAP4_ISS_CLKCTRL, omap4_iss_bit_data, CLKF_SW_SUP, "ducati_clk_mux_ck" }, - { OMAP4_FDIF_CLKCTRL, omap4_fdif_bit_data, CLKF_SW_SUP, "fdif_fck" }, + { OMAP4_FDIF_CLKCTRL, omap4_fdif_bit_data, CLKF_SW_SUP, "iss_cm:clk:0008:24" }, { 0 }, }; @@ -322,7 +323,7 @@ static const struct omap_clkctrl_bit_data omap4_dss_core_bit_data[] __initconst }; static const struct omap_clkctrl_reg_data omap4_l3_dss_clkctrl_regs[] __initconst = { - { OMAP4_DSS_CORE_CLKCTRL, omap4_dss_core_bit_data, CLKF_SW_SUP, "dss_dss_clk" }, + { OMAP4_DSS_CORE_CLKCTRL, omap4_dss_core_bit_data, CLKF_SW_SUP, "l3_dss_cm:clk:0000:8" }, { 0 }, }; @@ -338,7 +339,7 @@ static const struct omap_clkctrl_bit_data omap4_gpu_bit_data[] __initconst = { }; static const struct omap_clkctrl_reg_data omap4_l3_gfx_clkctrl_regs[] __initconst = { - { OMAP4_GPU_CLKCTRL, omap4_gpu_bit_data, CLKF_SW_SUP, "sgx_clk_mux" }, + { OMAP4_GPU_CLKCTRL, omap4_gpu_bit_data, CLKF_SW_SUP, "l3_gfx_cm:clk:0000:24" }, { 0 }, }; @@ -365,6 +366,7 @@ static const char * const omap4_hsi_fck_parents[] __initconst = { static const struct omap_clkctrl_div_data omap4_hsi_fck_data __initconst = { .max_div = 4, + .flags = CLK_DIVIDER_POWER_OF_TWO, }; static const struct omap_clkctrl_bit_data omap4_hsi_bit_data[] __initconst = { @@ -373,12 +375,12 @@ static const struct omap_clkctrl_bit_data omap4_hsi_bit_data[] __initconst = { }; static const char * const omap4_usb_host_hs_utmi_p1_clk_parents[] __initconst = { - "utmi_p1_gfclk", + "l3_init_cm:clk:0038:24", NULL, }; static const char * const omap4_usb_host_hs_utmi_p2_clk_parents[] __initconst = { - "utmi_p2_gfclk", + "l3_init_cm:clk:0038:25", NULL, }; @@ -419,7 +421,7 @@ static const struct omap_clkctrl_bit_data omap4_usb_host_hs_bit_data[] __initcon }; static const char * const omap4_usb_otg_hs_xclk_parents[] __initconst = { - "otg_60m_gfclk", + "l3_init_cm:clk:0040:24", NULL, }; @@ -453,14 +455,14 @@ static const struct omap_clkctrl_bit_data omap4_ocp2scp_usb_phy_bit_data[] __ini }; static const struct omap_clkctrl_reg_data omap4_l3_init_clkctrl_regs[] __initconst = { - { OMAP4_MMC1_CLKCTRL, omap4_mmc1_bit_data, CLKF_SW_SUP, "hsmmc1_fclk" }, - { OMAP4_MMC2_CLKCTRL, omap4_mmc2_bit_data, CLKF_SW_SUP, "hsmmc2_fclk" }, - { OMAP4_HSI_CLKCTRL, omap4_hsi_bit_data, CLKF_HW_SUP, "hsi_fck" }, + { OMAP4_MMC1_CLKCTRL, omap4_mmc1_bit_data, CLKF_SW_SUP, "l3_init_cm:clk:0008:24" }, + { OMAP4_MMC2_CLKCTRL, omap4_mmc2_bit_data, CLKF_SW_SUP, "l3_init_cm:clk:0010:24" }, + { OMAP4_HSI_CLKCTRL, omap4_hsi_bit_data, CLKF_HW_SUP, "l3_init_cm:clk:0018:24" }, { OMAP4_USB_HOST_HS_CLKCTRL, omap4_usb_host_hs_bit_data, CLKF_SW_SUP, "init_60m_fclk" }, { OMAP4_USB_OTG_HS_CLKCTRL, omap4_usb_otg_hs_bit_data, CLKF_HW_SUP, "l3_div_ck" }, { OMAP4_USB_TLL_HS_CLKCTRL, omap4_usb_tll_hs_bit_data, CLKF_HW_SUP, "l4_div_ck" }, { OMAP4_USB_HOST_FS_CLKCTRL, NULL, CLKF_SW_SUP, "func_48mc_fclk" }, - { OMAP4_OCP2SCP_USB_PHY_CLKCTRL, omap4_ocp2scp_usb_phy_bit_data, CLKF_HW_SUP, "ocp2scp_usb_phy_phy_48m" }, + { OMAP4_OCP2SCP_USB_PHY_CLKCTRL, omap4_ocp2scp_usb_phy_bit_data, CLKF_HW_SUP, "l3_init_cm:clk:00c0:8" }, { 0 }, }; @@ -531,7 +533,7 @@ static const struct omap_clkctrl_bit_data omap4_gpio6_bit_data[] __initconst = { }; static const char * const omap4_per_mcbsp4_gfclk_parents[] __initconst = { - "mcbsp4_sync_mux_ck", + "l4_per_cm:clk:00c0:26", "pad_clks_ck", NULL, }; @@ -544,7 +546,7 @@ static const char * const omap4_mcbsp4_sync_mux_ck_parents[] __initconst = { static const struct omap_clkctrl_bit_data omap4_mcbsp4_bit_data[] __initconst = { { 24, TI_CLK_MUX, omap4_per_mcbsp4_gfclk_parents, NULL }, - { 25, TI_CLK_MUX, omap4_mcbsp4_sync_mux_ck_parents, NULL }, + { 26, TI_CLK_MUX, omap4_mcbsp4_sync_mux_ck_parents, NULL }, { 0 }, }; @@ -571,12 +573,12 @@ static const struct omap_clkctrl_bit_data omap4_slimbus2_bit_data[] __initconst }; static const struct omap_clkctrl_reg_data omap4_l4_per_clkctrl_regs[] __initconst = { - { OMAP4_TIMER10_CLKCTRL, omap4_timer10_bit_data, CLKF_SW_SUP, "cm2_dm10_mux" }, - { OMAP4_TIMER11_CLKCTRL, omap4_timer11_bit_data, CLKF_SW_SUP, "cm2_dm11_mux" }, - { OMAP4_TIMER2_CLKCTRL, omap4_timer2_bit_data, CLKF_SW_SUP, "cm2_dm2_mux" }, - { OMAP4_TIMER3_CLKCTRL, omap4_timer3_bit_data, CLKF_SW_SUP, "cm2_dm3_mux" }, - { OMAP4_TIMER4_CLKCTRL, omap4_timer4_bit_data, CLKF_SW_SUP, "cm2_dm4_mux" }, - { OMAP4_TIMER9_CLKCTRL, omap4_timer9_bit_data, CLKF_SW_SUP, "cm2_dm9_mux" }, + { OMAP4_TIMER10_CLKCTRL, omap4_timer10_bit_data, CLKF_SW_SUP, "l4_per_cm:clk:0008:24" }, + { OMAP4_TIMER11_CLKCTRL, omap4_timer11_bit_data, CLKF_SW_SUP, "l4_per_cm:clk:0010:24" }, + { OMAP4_TIMER2_CLKCTRL, omap4_timer2_bit_data, CLKF_SW_SUP, "l4_per_cm:clk:0018:24" }, + { OMAP4_TIMER3_CLKCTRL, omap4_timer3_bit_data, CLKF_SW_SUP, "l4_per_cm:clk:0020:24" }, + { OMAP4_TIMER4_CLKCTRL, omap4_timer4_bit_data, CLKF_SW_SUP, "l4_per_cm:clk:0028:24" }, + { OMAP4_TIMER9_CLKCTRL, omap4_timer9_bit_data, CLKF_SW_SUP, "l4_per_cm:clk:0030:24" }, { OMAP4_ELM_CLKCTRL, NULL, 0, "l4_div_ck" }, { OMAP4_GPIO2_CLKCTRL, omap4_gpio2_bit_data, CLKF_HW_SUP, "l4_div_ck" }, { OMAP4_GPIO3_CLKCTRL, omap4_gpio3_bit_data, CLKF_HW_SUP, "l4_div_ck" }, @@ -589,14 +591,14 @@ static const struct omap_clkctrl_reg_data omap4_l4_per_clkctrl_regs[] __initcons { OMAP4_I2C3_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" }, { OMAP4_I2C4_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" }, { OMAP4_L4_PER_CLKCTRL, NULL, 0, "l4_div_ck" }, - { OMAP4_MCBSP4_CLKCTRL, omap4_mcbsp4_bit_data, CLKF_SW_SUP, "per_mcbsp4_gfclk" }, + { OMAP4_MCBSP4_CLKCTRL, omap4_mcbsp4_bit_data, CLKF_SW_SUP, "l4_per_cm:clk:00c0:24" }, { OMAP4_MCSPI1_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, { OMAP4_MCSPI2_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, { OMAP4_MCSPI3_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, { OMAP4_MCSPI4_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, { OMAP4_MMC3_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, { OMAP4_MMC4_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, - { OMAP4_SLIMBUS2_CLKCTRL, omap4_slimbus2_bit_data, CLKF_SW_SUP, "slimbus2_fclk_0" }, + { OMAP4_SLIMBUS2_CLKCTRL, omap4_slimbus2_bit_data, CLKF_SW_SUP, "l4_per_cm:clk:0118:8" }, { OMAP4_UART1_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, { OMAP4_UART2_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, { OMAP4_UART3_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, @@ -619,7 +621,7 @@ static const struct omap_clkctrl_reg_data omap4_l4_wkup_clkctrl_regs[] __initcon { OMAP4_L4_WKUP_CLKCTRL, NULL, 0, "l4_wkup_clk_mux_ck" }, { OMAP4_WD_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "sys_32k_ck" }, { OMAP4_GPIO1_CLKCTRL, omap4_gpio1_bit_data, CLKF_HW_SUP, "l4_wkup_clk_mux_ck" }, - { OMAP4_TIMER1_CLKCTRL, omap4_timer1_bit_data, CLKF_SW_SUP, "dmt1_clk_mux" }, + { OMAP4_TIMER1_CLKCTRL, omap4_timer1_bit_data, CLKF_SW_SUP, "l4_wkup_cm:clk:0020:24" }, { OMAP4_COUNTER_32K_CLKCTRL, NULL, 0, "sys_32k_ck" }, { OMAP4_KBD_CLKCTRL, NULL, CLKF_SW_SUP, "sys_32k_ck" }, { 0 }, @@ -633,7 +635,7 @@ static const char * const omap4_pmd_stm_clock_mux_ck_parents[] __initconst = { }; static const char * const omap4_trace_clk_div_div_ck_parents[] __initconst = { - "pmd_trace_clk_mux_ck", + "emu_sys_cm:clk:0000:22", NULL, }; @@ -651,12 +653,13 @@ static const struct omap_clkctrl_div_data omap4_trace_clk_div_div_ck_data __init }; static const char * const omap4_stm_clk_div_ck_parents[] __initconst = { - "pmd_stm_clock_mux_ck", + "emu_sys_cm:clk:0000:20", NULL, }; static const struct omap_clkctrl_div_data omap4_stm_clk_div_ck_data __initconst = { .max_div = 64, + .flags = CLK_DIVIDER_POWER_OF_TWO, }; static const struct omap_clkctrl_bit_data omap4_debugss_bit_data[] __initconst = { @@ -697,52 +700,79 @@ const struct omap_clkctrl_data omap4_clkctrl_data[] __initconst = { }; static struct ti_dt_clk omap44xx_clks[] = { - DT_CLK("smp_twd", NULL, "mpu_periphclk"), - DT_CLK("omapdss_dss", "ick", "dss_fck"), - DT_CLK("usbhs_omap", "fs_fck", "usb_host_fs_fck"), - DT_CLK("usbhs_omap", "hs_fck", "usb_host_hs_fck"), - DT_CLK("musb-omap2430", "ick", "usb_otg_hs_ick"), - DT_CLK("usbhs_omap", "usbtll_ick", "usb_tll_hs_ick"), - DT_CLK("usbhs_tll", "usbtll_ick", "usb_tll_hs_ick"), - DT_CLK("omap_i2c.1", "ick", "dummy_ck"), - DT_CLK("omap_i2c.2", "ick", "dummy_ck"), - DT_CLK("omap_i2c.3", "ick", "dummy_ck"), - DT_CLK("omap_i2c.4", "ick", "dummy_ck"), - DT_CLK(NULL, "mailboxes_ick", "dummy_ck"), - DT_CLK("omap_hsmmc.0", "ick", "dummy_ck"), - DT_CLK("omap_hsmmc.1", "ick", "dummy_ck"), - DT_CLK("omap_hsmmc.2", "ick", "dummy_ck"), - DT_CLK("omap_hsmmc.3", "ick", "dummy_ck"), - DT_CLK("omap_hsmmc.4", "ick", "dummy_ck"), - DT_CLK("omap-mcbsp.1", "ick", "dummy_ck"), - DT_CLK("omap-mcbsp.2", "ick", "dummy_ck"), - DT_CLK("omap-mcbsp.3", "ick", "dummy_ck"), - DT_CLK("omap-mcbsp.4", "ick", "dummy_ck"), - DT_CLK("omap2_mcspi.1", "ick", "dummy_ck"), - DT_CLK("omap2_mcspi.2", "ick", "dummy_ck"), - DT_CLK("omap2_mcspi.3", "ick", "dummy_ck"), - DT_CLK("omap2_mcspi.4", "ick", "dummy_ck"), - DT_CLK(NULL, "uart1_ick", "dummy_ck"), - DT_CLK(NULL, "uart2_ick", "dummy_ck"), - DT_CLK(NULL, "uart3_ick", "dummy_ck"), - DT_CLK(NULL, "uart4_ick", "dummy_ck"), - DT_CLK("usbhs_omap", "usbhost_ick", "dummy_ck"), - DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"), - DT_CLK("usbhs_tll", "usbtll_fck", "dummy_ck"), - DT_CLK("omap_wdt", "ick", "dummy_ck"), DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"), - DT_CLK("4a318000.timer", "timer_sys_ck", "sys_clkin_ck"), - DT_CLK("48032000.timer", "timer_sys_ck", "sys_clkin_ck"), - DT_CLK("48034000.timer", "timer_sys_ck", "sys_clkin_ck"), - DT_CLK("48036000.timer", "timer_sys_ck", "sys_clkin_ck"), - DT_CLK("4803e000.timer", "timer_sys_ck", "sys_clkin_ck"), - DT_CLK("48086000.timer", "timer_sys_ck", "sys_clkin_ck"), - DT_CLK("48088000.timer", "timer_sys_ck", "sys_clkin_ck"), - DT_CLK("40138000.timer", "timer_sys_ck", "syc_clk_div_ck"), - DT_CLK("4013a000.timer", "timer_sys_ck", "syc_clk_div_ck"), - DT_CLK("4013c000.timer", "timer_sys_ck", "syc_clk_div_ck"), - DT_CLK("4013e000.timer", "timer_sys_ck", "syc_clk_div_ck"), - DT_CLK(NULL, "cpufreq_ck", "dpll_mpu_ck"), + /* + * XXX: All the clock aliases below are only needed for legacy + * hwmod support. Once hwmod is removed, these can be removed + * also. + */ + DT_CLK(NULL, "aess_fclk", "abe_cm:0008:24"), + DT_CLK(NULL, "cm2_dm10_mux", "l4_per_cm:0008:24"), + DT_CLK(NULL, "cm2_dm11_mux", "l4_per_cm:0010:24"), + DT_CLK(NULL, "cm2_dm2_mux", "l4_per_cm:0018:24"), + DT_CLK(NULL, "cm2_dm3_mux", "l4_per_cm:0020:24"), + DT_CLK(NULL, "cm2_dm4_mux", "l4_per_cm:0028:24"), + DT_CLK(NULL, "cm2_dm9_mux", "l4_per_cm:0030:24"), + DT_CLK(NULL, "dmic_sync_mux_ck", "abe_cm:0018:26"), + DT_CLK(NULL, "dmt1_clk_mux", "l4_wkup_cm:0020:24"), + DT_CLK(NULL, "dss_48mhz_clk", "l3_dss_cm:0000:9"), + DT_CLK(NULL, "dss_dss_clk", "l3_dss_cm:0000:8"), + DT_CLK(NULL, "dss_sys_clk", "l3_dss_cm:0000:10"), + DT_CLK(NULL, "dss_tv_clk", "l3_dss_cm:0000:11"), + DT_CLK(NULL, "fdif_fck", "iss_cm:0008:24"), + DT_CLK(NULL, "func_dmic_abe_gfclk", "abe_cm:0018:24"), + DT_CLK(NULL, "func_mcasp_abe_gfclk", "abe_cm:0020:24"), + DT_CLK(NULL, "func_mcbsp1_gfclk", "abe_cm:0028:24"), + DT_CLK(NULL, "func_mcbsp2_gfclk", "abe_cm:0030:24"), + DT_CLK(NULL, "func_mcbsp3_gfclk", "abe_cm:0038:24"), + DT_CLK(NULL, "gpio1_dbclk", "l4_wkup_cm:0018:8"), + DT_CLK(NULL, "gpio2_dbclk", "l4_per_cm:0040:8"), + DT_CLK(NULL, "gpio3_dbclk", "l4_per_cm:0048:8"), + DT_CLK(NULL, "gpio4_dbclk", "l4_per_cm:0050:8"), + DT_CLK(NULL, "gpio5_dbclk", "l4_per_cm:0058:8"), + DT_CLK(NULL, "gpio6_dbclk", "l4_per_cm:0060:8"), + DT_CLK(NULL, "hsi_fck", "l3_init_cm:0018:24"), + DT_CLK(NULL, "hsmmc1_fclk", "l3_init_cm:0008:24"), + DT_CLK(NULL, "hsmmc2_fclk", "l3_init_cm:0010:24"), + DT_CLK(NULL, "iss_ctrlclk", "iss_cm:0000:8"), + DT_CLK(NULL, "mcasp_sync_mux_ck", "abe_cm:0020:26"), + DT_CLK(NULL, "mcbsp1_sync_mux_ck", "abe_cm:0028:26"), + DT_CLK(NULL, "mcbsp2_sync_mux_ck", "abe_cm:0030:26"), + DT_CLK(NULL, "mcbsp3_sync_mux_ck", "abe_cm:0038:26"), + DT_CLK(NULL, "mcbsp4_sync_mux_ck", "l4_per_cm:00c0:26"), + DT_CLK(NULL, "ocp2scp_usb_phy_phy_48m", "l3_init_cm:00c0:8"), + DT_CLK(NULL, "otg_60m_gfclk", "l3_init_cm:0040:24"), + DT_CLK(NULL, "per_mcbsp4_gfclk", "l4_per_cm:00c0:24"), + DT_CLK(NULL, "pmd_stm_clock_mux_ck", "emu_sys_cm:0000:20"), + DT_CLK(NULL, "pmd_trace_clk_mux_ck", "emu_sys_cm:0000:22"), + DT_CLK(NULL, "sgx_clk_mux", "l3_gfx_cm:0000:24"), + DT_CLK(NULL, "slimbus1_fclk_0", "abe_cm:0040:8"), + DT_CLK(NULL, "slimbus1_fclk_1", "abe_cm:0040:9"), + DT_CLK(NULL, "slimbus1_fclk_2", "abe_cm:0040:10"), + DT_CLK(NULL, "slimbus1_slimbus_clk", "abe_cm:0040:11"), + DT_CLK(NULL, "slimbus2_fclk_0", "l4_per_cm:0118:8"), + DT_CLK(NULL, "slimbus2_fclk_1", "l4_per_cm:0118:9"), + DT_CLK(NULL, "slimbus2_slimbus_clk", "l4_per_cm:0118:10"), + DT_CLK(NULL, "stm_clk_div_ck", "emu_sys_cm:0000:27"), + DT_CLK(NULL, "timer5_sync_mux", "abe_cm:0048:24"), + DT_CLK(NULL, "timer6_sync_mux", "abe_cm:0050:24"), + DT_CLK(NULL, "timer7_sync_mux", "abe_cm:0058:24"), + DT_CLK(NULL, "timer8_sync_mux", "abe_cm:0060:24"), + DT_CLK(NULL, "trace_clk_div_div_ck", "emu_sys_cm:0000:24"), + DT_CLK(NULL, "usb_host_hs_func48mclk", "l3_init_cm:0038:15"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p1_clk", "l3_init_cm:0038:13"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p2_clk", "l3_init_cm:0038:14"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p1_clk", "l3_init_cm:0038:11"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p2_clk", "l3_init_cm:0038:12"), + DT_CLK(NULL, "usb_host_hs_utmi_p1_clk", "l3_init_cm:0038:8"), + DT_CLK(NULL, "usb_host_hs_utmi_p2_clk", "l3_init_cm:0038:9"), + DT_CLK(NULL, "usb_host_hs_utmi_p3_clk", "l3_init_cm:0038:10"), + DT_CLK(NULL, "usb_otg_hs_xclk", "l3_init_cm:0040:8"), + DT_CLK(NULL, "usb_tll_hs_usb_ch0_clk", "l3_init_cm:0048:8"), + DT_CLK(NULL, "usb_tll_hs_usb_ch1_clk", "l3_init_cm:0048:9"), + DT_CLK(NULL, "usb_tll_hs_usb_ch2_clk", "l3_init_cm:0048:10"), + DT_CLK(NULL, "utmi_p1_gfclk", "l3_init_cm:0038:24"), + DT_CLK(NULL, "utmi_p2_gfclk", "l3_init_cm:0038:25"), { .node_name = NULL }, }; diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c index 294bc03ec067..a17b0c4646a1 100644 --- a/drivers/clk/ti/clk-54xx.c +++ b/drivers/clk/ti/clk-54xx.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "clock.h" @@ -27,201 +28,511 @@ */ #define OMAP5_DPLL_USB_DEFFREQ 960000000 +static const struct omap_clkctrl_reg_data omap5_mpu_clkctrl_regs[] __initconst = { + { OMAP5_MPU_CLKCTRL, NULL, 0, "dpll_mpu_m2_ck" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data omap5_dsp_clkctrl_regs[] __initconst = { + { OMAP5_MMU_DSP_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_iva_h11x2_ck" }, + { 0 }, +}; + +static const char * const omap5_dmic_gfclk_parents[] __initconst = { + "abe_cm:clk:0018:26", + "pad_clks_ck", + "slimbus_clk", + NULL, +}; + +static const char * const omap5_dmic_sync_mux_ck_parents[] __initconst = { + "abe_24m_fclk", + "dss_syc_gfclk_div", + "func_24m_clk", + NULL, +}; + +static const struct omap_clkctrl_bit_data omap5_dmic_bit_data[] __initconst = { + { 24, TI_CLK_MUX, omap5_dmic_gfclk_parents, NULL }, + { 26, TI_CLK_MUX, omap5_dmic_sync_mux_ck_parents, NULL }, + { 0 }, +}; + +static const char * const omap5_mcbsp1_gfclk_parents[] __initconst = { + "abe_cm:clk:0028:26", + "pad_clks_ck", + "slimbus_clk", + NULL, +}; + +static const struct omap_clkctrl_bit_data omap5_mcbsp1_bit_data[] __initconst = { + { 24, TI_CLK_MUX, omap5_mcbsp1_gfclk_parents, NULL }, + { 26, TI_CLK_MUX, omap5_dmic_sync_mux_ck_parents, NULL }, + { 0 }, +}; + +static const char * const omap5_mcbsp2_gfclk_parents[] __initconst = { + "abe_cm:clk:0030:26", + "pad_clks_ck", + "slimbus_clk", + NULL, +}; + +static const struct omap_clkctrl_bit_data omap5_mcbsp2_bit_data[] __initconst = { + { 24, TI_CLK_MUX, omap5_mcbsp2_gfclk_parents, NULL }, + { 26, TI_CLK_MUX, omap5_dmic_sync_mux_ck_parents, NULL }, + { 0 }, +}; + +static const char * const omap5_mcbsp3_gfclk_parents[] __initconst = { + "abe_cm:clk:0038:26", + "pad_clks_ck", + "slimbus_clk", + NULL, +}; + +static const struct omap_clkctrl_bit_data omap5_mcbsp3_bit_data[] __initconst = { + { 24, TI_CLK_MUX, omap5_mcbsp3_gfclk_parents, NULL }, + { 26, TI_CLK_MUX, omap5_dmic_sync_mux_ck_parents, NULL }, + { 0 }, +}; + +static const char * const omap5_timer5_gfclk_mux_parents[] __initconst = { + "dss_syc_gfclk_div", + "sys_32k_ck", + NULL, +}; + +static const struct omap_clkctrl_bit_data omap5_timer5_bit_data[] __initconst = { + { 24, TI_CLK_MUX, omap5_timer5_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data omap5_timer6_bit_data[] __initconst = { + { 24, TI_CLK_MUX, omap5_timer5_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data omap5_timer7_bit_data[] __initconst = { + { 24, TI_CLK_MUX, omap5_timer5_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data omap5_timer8_bit_data[] __initconst = { + { 24, TI_CLK_MUX, omap5_timer5_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data omap5_abe_clkctrl_regs[] __initconst = { + { OMAP5_L4_ABE_CLKCTRL, NULL, 0, "abe_iclk" }, + { OMAP5_MCPDM_CLKCTRL, NULL, CLKF_SW_SUP, "pad_clks_ck" }, + { OMAP5_DMIC_CLKCTRL, omap5_dmic_bit_data, CLKF_SW_SUP, "abe_cm:clk:0018:24" }, + { OMAP5_MCBSP1_CLKCTRL, omap5_mcbsp1_bit_data, CLKF_SW_SUP, "abe_cm:clk:0028:24" }, + { OMAP5_MCBSP2_CLKCTRL, omap5_mcbsp2_bit_data, CLKF_SW_SUP, "abe_cm:clk:0030:24" }, + { OMAP5_MCBSP3_CLKCTRL, omap5_mcbsp3_bit_data, CLKF_SW_SUP, "abe_cm:clk:0038:24" }, + { OMAP5_TIMER5_CLKCTRL, omap5_timer5_bit_data, CLKF_SW_SUP, "abe_cm:clk:0048:24" }, + { OMAP5_TIMER6_CLKCTRL, omap5_timer6_bit_data, CLKF_SW_SUP, "abe_cm:clk:0050:24" }, + { OMAP5_TIMER7_CLKCTRL, omap5_timer7_bit_data, CLKF_SW_SUP, "abe_cm:clk:0058:24" }, + { OMAP5_TIMER8_CLKCTRL, omap5_timer8_bit_data, CLKF_SW_SUP, "abe_cm:clk:0060:24" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data omap5_l3main1_clkctrl_regs[] __initconst = { + { OMAP5_L3_MAIN_1_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data omap5_l3main2_clkctrl_regs[] __initconst = { + { OMAP5_L3_MAIN_2_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data omap5_ipu_clkctrl_regs[] __initconst = { + { OMAP5_MMU_IPU_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h22x2_ck" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data omap5_dma_clkctrl_regs[] __initconst = { + { OMAP5_DMA_SYSTEM_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data omap5_emif_clkctrl_regs[] __initconst = { + { OMAP5_DMM_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { OMAP5_EMIF1_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h11x2_ck" }, + { OMAP5_EMIF2_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h11x2_ck" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data omap5_l4cfg_clkctrl_regs[] __initconst = { + { OMAP5_L4_CFG_CLKCTRL, NULL, 0, "l4_root_clk_div" }, + { OMAP5_SPINLOCK_CLKCTRL, NULL, 0, "l4_root_clk_div" }, + { OMAP5_MAILBOX_CLKCTRL, NULL, 0, "l4_root_clk_div" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data omap5_l3instr_clkctrl_regs[] __initconst = { + { OMAP5_L3_MAIN_3_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" }, + { OMAP5_L3_INSTR_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" }, + { 0 }, +}; + +static const char * const omap5_timer10_gfclk_mux_parents[] __initconst = { + "sys_clkin", + "sys_32k_ck", + NULL, +}; + +static const struct omap_clkctrl_bit_data omap5_timer10_bit_data[] __initconst = { + { 24, TI_CLK_MUX, omap5_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data omap5_timer11_bit_data[] __initconst = { + { 24, TI_CLK_MUX, omap5_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data omap5_timer2_bit_data[] __initconst = { + { 24, TI_CLK_MUX, omap5_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data omap5_timer3_bit_data[] __initconst = { + { 24, TI_CLK_MUX, omap5_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data omap5_timer4_bit_data[] __initconst = { + { 24, TI_CLK_MUX, omap5_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data omap5_timer9_bit_data[] __initconst = { + { 24, TI_CLK_MUX, omap5_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const char * const omap5_gpio2_dbclk_parents[] __initconst = { + "sys_32k_ck", + NULL, +}; + +static const struct omap_clkctrl_bit_data omap5_gpio2_bit_data[] __initconst = { + { 8, TI_CLK_GATE, omap5_gpio2_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data omap5_gpio3_bit_data[] __initconst = { + { 8, TI_CLK_GATE, omap5_gpio2_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data omap5_gpio4_bit_data[] __initconst = { + { 8, TI_CLK_GATE, omap5_gpio2_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data omap5_gpio5_bit_data[] __initconst = { + { 8, TI_CLK_GATE, omap5_gpio2_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data omap5_gpio6_bit_data[] __initconst = { + { 8, TI_CLK_GATE, omap5_gpio2_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data omap5_gpio7_bit_data[] __initconst = { + { 8, TI_CLK_GATE, omap5_gpio2_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data omap5_gpio8_bit_data[] __initconst = { + { 8, TI_CLK_GATE, omap5_gpio2_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data omap5_l4per_clkctrl_regs[] __initconst = { + { OMAP5_TIMER10_CLKCTRL, omap5_timer10_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0008:24" }, + { OMAP5_TIMER11_CLKCTRL, omap5_timer11_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0010:24" }, + { OMAP5_TIMER2_CLKCTRL, omap5_timer2_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0018:24" }, + { OMAP5_TIMER3_CLKCTRL, omap5_timer3_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0020:24" }, + { OMAP5_TIMER4_CLKCTRL, omap5_timer4_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0028:24" }, + { OMAP5_TIMER9_CLKCTRL, omap5_timer9_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0030:24" }, + { OMAP5_GPIO2_CLKCTRL, omap5_gpio2_bit_data, CLKF_HW_SUP, "l4_root_clk_div" }, + { OMAP5_GPIO3_CLKCTRL, omap5_gpio3_bit_data, CLKF_HW_SUP, "l4_root_clk_div" }, + { OMAP5_GPIO4_CLKCTRL, omap5_gpio4_bit_data, CLKF_HW_SUP, "l4_root_clk_div" }, + { OMAP5_GPIO5_CLKCTRL, omap5_gpio5_bit_data, CLKF_HW_SUP, "l4_root_clk_div" }, + { OMAP5_GPIO6_CLKCTRL, omap5_gpio6_bit_data, CLKF_HW_SUP, "l4_root_clk_div" }, + { OMAP5_I2C1_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" }, + { OMAP5_I2C2_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" }, + { OMAP5_I2C3_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" }, + { OMAP5_I2C4_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" }, + { OMAP5_L4_PER_CLKCTRL, NULL, 0, "l4_root_clk_div" }, + { OMAP5_MCSPI1_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, + { OMAP5_MCSPI2_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, + { OMAP5_MCSPI3_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, + { OMAP5_MCSPI4_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, + { OMAP5_GPIO7_CLKCTRL, omap5_gpio7_bit_data, CLKF_HW_SUP, "l4_root_clk_div" }, + { OMAP5_GPIO8_CLKCTRL, omap5_gpio8_bit_data, CLKF_HW_SUP, "l4_root_clk_div" }, + { OMAP5_MMC3_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, + { OMAP5_MMC4_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, + { OMAP5_UART1_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, + { OMAP5_UART2_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, + { OMAP5_UART3_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, + { OMAP5_UART4_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, + { OMAP5_MMC5_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" }, + { OMAP5_I2C5_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" }, + { OMAP5_UART5_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, + { OMAP5_UART6_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, + { 0 }, +}; + +static const char * const omap5_dss_dss_clk_parents[] __initconst = { + "dpll_per_h12x2_ck", + NULL, +}; + +static const char * const omap5_dss_48mhz_clk_parents[] __initconst = { + "func_48m_fclk", + NULL, +}; + +static const char * const omap5_dss_sys_clk_parents[] __initconst = { + "dss_syc_gfclk_div", + NULL, +}; + +static const struct omap_clkctrl_bit_data omap5_dss_core_bit_data[] __initconst = { + { 8, TI_CLK_GATE, omap5_dss_dss_clk_parents, NULL }, + { 9, TI_CLK_GATE, omap5_dss_48mhz_clk_parents, NULL }, + { 10, TI_CLK_GATE, omap5_dss_sys_clk_parents, NULL }, + { 11, TI_CLK_GATE, omap5_gpio2_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data omap5_dss_clkctrl_regs[] __initconst = { + { OMAP5_DSS_CORE_CLKCTRL, omap5_dss_core_bit_data, CLKF_SW_SUP, "dss_cm:clk:0000:8" }, + { 0 }, +}; + +static const char * const omap5_mmc1_fclk_mux_parents[] __initconst = { + "func_128m_clk", + "dpll_per_m2x2_ck", + NULL, +}; + +static const char * const omap5_mmc1_fclk_parents[] __initconst = { + "l3init_cm:clk:0008:24", + NULL, +}; + +static const struct omap_clkctrl_div_data omap5_mmc1_fclk_data __initconst = { + .max_div = 2, +}; + +static const struct omap_clkctrl_bit_data omap5_mmc1_bit_data[] __initconst = { + { 8, TI_CLK_GATE, omap5_gpio2_dbclk_parents, NULL }, + { 24, TI_CLK_MUX, omap5_mmc1_fclk_mux_parents, NULL }, + { 25, TI_CLK_DIVIDER, omap5_mmc1_fclk_parents, &omap5_mmc1_fclk_data }, + { 0 }, +}; + +static const char * const omap5_mmc2_fclk_parents[] __initconst = { + "l3init_cm:clk:0010:24", + NULL, +}; + +static const struct omap_clkctrl_div_data omap5_mmc2_fclk_data __initconst = { + .max_div = 2, +}; + +static const struct omap_clkctrl_bit_data omap5_mmc2_bit_data[] __initconst = { + { 24, TI_CLK_MUX, omap5_mmc1_fclk_mux_parents, NULL }, + { 25, TI_CLK_DIVIDER, omap5_mmc2_fclk_parents, &omap5_mmc2_fclk_data }, + { 0 }, +}; + +static const char * const omap5_usb_host_hs_hsic60m_p3_clk_parents[] __initconst = { + "l3init_60m_fclk", + NULL, +}; + +static const char * const omap5_usb_host_hs_hsic480m_p3_clk_parents[] __initconst = { + "dpll_usb_m2_ck", + NULL, +}; + +static const char * const omap5_usb_host_hs_utmi_p1_clk_parents[] __initconst = { + "l3init_cm:clk:0038:24", + NULL, +}; + +static const char * const omap5_usb_host_hs_utmi_p2_clk_parents[] __initconst = { + "l3init_cm:clk:0038:25", + NULL, +}; + +static const char * const omap5_utmi_p1_gfclk_parents[] __initconst = { + "l3init_60m_fclk", + "xclk60mhsp1_ck", + NULL, +}; + +static const char * const omap5_utmi_p2_gfclk_parents[] __initconst = { + "l3init_60m_fclk", + "xclk60mhsp2_ck", + NULL, +}; + +static const struct omap_clkctrl_bit_data omap5_usb_host_hs_bit_data[] __initconst = { + { 6, TI_CLK_GATE, omap5_usb_host_hs_hsic60m_p3_clk_parents, NULL }, + { 7, TI_CLK_GATE, omap5_usb_host_hs_hsic480m_p3_clk_parents, NULL }, + { 8, TI_CLK_GATE, omap5_usb_host_hs_utmi_p1_clk_parents, NULL }, + { 9, TI_CLK_GATE, omap5_usb_host_hs_utmi_p2_clk_parents, NULL }, + { 10, TI_CLK_GATE, omap5_usb_host_hs_hsic60m_p3_clk_parents, NULL }, + { 11, TI_CLK_GATE, omap5_usb_host_hs_hsic60m_p3_clk_parents, NULL }, + { 12, TI_CLK_GATE, omap5_usb_host_hs_hsic60m_p3_clk_parents, NULL }, + { 13, TI_CLK_GATE, omap5_usb_host_hs_hsic480m_p3_clk_parents, NULL }, + { 14, TI_CLK_GATE, omap5_usb_host_hs_hsic480m_p3_clk_parents, NULL }, + { 24, TI_CLK_MUX, omap5_utmi_p1_gfclk_parents, NULL }, + { 25, TI_CLK_MUX, omap5_utmi_p2_gfclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data omap5_usb_tll_hs_bit_data[] __initconst = { + { 8, TI_CLK_GATE, omap5_usb_host_hs_hsic60m_p3_clk_parents, NULL }, + { 9, TI_CLK_GATE, omap5_usb_host_hs_hsic60m_p3_clk_parents, NULL }, + { 10, TI_CLK_GATE, omap5_usb_host_hs_hsic60m_p3_clk_parents, NULL }, + { 0 }, +}; + +static const char * const omap5_sata_ref_clk_parents[] __initconst = { + "sys_clkin", + NULL, +}; + +static const struct omap_clkctrl_bit_data omap5_sata_bit_data[] __initconst = { + { 8, TI_CLK_GATE, omap5_sata_ref_clk_parents, NULL }, + { 0 }, +}; + +static const char * const omap5_usb_otg_ss_refclk960m_parents[] __initconst = { + "dpll_usb_clkdcoldo", + NULL, +}; + +static const struct omap_clkctrl_bit_data omap5_usb_otg_ss_bit_data[] __initconst = { + { 8, TI_CLK_GATE, omap5_usb_otg_ss_refclk960m_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data omap5_l3init_clkctrl_regs[] __initconst = { + { OMAP5_MMC1_CLKCTRL, omap5_mmc1_bit_data, CLKF_SW_SUP, "l3init_cm:clk:0008:25" }, + { OMAP5_MMC2_CLKCTRL, omap5_mmc2_bit_data, CLKF_SW_SUP, "l3init_cm:clk:0010:25" }, + { OMAP5_USB_HOST_HS_CLKCTRL, omap5_usb_host_hs_bit_data, CLKF_SW_SUP, "l3init_60m_fclk" }, + { OMAP5_USB_TLL_HS_CLKCTRL, omap5_usb_tll_hs_bit_data, CLKF_HW_SUP, "l4_root_clk_div" }, + { OMAP5_SATA_CLKCTRL, omap5_sata_bit_data, CLKF_SW_SUP, "func_48m_fclk" }, + { OMAP5_OCP2SCP1_CLKCTRL, NULL, CLKF_HW_SUP, "l4_root_clk_div" }, + { OMAP5_OCP2SCP3_CLKCTRL, NULL, CLKF_HW_SUP, "l4_root_clk_div" }, + { OMAP5_USB_OTG_SS_CLKCTRL, omap5_usb_otg_ss_bit_data, CLKF_HW_SUP, "dpll_core_h13x2_ck" }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data omap5_gpio1_bit_data[] __initconst = { + { 8, TI_CLK_GATE, omap5_gpio2_dbclk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data omap5_timer1_bit_data[] __initconst = { + { 24, TI_CLK_MUX, omap5_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data omap5_wkupaon_clkctrl_regs[] __initconst = { + { OMAP5_L4_WKUP_CLKCTRL, NULL, 0, "wkupaon_iclk_mux" }, + { OMAP5_WD_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "sys_32k_ck" }, + { OMAP5_GPIO1_CLKCTRL, omap5_gpio1_bit_data, CLKF_HW_SUP, "wkupaon_iclk_mux" }, + { OMAP5_TIMER1_CLKCTRL, omap5_timer1_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0020:24" }, + { OMAP5_COUNTER_32K_CLKCTRL, NULL, 0, "wkupaon_iclk_mux" }, + { OMAP5_KBD_CLKCTRL, NULL, CLKF_SW_SUP, "sys_32k_ck" }, + { 0 }, +}; + +const struct omap_clkctrl_data omap5_clkctrl_data[] __initconst = { + { 0x4a004320, omap5_mpu_clkctrl_regs }, + { 0x4a004420, omap5_dsp_clkctrl_regs }, + { 0x4a004520, omap5_abe_clkctrl_regs }, + { 0x4a008720, omap5_l3main1_clkctrl_regs }, + { 0x4a008820, omap5_l3main2_clkctrl_regs }, + { 0x4a008920, omap5_ipu_clkctrl_regs }, + { 0x4a008a20, omap5_dma_clkctrl_regs }, + { 0x4a008b20, omap5_emif_clkctrl_regs }, + { 0x4a008d20, omap5_l4cfg_clkctrl_regs }, + { 0x4a008e20, omap5_l3instr_clkctrl_regs }, + { 0x4a009020, omap5_l4per_clkctrl_regs }, + { 0x4a009420, omap5_dss_clkctrl_regs }, + { 0x4a009620, omap5_l3init_clkctrl_regs }, + { 0x4ae07920, omap5_wkupaon_clkctrl_regs }, + { 0 }, +}; + static struct ti_dt_clk omap54xx_clks[] = { - DT_CLK(NULL, "pad_clks_src_ck", "pad_clks_src_ck"), - DT_CLK(NULL, "pad_clks_ck", "pad_clks_ck"), - DT_CLK(NULL, "secure_32k_clk_src_ck", "secure_32k_clk_src_ck"), - DT_CLK(NULL, "slimbus_src_clk", "slimbus_src_clk"), - DT_CLK(NULL, "slimbus_clk", "slimbus_clk"), - DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"), - DT_CLK(NULL, "virt_12000000_ck", "virt_12000000_ck"), - DT_CLK(NULL, "virt_13000000_ck", "virt_13000000_ck"), - DT_CLK(NULL, "virt_16800000_ck", "virt_16800000_ck"), - DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), - DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), - DT_CLK(NULL, "virt_27000000_ck", "virt_27000000_ck"), - DT_CLK(NULL, "virt_38400000_ck", "virt_38400000_ck"), - DT_CLK(NULL, "sys_clkin", "sys_clkin"), - DT_CLK(NULL, "xclk60mhsp1_ck", "xclk60mhsp1_ck"), - DT_CLK(NULL, "xclk60mhsp2_ck", "xclk60mhsp2_ck"), - DT_CLK(NULL, "abe_dpll_bypass_clk_mux", "abe_dpll_bypass_clk_mux"), - DT_CLK(NULL, "abe_dpll_clk_mux", "abe_dpll_clk_mux"), - DT_CLK(NULL, "dpll_abe_ck", "dpll_abe_ck"), - DT_CLK(NULL, "dpll_abe_x2_ck", "dpll_abe_x2_ck"), - DT_CLK(NULL, "dpll_abe_m2x2_ck", "dpll_abe_m2x2_ck"), - DT_CLK(NULL, "abe_24m_fclk", "abe_24m_fclk"), - DT_CLK(NULL, "abe_clk", "abe_clk"), - DT_CLK(NULL, "abe_iclk", "abe_iclk"), - DT_CLK(NULL, "abe_lp_clk_div", "abe_lp_clk_div"), - DT_CLK(NULL, "dpll_abe_m3x2_ck", "dpll_abe_m3x2_ck"), - DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), - DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), - DT_CLK(NULL, "dpll_core_h21x2_ck", "dpll_core_h21x2_ck"), - DT_CLK(NULL, "c2c_fclk", "c2c_fclk"), - DT_CLK(NULL, "c2c_iclk", "c2c_iclk"), - DT_CLK(NULL, "custefuse_sys_gfclk_div", "custefuse_sys_gfclk_div"), - DT_CLK(NULL, "dpll_core_h11x2_ck", "dpll_core_h11x2_ck"), - DT_CLK(NULL, "dpll_core_h12x2_ck", "dpll_core_h12x2_ck"), - DT_CLK(NULL, "dpll_core_h13x2_ck", "dpll_core_h13x2_ck"), - DT_CLK(NULL, "dpll_core_h14x2_ck", "dpll_core_h14x2_ck"), - DT_CLK(NULL, "dpll_core_h22x2_ck", "dpll_core_h22x2_ck"), - DT_CLK(NULL, "dpll_core_h23x2_ck", "dpll_core_h23x2_ck"), - DT_CLK(NULL, "dpll_core_h24x2_ck", "dpll_core_h24x2_ck"), - DT_CLK(NULL, "dpll_core_m2_ck", "dpll_core_m2_ck"), - DT_CLK(NULL, "dpll_core_m3x2_ck", "dpll_core_m3x2_ck"), - DT_CLK(NULL, "iva_dpll_hs_clk_div", "iva_dpll_hs_clk_div"), - DT_CLK(NULL, "dpll_iva_ck", "dpll_iva_ck"), - DT_CLK(NULL, "dpll_iva_x2_ck", "dpll_iva_x2_ck"), - DT_CLK(NULL, "dpll_iva_h11x2_ck", "dpll_iva_h11x2_ck"), - DT_CLK(NULL, "dpll_iva_h12x2_ck", "dpll_iva_h12x2_ck"), - DT_CLK(NULL, "mpu_dpll_hs_clk_div", "mpu_dpll_hs_clk_div"), - DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), - DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), - DT_CLK(NULL, "per_dpll_hs_clk_div", "per_dpll_hs_clk_div"), - DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), - DT_CLK(NULL, "dpll_per_x2_ck", "dpll_per_x2_ck"), - DT_CLK(NULL, "dpll_per_h11x2_ck", "dpll_per_h11x2_ck"), - DT_CLK(NULL, "dpll_per_h12x2_ck", "dpll_per_h12x2_ck"), - DT_CLK(NULL, "dpll_per_h14x2_ck", "dpll_per_h14x2_ck"), - DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), - DT_CLK(NULL, "dpll_per_m2x2_ck", "dpll_per_m2x2_ck"), - DT_CLK(NULL, "dpll_per_m3x2_ck", "dpll_per_m3x2_ck"), - DT_CLK(NULL, "dpll_unipro1_ck", "dpll_unipro1_ck"), - DT_CLK(NULL, "dpll_unipro1_clkdcoldo", "dpll_unipro1_clkdcoldo"), - DT_CLK(NULL, "dpll_unipro1_m2_ck", "dpll_unipro1_m2_ck"), - DT_CLK(NULL, "dpll_unipro2_ck", "dpll_unipro2_ck"), - DT_CLK(NULL, "dpll_unipro2_clkdcoldo", "dpll_unipro2_clkdcoldo"), - DT_CLK(NULL, "dpll_unipro2_m2_ck", "dpll_unipro2_m2_ck"), - DT_CLK(NULL, "usb_dpll_hs_clk_div", "usb_dpll_hs_clk_div"), - DT_CLK(NULL, "dpll_usb_ck", "dpll_usb_ck"), - DT_CLK(NULL, "dpll_usb_clkdcoldo", "dpll_usb_clkdcoldo"), - DT_CLK(NULL, "dpll_usb_m2_ck", "dpll_usb_m2_ck"), - DT_CLK(NULL, "dss_syc_gfclk_div", "dss_syc_gfclk_div"), - DT_CLK(NULL, "func_128m_clk", "func_128m_clk"), - DT_CLK(NULL, "func_12m_fclk", "func_12m_fclk"), - DT_CLK(NULL, "func_24m_clk", "func_24m_clk"), - DT_CLK(NULL, "func_48m_fclk", "func_48m_fclk"), - DT_CLK(NULL, "func_96m_fclk", "func_96m_fclk"), - DT_CLK(NULL, "l3_iclk_div", "l3_iclk_div"), - DT_CLK(NULL, "gpu_l3_iclk", "gpu_l3_iclk"), - DT_CLK(NULL, "l3init_60m_fclk", "l3init_60m_fclk"), - DT_CLK(NULL, "wkupaon_iclk_mux", "wkupaon_iclk_mux"), - DT_CLK(NULL, "l3instr_ts_gclk_div", "l3instr_ts_gclk_div"), - DT_CLK(NULL, "l4_root_clk_div", "l4_root_clk_div"), - DT_CLK(NULL, "dss_32khz_clk", "dss_32khz_clk"), - DT_CLK(NULL, "dss_48mhz_clk", "dss_48mhz_clk"), - DT_CLK(NULL, "dss_dss_clk", "dss_dss_clk"), - DT_CLK(NULL, "dss_sys_clk", "dss_sys_clk"), - DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), - DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), - DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), - DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"), - DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"), - DT_CLK(NULL, "gpio6_dbclk", "gpio6_dbclk"), - DT_CLK(NULL, "gpio7_dbclk", "gpio7_dbclk"), - DT_CLK(NULL, "gpio8_dbclk", "gpio8_dbclk"), - DT_CLK(NULL, "iss_ctrlclk", "iss_ctrlclk"), - DT_CLK(NULL, "lli_txphy_clk", "lli_txphy_clk"), - DT_CLK(NULL, "lli_txphy_ls_clk", "lli_txphy_ls_clk"), - DT_CLK(NULL, "mmc1_32khz_clk", "mmc1_32khz_clk"), - DT_CLK(NULL, "sata_ref_clk", "sata_ref_clk"), - DT_CLK(NULL, "slimbus1_slimbus_clk", "slimbus1_slimbus_clk"), - DT_CLK(NULL, "usb_host_hs_hsic480m_p1_clk", "usb_host_hs_hsic480m_p1_clk"), - DT_CLK(NULL, "usb_host_hs_hsic480m_p2_clk", "usb_host_hs_hsic480m_p2_clk"), - DT_CLK(NULL, "usb_host_hs_hsic480m_p3_clk", "usb_host_hs_hsic480m_p3_clk"), - DT_CLK(NULL, "usb_host_hs_hsic60m_p1_clk", "usb_host_hs_hsic60m_p1_clk"), - DT_CLK(NULL, "usb_host_hs_hsic60m_p2_clk", "usb_host_hs_hsic60m_p2_clk"), - DT_CLK(NULL, "usb_host_hs_hsic60m_p3_clk", "usb_host_hs_hsic60m_p3_clk"), - DT_CLK(NULL, "usb_host_hs_utmi_p1_clk", "usb_host_hs_utmi_p1_clk"), - DT_CLK(NULL, "usb_host_hs_utmi_p2_clk", "usb_host_hs_utmi_p2_clk"), - DT_CLK(NULL, "usb_host_hs_utmi_p3_clk", "usb_host_hs_utmi_p3_clk"), - DT_CLK(NULL, "usb_otg_ss_refclk960m", "usb_otg_ss_refclk960m"), - DT_CLK(NULL, "usb_phy_cm_clk32k", "usb_phy_cm_clk32k"), - DT_CLK(NULL, "usb_tll_hs_usb_ch0_clk", "usb_tll_hs_usb_ch0_clk"), - DT_CLK(NULL, "usb_tll_hs_usb_ch1_clk", "usb_tll_hs_usb_ch1_clk"), - DT_CLK(NULL, "usb_tll_hs_usb_ch2_clk", "usb_tll_hs_usb_ch2_clk"), - DT_CLK(NULL, "aess_fclk", "aess_fclk"), - DT_CLK(NULL, "dmic_sync_mux_ck", "dmic_sync_mux_ck"), - DT_CLK(NULL, "dmic_gfclk", "dmic_gfclk"), - DT_CLK(NULL, "fdif_fclk", "fdif_fclk"), - DT_CLK(NULL, "gpu_core_gclk_mux", "gpu_core_gclk_mux"), - DT_CLK(NULL, "gpu_hyd_gclk_mux", "gpu_hyd_gclk_mux"), - DT_CLK(NULL, "hsi_fclk", "hsi_fclk"), - DT_CLK(NULL, "mcasp_sync_mux_ck", "mcasp_sync_mux_ck"), - DT_CLK(NULL, "mcasp_gfclk", "mcasp_gfclk"), - DT_CLK(NULL, "mcbsp1_sync_mux_ck", "mcbsp1_sync_mux_ck"), - DT_CLK(NULL, "mcbsp1_gfclk", "mcbsp1_gfclk"), - DT_CLK(NULL, "mcbsp2_sync_mux_ck", "mcbsp2_sync_mux_ck"), - DT_CLK(NULL, "mcbsp2_gfclk", "mcbsp2_gfclk"), - DT_CLK(NULL, "mcbsp3_sync_mux_ck", "mcbsp3_sync_mux_ck"), - DT_CLK(NULL, "mcbsp3_gfclk", "mcbsp3_gfclk"), - DT_CLK(NULL, "mmc1_fclk_mux", "mmc1_fclk_mux"), - DT_CLK(NULL, "mmc1_fclk", "mmc1_fclk"), - DT_CLK(NULL, "mmc2_fclk_mux", "mmc2_fclk_mux"), - DT_CLK(NULL, "mmc2_fclk", "mmc2_fclk"), - DT_CLK(NULL, "timer10_gfclk_mux", "timer10_gfclk_mux"), - DT_CLK(NULL, "timer11_gfclk_mux", "timer11_gfclk_mux"), - DT_CLK(NULL, "timer1_gfclk_mux", "timer1_gfclk_mux"), - DT_CLK(NULL, "timer2_gfclk_mux", "timer2_gfclk_mux"), - DT_CLK(NULL, "timer3_gfclk_mux", "timer3_gfclk_mux"), - DT_CLK(NULL, "timer4_gfclk_mux", "timer4_gfclk_mux"), - DT_CLK(NULL, "timer5_gfclk_mux", "timer5_gfclk_mux"), - DT_CLK(NULL, "timer6_gfclk_mux", "timer6_gfclk_mux"), - DT_CLK(NULL, "timer7_gfclk_mux", "timer7_gfclk_mux"), - DT_CLK(NULL, "timer8_gfclk_mux", "timer8_gfclk_mux"), - DT_CLK(NULL, "timer9_gfclk_mux", "timer9_gfclk_mux"), - DT_CLK(NULL, "utmi_p1_gfclk", "utmi_p1_gfclk"), - DT_CLK(NULL, "utmi_p2_gfclk", "utmi_p2_gfclk"), - DT_CLK(NULL, "auxclk0_src_ck", "auxclk0_src_ck"), - DT_CLK(NULL, "auxclk0_ck", "auxclk0_ck"), - DT_CLK(NULL, "auxclkreq0_ck", "auxclkreq0_ck"), - DT_CLK(NULL, "auxclk1_src_ck", "auxclk1_src_ck"), - DT_CLK(NULL, "auxclk1_ck", "auxclk1_ck"), - DT_CLK(NULL, "auxclkreq1_ck", "auxclkreq1_ck"), - DT_CLK(NULL, "auxclk2_src_ck", "auxclk2_src_ck"), - DT_CLK(NULL, "auxclk2_ck", "auxclk2_ck"), - DT_CLK(NULL, "auxclkreq2_ck", "auxclkreq2_ck"), - DT_CLK(NULL, "auxclk3_src_ck", "auxclk3_src_ck"), - DT_CLK(NULL, "auxclk3_ck", "auxclk3_ck"), - DT_CLK(NULL, "auxclkreq3_ck", "auxclkreq3_ck"), - DT_CLK("omap_i2c.1", "ick", "dummy_ck"), - DT_CLK("omap_i2c.2", "ick", "dummy_ck"), - DT_CLK("omap_i2c.3", "ick", "dummy_ck"), - DT_CLK("omap_i2c.4", "ick", "dummy_ck"), - DT_CLK(NULL, "mailboxes_ick", "dummy_ck"), - DT_CLK("omap_hsmmc.0", "ick", "dummy_ck"), - DT_CLK("omap_hsmmc.1", "ick", "dummy_ck"), - DT_CLK("omap_hsmmc.2", "ick", "dummy_ck"), - DT_CLK("omap_hsmmc.3", "ick", "dummy_ck"), - DT_CLK("omap_hsmmc.4", "ick", "dummy_ck"), - DT_CLK("omap-mcbsp.1", "ick", "dummy_ck"), - DT_CLK("omap-mcbsp.2", "ick", "dummy_ck"), - DT_CLK("omap-mcbsp.3", "ick", "dummy_ck"), - DT_CLK("omap-mcbsp.4", "ick", "dummy_ck"), - DT_CLK("omap2_mcspi.1", "ick", "dummy_ck"), - DT_CLK("omap2_mcspi.2", "ick", "dummy_ck"), - DT_CLK("omap2_mcspi.3", "ick", "dummy_ck"), - DT_CLK("omap2_mcspi.4", "ick", "dummy_ck"), - DT_CLK(NULL, "uart1_ick", "dummy_ck"), - DT_CLK(NULL, "uart2_ick", "dummy_ck"), - DT_CLK(NULL, "uart3_ick", "dummy_ck"), - DT_CLK(NULL, "uart4_ick", "dummy_ck"), - DT_CLK("usbhs_omap", "usbhost_ick", "dummy_ck"), - DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"), - DT_CLK("omap_wdt", "ick", "dummy_ck"), DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"), DT_CLK(NULL, "sys_clkin_ck", "sys_clkin"), - DT_CLK("4ae18000.timer", "timer_sys_ck", "sys_clkin"), - DT_CLK("48032000.timer", "timer_sys_ck", "sys_clkin"), - DT_CLK("48034000.timer", "timer_sys_ck", "sys_clkin"), - DT_CLK("48036000.timer", "timer_sys_ck", "sys_clkin"), - DT_CLK("4803e000.timer", "timer_sys_ck", "sys_clkin"), - DT_CLK("48086000.timer", "timer_sys_ck", "sys_clkin"), - DT_CLK("48088000.timer", "timer_sys_ck", "sys_clkin"), - DT_CLK("40138000.timer", "timer_sys_ck", "dss_syc_gfclk_div"), - DT_CLK("4013a000.timer", "timer_sys_ck", "dss_syc_gfclk_div"), - DT_CLK("4013c000.timer", "timer_sys_ck", "dss_syc_gfclk_div"), - DT_CLK("4013e000.timer", "timer_sys_ck", "dss_syc_gfclk_div"), + DT_CLK(NULL, "dmic_gfclk", "abe_cm:0018:24"), + DT_CLK(NULL, "dmic_sync_mux_ck", "abe_cm:0018:26"), + DT_CLK(NULL, "dss_32khz_clk", "dss_cm:0000:11"), + DT_CLK(NULL, "dss_48mhz_clk", "dss_cm:0000:9"), + DT_CLK(NULL, "dss_dss_clk", "dss_cm:0000:8"), + DT_CLK(NULL, "dss_sys_clk", "dss_cm:0000:10"), + DT_CLK(NULL, "gpio1_dbclk", "wkupaon_cm:0018:8"), + DT_CLK(NULL, "gpio2_dbclk", "l4per_cm:0040:8"), + DT_CLK(NULL, "gpio3_dbclk", "l4per_cm:0048:8"), + DT_CLK(NULL, "gpio4_dbclk", "l4per_cm:0050:8"), + DT_CLK(NULL, "gpio5_dbclk", "l4per_cm:0058:8"), + DT_CLK(NULL, "gpio6_dbclk", "l4per_cm:0060:8"), + DT_CLK(NULL, "gpio7_dbclk", "l4per_cm:00f0:8"), + DT_CLK(NULL, "gpio8_dbclk", "l4per_cm:00f8:8"), + DT_CLK(NULL, "mcbsp1_gfclk", "abe_cm:0028:24"), + DT_CLK(NULL, "mcbsp1_sync_mux_ck", "abe_cm:0028:26"), + DT_CLK(NULL, "mcbsp2_gfclk", "abe_cm:0030:24"), + DT_CLK(NULL, "mcbsp2_sync_mux_ck", "abe_cm:0030:26"), + DT_CLK(NULL, "mcbsp3_gfclk", "abe_cm:0038:24"), + DT_CLK(NULL, "mcbsp3_sync_mux_ck", "abe_cm:0038:26"), + DT_CLK(NULL, "mmc1_32khz_clk", "l3init_cm:0008:8"), + DT_CLK(NULL, "mmc1_fclk", "l3init_cm:0008:25"), + DT_CLK(NULL, "mmc1_fclk_mux", "l3init_cm:0008:24"), + DT_CLK(NULL, "mmc2_fclk", "l3init_cm:0010:25"), + DT_CLK(NULL, "mmc2_fclk_mux", "l3init_cm:0010:24"), + DT_CLK(NULL, "sata_ref_clk", "l3init_cm:0068:8"), + DT_CLK(NULL, "timer10_gfclk_mux", "l4per_cm:0008:24"), + DT_CLK(NULL, "timer11_gfclk_mux", "l4per_cm:0010:24"), + DT_CLK(NULL, "timer1_gfclk_mux", "wkupaon_cm:0020:24"), + DT_CLK(NULL, "timer2_gfclk_mux", "l4per_cm:0018:24"), + DT_CLK(NULL, "timer3_gfclk_mux", "l4per_cm:0020:24"), + DT_CLK(NULL, "timer4_gfclk_mux", "l4per_cm:0028:24"), + DT_CLK(NULL, "timer5_gfclk_mux", "abe_cm:0048:24"), + DT_CLK(NULL, "timer6_gfclk_mux", "abe_cm:0050:24"), + DT_CLK(NULL, "timer7_gfclk_mux", "abe_cm:0058:24"), + DT_CLK(NULL, "timer8_gfclk_mux", "abe_cm:0060:24"), + DT_CLK(NULL, "timer9_gfclk_mux", "l4per_cm:0030:24"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p1_clk", "l3init_cm:0038:13"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p2_clk", "l3init_cm:0038:14"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p3_clk", "l3init_cm:0038:7"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p1_clk", "l3init_cm:0038:11"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p2_clk", "l3init_cm:0038:12"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p3_clk", "l3init_cm:0038:6"), + DT_CLK(NULL, "usb_host_hs_utmi_p1_clk", "l3init_cm:0038:8"), + DT_CLK(NULL, "usb_host_hs_utmi_p2_clk", "l3init_cm:0038:9"), + DT_CLK(NULL, "usb_host_hs_utmi_p3_clk", "l3init_cm:0038:10"), + DT_CLK(NULL, "usb_otg_ss_refclk960m", "l3init_cm:00d0:8"), + DT_CLK(NULL, "usb_tll_hs_usb_ch0_clk", "l3init_cm:0048:8"), + DT_CLK(NULL, "usb_tll_hs_usb_ch1_clk", "l3init_cm:0048:9"), + DT_CLK(NULL, "usb_tll_hs_usb_ch2_clk", "l3init_cm:0048:10"), + DT_CLK(NULL, "utmi_p1_gfclk", "l3init_cm:0038:24"), + DT_CLK(NULL, "utmi_p2_gfclk", "l3init_cm:0038:25"), { .node_name = NULL }, }; @@ -234,6 +545,8 @@ int __init omap5xxx_dt_clk_init(void) omap2_clk_disable_autoidle_all(); + ti_clk_add_aliases(); + abe_dpll_ref = clk_get_sys(NULL, "abe_dpll_clk_mux"); sys_32k_ck = clk_get_sys(NULL, "sys_32k_ck"); rc = clk_set_parent(abe_dpll_ref, sys_32k_ck); diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c index 9fd6043314eb..fb249a1637a5 100644 --- a/drivers/clk/ti/clk-7xx.c +++ b/drivers/clk/ti/clk-7xx.c @@ -15,297 +15,809 @@ #include #include #include +#include #include "clock.h" #define DRA7_DPLL_GMAC_DEFFREQ 1000000000 #define DRA7_DPLL_USB_DEFFREQ 960000000 +static const struct omap_clkctrl_reg_data dra7_mpu_clkctrl_regs[] __initconst = { + { DRA7_MPU_CLKCTRL, NULL, 0, "dpll_mpu_m2_ck" }, + { 0 }, +}; + +static const char * const dra7_mcasp1_aux_gfclk_mux_parents[] __initconst = { + "per_abe_x1_gfclk2_div", + "video1_clk2_div", + "video2_clk2_div", + "hdmi_clk2_div", + NULL, +}; + +static const char * const dra7_mcasp1_ahclkx_mux_parents[] __initconst = { + "abe_24m_fclk", + "abe_sys_clk_div", + "func_24m_clk", + "atl_clkin3_ck", + "atl_clkin2_ck", + "atl_clkin1_ck", + "atl_clkin0_ck", + "sys_clkin2", + "ref_clkin0_ck", + "ref_clkin1_ck", + "ref_clkin2_ck", + "ref_clkin3_ck", + "mlb_clk", + "mlbp_clk", + NULL, +}; + +static const struct omap_clkctrl_bit_data dra7_mcasp1_bit_data[] __initconst = { + { 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL }, + { 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL }, + { 28, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL }, + { 0 }, +}; + +static const char * const dra7_timer5_gfclk_mux_parents[] __initconst = { + "timer_sys_clk_div", + "sys_32k_ck", + "sys_clkin2", + "ref_clkin0_ck", + "ref_clkin1_ck", + "ref_clkin2_ck", + "ref_clkin3_ck", + "abe_giclk_div", + "video1_div_clk", + "video2_div_clk", + "hdmi_div_clk", + "clkoutmux0_clk_mux", + NULL, +}; + +static const struct omap_clkctrl_bit_data dra7_timer5_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_timer5_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_timer6_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_timer5_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_timer7_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_timer5_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_timer8_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_timer5_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const char * const dra7_uart6_gfclk_mux_parents[] __initconst = { + "func_48m_fclk", + "dpll_per_m2x2_ck", + NULL, +}; + +static const struct omap_clkctrl_bit_data dra7_uart6_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data dra7_ipu_clkctrl_regs[] __initconst = { + { DRA7_MCASP1_CLKCTRL, dra7_mcasp1_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0010:22" }, + { DRA7_TIMER5_CLKCTRL, dra7_timer5_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0018:24" }, + { DRA7_TIMER6_CLKCTRL, dra7_timer6_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0020:24" }, + { DRA7_TIMER7_CLKCTRL, dra7_timer7_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0028:24" }, + { DRA7_TIMER8_CLKCTRL, dra7_timer8_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0030:24" }, + { DRA7_I2C5_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" }, + { DRA7_UART6_CLKCTRL, dra7_uart6_bit_data, CLKF_SW_SUP, "ipu_cm:clk:0040:24" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data dra7_rtc_clkctrl_regs[] __initconst = { + { DRA7_RTCSS_CLKCTRL, NULL, CLKF_SW_SUP, "sys_32k_ck" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data dra7_coreaon_clkctrl_regs[] __initconst = { + { DRA7_SMARTREFLEX_MPU_CLKCTRL, NULL, CLKF_SW_SUP, "wkupaon_iclk_mux" }, + { DRA7_SMARTREFLEX_CORE_CLKCTRL, NULL, CLKF_SW_SUP, "wkupaon_iclk_mux" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data dra7_l3main1_clkctrl_regs[] __initconst = { + { DRA7_L3_MAIN_1_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_GPMC_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" }, + { DRA7_TPCC_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_TPTC0_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" }, + { DRA7_TPTC1_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" }, + { DRA7_VCP1_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_VCP2_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data dra7_dma_clkctrl_regs[] __initconst = { + { DRA7_DMA_SYSTEM_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data dra7_emif_clkctrl_regs[] __initconst = { + { DRA7_DMM_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { 0 }, +}; + +static const char * const dra7_atl_dpll_clk_mux_parents[] __initconst = { + "sys_32k_ck", + "video1_clkin_ck", + "video2_clkin_ck", + "hdmi_clkin_ck", + NULL, +}; + +static const char * const dra7_atl_gfclk_mux_parents[] __initconst = { + "l3_iclk_div", + "dpll_abe_m2_ck", + "atl_cm:clk:0000:24", + NULL, +}; + +static const struct omap_clkctrl_bit_data dra7_atl_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_atl_dpll_clk_mux_parents, NULL }, + { 26, TI_CLK_MUX, dra7_atl_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data dra7_atl_clkctrl_regs[] __initconst = { + { DRA7_ATL_CLKCTRL, dra7_atl_bit_data, CLKF_SW_SUP, "atl_cm:clk:0000:26" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data dra7_l4cfg_clkctrl_regs[] __initconst = { + { DRA7_L4_CFG_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_SPINLOCK_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_MAILBOX1_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_MAILBOX2_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_MAILBOX3_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_MAILBOX4_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_MAILBOX5_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_MAILBOX6_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_MAILBOX7_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_MAILBOX8_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_MAILBOX9_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_MAILBOX10_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_MAILBOX11_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_MAILBOX12_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_MAILBOX13_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data dra7_l3instr_clkctrl_regs[] __initconst = { + { DRA7_L3_MAIN_2_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" }, + { DRA7_L3_INSTR_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" }, + { 0 }, +}; + +static const char * const dra7_dss_dss_clk_parents[] __initconst = { + "dpll_per_h12x2_ck", + NULL, +}; + +static const char * const dra7_dss_48mhz_clk_parents[] __initconst = { + "func_48m_fclk", + NULL, +}; + +static const char * const dra7_dss_hdmi_clk_parents[] __initconst = { + "hdmi_dpll_clk_mux", + NULL, +}; + +static const char * const dra7_dss_32khz_clk_parents[] __initconst = { + "sys_32k_ck", + NULL, +}; + +static const char * const dra7_dss_video1_clk_parents[] __initconst = { + "video1_dpll_clk_mux", + NULL, +}; + +static const char * const dra7_dss_video2_clk_parents[] __initconst = { + "video2_dpll_clk_mux", + NULL, +}; + +static const struct omap_clkctrl_bit_data dra7_dss_core_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_dss_dss_clk_parents, NULL }, + { 9, TI_CLK_GATE, dra7_dss_48mhz_clk_parents, NULL }, + { 10, TI_CLK_GATE, dra7_dss_hdmi_clk_parents, NULL }, + { 11, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL }, + { 12, TI_CLK_GATE, dra7_dss_video1_clk_parents, NULL }, + { 13, TI_CLK_GATE, dra7_dss_video2_clk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data dra7_dss_clkctrl_regs[] __initconst = { + { DRA7_DSS_CORE_CLKCTRL, dra7_dss_core_bit_data, CLKF_SW_SUP, "dss_cm:clk:0000:8" }, + { DRA7_BB2D_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_core_h24x2_ck" }, + { 0 }, +}; + +static const char * const dra7_mmc1_fclk_mux_parents[] __initconst = { + "func_128m_clk", + "dpll_per_m2x2_ck", + NULL, +}; + +static const char * const dra7_mmc1_fclk_div_parents[] __initconst = { + "l3init_cm:clk:0008:24", + NULL, +}; + +static const struct omap_clkctrl_div_data dra7_mmc1_fclk_div_data __initconst = { + .max_div = 4, + .flags = CLK_DIVIDER_POWER_OF_TWO, +}; + +static const struct omap_clkctrl_bit_data dra7_mmc1_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL }, + { 24, TI_CLK_MUX, dra7_mmc1_fclk_mux_parents, NULL }, + { 25, TI_CLK_DIVIDER, dra7_mmc1_fclk_div_parents, &dra7_mmc1_fclk_div_data }, + { 0 }, +}; + +static const char * const dra7_mmc2_fclk_div_parents[] __initconst = { + "l3init_cm:clk:0010:24", + NULL, +}; + +static const struct omap_clkctrl_div_data dra7_mmc2_fclk_div_data __initconst = { + .max_div = 4, + .flags = CLK_DIVIDER_POWER_OF_TWO, +}; + +static const struct omap_clkctrl_bit_data dra7_mmc2_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL }, + { 24, TI_CLK_MUX, dra7_mmc1_fclk_mux_parents, NULL }, + { 25, TI_CLK_DIVIDER, dra7_mmc2_fclk_div_parents, &dra7_mmc2_fclk_div_data }, + { 0 }, +}; + +static const char * const dra7_usb_otg_ss2_refclk960m_parents[] __initconst = { + "l3init_960m_gfclk", + NULL, +}; + +static const struct omap_clkctrl_bit_data dra7_usb_otg_ss2_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_usb_otg_ss2_refclk960m_parents, NULL }, + { 0 }, +}; + +static const char * const dra7_sata_ref_clk_parents[] __initconst = { + "sys_clkin1", + NULL, +}; + +static const struct omap_clkctrl_bit_data dra7_sata_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_sata_ref_clk_parents, NULL }, + { 0 }, +}; + +static const char * const dra7_optfclk_pciephy1_clk_parents[] __initconst = { + "apll_pcie_ck", + NULL, +}; + +static const char * const dra7_optfclk_pciephy1_div_clk_parents[] __initconst = { + "optfclk_pciephy_div", + NULL, +}; + +static const struct omap_clkctrl_bit_data dra7_pcie1_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL }, + { 9, TI_CLK_GATE, dra7_optfclk_pciephy1_clk_parents, NULL }, + { 10, TI_CLK_GATE, dra7_optfclk_pciephy1_div_clk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_pcie2_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL }, + { 9, TI_CLK_GATE, dra7_optfclk_pciephy1_clk_parents, NULL }, + { 10, TI_CLK_GATE, dra7_optfclk_pciephy1_div_clk_parents, NULL }, + { 0 }, +}; + +static const char * const dra7_rmii_50mhz_clk_mux_parents[] __initconst = { + "dpll_gmac_h11x2_ck", + "rmii_clk_ck", + NULL, +}; + +static const char * const dra7_gmac_rft_clk_mux_parents[] __initconst = { + "video1_clkin_ck", + "video2_clkin_ck", + "dpll_abe_m2_ck", + "hdmi_clkin_ck", + "l3_iclk_div", + NULL, +}; + +static const struct omap_clkctrl_bit_data dra7_gmac_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_rmii_50mhz_clk_mux_parents, NULL }, + { 25, TI_CLK_MUX, dra7_gmac_rft_clk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_usb_otg_ss1_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_usb_otg_ss2_refclk960m_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data dra7_l3init_clkctrl_regs[] __initconst = { + { DRA7_MMC1_CLKCTRL, dra7_mmc1_bit_data, CLKF_SW_SUP, "l3init_cm:clk:0008:25" }, + { DRA7_MMC2_CLKCTRL, dra7_mmc2_bit_data, CLKF_SW_SUP, "l3init_cm:clk:0010:25" }, + { DRA7_USB_OTG_SS2_CLKCTRL, dra7_usb_otg_ss2_bit_data, CLKF_HW_SUP, "dpll_core_h13x2_ck" }, + { DRA7_USB_OTG_SS3_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h13x2_ck" }, + { DRA7_USB_OTG_SS4_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h13x2_ck" }, + { DRA7_SATA_CLKCTRL, dra7_sata_bit_data, CLKF_SW_SUP, "func_48m_fclk" }, + { DRA7_PCIE1_CLKCTRL, dra7_pcie1_bit_data, CLKF_SW_SUP, "l4_root_clk_div", "pcie_clkdm" }, + { DRA7_PCIE2_CLKCTRL, dra7_pcie2_bit_data, CLKF_SW_SUP, "l4_root_clk_div", "pcie_clkdm" }, + { DRA7_GMAC_CLKCTRL, dra7_gmac_bit_data, CLKF_SW_SUP, "dpll_gmac_ck", "gmac_clkdm" }, + { DRA7_OCP2SCP1_CLKCTRL, NULL, CLKF_HW_SUP, "l4_root_clk_div" }, + { DRA7_OCP2SCP3_CLKCTRL, NULL, CLKF_HW_SUP, "l4_root_clk_div" }, + { DRA7_USB_OTG_SS1_CLKCTRL, dra7_usb_otg_ss1_bit_data, CLKF_HW_SUP, "dpll_core_h13x2_ck" }, + { 0 }, +}; + +static const char * const dra7_timer10_gfclk_mux_parents[] __initconst = { + "timer_sys_clk_div", + "sys_32k_ck", + "sys_clkin2", + "ref_clkin0_ck", + "ref_clkin1_ck", + "ref_clkin2_ck", + "ref_clkin3_ck", + "abe_giclk_div", + "video1_div_clk", + "video2_div_clk", + "hdmi_div_clk", + NULL, +}; + +static const struct omap_clkctrl_bit_data dra7_timer10_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_timer11_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_timer2_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_timer3_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_timer4_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_timer9_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_gpio2_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_gpio3_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_gpio4_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_gpio5_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_gpio6_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_timer13_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_timer14_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_timer15_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_gpio7_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_gpio8_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL }, + { 0 }, +}; + +static const char * const dra7_mmc3_gfclk_div_parents[] __initconst = { + "l4per_cm:clk:0120:24", + NULL, +}; + +static const struct omap_clkctrl_div_data dra7_mmc3_gfclk_div_data __initconst = { + .max_div = 4, + .flags = CLK_DIVIDER_POWER_OF_TWO, +}; + +static const struct omap_clkctrl_bit_data dra7_mmc3_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL }, + { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL }, + { 25, TI_CLK_DIVIDER, dra7_mmc3_gfclk_div_parents, &dra7_mmc3_gfclk_div_data }, + { 0 }, +}; + +static const char * const dra7_mmc4_gfclk_div_parents[] __initconst = { + "l4per_cm:clk:0128:24", + NULL, +}; + +static const struct omap_clkctrl_div_data dra7_mmc4_gfclk_div_data __initconst = { + .max_div = 4, + .flags = CLK_DIVIDER_POWER_OF_TWO, +}; + +static const struct omap_clkctrl_bit_data dra7_mmc4_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL }, + { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL }, + { 25, TI_CLK_DIVIDER, dra7_mmc4_gfclk_div_parents, &dra7_mmc4_gfclk_div_data }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_timer16_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const char * const dra7_qspi_gfclk_mux_parents[] __initconst = { + "func_128m_clk", + "dpll_per_h13x2_ck", + NULL, +}; + +static const char * const dra7_qspi_gfclk_div_parents[] __initconst = { + "l4per_cm:clk:0138:24", + NULL, +}; + +static const struct omap_clkctrl_div_data dra7_qspi_gfclk_div_data __initconst = { + .max_div = 4, + .flags = CLK_DIVIDER_POWER_OF_TWO, +}; + +static const struct omap_clkctrl_bit_data dra7_qspi_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_qspi_gfclk_mux_parents, NULL }, + { 25, TI_CLK_DIVIDER, dra7_qspi_gfclk_div_parents, &dra7_qspi_gfclk_div_data }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_uart1_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_uart2_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_uart3_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_uart4_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_mcasp2_bit_data[] __initconst = { + { 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL }, + { 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL }, + { 28, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_mcasp3_bit_data[] __initconst = { + { 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL }, + { 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_uart5_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_mcasp5_bit_data[] __initconst = { + { 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL }, + { 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_mcasp8_bit_data[] __initconst = { + { 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL }, + { 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_mcasp4_bit_data[] __initconst = { + { 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL }, + { 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_uart7_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_uart8_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_uart9_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_mcasp6_bit_data[] __initconst = { + { 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL }, + { 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_mcasp7_bit_data[] __initconst = { + { 22, TI_CLK_MUX, dra7_mcasp1_aux_gfclk_mux_parents, NULL }, + { 24, TI_CLK_MUX, dra7_mcasp1_ahclkx_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data dra7_l4per_clkctrl_regs[] __initconst = { + { DRA7_L4_PER2_CLKCTRL, NULL, 0, "l3_iclk_div", "l4per2_clkdm" }, + { DRA7_L4_PER3_CLKCTRL, NULL, 0, "l3_iclk_div", "l4per3_clkdm" }, + { DRA7_TIMER10_CLKCTRL, dra7_timer10_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0028:24" }, + { DRA7_TIMER11_CLKCTRL, dra7_timer11_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0030:24" }, + { DRA7_TIMER2_CLKCTRL, dra7_timer2_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0038:24" }, + { DRA7_TIMER3_CLKCTRL, dra7_timer3_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0040:24" }, + { DRA7_TIMER4_CLKCTRL, dra7_timer4_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0048:24" }, + { DRA7_TIMER9_CLKCTRL, dra7_timer9_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0050:24" }, + { DRA7_ELM_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_GPIO2_CLKCTRL, dra7_gpio2_bit_data, CLKF_HW_SUP, "l3_iclk_div" }, + { DRA7_GPIO3_CLKCTRL, dra7_gpio3_bit_data, CLKF_HW_SUP, "l3_iclk_div" }, + { DRA7_GPIO4_CLKCTRL, dra7_gpio4_bit_data, CLKF_HW_SUP, "l3_iclk_div" }, + { DRA7_GPIO5_CLKCTRL, dra7_gpio5_bit_data, CLKF_HW_SUP, "l3_iclk_div" }, + { DRA7_GPIO6_CLKCTRL, dra7_gpio6_bit_data, CLKF_HW_SUP, "l3_iclk_div" }, + { DRA7_HDQ1W_CLKCTRL, NULL, CLKF_SW_SUP, "func_12m_fclk" }, + { DRA7_EPWMSS1_CLKCTRL, NULL, CLKF_SW_SUP, "l4_root_clk_div", "l4per2_clkdm" }, + { DRA7_EPWMSS2_CLKCTRL, NULL, CLKF_SW_SUP, "l4_root_clk_div", "l4per2_clkdm" }, + { DRA7_I2C1_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" }, + { DRA7_I2C2_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" }, + { DRA7_I2C3_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" }, + { DRA7_I2C4_CLKCTRL, NULL, CLKF_SW_SUP, "func_96m_fclk" }, + { DRA7_L4_PER1_CLKCTRL, NULL, 0, "l3_iclk_div" }, + { DRA7_EPWMSS0_CLKCTRL, NULL, CLKF_SW_SUP, "l4_root_clk_div", "l4per2_clkdm" }, + { DRA7_TIMER13_CLKCTRL, dra7_timer13_bit_data, CLKF_SW_SUP, "l4per_cm:clk:00c8:24", "l4per3_clkdm" }, + { DRA7_TIMER14_CLKCTRL, dra7_timer14_bit_data, CLKF_SW_SUP, "l4per_cm:clk:00d0:24", "l4per3_clkdm" }, + { DRA7_TIMER15_CLKCTRL, dra7_timer15_bit_data, CLKF_SW_SUP, "l4per_cm:clk:00d8:24", "l4per3_clkdm" }, + { DRA7_MCSPI1_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, + { DRA7_MCSPI2_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, + { DRA7_MCSPI3_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, + { DRA7_MCSPI4_CLKCTRL, NULL, CLKF_SW_SUP, "func_48m_fclk" }, + { DRA7_GPIO7_CLKCTRL, dra7_gpio7_bit_data, CLKF_HW_SUP, "l3_iclk_div" }, + { DRA7_GPIO8_CLKCTRL, dra7_gpio8_bit_data, CLKF_HW_SUP, "l3_iclk_div" }, + { DRA7_MMC3_CLKCTRL, dra7_mmc3_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0120:25" }, + { DRA7_MMC4_CLKCTRL, dra7_mmc4_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0128:25" }, + { DRA7_TIMER16_CLKCTRL, dra7_timer16_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0130:24", "l4per3_clkdm" }, + { DRA7_QSPI_CLKCTRL, dra7_qspi_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0138:25", "l4per2_clkdm" }, + { DRA7_UART1_CLKCTRL, dra7_uart1_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0140:24" }, + { DRA7_UART2_CLKCTRL, dra7_uart2_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0148:24" }, + { DRA7_UART3_CLKCTRL, dra7_uart3_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0150:24" }, + { DRA7_UART4_CLKCTRL, dra7_uart4_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0158:24" }, + { DRA7_MCASP2_CLKCTRL, dra7_mcasp2_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0160:22", "l4per2_clkdm" }, + { DRA7_MCASP3_CLKCTRL, dra7_mcasp3_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0168:22", "l4per2_clkdm" }, + { DRA7_UART5_CLKCTRL, dra7_uart5_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0170:24" }, + { DRA7_MCASP5_CLKCTRL, dra7_mcasp5_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0178:22", "l4per2_clkdm" }, + { DRA7_MCASP8_CLKCTRL, dra7_mcasp8_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0190:24", "l4per2_clkdm" }, + { DRA7_MCASP4_CLKCTRL, dra7_mcasp4_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0198:22", "l4per2_clkdm" }, + { DRA7_AES1_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" }, + { DRA7_AES2_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" }, + { DRA7_DES_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" }, + { DRA7_RNG_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" }, + { DRA7_SHAM_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div", "l4sec_clkdm" }, + { DRA7_UART7_CLKCTRL, dra7_uart7_bit_data, CLKF_SW_SUP, "l4per_cm:clk:01d0:24", "l4per2_clkdm" }, + { DRA7_UART8_CLKCTRL, dra7_uart8_bit_data, CLKF_SW_SUP, "l4per_cm:clk:01e0:24", "l4per2_clkdm" }, + { DRA7_UART9_CLKCTRL, dra7_uart9_bit_data, CLKF_SW_SUP, "l4per_cm:clk:01e8:24", "l4per2_clkdm" }, + { DRA7_DCAN2_CLKCTRL, NULL, CLKF_SW_SUP, "sys_clkin1", "l4per2_clkdm" }, + { DRA7_MCASP6_CLKCTRL, dra7_mcasp6_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0204:22", "l4per2_clkdm" }, + { DRA7_MCASP7_CLKCTRL, dra7_mcasp7_bit_data, CLKF_SW_SUP, "l4per_cm:clk:0208:22", "l4per2_clkdm" }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_gpio1_bit_data[] __initconst = { + { 8, TI_CLK_GATE, dra7_dss_32khz_clk_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_timer1_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_timer10_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_bit_data dra7_uart10_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_uart6_gfclk_mux_parents, NULL }, + { 0 }, +}; + +static const char * const dra7_dcan1_sys_clk_mux_parents[] __initconst = { + "sys_clkin1", + "sys_clkin2", + NULL, +}; + +static const struct omap_clkctrl_bit_data dra7_dcan1_bit_data[] __initconst = { + { 24, TI_CLK_MUX, dra7_dcan1_sys_clk_mux_parents, NULL }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data dra7_wkupaon_clkctrl_regs[] __initconst = { + { DRA7_L4_WKUP_CLKCTRL, NULL, 0, "wkupaon_iclk_mux" }, + { DRA7_WD_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "sys_32k_ck" }, + { DRA7_GPIO1_CLKCTRL, dra7_gpio1_bit_data, CLKF_HW_SUP, "wkupaon_iclk_mux" }, + { DRA7_TIMER1_CLKCTRL, dra7_timer1_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0020:24" }, + { DRA7_TIMER12_CLKCTRL, NULL, 0, "secure_32k_clk_src_ck" }, + { DRA7_COUNTER_32K_CLKCTRL, NULL, 0, "wkupaon_iclk_mux" }, + { DRA7_UART10_CLKCTRL, dra7_uart10_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0060:24" }, + { DRA7_DCAN1_CLKCTRL, dra7_dcan1_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0068:24" }, + { 0 }, +}; + +const struct omap_clkctrl_data dra7_clkctrl_data[] __initconst = { + { 0x4a005320, dra7_mpu_clkctrl_regs }, + { 0x4a005540, dra7_ipu_clkctrl_regs }, + { 0x4a005740, dra7_rtc_clkctrl_regs }, + { 0x4a008620, dra7_coreaon_clkctrl_regs }, + { 0x4a008720, dra7_l3main1_clkctrl_regs }, + { 0x4a008a20, dra7_dma_clkctrl_regs }, + { 0x4a008b20, dra7_emif_clkctrl_regs }, + { 0x4a008c00, dra7_atl_clkctrl_regs }, + { 0x4a008d20, dra7_l4cfg_clkctrl_regs }, + { 0x4a008e20, dra7_l3instr_clkctrl_regs }, + { 0x4a009120, dra7_dss_clkctrl_regs }, + { 0x4a009320, dra7_l3init_clkctrl_regs }, + { 0x4a009700, dra7_l4per_clkctrl_regs }, + { 0x4ae07820, dra7_wkupaon_clkctrl_regs }, + { 0 }, +}; + static struct ti_dt_clk dra7xx_clks[] = { - DT_CLK(NULL, "atl_clkin0_ck", "atl_clkin0_ck"), - DT_CLK(NULL, "atl_clkin1_ck", "atl_clkin1_ck"), - DT_CLK(NULL, "atl_clkin2_ck", "atl_clkin2_ck"), - DT_CLK(NULL, "atl_clkin3_ck", "atl_clkin3_ck"), - DT_CLK(NULL, "hdmi_clkin_ck", "hdmi_clkin_ck"), - DT_CLK(NULL, "mlb_clkin_ck", "mlb_clkin_ck"), - DT_CLK(NULL, "mlbp_clkin_ck", "mlbp_clkin_ck"), - DT_CLK(NULL, "pciesref_acs_clk_ck", "pciesref_acs_clk_ck"), - DT_CLK(NULL, "ref_clkin0_ck", "ref_clkin0_ck"), - DT_CLK(NULL, "ref_clkin1_ck", "ref_clkin1_ck"), - DT_CLK(NULL, "ref_clkin2_ck", "ref_clkin2_ck"), - DT_CLK(NULL, "ref_clkin3_ck", "ref_clkin3_ck"), - DT_CLK(NULL, "rmii_clk_ck", "rmii_clk_ck"), - DT_CLK(NULL, "sdvenc_clkin_ck", "sdvenc_clkin_ck"), - DT_CLK(NULL, "secure_32k_clk_src_ck", "secure_32k_clk_src_ck"), - DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"), - DT_CLK(NULL, "virt_12000000_ck", "virt_12000000_ck"), - DT_CLK(NULL, "virt_13000000_ck", "virt_13000000_ck"), - DT_CLK(NULL, "virt_16800000_ck", "virt_16800000_ck"), - DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), - DT_CLK(NULL, "virt_20000000_ck", "virt_20000000_ck"), - DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), - DT_CLK(NULL, "virt_27000000_ck", "virt_27000000_ck"), - DT_CLK(NULL, "virt_38400000_ck", "virt_38400000_ck"), - DT_CLK(NULL, "sys_clkin1", "sys_clkin1"), - DT_CLK(NULL, "sys_clkin2", "sys_clkin2"), - DT_CLK(NULL, "usb_otg_clkin_ck", "usb_otg_clkin_ck"), - DT_CLK(NULL, "video1_clkin_ck", "video1_clkin_ck"), - DT_CLK(NULL, "video1_m2_clkin_ck", "video1_m2_clkin_ck"), - DT_CLK(NULL, "video2_clkin_ck", "video2_clkin_ck"), - DT_CLK(NULL, "video2_m2_clkin_ck", "video2_m2_clkin_ck"), - DT_CLK(NULL, "abe_dpll_sys_clk_mux", "abe_dpll_sys_clk_mux"), - DT_CLK(NULL, "abe_dpll_bypass_clk_mux", "abe_dpll_bypass_clk_mux"), - DT_CLK(NULL, "abe_dpll_clk_mux", "abe_dpll_clk_mux"), - DT_CLK(NULL, "dpll_abe_ck", "dpll_abe_ck"), - DT_CLK(NULL, "dpll_abe_x2_ck", "dpll_abe_x2_ck"), - DT_CLK(NULL, "dpll_abe_m2x2_ck", "dpll_abe_m2x2_ck"), - DT_CLK(NULL, "abe_24m_fclk", "abe_24m_fclk"), - DT_CLK(NULL, "abe_clk", "abe_clk"), - DT_CLK(NULL, "aess_fclk", "aess_fclk"), - DT_CLK(NULL, "abe_giclk_div", "abe_giclk_div"), - DT_CLK(NULL, "abe_lp_clk_div", "abe_lp_clk_div"), - DT_CLK(NULL, "abe_sys_clk_div", "abe_sys_clk_div"), - DT_CLK(NULL, "adc_gfclk_mux", "adc_gfclk_mux"), - DT_CLK(NULL, "dpll_pcie_ref_ck", "dpll_pcie_ref_ck"), - DT_CLK(NULL, "dpll_pcie_ref_m2ldo_ck", "dpll_pcie_ref_m2ldo_ck"), - DT_CLK(NULL, "apll_pcie_ck", "apll_pcie_ck"), - DT_CLK(NULL, "apll_pcie_clkvcoldo", "apll_pcie_clkvcoldo"), - DT_CLK(NULL, "apll_pcie_clkvcoldo_div", "apll_pcie_clkvcoldo_div"), - DT_CLK(NULL, "apll_pcie_m2_ck", "apll_pcie_m2_ck"), - DT_CLK(NULL, "sys_clk1_dclk_div", "sys_clk1_dclk_div"), - DT_CLK(NULL, "sys_clk2_dclk_div", "sys_clk2_dclk_div"), - DT_CLK(NULL, "dpll_abe_m2_ck", "dpll_abe_m2_ck"), - DT_CLK(NULL, "per_abe_x1_dclk_div", "per_abe_x1_dclk_div"), - DT_CLK(NULL, "dpll_abe_m3x2_ck", "dpll_abe_m3x2_ck"), - DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), - DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), - DT_CLK(NULL, "dpll_core_h12x2_ck", "dpll_core_h12x2_ck"), - DT_CLK(NULL, "mpu_dpll_hs_clk_div", "mpu_dpll_hs_clk_div"), - DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), - DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), - DT_CLK(NULL, "mpu_dclk_div", "mpu_dclk_div"), - DT_CLK(NULL, "dsp_dpll_hs_clk_div", "dsp_dpll_hs_clk_div"), - DT_CLK(NULL, "dpll_dsp_ck", "dpll_dsp_ck"), - DT_CLK(NULL, "dpll_dsp_m2_ck", "dpll_dsp_m2_ck"), - DT_CLK(NULL, "dsp_gclk_div", "dsp_gclk_div"), - DT_CLK(NULL, "iva_dpll_hs_clk_div", "iva_dpll_hs_clk_div"), - DT_CLK(NULL, "dpll_iva_ck", "dpll_iva_ck"), - DT_CLK(NULL, "dpll_iva_m2_ck", "dpll_iva_m2_ck"), - DT_CLK(NULL, "iva_dclk", "iva_dclk"), - DT_CLK(NULL, "dpll_gpu_ck", "dpll_gpu_ck"), - DT_CLK(NULL, "dpll_gpu_m2_ck", "dpll_gpu_m2_ck"), - DT_CLK(NULL, "gpu_dclk", "gpu_dclk"), - DT_CLK(NULL, "dpll_core_m2_ck", "dpll_core_m2_ck"), - DT_CLK(NULL, "core_dpll_out_dclk_div", "core_dpll_out_dclk_div"), - DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"), - DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"), - DT_CLK(NULL, "emif_phy_dclk_div", "emif_phy_dclk_div"), - DT_CLK(NULL, "dpll_gmac_ck", "dpll_gmac_ck"), - DT_CLK(NULL, "dpll_gmac_m2_ck", "dpll_gmac_m2_ck"), - DT_CLK(NULL, "gmac_250m_dclk_div", "gmac_250m_dclk_div"), - DT_CLK(NULL, "video2_dclk_div", "video2_dclk_div"), - DT_CLK(NULL, "video1_dclk_div", "video1_dclk_div"), - DT_CLK(NULL, "hdmi_dclk_div", "hdmi_dclk_div"), - DT_CLK(NULL, "per_dpll_hs_clk_div", "per_dpll_hs_clk_div"), - DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), - DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), - DT_CLK(NULL, "func_96m_aon_dclk_div", "func_96m_aon_dclk_div"), - DT_CLK(NULL, "usb_dpll_hs_clk_div", "usb_dpll_hs_clk_div"), - DT_CLK(NULL, "dpll_usb_ck", "dpll_usb_ck"), - DT_CLK(NULL, "dpll_usb_m2_ck", "dpll_usb_m2_ck"), - DT_CLK(NULL, "l3init_480m_dclk_div", "l3init_480m_dclk_div"), - DT_CLK(NULL, "usb_otg_dclk_div", "usb_otg_dclk_div"), - DT_CLK(NULL, "sata_dclk_div", "sata_dclk_div"), - DT_CLK(NULL, "dpll_pcie_ref_m2_ck", "dpll_pcie_ref_m2_ck"), - DT_CLK(NULL, "pcie2_dclk_div", "pcie2_dclk_div"), - DT_CLK(NULL, "pcie_dclk_div", "pcie_dclk_div"), - DT_CLK(NULL, "emu_dclk_div", "emu_dclk_div"), - DT_CLK(NULL, "secure_32k_dclk_div", "secure_32k_dclk_div"), - DT_CLK(NULL, "eve_dpll_hs_clk_div", "eve_dpll_hs_clk_div"), - DT_CLK(NULL, "dpll_eve_ck", "dpll_eve_ck"), - DT_CLK(NULL, "dpll_eve_m2_ck", "dpll_eve_m2_ck"), - DT_CLK(NULL, "eve_dclk_div", "eve_dclk_div"), - DT_CLK(NULL, "clkoutmux0_clk_mux", "clkoutmux0_clk_mux"), - DT_CLK(NULL, "clkoutmux1_clk_mux", "clkoutmux1_clk_mux"), - DT_CLK(NULL, "clkoutmux2_clk_mux", "clkoutmux2_clk_mux"), - DT_CLK(NULL, "custefuse_sys_gfclk_div", "custefuse_sys_gfclk_div"), - DT_CLK(NULL, "dpll_core_h13x2_ck", "dpll_core_h13x2_ck"), - DT_CLK(NULL, "dpll_core_h14x2_ck", "dpll_core_h14x2_ck"), - DT_CLK(NULL, "dpll_core_h22x2_ck", "dpll_core_h22x2_ck"), - DT_CLK(NULL, "dpll_core_h23x2_ck", "dpll_core_h23x2_ck"), - DT_CLK(NULL, "dpll_core_h24x2_ck", "dpll_core_h24x2_ck"), - DT_CLK(NULL, "dpll_ddr_x2_ck", "dpll_ddr_x2_ck"), - DT_CLK(NULL, "dpll_ddr_h11x2_ck", "dpll_ddr_h11x2_ck"), - DT_CLK(NULL, "dpll_dsp_x2_ck", "dpll_dsp_x2_ck"), - DT_CLK(NULL, "dpll_dsp_m3x2_ck", "dpll_dsp_m3x2_ck"), - DT_CLK(NULL, "dpll_gmac_x2_ck", "dpll_gmac_x2_ck"), - DT_CLK(NULL, "dpll_gmac_h11x2_ck", "dpll_gmac_h11x2_ck"), - DT_CLK(NULL, "dpll_gmac_h12x2_ck", "dpll_gmac_h12x2_ck"), - DT_CLK(NULL, "dpll_gmac_h13x2_ck", "dpll_gmac_h13x2_ck"), - DT_CLK(NULL, "dpll_gmac_m3x2_ck", "dpll_gmac_m3x2_ck"), - DT_CLK(NULL, "dpll_per_x2_ck", "dpll_per_x2_ck"), - DT_CLK(NULL, "dpll_per_h11x2_ck", "dpll_per_h11x2_ck"), - DT_CLK(NULL, "dpll_per_h12x2_ck", "dpll_per_h12x2_ck"), - DT_CLK(NULL, "dpll_per_h13x2_ck", "dpll_per_h13x2_ck"), - DT_CLK(NULL, "dpll_per_h14x2_ck", "dpll_per_h14x2_ck"), - DT_CLK(NULL, "dpll_per_m2x2_ck", "dpll_per_m2x2_ck"), - DT_CLK(NULL, "dpll_usb_clkdcoldo", "dpll_usb_clkdcoldo"), - DT_CLK(NULL, "eve_clk", "eve_clk"), - DT_CLK(NULL, "func_128m_clk", "func_128m_clk"), - DT_CLK(NULL, "func_12m_fclk", "func_12m_fclk"), - DT_CLK(NULL, "func_24m_clk", "func_24m_clk"), - DT_CLK(NULL, "func_48m_fclk", "func_48m_fclk"), - DT_CLK(NULL, "func_96m_fclk", "func_96m_fclk"), - DT_CLK(NULL, "gmii_m_clk_div", "gmii_m_clk_div"), - DT_CLK(NULL, "hdmi_clk2_div", "hdmi_clk2_div"), - DT_CLK(NULL, "hdmi_div_clk", "hdmi_div_clk"), - DT_CLK(NULL, "hdmi_dpll_clk_mux", "hdmi_dpll_clk_mux"), - DT_CLK(NULL, "l3_iclk_div", "l3_iclk_div"), - DT_CLK(NULL, "l3init_60m_fclk", "l3init_60m_fclk"), - DT_CLK(NULL, "l4_root_clk_div", "l4_root_clk_div"), - DT_CLK(NULL, "mlb_clk", "mlb_clk"), - DT_CLK(NULL, "mlbp_clk", "mlbp_clk"), - DT_CLK(NULL, "per_abe_x1_gfclk2_div", "per_abe_x1_gfclk2_div"), - DT_CLK(NULL, "timer_sys_clk_div", "timer_sys_clk_div"), - DT_CLK(NULL, "video1_clk2_div", "video1_clk2_div"), - DT_CLK(NULL, "video1_div_clk", "video1_div_clk"), - DT_CLK(NULL, "video1_dpll_clk_mux", "video1_dpll_clk_mux"), - DT_CLK(NULL, "video2_clk2_div", "video2_clk2_div"), - DT_CLK(NULL, "video2_div_clk", "video2_div_clk"), - DT_CLK(NULL, "video2_dpll_clk_mux", "video2_dpll_clk_mux"), - DT_CLK(NULL, "wkupaon_iclk_mux", "wkupaon_iclk_mux"), - DT_CLK(NULL, "dss_32khz_clk", "dss_32khz_clk"), - DT_CLK(NULL, "dss_48mhz_clk", "dss_48mhz_clk"), - DT_CLK(NULL, "dss_dss_clk", "dss_dss_clk"), - DT_CLK(NULL, "dss_hdmi_clk", "dss_hdmi_clk"), - DT_CLK(NULL, "dss_video1_clk", "dss_video1_clk"), - DT_CLK(NULL, "dss_video2_clk", "dss_video2_clk"), - DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), - DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), - DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), - DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"), - DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"), - DT_CLK(NULL, "gpio6_dbclk", "gpio6_dbclk"), - DT_CLK(NULL, "gpio7_dbclk", "gpio7_dbclk"), - DT_CLK(NULL, "gpio8_dbclk", "gpio8_dbclk"), - DT_CLK(NULL, "mmc1_clk32k", "mmc1_clk32k"), - DT_CLK(NULL, "mmc2_clk32k", "mmc2_clk32k"), - DT_CLK(NULL, "mmc3_clk32k", "mmc3_clk32k"), - DT_CLK(NULL, "mmc4_clk32k", "mmc4_clk32k"), - DT_CLK(NULL, "sata_ref_clk", "sata_ref_clk"), - DT_CLK(NULL, "usb_otg_ss1_refclk960m", "usb_otg_ss1_refclk960m"), - DT_CLK(NULL, "usb_otg_ss2_refclk960m", "usb_otg_ss2_refclk960m"), - DT_CLK(NULL, "usb_phy1_always_on_clk32k", "usb_phy1_always_on_clk32k"), - DT_CLK(NULL, "usb_phy2_always_on_clk32k", "usb_phy2_always_on_clk32k"), - DT_CLK(NULL, "usb_phy3_always_on_clk32k", "usb_phy3_always_on_clk32k"), - DT_CLK(NULL, "atl_dpll_clk_mux", "atl_dpll_clk_mux"), - DT_CLK(NULL, "atl_gfclk_mux", "atl_gfclk_mux"), - DT_CLK(NULL, "dcan1_sys_clk_mux", "dcan1_sys_clk_mux"), - DT_CLK(NULL, "gmac_rft_clk_mux", "gmac_rft_clk_mux"), - DT_CLK(NULL, "gpu_core_gclk_mux", "gpu_core_gclk_mux"), - DT_CLK(NULL, "gpu_hyd_gclk_mux", "gpu_hyd_gclk_mux"), - DT_CLK(NULL, "ipu1_gfclk_mux", "ipu1_gfclk_mux"), - DT_CLK(NULL, "l3instr_ts_gclk_div", "l3instr_ts_gclk_div"), - DT_CLK(NULL, "mcasp1_ahclkr_mux", "mcasp1_ahclkr_mux"), - DT_CLK(NULL, "mcasp1_ahclkx_mux", "mcasp1_ahclkx_mux"), - DT_CLK(NULL, "mcasp1_aux_gfclk_mux", "mcasp1_aux_gfclk_mux"), - DT_CLK(NULL, "mcasp2_ahclkr_mux", "mcasp2_ahclkr_mux"), - DT_CLK(NULL, "mcasp2_ahclkx_mux", "mcasp2_ahclkx_mux"), - DT_CLK(NULL, "mcasp2_aux_gfclk_mux", "mcasp2_aux_gfclk_mux"), - DT_CLK(NULL, "mcasp3_ahclkx_mux", "mcasp3_ahclkx_mux"), - DT_CLK(NULL, "mcasp3_aux_gfclk_mux", "mcasp3_aux_gfclk_mux"), - DT_CLK(NULL, "mcasp4_ahclkx_mux", "mcasp4_ahclkx_mux"), - DT_CLK(NULL, "mcasp4_aux_gfclk_mux", "mcasp4_aux_gfclk_mux"), - DT_CLK(NULL, "mcasp5_ahclkx_mux", "mcasp5_ahclkx_mux"), - DT_CLK(NULL, "mcasp5_aux_gfclk_mux", "mcasp5_aux_gfclk_mux"), - DT_CLK(NULL, "mcasp6_ahclkx_mux", "mcasp6_ahclkx_mux"), - DT_CLK(NULL, "mcasp6_aux_gfclk_mux", "mcasp6_aux_gfclk_mux"), - DT_CLK(NULL, "mcasp7_ahclkx_mux", "mcasp7_ahclkx_mux"), - DT_CLK(NULL, "mcasp7_aux_gfclk_mux", "mcasp7_aux_gfclk_mux"), - DT_CLK(NULL, "mcasp8_ahclkx_mux", "mcasp8_ahclkx_mux"), - DT_CLK(NULL, "mcasp8_aux_gfclk_mux", "mcasp8_aux_gfclk_mux"), - DT_CLK(NULL, "mmc1_fclk_mux", "mmc1_fclk_mux"), - DT_CLK(NULL, "mmc1_fclk_div", "mmc1_fclk_div"), - DT_CLK(NULL, "mmc2_fclk_mux", "mmc2_fclk_mux"), - DT_CLK(NULL, "mmc2_fclk_div", "mmc2_fclk_div"), - DT_CLK(NULL, "mmc3_gfclk_mux", "mmc3_gfclk_mux"), - DT_CLK(NULL, "mmc3_gfclk_div", "mmc3_gfclk_div"), - DT_CLK(NULL, "mmc4_gfclk_mux", "mmc4_gfclk_mux"), - DT_CLK(NULL, "mmc4_gfclk_div", "mmc4_gfclk_div"), - DT_CLK(NULL, "qspi_gfclk_mux", "qspi_gfclk_mux"), - DT_CLK(NULL, "qspi_gfclk_div", "qspi_gfclk_div"), - DT_CLK(NULL, "timer10_gfclk_mux", "timer10_gfclk_mux"), - DT_CLK(NULL, "timer11_gfclk_mux", "timer11_gfclk_mux"), - DT_CLK(NULL, "timer13_gfclk_mux", "timer13_gfclk_mux"), - DT_CLK(NULL, "timer14_gfclk_mux", "timer14_gfclk_mux"), - DT_CLK(NULL, "timer15_gfclk_mux", "timer15_gfclk_mux"), - DT_CLK(NULL, "timer16_gfclk_mux", "timer16_gfclk_mux"), - DT_CLK(NULL, "timer1_gfclk_mux", "timer1_gfclk_mux"), - DT_CLK(NULL, "timer2_gfclk_mux", "timer2_gfclk_mux"), - DT_CLK(NULL, "timer3_gfclk_mux", "timer3_gfclk_mux"), - DT_CLK(NULL, "timer4_gfclk_mux", "timer4_gfclk_mux"), - DT_CLK(NULL, "timer5_gfclk_mux", "timer5_gfclk_mux"), - DT_CLK(NULL, "timer6_gfclk_mux", "timer6_gfclk_mux"), - DT_CLK(NULL, "timer7_gfclk_mux", "timer7_gfclk_mux"), - DT_CLK(NULL, "timer8_gfclk_mux", "timer8_gfclk_mux"), - DT_CLK(NULL, "timer9_gfclk_mux", "timer9_gfclk_mux"), - DT_CLK(NULL, "uart10_gfclk_mux", "uart10_gfclk_mux"), - DT_CLK(NULL, "uart1_gfclk_mux", "uart1_gfclk_mux"), - DT_CLK(NULL, "uart2_gfclk_mux", "uart2_gfclk_mux"), - DT_CLK(NULL, "uart3_gfclk_mux", "uart3_gfclk_mux"), - DT_CLK(NULL, "uart4_gfclk_mux", "uart4_gfclk_mux"), - DT_CLK(NULL, "uart5_gfclk_mux", "uart5_gfclk_mux"), - DT_CLK(NULL, "uart6_gfclk_mux", "uart6_gfclk_mux"), - DT_CLK(NULL, "uart7_gfclk_mux", "uart7_gfclk_mux"), - DT_CLK(NULL, "uart8_gfclk_mux", "uart8_gfclk_mux"), - DT_CLK(NULL, "uart9_gfclk_mux", "uart9_gfclk_mux"), - DT_CLK(NULL, "vip1_gclk_mux", "vip1_gclk_mux"), - DT_CLK(NULL, "vip2_gclk_mux", "vip2_gclk_mux"), - DT_CLK(NULL, "vip3_gclk_mux", "vip3_gclk_mux"), - DT_CLK("omap_i2c.1", "ick", "dummy_ck"), - DT_CLK("omap_i2c.2", "ick", "dummy_ck"), - DT_CLK("omap_i2c.3", "ick", "dummy_ck"), - DT_CLK("omap_i2c.4", "ick", "dummy_ck"), - DT_CLK(NULL, "mailboxes_ick", "dummy_ck"), - DT_CLK("omap_hsmmc.0", "ick", "dummy_ck"), - DT_CLK("omap_hsmmc.1", "ick", "dummy_ck"), - DT_CLK("omap_hsmmc.2", "ick", "dummy_ck"), - DT_CLK("omap_hsmmc.3", "ick", "dummy_ck"), - DT_CLK("omap_hsmmc.4", "ick", "dummy_ck"), - DT_CLK("omap-mcbsp.1", "ick", "dummy_ck"), - DT_CLK("omap-mcbsp.2", "ick", "dummy_ck"), - DT_CLK("omap-mcbsp.3", "ick", "dummy_ck"), - DT_CLK("omap-mcbsp.4", "ick", "dummy_ck"), - DT_CLK("omap2_mcspi.1", "ick", "dummy_ck"), - DT_CLK("omap2_mcspi.2", "ick", "dummy_ck"), - DT_CLK("omap2_mcspi.3", "ick", "dummy_ck"), - DT_CLK("omap2_mcspi.4", "ick", "dummy_ck"), - DT_CLK(NULL, "uart1_ick", "dummy_ck"), - DT_CLK(NULL, "uart2_ick", "dummy_ck"), - DT_CLK(NULL, "uart3_ick", "dummy_ck"), - DT_CLK(NULL, "uart4_ick", "dummy_ck"), - DT_CLK("usbhs_omap", "usbhost_ick", "dummy_ck"), - DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"), - DT_CLK("omap_wdt", "ick", "dummy_ck"), DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"), DT_CLK(NULL, "sys_clkin_ck", "timer_sys_clk_div"), - DT_CLK("4ae18000.timer", "timer_sys_ck", "timer_sys_clk_div"), - DT_CLK("48032000.timer", "timer_sys_ck", "timer_sys_clk_div"), - DT_CLK("48034000.timer", "timer_sys_ck", "timer_sys_clk_div"), - DT_CLK("48036000.timer", "timer_sys_ck", "timer_sys_clk_div"), - DT_CLK("4803e000.timer", "timer_sys_ck", "timer_sys_clk_div"), - DT_CLK("48086000.timer", "timer_sys_ck", "timer_sys_clk_div"), - DT_CLK("48088000.timer", "timer_sys_ck", "timer_sys_clk_div"), - DT_CLK("48820000.timer", "timer_sys_ck", "timer_sys_clk_div"), - DT_CLK("48822000.timer", "timer_sys_ck", "timer_sys_clk_div"), - DT_CLK("48824000.timer", "timer_sys_ck", "timer_sys_clk_div"), - DT_CLK("48826000.timer", "timer_sys_ck", "timer_sys_clk_div"), - DT_CLK("48828000.timer", "timer_sys_ck", "timer_sys_clk_div"), - DT_CLK("4882a000.timer", "timer_sys_ck", "timer_sys_clk_div"), - DT_CLK("4882c000.timer", "timer_sys_ck", "timer_sys_clk_div"), - DT_CLK("4882e000.timer", "timer_sys_ck", "timer_sys_clk_div"), DT_CLK(NULL, "sys_clkin", "sys_clkin1"), - DT_CLK(NULL, "dss_deshdcp_clk", "dss_deshdcp_clk"), + DT_CLK(NULL, "atl_dpll_clk_mux", "atl_cm:0000:24"), + DT_CLK(NULL, "atl_gfclk_mux", "atl_cm:0000:26"), + DT_CLK(NULL, "dcan1_sys_clk_mux", "wkupaon_cm:0068:24"), + DT_CLK(NULL, "dss_32khz_clk", "dss_cm:0000:11"), + DT_CLK(NULL, "dss_48mhz_clk", "dss_cm:0000:9"), + DT_CLK(NULL, "dss_dss_clk", "dss_cm:0000:8"), + DT_CLK(NULL, "dss_hdmi_clk", "dss_cm:0000:10"), + DT_CLK(NULL, "dss_video1_clk", "dss_cm:0000:12"), + DT_CLK(NULL, "dss_video2_clk", "dss_cm:0000:13"), + DT_CLK(NULL, "gmac_rft_clk_mux", "l3init_cm:00b0:25"), + DT_CLK(NULL, "gpio1_dbclk", "wkupaon_cm:0018:8"), + DT_CLK(NULL, "gpio2_dbclk", "l4per_cm:0060:8"), + DT_CLK(NULL, "gpio3_dbclk", "l4per_cm:0068:8"), + DT_CLK(NULL, "gpio4_dbclk", "l4per_cm:0070:8"), + DT_CLK(NULL, "gpio5_dbclk", "l4per_cm:0078:8"), + DT_CLK(NULL, "gpio6_dbclk", "l4per_cm:0080:8"), + DT_CLK(NULL, "gpio7_dbclk", "l4per_cm:0110:8"), + DT_CLK(NULL, "gpio8_dbclk", "l4per_cm:0118:8"), + DT_CLK(NULL, "mcasp1_ahclkr_mux", "ipu_cm:0010:28"), + DT_CLK(NULL, "mcasp1_ahclkx_mux", "ipu_cm:0010:24"), + DT_CLK(NULL, "mcasp1_aux_gfclk_mux", "ipu_cm:0010:22"), + DT_CLK(NULL, "mcasp2_ahclkr_mux", "l4per_cm:0160:28"), + DT_CLK(NULL, "mcasp2_ahclkx_mux", "l4per_cm:0160:24"), + DT_CLK(NULL, "mcasp2_aux_gfclk_mux", "l4per_cm:0160:22"), + DT_CLK(NULL, "mcasp3_ahclkx_mux", "l4per_cm:0168:24"), + DT_CLK(NULL, "mcasp3_aux_gfclk_mux", "l4per_cm:0168:22"), + DT_CLK(NULL, "mcasp4_ahclkx_mux", "l4per_cm:0198:24"), + DT_CLK(NULL, "mcasp4_aux_gfclk_mux", "l4per_cm:0198:22"), + DT_CLK(NULL, "mcasp5_ahclkx_mux", "l4per_cm:0178:24"), + DT_CLK(NULL, "mcasp5_aux_gfclk_mux", "l4per_cm:0178:22"), + DT_CLK(NULL, "mcasp6_ahclkx_mux", "l4per_cm:0204:24"), + DT_CLK(NULL, "mcasp6_aux_gfclk_mux", "l4per_cm:0204:22"), + DT_CLK(NULL, "mcasp7_ahclkx_mux", "l4per_cm:0208:24"), + DT_CLK(NULL, "mcasp7_aux_gfclk_mux", "l4per_cm:0208:22"), + DT_CLK(NULL, "mcasp8_ahclkx_mux", "l4per_cm:0190:22"), + DT_CLK(NULL, "mcasp8_aux_gfclk_mux", "l4per_cm:0190:24"), + DT_CLK(NULL, "mmc1_clk32k", "l3init_cm:0008:8"), + DT_CLK(NULL, "mmc1_fclk_div", "l3init_cm:0008:25"), + DT_CLK(NULL, "mmc1_fclk_mux", "l3init_cm:0008:24"), + DT_CLK(NULL, "mmc2_clk32k", "l3init_cm:0010:8"), + DT_CLK(NULL, "mmc2_fclk_div", "l3init_cm:0010:25"), + DT_CLK(NULL, "mmc2_fclk_mux", "l3init_cm:0010:24"), + DT_CLK(NULL, "mmc3_clk32k", "l4per_cm:0120:8"), + DT_CLK(NULL, "mmc3_gfclk_div", "l4per_cm:0120:25"), + DT_CLK(NULL, "mmc3_gfclk_mux", "l4per_cm:0120:24"), + DT_CLK(NULL, "mmc4_clk32k", "l4per_cm:0128:8"), + DT_CLK(NULL, "mmc4_gfclk_div", "l4per_cm:0128:25"), + DT_CLK(NULL, "mmc4_gfclk_mux", "l4per_cm:0128:24"), + DT_CLK(NULL, "optfclk_pciephy1_32khz", "l3init_cm:0090:8"), + DT_CLK(NULL, "optfclk_pciephy1_clk", "l3init_cm:0090:9"), + DT_CLK(NULL, "optfclk_pciephy1_div_clk", "l3init_cm:0090:10"), + DT_CLK(NULL, "optfclk_pciephy2_32khz", "l3init_cm:0098:8"), + DT_CLK(NULL, "optfclk_pciephy2_clk", "l3init_cm:0098:9"), + DT_CLK(NULL, "optfclk_pciephy2_div_clk", "l3init_cm:0098:10"), + DT_CLK(NULL, "qspi_gfclk_div", "l4per_cm:0138:25"), + DT_CLK(NULL, "qspi_gfclk_mux", "l4per_cm:0138:24"), + DT_CLK(NULL, "rmii_50mhz_clk_mux", "l3init_cm:00b0:24"), + DT_CLK(NULL, "sata_ref_clk", "l3init_cm:0068:8"), + DT_CLK(NULL, "timer10_gfclk_mux", "l4per_cm:0028:24"), + DT_CLK(NULL, "timer11_gfclk_mux", "l4per_cm:0030:24"), + DT_CLK(NULL, "timer13_gfclk_mux", "l4per_cm:00c8:24"), + DT_CLK(NULL, "timer14_gfclk_mux", "l4per_cm:00d0:24"), + DT_CLK(NULL, "timer15_gfclk_mux", "l4per_cm:00d8:24"), + DT_CLK(NULL, "timer16_gfclk_mux", "l4per_cm:0130:24"), + DT_CLK(NULL, "timer1_gfclk_mux", "wkupaon_cm:0020:24"), + DT_CLK(NULL, "timer2_gfclk_mux", "l4per_cm:0038:24"), + DT_CLK(NULL, "timer3_gfclk_mux", "l4per_cm:0040:24"), + DT_CLK(NULL, "timer4_gfclk_mux", "l4per_cm:0048:24"), + DT_CLK(NULL, "timer5_gfclk_mux", "ipu_cm:0018:24"), + DT_CLK(NULL, "timer6_gfclk_mux", "ipu_cm:0020:24"), + DT_CLK(NULL, "timer7_gfclk_mux", "ipu_cm:0028:24"), + DT_CLK(NULL, "timer8_gfclk_mux", "ipu_cm:0030:24"), + DT_CLK(NULL, "timer9_gfclk_mux", "l4per_cm:0050:24"), + DT_CLK(NULL, "uart10_gfclk_mux", "wkupaon_cm:0060:24"), + DT_CLK(NULL, "uart1_gfclk_mux", "l4per_cm:0140:24"), + DT_CLK(NULL, "uart2_gfclk_mux", "l4per_cm:0148:24"), + DT_CLK(NULL, "uart3_gfclk_mux", "l4per_cm:0150:24"), + DT_CLK(NULL, "uart4_gfclk_mux", "l4per_cm:0158:24"), + DT_CLK(NULL, "uart5_gfclk_mux", "l4per_cm:0170:24"), + DT_CLK(NULL, "uart6_gfclk_mux", "ipu_cm:0040:24"), + DT_CLK(NULL, "uart7_gfclk_mux", "l4per_cm:01d0:24"), + DT_CLK(NULL, "uart8_gfclk_mux", "l4per_cm:01e0:24"), + DT_CLK(NULL, "uart9_gfclk_mux", "l4per_cm:01e8:24"), + DT_CLK(NULL, "usb_otg_ss1_refclk960m", "l3init_cm:00d0:8"), + DT_CLK(NULL, "usb_otg_ss2_refclk960m", "l3init_cm:0020:8"), { .node_name = NULL }, }; @@ -318,6 +830,8 @@ int __init dra7xx_dt_clk_init(void) omap2_clk_disable_autoidle_all(); + ti_clk_add_aliases(); + dpll_ck = clk_get_sys(NULL, "dpll_gmac_ck"); rc = clk_set_rate(dpll_ck, DRA7_DPLL_GMAC_DEFFREQ); if (rc) diff --git a/drivers/clk/ti/clk-814x.c b/drivers/clk/ti/clk-814x.c index 52c6efc53731..f688fdd2cb59 100644 --- a/drivers/clk/ti/clk-814x.c +++ b/drivers/clk/ti/clk-814x.c @@ -9,23 +9,48 @@ #include #include #include +#include #include "clock.h" +static const struct omap_clkctrl_reg_data dm814_default_clkctrl_regs[] __initconst = { + { DM814_USB_OTG_HS_CLKCTRL, NULL, CLKF_SW_SUP, "pll260dcoclkldo" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data dm814_alwon_clkctrl_regs[] __initconst = { + { DM814_UART1_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk10_ck" }, + { DM814_UART2_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk10_ck" }, + { DM814_UART3_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk10_ck" }, + { DM814_GPIO1_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk6_ck" }, + { DM814_GPIO2_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk6_ck" }, + { DM814_I2C1_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk10_ck" }, + { DM814_I2C2_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk10_ck" }, + { DM814_WD_TIMER_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_NO_IDLEST, "sysclk18_ck" }, + { DM814_MCSPI1_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk10_ck" }, + { DM814_GPMC_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk6_ck" }, + { DM814_CPGMAC0_CLKCTRL, NULL, CLKF_SW_SUP, "cpsw_125mhz_gclk" }, + { DM814_MPU_CLKCTRL, NULL, CLKF_SW_SUP, "mpu_ck" }, + { DM814_RTC_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_NO_IDLEST, "sysclk18_ck" }, + { DM814_TPCC_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk4_ck" }, + { DM814_TPTC0_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk4_ck" }, + { DM814_TPTC1_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk4_ck" }, + { DM814_TPTC2_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk4_ck" }, + { DM814_TPTC3_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk4_ck" }, + { DM814_MMC1_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk8_ck" }, + { DM814_MMC2_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk8_ck" }, + { DM814_MMC3_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk8_ck" }, + { 0 }, +}; + +const struct omap_clkctrl_data dm814_clkctrl_data[] __initconst = { + { 0x48180500, dm814_default_clkctrl_regs }, + { 0x48181400, dm814_alwon_clkctrl_regs }, + { 0 }, +}; + static struct ti_dt_clk dm814_clks[] = { - DT_CLK(NULL, "devosc_ck", "devosc_ck"), - DT_CLK(NULL, "mpu_ck", "mpu_ck"), - DT_CLK(NULL, "sysclk4_ck", "sysclk4_ck"), - DT_CLK(NULL, "sysclk5_ck", "sysclk5_ck"), - DT_CLK(NULL, "sysclk6_ck", "sysclk6_ck"), - DT_CLK(NULL, "sysclk8_ck", "sysclk8_ck"), - DT_CLK(NULL, "sysclk10_ck", "sysclk10_ck"), - DT_CLK(NULL, "sysclk18_ck", "sysclk18_ck"), DT_CLK(NULL, "timer_sys_ck", "devosc_ck"), - DT_CLK(NULL, "timer1_fck", "timer1_fck"), - DT_CLK(NULL, "timer2_fck", "timer2_fck"), - DT_CLK(NULL, "cpsw_125mhz_gclk", "cpsw_125mhz_gclk"), - DT_CLK(NULL, "cpsw_cpts_rft_clk", "cpsw_cpts_rft_clk"), { .node_name = NULL }, }; @@ -83,6 +108,7 @@ int __init dm814x_dt_clk_init(void) { ti_dt_clocks_register(dm814_clks); omap2_clk_disable_autoidle_all(); + ti_clk_add_aliases(); omap2_clk_enable_init_clocks(NULL, 0); timer_clocks_initialized = true; diff --git a/drivers/clk/ti/clk-816x.c b/drivers/clk/ti/clk-816x.c index 2a5d84fdddc5..7d215cdf9dda 100644 --- a/drivers/clk/ti/clk-816x.c +++ b/drivers/clk/ti/clk-816x.c @@ -13,30 +13,59 @@ #include #include #include +#include #include "clock.h" +static const struct omap_clkctrl_reg_data dm816_default_clkctrl_regs[] __initconst = { + { DM816_USB_OTG_HS_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk6_ck" }, + { 0 }, +}; + +static const struct omap_clkctrl_reg_data dm816_alwon_clkctrl_regs[] __initconst = { + { DM816_UART1_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk10_ck" }, + { DM816_UART2_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk10_ck" }, + { DM816_UART3_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk10_ck" }, + { DM816_GPIO1_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk6_ck" }, + { DM816_GPIO2_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk6_ck" }, + { DM816_I2C1_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk10_ck" }, + { DM816_I2C2_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk10_ck" }, + { DM816_TIMER1_CLKCTRL, NULL, CLKF_SW_SUP, "timer1_fck" }, + { DM816_TIMER2_CLKCTRL, NULL, CLKF_SW_SUP, "timer2_fck" }, + { DM816_TIMER3_CLKCTRL, NULL, CLKF_SW_SUP, "timer3_fck" }, + { DM816_TIMER4_CLKCTRL, NULL, CLKF_SW_SUP, "timer4_fck" }, + { DM816_TIMER5_CLKCTRL, NULL, CLKF_SW_SUP, "timer5_fck" }, + { DM816_TIMER6_CLKCTRL, NULL, CLKF_SW_SUP, "timer6_fck" }, + { DM816_TIMER7_CLKCTRL, NULL, CLKF_SW_SUP, "timer7_fck" }, + { DM816_WD_TIMER_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_NO_IDLEST, "sysclk18_ck" }, + { DM816_MCSPI1_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk10_ck" }, + { DM816_MAILBOX_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk6_ck" }, + { DM816_SPINBOX_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk6_ck" }, + { DM816_MMC1_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk10_ck" }, + { DM816_GPMC_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk6_ck" }, + { DM816_DAVINCI_MDIO_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_NO_IDLEST, "sysclk24_ck" }, + { DM816_EMAC1_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_NO_IDLEST, "sysclk24_ck" }, + { DM816_MPU_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk2_ck" }, + { DM816_RTC_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_NO_IDLEST, "sysclk18_ck" }, + { DM816_TPCC_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk4_ck" }, + { DM816_TPTC0_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk4_ck" }, + { DM816_TPTC1_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk4_ck" }, + { DM816_TPTC2_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk4_ck" }, + { DM816_TPTC3_CLKCTRL, NULL, CLKF_SW_SUP, "sysclk4_ck" }, + { 0 }, +}; + +const struct omap_clkctrl_data dm816_clkctrl_data[] __initconst = { + { 0x48180500, dm816_default_clkctrl_regs }, + { 0x48181400, dm816_alwon_clkctrl_regs }, + { 0 }, +}; + static struct ti_dt_clk dm816x_clks[] = { DT_CLK(NULL, "sys_clkin", "sys_clkin_ck"), DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"), - DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"), DT_CLK(NULL, "timer_32k_ck", "sysclk18_ck"), DT_CLK(NULL, "timer_ext_ck", "tclkin_ck"), - DT_CLK(NULL, "mpu_ck", "mpu_ck"), - DT_CLK(NULL, "timer1_fck", "timer1_fck"), - DT_CLK(NULL, "timer2_fck", "timer2_fck"), - DT_CLK(NULL, "timer3_fck", "timer3_fck"), - DT_CLK(NULL, "timer4_fck", "timer4_fck"), - DT_CLK(NULL, "timer5_fck", "timer5_fck"), - DT_CLK(NULL, "timer6_fck", "timer6_fck"), - DT_CLK(NULL, "timer7_fck", "timer7_fck"), - DT_CLK(NULL, "sysclk4_ck", "sysclk4_ck"), - DT_CLK(NULL, "sysclk5_ck", "sysclk5_ck"), - DT_CLK(NULL, "sysclk6_ck", "sysclk6_ck"), - DT_CLK(NULL, "sysclk10_ck", "sysclk10_ck"), - DT_CLK(NULL, "sysclk18_ck", "sysclk18_ck"), - DT_CLK(NULL, "sysclk24_ck", "sysclk24_ck"), - DT_CLK("4a100000.ethernet", "sysclk24_ck", "sysclk24_ck"), { .node_name = NULL }, }; @@ -50,6 +79,7 @@ int __init dm816x_dt_clk_init(void) { ti_dt_clocks_register(dm816x_clks); omap2_clk_disable_autoidle_all(); + ti_clk_add_aliases(); omap2_clk_enable_init_clocks(enable_init_clks, ARRAY_SIZE(enable_init_clks)); diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index e5a1c8297a1d..f4d6802a8544 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -108,25 +108,77 @@ void __init ti_dt_clocks_register(struct ti_dt_clk oclks[]) struct device_node *node; struct clk *clk; struct of_phandle_args clkspec; + char buf[64]; + char *ptr; + char *tags[2]; + int i; + int num_args; + int ret; + static bool clkctrl_nodes_missing; + static bool has_clkctrl_data; for (c = oclks; c->node_name != NULL; c++) { - node = of_find_node_by_name(NULL, c->node_name); + strcpy(buf, c->node_name); + ptr = buf; + for (i = 0; i < 2; i++) + tags[i] = NULL; + num_args = 0; + while (*ptr) { + if (*ptr == ':') { + if (num_args >= 2) { + pr_warn("Bad number of tags on %s\n", + c->node_name); + return; + } + tags[num_args++] = ptr + 1; + *ptr = 0; + } + ptr++; + } + + if (num_args && clkctrl_nodes_missing) + continue; + + node = of_find_node_by_name(NULL, buf); + if (num_args) + node = of_find_node_by_name(node, "clk"); clkspec.np = node; + clkspec.args_count = num_args; + for (i = 0; i < num_args; i++) { + ret = kstrtoint(tags[i], i ? 10 : 16, clkspec.args + i); + if (ret) { + pr_warn("Bad tag in %s at %d: %s\n", + c->node_name, i, tags[i]); + return; + } + } clk = of_clk_get_from_provider(&clkspec); if (!IS_ERR(clk)) { c->lk.clk = clk; clkdev_add(&c->lk); } else { - pr_warn("failed to lookup clock node %s\n", - c->node_name); + if (num_args && !has_clkctrl_data) { + if (of_find_compatible_node(NULL, NULL, + "ti,clkctrl")) { + has_clkctrl_data = true; + } else { + clkctrl_nodes_missing = true; + + pr_warn("missing clkctrl nodes, please update your dts.\n"); + continue; + } + } + + pr_warn("failed to lookup clock node %s, ret=%ld\n", + c->node_name, PTR_ERR(clk)); } } } struct clk_init_item { struct device_node *node; - struct clk_hw *hw; + void *user; ti_of_clk_init_cb_t func; struct list_head link; }; @@ -136,14 +188,14 @@ static LIST_HEAD(retry_list); /** * ti_clk_retry_init - retries a failed clock init at later phase * @node: device not for the clock - * @hw: partially initialized clk_hw struct for the clock + * @user: user data pointer * @func: init function to be called for the clock * * Adds a failed clock init to the retry list. The retry list is parsed * once all the other clocks have been initialized. */ -int __init ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, - ti_of_clk_init_cb_t func) +int __init ti_clk_retry_init(struct device_node *node, void *user, + ti_of_clk_init_cb_t func) { struct clk_init_item *retry; @@ -154,7 +206,7 @@ int __init ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, retry->node = node; retry->func = func; - retry->hw = hw; + retry->user = user; list_add(&retry->link, &retry_list); return 0; @@ -276,7 +328,7 @@ void ti_dt_clk_init_retry_clks(void) while (!list_empty(&retry_list) && retries) { list_for_each_entry_safe(retry, tmp, &retry_list, link) { pr_debug("retry-init: %s\n", retry->node->name); - retry->func(retry->hw, retry->node); + retry->func(retry->user, retry->node); list_del(&retry->link); kfree(retry); } @@ -284,141 +336,6 @@ void ti_dt_clk_init_retry_clks(void) } } -#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS) -void __init ti_clk_patch_legacy_clks(struct ti_clk **patch) -{ - while (*patch) { - memcpy((*patch)->patch, *patch, sizeof(**patch)); - patch++; - } -} - -struct clk __init *ti_clk_register_clk(struct ti_clk *setup) -{ - struct clk *clk; - struct ti_clk_fixed *fixed; - struct ti_clk_fixed_factor *fixed_factor; - struct clk_hw *clk_hw; - int ret; - - if (setup->clk) - return setup->clk; - - switch (setup->type) { - case TI_CLK_FIXED: - fixed = setup->data; - - clk = clk_register_fixed_rate(NULL, setup->name, NULL, 0, - fixed->frequency); - if (!IS_ERR(clk)) { - ret = ti_clk_add_alias(NULL, clk, setup->name); - if (ret) { - clk_unregister(clk); - clk = ERR_PTR(ret); - } - } - break; - case TI_CLK_MUX: - clk = ti_clk_register_mux(setup); - break; - case TI_CLK_DIVIDER: - clk = ti_clk_register_divider(setup); - break; - case TI_CLK_COMPOSITE: - clk = ti_clk_register_composite(setup); - break; - case TI_CLK_FIXED_FACTOR: - fixed_factor = setup->data; - - clk = clk_register_fixed_factor(NULL, setup->name, - fixed_factor->parent, - 0, fixed_factor->mult, - fixed_factor->div); - if (!IS_ERR(clk)) { - ret = ti_clk_add_alias(NULL, clk, setup->name); - if (ret) { - clk_unregister(clk); - clk = ERR_PTR(ret); - } - } - break; - case TI_CLK_GATE: - clk = ti_clk_register_gate(setup); - break; - case TI_CLK_DPLL: - clk = ti_clk_register_dpll(setup); - break; - default: - pr_err("bad type for %s!\n", setup->name); - clk = ERR_PTR(-EINVAL); - } - - if (!IS_ERR(clk)) { - setup->clk = clk; - if (setup->clkdm_name) { - clk_hw = __clk_get_hw(clk); - if (clk_hw_get_flags(clk_hw) & CLK_IS_BASIC) { - pr_warn("can't setup clkdm for basic clk %s\n", - setup->name); - } else { - to_clk_hw_omap(clk_hw)->clkdm_name = - setup->clkdm_name; - omap2_init_clk_clkdm(clk_hw); - } - } - } - - return clk; -} - -int __init ti_clk_register_legacy_clks(struct ti_clk_alias *clks) -{ - struct clk *clk; - bool retry; - struct ti_clk_alias *retry_clk; - struct ti_clk_alias *tmp; - - while (clks->clk) { - clk = ti_clk_register_clk(clks->clk); - if (IS_ERR(clk)) { - if (PTR_ERR(clk) == -EAGAIN) { - list_add(&clks->link, &retry_list); - } else { - pr_err("register for %s failed: %ld\n", - clks->clk->name, PTR_ERR(clk)); - return PTR_ERR(clk); - } - } - clks++; - } - - retry = true; - - while (!list_empty(&retry_list) && retry) { - retry = false; - list_for_each_entry_safe(retry_clk, tmp, &retry_list, link) { - pr_debug("retry-init: %s\n", retry_clk->clk->name); - clk = ti_clk_register_clk(retry_clk->clk); - if (IS_ERR(clk)) { - if (PTR_ERR(clk) == -EAGAIN) { - continue; - } else { - pr_err("register for %s failed: %ld\n", - retry_clk->clk->name, - PTR_ERR(clk)); - return PTR_ERR(clk); - } - } else { - retry = true; - list_del(&retry_clk->link); - } - } - } - - return 0; -} -#endif - static const struct of_device_id simple_clk_match_table[] __initconst = { { .compatible = "fixed-clock" }, { .compatible = "fixed-factor-clock" }, diff --git a/drivers/clk/ti/clkctrl.c b/drivers/clk/ti/clkctrl.c index 53e71d0503ec..afa0d6bfc5c1 100644 --- a/drivers/clk/ti/clkctrl.c +++ b/drivers/clk/ti/clkctrl.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "clock.h" #define NO_IDLEST 0x1 @@ -46,6 +47,7 @@ static bool _early_timeout = true; struct omap_clkctrl_provider { void __iomem *base; struct list_head clocks; + char *clkdm_name; }; struct omap_clkctrl_clk { @@ -89,7 +91,18 @@ static bool _omap4_is_ready(u32 val) static bool _omap4_is_timeout(union omap4_timeout *time, u32 timeout) { - if (unlikely(_early_timeout)) { + /* + * There are two special cases where ktime_to_ns() can't be + * used to track the timeouts. First one is during early boot + * when the timers haven't been initialized yet. The second + * one is during suspend-resume cycle while timekeeping is + * being suspended / resumed. Clocksource for the system + * can be from a timer that requires pm_runtime access, which + * will eventually bring us here with timekeeping_suspended, + * during both suspend entry and resume paths. This happens + * at least on am43xx platform. + */ + if (unlikely(_early_timeout || timekeeping_suspended)) { if (time->cycles++ < timeout) { udelay(1); return false; @@ -208,6 +221,7 @@ static const struct clk_ops omap4_clkctrl_clk_ops = { .enable = _omap4_clkctrl_clk_enable, .disable = _omap4_clkctrl_clk_disable, .is_enabled = _omap4_clkctrl_clk_is_enabled, + .init = omap2_init_clk_clkdm, }; static struct clk_hw *_ti_omap4_clkctrl_xlate(struct of_phandle_args *clkspec, @@ -321,6 +335,9 @@ _ti_clkctrl_setup_mux(struct omap_clkctrl_provider *provider, } mux->mask = num_parents; + if (!(mux->flags & CLK_MUX_INDEX_ONE)) + mux->mask--; + mux->mask = (1 << fls(mux->mask)) - 1; mux->shift = data->bit; @@ -340,6 +357,7 @@ _ti_clkctrl_setup_div(struct omap_clkctrl_provider *provider, { struct clk_omap_divider *div; const struct omap_clkctrl_div_data *div_data = data->data; + u8 div_flags = 0; div = kzalloc(sizeof(*div), GFP_KERNEL); if (!div) @@ -347,12 +365,16 @@ _ti_clkctrl_setup_div(struct omap_clkctrl_provider *provider, div->reg.ptr = reg; div->shift = data->bit; + div->flags = div_data->flags; - if (ti_clk_parse_divider_data((int *)div_data->dividers, - div_data->max_div, 0, 0, + if (div->flags & CLK_DIVIDER_POWER_OF_TWO) + div_flags |= CLKF_INDEX_POWER_OF_TWO; + + if (ti_clk_parse_divider_data((int *)div_data->dividers, 0, + div_data->max_div, div_flags, &div->width, &div->table)) { - pr_err("%s: Data parsing for %s:%04x:%d failed\n", __func__, - node->name, offset, data->bit); + pr_err("%s: Data parsing for %pOF:%04x:%d failed\n", __func__, + node, offset, data->bit); kfree(div); return; } @@ -400,6 +422,12 @@ _ti_clkctrl_setup_subclks(struct omap_clkctrl_provider *provider, } } +static void __init _clkctrl_add_provider(void *data, + struct device_node *np) +{ + of_clk_add_hw_provider(np, _ti_omap4_clkctrl_xlate, data); +} + static void __init _ti_omap4_clkctrl_setup(struct device_node *node) { struct omap_clkctrl_provider *provider; @@ -411,6 +439,7 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node) struct omap_clkctrl_clk *clkctrl_clk; const __be32 *addrp; u32 addr; + int ret; addrp = of_get_address(node, 0, NULL, NULL); addr = (u32)of_translate_address(node, addrp); @@ -419,6 +448,31 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node) if (of_machine_is_compatible("ti,omap4")) data = omap4_clkctrl_data; #endif +#ifdef CONFIG_SOC_OMAP5 + if (of_machine_is_compatible("ti,omap5")) + data = omap5_clkctrl_data; +#endif +#ifdef CONFIG_SOC_DRA7XX + if (of_machine_is_compatible("ti,dra7")) + data = dra7_clkctrl_data; +#endif +#ifdef CONFIG_SOC_AM33XX + if (of_machine_is_compatible("ti,am33xx")) + data = am3_clkctrl_data; +#endif +#ifdef CONFIG_SOC_AM43XX + if (of_machine_is_compatible("ti,am4372")) + data = am4_clkctrl_data; + if (of_machine_is_compatible("ti,am438x")) + data = am438x_clkctrl_data; +#endif +#ifdef CONFIG_SOC_TI81XX + if (of_machine_is_compatible("ti,dm814")) + data = dm814_clkctrl_data; + + if (of_machine_is_compatible("ti,dm816")) + data = dm816_clkctrl_data; +#endif while (data->addr) { if (addr == data->addr) @@ -428,7 +482,7 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node) } if (!data->addr) { - pr_err("%s not found from clkctrl data.\n", node->name); + pr_err("%pOF not found from clkctrl data.\n", node); return; } @@ -438,6 +492,21 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node) provider->base = of_iomap(node, 0); + provider->clkdm_name = kmalloc(strlen(node->parent->name) + 3, + GFP_KERNEL); + if (!provider->clkdm_name) { + kfree(provider); + return; + } + + /* + * Create default clkdm name, replace _cm from end of parent node + * name with _clkdm + */ + strcpy(provider->clkdm_name, node->parent->name); + provider->clkdm_name[strlen(provider->clkdm_name) - 2] = 0; + strcat(provider->clkdm_name, "clkdm"); + INIT_LIST_HEAD(&provider->clocks); /* Generate clocks */ @@ -460,6 +529,11 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node) if (reg_data->flags & CLKF_NO_IDLEST) hw->flags |= NO_IDLEST; + if (reg_data->clkdm_name) + hw->clkdm_name = reg_data->clkdm_name; + else + hw->clkdm_name = provider->clkdm_name; + init.parent_names = ®_data->parent; init.num_parents = 1; init.flags = 0; @@ -485,7 +559,10 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node) reg_data++; } - of_clk_add_hw_provider(node, _ti_omap4_clkctrl_xlate, provider); + ret = of_clk_add_hw_provider(node, _ti_omap4_clkctrl_xlate, provider); + if (ret == -EPROBE_DEFER) + ti_clk_retry_init(node, provider, _clkctrl_add_provider); + return; cleanup: diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 561dbe99ced7..d9b43bfc2532 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -92,17 +92,6 @@ struct ti_clk { struct clk *clk; }; -struct ti_clk_alias { - struct ti_clk *clk; - struct clk_lookup lk; - struct list_head link; -}; - -struct ti_clk_fixed { - u32 frequency; - u16 flags; -}; - struct ti_clk_mux { u8 bit_shift; int num_parents; @@ -123,13 +112,6 @@ struct ti_clk_divider { u16 flags; }; -struct ti_clk_fixed_factor { - const char *parent; - u16 div; - u16 mult; - u16 flags; -}; - struct ti_clk_gate { const char *parent; u8 bit_shift; @@ -138,44 +120,6 @@ struct ti_clk_gate { u16 flags; }; -struct ti_clk_composite { - struct ti_clk_divider *divider; - struct ti_clk_mux *mux; - struct ti_clk_gate *gate; - u16 flags; -}; - -struct ti_clk_clkdm_gate { - const char *parent; - u16 flags; -}; - -struct ti_clk_dpll { - int num_parents; - u16 control_reg; - u16 idlest_reg; - u16 autoidle_reg; - u16 mult_div1_reg; - u8 module; - const char **parents; - u16 flags; - u8 modes; - u32 mult_mask; - u32 div1_mask; - u32 enable_mask; - u32 autoidle_mask; - u32 freqsel_mask; - u32 idlest_mask; - u32 dco_mask; - u32 sddiv_mask; - u16 max_multiplier; - u16 max_divider; - u8 min_divider; - u8 auto_recal_bit; - u8 recal_en_bit; - u8 recal_st_bit; -}; - /* Composite clock component types */ enum { CLK_COMPONENT_TYPE_GATE = 0, @@ -207,6 +151,7 @@ struct ti_dt_clk { struct omap_clkctrl_div_data { const int *dividers; int max_div; + u32 flags; }; struct omap_clkctrl_bit_data { @@ -221,6 +166,7 @@ struct omap_clkctrl_reg_data { const struct omap_clkctrl_bit_data *bit_data; u16 flags; const char *parent; + const char *clkdm_name; }; struct omap_clkctrl_data { @@ -229,40 +175,35 @@ struct omap_clkctrl_data { }; extern const struct omap_clkctrl_data omap4_clkctrl_data[]; +extern const struct omap_clkctrl_data omap5_clkctrl_data[]; +extern const struct omap_clkctrl_data dra7_clkctrl_data[]; +extern const struct omap_clkctrl_data am3_clkctrl_data[]; +extern const struct omap_clkctrl_data am4_clkctrl_data[]; +extern const struct omap_clkctrl_data am438x_clkctrl_data[]; +extern const struct omap_clkctrl_data dm814_clkctrl_data[]; +extern const struct omap_clkctrl_data dm816_clkctrl_data[]; #define CLKF_SW_SUP BIT(0) #define CLKF_HW_SUP BIT(1) #define CLKF_NO_IDLEST BIT(2) -typedef void (*ti_of_clk_init_cb_t)(struct clk_hw *, struct device_node *); +typedef void (*ti_of_clk_init_cb_t)(void *, struct device_node *); -struct clk *ti_clk_register_gate(struct ti_clk *setup); -struct clk *ti_clk_register_interface(struct ti_clk *setup); -struct clk *ti_clk_register_mux(struct ti_clk *setup); -struct clk *ti_clk_register_divider(struct ti_clk *setup); -struct clk *ti_clk_register_composite(struct ti_clk *setup); -struct clk *ti_clk_register_dpll(struct ti_clk *setup); struct clk *ti_clk_register(struct device *dev, struct clk_hw *hw, const char *con); int ti_clk_add_alias(struct device *dev, struct clk *clk, const char *con); void ti_clk_add_aliases(void); -struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup); -struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup); struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup); int ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div, u8 flags, u8 *width, const struct clk_div_table **table); -void ti_clk_patch_legacy_clks(struct ti_clk **patch); -struct clk *ti_clk_register_clk(struct ti_clk *setup); -int ti_clk_register_legacy_clks(struct ti_clk_alias *clks); - int ti_clk_get_reg_addr(struct device_node *node, int index, struct clk_omap_reg *reg); void ti_dt_clocks_register(struct ti_dt_clk *oclks); -int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, +int ti_clk_retry_init(struct device_node *node, void *user, ti_of_clk_init_cb_t func); int ti_clk_add_component(struct device_node *node, struct clk_hw *hw, int type); diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c index beea89463ca2..030e8b2c1050 100644 --- a/drivers/clk/ti/composite.c +++ b/drivers/clk/ti/composite.c @@ -116,54 +116,10 @@ static inline struct clk_hw *_get_hw(struct clk_hw_omap_comp *clk, int idx) #define to_clk_hw_comp(_hw) container_of(_hw, struct clk_hw_omap_comp, hw) -#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS) -struct clk *ti_clk_register_composite(struct ti_clk *setup) -{ - struct ti_clk_composite *comp; - struct clk_hw *gate; - struct clk_hw *mux; - struct clk_hw *div; - int num_parents = 1; - const char * const *parent_names = NULL; - struct clk *clk; - int ret; - - comp = setup->data; - - div = ti_clk_build_component_div(comp->divider); - gate = ti_clk_build_component_gate(comp->gate); - mux = ti_clk_build_component_mux(comp->mux); - - if (div) - parent_names = &comp->divider->parent; - - if (gate) - parent_names = &comp->gate->parent; - - if (mux) { - num_parents = comp->mux->num_parents; - parent_names = comp->mux->parents; - } - - clk = clk_register_composite(NULL, setup->name, - parent_names, num_parents, mux, - &ti_clk_mux_ops, div, - &ti_composite_divider_ops, gate, - &ti_composite_gate_ops, 0); - - ret = ti_clk_add_alias(NULL, clk, setup->name); - if (ret) { - clk_unregister(clk); - return ERR_PTR(ret); - } - - return clk; -} -#endif - -static void __init _register_composite(struct clk_hw *hw, +static void __init _register_composite(void *user, struct device_node *node) { + struct clk_hw *hw = user; struct clk *clk; struct clk_hw_omap_comp *cclk = to_clk_hw_comp(hw); struct component_clk *comp; diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c index d4e4444bc5ca..7d33ca9042cb 100644 --- a/drivers/clk/ti/dpll.c +++ b/drivers/clk/ti/dpll.c @@ -152,9 +152,10 @@ static const struct clk_ops dpll_x2_ck_ops = { * clk-bypass is missing), the clock is added to retry list and * the initialization is retried on later stage. */ -static void __init _register_dpll(struct clk_hw *hw, +static void __init _register_dpll(void *user, struct device_node *node) { + struct clk_hw *hw = user; struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw); struct dpll_data *dd = clk_hw->dpll_data; struct clk *clk; @@ -202,96 +203,6 @@ cleanup: kfree(clk_hw); } -#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS) -void _get_reg(u8 module, u16 offset, struct clk_omap_reg *reg) -{ - reg->index = module; - reg->offset = offset; -} - -struct clk *ti_clk_register_dpll(struct ti_clk *setup) -{ - struct clk_hw_omap *clk_hw; - struct clk_init_data init = { NULL }; - struct dpll_data *dd; - struct clk *clk; - struct ti_clk_dpll *dpll; - const struct clk_ops *ops = &omap3_dpll_ck_ops; - struct clk *clk_ref; - struct clk *clk_bypass; - - dpll = setup->data; - - if (dpll->num_parents < 2) - return ERR_PTR(-EINVAL); - - clk_ref = clk_get_sys(NULL, dpll->parents[0]); - clk_bypass = clk_get_sys(NULL, dpll->parents[1]); - - if (IS_ERR_OR_NULL(clk_ref) || IS_ERR_OR_NULL(clk_bypass)) - return ERR_PTR(-EAGAIN); - - dd = kzalloc(sizeof(*dd), GFP_KERNEL); - clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); - if (!dd || !clk_hw) { - clk = ERR_PTR(-ENOMEM); - goto cleanup; - } - - clk_hw->dpll_data = dd; - clk_hw->ops = &clkhwops_omap3_dpll; - clk_hw->hw.init = &init; - - init.name = setup->name; - init.ops = ops; - - init.num_parents = dpll->num_parents; - init.parent_names = dpll->parents; - - _get_reg(dpll->module, dpll->control_reg, &dd->control_reg); - _get_reg(dpll->module, dpll->idlest_reg, &dd->idlest_reg); - _get_reg(dpll->module, dpll->mult_div1_reg, &dd->mult_div1_reg); - _get_reg(dpll->module, dpll->autoidle_reg, &dd->autoidle_reg); - - dd->modes = dpll->modes; - dd->div1_mask = dpll->div1_mask; - dd->idlest_mask = dpll->idlest_mask; - dd->mult_mask = dpll->mult_mask; - dd->autoidle_mask = dpll->autoidle_mask; - dd->enable_mask = dpll->enable_mask; - dd->sddiv_mask = dpll->sddiv_mask; - dd->dco_mask = dpll->dco_mask; - dd->max_divider = dpll->max_divider; - dd->min_divider = dpll->min_divider; - dd->max_multiplier = dpll->max_multiplier; - dd->auto_recal_bit = dpll->auto_recal_bit; - dd->recal_en_bit = dpll->recal_en_bit; - dd->recal_st_bit = dpll->recal_st_bit; - - dd->clk_ref = __clk_get_hw(clk_ref); - dd->clk_bypass = __clk_get_hw(clk_bypass); - - if (dpll->flags & CLKF_CORE) - ops = &omap3_dpll_core_ck_ops; - - if (dpll->flags & CLKF_PER) - ops = &omap3_dpll_per_ck_ops; - - if (dpll->flags & CLKF_J_TYPE) - dd->flags |= DPLL_J_TYPE; - - clk = ti_clk_register(NULL, &clk_hw->hw, setup->name); - - if (!IS_ERR(clk)) - return clk; - -cleanup: - kfree(dd); - kfree(clk_hw); - return clk; -} -#endif - #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM33XX) || \ defined(CONFIG_SOC_AM43XX) diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c index 7151ec3a1b07..935b2de5fb88 100644 --- a/drivers/clk/ti/gate.c +++ b/drivers/clk/ti/gate.c @@ -128,53 +128,6 @@ static struct clk *_register_gate(struct device *dev, const char *name, return clk; } -#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS) -struct clk *ti_clk_register_gate(struct ti_clk *setup) -{ - const struct clk_ops *ops = &omap_gate_clk_ops; - const struct clk_hw_omap_ops *hw_ops = NULL; - struct clk_omap_reg reg; - u32 flags = 0; - u8 clk_gate_flags = 0; - struct ti_clk_gate *gate; - - gate = setup->data; - - if (gate->flags & CLKF_INTERFACE) - return ti_clk_register_interface(setup); - - if (gate->flags & CLKF_SET_RATE_PARENT) - flags |= CLK_SET_RATE_PARENT; - - if (gate->flags & CLKF_SET_BIT_TO_DISABLE) - clk_gate_flags |= INVERT_ENABLE; - - if (gate->flags & CLKF_HSDIV) { - ops = &omap_gate_clk_hsdiv_restore_ops; - hw_ops = &clkhwops_wait; - } - - if (gate->flags & CLKF_DSS) - hw_ops = &clkhwops_omap3430es2_dss_usbhost_wait; - - if (gate->flags & CLKF_WAIT) - hw_ops = &clkhwops_wait; - - if (gate->flags & CLKF_CLKDM) - ops = &omap_gate_clkdm_clk_ops; - - if (gate->flags & CLKF_AM35XX) - hw_ops = &clkhwops_am35xx_ipss_module_wait; - - reg.index = gate->module; - reg.offset = gate->reg; - reg.ptr = NULL; - - return _register_gate(NULL, setup->name, gate->parent, flags, - ®, gate->bit_shift, - clk_gate_flags, ops, hw_ops); -} - struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup) { struct clk_hw_omap *gate; @@ -204,7 +157,6 @@ struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup) return &gate->hw; } -#endif static void __init _of_ti_gate_clk_setup(struct device_node *node, const struct clk_ops *ops, diff --git a/drivers/clk/ti/interface.c b/drivers/clk/ti/interface.c index 62cf50c1e1e3..41ae7021670e 100644 --- a/drivers/clk/ti/interface.c +++ b/drivers/clk/ti/interface.c @@ -67,38 +67,6 @@ static struct clk *_register_interface(struct device *dev, const char *name, return clk; } -#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS) -struct clk *ti_clk_register_interface(struct ti_clk *setup) -{ - const struct clk_hw_omap_ops *ops = &clkhwops_iclk_wait; - struct clk_omap_reg reg; - struct ti_clk_gate *gate; - - gate = setup->data; - reg.index = gate->module; - reg.offset = gate->reg; - reg.ptr = NULL; - - if (gate->flags & CLKF_NO_WAIT) - ops = &clkhwops_iclk; - - if (gate->flags & CLKF_HSOTGUSB) - ops = &clkhwops_omap3430es2_iclk_hsotgusb_wait; - - if (gate->flags & CLKF_DSS) - ops = &clkhwops_omap3430es2_iclk_dss_usbhost_wait; - - if (gate->flags & CLKF_SSI) - ops = &clkhwops_omap3430es2_iclk_ssi_wait; - - if (gate->flags & CLKF_AM35XX) - ops = &clkhwops_am35xx_ipss_wait; - - return _register_interface(NULL, setup->name, gate->parent, - ®, gate->bit_shift, ops); -} -#endif - static void __init _of_ti_interface_clk_setup(struct device_node *node, const struct clk_hw_omap_ops *ops) { diff --git a/drivers/clk/zte/clk.h b/drivers/clk/zte/clk.h index 4df0f121b56d..f1041e36bcf1 100644 --- a/drivers/clk/zte/clk.h +++ b/drivers/clk/zte/clk.h @@ -14,24 +14,6 @@ #define PNAME(x) static const char *x[] -#define CLK_HW_INIT(_name, _parent, _ops, _flags) \ - &(struct clk_init_data) { \ - .flags = _flags, \ - .name = _name, \ - .parent_names = (const char *[]) { _parent }, \ - .num_parents = 1, \ - .ops = _ops, \ - } - -#define CLK_HW_INIT_PARENTS(_name, _parents, _ops, _flags) \ - &(struct clk_init_data) { \ - .flags = _flags, \ - .name = _name, \ - .parent_names = _parents, \ - .num_parents = ARRAY_SIZE(_parents), \ - .ops = _ops, \ - } - struct zx_pll_config { unsigned long rate; u32 cfg0; diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index c729a88007d0..b3b4ed9b6874 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -269,6 +269,7 @@ config CLKSRC_STM32 bool "Clocksource for STM32 SoCs" if !ARCH_STM32 depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST) select CLKSRC_MMIO + select TIMER_OF config CLKSRC_MPS2 bool "Clocksource for MPS2 SoCs" if COMPILE_TEST @@ -441,6 +442,13 @@ config MTK_TIMER help Support for Mediatek timer driver. +config SPRD_TIMER + bool "Spreadtrum timer driver" if COMPILE_TEST + depends on HAS_IOMEM + select TIMER_OF + help + Enables support for the Spreadtrum timer driver. + config SYS_SUPPORTS_SH_MTU2 bool diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 72711f1491e3..d6dec4489d66 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o obj-$(CONFIG_CLKSRC_NPS) += timer-nps.o obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o obj-$(CONFIG_OWL_TIMER) += owl-timer.o +obj-$(CONFIG_SPRD_TIMER) += timer-sprd.o obj-$(CONFIG_ARC_TIMERS) += arc_timer.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o diff --git a/drivers/clocksource/owl-timer.c b/drivers/clocksource/owl-timer.c index c68630565079..ea00a5e8f95d 100644 --- a/drivers/clocksource/owl-timer.c +++ b/drivers/clocksource/owl-timer.c @@ -168,5 +168,6 @@ static int __init owl_timer_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE(owl_s500, "actions,s500-timer", owl_timer_init); -CLOCKSOURCE_OF_DECLARE(owl_s900, "actions,s900-timer", owl_timer_init); +TIMER_OF_DECLARE(owl_s500, "actions,s500-timer", owl_timer_init); +TIMER_OF_DECLARE(owl_s700, "actions,s700-timer", owl_timer_init); +TIMER_OF_DECLARE(owl_s900, "actions,s900-timer", owl_timer_init); diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c index 9de47d4d2d9e..43f4d5c4d6fa 100644 --- a/drivers/clocksource/tcb_clksrc.c +++ b/drivers/clocksource/tcb_clksrc.c @@ -384,7 +384,7 @@ static int __init tcb_clksrc_init(void) printk(bootinfo, clksrc.name, CONFIG_ATMEL_TCB_CLKSRC_BLOCK, divided_rate / 1000000, - ((divided_rate + 500000) % 1000000) / 1000); + ((divided_rate % 1000000) + 500) / 1000); if (tc->tcb_config && tc->tcb_config->counter_width == 32) { /* use apropriate function to read 32 bit counter */ diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c index a31990408153..06ed88a2a8a0 100644 --- a/drivers/clocksource/timer-of.c +++ b/drivers/clocksource/timer-of.c @@ -24,7 +24,13 @@ #include "timer-of.h" -static __init void timer_irq_exit(struct of_timer_irq *of_irq) +/** + * timer_of_irq_exit - Release the interrupt + * @of_irq: an of_timer_irq structure pointer + * + * Free the irq resource + */ +static __init void timer_of_irq_exit(struct of_timer_irq *of_irq) { struct timer_of *to = container_of(of_irq, struct timer_of, of_irq); @@ -34,8 +40,24 @@ static __init void timer_irq_exit(struct of_timer_irq *of_irq) free_irq(of_irq->irq, clkevt); } -static __init int timer_irq_init(struct device_node *np, - struct of_timer_irq *of_irq) +/** + * timer_of_irq_init - Request the interrupt + * @np: a device tree node pointer + * @of_irq: an of_timer_irq structure pointer + * + * Get the interrupt number from the DT from its definition and + * request it. The interrupt is gotten by falling back the following way: + * + * - Get interrupt number by name + * - Get interrupt number by index + * + * When the interrupt is per CPU, 'request_percpu_irq()' is called, + * otherwise 'request_irq()' is used. + * + * Returns 0 on success, < 0 otherwise + */ +static __init int timer_of_irq_init(struct device_node *np, + struct of_timer_irq *of_irq) { int ret; struct timer_of *to = container_of(of_irq, struct timer_of, of_irq); @@ -72,15 +94,30 @@ static __init int timer_irq_init(struct device_node *np, return 0; } -static __init void timer_clk_exit(struct of_timer_clk *of_clk) +/** + * timer_of_clk_exit - Release the clock resources + * @of_clk: a of_timer_clk structure pointer + * + * Disables and releases the refcount on the clk + */ +static __init void timer_of_clk_exit(struct of_timer_clk *of_clk) { of_clk->rate = 0; clk_disable_unprepare(of_clk->clk); clk_put(of_clk->clk); } -static __init int timer_clk_init(struct device_node *np, - struct of_timer_clk *of_clk) +/** + * timer_of_clk_init - Initialize the clock resources + * @np: a device tree node pointer + * @of_clk: a of_timer_clk structure pointer + * + * Get the clock by name or by index, enable it and get the rate + * + * Returns 0 on success, < 0 otherwise + */ +static __init int timer_of_clk_init(struct device_node *np, + struct of_timer_clk *of_clk) { int ret; @@ -116,19 +153,19 @@ out_clk_put: goto out; } -static __init void timer_base_exit(struct of_timer_base *of_base) +static __init void timer_of_base_exit(struct of_timer_base *of_base) { iounmap(of_base->base); } -static __init int timer_base_init(struct device_node *np, - struct of_timer_base *of_base) +static __init int timer_of_base_init(struct device_node *np, + struct of_timer_base *of_base) { - const char *name = of_base->name ? of_base->name : np->full_name; - - of_base->base = of_io_request_and_map(np, of_base->index, name); + of_base->base = of_base->name ? + of_io_request_and_map(np, of_base->index, of_base->name) : + of_iomap(np, of_base->index); if (IS_ERR(of_base->base)) { - pr_err("Failed to iomap (%s)\n", name); + pr_err("Failed to iomap (%s)\n", of_base->name); return PTR_ERR(of_base->base); } @@ -141,21 +178,21 @@ int __init timer_of_init(struct device_node *np, struct timer_of *to) int flags = 0; if (to->flags & TIMER_OF_BASE) { - ret = timer_base_init(np, &to->of_base); + ret = timer_of_base_init(np, &to->of_base); if (ret) goto out_fail; flags |= TIMER_OF_BASE; } if (to->flags & TIMER_OF_CLOCK) { - ret = timer_clk_init(np, &to->of_clk); + ret = timer_of_clk_init(np, &to->of_clk); if (ret) goto out_fail; flags |= TIMER_OF_CLOCK; } if (to->flags & TIMER_OF_IRQ) { - ret = timer_irq_init(np, &to->of_irq); + ret = timer_of_irq_init(np, &to->of_irq); if (ret) goto out_fail; flags |= TIMER_OF_IRQ; @@ -163,17 +200,20 @@ int __init timer_of_init(struct device_node *np, struct timer_of *to) if (!to->clkevt.name) to->clkevt.name = np->name; + + to->np = np; + return ret; out_fail: if (flags & TIMER_OF_IRQ) - timer_irq_exit(&to->of_irq); + timer_of_irq_exit(&to->of_irq); if (flags & TIMER_OF_CLOCK) - timer_clk_exit(&to->of_clk); + timer_of_clk_exit(&to->of_clk); if (flags & TIMER_OF_BASE) - timer_base_exit(&to->of_base); + timer_of_base_exit(&to->of_base); return ret; } @@ -187,11 +227,11 @@ out_fail: void __init timer_of_cleanup(struct timer_of *to) { if (to->flags & TIMER_OF_IRQ) - timer_irq_exit(&to->of_irq); + timer_of_irq_exit(&to->of_irq); if (to->flags & TIMER_OF_CLOCK) - timer_clk_exit(&to->of_clk); + timer_of_clk_exit(&to->of_clk); if (to->flags & TIMER_OF_BASE) - timer_base_exit(&to->of_base); + timer_of_base_exit(&to->of_base); } diff --git a/drivers/clocksource/timer-of.h b/drivers/clocksource/timer-of.h index 3f708f1be43d..a5478f3e8589 100644 --- a/drivers/clocksource/timer-of.h +++ b/drivers/clocksource/timer-of.h @@ -33,6 +33,7 @@ struct of_timer_clk { struct timer_of { unsigned int flags; + struct device_node *np; struct clock_event_device clkevt; struct of_timer_base of_base; struct of_timer_irq of_irq; diff --git a/drivers/clocksource/timer-sprd.c b/drivers/clocksource/timer-sprd.c new file mode 100644 index 000000000000..ef9ebeafb3ed --- /dev/null +++ b/drivers/clocksource/timer-sprd.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 Spreadtrum Communications Inc. + */ + +#include +#include + +#include "timer-of.h" + +#define TIMER_NAME "sprd_timer" + +#define TIMER_LOAD_LO 0x0 +#define TIMER_LOAD_HI 0x4 +#define TIMER_VALUE_LO 0x8 +#define TIMER_VALUE_HI 0xc + +#define TIMER_CTL 0x10 +#define TIMER_CTL_PERIOD_MODE BIT(0) +#define TIMER_CTL_ENABLE BIT(1) +#define TIMER_CTL_64BIT_WIDTH BIT(16) + +#define TIMER_INT 0x14 +#define TIMER_INT_EN BIT(0) +#define TIMER_INT_RAW_STS BIT(1) +#define TIMER_INT_MASK_STS BIT(2) +#define TIMER_INT_CLR BIT(3) + +#define TIMER_VALUE_SHDW_LO 0x18 +#define TIMER_VALUE_SHDW_HI 0x1c + +#define TIMER_VALUE_LO_MASK GENMASK(31, 0) + +static void sprd_timer_enable(void __iomem *base, u32 flag) +{ + u32 val = readl_relaxed(base + TIMER_CTL); + + val |= TIMER_CTL_ENABLE; + if (flag & TIMER_CTL_64BIT_WIDTH) + val |= TIMER_CTL_64BIT_WIDTH; + else + val &= ~TIMER_CTL_64BIT_WIDTH; + + if (flag & TIMER_CTL_PERIOD_MODE) + val |= TIMER_CTL_PERIOD_MODE; + else + val &= ~TIMER_CTL_PERIOD_MODE; + + writel_relaxed(val, base + TIMER_CTL); +} + +static void sprd_timer_disable(void __iomem *base) +{ + u32 val = readl_relaxed(base + TIMER_CTL); + + val &= ~TIMER_CTL_ENABLE; + writel_relaxed(val, base + TIMER_CTL); +} + +static void sprd_timer_update_counter(void __iomem *base, unsigned long cycles) +{ + writel_relaxed(cycles & TIMER_VALUE_LO_MASK, base + TIMER_LOAD_LO); + writel_relaxed(0, base + TIMER_LOAD_HI); +} + +static void sprd_timer_enable_interrupt(void __iomem *base) +{ + writel_relaxed(TIMER_INT_EN, base + TIMER_INT); +} + +static void sprd_timer_clear_interrupt(void __iomem *base) +{ + u32 val = readl_relaxed(base + TIMER_INT); + + val |= TIMER_INT_CLR; + writel_relaxed(val, base + TIMER_INT); +} + +static int sprd_timer_set_next_event(unsigned long cycles, + struct clock_event_device *ce) +{ + struct timer_of *to = to_timer_of(ce); + + sprd_timer_disable(timer_of_base(to)); + sprd_timer_update_counter(timer_of_base(to), cycles); + sprd_timer_enable(timer_of_base(to), 0); + + return 0; +} + +static int sprd_timer_set_periodic(struct clock_event_device *ce) +{ + struct timer_of *to = to_timer_of(ce); + + sprd_timer_disable(timer_of_base(to)); + sprd_timer_update_counter(timer_of_base(to), timer_of_period(to)); + sprd_timer_enable(timer_of_base(to), TIMER_CTL_PERIOD_MODE); + + return 0; +} + +static int sprd_timer_shutdown(struct clock_event_device *ce) +{ + struct timer_of *to = to_timer_of(ce); + + sprd_timer_disable(timer_of_base(to)); + return 0; +} + +static irqreturn_t sprd_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *ce = (struct clock_event_device *)dev_id; + struct timer_of *to = to_timer_of(ce); + + sprd_timer_clear_interrupt(timer_of_base(to)); + + if (clockevent_state_oneshot(ce)) + sprd_timer_disable(timer_of_base(to)); + + ce->event_handler(ce); + return IRQ_HANDLED; +} + +static struct timer_of to = { + .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK, + + .clkevt = { + .name = TIMER_NAME, + .rating = 300, + .features = CLOCK_EVT_FEAT_DYNIRQ | CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .set_state_shutdown = sprd_timer_shutdown, + .set_state_periodic = sprd_timer_set_periodic, + .set_next_event = sprd_timer_set_next_event, + .cpumask = cpu_possible_mask, + }, + + .of_irq = { + .handler = sprd_timer_interrupt, + .flags = IRQF_TIMER | IRQF_IRQPOLL, + }, +}; + +static int __init sprd_timer_init(struct device_node *np) +{ + int ret; + + ret = timer_of_init(np, &to); + if (ret) + return ret; + + sprd_timer_enable_interrupt(timer_of_base(&to)); + clockevents_config_and_register(&to.clkevt, timer_of_rate(&to), + 1, UINT_MAX); + + return 0; +} + +TIMER_OF_DECLARE(sc9860_timer, "sprd,sc9860-timer", sprd_timer_init); diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c index 8f2423789ba9..e5cdc3af684c 100644 --- a/drivers/clocksource/timer-stm32.c +++ b/drivers/clocksource/timer-stm32.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -16,175 +17,318 @@ #include #include #include +#include +#include + +#include "timer-of.h" #define TIM_CR1 0x00 #define TIM_DIER 0x0c #define TIM_SR 0x10 #define TIM_EGR 0x14 +#define TIM_CNT 0x24 #define TIM_PSC 0x28 #define TIM_ARR 0x2c +#define TIM_CCR1 0x34 #define TIM_CR1_CEN BIT(0) +#define TIM_CR1_UDIS BIT(1) #define TIM_CR1_OPM BIT(3) #define TIM_CR1_ARPE BIT(7) #define TIM_DIER_UIE BIT(0) +#define TIM_DIER_CC1IE BIT(1) #define TIM_SR_UIF BIT(0) #define TIM_EGR_UG BIT(0) -struct stm32_clock_event_ddata { - struct clock_event_device evtdev; - unsigned periodic_top; - void __iomem *base; +#define TIM_PSC_MAX USHRT_MAX +#define TIM_PSC_CLKRATE 10000 + +struct stm32_timer_private { + int bits; }; -static int stm32_clock_event_shutdown(struct clock_event_device *evtdev) +/** + * stm32_timer_of_bits_set - set accessor helper + * @to: a timer_of structure pointer + * @bits: the number of bits (16 or 32) + * + * Accessor helper to set the number of bits in the timer-of private + * structure. + * + */ +static void stm32_timer_of_bits_set(struct timer_of *to, int bits) { - struct stm32_clock_event_ddata *data = - container_of(evtdev, struct stm32_clock_event_ddata, evtdev); - void *base = data->base; + struct stm32_timer_private *pd = to->private_data; - writel_relaxed(0, base + TIM_CR1); - return 0; + pd->bits = bits; } -static int stm32_clock_event_set_periodic(struct clock_event_device *evtdev) +/** + * stm32_timer_of_bits_get - get accessor helper + * @to: a timer_of structure pointer + * + * Accessor helper to get the number of bits in the timer-of private + * structure. + * + * Returns an integer corresponding to the number of bits. + */ +static int stm32_timer_of_bits_get(struct timer_of *to) { - struct stm32_clock_event_ddata *data = - container_of(evtdev, struct stm32_clock_event_ddata, evtdev); - void *base = data->base; + struct stm32_timer_private *pd = to->private_data; + + return pd->bits; +} + +static void __iomem *stm32_timer_cnt __read_mostly; + +static u64 notrace stm32_read_sched_clock(void) +{ + return readl_relaxed(stm32_timer_cnt); +} + +static struct delay_timer stm32_timer_delay; + +static unsigned long stm32_read_delay(void) +{ + return readl_relaxed(stm32_timer_cnt); +} + +static void stm32_clock_event_disable(struct timer_of *to) +{ + writel_relaxed(0, timer_of_base(to) + TIM_DIER); +} + +/** + * stm32_timer_start - Start the counter without event + * @to: a timer_of structure pointer + * + * Start the timer in order to have the counter reset and start + * incrementing but disable interrupt event when there is a counter + * overflow. By default, the counter direction is used as upcounter. + */ +static void stm32_timer_start(struct timer_of *to) +{ + writel_relaxed(TIM_CR1_UDIS | TIM_CR1_CEN, timer_of_base(to) + TIM_CR1); +} + +static int stm32_clock_event_shutdown(struct clock_event_device *clkevt) +{ + struct timer_of *to = to_timer_of(clkevt); + + stm32_clock_event_disable(to); - writel_relaxed(data->periodic_top, base + TIM_ARR); - writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, base + TIM_CR1); return 0; } static int stm32_clock_event_set_next_event(unsigned long evt, - struct clock_event_device *evtdev) + struct clock_event_device *clkevt) { - struct stm32_clock_event_ddata *data = - container_of(evtdev, struct stm32_clock_event_ddata, evtdev); + struct timer_of *to = to_timer_of(clkevt); + unsigned long now, next; - writel_relaxed(evt, data->base + TIM_ARR); - writel_relaxed(TIM_CR1_ARPE | TIM_CR1_OPM | TIM_CR1_CEN, - data->base + TIM_CR1); + next = readl_relaxed(timer_of_base(to) + TIM_CNT) + evt; + writel_relaxed(next, timer_of_base(to) + TIM_CCR1); + now = readl_relaxed(timer_of_base(to) + TIM_CNT); + + if ((next - now) > evt) + return -ETIME; + + writel_relaxed(TIM_DIER_CC1IE, timer_of_base(to) + TIM_DIER); + + return 0; +} + +static int stm32_clock_event_set_periodic(struct clock_event_device *clkevt) +{ + struct timer_of *to = to_timer_of(clkevt); + + stm32_timer_start(to); + + return stm32_clock_event_set_next_event(timer_of_period(to), clkevt); +} + +static int stm32_clock_event_set_oneshot(struct clock_event_device *clkevt) +{ + struct timer_of *to = to_timer_of(clkevt); + + stm32_timer_start(to); return 0; } static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id) { - struct stm32_clock_event_ddata *data = dev_id; + struct clock_event_device *clkevt = (struct clock_event_device *)dev_id; + struct timer_of *to = to_timer_of(clkevt); - writel_relaxed(0, data->base + TIM_SR); + writel_relaxed(0, timer_of_base(to) + TIM_SR); - data->evtdev.event_handler(&data->evtdev); + if (clockevent_state_periodic(clkevt)) + stm32_clock_event_set_periodic(clkevt); + else + stm32_clock_event_shutdown(clkevt); + + clkevt->event_handler(clkevt); return IRQ_HANDLED; } -static struct stm32_clock_event_ddata clock_event_ddata = { - .evtdev = { - .name = "stm32 clockevent", - .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .set_state_shutdown = stm32_clock_event_shutdown, - .set_state_periodic = stm32_clock_event_set_periodic, - .set_state_oneshot = stm32_clock_event_shutdown, - .tick_resume = stm32_clock_event_shutdown, - .set_next_event = stm32_clock_event_set_next_event, - .rating = 200, - }, -}; - -static int __init stm32_clockevent_init(struct device_node *np) +/** + * stm32_timer_width - Sort out the timer width (32/16) + * @to: a pointer to a timer-of structure + * + * Write the 32-bit max value and read/return the result. If the timer + * is 32 bits wide, the result will be UINT_MAX, otherwise it will + * be truncated by the 16-bit register to USHRT_MAX. + * + */ +static void __init stm32_timer_set_width(struct timer_of *to) +{ + u32 width; + + writel_relaxed(UINT_MAX, timer_of_base(to) + TIM_ARR); + + width = readl_relaxed(timer_of_base(to) + TIM_ARR); + + stm32_timer_of_bits_set(to, width == UINT_MAX ? 32 : 16); +} + +/** + * stm32_timer_set_prescaler - Compute and set the prescaler register + * @to: a pointer to a timer-of structure + * + * Depending on the timer width, compute the prescaler to always + * target a 10MHz timer rate for 16 bits. 32-bit timers are + * considered precise and long enough to not use the prescaler. + */ +static void __init stm32_timer_set_prescaler(struct timer_of *to) +{ + int prescaler = 1; + + if (stm32_timer_of_bits_get(to) != 32) { + prescaler = DIV_ROUND_CLOSEST(timer_of_rate(to), + TIM_PSC_CLKRATE); + /* + * The prescaler register is an u16, the variable + * can't be greater than TIM_PSC_MAX, let's cap it in + * this case. + */ + prescaler = prescaler < TIM_PSC_MAX ? prescaler : TIM_PSC_MAX; + } + + writel_relaxed(prescaler - 1, timer_of_base(to) + TIM_PSC); + writel_relaxed(TIM_EGR_UG, timer_of_base(to) + TIM_EGR); + writel_relaxed(0, timer_of_base(to) + TIM_SR); + + /* Adjust rate and period given the prescaler value */ + to->of_clk.rate = DIV_ROUND_CLOSEST(to->of_clk.rate, prescaler); + to->of_clk.period = DIV_ROUND_UP(to->of_clk.rate, HZ); +} + +static int __init stm32_clocksource_init(struct timer_of *to) +{ + u32 bits = stm32_timer_of_bits_get(to); + const char *name = to->np->full_name; + + /* + * This driver allows to register several timers and relies on + * the generic time framework to select the right one. + * However, nothing allows to do the same for the + * sched_clock. We are not interested in a sched_clock for the + * 16-bit timers but only for the 32-bit one, so if no 32-bit + * timer is registered yet, we select this 32-bit timer as a + * sched_clock. + */ + if (bits == 32 && !stm32_timer_cnt) { + + /* + * Start immediately the counter as we will be using + * it right after. + */ + stm32_timer_start(to); + + stm32_timer_cnt = timer_of_base(to) + TIM_CNT; + sched_clock_register(stm32_read_sched_clock, bits, timer_of_rate(to)); + pr_info("%s: STM32 sched_clock registered\n", name); + + stm32_timer_delay.read_current_timer = stm32_read_delay; + stm32_timer_delay.freq = timer_of_rate(to); + register_current_timer_delay(&stm32_timer_delay); + pr_info("%s: STM32 delay timer registered\n", name); + } + + return clocksource_mmio_init(timer_of_base(to) + TIM_CNT, name, + timer_of_rate(to), bits == 32 ? 250 : 100, + bits, clocksource_mmio_readl_up); +} + +static void __init stm32_clockevent_init(struct timer_of *to) +{ + u32 bits = stm32_timer_of_bits_get(to); + + to->clkevt.name = to->np->full_name; + to->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; + to->clkevt.set_state_shutdown = stm32_clock_event_shutdown; + to->clkevt.set_state_periodic = stm32_clock_event_set_periodic; + to->clkevt.set_state_oneshot = stm32_clock_event_set_oneshot; + to->clkevt.tick_resume = stm32_clock_event_shutdown; + to->clkevt.set_next_event = stm32_clock_event_set_next_event; + to->clkevt.rating = bits == 32 ? 250 : 100; + + clockevents_config_and_register(&to->clkevt, timer_of_rate(to), 0x1, + (1 << bits) - 1); + + pr_info("%pOF: STM32 clockevent driver initialized (%d bits)\n", + to->np, bits); +} + +static int __init stm32_timer_init(struct device_node *node) { - struct stm32_clock_event_ddata *data = &clock_event_ddata; - struct clk *clk; struct reset_control *rstc; - unsigned long rate, max_delta; - int irq, ret, bits, prescaler = 1; + struct timer_of *to; + int ret; - clk = of_clk_get(np, 0); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - pr_err("failed to get clock for clockevent (%d)\n", ret); - goto err_clk_get; - } + to = kzalloc(sizeof(*to), GFP_KERNEL); + if (!to) + return -ENOMEM; - ret = clk_prepare_enable(clk); - if (ret) { - pr_err("failed to enable timer clock for clockevent (%d)\n", - ret); - goto err_clk_enable; - } + to->flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE; + to->of_irq.handler = stm32_clock_event_handler; - rate = clk_get_rate(clk); + ret = timer_of_init(node, to); + if (ret) + goto err; - rstc = of_reset_control_get(np, NULL); + to->private_data = kzalloc(sizeof(struct stm32_timer_private), + GFP_KERNEL); + if (!to->private_data) + goto deinit; + + rstc = of_reset_control_get(node, NULL); if (!IS_ERR(rstc)) { reset_control_assert(rstc); reset_control_deassert(rstc); } - data->base = of_iomap(np, 0); - if (!data->base) { - ret = -ENXIO; - pr_err("failed to map registers for clockevent\n"); - goto err_iomap; - } + stm32_timer_set_width(to); - irq = irq_of_parse_and_map(np, 0); - if (!irq) { - ret = -EINVAL; - pr_err("%pOF: failed to get irq.\n", np); - goto err_get_irq; - } + stm32_timer_set_prescaler(to); - /* Detect whether the timer is 16 or 32 bits */ - writel_relaxed(~0U, data->base + TIM_ARR); - max_delta = readl_relaxed(data->base + TIM_ARR); - if (max_delta == ~0U) { - prescaler = 1; - bits = 32; - } else { - prescaler = 1024; - bits = 16; - } - writel_relaxed(0, data->base + TIM_ARR); + ret = stm32_clocksource_init(to); + if (ret) + goto deinit; - writel_relaxed(prescaler - 1, data->base + TIM_PSC); - writel_relaxed(TIM_EGR_UG, data->base + TIM_EGR); - writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER); - writel_relaxed(0, data->base + TIM_SR); + stm32_clockevent_init(to); + return 0; - data->periodic_top = DIV_ROUND_CLOSEST(rate, prescaler * HZ); - - clockevents_config_and_register(&data->evtdev, - DIV_ROUND_CLOSEST(rate, prescaler), - 0x1, max_delta); - - ret = request_irq(irq, stm32_clock_event_handler, IRQF_TIMER, - "stm32 clockevent", data); - if (ret) { - pr_err("%pOF: failed to request irq.\n", np); - goto err_get_irq; - } - - pr_info("%pOF: STM32 clockevent driver initialized (%d bits)\n", - np, bits); - - return ret; - -err_get_irq: - iounmap(data->base); -err_iomap: - clk_disable_unprepare(clk); -err_clk_enable: - clk_put(clk); -err_clk_get: +deinit: + timer_of_cleanup(to); +err: + kfree(to); return ret; } -TIMER_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init); +TIMER_OF_DECLARE(stm32, "st,stm32-timer", stm32_timer_init); diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index d8addbce40bc..608af20a3494 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -239,16 +239,6 @@ if PPC32 || PPC64 source "drivers/cpufreq/Kconfig.powerpc" endif -if AVR32 -config AVR32_AT32AP_CPUFREQ - bool "CPU frequency driver for AT32AP" - depends on PLATFORM_AT32AP - default n - help - This enables the CPU frequency driver for AT32AP processors. - If in doubt, say N. -endif - if IA64 config IA64_ACPI_CPUFREQ tristate "ACPI Processor P-States driver" diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index bdce4488ded1..3a88e33b0cfe 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -2,6 +2,29 @@ # ARM CPU Frequency scaling drivers # +config ACPI_CPPC_CPUFREQ + tristate "CPUFreq driver based on the ACPI CPPC spec" + depends on ACPI_PROCESSOR + select ACPI_CPPC_LIB + help + This adds a CPUFreq driver which uses CPPC methods + as described in the ACPIv5.1 spec. CPPC stands for + Collaborative Processor Performance Controls. It + is based on an abstract continuous scale of CPU + performance values which allows the remote power + processor to flexibly optimize for power and + performance. CPPC relies on power management firmware + support for its operation. + + If in doubt, say N. + +config ARM_ARMADA_37XX_CPUFREQ + tristate "Armada 37xx CPUFreq support" + depends on ARCH_MVEBU + help + This adds the CPUFreq driver support for Marvell Armada 37xx SoCs. + The Armada 37xx PMU supports 4 frequency and VDD levels. + # big LITTLE core layer and glue drivers config ARM_BIG_LITTLE_CPUFREQ tristate "Generic ARM big LITTLE CPUfreq driver" @@ -12,6 +35,30 @@ config ARM_BIG_LITTLE_CPUFREQ help This enables the Generic CPUfreq driver for ARM big.LITTLE platforms. +config ARM_DT_BL_CPUFREQ + tristate "Generic probing via DT for ARM big LITTLE CPUfreq driver" + depends on ARM_BIG_LITTLE_CPUFREQ && OF + help + This enables probing via DT for Generic CPUfreq driver for ARM + big.LITTLE platform. This gets frequency tables from DT. + +config ARM_SCPI_CPUFREQ + tristate "SCPI based CPUfreq driver" + depends on ARM_BIG_LITTLE_CPUFREQ && ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI + help + This adds the CPUfreq driver support for ARM big.LITTLE platforms + using SCPI protocol for CPU power management. + + This driver uses SCPI Message Protocol driver to interact with the + firmware providing the CPU DVFS functionality. + +config ARM_VEXPRESS_SPC_CPUFREQ + tristate "Versatile Express SPC based CPUfreq driver" + depends on ARM_BIG_LITTLE_CPUFREQ && ARCH_VEXPRESS_SPC + help + This add the CPUfreq driver support for Versatile Express + big.LITTLE platforms using SPC for power management. + config ARM_BRCMSTB_AVS_CPUFREQ tristate "Broadcom STB AVS CPUfreq driver" depends on ARCH_BRCMSTB || COMPILE_TEST @@ -33,20 +80,6 @@ config ARM_BRCMSTB_AVS_CPUFREQ_DEBUG If in doubt, say N. -config ARM_DT_BL_CPUFREQ - tristate "Generic probing via DT for ARM big LITTLE CPUfreq driver" - depends on ARM_BIG_LITTLE_CPUFREQ && OF - help - This enables probing via DT for Generic CPUfreq driver for ARM - big.LITTLE platform. This gets frequency tables from DT. - -config ARM_VEXPRESS_SPC_CPUFREQ - tristate "Versatile Express SPC based CPUfreq driver" - depends on ARM_BIG_LITTLE_CPUFREQ && ARCH_VEXPRESS_SPC - help - This add the CPUfreq driver support for Versatile Express - big.LITTLE platforms using SPC for power management. - config ARM_EXYNOS5440_CPUFREQ tristate "SAMSUNG EXYNOS5440" depends on SOC_EXYNOS5440 @@ -205,16 +238,6 @@ config ARM_SA1100_CPUFREQ config ARM_SA1110_CPUFREQ bool -config ARM_SCPI_CPUFREQ - tristate "SCPI based CPUfreq driver" - depends on ARM_BIG_LITTLE_CPUFREQ && ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI - help - This adds the CPUfreq driver support for ARM big.LITTLE platforms - using SCPI protocol for CPU power management. - - This driver uses SCPI Message Protocol driver to interact with the - firmware providing the CPU DVFS functionality. - config ARM_SPEAR_CPUFREQ bool "SPEAr CPUFreq support" depends on PLAT_SPEAR @@ -275,20 +298,3 @@ config ARM_PXA2xx_CPUFREQ This add the CPUFreq driver support for Intel PXA2xx SOCs. If in doubt, say N. - -config ACPI_CPPC_CPUFREQ - tristate "CPUFreq driver based on the ACPI CPPC spec" - depends on ACPI_PROCESSOR - select ACPI_CPPC_LIB - default n - help - This adds a CPUFreq driver which uses CPPC methods - as described in the ACPIv5.1 spec. CPPC stands for - Collaborative Processor Performance Controls. It - is based on an abstract continuous scale of CPU - performance values which allows the remote power - processor to flexibly optimize for power and - performance. CPPC relies on power management firmware - support for its operation. - - If in doubt, say N. diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 812f9e0d01a3..c60c1e141d9d 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -52,23 +52,26 @@ obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ) += arm_big_little.o # LITTLE drivers, so that it is probed last. obj-$(CONFIG_ARM_DT_BL_CPUFREQ) += arm_big_little_dt.o +obj-$(CONFIG_ARM_ARMADA_37XX_CPUFREQ) += armada-37xx-cpufreq.o obj-$(CONFIG_ARM_BRCMSTB_AVS_CPUFREQ) += brcmstb-avs-cpufreq.o +obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o obj-$(CONFIG_ARM_MEDIATEK_CPUFREQ) += mediatek-cpufreq.o +obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o -obj-$(CONFIG_ARM_S3C24XX_CPUFREQ) += s3c24xx-cpufreq.o -obj-$(CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS) += s3c24xx-cpufreq-debugfs.o obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o obj-$(CONFIG_ARM_S3C2440_CPUFREQ) += s3c2440-cpufreq.o obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o +obj-$(CONFIG_ARM_S3C24XX_CPUFREQ) += s3c24xx-cpufreq.o +obj-$(CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS) += s3c24xx-cpufreq-debugfs.o obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o @@ -81,8 +84,6 @@ obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += tegra186-cpufreq.o obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o -obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o -obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o ################################################################################## @@ -99,7 +100,6 @@ obj-$(CONFIG_POWERNV_CPUFREQ) += powernv-cpufreq.o ################################################################################## # Other platform drivers -obj-$(CONFIG_AVR32_AT32AP_CPUFREQ) += at32ap-cpufreq.o obj-$(CONFIG_BFIN_CPU_FREQ) += blackfin-cpufreq.o obj-$(CONFIG_BMIPS_CPUFREQ) += bmips-cpufreq.o obj-$(CONFIG_CRIS_MACH_ARTPEC3) += cris-artpec3-cpufreq.o diff --git a/drivers/cpufreq/amd_freq_sensitivity.c b/drivers/cpufreq/amd_freq_sensitivity.c index 042023bbbf62..be926d9a66e5 100644 --- a/drivers/cpufreq/amd_freq_sensitivity.c +++ b/drivers/cpufreq/amd_freq_sensitivity.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -109,12 +110,18 @@ out: static int __init amd_freq_sensitivity_init(void) { u64 val; + struct pci_dev *pcidev; if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) return -ENODEV; - if (!static_cpu_has(X86_FEATURE_PROC_FEEDBACK)) - return -ENODEV; + pcidev = pci_get_device(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_KERNCZ_SMBUS, NULL); + + if (!pcidev) { + if (!static_cpu_has(X86_FEATURE_PROC_FEEDBACK)) + return -ENODEV; + } if (rdmsrl_safe(MSR_AMD64_FREQ_SENSITIVITY_ACTUAL, &val)) return -ENODEV; diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c index 65ec5f01aa8d..c56b57dcfda5 100644 --- a/drivers/cpufreq/arm_big_little.c +++ b/drivers/cpufreq/arm_big_little.c @@ -526,34 +526,13 @@ static int bL_cpufreq_exit(struct cpufreq_policy *policy) static void bL_cpufreq_ready(struct cpufreq_policy *policy) { - struct device *cpu_dev = get_cpu_device(policy->cpu); int cur_cluster = cpu_to_cluster(policy->cpu); - struct device_node *np; /* Do not register a cpu_cooling device if we are in IKS mode */ if (cur_cluster >= MAX_CLUSTERS) return; - np = of_node_get(cpu_dev->of_node); - if (WARN_ON(!np)) - return; - - if (of_find_property(np, "#cooling-cells", NULL)) { - u32 power_coefficient = 0; - - of_property_read_u32(np, "dynamic-power-coefficient", - &power_coefficient); - - cdev[cur_cluster] = of_cpufreq_power_cooling_register(np, - policy, power_coefficient, NULL); - if (IS_ERR(cdev[cur_cluster])) { - dev_err(cpu_dev, - "running cpufreq without cooling device: %ld\n", - PTR_ERR(cdev[cur_cluster])); - cdev[cur_cluster] = NULL; - } - } - of_node_put(np); + cdev[cur_cluster] = of_cpufreq_cooling_register(policy); } static struct cpufreq_driver bL_cpufreq_driver = { diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c new file mode 100644 index 000000000000..c6ebc88a7d8d --- /dev/null +++ b/drivers/cpufreq/armada-37xx-cpufreq.c @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * CPU frequency scaling support for Armada 37xx platform. + * + * Copyright (C) 2017 Marvell + * + * Gregory CLEMENT + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Power management in North Bridge register set */ +#define ARMADA_37XX_NB_L0L1 0x18 +#define ARMADA_37XX_NB_L2L3 0x1C +#define ARMADA_37XX_NB_TBG_DIV_OFF 13 +#define ARMADA_37XX_NB_TBG_DIV_MASK 0x7 +#define ARMADA_37XX_NB_CLK_SEL_OFF 11 +#define ARMADA_37XX_NB_CLK_SEL_MASK 0x1 +#define ARMADA_37XX_NB_CLK_SEL_TBG 0x1 +#define ARMADA_37XX_NB_TBG_SEL_OFF 9 +#define ARMADA_37XX_NB_TBG_SEL_MASK 0x3 +#define ARMADA_37XX_NB_VDD_SEL_OFF 6 +#define ARMADA_37XX_NB_VDD_SEL_MASK 0x3 +#define ARMADA_37XX_NB_CONFIG_SHIFT 16 +#define ARMADA_37XX_NB_DYN_MOD 0x24 +#define ARMADA_37XX_NB_CLK_SEL_EN BIT(26) +#define ARMADA_37XX_NB_TBG_EN BIT(28) +#define ARMADA_37XX_NB_DIV_EN BIT(29) +#define ARMADA_37XX_NB_VDD_EN BIT(30) +#define ARMADA_37XX_NB_DFS_EN BIT(31) +#define ARMADA_37XX_NB_CPU_LOAD 0x30 +#define ARMADA_37XX_NB_CPU_LOAD_MASK 0x3 +#define ARMADA_37XX_DVFS_LOAD_0 0 +#define ARMADA_37XX_DVFS_LOAD_1 1 +#define ARMADA_37XX_DVFS_LOAD_2 2 +#define ARMADA_37XX_DVFS_LOAD_3 3 + +/* + * On Armada 37xx the Power management manages 4 level of CPU load, + * each level can be associated with a CPU clock source, a CPU + * divider, a VDD level, etc... + */ +#define LOAD_LEVEL_NR 4 + +struct armada_37xx_dvfs { + u32 cpu_freq_max; + u8 divider[LOAD_LEVEL_NR]; +}; + +static struct armada_37xx_dvfs armada_37xx_dvfs[] = { + {.cpu_freq_max = 1200*1000*1000, .divider = {1, 2, 4, 6} }, + {.cpu_freq_max = 1000*1000*1000, .divider = {1, 2, 4, 5} }, + {.cpu_freq_max = 800*1000*1000, .divider = {1, 2, 3, 4} }, + {.cpu_freq_max = 600*1000*1000, .divider = {2, 4, 5, 6} }, +}; + +static struct armada_37xx_dvfs *armada_37xx_cpu_freq_info_get(u32 freq) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(armada_37xx_dvfs); i++) { + if (freq == armada_37xx_dvfs[i].cpu_freq_max) + return &armada_37xx_dvfs[i]; + } + + pr_err("Unsupported CPU frequency %d MHz\n", freq/1000000); + return NULL; +} + +/* + * Setup the four level managed by the hardware. Once the four level + * will be configured then the DVFS will be enabled. + */ +static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base, + struct clk *clk, u8 *divider) +{ + int load_lvl; + struct clk *parent; + + for (load_lvl = 0; load_lvl < LOAD_LEVEL_NR; load_lvl++) { + unsigned int reg, mask, val, offset = 0; + + if (load_lvl <= ARMADA_37XX_DVFS_LOAD_1) + reg = ARMADA_37XX_NB_L0L1; + else + reg = ARMADA_37XX_NB_L2L3; + + if (load_lvl == ARMADA_37XX_DVFS_LOAD_0 || + load_lvl == ARMADA_37XX_DVFS_LOAD_2) + offset += ARMADA_37XX_NB_CONFIG_SHIFT; + + /* Set cpu clock source, for all the level we use TBG */ + val = ARMADA_37XX_NB_CLK_SEL_TBG << ARMADA_37XX_NB_CLK_SEL_OFF; + mask = (ARMADA_37XX_NB_CLK_SEL_MASK + << ARMADA_37XX_NB_CLK_SEL_OFF); + + /* + * Set cpu divider based on the pre-computed array in + * order to have balanced step. + */ + val |= divider[load_lvl] << ARMADA_37XX_NB_TBG_DIV_OFF; + mask |= (ARMADA_37XX_NB_TBG_DIV_MASK + << ARMADA_37XX_NB_TBG_DIV_OFF); + + /* Set VDD divider which is actually the load level. */ + val |= load_lvl << ARMADA_37XX_NB_VDD_SEL_OFF; + mask |= (ARMADA_37XX_NB_VDD_SEL_MASK + << ARMADA_37XX_NB_VDD_SEL_OFF); + + val <<= offset; + mask <<= offset; + + regmap_update_bits(base, reg, mask, val); + } + + /* + * Set cpu clock source, for all the level we keep the same + * clock source that the one already configured. For this one + * we need to use the clock framework + */ + parent = clk_get_parent(clk); + clk_set_parent(clk, parent); +} + +static void __init armada37xx_cpufreq_disable_dvfs(struct regmap *base) +{ + unsigned int reg = ARMADA_37XX_NB_DYN_MOD, + mask = ARMADA_37XX_NB_DFS_EN; + + regmap_update_bits(base, reg, mask, 0); +} + +static void __init armada37xx_cpufreq_enable_dvfs(struct regmap *base) +{ + unsigned int val, reg = ARMADA_37XX_NB_CPU_LOAD, + mask = ARMADA_37XX_NB_CPU_LOAD_MASK; + + /* Start with the highest load (0) */ + val = ARMADA_37XX_DVFS_LOAD_0; + regmap_update_bits(base, reg, mask, val); + + /* Now enable DVFS for the CPUs */ + reg = ARMADA_37XX_NB_DYN_MOD; + mask = ARMADA_37XX_NB_CLK_SEL_EN | ARMADA_37XX_NB_TBG_EN | + ARMADA_37XX_NB_DIV_EN | ARMADA_37XX_NB_VDD_EN | + ARMADA_37XX_NB_DFS_EN; + + regmap_update_bits(base, reg, mask, mask); +} + +static int __init armada37xx_cpufreq_driver_init(void) +{ + struct armada_37xx_dvfs *dvfs; + struct platform_device *pdev; + unsigned int cur_frequency; + struct regmap *nb_pm_base; + struct device *cpu_dev; + int load_lvl, ret; + struct clk *clk; + + nb_pm_base = + syscon_regmap_lookup_by_compatible("marvell,armada-3700-nb-pm"); + + if (IS_ERR(nb_pm_base)) + return -ENODEV; + + /* Before doing any configuration on the DVFS first, disable it */ + armada37xx_cpufreq_disable_dvfs(nb_pm_base); + + /* + * On CPU 0 register the operating points supported (which are + * the nominal CPU frequency and full integer divisions of + * it). + */ + cpu_dev = get_cpu_device(0); + if (!cpu_dev) { + dev_err(cpu_dev, "Cannot get CPU\n"); + return -ENODEV; + } + + clk = clk_get(cpu_dev, 0); + if (IS_ERR(clk)) { + dev_err(cpu_dev, "Cannot get clock for CPU0\n"); + return PTR_ERR(clk); + } + + /* Get nominal (current) CPU frequency */ + cur_frequency = clk_get_rate(clk); + if (!cur_frequency) { + dev_err(cpu_dev, "Failed to get clock rate for CPU\n"); + return -EINVAL; + } + + dvfs = armada_37xx_cpu_freq_info_get(cur_frequency); + if (!dvfs) + return -EINVAL; + + armada37xx_cpufreq_dvfs_setup(nb_pm_base, clk, dvfs->divider); + + for (load_lvl = ARMADA_37XX_DVFS_LOAD_0; load_lvl < LOAD_LEVEL_NR; + load_lvl++) { + unsigned long freq = cur_frequency / dvfs->divider[load_lvl]; + + ret = dev_pm_opp_add(cpu_dev, freq, 0); + if (ret) { + /* clean-up the already added opp before leaving */ + while (load_lvl-- > ARMADA_37XX_DVFS_LOAD_0) { + freq = cur_frequency / dvfs->divider[load_lvl]; + dev_pm_opp_remove(cpu_dev, freq); + } + return ret; + } + } + + /* Now that everything is setup, enable the DVFS at hardware level */ + armada37xx_cpufreq_enable_dvfs(nb_pm_base); + + pdev = platform_device_register_simple("cpufreq-dt", -1, NULL, 0); + + return PTR_ERR_OR_ZERO(pdev); +} +/* late_initcall, to guarantee the driver is loaded after A37xx clock driver */ +late_initcall(armada37xx_cpufreq_driver_init); + +MODULE_AUTHOR("Gregory CLEMENT "); +MODULE_DESCRIPTION("Armada 37xx cpufreq driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/cpufreq/at32ap-cpufreq.c b/drivers/cpufreq/at32ap-cpufreq.c deleted file mode 100644 index 7b612c8bb09e..000000000000 --- a/drivers/cpufreq/at32ap-cpufreq.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2004-2007 Atmel Corporation - * - * Based on MIPS implementation arch/mips/kernel/time.c - * Copyright 2001 MontaVista Software Inc. - * - * 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. - */ - -/*#define DEBUG*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct cpufreq_frequency_table *freq_table; - -static unsigned int ref_freq; -static unsigned long loops_per_jiffy_ref; - -static int at32_set_target(struct cpufreq_policy *policy, unsigned int index) -{ - unsigned int old_freq, new_freq; - - old_freq = policy->cur; - new_freq = freq_table[index].frequency; - - if (!ref_freq) { - ref_freq = old_freq; - loops_per_jiffy_ref = boot_cpu_data.loops_per_jiffy; - } - - if (old_freq < new_freq) - boot_cpu_data.loops_per_jiffy = cpufreq_scale( - loops_per_jiffy_ref, ref_freq, new_freq); - clk_set_rate(policy->clk, new_freq * 1000); - if (new_freq < old_freq) - boot_cpu_data.loops_per_jiffy = cpufreq_scale( - loops_per_jiffy_ref, ref_freq, new_freq); - - return 0; -} - -static int at32_cpufreq_driver_init(struct cpufreq_policy *policy) -{ - unsigned int frequency, rate, min_freq; - struct clk *cpuclk; - int retval, steps, i; - - if (policy->cpu != 0) - return -EINVAL; - - cpuclk = clk_get(NULL, "cpu"); - if (IS_ERR(cpuclk)) { - pr_debug("cpufreq: could not get CPU clk\n"); - retval = PTR_ERR(cpuclk); - goto out_err; - } - - min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000; - frequency = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; - policy->cpuinfo.transition_latency = 0; - - /* - * AVR32 CPU frequency rate scales in power of two between maximum and - * minimum, also add space for the table end marker. - * - * Further validate that the frequency is usable, and append it to the - * frequency table. - */ - steps = fls(frequency / min_freq) + 1; - freq_table = kzalloc(steps * sizeof(struct cpufreq_frequency_table), - GFP_KERNEL); - if (!freq_table) { - retval = -ENOMEM; - goto out_err_put_clk; - } - - for (i = 0; i < (steps - 1); i++) { - rate = clk_round_rate(cpuclk, frequency * 1000) / 1000; - - if (rate != frequency) - freq_table[i].frequency = CPUFREQ_ENTRY_INVALID; - else - freq_table[i].frequency = frequency; - - frequency /= 2; - } - - policy->clk = cpuclk; - freq_table[steps - 1].frequency = CPUFREQ_TABLE_END; - - retval = cpufreq_table_validate_and_show(policy, freq_table); - if (!retval) { - printk("cpufreq: AT32AP CPU frequency driver\n"); - return 0; - } - - kfree(freq_table); -out_err_put_clk: - clk_put(cpuclk); -out_err: - return retval; -} - -static struct cpufreq_driver at32_driver = { - .name = "at32ap", - .init = at32_cpufreq_driver_init, - .verify = cpufreq_generic_frequency_table_verify, - .target_index = at32_set_target, - .get = cpufreq_generic_get, - .flags = CPUFREQ_STICKY, -}; - -static int __init at32_cpufreq_init(void) -{ - return cpufreq_register_driver(&at32_driver); -} -late_initcall(at32_cpufreq_init); diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index ecc56e26f8f6..3b585e4bfac5 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -108,6 +108,14 @@ static const struct of_device_id blacklist[] __initconst = { { .compatible = "marvell,armadaxp", }, + { .compatible = "mediatek,mt2701", }, + { .compatible = "mediatek,mt2712", }, + { .compatible = "mediatek,mt7622", }, + { .compatible = "mediatek,mt7623", }, + { .compatible = "mediatek,mt817x", }, + { .compatible = "mediatek,mt8173", }, + { .compatible = "mediatek,mt8176", }, + { .compatible = "nvidia,tegra124", }, { .compatible = "st,stih407", }, diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 545946ad0752..de3d104c25d7 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -319,33 +319,8 @@ static int cpufreq_exit(struct cpufreq_policy *policy) static void cpufreq_ready(struct cpufreq_policy *policy) { struct private_data *priv = policy->driver_data; - struct device_node *np = of_node_get(priv->cpu_dev->of_node); - if (WARN_ON(!np)) - return; - - /* - * For now, just loading the cooling device; - * thermal DT code takes care of matching them. - */ - if (of_find_property(np, "#cooling-cells", NULL)) { - u32 power_coefficient = 0; - - of_property_read_u32(np, "dynamic-power-coefficient", - &power_coefficient); - - priv->cdev = of_cpufreq_power_cooling_register(np, - policy, power_coefficient, NULL); - if (IS_ERR(priv->cdev)) { - dev_err(priv->cpu_dev, - "running cpufreq without cooling device: %ld\n", - PTR_ERR(priv->cdev)); - - priv->cdev = NULL; - } - } - - of_node_put(np); + priv->cdev = of_cpufreq_cooling_register(policy); } static struct cpufreq_driver dt_cpufreq_driver = { diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 41d148af7748..de33ebf008ad 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -601,19 +601,18 @@ static struct cpufreq_governor *find_governor(const char *str_governor) /** * cpufreq_parse_governor - parse a governor string */ -static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, - struct cpufreq_governor **governor) +static int cpufreq_parse_governor(char *str_governor, + struct cpufreq_policy *policy) { - int err = -EINVAL; - if (cpufreq_driver->setpolicy) { if (!strncasecmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { - *policy = CPUFREQ_POLICY_PERFORMANCE; - err = 0; - } else if (!strncasecmp(str_governor, "powersave", - CPUFREQ_NAME_LEN)) { - *policy = CPUFREQ_POLICY_POWERSAVE; - err = 0; + policy->policy = CPUFREQ_POLICY_PERFORMANCE; + return 0; + } + + if (!strncasecmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) { + policy->policy = CPUFREQ_POLICY_POWERSAVE; + return 0; } } else { struct cpufreq_governor *t; @@ -621,26 +620,31 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, mutex_lock(&cpufreq_governor_mutex); t = find_governor(str_governor); - - if (t == NULL) { + if (!t) { int ret; mutex_unlock(&cpufreq_governor_mutex); + ret = request_module("cpufreq_%s", str_governor); + if (ret) + return -EINVAL; + mutex_lock(&cpufreq_governor_mutex); - if (ret == 0) - t = find_governor(str_governor); - } - - if (t != NULL) { - *governor = t; - err = 0; + t = find_governor(str_governor); } + if (t && !try_module_get(t->owner)) + t = NULL; mutex_unlock(&cpufreq_governor_mutex); + + if (t) { + policy->governor = t; + return 0; + } } - return err; + + return -EINVAL; } /** @@ -760,11 +764,14 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy, if (ret != 1) return -EINVAL; - if (cpufreq_parse_governor(str_governor, &new_policy.policy, - &new_policy.governor)) + if (cpufreq_parse_governor(str_governor, &new_policy)) return -EINVAL; ret = cpufreq_set_policy(policy, &new_policy); + + if (new_policy.governor) + module_put(new_policy.governor->owner); + return ret ? ret : count; } @@ -1044,8 +1051,7 @@ static int cpufreq_init_policy(struct cpufreq_policy *policy) if (policy->last_policy) new_policy.policy = policy->last_policy; else - cpufreq_parse_governor(gov->name, &new_policy.policy, - NULL); + cpufreq_parse_governor(gov->name, &new_policy); } /* set default policy */ return cpufreq_set_policy(policy, &new_policy); @@ -1680,6 +1686,9 @@ void cpufreq_resume(void) if (!cpufreq_driver) return; + if (unlikely(!cpufreq_suspended)) + return; + cpufreq_suspended = false; if (!has_target() && !cpufreq_driver->resume) @@ -2160,7 +2169,6 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor) mutex_lock(&cpufreq_governor_mutex); list_del(&governor->governor_list); mutex_unlock(&cpufreq_governor_mutex); - return; } EXPORT_SYMBOL_GPL(cpufreq_unregister_governor); diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 1e55b5790853..1572129844a5 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -27,7 +27,7 @@ struct cpufreq_stats { unsigned int *trans_table; }; -static int cpufreq_stats_update(struct cpufreq_stats *stats) +static void cpufreq_stats_update(struct cpufreq_stats *stats) { unsigned long long cur_time = get_jiffies_64(); @@ -35,7 +35,6 @@ static int cpufreq_stats_update(struct cpufreq_stats *stats) stats->time_in_state[stats->last_index] += cur_time - stats->last_time; stats->last_time = cur_time; spin_unlock(&cpufreq_stats_lock); - return 0; } static void cpufreq_stats_clear_table(struct cpufreq_stats *stats) diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c index b6b369c22272..932caa386ece 100644 --- a/drivers/cpufreq/exynos5440-cpufreq.c +++ b/drivers/cpufreq/exynos5440-cpufreq.c @@ -115,10 +115,10 @@ static struct cpufreq_freqs freqs; static int init_div_table(void) { struct cpufreq_frequency_table *pos, *freq_tbl = dvfs_info->freq_table; - unsigned int tmp, clk_div, ema_div, freq, volt_id; + unsigned int tmp, clk_div, ema_div, freq, volt_id, idx; struct dev_pm_opp *opp; - cpufreq_for_each_entry(pos, freq_tbl) { + cpufreq_for_each_entry_idx(pos, freq_tbl, idx) { opp = dev_pm_opp_find_freq_exact(dvfs_info->dev, pos->frequency * 1000, true); if (IS_ERR(opp)) { @@ -154,8 +154,7 @@ static int init_div_table(void) tmp = (clk_div | ema_div | (volt_id << P0_7_VDD_SHIFT) | ((freq / FREQ_UNIT) << P0_7_FREQ_SHIFT)); - __raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 * - (pos - freq_tbl)); + __raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 * idx); dev_pm_opp_put(opp); } diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index 3bbbf9e6960c..6d007f824ca7 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -143,10 +143,9 @@ int cpufreq_table_index_unsorted(struct cpufreq_policy *policy, break; } - cpufreq_for_each_valid_entry(pos, table) { + cpufreq_for_each_valid_entry_idx(pos, table, i) { freq = pos->frequency; - i = pos - table; if ((freq < policy->min) || (freq > policy->max)) continue; if (freq == target_freq) { @@ -211,15 +210,16 @@ int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, unsigned int freq) { struct cpufreq_frequency_table *pos, *table = policy->freq_table; + int idx; if (unlikely(!table)) { pr_debug("%s: Unable to find frequency table\n", __func__); return -ENOENT; } - cpufreq_for_each_valid_entry(pos, table) + cpufreq_for_each_valid_entry_idx(pos, table, idx) if (pos->frequency == freq) - return pos - table; + return idx; return -EINVAL; } diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index d9b2c2de49c4..ff67859948b3 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -25,15 +25,29 @@ static struct regulator *arm_reg; static struct regulator *pu_reg; static struct regulator *soc_reg; -static struct clk *arm_clk; -static struct clk *pll1_sys_clk; -static struct clk *pll1_sw_clk; -static struct clk *step_clk; -static struct clk *pll2_pfd2_396m_clk; +enum IMX6_CPUFREQ_CLKS { + ARM, + PLL1_SYS, + STEP, + PLL1_SW, + PLL2_PFD2_396M, + /* MX6UL requires two more clks */ + PLL2_BUS, + SECONDARY_SEL, +}; +#define IMX6Q_CPUFREQ_CLK_NUM 5 +#define IMX6UL_CPUFREQ_CLK_NUM 7 -/* clk used by i.MX6UL */ -static struct clk *pll2_bus_clk; -static struct clk *secondary_sel_clk; +static int num_clks; +static struct clk_bulk_data clks[] = { + { .id = "arm" }, + { .id = "pll1_sys" }, + { .id = "step" }, + { .id = "pll1_sw" }, + { .id = "pll2_pfd2_396m" }, + { .id = "pll2_bus" }, + { .id = "secondary_sel" }, +}; static struct device *cpu_dev; static bool free_opp; @@ -53,7 +67,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) new_freq = freq_table[index].frequency; freq_hz = new_freq * 1000; - old_freq = clk_get_rate(arm_clk) / 1000; + old_freq = clk_get_rate(clks[ARM].clk) / 1000; opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); if (IS_ERR(opp)) { @@ -112,29 +126,35 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) * voltage of 528MHz, so lower the CPU frequency to one * half before changing CPU frequency. */ - clk_set_rate(arm_clk, (old_freq >> 1) * 1000); - clk_set_parent(pll1_sw_clk, pll1_sys_clk); - if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) - clk_set_parent(secondary_sel_clk, pll2_bus_clk); + clk_set_rate(clks[ARM].clk, (old_freq >> 1) * 1000); + clk_set_parent(clks[PLL1_SW].clk, clks[PLL1_SYS].clk); + if (freq_hz > clk_get_rate(clks[PLL2_PFD2_396M].clk)) + clk_set_parent(clks[SECONDARY_SEL].clk, + clks[PLL2_BUS].clk); else - clk_set_parent(secondary_sel_clk, pll2_pfd2_396m_clk); - clk_set_parent(step_clk, secondary_sel_clk); - clk_set_parent(pll1_sw_clk, step_clk); + clk_set_parent(clks[SECONDARY_SEL].clk, + clks[PLL2_PFD2_396M].clk); + clk_set_parent(clks[STEP].clk, clks[SECONDARY_SEL].clk); + clk_set_parent(clks[PLL1_SW].clk, clks[STEP].clk); + if (freq_hz > clk_get_rate(clks[PLL2_BUS].clk)) { + clk_set_rate(clks[PLL1_SYS].clk, new_freq * 1000); + clk_set_parent(clks[PLL1_SW].clk, clks[PLL1_SYS].clk); + } } else { - clk_set_parent(step_clk, pll2_pfd2_396m_clk); - clk_set_parent(pll1_sw_clk, step_clk); - if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) { - clk_set_rate(pll1_sys_clk, new_freq * 1000); - clk_set_parent(pll1_sw_clk, pll1_sys_clk); + clk_set_parent(clks[STEP].clk, clks[PLL2_PFD2_396M].clk); + clk_set_parent(clks[PLL1_SW].clk, clks[STEP].clk); + if (freq_hz > clk_get_rate(clks[PLL2_PFD2_396M].clk)) { + clk_set_rate(clks[PLL1_SYS].clk, new_freq * 1000); + clk_set_parent(clks[PLL1_SW].clk, clks[PLL1_SYS].clk); } else { /* pll1_sys needs to be enabled for divider rate change to work. */ pll1_sys_temp_enabled = true; - clk_prepare_enable(pll1_sys_clk); + clk_prepare_enable(clks[PLL1_SYS].clk); } } /* Ensure the arm clock divider is what we expect */ - ret = clk_set_rate(arm_clk, new_freq * 1000); + ret = clk_set_rate(clks[ARM].clk, new_freq * 1000); if (ret) { dev_err(cpu_dev, "failed to set clock rate: %d\n", ret); regulator_set_voltage_tol(arm_reg, volt_old, 0); @@ -143,7 +163,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) /* PLL1 is only needed until after ARM-PODF is set. */ if (pll1_sys_temp_enabled) - clk_disable_unprepare(pll1_sys_clk); + clk_disable_unprepare(clks[PLL1_SYS].clk); /* scaling down? scale voltage after frequency */ if (new_freq < old_freq) { @@ -174,7 +194,7 @@ static int imx6q_cpufreq_init(struct cpufreq_policy *policy) { int ret; - policy->clk = arm_clk; + policy->clk = clks[ARM].clk; ret = cpufreq_generic_init(policy, freq_table, transition_latency); policy->suspend_freq = policy->max; @@ -244,6 +264,43 @@ put_node: of_node_put(np); } +#define OCOTP_CFG3_6UL_SPEED_696MHZ 0x2 + +static void imx6ul_opp_check_speed_grading(struct device *dev) +{ + struct device_node *np; + void __iomem *base; + u32 val; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-ocotp"); + if (!np) + return; + + base = of_iomap(np, 0); + if (!base) { + dev_err(dev, "failed to map ocotp\n"); + goto put_node; + } + + /* + * Speed GRADING[1:0] defines the max speed of ARM: + * 2b'00: Reserved; + * 2b'01: 528000000Hz; + * 2b'10: 696000000Hz; + * 2b'11: Reserved; + * We need to set the max speed of ARM according to fuse map. + */ + val = readl_relaxed(base + OCOTP_CFG3); + val >>= OCOTP_CFG3_SPEED_SHIFT; + val &= 0x3; + if (val != OCOTP_CFG3_6UL_SPEED_696MHZ) + if (dev_pm_opp_disable(dev, 696000000)) + dev_warn(dev, "failed to disable 696MHz OPP\n"); + iounmap(base); +put_node: + of_node_put(np); +} + static int imx6q_cpufreq_probe(struct platform_device *pdev) { struct device_node *np; @@ -266,28 +323,15 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) return -ENOENT; } - arm_clk = clk_get(cpu_dev, "arm"); - pll1_sys_clk = clk_get(cpu_dev, "pll1_sys"); - pll1_sw_clk = clk_get(cpu_dev, "pll1_sw"); - step_clk = clk_get(cpu_dev, "step"); - pll2_pfd2_396m_clk = clk_get(cpu_dev, "pll2_pfd2_396m"); - if (IS_ERR(arm_clk) || IS_ERR(pll1_sys_clk) || IS_ERR(pll1_sw_clk) || - IS_ERR(step_clk) || IS_ERR(pll2_pfd2_396m_clk)) { - dev_err(cpu_dev, "failed to get clocks\n"); - ret = -ENOENT; - goto put_clk; - } - if (of_machine_is_compatible("fsl,imx6ul") || - of_machine_is_compatible("fsl,imx6ull")) { - pll2_bus_clk = clk_get(cpu_dev, "pll2_bus"); - secondary_sel_clk = clk_get(cpu_dev, "secondary_sel"); - if (IS_ERR(pll2_bus_clk) || IS_ERR(secondary_sel_clk)) { - dev_err(cpu_dev, "failed to get clocks specific to imx6ul\n"); - ret = -ENOENT; - goto put_clk; - } - } + of_machine_is_compatible("fsl,imx6ull")) + num_clks = IMX6UL_CPUFREQ_CLK_NUM; + else + num_clks = IMX6Q_CPUFREQ_CLK_NUM; + + ret = clk_bulk_get(cpu_dev, num_clks, clks); + if (ret) + goto put_node; arm_reg = regulator_get(cpu_dev, "arm"); pu_reg = regulator_get_optional(cpu_dev, "pu"); @@ -311,7 +355,10 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) goto put_reg; } - imx6q_opp_check_speed_grading(cpu_dev); + if (of_machine_is_compatible("fsl,imx6ul")) + imx6ul_opp_check_speed_grading(cpu_dev); + else + imx6q_opp_check_speed_grading(cpu_dev); /* Because we have added the OPPs here, we must free them */ free_opp = true; @@ -424,22 +471,11 @@ put_reg: regulator_put(pu_reg); if (!IS_ERR(soc_reg)) regulator_put(soc_reg); -put_clk: - if (!IS_ERR(arm_clk)) - clk_put(arm_clk); - if (!IS_ERR(pll1_sys_clk)) - clk_put(pll1_sys_clk); - if (!IS_ERR(pll1_sw_clk)) - clk_put(pll1_sw_clk); - if (!IS_ERR(step_clk)) - clk_put(step_clk); - if (!IS_ERR(pll2_pfd2_396m_clk)) - clk_put(pll2_pfd2_396m_clk); - if (!IS_ERR(pll2_bus_clk)) - clk_put(pll2_bus_clk); - if (!IS_ERR(secondary_sel_clk)) - clk_put(secondary_sel_clk); + + clk_bulk_put(num_clks, clks); +put_node: of_node_put(np); + return ret; } @@ -453,13 +489,8 @@ static int imx6q_cpufreq_remove(struct platform_device *pdev) if (!IS_ERR(pu_reg)) regulator_put(pu_reg); regulator_put(soc_reg); - clk_put(arm_clk); - clk_put(pll1_sys_clk); - clk_put(pll1_sw_clk); - clk_put(step_clk); - clk_put(pll2_pfd2_396m_clk); - clk_put(pll2_bus_clk); - clk_put(secondary_sel_clk); + + clk_bulk_put(num_clks, clks); return 0; } @@ -473,6 +504,7 @@ static struct platform_driver imx6q_cpufreq_platdrv = { }; module_platform_driver(imx6q_cpufreq_platdrv); +MODULE_ALIAS("platform:imx6q-cpufreq"); MODULE_AUTHOR("Shawn Guo "); MODULE_DESCRIPTION("Freescale i.MX6Q cpufreq driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 93a0e88bef76..6d084c61ee25 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -779,6 +779,8 @@ static int intel_pstate_hwp_save_state(struct cpufreq_policy *policy) return 0; } +static void intel_pstate_hwp_enable(struct cpudata *cpudata); + static int intel_pstate_resume(struct cpufreq_policy *policy) { if (!hwp_active) @@ -786,6 +788,9 @@ static int intel_pstate_resume(struct cpufreq_policy *policy) mutex_lock(&intel_pstate_limits_lock); + if (policy->cpu == 0) + intel_pstate_hwp_enable(all_cpu_data[policy->cpu]); + all_cpu_data[policy->cpu]->epp_policy = 0; intel_pstate_hwp_set(policy->cpu); @@ -1595,15 +1600,6 @@ static const struct pstate_funcs knl_funcs = { .get_val = core_get_val, }; -static const struct pstate_funcs bxt_funcs = { - .get_max = core_get_max_pstate, - .get_max_physical = core_get_max_pstate_physical, - .get_min = core_get_min_pstate, - .get_turbo = core_get_turbo_pstate, - .get_scaling = core_get_scaling, - .get_val = core_get_val, -}; - #define ICPU(model, policy) \ { X86_VENDOR_INTEL, 6, model, X86_FEATURE_APERFMPERF,\ (unsigned long)&policy } @@ -1627,8 +1623,9 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = { ICPU(INTEL_FAM6_BROADWELL_XEON_D, core_funcs), ICPU(INTEL_FAM6_XEON_PHI_KNL, knl_funcs), ICPU(INTEL_FAM6_XEON_PHI_KNM, knl_funcs), - ICPU(INTEL_FAM6_ATOM_GOLDMONT, bxt_funcs), - ICPU(INTEL_FAM6_ATOM_GEMINI_LAKE, bxt_funcs), + ICPU(INTEL_FAM6_ATOM_GOLDMONT, core_funcs), + ICPU(INTEL_FAM6_ATOM_GEMINI_LAKE, core_funcs), + ICPU(INTEL_FAM6_SKYLAKE_X, core_funcs), {} }; MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids); diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c index c46a12df40dd..942632a27b50 100644 --- a/drivers/cpufreq/longhaul.c +++ b/drivers/cpufreq/longhaul.c @@ -600,7 +600,7 @@ static void longhaul_setup_voltagescaling(void) /* Calculate kHz for one voltage step */ kHz_step = (highest_speed - min_vid_speed) / numvscales; - cpufreq_for_each_entry(freq_pos, longhaul_table) { + cpufreq_for_each_entry_idx(freq_pos, longhaul_table, j) { speed = freq_pos->frequency; if (speed > min_vid_speed) pos = (speed - min_vid_speed) / kHz_step + minvid.pos; @@ -609,7 +609,7 @@ static void longhaul_setup_voltagescaling(void) freq_pos->driver_data |= mV_vrm_table[pos] << 8; vid = vrm_mV_table[mV_vrm_table[pos]]; pr_info("f: %d kHz, index: %d, vid: %d mV\n", - speed, (int)(freq_pos - longhaul_table), vid.mV); + speed, j, vid.mV); } can_scale_voltage = 1; @@ -894,7 +894,7 @@ static int longhaul_cpu_init(struct cpufreq_policy *policy) if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0)) longhaul_setup_voltagescaling(); - policy->cpuinfo.transition_latency = 200000; /* nsec */ + policy->transition_delay_us = 200000; /* usec */ return cpufreq_table_validate_and_show(policy, longhaul_table); } diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c index e0d5090b303d..8c04dddd3c28 100644 --- a/drivers/cpufreq/mediatek-cpufreq.c +++ b/drivers/cpufreq/mediatek-cpufreq.c @@ -310,28 +310,8 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy, static void mtk_cpufreq_ready(struct cpufreq_policy *policy) { struct mtk_cpu_dvfs_info *info = policy->driver_data; - struct device_node *np = of_node_get(info->cpu_dev->of_node); - u32 capacitance = 0; - if (WARN_ON(!np)) - return; - - if (of_find_property(np, "#cooling-cells", NULL)) { - of_property_read_u32(np, DYNAMIC_POWER, &capacitance); - - info->cdev = of_cpufreq_power_cooling_register(np, - policy, capacitance, NULL); - - if (IS_ERR(info->cdev)) { - dev_err(info->cpu_dev, - "running cpufreq without cooling device: %ld\n", - PTR_ERR(info->cdev)); - - info->cdev = NULL; - } - } - - of_node_put(np); + info->cdev = of_cpufreq_cooling_register(policy); } static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) @@ -574,6 +554,7 @@ static struct platform_driver mtk_cpufreq_platdrv = { /* List of machines supported by this driver */ static const struct of_device_id mtk_cpufreq_machines[] __initconst = { { .compatible = "mediatek,mt2701", }, + { .compatible = "mediatek,mt2712", }, { .compatible = "mediatek,mt7622", }, { .compatible = "mediatek,mt7623", }, { .compatible = "mediatek,mt817x", }, diff --git a/drivers/cpufreq/mvebu-cpufreq.c b/drivers/cpufreq/mvebu-cpufreq.c index ed915ee85dd9..31513bd42705 100644 --- a/drivers/cpufreq/mvebu-cpufreq.c +++ b/drivers/cpufreq/mvebu-cpufreq.c @@ -76,12 +76,6 @@ static int __init armada_xp_pmsu_cpufreq_init(void) return PTR_ERR(clk); } - /* - * In case of a failure of dev_pm_opp_add(), we don't - * bother with cleaning up the registered OPP (there's - * no function to do so), and simply cancel the - * registration of the cpufreq device. - */ ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk), 0); if (ret) { clk_put(clk); @@ -91,7 +85,8 @@ static int __init armada_xp_pmsu_cpufreq_init(void) ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk) / 2, 0); if (ret) { clk_put(clk); - return ret; + dev_err(cpu_dev, "Failed to register OPPs\n"); + goto opp_register_failed; } ret = dev_pm_opp_set_sharing_cpus(cpu_dev, @@ -99,9 +94,16 @@ static int __init armada_xp_pmsu_cpufreq_init(void) if (ret) dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", __func__, ret); + clk_put(clk); } platform_device_register_simple("cpufreq-dt", -1, NULL, 0); return 0; + +opp_register_failed: + /* As registering has failed remove all the opp for all cpus */ + dev_pm_opp_cpumask_remove_table(cpu_possible_mask); + + return ret; } device_initcall(armada_xp_pmsu_cpufreq_init); diff --git a/drivers/cpufreq/pasemi-cpufreq.c b/drivers/cpufreq/pasemi-cpufreq.c index b257fc7d5204..75dfbd2a58ea 100644 --- a/drivers/cpufreq/pasemi-cpufreq.c +++ b/drivers/cpufreq/pasemi-cpufreq.c @@ -139,7 +139,7 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) struct cpufreq_frequency_table *pos; const u32 *max_freqp; u32 max_freq; - int cur_astate; + int cur_astate, idx; struct resource res; struct device_node *cpu, *dn; int err = -ENODEV; @@ -198,9 +198,9 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) pr_debug("initializing frequency table\n"); /* initialize frequency table */ - cpufreq_for_each_entry(pos, pas_freqs) { + cpufreq_for_each_entry_idx(pos, pas_freqs, idx) { pos->frequency = get_astate_freq(pos->driver_data) * 100000; - pr_debug("%d: %d\n", (int)(pos - pas_freqs), pos->frequency); + pr_debug("%d: %d\n", idx, pos->frequency); } cur_astate = get_cur_astate(policy->cpu); diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index b6d7c4c98d0a..29cdec198657 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -38,14 +39,13 @@ #include #include -#define POWERNV_MAX_PSTATES 256 +#define POWERNV_MAX_PSTATES_ORDER 8 +#define POWERNV_MAX_PSTATES (1UL << (POWERNV_MAX_PSTATES_ORDER)) #define PMSR_PSAFE_ENABLE (1UL << 30) #define PMSR_SPR_EM_DISABLE (1UL << 31) -#define PMSR_MAX(x) ((x >> 32) & 0xFF) +#define MAX_PSTATE_SHIFT 32 #define LPSTATE_SHIFT 48 #define GPSTATE_SHIFT 56 -#define GET_LPSTATE(x) (((x) >> LPSTATE_SHIFT) & 0xFF) -#define GET_GPSTATE(x) (((x) >> GPSTATE_SHIFT) & 0xFF) #define MAX_RAMP_DOWN_TIME 5120 /* @@ -94,6 +94,27 @@ struct global_pstate_info { }; static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1]; + +DEFINE_HASHTABLE(pstate_revmap, POWERNV_MAX_PSTATES_ORDER); +/** + * struct pstate_idx_revmap_data: Entry in the hashmap pstate_revmap + * indexed by a function of pstate id. + * + * @pstate_id: pstate id for this entry. + * + * @cpufreq_table_idx: Index into the powernv_freqs + * cpufreq_frequency_table for frequency + * corresponding to pstate_id. + * + * @hentry: hlist_node that hooks this entry into the pstate_revmap + * hashtable + */ +struct pstate_idx_revmap_data { + u8 pstate_id; + unsigned int cpufreq_table_idx; + struct hlist_node hentry; +}; + static bool rebooting, throttled, occ_reset; static const char * const throttle_reason[] = { @@ -148,39 +169,56 @@ static struct powernv_pstate_info { bool wof_enabled; } powernv_pstate_info; -/* Use following macros for conversions between pstate_id and index */ -static inline int idx_to_pstate(unsigned int i) +static inline u8 extract_pstate(u64 pmsr_val, unsigned int shift) +{ + return ((pmsr_val >> shift) & 0xFF); +} + +#define extract_local_pstate(x) extract_pstate(x, LPSTATE_SHIFT) +#define extract_global_pstate(x) extract_pstate(x, GPSTATE_SHIFT) +#define extract_max_pstate(x) extract_pstate(x, MAX_PSTATE_SHIFT) + +/* Use following functions for conversions between pstate_id and index */ + +/** + * idx_to_pstate : Returns the pstate id corresponding to the + * frequency in the cpufreq frequency table + * powernv_freqs indexed by @i. + * + * If @i is out of bound, this will return the pstate + * corresponding to the nominal frequency. + */ +static inline u8 idx_to_pstate(unsigned int i) { if (unlikely(i >= powernv_pstate_info.nr_pstates)) { - pr_warn_once("index %u is out of bound\n", i); + pr_warn_once("idx_to_pstate: index %u is out of bound\n", i); return powernv_freqs[powernv_pstate_info.nominal].driver_data; } return powernv_freqs[i].driver_data; } -static inline unsigned int pstate_to_idx(int pstate) +/** + * pstate_to_idx : Returns the index in the cpufreq frequencytable + * powernv_freqs for the frequency whose corresponding + * pstate id is @pstate. + * + * If no frequency corresponding to @pstate is found, + * this will return the index of the nominal + * frequency. + */ +static unsigned int pstate_to_idx(u8 pstate) { - int min = powernv_freqs[powernv_pstate_info.min].driver_data; - int max = powernv_freqs[powernv_pstate_info.max].driver_data; + unsigned int key = pstate % POWERNV_MAX_PSTATES; + struct pstate_idx_revmap_data *revmap_data; - if (min > 0) { - if (unlikely((pstate < max) || (pstate > min))) { - pr_warn_once("pstate %d is out of bound\n", pstate); - return powernv_pstate_info.nominal; - } - } else { - if (unlikely((pstate > max) || (pstate < min))) { - pr_warn_once("pstate %d is out of bound\n", pstate); - return powernv_pstate_info.nominal; - } + hash_for_each_possible(pstate_revmap, revmap_data, hentry, key) { + if (revmap_data->pstate_id == pstate) + return revmap_data->cpufreq_table_idx; } - /* - * abs() is deliberately used so that is works with - * both monotonically increasing and decreasing - * pstate values - */ - return abs(pstate - idx_to_pstate(powernv_pstate_info.max)); + + pr_warn_once("pstate_to_idx: pstate 0x%x not found\n", pstate); + return powernv_pstate_info.nominal; } static inline void reset_gpstates(struct cpufreq_policy *policy) @@ -247,7 +285,7 @@ static int init_powernv_pstates(void) powernv_pstate_info.wof_enabled = true; next: - pr_info("cpufreq pstate min %d nominal %d max %d\n", pstate_min, + pr_info("cpufreq pstate min 0x%x nominal 0x%x max 0x%x\n", pstate_min, pstate_nominal, pstate_max); pr_info("Workload Optimized Frequency is %s in the platform\n", (powernv_pstate_info.wof_enabled) ? "enabled" : "disabled"); @@ -278,19 +316,30 @@ next: powernv_pstate_info.nr_pstates = nr_pstates; pr_debug("NR PStates %d\n", nr_pstates); + for (i = 0; i < nr_pstates; i++) { u32 id = be32_to_cpu(pstate_ids[i]); u32 freq = be32_to_cpu(pstate_freqs[i]); + struct pstate_idx_revmap_data *revmap_data; + unsigned int key; pr_debug("PState id %d freq %d MHz\n", id, freq); powernv_freqs[i].frequency = freq * 1000; /* kHz */ - powernv_freqs[i].driver_data = id; + powernv_freqs[i].driver_data = id & 0xFF; + + revmap_data = (struct pstate_idx_revmap_data *) + kmalloc(sizeof(*revmap_data), GFP_KERNEL); + + revmap_data->pstate_id = id & 0xFF; + revmap_data->cpufreq_table_idx = i; + key = (revmap_data->pstate_id) % POWERNV_MAX_PSTATES; + hash_add(pstate_revmap, &revmap_data->hentry, key); if (id == pstate_max) powernv_pstate_info.max = i; - else if (id == pstate_nominal) + if (id == pstate_nominal) powernv_pstate_info.nominal = i; - else if (id == pstate_min) + if (id == pstate_min) powernv_pstate_info.min = i; if (powernv_pstate_info.wof_enabled && id == pstate_turbo) { @@ -307,14 +356,13 @@ next: } /* Returns the CPU frequency corresponding to the pstate_id. */ -static unsigned int pstate_id_to_freq(int pstate_id) +static unsigned int pstate_id_to_freq(u8 pstate_id) { int i; i = pstate_to_idx(pstate_id); if (i >= powernv_pstate_info.nr_pstates || i < 0) { - pr_warn("PState id %d outside of PState table, " - "reporting nominal id %d instead\n", + pr_warn("PState id 0x%x outside of PState table, reporting nominal id 0x%x instead\n", pstate_id, idx_to_pstate(powernv_pstate_info.nominal)); i = powernv_pstate_info.nominal; } @@ -420,8 +468,8 @@ static inline void set_pmspr(unsigned long sprn, unsigned long val) */ struct powernv_smp_call_data { unsigned int freq; - int pstate_id; - int gpstate_id; + u8 pstate_id; + u8 gpstate_id; }; /* @@ -438,22 +486,15 @@ struct powernv_smp_call_data { static void powernv_read_cpu_freq(void *arg) { unsigned long pmspr_val; - s8 local_pstate_id; struct powernv_smp_call_data *freq_data = arg; pmspr_val = get_pmspr(SPRN_PMSR); - - /* - * The local pstate id corresponds bits 48..55 in the PMSR. - * Note: Watch out for the sign! - */ - local_pstate_id = (pmspr_val >> 48) & 0xFF; - freq_data->pstate_id = local_pstate_id; + freq_data->pstate_id = extract_local_pstate(pmspr_val); freq_data->freq = pstate_id_to_freq(freq_data->pstate_id); - pr_debug("cpu %d pmsr %016lX pstate_id %d frequency %d kHz\n", - raw_smp_processor_id(), pmspr_val, freq_data->pstate_id, - freq_data->freq); + pr_debug("cpu %d pmsr %016lX pstate_id 0x%x frequency %d kHz\n", + raw_smp_processor_id(), pmspr_val, freq_data->pstate_id, + freq_data->freq); } /* @@ -515,21 +556,21 @@ static void powernv_cpufreq_throttle_check(void *data) struct chip *chip; unsigned int cpu = smp_processor_id(); unsigned long pmsr; - int pmsr_pmax; + u8 pmsr_pmax; unsigned int pmsr_pmax_idx; pmsr = get_pmspr(SPRN_PMSR); chip = this_cpu_read(chip_info); /* Check for Pmax Capping */ - pmsr_pmax = (s8)PMSR_MAX(pmsr); + pmsr_pmax = extract_max_pstate(pmsr); pmsr_pmax_idx = pstate_to_idx(pmsr_pmax); if (pmsr_pmax_idx != powernv_pstate_info.max) { if (chip->throttled) goto next; chip->throttled = true; if (pmsr_pmax_idx > powernv_pstate_info.nominal) { - pr_warn_once("CPU %d on Chip %u has Pmax(%d) reduced below nominal frequency(%d)\n", + pr_warn_once("CPU %d on Chip %u has Pmax(0x%x) reduced below that of nominal frequency(0x%x)\n", cpu, chip->id, pmsr_pmax, idx_to_pstate(powernv_pstate_info.nominal)); chip->throttle_sub_turbo++; @@ -645,8 +686,8 @@ void gpstate_timer_handler(struct timer_list *t) * value. Hence, read from PMCR to get correct data. */ val = get_pmspr(SPRN_PMCR); - freq_data.gpstate_id = (s8)GET_GPSTATE(val); - freq_data.pstate_id = (s8)GET_LPSTATE(val); + freq_data.gpstate_id = extract_global_pstate(val); + freq_data.pstate_id = extract_local_pstate(val); if (freq_data.gpstate_id == freq_data.pstate_id) { reset_gpstates(policy); spin_unlock(&gpstates->gpstate_lock); diff --git a/drivers/cpufreq/qoriq-cpufreq.c b/drivers/cpufreq/qoriq-cpufreq.c index 4ada55b8856e..0562761a3dec 100644 --- a/drivers/cpufreq/qoriq-cpufreq.c +++ b/drivers/cpufreq/qoriq-cpufreq.c @@ -275,20 +275,8 @@ static int qoriq_cpufreq_target(struct cpufreq_policy *policy, static void qoriq_cpufreq_ready(struct cpufreq_policy *policy) { struct cpu_data *cpud = policy->driver_data; - struct device_node *np = of_get_cpu_node(policy->cpu, NULL); - if (of_find_property(np, "#cooling-cells", NULL)) { - cpud->cdev = of_cpufreq_cooling_register(np, policy); - - if (IS_ERR(cpud->cdev) && PTR_ERR(cpud->cdev) != -ENOSYS) { - pr_err("cpu%d is not running as cooling device: %ld\n", - policy->cpu, PTR_ERR(cpud->cdev)); - - cpud->cdev = NULL; - } - } - - of_node_put(np); + cpud->cdev = of_cpufreq_cooling_register(policy); } static struct cpufreq_driver qoriq_cpufreq_driver = { diff --git a/drivers/cpufreq/scpi-cpufreq.c b/drivers/cpufreq/scpi-cpufreq.c index 05d299052c5c..c32a833e1b00 100644 --- a/drivers/cpufreq/scpi-cpufreq.c +++ b/drivers/cpufreq/scpi-cpufreq.c @@ -18,27 +18,89 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include +#include +#include +#include #include -#include +#include #include #include +#include #include -#include "arm_big_little.h" +struct scpi_data { + struct clk *clk; + struct device *cpu_dev; + struct thermal_cooling_device *cdev; +}; static struct scpi_ops *scpi_ops; -static int scpi_get_transition_latency(struct device *cpu_dev) +static unsigned int scpi_cpufreq_get_rate(unsigned int cpu) { - return scpi_ops->get_transition_latency(cpu_dev); + struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); + struct scpi_data *priv = policy->driver_data; + unsigned long rate = clk_get_rate(priv->clk); + + return rate / 1000; } -static int scpi_init_opp_table(const struct cpumask *cpumask) +static int +scpi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) +{ + struct scpi_data *priv = policy->driver_data; + u64 rate = policy->freq_table[index].frequency * 1000; + int ret; + + ret = clk_set_rate(priv->clk, rate); + if (!ret && (clk_get_rate(priv->clk) != rate)) + ret = -EIO; + + return ret; +} + +static int +scpi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) +{ + int cpu, domain, tdomain; + struct device *tcpu_dev; + + domain = scpi_ops->device_domain_id(cpu_dev); + if (domain < 0) + return domain; + + for_each_possible_cpu(cpu) { + if (cpu == cpu_dev->id) + continue; + + tcpu_dev = get_cpu_device(cpu); + if (!tcpu_dev) + continue; + + tdomain = scpi_ops->device_domain_id(tcpu_dev); + if (tdomain == domain) + cpumask_set_cpu(cpu, cpumask); + } + + return 0; +} + +static int scpi_cpufreq_init(struct cpufreq_policy *policy) { int ret; - struct device *cpu_dev = get_cpu_device(cpumask_first(cpumask)); + unsigned int latency; + struct device *cpu_dev; + struct scpi_data *priv; + struct cpufreq_frequency_table *freq_table; + + cpu_dev = get_cpu_device(policy->cpu); + if (!cpu_dev) { + pr_err("failed to get cpu%d device\n", policy->cpu); + return -ENODEV; + } ret = scpi_ops->add_opps_to_device(cpu_dev); if (ret) { @@ -46,32 +108,131 @@ static int scpi_init_opp_table(const struct cpumask *cpumask) return ret; } - ret = dev_pm_opp_set_sharing_cpus(cpu_dev, cpumask); - if (ret) + ret = scpi_get_sharing_cpus(cpu_dev, policy->cpus); + if (ret) { + dev_warn(cpu_dev, "failed to get sharing cpumask\n"); + return ret; + } + + ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus); + if (ret) { dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", __func__, ret); + return ret; + } + + ret = dev_pm_opp_get_opp_count(cpu_dev); + if (ret <= 0) { + dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n"); + ret = -EPROBE_DEFER; + goto out_free_opp; + } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto out_free_opp; + } + + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); + if (ret) { + dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); + goto out_free_priv; + } + + priv->cpu_dev = cpu_dev; + priv->clk = clk_get(cpu_dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(cpu_dev, "%s: Failed to get clk for cpu: %d\n", + __func__, cpu_dev->id); + ret = PTR_ERR(priv->clk); + goto out_free_cpufreq_table; + } + + policy->driver_data = priv; + + ret = cpufreq_table_validate_and_show(policy, freq_table); + if (ret) { + dev_err(cpu_dev, "%s: invalid frequency table: %d\n", __func__, + ret); + goto out_put_clk; + } + + /* scpi allows DVFS request for any domain from any CPU */ + policy->dvfs_possible_from_any_cpu = true; + + latency = scpi_ops->get_transition_latency(cpu_dev); + if (!latency) + latency = CPUFREQ_ETERNAL; + + policy->cpuinfo.transition_latency = latency; + + policy->fast_switch_possible = false; + return 0; + +out_put_clk: + clk_put(priv->clk); +out_free_cpufreq_table: + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); +out_free_priv: + kfree(priv); +out_free_opp: + dev_pm_opp_cpumask_remove_table(policy->cpus); + return ret; } -static const struct cpufreq_arm_bL_ops scpi_cpufreq_ops = { - .name = "scpi", - .get_transition_latency = scpi_get_transition_latency, - .init_opp_table = scpi_init_opp_table, - .free_opp_table = dev_pm_opp_cpumask_remove_table, +static int scpi_cpufreq_exit(struct cpufreq_policy *policy) +{ + struct scpi_data *priv = policy->driver_data; + + cpufreq_cooling_unregister(priv->cdev); + clk_put(priv->clk); + dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); + kfree(priv); + dev_pm_opp_cpumask_remove_table(policy->related_cpus); + + return 0; +} + +static void scpi_cpufreq_ready(struct cpufreq_policy *policy) +{ + struct scpi_data *priv = policy->driver_data; + + priv->cdev = of_cpufreq_cooling_register(policy); +} + +static struct cpufreq_driver scpi_cpufreq_driver = { + .name = "scpi-cpufreq", + .flags = CPUFREQ_STICKY | CPUFREQ_HAVE_GOVERNOR_PER_POLICY | + CPUFREQ_NEED_INITIAL_FREQ_CHECK, + .verify = cpufreq_generic_frequency_table_verify, + .attr = cpufreq_generic_attr, + .get = scpi_cpufreq_get_rate, + .init = scpi_cpufreq_init, + .exit = scpi_cpufreq_exit, + .ready = scpi_cpufreq_ready, + .target_index = scpi_cpufreq_set_target, }; static int scpi_cpufreq_probe(struct platform_device *pdev) { + int ret; + scpi_ops = get_scpi_ops(); if (!scpi_ops) return -EIO; - return bL_cpufreq_register(&scpi_cpufreq_ops); + ret = cpufreq_register_driver(&scpi_cpufreq_driver); + if (ret) + dev_err(&pdev->dev, "%s: registering cpufreq failed, err: %d\n", + __func__, ret); + return ret; } static int scpi_cpufreq_remove(struct platform_device *pdev) { - bL_cpufreq_unregister(&scpi_cpufreq_ops); + cpufreq_unregister_driver(&scpi_cpufreq_driver); scpi_ops = NULL; return 0; } diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c index 923317f03b4b..a099b7bf74cd 100644 --- a/drivers/cpufreq/ti-cpufreq.c +++ b/drivers/cpufreq/ti-cpufreq.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,7 @@ struct ti_cpufreq_soc_data { unsigned long efuse_mask; unsigned long efuse_shift; unsigned long rev_offset; + bool multi_regulator; }; struct ti_cpufreq_data { @@ -57,6 +59,7 @@ struct ti_cpufreq_data { struct device_node *opp_node; struct regmap *syscon; const struct ti_cpufreq_soc_data *soc_data; + struct opp_table *opp_table; }; static unsigned long amx3_efuse_xlate(struct ti_cpufreq_data *opp_data, @@ -95,6 +98,7 @@ static struct ti_cpufreq_soc_data am3x_soc_data = { .efuse_offset = 0x07fc, .efuse_mask = 0x1fff, .rev_offset = 0x600, + .multi_regulator = false, }; static struct ti_cpufreq_soc_data am4x_soc_data = { @@ -103,6 +107,7 @@ static struct ti_cpufreq_soc_data am4x_soc_data = { .efuse_offset = 0x0610, .efuse_mask = 0x3f, .rev_offset = 0x600, + .multi_regulator = false, }; static struct ti_cpufreq_soc_data dra7_soc_data = { @@ -111,6 +116,7 @@ static struct ti_cpufreq_soc_data dra7_soc_data = { .efuse_mask = 0xf80000, .efuse_shift = 19, .rev_offset = 0x204, + .multi_regulator = true, }; /** @@ -195,12 +201,14 @@ static const struct of_device_id ti_cpufreq_of_match[] = { {}, }; -static int ti_cpufreq_init(void) +static int ti_cpufreq_probe(struct platform_device *pdev) { u32 version[VERSION_COUNT]; struct device_node *np; const struct of_device_id *match; + struct opp_table *ti_opp_table; struct ti_cpufreq_data *opp_data; + const char * const reg_names[] = {"vdd", "vbb"}; int ret; np = of_find_node_by_path("/"); @@ -247,16 +255,29 @@ static int ti_cpufreq_init(void) if (ret) goto fail_put_node; - ret = PTR_ERR_OR_ZERO(dev_pm_opp_set_supported_hw(opp_data->cpu_dev, - version, VERSION_COUNT)); - if (ret) { + ti_opp_table = dev_pm_opp_set_supported_hw(opp_data->cpu_dev, + version, VERSION_COUNT); + if (IS_ERR(ti_opp_table)) { dev_err(opp_data->cpu_dev, "Failed to set supported hardware\n"); + ret = PTR_ERR(ti_opp_table); goto fail_put_node; } - of_node_put(opp_data->opp_node); + opp_data->opp_table = ti_opp_table; + if (opp_data->soc_data->multi_regulator) { + ti_opp_table = dev_pm_opp_set_regulators(opp_data->cpu_dev, + reg_names, + ARRAY_SIZE(reg_names)); + if (IS_ERR(ti_opp_table)) { + dev_pm_opp_put_supported_hw(opp_data->opp_table); + ret = PTR_ERR(ti_opp_table); + goto fail_put_node; + } + } + + of_node_put(opp_data->opp_node); register_cpufreq_dt: platform_device_register_simple("cpufreq-dt", -1, NULL, 0); @@ -269,4 +290,22 @@ free_opp_data: return ret; } -device_initcall(ti_cpufreq_init); + +static int ti_cpufreq_init(void) +{ + platform_device_register_simple("ti-cpufreq", -1, NULL, 0); + return 0; +} +module_init(ti_cpufreq_init); + +static struct platform_driver ti_cpufreq_driver = { + .probe = ti_cpufreq_probe, + .driver = { + .name = "ti-cpufreq", + }, +}; +module_platform_driver(ti_cpufreq_driver); + +MODULE_DESCRIPTION("TI CPUFreq/OPP hw-supported driver"); +MODULE_AUTHOR("Dave Gerlach "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c index e06605b21841..1a8234e706bc 100644 --- a/drivers/cpuidle/cpuidle-powernv.c +++ b/drivers/cpuidle/cpuidle-powernv.c @@ -76,6 +76,8 @@ static int snooze_loop(struct cpuidle_device *dev, ppc64_runlatch_on(); clear_thread_flag(TIF_POLLING_NRFLAG); + local_irq_disable(); + return index; } diff --git a/drivers/cpuidle/cpuidle-pseries.c b/drivers/cpuidle/cpuidle-pseries.c index a187a39fb866..9e56bc411061 100644 --- a/drivers/cpuidle/cpuidle-pseries.c +++ b/drivers/cpuidle/cpuidle-pseries.c @@ -51,8 +51,6 @@ static inline void idle_loop_epilog(unsigned long in_purr) get_lppaca()->wait_state_cycles = cpu_to_be64(wait_cycles); get_lppaca()->idle = 0; - if (irqs_disabled()) - local_irq_enable(); ppc64_runlatch_on(); } @@ -87,6 +85,8 @@ static int snooze_loop(struct cpuidle_device *dev, HMT_medium(); clear_thread_flag(TIF_POLLING_NRFLAG); + local_irq_disable(); + idle_loop_epilog(in_purr); return index; @@ -121,6 +121,7 @@ static int dedicated_cede_loop(struct cpuidle_device *dev, HMT_medium(); check_and_cede_processor(); + local_irq_disable(); get_lppaca()->donate_dedicated_cpu = 0; idle_loop_epilog(in_purr); @@ -145,6 +146,7 @@ static int shared_cede_loop(struct cpuidle_device *dev, */ check_and_cede_processor(); + local_irq_disable(); idle_loop_epilog(in_purr); return index; @@ -172,11 +174,17 @@ static struct cpuidle_state dedicated_states[] = { * States for shared partition case. */ static struct cpuidle_state shared_states[] = { + { /* Snooze */ + .name = "snooze", + .desc = "snooze", + .exit_latency = 0, + .target_residency = 0, + .enter = &snooze_loop }, { /* Shared Cede */ .name = "Shared Cede", .desc = "Shared Cede", - .exit_latency = 0, - .target_residency = 0, + .exit_latency = 10, + .target_residency = 100, .enter = &shared_cede_loop }, }; diff --git a/drivers/cpuidle/governor.c b/drivers/cpuidle/governor.c index 4e78263e34a4..5d359aff3cc5 100644 --- a/drivers/cpuidle/governor.c +++ b/drivers/cpuidle/governor.c @@ -36,14 +36,15 @@ static struct cpuidle_governor * __cpuidle_find_governor(const char *str) /** * cpuidle_switch_governor - changes the governor * @gov: the new target governor - * - * NOTE: "gov" can be NULL to specify disabled * Must be called with cpuidle_lock acquired. */ int cpuidle_switch_governor(struct cpuidle_governor *gov) { struct cpuidle_device *dev; + if (!gov) + return -EINVAL; + if (gov == cpuidle_curr_governor) return 0; diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 47ec920d5b71..4b741b83e23f 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -723,7 +723,6 @@ config CRYPTO_DEV_ARTPEC6 select CRYPTO_HASH select CRYPTO_SHA1 select CRYPTO_SHA256 - select CRYPTO_SHA384 select CRYPTO_SHA512 help Enables the driver for the on-chip crypto accelerator diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c index eeaf27859d80..ea83d0bff0e9 100644 --- a/drivers/crypto/amcc/crypto4xx_alg.c +++ b/drivers/crypto/amcc/crypto4xx_alg.c @@ -256,10 +256,6 @@ static inline bool crypto4xx_aead_need_fallback(struct aead_request *req, if (is_ccm && !(req->iv[0] == 1 || req->iv[0] == 3)) return true; - /* CCM - fix CBC MAC mismatch in special case */ - if (is_ccm && decrypt && !req->assoclen) - return true; - return false; } @@ -330,7 +326,7 @@ int crypto4xx_setkey_aes_ccm(struct crypto_aead *cipher, const u8 *key, sa = (struct dynamic_sa_ctl *) ctx->sa_in; sa->sa_contents.w = SA_AES_CCM_CONTENTS | (keylen << 2); - set_dynamic_sa_command_0(sa, SA_NOT_SAVE_HASH, SA_NOT_SAVE_IV, + set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV, SA_LOAD_HASH_FROM_SA, SA_LOAD_IV_FROM_STATE, SA_NO_HEADER_PROC, SA_HASH_ALG_CBC_MAC, SA_CIPHER_ALG_AES, diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index c44954e274bc..76f459ad2821 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -128,7 +128,14 @@ static void crypto4xx_hw_init(struct crypto4xx_device *dev) writel(PPC4XX_INT_DESCR_CNT, dev->ce_base + CRYPTO4XX_INT_DESCR_CNT); writel(PPC4XX_INT_DESCR_CNT, dev->ce_base + CRYPTO4XX_INT_DESCR_CNT); writel(PPC4XX_INT_CFG, dev->ce_base + CRYPTO4XX_INT_CFG); - writel(PPC4XX_PD_DONE_INT, dev->ce_base + CRYPTO4XX_INT_EN); + if (dev->is_revb) { + writel(PPC4XX_INT_TIMEOUT_CNT_REVB << 10, + dev->ce_base + CRYPTO4XX_INT_TIMEOUT_CNT); + writel(PPC4XX_PD_DONE_INT | PPC4XX_TMO_ERR_INT, + dev->ce_base + CRYPTO4XX_INT_EN); + } else { + writel(PPC4XX_PD_DONE_INT, dev->ce_base + CRYPTO4XX_INT_EN); + } } int crypto4xx_alloc_sa(struct crypto4xx_ctx *ctx, u32 size) @@ -275,14 +282,12 @@ static u32 crypto4xx_put_pd_to_pdr(struct crypto4xx_device *dev, u32 idx) */ static u32 crypto4xx_build_gdr(struct crypto4xx_device *dev) { - dev->gdr = dma_alloc_coherent(dev->core_dev->device, - sizeof(struct ce_gd) * PPC4XX_NUM_GD, - &dev->gdr_pa, GFP_ATOMIC); + dev->gdr = dma_zalloc_coherent(dev->core_dev->device, + sizeof(struct ce_gd) * PPC4XX_NUM_GD, + &dev->gdr_pa, GFP_ATOMIC); if (!dev->gdr) return -ENOMEM; - memset(dev->gdr, 0, sizeof(struct ce_gd) * PPC4XX_NUM_GD); - return 0; } @@ -570,15 +575,14 @@ static void crypto4xx_aead_done(struct crypto4xx_device *dev, struct pd_uinfo *pd_uinfo, struct ce_pd *pd) { - struct aead_request *aead_req; - struct crypto4xx_ctx *ctx; + struct aead_request *aead_req = container_of(pd_uinfo->async_req, + struct aead_request, base); struct scatterlist *dst = pd_uinfo->dest_va; + size_t cp_len = crypto_aead_authsize( + crypto_aead_reqtfm(aead_req)); + u32 icv[cp_len]; int err = 0; - aead_req = container_of(pd_uinfo->async_req, struct aead_request, - base); - ctx = crypto_tfm_ctx(aead_req->base.tfm); - if (pd_uinfo->using_sd) { crypto4xx_copy_pkt_to_dst(dev, pd, pd_uinfo, pd->pd_ctl_len.bf.pkt_len, @@ -590,38 +594,39 @@ static void crypto4xx_aead_done(struct crypto4xx_device *dev, if (pd_uinfo->sa_va->sa_command_0.bf.dir == DIR_OUTBOUND) { /* append icv at the end */ - size_t cp_len = crypto_aead_authsize( - crypto_aead_reqtfm(aead_req)); - u32 icv[cp_len]; - crypto4xx_memcpy_from_le32(icv, pd_uinfo->sr_va->save_digest, cp_len); scatterwalk_map_and_copy(icv, dst, aead_req->cryptlen, cp_len, 1); + } else { + /* check icv at the end */ + scatterwalk_map_and_copy(icv, aead_req->src, + aead_req->assoclen + aead_req->cryptlen - + cp_len, cp_len, 0); + + crypto4xx_memcpy_from_le32(icv, icv, cp_len); + + if (crypto_memneq(icv, pd_uinfo->sr_va->save_digest, cp_len)) + err = -EBADMSG; } crypto4xx_ret_sg_desc(dev, pd_uinfo); if (pd->pd_ctl.bf.status & 0xff) { - if (pd->pd_ctl.bf.status & 0x1) { - /* authentication error */ - err = -EBADMSG; - } else { - if (!__ratelimit(&dev->aead_ratelimit)) { - if (pd->pd_ctl.bf.status & 2) - pr_err("pad fail error\n"); - if (pd->pd_ctl.bf.status & 4) - pr_err("seqnum fail\n"); - if (pd->pd_ctl.bf.status & 8) - pr_err("error _notify\n"); - pr_err("aead return err status = 0x%02x\n", - pd->pd_ctl.bf.status & 0xff); - pr_err("pd pad_ctl = 0x%08x\n", - pd->pd_ctl.bf.pd_pad_ctl); - } - err = -EINVAL; + if (!__ratelimit(&dev->aead_ratelimit)) { + if (pd->pd_ctl.bf.status & 2) + pr_err("pad fail error\n"); + if (pd->pd_ctl.bf.status & 4) + pr_err("seqnum fail\n"); + if (pd->pd_ctl.bf.status & 8) + pr_err("error _notify\n"); + pr_err("aead return err status = 0x%02x\n", + pd->pd_ctl.bf.status & 0xff); + pr_err("pd pad_ctl = 0x%08x\n", + pd->pd_ctl.bf.pd_pad_ctl); } + err = -EINVAL; } if (pd_uinfo->state & PD_ENTRY_BUSY) @@ -1070,21 +1075,29 @@ static void crypto4xx_bh_tasklet_cb(unsigned long data) /** * Top Half of isr. */ -static irqreturn_t crypto4xx_ce_interrupt_handler(int irq, void *data) +static inline irqreturn_t crypto4xx_interrupt_handler(int irq, void *data, + u32 clr_val) { struct device *dev = (struct device *)data; struct crypto4xx_core_device *core_dev = dev_get_drvdata(dev); - if (!core_dev->dev->ce_base) - return 0; - - writel(PPC4XX_INTERRUPT_CLR, - core_dev->dev->ce_base + CRYPTO4XX_INT_CLR); + writel(clr_val, core_dev->dev->ce_base + CRYPTO4XX_INT_CLR); tasklet_schedule(&core_dev->tasklet); return IRQ_HANDLED; } +static irqreturn_t crypto4xx_ce_interrupt_handler(int irq, void *data) +{ + return crypto4xx_interrupt_handler(irq, data, PPC4XX_INTERRUPT_CLR); +} + +static irqreturn_t crypto4xx_ce_interrupt_handler_revb(int irq, void *data) +{ + return crypto4xx_interrupt_handler(irq, data, PPC4XX_INTERRUPT_CLR | + PPC4XX_TMO_ERR_INT); +} + /** * Supported Crypto Algorithms */ @@ -1266,6 +1279,8 @@ static int crypto4xx_probe(struct platform_device *ofdev) struct resource res; struct device *dev = &ofdev->dev; struct crypto4xx_core_device *core_dev; + u32 pvr; + bool is_revb = true; rc = of_address_to_resource(ofdev->dev.of_node, 0, &res); if (rc) @@ -1282,6 +1297,7 @@ static int crypto4xx_probe(struct platform_device *ofdev) mfdcri(SDR0, PPC405EX_SDR0_SRST) | PPC405EX_CE_RESET); mtdcri(SDR0, PPC405EX_SDR0_SRST, mfdcri(SDR0, PPC405EX_SDR0_SRST) & ~PPC405EX_CE_RESET); + is_revb = false; } else if (of_find_compatible_node(NULL, NULL, "amcc,ppc460sx-crypto")) { mtdcri(SDR0, PPC460SX_SDR0_SRST, @@ -1304,7 +1320,22 @@ static int crypto4xx_probe(struct platform_device *ofdev) if (!core_dev->dev) goto err_alloc_dev; + /* + * Older version of 460EX/GT have a hardware bug. + * Hence they do not support H/W based security intr coalescing + */ + pvr = mfspr(SPRN_PVR); + if (is_revb && ((pvr >> 4) == 0x130218A)) { + u32 min = PVR_MIN(pvr); + + if (min < 4) { + dev_info(dev, "RevA detected - disable interrupt coalescing\n"); + is_revb = false; + } + } + core_dev->dev->core_dev = core_dev; + core_dev->dev->is_revb = is_revb; core_dev->device = dev; spin_lock_init(&core_dev->lock); INIT_LIST_HEAD(&core_dev->dev->alg_list); @@ -1325,13 +1356,6 @@ static int crypto4xx_probe(struct platform_device *ofdev) tasklet_init(&core_dev->tasklet, crypto4xx_bh_tasklet_cb, (unsigned long) dev); - /* Register for Crypto isr, Crypto Engine IRQ */ - core_dev->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); - rc = request_irq(core_dev->irq, crypto4xx_ce_interrupt_handler, 0, - core_dev->dev->name, dev); - if (rc) - goto err_request_irq; - core_dev->dev->ce_base = of_iomap(ofdev->dev.of_node, 0); if (!core_dev->dev->ce_base) { dev_err(dev, "failed to of_iomap\n"); @@ -1339,6 +1363,15 @@ static int crypto4xx_probe(struct platform_device *ofdev) goto err_iomap; } + /* Register for Crypto isr, Crypto Engine IRQ */ + core_dev->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); + rc = request_irq(core_dev->irq, is_revb ? + crypto4xx_ce_interrupt_handler_revb : + crypto4xx_ce_interrupt_handler, 0, + KBUILD_MODNAME, dev); + if (rc) + goto err_request_irq; + /* need to setup pdr, rdr, gdr and sdr before this */ crypto4xx_hw_init(core_dev->dev); @@ -1352,11 +1385,11 @@ static int crypto4xx_probe(struct platform_device *ofdev) return 0; err_start_dev: - iounmap(core_dev->dev->ce_base); -err_iomap: free_irq(core_dev->irq, dev); err_request_irq: irq_dispose_mapping(core_dev->irq); + iounmap(core_dev->dev->ce_base); +err_iomap: tasklet_kill(&core_dev->tasklet); err_build_sdr: crypto4xx_destroy_sdr(core_dev->dev); @@ -1397,7 +1430,7 @@ MODULE_DEVICE_TABLE(of, crypto4xx_match); static struct platform_driver crypto4xx_driver = { .driver = { - .name = MODULE_NAME, + .name = KBUILD_MODNAME, .of_match_table = crypto4xx_match, }, .probe = crypto4xx_probe, diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h index 8ac3bd37203b..23b726da6534 100644 --- a/drivers/crypto/amcc/crypto4xx_core.h +++ b/drivers/crypto/amcc/crypto4xx_core.h @@ -28,8 +28,6 @@ #include "crypto4xx_reg_def.h" #include "crypto4xx_sa.h" -#define MODULE_NAME "crypto4xx" - #define PPC460SX_SDR0_SRST 0x201 #define PPC405EX_SDR0_SRST 0x200 #define PPC460EX_SDR0_SRST 0x201 @@ -82,7 +80,6 @@ struct pd_uinfo { struct crypto4xx_device { struct crypto4xx_core_device *core_dev; - char *name; void __iomem *ce_base; void __iomem *trng_base; @@ -109,6 +106,7 @@ struct crypto4xx_device { struct list_head alg_list; /* List of algorithm supported by this device */ struct ratelimit_state aead_ratelimit; + bool is_revb; }; struct crypto4xx_core_device { diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h index 0a22ec5d1a96..472331787e04 100644 --- a/drivers/crypto/amcc/crypto4xx_reg_def.h +++ b/drivers/crypto/amcc/crypto4xx_reg_def.h @@ -121,13 +121,15 @@ #define PPC4XX_PD_SIZE 6 #define PPC4XX_CTX_DONE_INT 0x2000 #define PPC4XX_PD_DONE_INT 0x8000 +#define PPC4XX_TMO_ERR_INT 0x40000 #define PPC4XX_BYTE_ORDER 0x22222 #define PPC4XX_INTERRUPT_CLR 0x3ffff #define PPC4XX_PRNG_CTRL_AUTO_EN 0x3 #define PPC4XX_DC_3DES_EN 1 #define PPC4XX_TRNG_EN 0x00020000 -#define PPC4XX_INT_DESCR_CNT 4 +#define PPC4XX_INT_DESCR_CNT 7 #define PPC4XX_INT_TIMEOUT_CNT 0 +#define PPC4XX_INT_TIMEOUT_CNT_REVB 0x3FF #define PPC4XX_INT_CFG 1 /** * all follow define are ad hoc diff --git a/drivers/crypto/amcc/crypto4xx_trng.c b/drivers/crypto/amcc/crypto4xx_trng.c index 677ca17fd223..5e63742b0d22 100644 --- a/drivers/crypto/amcc/crypto4xx_trng.c +++ b/drivers/crypto/amcc/crypto4xx_trng.c @@ -92,7 +92,7 @@ void ppc4xx_trng_probe(struct crypto4xx_core_device *core_dev) if (!rng) goto err_out; - rng->name = MODULE_NAME; + rng->name = KBUILD_MODNAME; rng->data_present = ppc4xx_trng_data_present; rng->data_read = ppc4xx_trng_data_read; rng->priv = (unsigned long) dev; diff --git a/drivers/crypto/axis/artpec6_crypto.c b/drivers/crypto/axis/artpec6_crypto.c index 456278440863..0fb8bbf41a8d 100644 --- a/drivers/crypto/axis/artpec6_crypto.c +++ b/drivers/crypto/axis/artpec6_crypto.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -1934,7 +1935,7 @@ static int artpec6_crypto_prepare_aead(struct aead_request *areq) memcpy(req_ctx->hw_ctx.J0, areq->iv, crypto_aead_ivsize(cipher)); // The HW omits the initial increment of the counter field. - crypto_inc(req_ctx->hw_ctx.J0+12, 4); + memcpy(req_ctx->hw_ctx.J0 + GCM_AES_IV_SIZE, "\x00\x00\x00\x01", 4); ret = artpec6_crypto_setup_out_descr(common, &req_ctx->hw_ctx, sizeof(struct artpec6_crypto_aead_hw_ctx), false, false); @@ -2956,7 +2957,7 @@ static struct aead_alg aead_algos[] = { .setkey = artpec6_crypto_aead_set_key, .encrypt = artpec6_crypto_aead_encrypt, .decrypt = artpec6_crypto_aead_decrypt, - .ivsize = AES_BLOCK_SIZE, + .ivsize = GCM_AES_IV_SIZE, .maxauthsize = AES_BLOCK_SIZE, .base = { @@ -3041,9 +3042,6 @@ static int artpec6_crypto_probe(struct platform_device *pdev) variant = (enum artpec6_crypto_variant)match->data; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/drivers/crypto/bcm/cipher.c b/drivers/crypto/bcm/cipher.c index ce70b44d0fb6..2b75f95bbe1b 100644 --- a/drivers/crypto/bcm/cipher.c +++ b/drivers/crypto/bcm/cipher.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include "util.h" diff --git a/drivers/crypto/bfin_crc.c b/drivers/crypto/bfin_crc.c index a118b9bed669..bfbf8bf77f03 100644 --- a/drivers/crypto/bfin_crc.c +++ b/drivers/crypto/bfin_crc.c @@ -494,7 +494,8 @@ static struct ahash_alg algs = { .cra_driver_name = DRIVER_NAME, .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_AHASH | - CRYPTO_ALG_ASYNC, + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_OPTIONAL_KEY, .cra_blocksize = CHKSUM_BLOCK_SIZE, .cra_ctxsize = sizeof(struct bfin_crypto_crc_ctx), .cra_alignmask = 3, diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index baa8dd52472d..2188235be02d 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -108,6 +108,7 @@ struct caam_ctx { dma_addr_t sh_desc_dec_dma; dma_addr_t sh_desc_givenc_dma; dma_addr_t key_dma; + enum dma_data_direction dir; struct device *jrdev; struct alginfo adata; struct alginfo cdata; @@ -118,6 +119,7 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) { struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; + struct caam_drv_private *ctrlpriv = dev_get_drvdata(jrdev->parent); u32 *desc; int rem_bytes = CAAM_DESC_BYTES_MAX - AEAD_DESC_JOB_IO_LEN - ctx->adata.keylen_pad; @@ -136,9 +138,10 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) /* aead_encrypt shared descriptor */ desc = ctx->sh_desc_enc; - cnstr_shdsc_aead_null_encap(desc, &ctx->adata, ctx->authsize); + cnstr_shdsc_aead_null_encap(desc, &ctx->adata, ctx->authsize, + ctrlpriv->era); dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); /* * Job Descriptor and Shared Descriptors @@ -154,9 +157,10 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) /* aead_decrypt shared descriptor */ desc = ctx->sh_desc_dec; - cnstr_shdsc_aead_null_decap(desc, &ctx->adata, ctx->authsize); + cnstr_shdsc_aead_null_decap(desc, &ctx->adata, ctx->authsize, + ctrlpriv->era); dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); return 0; } @@ -168,6 +172,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead) unsigned int ivsize = crypto_aead_ivsize(aead); struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; + struct caam_drv_private *ctrlpriv = dev_get_drvdata(jrdev->parent); u32 ctx1_iv_off = 0; u32 *desc, *nonce = NULL; u32 inl_mask; @@ -234,9 +239,9 @@ static int aead_set_sh_desc(struct crypto_aead *aead) desc = ctx->sh_desc_enc; cnstr_shdsc_aead_encap(desc, &ctx->cdata, &ctx->adata, ivsize, ctx->authsize, is_rfc3686, nonce, ctx1_iv_off, - false); + false, ctrlpriv->era); dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); skip_enc: /* @@ -266,9 +271,9 @@ skip_enc: desc = ctx->sh_desc_dec; cnstr_shdsc_aead_decap(desc, &ctx->cdata, &ctx->adata, ivsize, ctx->authsize, alg->caam.geniv, is_rfc3686, - nonce, ctx1_iv_off, false); + nonce, ctx1_iv_off, false, ctrlpriv->era); dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); if (!alg->caam.geniv) goto skip_givenc; @@ -300,9 +305,9 @@ skip_enc: desc = ctx->sh_desc_enc; cnstr_shdsc_aead_givencap(desc, &ctx->cdata, &ctx->adata, ivsize, ctx->authsize, is_rfc3686, nonce, - ctx1_iv_off, false); + ctx1_iv_off, false, ctrlpriv->era); dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); skip_givenc: return 0; @@ -346,7 +351,7 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) desc = ctx->sh_desc_enc; cnstr_shdsc_gcm_encap(desc, &ctx->cdata, ctx->authsize); dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); /* * Job Descriptor and Shared Descriptors @@ -363,7 +368,7 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) desc = ctx->sh_desc_dec; cnstr_shdsc_gcm_decap(desc, &ctx->cdata, ctx->authsize); dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); return 0; } @@ -405,7 +410,7 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) desc = ctx->sh_desc_enc; cnstr_shdsc_rfc4106_encap(desc, &ctx->cdata, ctx->authsize); dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); /* * Job Descriptor and Shared Descriptors @@ -422,7 +427,7 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) desc = ctx->sh_desc_dec; cnstr_shdsc_rfc4106_decap(desc, &ctx->cdata, ctx->authsize); dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); return 0; } @@ -465,7 +470,7 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) desc = ctx->sh_desc_enc; cnstr_shdsc_rfc4543_encap(desc, &ctx->cdata, ctx->authsize); dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); /* * Job Descriptor and Shared Descriptors @@ -482,7 +487,7 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) desc = ctx->sh_desc_dec; cnstr_shdsc_rfc4543_decap(desc, &ctx->cdata, ctx->authsize); dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); return 0; } @@ -503,6 +508,7 @@ static int aead_setkey(struct crypto_aead *aead, { struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; + struct caam_drv_private *ctrlpriv = dev_get_drvdata(jrdev->parent); struct crypto_authenc_keys keys; int ret = 0; @@ -517,6 +523,27 @@ static int aead_setkey(struct crypto_aead *aead, DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); #endif + /* + * If DKP is supported, use it in the shared descriptor to generate + * the split key. + */ + if (ctrlpriv->era >= 6) { + ctx->adata.keylen = keys.authkeylen; + ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype & + OP_ALG_ALGSEL_MASK); + + if (ctx->adata.keylen_pad + keys.enckeylen > CAAM_MAX_KEY_SIZE) + goto badkey; + + memcpy(ctx->key, keys.authkey, keys.authkeylen); + memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, + keys.enckeylen); + dma_sync_single_for_device(jrdev, ctx->key_dma, + ctx->adata.keylen_pad + + keys.enckeylen, ctx->dir); + goto skip_split_key; + } + ret = gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, keys.authkey, keys.authkeylen, CAAM_MAX_KEY_SIZE - keys.enckeylen); @@ -527,12 +554,14 @@ static int aead_setkey(struct crypto_aead *aead, /* postpend encryption key to auth split key */ memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen); dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->adata.keylen_pad + - keys.enckeylen, DMA_TO_DEVICE); + keys.enckeylen, ctx->dir); #ifdef DEBUG print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, ctx->adata.keylen_pad + keys.enckeylen, 1); #endif + +skip_split_key: ctx->cdata.keylen = keys.enckeylen; return aead_set_sh_desc(aead); badkey: @@ -552,7 +581,7 @@ static int gcm_setkey(struct crypto_aead *aead, #endif memcpy(ctx->key, key, keylen); - dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, DMA_TO_DEVICE); + dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, ctx->dir); ctx->cdata.keylen = keylen; return gcm_set_sh_desc(aead); @@ -580,7 +609,7 @@ static int rfc4106_setkey(struct crypto_aead *aead, */ ctx->cdata.keylen = keylen - 4; dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->cdata.keylen, - DMA_TO_DEVICE); + ctx->dir); return rfc4106_set_sh_desc(aead); } @@ -606,7 +635,7 @@ static int rfc4543_setkey(struct crypto_aead *aead, */ ctx->cdata.keylen = keylen - 4; dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->cdata.keylen, - DMA_TO_DEVICE); + ctx->dir); return rfc4543_set_sh_desc(aead); } @@ -625,7 +654,6 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, const bool is_rfc3686 = (ctr_mode && (strstr(alg_name, "rfc3686") != NULL)); - memcpy(ctx->key, key, keylen); #ifdef DEBUG print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); @@ -648,9 +676,8 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, keylen -= CTR_RFC3686_NONCE_SIZE; } - dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, DMA_TO_DEVICE); ctx->cdata.keylen = keylen; - ctx->cdata.key_virt = ctx->key; + ctx->cdata.key_virt = key; ctx->cdata.key_inline = true; /* ablkcipher_encrypt shared descriptor */ @@ -658,21 +685,21 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, cnstr_shdsc_ablkcipher_encap(desc, &ctx->cdata, ivsize, is_rfc3686, ctx1_iv_off); dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); /* ablkcipher_decrypt shared descriptor */ desc = ctx->sh_desc_dec; cnstr_shdsc_ablkcipher_decap(desc, &ctx->cdata, ivsize, is_rfc3686, ctx1_iv_off); dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); /* ablkcipher_givencrypt shared descriptor */ desc = ctx->sh_desc_givenc; cnstr_shdsc_ablkcipher_givencap(desc, &ctx->cdata, ivsize, is_rfc3686, ctx1_iv_off); dma_sync_single_for_device(jrdev, ctx->sh_desc_givenc_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); return 0; } @@ -691,23 +718,21 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, return -EINVAL; } - memcpy(ctx->key, key, keylen); - dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, DMA_TO_DEVICE); ctx->cdata.keylen = keylen; - ctx->cdata.key_virt = ctx->key; + ctx->cdata.key_virt = key; ctx->cdata.key_inline = true; /* xts_ablkcipher_encrypt shared descriptor */ desc = ctx->sh_desc_enc; cnstr_shdsc_xts_ablkcipher_encap(desc, &ctx->cdata); dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); /* xts_ablkcipher_decrypt shared descriptor */ desc = ctx->sh_desc_dec; cnstr_shdsc_xts_ablkcipher_decap(desc, &ctx->cdata); dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); return 0; } @@ -979,9 +1004,6 @@ static void init_aead_job(struct aead_request *req, append_seq_out_ptr(desc, dst_dma, req->assoclen + req->cryptlen - authsize, out_options); - - /* REG3 = assoclen */ - append_math_add_imm_u32(desc, REG3, ZERO, IMM, req->assoclen); } static void init_gcm_job(struct aead_request *req, @@ -996,6 +1018,7 @@ static void init_gcm_job(struct aead_request *req, unsigned int last; init_aead_job(req, edesc, all_contig, encrypt); + append_math_add_imm_u32(desc, REG3, ZERO, IMM, req->assoclen); /* BUG This should not be specific to generic GCM. */ last = 0; @@ -1022,6 +1045,7 @@ static void init_authenc_job(struct aead_request *req, struct caam_aead_alg, aead); unsigned int ivsize = crypto_aead_ivsize(aead); struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctx->jrdev->parent); const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == OP_ALG_AAI_CTR_MOD128); const bool is_rfc3686 = alg->caam.rfc3686; @@ -1045,6 +1069,15 @@ static void init_authenc_job(struct aead_request *req, init_aead_job(req, edesc, all_contig, encrypt); + /* + * {REG3, DPOVRD} = assoclen, depending on whether MATH command supports + * having DPOVRD as destination. + */ + if (ctrlpriv->era < 3) + append_math_add_imm_u32(desc, REG3, ZERO, IMM, req->assoclen); + else + append_math_add_imm_u32(desc, DPOVRD, ZERO, IMM, req->assoclen); + if (ivsize && ((is_rfc3686 && encrypt) || !alg->caam.geniv)) append_load_as_imm(desc, req->iv, ivsize, LDST_CLASS_1_CCB | @@ -3228,9 +3261,11 @@ struct caam_crypto_alg { struct caam_alg_entry caam; }; -static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam) +static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam, + bool uses_dkp) { dma_addr_t dma_addr; + struct caam_drv_private *priv; ctx->jrdev = caam_jr_alloc(); if (IS_ERR(ctx->jrdev)) { @@ -3238,10 +3273,16 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam) return PTR_ERR(ctx->jrdev); } + priv = dev_get_drvdata(ctx->jrdev->parent); + if (priv->era >= 6 && uses_dkp) + ctx->dir = DMA_BIDIRECTIONAL; + else + ctx->dir = DMA_TO_DEVICE; + dma_addr = dma_map_single_attrs(ctx->jrdev, ctx->sh_desc_enc, offsetof(struct caam_ctx, sh_desc_enc_dma), - DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); + ctx->dir, DMA_ATTR_SKIP_CPU_SYNC); if (dma_mapping_error(ctx->jrdev, dma_addr)) { dev_err(ctx->jrdev, "unable to map key, shared descriptors\n"); caam_jr_free(ctx->jrdev); @@ -3269,7 +3310,7 @@ static int caam_cra_init(struct crypto_tfm *tfm) container_of(alg, struct caam_crypto_alg, crypto_alg); struct caam_ctx *ctx = crypto_tfm_ctx(tfm); - return caam_init_common(ctx, &caam_alg->caam); + return caam_init_common(ctx, &caam_alg->caam, false); } static int caam_aead_init(struct crypto_aead *tfm) @@ -3279,14 +3320,15 @@ static int caam_aead_init(struct crypto_aead *tfm) container_of(alg, struct caam_aead_alg, aead); struct caam_ctx *ctx = crypto_aead_ctx(tfm); - return caam_init_common(ctx, &caam_alg->caam); + return caam_init_common(ctx, &caam_alg->caam, + alg->setkey == aead_setkey); } static void caam_exit_common(struct caam_ctx *ctx) { dma_unmap_single_attrs(ctx->jrdev, ctx->sh_desc_enc_dma, offsetof(struct caam_ctx, sh_desc_enc_dma), - DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); + ctx->dir, DMA_ATTR_SKIP_CPU_SYNC); caam_jr_free(ctx->jrdev); } diff --git a/drivers/crypto/caam/caamalg_desc.c b/drivers/crypto/caam/caamalg_desc.c index 530c14ee32de..ceb93fbb76e6 100644 --- a/drivers/crypto/caam/caamalg_desc.c +++ b/drivers/crypto/caam/caamalg_desc.c @@ -45,16 +45,16 @@ static inline void append_dec_op1(u32 *desc, u32 type) * cnstr_shdsc_aead_null_encap - IPSec ESP encapsulation shared descriptor * (non-protocol) with no (null) encryption. * @desc: pointer to buffer used for descriptor construction - * @adata: pointer to authentication transform definitions. Note that since a - * split key is to be used, the size of the split key itself is - * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, - * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP. + * @adata: pointer to authentication transform definitions. + * A split key is required for SEC Era < 6; the size of the split key + * is specified in this case. Valid algorithm values - one of + * OP_ALG_ALGSEL_{MD5, SHA1, SHA224, SHA256, SHA384, SHA512} ANDed + * with OP_ALG_AAI_HMAC_PRECOMP. * @icvsize: integrity check value (ICV) size (truncated or full) - * - * Note: Requires an MDHA split key. + * @era: SEC Era */ void cnstr_shdsc_aead_null_encap(u32 * const desc, struct alginfo *adata, - unsigned int icvsize) + unsigned int icvsize, int era) { u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd; @@ -63,13 +63,18 @@ void cnstr_shdsc_aead_null_encap(u32 * const desc, struct alginfo *adata, /* Skip if already shared */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); - if (adata->key_inline) - append_key_as_imm(desc, adata->key_virt, adata->keylen_pad, - adata->keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT | - KEY_ENC); - else - append_key(desc, adata->key_dma, adata->keylen, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); + if (era < 6) { + if (adata->key_inline) + append_key_as_imm(desc, adata->key_virt, + adata->keylen_pad, adata->keylen, + CLASS_2 | KEY_DEST_MDHA_SPLIT | + KEY_ENC); + else + append_key(desc, adata->key_dma, adata->keylen, + CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); + } else { + append_proto_dkp(desc, adata); + } set_jump_tgt_here(desc, key_jump_cmd); /* assoclen + cryptlen = seqinlen */ @@ -121,16 +126,16 @@ EXPORT_SYMBOL(cnstr_shdsc_aead_null_encap); * cnstr_shdsc_aead_null_decap - IPSec ESP decapsulation shared descriptor * (non-protocol) with no (null) decryption. * @desc: pointer to buffer used for descriptor construction - * @adata: pointer to authentication transform definitions. Note that since a - * split key is to be used, the size of the split key itself is - * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, - * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP. + * @adata: pointer to authentication transform definitions. + * A split key is required for SEC Era < 6; the size of the split key + * is specified in this case. Valid algorithm values - one of + * OP_ALG_ALGSEL_{MD5, SHA1, SHA224, SHA256, SHA384, SHA512} ANDed + * with OP_ALG_AAI_HMAC_PRECOMP. * @icvsize: integrity check value (ICV) size (truncated or full) - * - * Note: Requires an MDHA split key. + * @era: SEC Era */ void cnstr_shdsc_aead_null_decap(u32 * const desc, struct alginfo *adata, - unsigned int icvsize) + unsigned int icvsize, int era) { u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd, *jump_cmd; @@ -139,13 +144,18 @@ void cnstr_shdsc_aead_null_decap(u32 * const desc, struct alginfo *adata, /* Skip if already shared */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); - if (adata->key_inline) - append_key_as_imm(desc, adata->key_virt, adata->keylen_pad, - adata->keylen, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); - else - append_key(desc, adata->key_dma, adata->keylen, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); + if (era < 6) { + if (adata->key_inline) + append_key_as_imm(desc, adata->key_virt, + adata->keylen_pad, adata->keylen, + CLASS_2 | KEY_DEST_MDHA_SPLIT | + KEY_ENC); + else + append_key(desc, adata->key_dma, adata->keylen, + CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); + } else { + append_proto_dkp(desc, adata); + } set_jump_tgt_here(desc, key_jump_cmd); /* Class 2 operation */ @@ -204,7 +214,7 @@ EXPORT_SYMBOL(cnstr_shdsc_aead_null_decap); static void init_sh_desc_key_aead(u32 * const desc, struct alginfo * const cdata, struct alginfo * const adata, - const bool is_rfc3686, u32 *nonce) + const bool is_rfc3686, u32 *nonce, int era) { u32 *key_jump_cmd; unsigned int enckeylen = cdata->keylen; @@ -224,13 +234,18 @@ static void init_sh_desc_key_aead(u32 * const desc, if (is_rfc3686) enckeylen -= CTR_RFC3686_NONCE_SIZE; - if (adata->key_inline) - append_key_as_imm(desc, adata->key_virt, adata->keylen_pad, - adata->keylen, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); - else - append_key(desc, adata->key_dma, adata->keylen, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); + if (era < 6) { + if (adata->key_inline) + append_key_as_imm(desc, adata->key_virt, + adata->keylen_pad, adata->keylen, + CLASS_2 | KEY_DEST_MDHA_SPLIT | + KEY_ENC); + else + append_key(desc, adata->key_dma, adata->keylen, + CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); + } else { + append_proto_dkp(desc, adata); + } if (cdata->key_inline) append_key_as_imm(desc, cdata->key_virt, enckeylen, @@ -261,26 +276,27 @@ static void init_sh_desc_key_aead(u32 * const desc, * @cdata: pointer to block cipher transform definitions * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed * with OP_ALG_AAI_CBC or OP_ALG_AAI_CTR_MOD128. - * @adata: pointer to authentication transform definitions. Note that since a - * split key is to be used, the size of the split key itself is - * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, - * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP. + * @adata: pointer to authentication transform definitions. + * A split key is required for SEC Era < 6; the size of the split key + * is specified in this case. Valid algorithm values - one of + * OP_ALG_ALGSEL_{MD5, SHA1, SHA224, SHA256, SHA384, SHA512} ANDed + * with OP_ALG_AAI_HMAC_PRECOMP. * @ivsize: initialization vector size * @icvsize: integrity check value (ICV) size (truncated or full) * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template * @nonce: pointer to rfc3686 nonce * @ctx1_iv_off: IV offset in CONTEXT1 register * @is_qi: true when called from caam/qi - * - * Note: Requires an MDHA split key. + * @era: SEC Era */ void cnstr_shdsc_aead_encap(u32 * const desc, struct alginfo *cdata, struct alginfo *adata, unsigned int ivsize, unsigned int icvsize, const bool is_rfc3686, - u32 *nonce, const u32 ctx1_iv_off, const bool is_qi) + u32 *nonce, const u32 ctx1_iv_off, const bool is_qi, + int era) { /* Note: Context registers are saved. */ - init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce); + init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce, era); /* Class 2 operation */ append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL | @@ -306,8 +322,13 @@ void cnstr_shdsc_aead_encap(u32 * const desc, struct alginfo *cdata, } /* Read and write assoclen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); - append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); + if (is_qi || era < 3) { + append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); + append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); + } else { + append_math_add(desc, VARSEQINLEN, ZERO, DPOVRD, CAAM_CMD_SZ); + append_math_add(desc, VARSEQOUTLEN, ZERO, DPOVRD, CAAM_CMD_SZ); + } /* Skip assoc data */ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); @@ -350,27 +371,27 @@ EXPORT_SYMBOL(cnstr_shdsc_aead_encap); * @cdata: pointer to block cipher transform definitions * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed * with OP_ALG_AAI_CBC or OP_ALG_AAI_CTR_MOD128. - * @adata: pointer to authentication transform definitions. Note that since a - * split key is to be used, the size of the split key itself is - * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, - * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP. + * @adata: pointer to authentication transform definitions. + * A split key is required for SEC Era < 6; the size of the split key + * is specified in this case. Valid algorithm values - one of + * OP_ALG_ALGSEL_{MD5, SHA1, SHA224, SHA256, SHA384, SHA512} ANDed + * with OP_ALG_AAI_HMAC_PRECOMP. * @ivsize: initialization vector size * @icvsize: integrity check value (ICV) size (truncated or full) * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template * @nonce: pointer to rfc3686 nonce * @ctx1_iv_off: IV offset in CONTEXT1 register * @is_qi: true when called from caam/qi - * - * Note: Requires an MDHA split key. + * @era: SEC Era */ void cnstr_shdsc_aead_decap(u32 * const desc, struct alginfo *cdata, struct alginfo *adata, unsigned int ivsize, unsigned int icvsize, const bool geniv, const bool is_rfc3686, u32 *nonce, - const u32 ctx1_iv_off, const bool is_qi) + const u32 ctx1_iv_off, const bool is_qi, int era) { /* Note: Context registers are saved. */ - init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce); + init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce, era); /* Class 2 operation */ append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL | @@ -397,11 +418,23 @@ void cnstr_shdsc_aead_decap(u32 * const desc, struct alginfo *cdata, } /* Read and write assoclen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); - if (geniv) - append_math_add_imm_u32(desc, VARSEQOUTLEN, REG3, IMM, ivsize); - else - append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); + if (is_qi || era < 3) { + append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); + if (geniv) + append_math_add_imm_u32(desc, VARSEQOUTLEN, REG3, IMM, + ivsize); + else + append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, + CAAM_CMD_SZ); + } else { + append_math_add(desc, VARSEQINLEN, ZERO, DPOVRD, CAAM_CMD_SZ); + if (geniv) + append_math_add_imm_u32(desc, VARSEQOUTLEN, DPOVRD, IMM, + ivsize); + else + append_math_add(desc, VARSEQOUTLEN, ZERO, DPOVRD, + CAAM_CMD_SZ); + } /* Skip assoc data */ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); @@ -456,29 +489,29 @@ EXPORT_SYMBOL(cnstr_shdsc_aead_decap); * @cdata: pointer to block cipher transform definitions * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed * with OP_ALG_AAI_CBC or OP_ALG_AAI_CTR_MOD128. - * @adata: pointer to authentication transform definitions. Note that since a - * split key is to be used, the size of the split key itself is - * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, - * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP. + * @adata: pointer to authentication transform definitions. + * A split key is required for SEC Era < 6; the size of the split key + * is specified in this case. Valid algorithm values - one of + * OP_ALG_ALGSEL_{MD5, SHA1, SHA224, SHA256, SHA384, SHA512} ANDed + * with OP_ALG_AAI_HMAC_PRECOMP. * @ivsize: initialization vector size * @icvsize: integrity check value (ICV) size (truncated or full) * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template * @nonce: pointer to rfc3686 nonce * @ctx1_iv_off: IV offset in CONTEXT1 register * @is_qi: true when called from caam/qi - * - * Note: Requires an MDHA split key. + * @era: SEC Era */ void cnstr_shdsc_aead_givencap(u32 * const desc, struct alginfo *cdata, struct alginfo *adata, unsigned int ivsize, unsigned int icvsize, const bool is_rfc3686, u32 *nonce, const u32 ctx1_iv_off, - const bool is_qi) + const bool is_qi, int era) { u32 geniv, moveiv; /* Note: Context registers are saved. */ - init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce); + init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce, era); if (is_qi) { u32 *wait_load_cmd; @@ -528,8 +561,13 @@ copy_iv: OP_ALG_ENCRYPT); /* Read and write assoclen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); - append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); + if (is_qi || era < 3) { + append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); + append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); + } else { + append_math_add(desc, VARSEQINLEN, ZERO, DPOVRD, CAAM_CMD_SZ); + append_math_add(desc, VARSEQOUTLEN, ZERO, DPOVRD, CAAM_CMD_SZ); + } /* Skip assoc data */ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); @@ -1075,7 +1113,7 @@ void cnstr_shdsc_ablkcipher_encap(u32 * const desc, struct alginfo *cdata, /* Load nonce into CONTEXT1 reg */ if (is_rfc3686) { - u8 *nonce = cdata->key_virt + cdata->keylen; + const u8 *nonce = cdata->key_virt + cdata->keylen; append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, LDST_CLASS_IND_CCB | @@ -1140,7 +1178,7 @@ void cnstr_shdsc_ablkcipher_decap(u32 * const desc, struct alginfo *cdata, /* Load nonce into CONTEXT1 reg */ if (is_rfc3686) { - u8 *nonce = cdata->key_virt + cdata->keylen; + const u8 *nonce = cdata->key_virt + cdata->keylen; append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, LDST_CLASS_IND_CCB | @@ -1209,7 +1247,7 @@ void cnstr_shdsc_ablkcipher_givencap(u32 * const desc, struct alginfo *cdata, /* Load Nonce into CONTEXT1 reg */ if (is_rfc3686) { - u8 *nonce = cdata->key_virt + cdata->keylen; + const u8 *nonce = cdata->key_virt + cdata->keylen; append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, LDST_CLASS_IND_CCB | diff --git a/drivers/crypto/caam/caamalg_desc.h b/drivers/crypto/caam/caamalg_desc.h index e412ec8f7005..5f9445ae2114 100644 --- a/drivers/crypto/caam/caamalg_desc.h +++ b/drivers/crypto/caam/caamalg_desc.h @@ -43,28 +43,28 @@ 15 * CAAM_CMD_SZ) void cnstr_shdsc_aead_null_encap(u32 * const desc, struct alginfo *adata, - unsigned int icvsize); + unsigned int icvsize, int era); void cnstr_shdsc_aead_null_decap(u32 * const desc, struct alginfo *adata, - unsigned int icvsize); + unsigned int icvsize, int era); void cnstr_shdsc_aead_encap(u32 * const desc, struct alginfo *cdata, struct alginfo *adata, unsigned int ivsize, unsigned int icvsize, const bool is_rfc3686, u32 *nonce, const u32 ctx1_iv_off, - const bool is_qi); + const bool is_qi, int era); void cnstr_shdsc_aead_decap(u32 * const desc, struct alginfo *cdata, struct alginfo *adata, unsigned int ivsize, unsigned int icvsize, const bool geniv, const bool is_rfc3686, u32 *nonce, - const u32 ctx1_iv_off, const bool is_qi); + const u32 ctx1_iv_off, const bool is_qi, int era); void cnstr_shdsc_aead_givencap(u32 * const desc, struct alginfo *cdata, struct alginfo *adata, unsigned int ivsize, unsigned int icvsize, const bool is_rfc3686, u32 *nonce, const u32 ctx1_iv_off, - const bool is_qi); + const bool is_qi, int era); void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata, unsigned int icvsize); diff --git a/drivers/crypto/caam/caamalg_qi.c b/drivers/crypto/caam/caamalg_qi.c index f9f08fce4356..4aecc9435f69 100644 --- a/drivers/crypto/caam/caamalg_qi.c +++ b/drivers/crypto/caam/caamalg_qi.c @@ -53,6 +53,7 @@ struct caam_ctx { u32 sh_desc_givenc[DESC_MAX_USED_LEN]; u8 key[CAAM_MAX_KEY_SIZE]; dma_addr_t key_dma; + enum dma_data_direction dir; struct alginfo adata; struct alginfo cdata; unsigned int authsize; @@ -74,6 +75,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead) const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == OP_ALG_AAI_CTR_MOD128); const bool is_rfc3686 = alg->caam.rfc3686; + struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctx->jrdev->parent); if (!ctx->cdata.keylen || !ctx->authsize) return 0; @@ -124,7 +126,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead) cnstr_shdsc_aead_encap(ctx->sh_desc_enc, &ctx->cdata, &ctx->adata, ivsize, ctx->authsize, is_rfc3686, nonce, - ctx1_iv_off, true); + ctx1_iv_off, true, ctrlpriv->era); skip_enc: /* aead_decrypt shared descriptor */ @@ -149,7 +151,8 @@ skip_enc: cnstr_shdsc_aead_decap(ctx->sh_desc_dec, &ctx->cdata, &ctx->adata, ivsize, ctx->authsize, alg->caam.geniv, - is_rfc3686, nonce, ctx1_iv_off, true); + is_rfc3686, nonce, ctx1_iv_off, true, + ctrlpriv->era); if (!alg->caam.geniv) goto skip_givenc; @@ -176,7 +179,7 @@ skip_enc: cnstr_shdsc_aead_givencap(ctx->sh_desc_enc, &ctx->cdata, &ctx->adata, ivsize, ctx->authsize, is_rfc3686, nonce, - ctx1_iv_off, true); + ctx1_iv_off, true, ctrlpriv->era); skip_givenc: return 0; @@ -197,6 +200,7 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key, { struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; + struct caam_drv_private *ctrlpriv = dev_get_drvdata(jrdev->parent); struct crypto_authenc_keys keys; int ret = 0; @@ -211,6 +215,27 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key, DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); #endif + /* + * If DKP is supported, use it in the shared descriptor to generate + * the split key. + */ + if (ctrlpriv->era >= 6) { + ctx->adata.keylen = keys.authkeylen; + ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype & + OP_ALG_ALGSEL_MASK); + + if (ctx->adata.keylen_pad + keys.enckeylen > CAAM_MAX_KEY_SIZE) + goto badkey; + + memcpy(ctx->key, keys.authkey, keys.authkeylen); + memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, + keys.enckeylen); + dma_sync_single_for_device(jrdev, ctx->key_dma, + ctx->adata.keylen_pad + + keys.enckeylen, ctx->dir); + goto skip_split_key; + } + ret = gen_split_key(jrdev, ctx->key, &ctx->adata, keys.authkey, keys.authkeylen, CAAM_MAX_KEY_SIZE - keys.enckeylen); @@ -220,13 +245,14 @@ static int aead_setkey(struct crypto_aead *aead, const u8 *key, /* postpend encryption key to auth split key */ memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen); dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->adata.keylen_pad + - keys.enckeylen, DMA_TO_DEVICE); + keys.enckeylen, ctx->dir); #ifdef DEBUG print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, ctx->adata.keylen_pad + keys.enckeylen, 1); #endif +skip_split_key: ctx->cdata.keylen = keys.enckeylen; ret = aead_set_sh_desc(aead); @@ -272,7 +298,6 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, const bool is_rfc3686 = (ctr_mode && strstr(alg_name, "rfc3686")); int ret = 0; - memcpy(ctx->key, key, keylen); #ifdef DEBUG print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); @@ -295,9 +320,8 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, keylen -= CTR_RFC3686_NONCE_SIZE; } - dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, DMA_TO_DEVICE); ctx->cdata.keylen = keylen; - ctx->cdata.key_virt = ctx->key; + ctx->cdata.key_virt = key; ctx->cdata.key_inline = true; /* ablkcipher encrypt, decrypt, givencrypt shared descriptors */ @@ -356,10 +380,8 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, return -EINVAL; } - memcpy(ctx->key, key, keylen); - dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, DMA_TO_DEVICE); ctx->cdata.keylen = keylen; - ctx->cdata.key_virt = ctx->key; + ctx->cdata.key_virt = key; ctx->cdata.key_inline = true; /* xts ablkcipher encrypt, decrypt shared descriptors */ @@ -668,7 +690,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, qm_sg_ents = 1 + !!ivsize + mapped_src_nents + (mapped_dst_nents > 1 ? mapped_dst_nents : 0); if (unlikely(qm_sg_ents > CAAM_QI_MAX_AEAD_SG)) { - dev_err(qidev, "Insufficient S/G entries: %d > %lu\n", + dev_err(qidev, "Insufficient S/G entries: %d > %zu\n", qm_sg_ents, CAAM_QI_MAX_AEAD_SG); caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, iv_dma, ivsize, op_type, 0, 0); @@ -905,7 +927,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request qm_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0; if (unlikely(qm_sg_ents > CAAM_QI_MAX_ABLKCIPHER_SG)) { - dev_err(qidev, "Insufficient S/G entries: %d > %lu\n", + dev_err(qidev, "Insufficient S/G entries: %d > %zu\n", qm_sg_ents, CAAM_QI_MAX_ABLKCIPHER_SG); caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, iv_dma, ivsize, op_type, 0, 0); @@ -1058,7 +1080,7 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( } if (unlikely(qm_sg_ents > CAAM_QI_MAX_ABLKCIPHER_SG)) { - dev_err(qidev, "Insufficient S/G entries: %d > %lu\n", + dev_err(qidev, "Insufficient S/G entries: %d > %zu\n", qm_sg_ents, CAAM_QI_MAX_ABLKCIPHER_SG); caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, iv_dma, ivsize, GIVENCRYPT, 0, 0); @@ -2123,7 +2145,8 @@ struct caam_crypto_alg { struct caam_alg_entry caam; }; -static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam) +static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam, + bool uses_dkp) { struct caam_drv_private *priv; @@ -2137,8 +2160,14 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam) return PTR_ERR(ctx->jrdev); } + priv = dev_get_drvdata(ctx->jrdev->parent); + if (priv->era >= 6 && uses_dkp) + ctx->dir = DMA_BIDIRECTIONAL; + else + ctx->dir = DMA_TO_DEVICE; + ctx->key_dma = dma_map_single(ctx->jrdev, ctx->key, sizeof(ctx->key), - DMA_TO_DEVICE); + ctx->dir); if (dma_mapping_error(ctx->jrdev, ctx->key_dma)) { dev_err(ctx->jrdev, "unable to map key\n"); caam_jr_free(ctx->jrdev); @@ -2149,7 +2178,6 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam) ctx->cdata.algtype = OP_TYPE_CLASS1_ALG | caam->class1_alg_type; ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam->class2_alg_type; - priv = dev_get_drvdata(ctx->jrdev->parent); ctx->qidev = priv->qidev; spin_lock_init(&ctx->lock); @@ -2167,7 +2195,7 @@ static int caam_cra_init(struct crypto_tfm *tfm) crypto_alg); struct caam_ctx *ctx = crypto_tfm_ctx(tfm); - return caam_init_common(ctx, &caam_alg->caam); + return caam_init_common(ctx, &caam_alg->caam, false); } static int caam_aead_init(struct crypto_aead *tfm) @@ -2177,7 +2205,8 @@ static int caam_aead_init(struct crypto_aead *tfm) aead); struct caam_ctx *ctx = crypto_aead_ctx(tfm); - return caam_init_common(ctx, &caam_alg->caam); + return caam_init_common(ctx, &caam_alg->caam, + alg->setkey == aead_setkey); } static void caam_exit_common(struct caam_ctx *ctx) @@ -2186,8 +2215,7 @@ static void caam_exit_common(struct caam_ctx *ctx) caam_drv_ctx_rel(ctx->drv_ctx[DECRYPT]); caam_drv_ctx_rel(ctx->drv_ctx[GIVENCRYPT]); - dma_unmap_single(ctx->jrdev, ctx->key_dma, sizeof(ctx->key), - DMA_TO_DEVICE); + dma_unmap_single(ctx->jrdev, ctx->key_dma, sizeof(ctx->key), ctx->dir); caam_jr_free(ctx->jrdev); } diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 616720a04e7a..0beb28196e20 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -107,6 +107,7 @@ struct caam_hash_ctx { dma_addr_t sh_desc_update_first_dma; dma_addr_t sh_desc_fin_dma; dma_addr_t sh_desc_digest_dma; + enum dma_data_direction dir; struct device *jrdev; u8 key[CAAM_MAX_HASH_KEY_SIZE]; int ctx_len; @@ -241,7 +242,8 @@ static inline int ctx_map_to_sec4_sg(struct device *jrdev, * read and write to seqout */ static inline void ahash_gen_sh_desc(u32 *desc, u32 state, int digestsize, - struct caam_hash_ctx *ctx, bool import_ctx) + struct caam_hash_ctx *ctx, bool import_ctx, + int era) { u32 op = ctx->adata.algtype; u32 *skip_key_load; @@ -254,9 +256,12 @@ static inline void ahash_gen_sh_desc(u32 *desc, u32 state, int digestsize, skip_key_load = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); - append_key_as_imm(desc, ctx->key, ctx->adata.keylen_pad, - ctx->adata.keylen, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); + if (era < 6) + append_key_as_imm(desc, ctx->key, ctx->adata.keylen_pad, + ctx->adata.keylen, CLASS_2 | + KEY_DEST_MDHA_SPLIT | KEY_ENC); + else + append_proto_dkp(desc, &ctx->adata); set_jump_tgt_here(desc, skip_key_load); @@ -289,13 +294,17 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); int digestsize = crypto_ahash_digestsize(ahash); struct device *jrdev = ctx->jrdev; + struct caam_drv_private *ctrlpriv = dev_get_drvdata(jrdev->parent); u32 *desc; + ctx->adata.key_virt = ctx->key; + /* ahash_update shared descriptor */ desc = ctx->sh_desc_update; - ahash_gen_sh_desc(desc, OP_ALG_AS_UPDATE, ctx->ctx_len, ctx, true); + ahash_gen_sh_desc(desc, OP_ALG_AS_UPDATE, ctx->ctx_len, ctx, true, + ctrlpriv->era); dma_sync_single_for_device(jrdev, ctx->sh_desc_update_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); #ifdef DEBUG print_hex_dump(KERN_ERR, "ahash update shdesc@"__stringify(__LINE__)": ", @@ -304,9 +313,10 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) /* ahash_update_first shared descriptor */ desc = ctx->sh_desc_update_first; - ahash_gen_sh_desc(desc, OP_ALG_AS_INIT, ctx->ctx_len, ctx, false); + ahash_gen_sh_desc(desc, OP_ALG_AS_INIT, ctx->ctx_len, ctx, false, + ctrlpriv->era); dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); #ifdef DEBUG print_hex_dump(KERN_ERR, "ahash update first shdesc@"__stringify(__LINE__)": ", @@ -315,9 +325,10 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) /* ahash_final shared descriptor */ desc = ctx->sh_desc_fin; - ahash_gen_sh_desc(desc, OP_ALG_AS_FINALIZE, digestsize, ctx, true); + ahash_gen_sh_desc(desc, OP_ALG_AS_FINALIZE, digestsize, ctx, true, + ctrlpriv->era); dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); #ifdef DEBUG print_hex_dump(KERN_ERR, "ahash final shdesc@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, @@ -326,9 +337,10 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) /* ahash_digest shared descriptor */ desc = ctx->sh_desc_digest; - ahash_gen_sh_desc(desc, OP_ALG_AS_INITFINAL, digestsize, ctx, false); + ahash_gen_sh_desc(desc, OP_ALG_AS_INITFINAL, digestsize, ctx, false, + ctrlpriv->era); dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma, - desc_bytes(desc), DMA_TO_DEVICE); + desc_bytes(desc), ctx->dir); #ifdef DEBUG print_hex_dump(KERN_ERR, "ahash digest shdesc@"__stringify(__LINE__)": ", @@ -421,6 +433,7 @@ static int ahash_setkey(struct crypto_ahash *ahash, struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); int blocksize = crypto_tfm_alg_blocksize(&ahash->base); int digestsize = crypto_ahash_digestsize(ahash); + struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctx->jrdev->parent); int ret; u8 *hashed_key = NULL; @@ -441,16 +454,26 @@ static int ahash_setkey(struct crypto_ahash *ahash, key = hashed_key; } - ret = gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, key, keylen, - CAAM_MAX_HASH_KEY_SIZE); - if (ret) - goto bad_free_key; + /* + * If DKP is supported, use it in the shared descriptor to generate + * the split key. + */ + if (ctrlpriv->era >= 6) { + ctx->adata.key_inline = true; + ctx->adata.keylen = keylen; + ctx->adata.keylen_pad = split_key_len(ctx->adata.algtype & + OP_ALG_ALGSEL_MASK); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, - ctx->adata.keylen_pad, 1); -#endif + if (ctx->adata.keylen_pad > CAAM_MAX_HASH_KEY_SIZE) + goto bad_free_key; + + memcpy(ctx->key, key, keylen); + } else { + ret = gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, key, + keylen, CAAM_MAX_HASH_KEY_SIZE); + if (ret) + goto bad_free_key; + } kfree(hashed_key); return ahash_set_sh_desc(ahash); @@ -1715,6 +1738,7 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) HASH_MSG_LEN + 64, HASH_MSG_LEN + SHA512_DIGEST_SIZE }; dma_addr_t dma_addr; + struct caam_drv_private *priv; /* * Get a Job ring from Job Ring driver to ensure in-order @@ -1726,10 +1750,13 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) return PTR_ERR(ctx->jrdev); } + priv = dev_get_drvdata(ctx->jrdev->parent); + ctx->dir = priv->era >= 6 ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE; + dma_addr = dma_map_single_attrs(ctx->jrdev, ctx->sh_desc_update, offsetof(struct caam_hash_ctx, sh_desc_update_dma), - DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); + ctx->dir, DMA_ATTR_SKIP_CPU_SYNC); if (dma_mapping_error(ctx->jrdev, dma_addr)) { dev_err(ctx->jrdev, "unable to map shared descriptors\n"); caam_jr_free(ctx->jrdev); @@ -1764,7 +1791,7 @@ static void caam_hash_cra_exit(struct crypto_tfm *tfm) dma_unmap_single_attrs(ctx->jrdev, ctx->sh_desc_update_dma, offsetof(struct caam_hash_ctx, sh_desc_update_dma), - DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); + ctx->dir, DMA_ATTR_SKIP_CPU_SYNC); caam_jr_free(ctx->jrdev); } diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 027e121c6f70..75d280cb2dc0 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -611,6 +611,8 @@ static int caam_probe(struct platform_device *pdev) goto iounmap_ctrl; } + ctrlpriv->era = caam_get_era(); + ret = of_platform_populate(nprop, caam_match, NULL, dev); if (ret) { dev_err(dev, "JR platform devices creation error\n"); @@ -742,7 +744,7 @@ static int caam_probe(struct platform_device *pdev) /* Report "alive" for developer to see */ dev_info(dev, "device ID = 0x%016llx (Era %d)\n", caam_id, - caam_get_era()); + ctrlpriv->era); dev_info(dev, "job rings = %d, qi = %d, dpaa2 = %s\n", ctrlpriv->total_jobrs, ctrlpriv->qi_present, caam_dpaa2 ? "yes" : "no"); diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h index 8142de7ba050..f76ff160a02c 100644 --- a/drivers/crypto/caam/desc.h +++ b/drivers/crypto/caam/desc.h @@ -444,6 +444,18 @@ #define OP_PCLID_DSAVERIFY (0x16 << OP_PCLID_SHIFT) #define OP_PCLID_RSAENC_PUBKEY (0x18 << OP_PCLID_SHIFT) #define OP_PCLID_RSADEC_PRVKEY (0x19 << OP_PCLID_SHIFT) +#define OP_PCLID_DKP_MD5 (0x20 << OP_PCLID_SHIFT) +#define OP_PCLID_DKP_SHA1 (0x21 << OP_PCLID_SHIFT) +#define OP_PCLID_DKP_SHA224 (0x22 << OP_PCLID_SHIFT) +#define OP_PCLID_DKP_SHA256 (0x23 << OP_PCLID_SHIFT) +#define OP_PCLID_DKP_SHA384 (0x24 << OP_PCLID_SHIFT) +#define OP_PCLID_DKP_SHA512 (0x25 << OP_PCLID_SHIFT) +#define OP_PCLID_DKP_RIF_MD5 (0x60 << OP_PCLID_SHIFT) +#define OP_PCLID_DKP_RIF_SHA1 (0x61 << OP_PCLID_SHIFT) +#define OP_PCLID_DKP_RIF_SHA224 (0x62 << OP_PCLID_SHIFT) +#define OP_PCLID_DKP_RIF_SHA256 (0x63 << OP_PCLID_SHIFT) +#define OP_PCLID_DKP_RIF_SHA384 (0x64 << OP_PCLID_SHIFT) +#define OP_PCLID_DKP_RIF_SHA512 (0x65 << OP_PCLID_SHIFT) /* Assuming OP_TYPE = OP_TYPE_DECAP_PROTOCOL/ENCAP_PROTOCOL */ #define OP_PCLID_IPSEC (0x01 << OP_PCLID_SHIFT) @@ -1093,6 +1105,22 @@ /* MacSec protinfos */ #define OP_PCL_MACSEC 0x0001 +/* Derived Key Protocol (DKP) Protinfo */ +#define OP_PCL_DKP_SRC_SHIFT 14 +#define OP_PCL_DKP_SRC_MASK (3 << OP_PCL_DKP_SRC_SHIFT) +#define OP_PCL_DKP_SRC_IMM (0 << OP_PCL_DKP_SRC_SHIFT) +#define OP_PCL_DKP_SRC_SEQ (1 << OP_PCL_DKP_SRC_SHIFT) +#define OP_PCL_DKP_SRC_PTR (2 << OP_PCL_DKP_SRC_SHIFT) +#define OP_PCL_DKP_SRC_SGF (3 << OP_PCL_DKP_SRC_SHIFT) +#define OP_PCL_DKP_DST_SHIFT 12 +#define OP_PCL_DKP_DST_MASK (3 << OP_PCL_DKP_DST_SHIFT) +#define OP_PCL_DKP_DST_IMM (0 << OP_PCL_DKP_DST_SHIFT) +#define OP_PCL_DKP_DST_SEQ (1 << OP_PCL_DKP_DST_SHIFT) +#define OP_PCL_DKP_DST_PTR (2 << OP_PCL_DKP_DST_SHIFT) +#define OP_PCL_DKP_DST_SGF (3 << OP_PCL_DKP_DST_SHIFT) +#define OP_PCL_DKP_KEY_SHIFT 0 +#define OP_PCL_DKP_KEY_MASK (0xfff << OP_PCL_DKP_KEY_SHIFT) + /* PKI unidirectional protocol protinfo bits */ #define OP_PCL_PKPROT_TEST 0x0008 #define OP_PCL_PKPROT_DECRYPT 0x0004 @@ -1452,6 +1480,7 @@ #define MATH_DEST_REG1 (0x01 << MATH_DEST_SHIFT) #define MATH_DEST_REG2 (0x02 << MATH_DEST_SHIFT) #define MATH_DEST_REG3 (0x03 << MATH_DEST_SHIFT) +#define MATH_DEST_DPOVRD (0x07 << MATH_DEST_SHIFT) #define MATH_DEST_SEQINLEN (0x08 << MATH_DEST_SHIFT) #define MATH_DEST_SEQOUTLEN (0x09 << MATH_DEST_SHIFT) #define MATH_DEST_VARSEQINLEN (0x0a << MATH_DEST_SHIFT) diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h index ba1ca0806f0a..d4256fa4a1d6 100644 --- a/drivers/crypto/caam/desc_constr.h +++ b/drivers/crypto/caam/desc_constr.h @@ -109,7 +109,7 @@ static inline void init_job_desc_shared(u32 * const desc, dma_addr_t ptr, append_ptr(desc, ptr); } -static inline void append_data(u32 * const desc, void *data, int len) +static inline void append_data(u32 * const desc, const void *data, int len) { u32 *offset = desc_end(desc); @@ -172,7 +172,7 @@ static inline void append_cmd_ptr_extlen(u32 * const desc, dma_addr_t ptr, append_cmd(desc, len); } -static inline void append_cmd_data(u32 * const desc, void *data, int len, +static inline void append_cmd_data(u32 * const desc, const void *data, int len, u32 command) { append_cmd(desc, command | IMMEDIATE | len); @@ -271,7 +271,7 @@ APPEND_SEQ_PTR_INTLEN(in, IN) APPEND_SEQ_PTR_INTLEN(out, OUT) #define APPEND_CMD_PTR_TO_IMM(cmd, op) \ -static inline void append_##cmd##_as_imm(u32 * const desc, void *data, \ +static inline void append_##cmd##_as_imm(u32 * const desc, const void *data, \ unsigned int len, u32 options) \ { \ PRINT_POS; \ @@ -312,7 +312,7 @@ APPEND_CMD_PTR_LEN(seq_out_ptr, SEQ_OUT_PTR, u32) * from length of immediate data provided, e.g., split keys */ #define APPEND_CMD_PTR_TO_IMM2(cmd, op) \ -static inline void append_##cmd##_as_imm(u32 * const desc, void *data, \ +static inline void append_##cmd##_as_imm(u32 * const desc, const void *data, \ unsigned int data_len, \ unsigned int len, u32 options) \ { \ @@ -452,7 +452,7 @@ struct alginfo { unsigned int keylen_pad; union { dma_addr_t key_dma; - void *key_virt; + const void *key_virt; }; bool key_inline; }; @@ -496,4 +496,45 @@ static inline int desc_inline_query(unsigned int sd_base_len, return (rem_bytes >= 0) ? 0 : -1; } +/** + * append_proto_dkp - Derived Key Protocol (DKP): key -> split key + * @desc: pointer to buffer used for descriptor construction + * @adata: pointer to authentication transform definitions. + * keylen should be the length of initial key, while keylen_pad + * the length of the derived (split) key. + * Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, SHA224, + * SHA256, SHA384, SHA512}. + */ +static inline void append_proto_dkp(u32 * const desc, struct alginfo *adata) +{ + u32 protid; + + /* + * Quick & dirty translation from OP_ALG_ALGSEL_{MD5, SHA*} + * to OP_PCLID_DKP_{MD5, SHA*} + */ + protid = (adata->algtype & OP_ALG_ALGSEL_SUBMASK) | + (0x20 << OP_ALG_ALGSEL_SHIFT); + + if (adata->key_inline) { + int words; + + append_operation(desc, OP_TYPE_UNI_PROTOCOL | protid | + OP_PCL_DKP_SRC_IMM | OP_PCL_DKP_DST_IMM | + adata->keylen); + append_data(desc, adata->key_virt, adata->keylen); + + /* Reserve space in descriptor buffer for the derived key */ + words = (ALIGN(adata->keylen_pad, CAAM_CMD_SZ) - + ALIGN(adata->keylen, CAAM_CMD_SZ)) / CAAM_CMD_SZ; + if (words) + (*desc) = cpu_to_caam32(caam32_to_cpu(*desc) + words); + } else { + append_operation(desc, OP_TYPE_UNI_PROTOCOL | protid | + OP_PCL_DKP_SRC_PTR | OP_PCL_DKP_DST_PTR | + adata->keylen); + append_ptr(desc, adata->key_dma); + } +} + #endif /* DESC_CONSTR_H */ diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h index 91f1107276e5..7696a774a362 100644 --- a/drivers/crypto/caam/intern.h +++ b/drivers/crypto/caam/intern.h @@ -84,6 +84,7 @@ struct caam_drv_private { u8 qi_present; /* Nonzero if QI present in device */ int secvio_irq; /* Security violation interrupt number */ int virt_en; /* Virtualization enabled in CAAM */ + int era; /* CAAM Era (internal HW revision) */ #define RNG4_MAX_HANDLES 2 /* RNG4 block */ diff --git a/drivers/crypto/caam/key_gen.c b/drivers/crypto/caam/key_gen.c index 8c79c3a153dc..312b5f042f31 100644 --- a/drivers/crypto/caam/key_gen.c +++ b/drivers/crypto/caam/key_gen.c @@ -11,36 +11,6 @@ #include "desc_constr.h" #include "key_gen.h" -/** - * split_key_len - Compute MDHA split key length for a given algorithm - * @hash: Hashing algorithm selection, one of OP_ALG_ALGSEL_* - MD5, SHA1, - * SHA224, SHA384, SHA512. - * - * Return: MDHA split key length - */ -static inline u32 split_key_len(u32 hash) -{ - /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */ - static const u8 mdpadlen[] = { 16, 20, 32, 32, 64, 64 }; - u32 idx; - - idx = (hash & OP_ALG_ALGSEL_SUBMASK) >> OP_ALG_ALGSEL_SHIFT; - - return (u32)(mdpadlen[idx] * 2); -} - -/** - * split_key_pad_len - Compute MDHA split key pad length for a given algorithm - * @hash: Hashing algorithm selection, one of OP_ALG_ALGSEL_* - MD5, SHA1, - * SHA224, SHA384, SHA512. - * - * Return: MDHA split key pad length - */ -static inline u32 split_key_pad_len(u32 hash) -{ - return ALIGN(split_key_len(hash), 16); -} - void split_key_done(struct device *dev, u32 *desc, u32 err, void *context) { diff --git a/drivers/crypto/caam/key_gen.h b/drivers/crypto/caam/key_gen.h index 5db055c25bd2..818f78f6fc1a 100644 --- a/drivers/crypto/caam/key_gen.h +++ b/drivers/crypto/caam/key_gen.h @@ -6,6 +6,36 @@ * */ +/** + * split_key_len - Compute MDHA split key length for a given algorithm + * @hash: Hashing algorithm selection, one of OP_ALG_ALGSEL_* - MD5, SHA1, + * SHA224, SHA384, SHA512. + * + * Return: MDHA split key length + */ +static inline u32 split_key_len(u32 hash) +{ + /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */ + static const u8 mdpadlen[] = { 16, 20, 32, 32, 64, 64 }; + u32 idx; + + idx = (hash & OP_ALG_ALGSEL_SUBMASK) >> OP_ALG_ALGSEL_SHIFT; + + return (u32)(mdpadlen[idx] * 2); +} + +/** + * split_key_pad_len - Compute MDHA split key pad length for a given algorithm + * @hash: Hashing algorithm selection, one of OP_ALG_ALGSEL_* - MD5, SHA1, + * SHA224, SHA384, SHA512. + * + * Return: MDHA split key pad length + */ +static inline u32 split_key_pad_len(u32 hash) +{ + return ALIGN(split_key_len(hash), 16); +} + struct split_key_result { struct completion completion; int err; diff --git a/drivers/crypto/cavium/cpt/cptvf_reqmanager.c b/drivers/crypto/cavium/cpt/cptvf_reqmanager.c index 169e66231bcf..b0ba4331944b 100644 --- a/drivers/crypto/cavium/cpt/cptvf_reqmanager.c +++ b/drivers/crypto/cavium/cpt/cptvf_reqmanager.c @@ -459,7 +459,8 @@ int process_request(struct cpt_vf *cptvf, struct cpt_request_info *req) info->completion_addr = kzalloc(sizeof(union cpt_res_s), GFP_KERNEL); if (unlikely(!info->completion_addr)) { dev_err(&pdev->dev, "Unable to allocate memory for completion_addr\n"); - return -ENOMEM; + ret = -ENOMEM; + goto request_cleanup; } result = (union cpt_res_s *)info->completion_addr; diff --git a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c index 4addc238a6ef..deaefd532aaa 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c +++ b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c @@ -6,7 +6,6 @@ #include "nitrox_dev.h" #include "nitrox_req.h" #include "nitrox_csr.h" -#include "nitrox_req.h" /* SLC_STORE_INFO */ #define MIN_UDD_LEN 16 diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig index 6d626606b9c5..b9dfae47aefd 100644 --- a/drivers/crypto/ccp/Kconfig +++ b/drivers/crypto/ccp/Kconfig @@ -1,5 +1,6 @@ config CRYPTO_DEV_CCP_DD tristate "Secure Processor device driver" + depends on CPU_SUP_AMD || ARM64 default m help Provides AMD Secure Processor device driver. @@ -32,3 +33,14 @@ config CRYPTO_DEV_CCP_CRYPTO Support for using the cryptographic API with the AMD Cryptographic Coprocessor. This module supports offload of SHA and AES algorithms. If you choose 'M' here, this module will be called ccp_crypto. + +config CRYPTO_DEV_SP_PSP + bool "Platform Security Processor (PSP) device" + default y + depends on CRYPTO_DEV_CCP_DD && X86_64 + help + Provide support for the AMD Platform Security Processor (PSP). + The PSP is a dedicated processor that provides support for key + management commands in Secure Encrypted Virtualization (SEV) mode, + along with software-based Trusted Execution Environment (TEE) to + enable third-party trusted applications. diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile index c4ce726b931e..51d1c0cf66c7 100644 --- a/drivers/crypto/ccp/Makefile +++ b/drivers/crypto/ccp/Makefile @@ -8,6 +8,7 @@ ccp-$(CONFIG_CRYPTO_DEV_SP_CCP) += ccp-dev.o \ ccp-dmaengine.o \ ccp-debugfs.o ccp-$(CONFIG_PCI) += sp-pci.o +ccp-$(CONFIG_CRYPTO_DEV_SP_PSP) += psp-dev.o obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o ccp-crypto-objs := ccp-crypto-main.o \ diff --git a/drivers/crypto/ccp/ccp-crypto-aes-galois.c b/drivers/crypto/ccp/ccp-crypto-aes-galois.c index ff02b713c6f6..ca1f0d780b61 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes-galois.c +++ b/drivers/crypto/ccp/ccp-crypto-aes-galois.c @@ -21,7 +21,6 @@ #include #include #include -#include #include "ccp-crypto.h" diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c new file mode 100644 index 000000000000..fcfa5b1eae61 --- /dev/null +++ b/drivers/crypto/ccp/psp-dev.c @@ -0,0 +1,805 @@ +/* + * AMD Platform Security Processor (PSP) interface + * + * Copyright (C) 2016-2017 Advanced Micro Devices, Inc. + * + * Author: Brijesh Singh + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sp-dev.h" +#include "psp-dev.h" + +#define DEVICE_NAME "sev" + +static DEFINE_MUTEX(sev_cmd_mutex); +static struct sev_misc_dev *misc_dev; +static struct psp_device *psp_master; + +static struct psp_device *psp_alloc_struct(struct sp_device *sp) +{ + struct device *dev = sp->dev; + struct psp_device *psp; + + psp = devm_kzalloc(dev, sizeof(*psp), GFP_KERNEL); + if (!psp) + return NULL; + + psp->dev = dev; + psp->sp = sp; + + snprintf(psp->name, sizeof(psp->name), "psp-%u", sp->ord); + + return psp; +} + +static irqreturn_t psp_irq_handler(int irq, void *data) +{ + struct psp_device *psp = data; + unsigned int status; + int reg; + + /* Read the interrupt status: */ + status = ioread32(psp->io_regs + PSP_P2CMSG_INTSTS); + + /* Check if it is command completion: */ + if (!(status & BIT(PSP_CMD_COMPLETE_REG))) + goto done; + + /* Check if it is SEV command completion: */ + reg = ioread32(psp->io_regs + PSP_CMDRESP); + if (reg & PSP_CMDRESP_RESP) { + psp->sev_int_rcvd = 1; + wake_up(&psp->sev_int_queue); + } + +done: + /* Clear the interrupt status by writing the same value we read. */ + iowrite32(status, psp->io_regs + PSP_P2CMSG_INTSTS); + + return IRQ_HANDLED; +} + +static void sev_wait_cmd_ioc(struct psp_device *psp, unsigned int *reg) +{ + psp->sev_int_rcvd = 0; + + wait_event(psp->sev_int_queue, psp->sev_int_rcvd); + *reg = ioread32(psp->io_regs + PSP_CMDRESP); +} + +static int sev_cmd_buffer_len(int cmd) +{ + switch (cmd) { + case SEV_CMD_INIT: return sizeof(struct sev_data_init); + case SEV_CMD_PLATFORM_STATUS: return sizeof(struct sev_user_data_status); + case SEV_CMD_PEK_CSR: return sizeof(struct sev_data_pek_csr); + case SEV_CMD_PEK_CERT_IMPORT: return sizeof(struct sev_data_pek_cert_import); + case SEV_CMD_PDH_CERT_EXPORT: return sizeof(struct sev_data_pdh_cert_export); + case SEV_CMD_LAUNCH_START: return sizeof(struct sev_data_launch_start); + case SEV_CMD_LAUNCH_UPDATE_DATA: return sizeof(struct sev_data_launch_update_data); + case SEV_CMD_LAUNCH_UPDATE_VMSA: return sizeof(struct sev_data_launch_update_vmsa); + case SEV_CMD_LAUNCH_FINISH: return sizeof(struct sev_data_launch_finish); + case SEV_CMD_LAUNCH_MEASURE: return sizeof(struct sev_data_launch_measure); + case SEV_CMD_ACTIVATE: return sizeof(struct sev_data_activate); + case SEV_CMD_DEACTIVATE: return sizeof(struct sev_data_deactivate); + case SEV_CMD_DECOMMISSION: return sizeof(struct sev_data_decommission); + case SEV_CMD_GUEST_STATUS: return sizeof(struct sev_data_guest_status); + case SEV_CMD_DBG_DECRYPT: return sizeof(struct sev_data_dbg); + case SEV_CMD_DBG_ENCRYPT: return sizeof(struct sev_data_dbg); + case SEV_CMD_SEND_START: return sizeof(struct sev_data_send_start); + case SEV_CMD_SEND_UPDATE_DATA: return sizeof(struct sev_data_send_update_data); + case SEV_CMD_SEND_UPDATE_VMSA: return sizeof(struct sev_data_send_update_vmsa); + case SEV_CMD_SEND_FINISH: return sizeof(struct sev_data_send_finish); + case SEV_CMD_RECEIVE_START: return sizeof(struct sev_data_receive_start); + case SEV_CMD_RECEIVE_FINISH: return sizeof(struct sev_data_receive_finish); + case SEV_CMD_RECEIVE_UPDATE_DATA: return sizeof(struct sev_data_receive_update_data); + case SEV_CMD_RECEIVE_UPDATE_VMSA: return sizeof(struct sev_data_receive_update_vmsa); + case SEV_CMD_LAUNCH_UPDATE_SECRET: return sizeof(struct sev_data_launch_secret); + default: return 0; + } + + return 0; +} + +static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret) +{ + struct psp_device *psp = psp_master; + unsigned int phys_lsb, phys_msb; + unsigned int reg, ret = 0; + + if (!psp) + return -ENODEV; + + /* Get the physical address of the command buffer */ + phys_lsb = data ? lower_32_bits(__psp_pa(data)) : 0; + phys_msb = data ? upper_32_bits(__psp_pa(data)) : 0; + + dev_dbg(psp->dev, "sev command id %#x buffer 0x%08x%08x\n", + cmd, phys_msb, phys_lsb); + + print_hex_dump_debug("(in): ", DUMP_PREFIX_OFFSET, 16, 2, data, + sev_cmd_buffer_len(cmd), false); + + iowrite32(phys_lsb, psp->io_regs + PSP_CMDBUFF_ADDR_LO); + iowrite32(phys_msb, psp->io_regs + PSP_CMDBUFF_ADDR_HI); + + reg = cmd; + reg <<= PSP_CMDRESP_CMD_SHIFT; + reg |= PSP_CMDRESP_IOC; + iowrite32(reg, psp->io_regs + PSP_CMDRESP); + + /* wait for command completion */ + sev_wait_cmd_ioc(psp, ®); + + if (psp_ret) + *psp_ret = reg & PSP_CMDRESP_ERR_MASK; + + if (reg & PSP_CMDRESP_ERR_MASK) { + dev_dbg(psp->dev, "sev command %#x failed (%#010x)\n", + cmd, reg & PSP_CMDRESP_ERR_MASK); + ret = -EIO; + } + + print_hex_dump_debug("(out): ", DUMP_PREFIX_OFFSET, 16, 2, data, + sev_cmd_buffer_len(cmd), false); + + return ret; +} + +static int sev_do_cmd(int cmd, void *data, int *psp_ret) +{ + int rc; + + mutex_lock(&sev_cmd_mutex); + rc = __sev_do_cmd_locked(cmd, data, psp_ret); + mutex_unlock(&sev_cmd_mutex); + + return rc; +} + +static int __sev_platform_init_locked(int *error) +{ + struct psp_device *psp = psp_master; + int rc = 0; + + if (!psp) + return -ENODEV; + + if (psp->sev_state == SEV_STATE_INIT) + return 0; + + rc = __sev_do_cmd_locked(SEV_CMD_INIT, &psp->init_cmd_buf, error); + if (rc) + return rc; + + psp->sev_state = SEV_STATE_INIT; + dev_dbg(psp->dev, "SEV firmware initialized\n"); + + return rc; +} + +int sev_platform_init(int *error) +{ + int rc; + + mutex_lock(&sev_cmd_mutex); + rc = __sev_platform_init_locked(error); + mutex_unlock(&sev_cmd_mutex); + + return rc; +} +EXPORT_SYMBOL_GPL(sev_platform_init); + +static int __sev_platform_shutdown_locked(int *error) +{ + int ret; + + ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, 0, error); + if (ret) + return ret; + + psp_master->sev_state = SEV_STATE_UNINIT; + dev_dbg(psp_master->dev, "SEV firmware shutdown\n"); + + return ret; +} + +static int sev_platform_shutdown(int *error) +{ + int rc; + + mutex_lock(&sev_cmd_mutex); + rc = __sev_platform_shutdown_locked(NULL); + mutex_unlock(&sev_cmd_mutex); + + return rc; +} + +static int sev_get_platform_state(int *state, int *error) +{ + int rc; + + rc = __sev_do_cmd_locked(SEV_CMD_PLATFORM_STATUS, + &psp_master->status_cmd_buf, error); + if (rc) + return rc; + + *state = psp_master->status_cmd_buf.state; + return rc; +} + +static int sev_ioctl_do_reset(struct sev_issue_cmd *argp) +{ + int state, rc; + + /* + * The SEV spec requires that FACTORY_RESET must be issued in + * UNINIT state. Before we go further lets check if any guest is + * active. + * + * If FW is in WORKING state then deny the request otherwise issue + * SHUTDOWN command do INIT -> UNINIT before issuing the FACTORY_RESET. + * + */ + rc = sev_get_platform_state(&state, &argp->error); + if (rc) + return rc; + + if (state == SEV_STATE_WORKING) + return -EBUSY; + + if (state == SEV_STATE_INIT) { + rc = __sev_platform_shutdown_locked(&argp->error); + if (rc) + return rc; + } + + return __sev_do_cmd_locked(SEV_CMD_FACTORY_RESET, 0, &argp->error); +} + +static int sev_ioctl_do_platform_status(struct sev_issue_cmd *argp) +{ + struct sev_user_data_status *data = &psp_master->status_cmd_buf; + int ret; + + ret = __sev_do_cmd_locked(SEV_CMD_PLATFORM_STATUS, data, &argp->error); + if (ret) + return ret; + + if (copy_to_user((void __user *)argp->data, data, sizeof(*data))) + ret = -EFAULT; + + return ret; +} + +static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp) +{ + int rc; + + if (psp_master->sev_state == SEV_STATE_UNINIT) { + rc = __sev_platform_init_locked(&argp->error); + if (rc) + return rc; + } + + return __sev_do_cmd_locked(cmd, 0, &argp->error); +} + +static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp) +{ + struct sev_user_data_pek_csr input; + struct sev_data_pek_csr *data; + void *blob = NULL; + int ret; + + if (copy_from_user(&input, (void __user *)argp->data, sizeof(input))) + return -EFAULT; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* userspace wants to query CSR length */ + if (!input.address || !input.length) + goto cmd; + + /* allocate a physically contiguous buffer to store the CSR blob */ + if (!access_ok(VERIFY_WRITE, input.address, input.length) || + input.length > SEV_FW_BLOB_MAX_SIZE) { + ret = -EFAULT; + goto e_free; + } + + blob = kmalloc(input.length, GFP_KERNEL); + if (!blob) { + ret = -ENOMEM; + goto e_free; + } + + data->address = __psp_pa(blob); + data->len = input.length; + +cmd: + if (psp_master->sev_state == SEV_STATE_UNINIT) { + ret = __sev_platform_init_locked(&argp->error); + if (ret) + goto e_free_blob; + } + + ret = __sev_do_cmd_locked(SEV_CMD_PEK_CSR, data, &argp->error); + + /* If we query the CSR length, FW responded with expected data. */ + input.length = data->len; + + if (copy_to_user((void __user *)argp->data, &input, sizeof(input))) { + ret = -EFAULT; + goto e_free_blob; + } + + if (blob) { + if (copy_to_user((void __user *)input.address, blob, input.length)) + ret = -EFAULT; + } + +e_free_blob: + kfree(blob); +e_free: + kfree(data); + return ret; +} + +void *psp_copy_user_blob(u64 __user uaddr, u32 len) +{ + void *data; + + if (!uaddr || !len) + return ERR_PTR(-EINVAL); + + /* verify that blob length does not exceed our limit */ + if (len > SEV_FW_BLOB_MAX_SIZE) + return ERR_PTR(-EINVAL); + + data = kmalloc(len, GFP_KERNEL); + if (!data) + return ERR_PTR(-ENOMEM); + + if (copy_from_user(data, (void __user *)(uintptr_t)uaddr, len)) + goto e_free; + + return data; + +e_free: + kfree(data); + return ERR_PTR(-EFAULT); +} +EXPORT_SYMBOL_GPL(psp_copy_user_blob); + +static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp) +{ + struct sev_user_data_pek_cert_import input; + struct sev_data_pek_cert_import *data; + void *pek_blob, *oca_blob; + int ret; + + if (copy_from_user(&input, (void __user *)argp->data, sizeof(input))) + return -EFAULT; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* copy PEK certificate blobs from userspace */ + pek_blob = psp_copy_user_blob(input.pek_cert_address, input.pek_cert_len); + if (IS_ERR(pek_blob)) { + ret = PTR_ERR(pek_blob); + goto e_free; + } + + data->pek_cert_address = __psp_pa(pek_blob); + data->pek_cert_len = input.pek_cert_len; + + /* copy PEK certificate blobs from userspace */ + oca_blob = psp_copy_user_blob(input.oca_cert_address, input.oca_cert_len); + if (IS_ERR(oca_blob)) { + ret = PTR_ERR(oca_blob); + goto e_free_pek; + } + + data->oca_cert_address = __psp_pa(oca_blob); + data->oca_cert_len = input.oca_cert_len; + + /* If platform is not in INIT state then transition it to INIT */ + if (psp_master->sev_state != SEV_STATE_INIT) { + ret = __sev_platform_init_locked(&argp->error); + if (ret) + goto e_free_oca; + } + + ret = __sev_do_cmd_locked(SEV_CMD_PEK_CERT_IMPORT, data, &argp->error); + +e_free_oca: + kfree(oca_blob); +e_free_pek: + kfree(pek_blob); +e_free: + kfree(data); + return ret; +} + +static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp) +{ + struct sev_user_data_pdh_cert_export input; + void *pdh_blob = NULL, *cert_blob = NULL; + struct sev_data_pdh_cert_export *data; + int ret; + + if (copy_from_user(&input, (void __user *)argp->data, sizeof(input))) + return -EFAULT; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* Userspace wants to query the certificate length. */ + if (!input.pdh_cert_address || + !input.pdh_cert_len || + !input.cert_chain_address) + goto cmd; + + /* Allocate a physically contiguous buffer to store the PDH blob. */ + if ((input.pdh_cert_len > SEV_FW_BLOB_MAX_SIZE) || + !access_ok(VERIFY_WRITE, input.pdh_cert_address, input.pdh_cert_len)) { + ret = -EFAULT; + goto e_free; + } + + /* Allocate a physically contiguous buffer to store the cert chain blob. */ + if ((input.cert_chain_len > SEV_FW_BLOB_MAX_SIZE) || + !access_ok(VERIFY_WRITE, input.cert_chain_address, input.cert_chain_len)) { + ret = -EFAULT; + goto e_free; + } + + pdh_blob = kmalloc(input.pdh_cert_len, GFP_KERNEL); + if (!pdh_blob) { + ret = -ENOMEM; + goto e_free; + } + + data->pdh_cert_address = __psp_pa(pdh_blob); + data->pdh_cert_len = input.pdh_cert_len; + + cert_blob = kmalloc(input.cert_chain_len, GFP_KERNEL); + if (!cert_blob) { + ret = -ENOMEM; + goto e_free_pdh; + } + + data->cert_chain_address = __psp_pa(cert_blob); + data->cert_chain_len = input.cert_chain_len; + +cmd: + /* If platform is not in INIT state then transition it to INIT. */ + if (psp_master->sev_state != SEV_STATE_INIT) { + ret = __sev_platform_init_locked(&argp->error); + if (ret) + goto e_free_cert; + } + + ret = __sev_do_cmd_locked(SEV_CMD_PDH_CERT_EXPORT, data, &argp->error); + + /* If we query the length, FW responded with expected data. */ + input.cert_chain_len = data->cert_chain_len; + input.pdh_cert_len = data->pdh_cert_len; + + if (copy_to_user((void __user *)argp->data, &input, sizeof(input))) { + ret = -EFAULT; + goto e_free_cert; + } + + if (pdh_blob) { + if (copy_to_user((void __user *)input.pdh_cert_address, + pdh_blob, input.pdh_cert_len)) { + ret = -EFAULT; + goto e_free_cert; + } + } + + if (cert_blob) { + if (copy_to_user((void __user *)input.cert_chain_address, + cert_blob, input.cert_chain_len)) + ret = -EFAULT; + } + +e_free_cert: + kfree(cert_blob); +e_free_pdh: + kfree(pdh_blob); +e_free: + kfree(data); + return ret; +} + +static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + struct sev_issue_cmd input; + int ret = -EFAULT; + + if (!psp_master) + return -ENODEV; + + if (ioctl != SEV_ISSUE_CMD) + return -EINVAL; + + if (copy_from_user(&input, argp, sizeof(struct sev_issue_cmd))) + return -EFAULT; + + if (input.cmd > SEV_MAX) + return -EINVAL; + + mutex_lock(&sev_cmd_mutex); + + switch (input.cmd) { + + case SEV_FACTORY_RESET: + ret = sev_ioctl_do_reset(&input); + break; + case SEV_PLATFORM_STATUS: + ret = sev_ioctl_do_platform_status(&input); + break; + case SEV_PEK_GEN: + ret = sev_ioctl_do_pek_pdh_gen(SEV_CMD_PEK_GEN, &input); + break; + case SEV_PDH_GEN: + ret = sev_ioctl_do_pek_pdh_gen(SEV_CMD_PDH_GEN, &input); + break; + case SEV_PEK_CSR: + ret = sev_ioctl_do_pek_csr(&input); + break; + case SEV_PEK_CERT_IMPORT: + ret = sev_ioctl_do_pek_import(&input); + break; + case SEV_PDH_CERT_EXPORT: + ret = sev_ioctl_do_pdh_export(&input); + break; + default: + ret = -EINVAL; + goto out; + } + + if (copy_to_user(argp, &input, sizeof(struct sev_issue_cmd))) + ret = -EFAULT; +out: + mutex_unlock(&sev_cmd_mutex); + + return ret; +} + +static const struct file_operations sev_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = sev_ioctl, +}; + +int sev_platform_status(struct sev_user_data_status *data, int *error) +{ + return sev_do_cmd(SEV_CMD_PLATFORM_STATUS, data, error); +} +EXPORT_SYMBOL_GPL(sev_platform_status); + +int sev_guest_deactivate(struct sev_data_deactivate *data, int *error) +{ + return sev_do_cmd(SEV_CMD_DEACTIVATE, data, error); +} +EXPORT_SYMBOL_GPL(sev_guest_deactivate); + +int sev_guest_activate(struct sev_data_activate *data, int *error) +{ + return sev_do_cmd(SEV_CMD_ACTIVATE, data, error); +} +EXPORT_SYMBOL_GPL(sev_guest_activate); + +int sev_guest_decommission(struct sev_data_decommission *data, int *error) +{ + return sev_do_cmd(SEV_CMD_DECOMMISSION, data, error); +} +EXPORT_SYMBOL_GPL(sev_guest_decommission); + +int sev_guest_df_flush(int *error) +{ + return sev_do_cmd(SEV_CMD_DF_FLUSH, 0, error); +} +EXPORT_SYMBOL_GPL(sev_guest_df_flush); + +static void sev_exit(struct kref *ref) +{ + struct sev_misc_dev *misc_dev = container_of(ref, struct sev_misc_dev, refcount); + + misc_deregister(&misc_dev->misc); +} + +static int sev_misc_init(struct psp_device *psp) +{ + struct device *dev = psp->dev; + int ret; + + /* + * SEV feature support can be detected on multiple devices but the SEV + * FW commands must be issued on the master. During probe, we do not + * know the master hence we create /dev/sev on the first device probe. + * sev_do_cmd() finds the right master device to which to issue the + * command to the firmware. + */ + if (!misc_dev) { + struct miscdevice *misc; + + misc_dev = devm_kzalloc(dev, sizeof(*misc_dev), GFP_KERNEL); + if (!misc_dev) + return -ENOMEM; + + misc = &misc_dev->misc; + misc->minor = MISC_DYNAMIC_MINOR; + misc->name = DEVICE_NAME; + misc->fops = &sev_fops; + + ret = misc_register(misc); + if (ret) + return ret; + + kref_init(&misc_dev->refcount); + } else { + kref_get(&misc_dev->refcount); + } + + init_waitqueue_head(&psp->sev_int_queue); + psp->sev_misc = misc_dev; + dev_dbg(dev, "registered SEV device\n"); + + return 0; +} + +static int sev_init(struct psp_device *psp) +{ + /* Check if device supports SEV feature */ + if (!(ioread32(psp->io_regs + PSP_FEATURE_REG) & 1)) { + dev_dbg(psp->dev, "device does not support SEV\n"); + return 1; + } + + return sev_misc_init(psp); +} + +int psp_dev_init(struct sp_device *sp) +{ + struct device *dev = sp->dev; + struct psp_device *psp; + int ret; + + ret = -ENOMEM; + psp = psp_alloc_struct(sp); + if (!psp) + goto e_err; + + sp->psp_data = psp; + + psp->vdata = (struct psp_vdata *)sp->dev_vdata->psp_vdata; + if (!psp->vdata) { + ret = -ENODEV; + dev_err(dev, "missing driver data\n"); + goto e_err; + } + + psp->io_regs = sp->io_map + psp->vdata->offset; + + /* Disable and clear interrupts until ready */ + iowrite32(0, psp->io_regs + PSP_P2CMSG_INTEN); + iowrite32(-1, psp->io_regs + PSP_P2CMSG_INTSTS); + + /* Request an irq */ + ret = sp_request_psp_irq(psp->sp, psp_irq_handler, psp->name, psp); + if (ret) { + dev_err(dev, "psp: unable to allocate an IRQ\n"); + goto e_err; + } + + ret = sev_init(psp); + if (ret) + goto e_irq; + + if (sp->set_psp_master_device) + sp->set_psp_master_device(sp); + + /* Enable interrupt */ + iowrite32(-1, psp->io_regs + PSP_P2CMSG_INTEN); + + return 0; + +e_irq: + sp_free_psp_irq(psp->sp, psp); +e_err: + sp->psp_data = NULL; + + dev_notice(dev, "psp initialization failed\n"); + + return ret; +} + +void psp_dev_destroy(struct sp_device *sp) +{ + struct psp_device *psp = sp->psp_data; + + if (psp->sev_misc) + kref_put(&misc_dev->refcount, sev_exit); + + sp_free_psp_irq(sp, psp); +} + +int sev_issue_cmd_external_user(struct file *filep, unsigned int cmd, + void *data, int *error) +{ + if (!filep || filep->f_op != &sev_fops) + return -EBADF; + + return sev_do_cmd(cmd, data, error); +} +EXPORT_SYMBOL_GPL(sev_issue_cmd_external_user); + +void psp_pci_init(void) +{ + struct sev_user_data_status *status; + struct sp_device *sp; + int error, rc; + + sp = sp_get_psp_master_device(); + if (!sp) + return; + + psp_master = sp->psp_data; + + /* Initialize the platform */ + rc = sev_platform_init(&error); + if (rc) { + dev_err(sp->dev, "SEV: failed to INIT error %#x\n", error); + goto err; + } + + /* Display SEV firmware version */ + status = &psp_master->status_cmd_buf; + rc = sev_platform_status(status, &error); + if (rc) { + dev_err(sp->dev, "SEV: failed to get status error %#x\n", error); + goto err; + } + + dev_info(sp->dev, "SEV API:%d.%d build:%d\n", status->api_major, + status->api_minor, status->build); + return; + +err: + psp_master = NULL; +} + +void psp_pci_exit(void) +{ + if (!psp_master) + return; + + sev_platform_shutdown(NULL); +} diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h new file mode 100644 index 000000000000..c81f0b11287a --- /dev/null +++ b/drivers/crypto/ccp/psp-dev.h @@ -0,0 +1,83 @@ +/* + * AMD Platform Security Processor (PSP) interface driver + * + * Copyright (C) 2017 Advanced Micro Devices, Inc. + * + * Author: Brijesh Singh + * + * 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. + */ + +#ifndef __PSP_DEV_H__ +#define __PSP_DEV_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sp-dev.h" + +#define PSP_C2PMSG(_num) ((_num) << 2) +#define PSP_CMDRESP PSP_C2PMSG(32) +#define PSP_CMDBUFF_ADDR_LO PSP_C2PMSG(56) +#define PSP_CMDBUFF_ADDR_HI PSP_C2PMSG(57) +#define PSP_FEATURE_REG PSP_C2PMSG(63) + +#define PSP_P2CMSG(_num) ((_num) << 2) +#define PSP_CMD_COMPLETE_REG 1 +#define PSP_CMD_COMPLETE PSP_P2CMSG(PSP_CMD_COMPLETE_REG) + +#define PSP_P2CMSG_INTEN 0x0110 +#define PSP_P2CMSG_INTSTS 0x0114 + +#define PSP_C2PMSG_ATTR_0 0x0118 +#define PSP_C2PMSG_ATTR_1 0x011c +#define PSP_C2PMSG_ATTR_2 0x0120 +#define PSP_C2PMSG_ATTR_3 0x0124 +#define PSP_P2CMSG_ATTR_0 0x0128 + +#define PSP_CMDRESP_CMD_SHIFT 16 +#define PSP_CMDRESP_IOC BIT(0) +#define PSP_CMDRESP_RESP BIT(31) +#define PSP_CMDRESP_ERR_MASK 0xffff + +#define MAX_PSP_NAME_LEN 16 + +struct sev_misc_dev { + struct kref refcount; + struct miscdevice misc; +}; + +struct psp_device { + struct list_head entry; + + struct psp_vdata *vdata; + char name[MAX_PSP_NAME_LEN]; + + struct device *dev; + struct sp_device *sp; + + void __iomem *io_regs; + + int sev_state; + unsigned int sev_int_rcvd; + wait_queue_head_t sev_int_queue; + struct sev_misc_dev *sev_misc; + struct sev_user_data_status status_cmd_buf; + struct sev_data_init init_cmd_buf; +}; + +#endif /* __PSP_DEV_H */ diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c index bef387c8abfd..eb0da6572720 100644 --- a/drivers/crypto/ccp/sp-dev.c +++ b/drivers/crypto/ccp/sp-dev.c @@ -198,6 +198,8 @@ int sp_init(struct sp_device *sp) if (sp->dev_vdata->ccp_vdata) ccp_dev_init(sp); + if (sp->dev_vdata->psp_vdata) + psp_dev_init(sp); return 0; } @@ -206,6 +208,9 @@ void sp_destroy(struct sp_device *sp) if (sp->dev_vdata->ccp_vdata) ccp_dev_destroy(sp); + if (sp->dev_vdata->psp_vdata) + psp_dev_destroy(sp); + sp_del_device(sp); } @@ -237,6 +242,27 @@ int sp_resume(struct sp_device *sp) } #endif +struct sp_device *sp_get_psp_master_device(void) +{ + struct sp_device *i, *ret = NULL; + unsigned long flags; + + write_lock_irqsave(&sp_unit_lock, flags); + if (list_empty(&sp_units)) + goto unlock; + + list_for_each_entry(i, &sp_units, entry) { + if (i->psp_data) + break; + } + + if (i->get_psp_master_device) + ret = i->get_psp_master_device(); +unlock: + write_unlock_irqrestore(&sp_unit_lock, flags); + return ret; +} + static int __init sp_mod_init(void) { #ifdef CONFIG_X86 @@ -246,6 +272,10 @@ static int __init sp_mod_init(void) if (ret) return ret; +#ifdef CONFIG_CRYPTO_DEV_SP_PSP + psp_pci_init(); +#endif + return 0; #endif @@ -265,6 +295,11 @@ static int __init sp_mod_init(void) static void __exit sp_mod_exit(void) { #ifdef CONFIG_X86 + +#ifdef CONFIG_CRYPTO_DEV_SP_PSP + psp_pci_exit(); +#endif + sp_pci_exit(); #endif diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h index 5ab486ade1ad..acb197b66ced 100644 --- a/drivers/crypto/ccp/sp-dev.h +++ b/drivers/crypto/ccp/sp-dev.h @@ -42,12 +42,17 @@ struct ccp_vdata { const unsigned int offset; const unsigned int rsamax; }; + +struct psp_vdata { + const unsigned int offset; +}; + /* Structure to hold SP device data */ struct sp_dev_vdata { const unsigned int bar; const struct ccp_vdata *ccp_vdata; - void *psp_vdata; + const struct psp_vdata *psp_vdata; }; struct sp_device { @@ -68,6 +73,10 @@ struct sp_device { /* DMA caching attribute support */ unsigned int axcache; + /* get and set master device */ + struct sp_device*(*get_psp_master_device)(void); + void (*set_psp_master_device)(struct sp_device *); + bool irq_registered; bool use_tasklet; @@ -103,6 +112,7 @@ void sp_free_ccp_irq(struct sp_device *sp, void *data); int sp_request_psp_irq(struct sp_device *sp, irq_handler_t handler, const char *name, void *data); void sp_free_psp_irq(struct sp_device *sp, void *data); +struct sp_device *sp_get_psp_master_device(void); #ifdef CONFIG_CRYPTO_DEV_SP_CCP @@ -130,4 +140,20 @@ static inline int ccp_dev_resume(struct sp_device *sp) } #endif /* CONFIG_CRYPTO_DEV_SP_CCP */ +#ifdef CONFIG_CRYPTO_DEV_SP_PSP + +int psp_dev_init(struct sp_device *sp); +void psp_pci_init(void); +void psp_dev_destroy(struct sp_device *sp); +void psp_pci_exit(void); + +#else /* !CONFIG_CRYPTO_DEV_SP_PSP */ + +static inline int psp_dev_init(struct sp_device *sp) { return 0; } +static inline void psp_pci_init(void) { } +static inline void psp_dev_destroy(struct sp_device *sp) { } +static inline void psp_pci_exit(void) { } + +#endif /* CONFIG_CRYPTO_DEV_SP_PSP */ + #endif diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c index 9859aa683a28..f5f43c50698a 100644 --- a/drivers/crypto/ccp/sp-pci.c +++ b/drivers/crypto/ccp/sp-pci.c @@ -25,6 +25,7 @@ #include #include "ccp-dev.h" +#include "psp-dev.h" #define MSIX_VECTORS 2 @@ -32,6 +33,7 @@ struct sp_pci { int msix_count; struct msix_entry msix_entry[MSIX_VECTORS]; }; +static struct sp_device *sp_dev_master; static int sp_get_msix_irqs(struct sp_device *sp) { @@ -108,6 +110,45 @@ static void sp_free_irqs(struct sp_device *sp) sp->psp_irq = 0; } +static bool sp_pci_is_master(struct sp_device *sp) +{ + struct device *dev_cur, *dev_new; + struct pci_dev *pdev_cur, *pdev_new; + + dev_new = sp->dev; + dev_cur = sp_dev_master->dev; + + pdev_new = to_pci_dev(dev_new); + pdev_cur = to_pci_dev(dev_cur); + + if (pdev_new->bus->number < pdev_cur->bus->number) + return true; + + if (PCI_SLOT(pdev_new->devfn) < PCI_SLOT(pdev_cur->devfn)) + return true; + + if (PCI_FUNC(pdev_new->devfn) < PCI_FUNC(pdev_cur->devfn)) + return true; + + return false; +} + +static void psp_set_master(struct sp_device *sp) +{ + if (!sp_dev_master) { + sp_dev_master = sp; + return; + } + + if (sp_pci_is_master(sp)) + sp_dev_master = sp; +} + +static struct sp_device *psp_get_master(void) +{ + return sp_dev_master; +} + static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct sp_device *sp; @@ -166,6 +207,8 @@ static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto e_err; pci_set_master(pdev); + sp->set_psp_master_device = psp_set_master; + sp->get_psp_master_device = psp_get_master; ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)); if (ret) { @@ -225,6 +268,12 @@ static int sp_pci_resume(struct pci_dev *pdev) } #endif +#ifdef CONFIG_CRYPTO_DEV_SP_PSP +static const struct psp_vdata psp_entry = { + .offset = 0x10500, +}; +#endif + static const struct sp_dev_vdata dev_vdata[] = { { .bar = 2, @@ -236,6 +285,9 @@ static const struct sp_dev_vdata dev_vdata[] = { .bar = 2, #ifdef CONFIG_CRYPTO_DEV_SP_CCP .ccp_vdata = &ccpv5a, +#endif +#ifdef CONFIG_CRYPTO_DEV_SP_PSP + .psp_vdata = &psp_entry #endif }, { diff --git a/drivers/crypto/chelsio/Kconfig b/drivers/crypto/chelsio/Kconfig index b56b3f711d94..5ae9f8706f17 100644 --- a/drivers/crypto/chelsio/Kconfig +++ b/drivers/crypto/chelsio/Kconfig @@ -19,3 +19,13 @@ config CRYPTO_DEV_CHELSIO To compile this driver as a module, choose M here: the module will be called chcr. + +config CHELSIO_IPSEC_INLINE + bool "Chelsio IPSec XFRM Tx crypto offload" + depends on CHELSIO_T4 + depends on CRYPTO_DEV_CHELSIO + depends on XFRM_OFFLOAD + depends on INET_ESP_OFFLOAD || INET6_ESP_OFFLOAD + default n + ---help--- + Enable support for IPSec Tx Inline. diff --git a/drivers/crypto/chelsio/Makefile b/drivers/crypto/chelsio/Makefile index bebdf06687ad..eaecaf1ebcf3 100644 --- a/drivers/crypto/chelsio/Makefile +++ b/drivers/crypto/chelsio/Makefile @@ -2,3 +2,4 @@ ccflags-y := -Idrivers/net/ethernet/chelsio/cxgb4 obj-$(CONFIG_CRYPTO_DEV_CHELSIO) += chcr.o chcr-objs := chcr_core.o chcr_algo.o +chcr-$(CONFIG_CHELSIO_IPSEC_INLINE) += chcr_ipsec.o diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index 4eed7171e2ae..34a02d690548 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -73,6 +73,29 @@ #define IV AES_BLOCK_SIZE +static unsigned int sgl_ent_len[] = { + 0, 0, 16, 24, 40, 48, 64, 72, 88, + 96, 112, 120, 136, 144, 160, 168, 184, + 192, 208, 216, 232, 240, 256, 264, 280, + 288, 304, 312, 328, 336, 352, 360, 376 +}; + +static unsigned int dsgl_ent_len[] = { + 0, 32, 32, 48, 48, 64, 64, 80, 80, + 112, 112, 128, 128, 144, 144, 160, 160, + 192, 192, 208, 208, 224, 224, 240, 240, + 272, 272, 288, 288, 304, 304, 320, 320 +}; + +static u32 round_constant[11] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000, 0x6C000000 +}; + +static int chcr_handle_cipher_resp(struct ablkcipher_request *req, + unsigned char *input, int err); + static inline struct chcr_aead_ctx *AEAD_CTX(struct chcr_context *ctx) { return ctx->crypto_ctx->aeadctx; @@ -108,18 +131,6 @@ static inline int is_ofld_imm(const struct sk_buff *skb) return (skb->len <= SGE_MAX_WR_LEN); } -/* - * sgl_len - calculates the size of an SGL of the given capacity - * @n: the number of SGL entries - * Calculates the number of flits needed for a scatter/gather list that - * can hold the given number of entries. - */ -static inline unsigned int sgl_len(unsigned int n) -{ - n--; - return (3 * n) / 2 + (n & 1) + 2; -} - static int sg_nents_xlen(struct scatterlist *sg, unsigned int reqlen, unsigned int entlen, unsigned int skip) @@ -160,7 +171,6 @@ static inline void chcr_handle_ahash_resp(struct ahash_request *req, if (input == NULL) goto out; - reqctx = ahash_request_ctx(req); digestsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(req)); if (reqctx->is_sg_map) chcr_hash_dma_unmap(&u_ctx->lldi.pdev->dev, req); @@ -183,30 +193,17 @@ static inline void chcr_handle_ahash_resp(struct ahash_request *req, } out: req->base.complete(&req->base, err); +} - } - -static inline void chcr_handle_aead_resp(struct aead_request *req, - unsigned char *input, - int err) +static inline int get_aead_subtype(struct crypto_aead *aead) { - struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct uld_ctx *u_ctx = ULD_CTX(a_ctx(tfm)); - - - chcr_aead_dma_unmap(&u_ctx->lldi.pdev->dev, req, reqctx->op); - if (reqctx->b0_dma) - dma_unmap_single(&u_ctx->lldi.pdev->dev, reqctx->b0_dma, - reqctx->b0_len, DMA_BIDIRECTIONAL); - if (reqctx->verify == VERIFY_SW) { - chcr_verify_tag(req, input, &err); - reqctx->verify = VERIFY_HW; + struct aead_alg *alg = crypto_aead_alg(aead); + struct chcr_alg_template *chcr_crypto_alg = + container_of(alg, struct chcr_alg_template, alg.aead); + return chcr_crypto_alg->type & CRYPTO_ALG_SUB_TYPE_MASK; } - req->base.complete(&req->base, err); -} -static void chcr_verify_tag(struct aead_request *req, u8 *input, int *err) +void chcr_verify_tag(struct aead_request *req, u8 *input, int *err) { u8 temp[SHA512_DIGEST_SIZE]; struct crypto_aead *tfm = crypto_aead_reqtfm(req); @@ -231,6 +228,25 @@ static void chcr_verify_tag(struct aead_request *req, u8 *input, int *err) *err = 0; } +static inline void chcr_handle_aead_resp(struct aead_request *req, + unsigned char *input, + int err) +{ + struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct uld_ctx *u_ctx = ULD_CTX(a_ctx(tfm)); + + chcr_aead_dma_unmap(&u_ctx->lldi.pdev->dev, req, reqctx->op); + if (reqctx->b0_dma) + dma_unmap_single(&u_ctx->lldi.pdev->dev, reqctx->b0_dma, + reqctx->b0_len, DMA_BIDIRECTIONAL); + if (reqctx->verify == VERIFY_SW) { + chcr_verify_tag(req, input, &err); + reqctx->verify = VERIFY_HW; + } + req->base.complete(&req->base, err); +} + /* * chcr_handle_resp - Unmap the DMA buffers associated with the request * @req: crypto request @@ -558,7 +574,8 @@ static void ulptx_walk_add_sg(struct ulptx_walk *walk, skip = 0; } } - if (walk->nents == 0) { + WARN(!sg, "SG should not be null here\n"); + if (sg && (walk->nents == 0)) { small = min_t(unsigned int, sg_dma_len(sg) - skip_len, len); sgmin = min_t(unsigned int, small, CHCR_SRC_SG_SIZE); walk->sgl->len0 = cpu_to_be32(sgmin); @@ -595,14 +612,6 @@ static void ulptx_walk_add_sg(struct ulptx_walk *walk, } } -static inline int get_aead_subtype(struct crypto_aead *aead) -{ - struct aead_alg *alg = crypto_aead_alg(aead); - struct chcr_alg_template *chcr_crypto_alg = - container_of(alg, struct chcr_alg_template, alg.aead); - return chcr_crypto_alg->type & CRYPTO_ALG_SUB_TYPE_MASK; -} - static inline int get_cryptoalg_subtype(struct crypto_tfm *tfm) { struct crypto_alg *alg = tfm->__crt_alg; @@ -675,7 +684,7 @@ static int chcr_sg_ent_in_wr(struct scatterlist *src, if (srclen <= dstlen) break; less = min_t(unsigned int, sg_dma_len(dst) - offset - - dstskip, CHCR_DST_SG_SIZE); + dstskip, CHCR_DST_SG_SIZE); dstlen += less; offset += less; if (offset == sg_dma_len(dst)) { @@ -686,7 +695,7 @@ static int chcr_sg_ent_in_wr(struct scatterlist *src, dstskip = 0; } src = sg_next(src); - srcskip = 0; + srcskip = 0; } return min(srclen, dstlen); } @@ -1008,7 +1017,8 @@ static unsigned int adjust_ctr_overflow(u8 *iv, u32 bytes) return bytes; } -static int chcr_update_tweak(struct ablkcipher_request *req, u8 *iv) +static int chcr_update_tweak(struct ablkcipher_request *req, u8 *iv, + u32 isfinal) { struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); struct ablk_ctx *ablkctx = ABLK_CTX(c_ctx(tfm)); @@ -1035,7 +1045,8 @@ static int chcr_update_tweak(struct ablkcipher_request *req, u8 *iv) for (i = 0; i < (round % 8); i++) gf128mul_x_ble((le128 *)iv, (le128 *)iv); - crypto_cipher_decrypt_one(cipher, iv, iv); + if (!isfinal) + crypto_cipher_decrypt_one(cipher, iv, iv); out: return ret; } @@ -1056,7 +1067,7 @@ static int chcr_update_cipher_iv(struct ablkcipher_request *req, CTR_RFC3686_IV_SIZE) = cpu_to_be32((reqctx->processed / AES_BLOCK_SIZE) + 1); else if (subtype == CRYPTO_ALG_SUB_TYPE_XTS) - ret = chcr_update_tweak(req, iv); + ret = chcr_update_tweak(req, iv, 0); else if (subtype == CRYPTO_ALG_SUB_TYPE_CBC) { if (reqctx->op) sg_pcopy_to_buffer(req->src, sg_nents(req->src), iv, @@ -1087,7 +1098,7 @@ static int chcr_final_cipher_iv(struct ablkcipher_request *req, ctr_add_iv(iv, req->info, (reqctx->processed / AES_BLOCK_SIZE)); else if (subtype == CRYPTO_ALG_SUB_TYPE_XTS) - ret = chcr_update_tweak(req, iv); + ret = chcr_update_tweak(req, iv, 1); else if (subtype == CRYPTO_ALG_SUB_TYPE_CBC) { if (reqctx->op) sg_pcopy_to_buffer(req->src, sg_nents(req->src), iv, @@ -1101,7 +1112,6 @@ static int chcr_final_cipher_iv(struct ablkcipher_request *req, } - static int chcr_handle_cipher_resp(struct ablkcipher_request *req, unsigned char *input, int err) { @@ -1135,10 +1145,10 @@ static int chcr_handle_cipher_resp(struct ablkcipher_request *req, bytes = chcr_sg_ent_in_wr(reqctx->srcsg, reqctx->dstsg, 1, SPACE_LEFT(ablkctx->enckey_len), reqctx->src_ofst, reqctx->dst_ofst); - if ((bytes + reqctx->processed) >= req->nbytes) - bytes = req->nbytes - reqctx->processed; - else - bytes = ROUND_16(bytes); + if ((bytes + reqctx->processed) >= req->nbytes) + bytes = req->nbytes - reqctx->processed; + else + bytes = ROUND_16(bytes); } else { /*CTR mode counter overfloa*/ bytes = req->nbytes - reqctx->processed; @@ -1239,15 +1249,15 @@ static int process_cipher(struct ablkcipher_request *req, MIN_CIPHER_SG, SPACE_LEFT(ablkctx->enckey_len), 0, 0); - if ((bytes + reqctx->processed) >= req->nbytes) - bytes = req->nbytes - reqctx->processed; - else - bytes = ROUND_16(bytes); + if ((bytes + reqctx->processed) >= req->nbytes) + bytes = req->nbytes - reqctx->processed; + else + bytes = ROUND_16(bytes); } else { bytes = req->nbytes; } if (get_cryptoalg_subtype(crypto_ablkcipher_tfm(tfm)) == - CRYPTO_ALG_SUB_TYPE_CTR) { + CRYPTO_ALG_SUB_TYPE_CTR) { bytes = adjust_ctr_overflow(req->info, bytes); } if (get_cryptoalg_subtype(crypto_ablkcipher_tfm(tfm)) == @@ -2014,11 +2024,8 @@ static int chcr_aead_common_init(struct aead_request *req, struct chcr_aead_ctx *aeadctx = AEAD_CTX(a_ctx(tfm)); struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); int error = -EINVAL; - unsigned int dst_size; unsigned int authsize = crypto_aead_authsize(tfm); - dst_size = req->assoclen + req->cryptlen + (op_type ? - -authsize : authsize); /* validate key size */ if (aeadctx->enckey_len == 0) goto err; @@ -2083,7 +2090,7 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, struct cpl_rx_phys_dsgl *phys_cpl; struct ulptx_sgl *ulptx; unsigned int transhdr_len; - unsigned int dst_size = 0, temp; + unsigned int dst_size = 0, temp, subtype = get_aead_subtype(tfm); unsigned int kctx_len = 0, dnents; unsigned int assoclen = req->assoclen; unsigned int authsize = crypto_aead_authsize(tfm); @@ -2097,24 +2104,19 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, return NULL; reqctx->b0_dma = 0; - if (get_aead_subtype(tfm) == CRYPTO_ALG_SUB_TYPE_AEAD_NULL) { + if (subtype == CRYPTO_ALG_SUB_TYPE_CBC_NULL || + subtype == CRYPTO_ALG_SUB_TYPE_CTR_NULL) { null = 1; assoclen = 0; } - dst_size = assoclen + req->cryptlen + (op_type ? -authsize : - authsize); error = chcr_aead_common_init(req, op_type); if (error) return ERR_PTR(error); - if (dst_size) { - dnents = sg_nents_xlen(req->dst, assoclen, CHCR_DST_SG_SIZE, 0); - dnents += sg_nents_xlen(req->dst, req->cryptlen + - (op_type ? -authsize : authsize), CHCR_DST_SG_SIZE, - req->assoclen); - dnents += MIN_AUTH_SG; // For IV - } else { - dnents = 0; - } + dnents = sg_nents_xlen(req->dst, assoclen, CHCR_DST_SG_SIZE, 0); + dnents += sg_nents_xlen(req->dst, req->cryptlen + + (op_type ? -authsize : authsize), CHCR_DST_SG_SIZE, + req->assoclen); + dnents += MIN_AUTH_SG; // For IV dst_size = get_space_for_phys_dsgl(dnents); kctx_len = (ntohl(KEY_CONTEXT_CTX_LEN_V(aeadctx->key_ctx_hdr)) << 4) @@ -2162,16 +2164,23 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, temp & 0xF, null ? 0 : assoclen + IV + 1, temp, temp); + if (subtype == CRYPTO_ALG_SUB_TYPE_CTR_NULL || + subtype == CRYPTO_ALG_SUB_TYPE_CTR_SHA) + temp = CHCR_SCMD_CIPHER_MODE_AES_CTR; + else + temp = CHCR_SCMD_CIPHER_MODE_AES_CBC; chcr_req->sec_cpl.seqno_numivs = FILL_SEC_CPL_SCMD0_SEQNO(op_type, (op_type == CHCR_ENCRYPT_OP) ? 1 : 0, - CHCR_SCMD_CIPHER_MODE_AES_CBC, + temp, actx->auth_mode, aeadctx->hmac_ctrl, IV >> 1); chcr_req->sec_cpl.ivgen_hdrlen = FILL_SEC_CPL_IVGEN_HDRLEN(0, 0, 1, 0, 0, dst_size); chcr_req->key_ctx.ctx_hdr = aeadctx->key_ctx_hdr; - if (op_type == CHCR_ENCRYPT_OP) + if (op_type == CHCR_ENCRYPT_OP || + subtype == CRYPTO_ALG_SUB_TYPE_CTR_SHA || + subtype == CRYPTO_ALG_SUB_TYPE_CTR_NULL) memcpy(chcr_req->key_ctx.key, aeadctx->key, aeadctx->enckey_len); else @@ -2181,7 +2190,16 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, memcpy(chcr_req->key_ctx.key + (DIV_ROUND_UP(aeadctx->enckey_len, 16) << 4), actx->h_iopad, kctx_len - (DIV_ROUND_UP(aeadctx->enckey_len, 16) << 4)); - memcpy(reqctx->iv, req->iv, IV); + if (subtype == CRYPTO_ALG_SUB_TYPE_CTR_SHA || + subtype == CRYPTO_ALG_SUB_TYPE_CTR_NULL) { + memcpy(reqctx->iv, aeadctx->nonce, CTR_RFC3686_NONCE_SIZE); + memcpy(reqctx->iv + CTR_RFC3686_NONCE_SIZE, req->iv, + CTR_RFC3686_IV_SIZE); + *(__be32 *)(reqctx->iv + CTR_RFC3686_NONCE_SIZE + + CTR_RFC3686_IV_SIZE) = cpu_to_be32(1); + } else { + memcpy(reqctx->iv, req->iv, IV); + } phys_cpl = (struct cpl_rx_phys_dsgl *)((u8 *)(chcr_req + 1) + kctx_len); ulptx = (struct ulptx_sgl *)((u8 *)(phys_cpl + 1) + dst_size); chcr_add_aead_dst_ent(req, phys_cpl, assoclen, op_type, qid); @@ -2202,9 +2220,9 @@ err: return ERR_PTR(error); } -static int chcr_aead_dma_map(struct device *dev, - struct aead_request *req, - unsigned short op_type) +int chcr_aead_dma_map(struct device *dev, + struct aead_request *req, + unsigned short op_type) { int error; struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); @@ -2246,9 +2264,9 @@ err: return -ENOMEM; } -static void chcr_aead_dma_unmap(struct device *dev, - struct aead_request *req, - unsigned short op_type) +void chcr_aead_dma_unmap(struct device *dev, + struct aead_request *req, + unsigned short op_type) { struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); struct crypto_aead *tfm = crypto_aead_reqtfm(req); @@ -2273,10 +2291,10 @@ static void chcr_aead_dma_unmap(struct device *dev, } } -static inline void chcr_add_aead_src_ent(struct aead_request *req, - struct ulptx_sgl *ulptx, - unsigned int assoclen, - unsigned short op_type) +void chcr_add_aead_src_ent(struct aead_request *req, + struct ulptx_sgl *ulptx, + unsigned int assoclen, + unsigned short op_type) { struct ulptx_walk ulp_walk; struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); @@ -2308,11 +2326,11 @@ static inline void chcr_add_aead_src_ent(struct aead_request *req, } } -static inline void chcr_add_aead_dst_ent(struct aead_request *req, - struct cpl_rx_phys_dsgl *phys_cpl, - unsigned int assoclen, - unsigned short op_type, - unsigned short qid) +void chcr_add_aead_dst_ent(struct aead_request *req, + struct cpl_rx_phys_dsgl *phys_cpl, + unsigned int assoclen, + unsigned short op_type, + unsigned short qid) { struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); struct crypto_aead *tfm = crypto_aead_reqtfm(req); @@ -2330,9 +2348,9 @@ static inline void chcr_add_aead_dst_ent(struct aead_request *req, dsgl_walk_end(&dsgl_walk, qid); } -static inline void chcr_add_cipher_src_ent(struct ablkcipher_request *req, - struct ulptx_sgl *ulptx, - struct cipher_wr_param *wrparam) +void chcr_add_cipher_src_ent(struct ablkcipher_request *req, + struct ulptx_sgl *ulptx, + struct cipher_wr_param *wrparam) { struct ulptx_walk ulp_walk; struct chcr_blkcipher_req_ctx *reqctx = ablkcipher_request_ctx(req); @@ -2355,10 +2373,10 @@ static inline void chcr_add_cipher_src_ent(struct ablkcipher_request *req, } } -static inline void chcr_add_cipher_dst_ent(struct ablkcipher_request *req, - struct cpl_rx_phys_dsgl *phys_cpl, - struct cipher_wr_param *wrparam, - unsigned short qid) +void chcr_add_cipher_dst_ent(struct ablkcipher_request *req, + struct cpl_rx_phys_dsgl *phys_cpl, + struct cipher_wr_param *wrparam, + unsigned short qid) { struct chcr_blkcipher_req_ctx *reqctx = ablkcipher_request_ctx(req); struct dsgl_walk dsgl_walk; @@ -2373,9 +2391,9 @@ static inline void chcr_add_cipher_dst_ent(struct ablkcipher_request *req, dsgl_walk_end(&dsgl_walk, qid); } -static inline void chcr_add_hash_src_ent(struct ahash_request *req, - struct ulptx_sgl *ulptx, - struct hash_wr_param *param) +void chcr_add_hash_src_ent(struct ahash_request *req, + struct ulptx_sgl *ulptx, + struct hash_wr_param *param) { struct ulptx_walk ulp_walk; struct chcr_ahash_req_ctx *reqctx = ahash_request_ctx(req); @@ -2395,16 +2413,13 @@ static inline void chcr_add_hash_src_ent(struct ahash_request *req, ulptx_walk_add_page(&ulp_walk, param->bfr_len, &reqctx->dma_addr); ulptx_walk_add_sg(&ulp_walk, req->src, param->sg_len, - 0); -// reqctx->srcsg = ulp_walk.last_sg; -// reqctx->src_ofst = ulp_walk.last_sg_len; - ulptx_walk_end(&ulp_walk); + 0); + ulptx_walk_end(&ulp_walk); } } - -static inline int chcr_hash_dma_map(struct device *dev, - struct ahash_request *req) +int chcr_hash_dma_map(struct device *dev, + struct ahash_request *req) { struct chcr_ahash_req_ctx *req_ctx = ahash_request_ctx(req); int error = 0; @@ -2414,13 +2429,13 @@ static inline int chcr_hash_dma_map(struct device *dev, error = dma_map_sg(dev, req->src, sg_nents(req->src), DMA_TO_DEVICE); if (!error) - return error; + return -ENOMEM; req_ctx->is_sg_map = 1; return 0; } -static inline void chcr_hash_dma_unmap(struct device *dev, - struct ahash_request *req) +void chcr_hash_dma_unmap(struct device *dev, + struct ahash_request *req) { struct chcr_ahash_req_ctx *req_ctx = ahash_request_ctx(req); @@ -2433,9 +2448,8 @@ static inline void chcr_hash_dma_unmap(struct device *dev, } - -static int chcr_cipher_dma_map(struct device *dev, - struct ablkcipher_request *req) +int chcr_cipher_dma_map(struct device *dev, + struct ablkcipher_request *req) { int error; struct chcr_blkcipher_req_ctx *reqctx = ablkcipher_request_ctx(req); @@ -2469,8 +2483,9 @@ err: dma_unmap_single(dev, reqctx->iv_dma, IV, DMA_BIDIRECTIONAL); return -ENOMEM; } -static void chcr_cipher_dma_unmap(struct device *dev, - struct ablkcipher_request *req) + +void chcr_cipher_dma_unmap(struct device *dev, + struct ablkcipher_request *req) { struct chcr_blkcipher_req_ctx *reqctx = ablkcipher_request_ctx(req); @@ -2666,8 +2681,6 @@ static struct sk_buff *create_aead_ccm_wr(struct aead_request *req, sub_type = get_aead_subtype(tfm); if (sub_type == CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309) assoclen -= 8; - dst_size = assoclen + req->cryptlen + (op_type ? -authsize : - authsize); error = chcr_aead_common_init(req, op_type); if (error) return ERR_PTR(error); @@ -2677,15 +2690,11 @@ static struct sk_buff *create_aead_ccm_wr(struct aead_request *req, error = aead_ccm_validate_input(op_type, req, aeadctx, sub_type); if (error) goto err; - if (dst_size) { - dnents = sg_nents_xlen(req->dst, assoclen, CHCR_DST_SG_SIZE, 0); - dnents += sg_nents_xlen(req->dst, req->cryptlen - + (op_type ? -authsize : authsize), - CHCR_DST_SG_SIZE, req->assoclen); - dnents += MIN_CCM_SG; // For IV and B0 - } else { - dnents = 0; - } + dnents = sg_nents_xlen(req->dst, assoclen, CHCR_DST_SG_SIZE, 0); + dnents += sg_nents_xlen(req->dst, req->cryptlen + + (op_type ? -authsize : authsize), + CHCR_DST_SG_SIZE, req->assoclen); + dnents += MIN_CCM_SG; // For IV and B0 dst_size = get_space_for_phys_dsgl(dnents); kctx_len = ((DIV_ROUND_UP(aeadctx->enckey_len, 16)) << 4) * 2; transhdr_len = CIPHER_TRANSHDR_SIZE(kctx_len, dst_size); @@ -2780,19 +2789,14 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, assoclen = req->assoclen - 8; reqctx->b0_dma = 0; - dst_size = assoclen + req->cryptlen + (op_type ? -authsize : authsize); error = chcr_aead_common_init(req, op_type); - if (error) - return ERR_PTR(error); - if (dst_size) { - dnents = sg_nents_xlen(req->dst, assoclen, CHCR_DST_SG_SIZE, 0); - dnents += sg_nents_xlen(req->dst, - req->cryptlen + (op_type ? -authsize : authsize), + if (error) + return ERR_PTR(error); + dnents = sg_nents_xlen(req->dst, assoclen, CHCR_DST_SG_SIZE, 0); + dnents += sg_nents_xlen(req->dst, req->cryptlen + + (op_type ? -authsize : authsize), CHCR_DST_SG_SIZE, req->assoclen); - dnents += MIN_GCM_SG; // For IV - } else { - dnents = 0; - } + dnents += MIN_GCM_SG; // For IV dst_size = get_space_for_phys_dsgl(dnents); kctx_len = ((DIV_ROUND_UP(aeadctx->enckey_len, 16)) << 4) + AEAD_H_SIZE; @@ -2829,10 +2833,10 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, chcr_req->sec_cpl.aadstart_cipherstop_hi = FILL_SEC_CPL_CIPHERSTOP_HI( assoclen ? 1 : 0, assoclen, assoclen + IV + 1, 0); - chcr_req->sec_cpl.cipherstop_lo_authinsert = + chcr_req->sec_cpl.cipherstop_lo_authinsert = FILL_SEC_CPL_AUTHINSERT(0, assoclen + IV + 1, temp, temp); - chcr_req->sec_cpl.seqno_numivs = + chcr_req->sec_cpl.seqno_numivs = FILL_SEC_CPL_SCMD0_SEQNO(op_type, (op_type == CHCR_ENCRYPT_OP) ? 1 : 0, CHCR_SCMD_CIPHER_MODE_AES_GCM, @@ -3212,7 +3216,7 @@ static int chcr_authenc_setkey(struct crypto_aead *authenc, const u8 *key, struct chcr_authenc_ctx *actx = AUTHENC_CTX(aeadctx); /* it contains auth and cipher key both*/ struct crypto_authenc_keys keys; - unsigned int bs; + unsigned int bs, subtype; unsigned int max_authsize = crypto_aead_alg(authenc)->maxauthsize; int err = 0, i, key_ctx_len = 0; unsigned char ck_size = 0; @@ -3241,6 +3245,15 @@ static int chcr_authenc_setkey(struct crypto_aead *authenc, const u8 *key, pr_err("chcr : Unsupported digest size\n"); goto out; } + subtype = get_aead_subtype(authenc); + if (subtype == CRYPTO_ALG_SUB_TYPE_CTR_SHA || + subtype == CRYPTO_ALG_SUB_TYPE_CTR_NULL) { + if (keys.enckeylen < CTR_RFC3686_NONCE_SIZE) + goto out; + memcpy(aeadctx->nonce, keys.enckey + (keys.enckeylen + - CTR_RFC3686_NONCE_SIZE), CTR_RFC3686_NONCE_SIZE); + keys.enckeylen -= CTR_RFC3686_NONCE_SIZE; + } if (keys.enckeylen == AES_KEYSIZE_128) { ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_128; } else if (keys.enckeylen == AES_KEYSIZE_192) { @@ -3258,9 +3271,12 @@ static int chcr_authenc_setkey(struct crypto_aead *authenc, const u8 *key, */ memcpy(aeadctx->key, keys.enckey, keys.enckeylen); aeadctx->enckey_len = keys.enckeylen; - get_aes_decrypt_key(actx->dec_rrkey, aeadctx->key, - aeadctx->enckey_len << 3); + if (subtype == CRYPTO_ALG_SUB_TYPE_CBC_SHA || + subtype == CRYPTO_ALG_SUB_TYPE_CBC_NULL) { + get_aes_decrypt_key(actx->dec_rrkey, aeadctx->key, + aeadctx->enckey_len << 3); + } base_hash = chcr_alloc_shash(max_authsize); if (IS_ERR(base_hash)) { pr_err("chcr : Base driver cannot be loaded\n"); @@ -3333,6 +3349,7 @@ static int chcr_aead_digest_null_setkey(struct crypto_aead *authenc, struct crypto_authenc_keys keys; int err; /* it contains auth and cipher key both*/ + unsigned int subtype; int key_ctx_len = 0; unsigned char ck_size = 0; @@ -3350,6 +3367,15 @@ static int chcr_aead_digest_null_setkey(struct crypto_aead *authenc, crypto_aead_set_flags(authenc, CRYPTO_TFM_RES_BAD_KEY_LEN); goto out; } + subtype = get_aead_subtype(authenc); + if (subtype == CRYPTO_ALG_SUB_TYPE_CTR_SHA || + subtype == CRYPTO_ALG_SUB_TYPE_CTR_NULL) { + if (keys.enckeylen < CTR_RFC3686_NONCE_SIZE) + goto out; + memcpy(aeadctx->nonce, keys.enckey + (keys.enckeylen + - CTR_RFC3686_NONCE_SIZE), CTR_RFC3686_NONCE_SIZE); + keys.enckeylen -= CTR_RFC3686_NONCE_SIZE; + } if (keys.enckeylen == AES_KEYSIZE_128) { ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_128; } else if (keys.enckeylen == AES_KEYSIZE_192) { @@ -3357,13 +3383,16 @@ static int chcr_aead_digest_null_setkey(struct crypto_aead *authenc, } else if (keys.enckeylen == AES_KEYSIZE_256) { ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_256; } else { - pr_err("chcr : Unsupported cipher key\n"); + pr_err("chcr : Unsupported cipher key %d\n", keys.enckeylen); goto out; } memcpy(aeadctx->key, keys.enckey, keys.enckeylen); aeadctx->enckey_len = keys.enckeylen; - get_aes_decrypt_key(actx->dec_rrkey, aeadctx->key, - aeadctx->enckey_len << 3); + if (subtype == CRYPTO_ALG_SUB_TYPE_CBC_SHA || + subtype == CRYPTO_ALG_SUB_TYPE_CBC_NULL) { + get_aes_decrypt_key(actx->dec_rrkey, aeadctx->key, + aeadctx->enckey_len << 3); + } key_ctx_len = sizeof(struct _key_ctx) + ((DIV_ROUND_UP(keys.enckeylen, 16)) << 4); @@ -3375,62 +3404,11 @@ out: aeadctx->enckey_len = 0; return -EINVAL; } -static int chcr_aead_encrypt(struct aead_request *req) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); - - reqctx->verify = VERIFY_HW; - - switch (get_aead_subtype(tfm)) { - case CRYPTO_ALG_SUB_TYPE_AEAD_AUTHENC: - case CRYPTO_ALG_SUB_TYPE_AEAD_NULL: - return chcr_aead_op(req, CHCR_ENCRYPT_OP, 0, - create_authenc_wr); - case CRYPTO_ALG_SUB_TYPE_AEAD_CCM: - case CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309: - return chcr_aead_op(req, CHCR_ENCRYPT_OP, 0, - create_aead_ccm_wr); - default: - return chcr_aead_op(req, CHCR_ENCRYPT_OP, 0, - create_gcm_wr); - } -} - -static int chcr_aead_decrypt(struct aead_request *req) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct chcr_aead_ctx *aeadctx = AEAD_CTX(a_ctx(tfm)); - struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); - int size; - - if (aeadctx->mayverify == VERIFY_SW) { - size = crypto_aead_maxauthsize(tfm); - reqctx->verify = VERIFY_SW; - } else { - size = 0; - reqctx->verify = VERIFY_HW; - } - - switch (get_aead_subtype(tfm)) { - case CRYPTO_ALG_SUB_TYPE_AEAD_AUTHENC: - case CRYPTO_ALG_SUB_TYPE_AEAD_NULL: - return chcr_aead_op(req, CHCR_DECRYPT_OP, size, - create_authenc_wr); - case CRYPTO_ALG_SUB_TYPE_AEAD_CCM: - case CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309: - return chcr_aead_op(req, CHCR_DECRYPT_OP, size, - create_aead_ccm_wr); - default: - return chcr_aead_op(req, CHCR_DECRYPT_OP, size, - create_gcm_wr); - } -} static int chcr_aead_op(struct aead_request *req, - unsigned short op_type, - int size, - create_wr_t create_wr_fn) + unsigned short op_type, + int size, + create_wr_t create_wr_fn) { struct crypto_aead *tfm = crypto_aead_reqtfm(req); struct uld_ctx *u_ctx; @@ -3459,6 +3437,63 @@ static int chcr_aead_op(struct aead_request *req, chcr_send_wr(skb); return -EINPROGRESS; } + +static int chcr_aead_encrypt(struct aead_request *req) +{ + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); + + reqctx->verify = VERIFY_HW; + + switch (get_aead_subtype(tfm)) { + case CRYPTO_ALG_SUB_TYPE_CTR_SHA: + case CRYPTO_ALG_SUB_TYPE_CBC_SHA: + case CRYPTO_ALG_SUB_TYPE_CBC_NULL: + case CRYPTO_ALG_SUB_TYPE_CTR_NULL: + return chcr_aead_op(req, CHCR_ENCRYPT_OP, 0, + create_authenc_wr); + case CRYPTO_ALG_SUB_TYPE_AEAD_CCM: + case CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309: + return chcr_aead_op(req, CHCR_ENCRYPT_OP, 0, + create_aead_ccm_wr); + default: + return chcr_aead_op(req, CHCR_ENCRYPT_OP, 0, + create_gcm_wr); + } +} + +static int chcr_aead_decrypt(struct aead_request *req) +{ + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct chcr_aead_ctx *aeadctx = AEAD_CTX(a_ctx(tfm)); + struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); + int size; + + if (aeadctx->mayverify == VERIFY_SW) { + size = crypto_aead_maxauthsize(tfm); + reqctx->verify = VERIFY_SW; + } else { + size = 0; + reqctx->verify = VERIFY_HW; + } + + switch (get_aead_subtype(tfm)) { + case CRYPTO_ALG_SUB_TYPE_CBC_SHA: + case CRYPTO_ALG_SUB_TYPE_CTR_SHA: + case CRYPTO_ALG_SUB_TYPE_CBC_NULL: + case CRYPTO_ALG_SUB_TYPE_CTR_NULL: + return chcr_aead_op(req, CHCR_DECRYPT_OP, size, + create_authenc_wr); + case CRYPTO_ALG_SUB_TYPE_AEAD_CCM: + case CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309: + return chcr_aead_op(req, CHCR_DECRYPT_OP, size, + create_aead_ccm_wr); + default: + return chcr_aead_op(req, CHCR_DECRYPT_OP, size, + create_gcm_wr); + } +} + static struct chcr_alg_template driver_algs[] = { /* AES-CBC */ { @@ -3742,7 +3777,7 @@ static struct chcr_alg_template driver_algs[] = { } }, { - .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_AEAD_AUTHENC, + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_CBC_SHA, .is_registered = 0, .alg.aead = { .base = { @@ -3763,7 +3798,7 @@ static struct chcr_alg_template driver_algs[] = { } }, { - .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_AEAD_AUTHENC, + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_CBC_SHA, .is_registered = 0, .alg.aead = { .base = { @@ -3785,7 +3820,7 @@ static struct chcr_alg_template driver_algs[] = { } }, { - .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_AEAD_AUTHENC, + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_CBC_SHA, .is_registered = 0, .alg.aead = { .base = { @@ -3805,7 +3840,7 @@ static struct chcr_alg_template driver_algs[] = { } }, { - .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_AEAD_AUTHENC, + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_CBC_SHA, .is_registered = 0, .alg.aead = { .base = { @@ -3826,7 +3861,7 @@ static struct chcr_alg_template driver_algs[] = { } }, { - .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_AEAD_AUTHENC, + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_CBC_SHA, .is_registered = 0, .alg.aead = { .base = { @@ -3847,7 +3882,7 @@ static struct chcr_alg_template driver_algs[] = { } }, { - .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_AEAD_NULL, + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_CBC_NULL, .is_registered = 0, .alg.aead = { .base = { @@ -3867,6 +3902,133 @@ static struct chcr_alg_template driver_algs[] = { .setauthsize = chcr_authenc_null_setauthsize, } }, + { + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_CTR_SHA, + .is_registered = 0, + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha1),rfc3686(ctr(aes)))", + .cra_driver_name = + "authenc-hmac-sha1-rfc3686-ctr-aes-chcr", + .cra_blocksize = 1, + .cra_priority = CHCR_AEAD_PRIORITY, + .cra_ctxsize = sizeof(struct chcr_context) + + sizeof(struct chcr_aead_ctx) + + sizeof(struct chcr_authenc_ctx), + + }, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + .setkey = chcr_authenc_setkey, + .setauthsize = chcr_authenc_setauthsize, + } + }, + { + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_CTR_SHA, + .is_registered = 0, + .alg.aead = { + .base = { + + .cra_name = "authenc(hmac(sha256),rfc3686(ctr(aes)))", + .cra_driver_name = + "authenc-hmac-sha256-rfc3686-ctr-aes-chcr", + .cra_blocksize = 1, + .cra_priority = CHCR_AEAD_PRIORITY, + .cra_ctxsize = sizeof(struct chcr_context) + + sizeof(struct chcr_aead_ctx) + + sizeof(struct chcr_authenc_ctx), + + }, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + .setkey = chcr_authenc_setkey, + .setauthsize = chcr_authenc_setauthsize, + } + }, + { + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_CTR_SHA, + .is_registered = 0, + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha224),rfc3686(ctr(aes)))", + .cra_driver_name = + "authenc-hmac-sha224-rfc3686-ctr-aes-chcr", + .cra_blocksize = 1, + .cra_priority = CHCR_AEAD_PRIORITY, + .cra_ctxsize = sizeof(struct chcr_context) + + sizeof(struct chcr_aead_ctx) + + sizeof(struct chcr_authenc_ctx), + }, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + .setkey = chcr_authenc_setkey, + .setauthsize = chcr_authenc_setauthsize, + } + }, + { + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_CTR_SHA, + .is_registered = 0, + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha384),rfc3686(ctr(aes)))", + .cra_driver_name = + "authenc-hmac-sha384-rfc3686-ctr-aes-chcr", + .cra_blocksize = 1, + .cra_priority = CHCR_AEAD_PRIORITY, + .cra_ctxsize = sizeof(struct chcr_context) + + sizeof(struct chcr_aead_ctx) + + sizeof(struct chcr_authenc_ctx), + + }, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + .setkey = chcr_authenc_setkey, + .setauthsize = chcr_authenc_setauthsize, + } + }, + { + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_CTR_SHA, + .is_registered = 0, + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha512),rfc3686(ctr(aes)))", + .cra_driver_name = + "authenc-hmac-sha512-rfc3686-ctr-aes-chcr", + .cra_blocksize = 1, + .cra_priority = CHCR_AEAD_PRIORITY, + .cra_ctxsize = sizeof(struct chcr_context) + + sizeof(struct chcr_aead_ctx) + + sizeof(struct chcr_authenc_ctx), + + }, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + .setkey = chcr_authenc_setkey, + .setauthsize = chcr_authenc_setauthsize, + } + }, + { + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_CTR_NULL, + .is_registered = 0, + .alg.aead = { + .base = { + .cra_name = "authenc(digest_null,rfc3686(ctr(aes)))", + .cra_driver_name = + "authenc-digest_null-rfc3686-ctr-aes-chcr", + .cra_blocksize = 1, + .cra_priority = CHCR_AEAD_PRIORITY, + .cra_ctxsize = sizeof(struct chcr_context) + + sizeof(struct chcr_aead_ctx) + + sizeof(struct chcr_authenc_ctx), + + }, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = 0, + .setkey = chcr_aead_digest_null_setkey, + .setauthsize = chcr_authenc_null_setauthsize, + } + }, + }; /* diff --git a/drivers/crypto/chelsio/chcr_algo.h b/drivers/crypto/chelsio/chcr_algo.h index 96c9335ee728..d1673a5d4bf5 100644 --- a/drivers/crypto/chelsio/chcr_algo.h +++ b/drivers/crypto/chelsio/chcr_algo.h @@ -226,15 +226,6 @@ #define SPACE_LEFT(len) \ ((SGE_MAX_WR_LEN - WR_MIN_LEN - (len))) -unsigned int sgl_ent_len[] = {0, 0, 16, 24, 40, 48, 64, 72, 88, - 96, 112, 120, 136, 144, 160, 168, 184, - 192, 208, 216, 232, 240, 256, 264, 280, - 288, 304, 312, 328, 336, 352, 360, 376}; -unsigned int dsgl_ent_len[] = {0, 32, 32, 48, 48, 64, 64, 80, 80, - 112, 112, 128, 128, 144, 144, 160, 160, - 192, 192, 208, 208, 224, 224, 240, 240, - 272, 272, 288, 288, 304, 304, 320, 320}; - struct algo_param { unsigned int auth_mode; unsigned int mk_size; @@ -404,10 +395,4 @@ static inline u32 aes_ks_subword(const u32 w) return *(u32 *)(&bytes[0]); } -static u32 round_constant[11] = { - 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000, - 0x1B000000, 0x36000000, 0x6C000000 -}; - #endif /* __CHCR_ALGO_H__ */ diff --git a/drivers/crypto/chelsio/chcr_core.c b/drivers/crypto/chelsio/chcr_core.c index f5a2624081dc..04f277cade7c 100644 --- a/drivers/crypto/chelsio/chcr_core.c +++ b/drivers/crypto/chelsio/chcr_core.c @@ -48,6 +48,9 @@ static struct cxgb4_uld_info chcr_uld_info = { .add = chcr_uld_add, .state_change = chcr_uld_state_change, .rx_handler = chcr_uld_rx_handler, +#ifdef CONFIG_CHELSIO_IPSEC_INLINE + .tx_handler = chcr_uld_tx_handler, +#endif /* CONFIG_CHELSIO_IPSEC_INLINE */ }; struct uld_ctx *assign_chcr_device(void) @@ -164,6 +167,10 @@ static void *chcr_uld_add(const struct cxgb4_lld_info *lld) goto out; } u_ctx->lldi = *lld; +#ifdef CONFIG_CHELSIO_IPSEC_INLINE + if (lld->crypto & ULP_CRYPTO_IPSEC_INLINE) + chcr_add_xfrmops(lld); +#endif /* CONFIG_CHELSIO_IPSEC_INLINE */ out: return u_ctx; } @@ -187,6 +194,13 @@ int chcr_uld_rx_handler(void *handle, const __be64 *rsp, return 0; } +#ifdef CONFIG_CHELSIO_IPSEC_INLINE +int chcr_uld_tx_handler(struct sk_buff *skb, struct net_device *dev) +{ + return chcr_ipsec_xmit(skb, dev); +} +#endif /* CONFIG_CHELSIO_IPSEC_INLINE */ + static int chcr_uld_state_change(void *handle, enum cxgb4_state state) { struct uld_ctx *u_ctx = handle; diff --git a/drivers/crypto/chelsio/chcr_core.h b/drivers/crypto/chelsio/chcr_core.h index 94e7412f6164..3c29ee09b8b5 100644 --- a/drivers/crypto/chelsio/chcr_core.h +++ b/drivers/crypto/chelsio/chcr_core.h @@ -39,6 +39,7 @@ #include #include "t4_hw.h" #include "cxgb4.h" +#include "t4_msg.h" #include "cxgb4_uld.h" #define DRV_MODULE_NAME "chcr" @@ -89,12 +90,49 @@ struct uld_ctx { struct chcr_dev *dev; }; +struct chcr_ipsec_req { + struct ulp_txpkt ulptx; + struct ulptx_idata sc_imm; + struct cpl_tx_sec_pdu sec_cpl; + struct _key_ctx key_ctx; +}; + +struct chcr_ipsec_wr { + struct fw_ulptx_wr wreq; + struct chcr_ipsec_req req; +}; + +struct ipsec_sa_entry { + int hmac_ctrl; + unsigned int enckey_len; + unsigned int kctx_len; + unsigned int authsize; + __be32 key_ctx_hdr; + char salt[MAX_SALT]; + char key[2 * AES_MAX_KEY_SIZE]; +}; + +/* + * sgl_len - calculates the size of an SGL of the given capacity + * @n: the number of SGL entries + * Calculates the number of flits needed for a scatter/gather list that + * can hold the given number of entries. + */ +static inline unsigned int sgl_len(unsigned int n) +{ + n--; + return (3 * n) / 2 + (n & 1) + 2; +} + struct uld_ctx *assign_chcr_device(void); int chcr_send_wr(struct sk_buff *skb); int start_crypto(void); int stop_crypto(void); int chcr_uld_rx_handler(void *handle, const __be64 *rsp, const struct pkt_gl *pgl); +int chcr_uld_tx_handler(struct sk_buff *skb, struct net_device *dev); int chcr_handle_resp(struct crypto_async_request *req, unsigned char *input, int err); +int chcr_ipsec_xmit(struct sk_buff *skb, struct net_device *dev); +void chcr_add_xfrmops(const struct cxgb4_lld_info *lld); #endif /* __CHCR_CORE_H__ */ diff --git a/drivers/crypto/chelsio/chcr_crypto.h b/drivers/crypto/chelsio/chcr_crypto.h index 94a87e3ad9bc..7daf0a17a7d2 100644 --- a/drivers/crypto/chelsio/chcr_crypto.h +++ b/drivers/crypto/chelsio/chcr_crypto.h @@ -134,14 +134,16 @@ #define CRYPTO_ALG_SUB_TYPE_HASH_HMAC 0x01000000 #define CRYPTO_ALG_SUB_TYPE_AEAD_RFC4106 0x02000000 #define CRYPTO_ALG_SUB_TYPE_AEAD_GCM 0x03000000 -#define CRYPTO_ALG_SUB_TYPE_AEAD_AUTHENC 0x04000000 +#define CRYPTO_ALG_SUB_TYPE_CBC_SHA 0x04000000 #define CRYPTO_ALG_SUB_TYPE_AEAD_CCM 0x05000000 #define CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309 0x06000000 -#define CRYPTO_ALG_SUB_TYPE_AEAD_NULL 0x07000000 +#define CRYPTO_ALG_SUB_TYPE_CBC_NULL 0x07000000 #define CRYPTO_ALG_SUB_TYPE_CTR 0x08000000 #define CRYPTO_ALG_SUB_TYPE_CTR_RFC3686 0x09000000 #define CRYPTO_ALG_SUB_TYPE_XTS 0x0a000000 #define CRYPTO_ALG_SUB_TYPE_CBC 0x0b000000 +#define CRYPTO_ALG_SUB_TYPE_CTR_SHA 0x0c000000 +#define CRYPTO_ALG_SUB_TYPE_CTR_NULL 0x0d000000 #define CRYPTO_ALG_TYPE_HMAC (CRYPTO_ALG_TYPE_AHASH |\ CRYPTO_ALG_SUB_TYPE_HASH_HMAC) @@ -210,8 +212,6 @@ struct dsgl_walk { struct phys_sge_pairs *to; }; - - struct chcr_gcm_ctx { u8 ghash_h[AEAD_H_SIZE]; }; @@ -227,21 +227,18 @@ struct __aead_ctx { struct chcr_authenc_ctx authenc[0]; }; - - struct chcr_aead_ctx { __be32 key_ctx_hdr; unsigned int enckey_len; struct crypto_aead *sw_cipher; u8 salt[MAX_SALT]; u8 key[CHCR_AES_MAX_KEY_LEN]; + u8 nonce[4]; u16 hmac_ctrl; u16 mayverify; struct __aead_ctx ctx[0]; }; - - struct hmac_ctx { struct crypto_shash *base_hash; u8 ipad[CHCR_HASH_MAX_BLOCK_SIZE_128]; @@ -307,44 +304,29 @@ typedef struct sk_buff *(*create_wr_t)(struct aead_request *req, int size, unsigned short op_type); -static int chcr_aead_op(struct aead_request *req_base, - unsigned short op_type, - int size, - create_wr_t create_wr_fn); -static inline int get_aead_subtype(struct crypto_aead *aead); -static int chcr_handle_cipher_resp(struct ablkcipher_request *req, - unsigned char *input, int err); -static void chcr_verify_tag(struct aead_request *req, u8 *input, int *err); -static int chcr_aead_dma_map(struct device *dev, struct aead_request *req, - unsigned short op_type); -static void chcr_aead_dma_unmap(struct device *dev, struct aead_request - *req, unsigned short op_type); -static inline void chcr_add_aead_dst_ent(struct aead_request *req, - struct cpl_rx_phys_dsgl *phys_cpl, - unsigned int assoclen, - unsigned short op_type, - unsigned short qid); -static inline void chcr_add_aead_src_ent(struct aead_request *req, - struct ulptx_sgl *ulptx, - unsigned int assoclen, - unsigned short op_type); -static inline void chcr_add_cipher_src_ent(struct ablkcipher_request *req, - struct ulptx_sgl *ulptx, - struct cipher_wr_param *wrparam); -static int chcr_cipher_dma_map(struct device *dev, - struct ablkcipher_request *req); -static void chcr_cipher_dma_unmap(struct device *dev, - struct ablkcipher_request *req); -static inline void chcr_add_cipher_dst_ent(struct ablkcipher_request *req, - struct cpl_rx_phys_dsgl *phys_cpl, - struct cipher_wr_param *wrparam, - unsigned short qid); +void chcr_verify_tag(struct aead_request *req, u8 *input, int *err); +int chcr_aead_dma_map(struct device *dev, struct aead_request *req, + unsigned short op_type); +void chcr_aead_dma_unmap(struct device *dev, struct aead_request *req, + unsigned short op_type); +void chcr_add_aead_dst_ent(struct aead_request *req, + struct cpl_rx_phys_dsgl *phys_cpl, + unsigned int assoclen, unsigned short op_type, + unsigned short qid); +void chcr_add_aead_src_ent(struct aead_request *req, struct ulptx_sgl *ulptx, + unsigned int assoclen, unsigned short op_type); +void chcr_add_cipher_src_ent(struct ablkcipher_request *req, + struct ulptx_sgl *ulptx, + struct cipher_wr_param *wrparam); +int chcr_cipher_dma_map(struct device *dev, struct ablkcipher_request *req); +void chcr_cipher_dma_unmap(struct device *dev, struct ablkcipher_request *req); +void chcr_add_cipher_dst_ent(struct ablkcipher_request *req, + struct cpl_rx_phys_dsgl *phys_cpl, + struct cipher_wr_param *wrparam, + unsigned short qid); int sg_nents_len_skip(struct scatterlist *sg, u64 len, u64 skip); -static inline void chcr_add_hash_src_ent(struct ahash_request *req, - struct ulptx_sgl *ulptx, - struct hash_wr_param *param); -static inline int chcr_hash_dma_map(struct device *dev, - struct ahash_request *req); -static inline void chcr_hash_dma_unmap(struct device *dev, - struct ahash_request *req); +void chcr_add_hash_src_ent(struct ahash_request *req, struct ulptx_sgl *ulptx, + struct hash_wr_param *param); +int chcr_hash_dma_map(struct device *dev, struct ahash_request *req); +void chcr_hash_dma_unmap(struct device *dev, struct ahash_request *req); #endif /* __CHCR_CRYPTO_H__ */ diff --git a/drivers/crypto/chelsio/chcr_ipsec.c b/drivers/crypto/chelsio/chcr_ipsec.c new file mode 100644 index 000000000000..db1e241104ed --- /dev/null +++ b/drivers/crypto/chelsio/chcr_ipsec.c @@ -0,0 +1,654 @@ +/* + * This file is part of the Chelsio T6 Crypto driver for Linux. + * + * Copyright (c) 2003-2017 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Written and Maintained by: + * Atul Gupta (atul.gupta@chelsio.com) + */ + +#define pr_fmt(fmt) "chcr:" fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "chcr_core.h" +#include "chcr_algo.h" +#include "chcr_crypto.h" + +/* + * Max Tx descriptor space we allow for an Ethernet packet to be inlined + * into a WR. + */ +#define MAX_IMM_TX_PKT_LEN 256 +#define GCM_ESP_IV_SIZE 8 + +static int chcr_xfrm_add_state(struct xfrm_state *x); +static void chcr_xfrm_del_state(struct xfrm_state *x); +static void chcr_xfrm_free_state(struct xfrm_state *x); +static bool chcr_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *x); + +static const struct xfrmdev_ops chcr_xfrmdev_ops = { + .xdo_dev_state_add = chcr_xfrm_add_state, + .xdo_dev_state_delete = chcr_xfrm_del_state, + .xdo_dev_state_free = chcr_xfrm_free_state, + .xdo_dev_offload_ok = chcr_ipsec_offload_ok, +}; + +/* Add offload xfrms to Chelsio Interface */ +void chcr_add_xfrmops(const struct cxgb4_lld_info *lld) +{ + struct net_device *netdev = NULL; + int i; + + for (i = 0; i < lld->nports; i++) { + netdev = lld->ports[i]; + if (!netdev) + continue; + netdev->xfrmdev_ops = &chcr_xfrmdev_ops; + netdev->hw_enc_features |= NETIF_F_HW_ESP; + netdev->features |= NETIF_F_HW_ESP; + rtnl_lock(); + netdev_change_features(netdev); + rtnl_unlock(); + } +} + +static inline int chcr_ipsec_setauthsize(struct xfrm_state *x, + struct ipsec_sa_entry *sa_entry) +{ + int hmac_ctrl; + int authsize = x->aead->alg_icv_len / 8; + + sa_entry->authsize = authsize; + + switch (authsize) { + case ICV_8: + hmac_ctrl = CHCR_SCMD_HMAC_CTRL_DIV2; + break; + case ICV_12: + hmac_ctrl = CHCR_SCMD_HMAC_CTRL_IPSEC_96BIT; + break; + case ICV_16: + hmac_ctrl = CHCR_SCMD_HMAC_CTRL_NO_TRUNC; + break; + default: + return -EINVAL; + } + return hmac_ctrl; +} + +static inline int chcr_ipsec_setkey(struct xfrm_state *x, + struct ipsec_sa_entry *sa_entry) +{ + struct crypto_cipher *cipher; + int keylen = (x->aead->alg_key_len + 7) / 8; + unsigned char *key = x->aead->alg_key; + int ck_size, key_ctx_size = 0; + unsigned char ghash_h[AEAD_H_SIZE]; + int ret = 0; + + if (keylen > 3) { + keylen -= 4; /* nonce/salt is present in the last 4 bytes */ + memcpy(sa_entry->salt, key + keylen, 4); + } + + if (keylen == AES_KEYSIZE_128) { + ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_128; + } else if (keylen == AES_KEYSIZE_192) { + ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_192; + } else if (keylen == AES_KEYSIZE_256) { + ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_256; + } else { + pr_err("GCM: Invalid key length %d\n", keylen); + ret = -EINVAL; + goto out; + } + + memcpy(sa_entry->key, key, keylen); + sa_entry->enckey_len = keylen; + key_ctx_size = sizeof(struct _key_ctx) + + ((DIV_ROUND_UP(keylen, 16)) << 4) + + AEAD_H_SIZE; + + sa_entry->key_ctx_hdr = FILL_KEY_CTX_HDR(ck_size, + CHCR_KEYCTX_MAC_KEY_SIZE_128, + 0, 0, + key_ctx_size >> 4); + + /* Calculate the H = CIPH(K, 0 repeated 16 times). + * It will go in key context + */ + cipher = crypto_alloc_cipher("aes-generic", 0, 0); + if (IS_ERR(cipher)) { + sa_entry->enckey_len = 0; + ret = -ENOMEM; + goto out; + } + + ret = crypto_cipher_setkey(cipher, key, keylen); + if (ret) { + sa_entry->enckey_len = 0; + goto out1; + } + memset(ghash_h, 0, AEAD_H_SIZE); + crypto_cipher_encrypt_one(cipher, ghash_h, ghash_h); + memcpy(sa_entry->key + (DIV_ROUND_UP(sa_entry->enckey_len, 16) * + 16), ghash_h, AEAD_H_SIZE); + sa_entry->kctx_len = ((DIV_ROUND_UP(sa_entry->enckey_len, 16)) << 4) + + AEAD_H_SIZE; +out1: + crypto_free_cipher(cipher); +out: + return ret; +} + +/* + * chcr_xfrm_add_state + * returns 0 on success, negative error if failed to send message to FPGA + * positive error if FPGA returned a bad response + */ +static int chcr_xfrm_add_state(struct xfrm_state *x) +{ + struct ipsec_sa_entry *sa_entry; + int res = 0; + + if (x->props.aalgo != SADB_AALG_NONE) { + pr_debug("CHCR: Cannot offload authenticated xfrm states\n"); + return -EINVAL; + } + if (x->props.calgo != SADB_X_CALG_NONE) { + pr_debug("CHCR: Cannot offload compressed xfrm states\n"); + return -EINVAL; + } + if (x->props.flags & XFRM_STATE_ESN) { + pr_debug("CHCR: Cannot offload ESN xfrm states\n"); + return -EINVAL; + } + if (x->props.family != AF_INET && + x->props.family != AF_INET6) { + pr_debug("CHCR: Only IPv4/6 xfrm state offloaded\n"); + return -EINVAL; + } + if (x->props.mode != XFRM_MODE_TRANSPORT && + x->props.mode != XFRM_MODE_TUNNEL) { + pr_debug("CHCR: Only transport and tunnel xfrm offload\n"); + return -EINVAL; + } + if (x->id.proto != IPPROTO_ESP) { + pr_debug("CHCR: Only ESP xfrm state offloaded\n"); + return -EINVAL; + } + if (x->encap) { + pr_debug("CHCR: Encapsulated xfrm state not offloaded\n"); + return -EINVAL; + } + if (!x->aead) { + pr_debug("CHCR: Cannot offload xfrm states without aead\n"); + return -EINVAL; + } + if (x->aead->alg_icv_len != 128 && + x->aead->alg_icv_len != 96) { + pr_debug("CHCR: Cannot offload xfrm states with AEAD ICV length other than 96b & 128b\n"); + return -EINVAL; + } + if ((x->aead->alg_key_len != 128 + 32) && + (x->aead->alg_key_len != 256 + 32)) { + pr_debug("CHCR: Cannot offload xfrm states with AEAD key length other than 128/256 bit\n"); + return -EINVAL; + } + if (x->tfcpad) { + pr_debug("CHCR: Cannot offload xfrm states with tfc padding\n"); + return -EINVAL; + } + if (!x->geniv) { + pr_debug("CHCR: Cannot offload xfrm states without geniv\n"); + return -EINVAL; + } + if (strcmp(x->geniv, "seqiv")) { + pr_debug("CHCR: Cannot offload xfrm states with geniv other than seqiv\n"); + return -EINVAL; + } + + sa_entry = kzalloc(sizeof(*sa_entry), GFP_KERNEL); + if (!sa_entry) { + res = -ENOMEM; + goto out; + } + + sa_entry->hmac_ctrl = chcr_ipsec_setauthsize(x, sa_entry); + chcr_ipsec_setkey(x, sa_entry); + x->xso.offload_handle = (unsigned long)sa_entry; + try_module_get(THIS_MODULE); +out: + return res; +} + +static void chcr_xfrm_del_state(struct xfrm_state *x) +{ + /* do nothing */ + if (!x->xso.offload_handle) + return; +} + +static void chcr_xfrm_free_state(struct xfrm_state *x) +{ + struct ipsec_sa_entry *sa_entry; + + if (!x->xso.offload_handle) + return; + + sa_entry = (struct ipsec_sa_entry *)x->xso.offload_handle; + kfree(sa_entry); + module_put(THIS_MODULE); +} + +static bool chcr_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *x) +{ + /* Offload with IP options is not supported yet */ + if (ip_hdr(skb)->ihl > 5) + return false; + + return true; +} + +static inline int is_eth_imm(const struct sk_buff *skb, unsigned int kctx_len) +{ + int hdrlen = sizeof(struct chcr_ipsec_req) + kctx_len; + + hdrlen += sizeof(struct cpl_tx_pkt); + if (skb->len <= MAX_IMM_TX_PKT_LEN - hdrlen) + return hdrlen; + return 0; +} + +static inline unsigned int calc_tx_sec_flits(const struct sk_buff *skb, + unsigned int kctx_len) +{ + unsigned int flits; + int hdrlen = is_eth_imm(skb, kctx_len); + + /* If the skb is small enough, we can pump it out as a work request + * with only immediate data. In that case we just have to have the + * TX Packet header plus the skb data in the Work Request. + */ + + if (hdrlen) + return DIV_ROUND_UP(skb->len + hdrlen, sizeof(__be64)); + + flits = sgl_len(skb_shinfo(skb)->nr_frags + 1); + + /* Otherwise, we're going to have to construct a Scatter gather list + * of the skb body and fragments. We also include the flits necessary + * for the TX Packet Work Request and CPL. We always have a firmware + * Write Header (incorporated as part of the cpl_tx_pkt_lso and + * cpl_tx_pkt structures), followed by either a TX Packet Write CPL + * message or, if we're doing a Large Send Offload, an LSO CPL message + * with an embedded TX Packet Write CPL message. + */ + flits += (sizeof(struct fw_ulptx_wr) + + sizeof(struct chcr_ipsec_req) + + kctx_len + + sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64); + return flits; +} + +inline void *copy_cpltx_pktxt(struct sk_buff *skb, + struct net_device *dev, + void *pos) +{ + struct adapter *adap; + struct port_info *pi; + struct sge_eth_txq *q; + struct cpl_tx_pkt_core *cpl; + u64 cntrl = 0; + u32 ctrl0, qidx; + + pi = netdev_priv(dev); + adap = pi->adapter; + qidx = skb->queue_mapping; + q = &adap->sge.ethtxq[qidx + pi->first_qset]; + + cpl = (struct cpl_tx_pkt_core *)pos; + + if (skb->ip_summed == CHECKSUM_PARTIAL) + cntrl = TXPKT_L4CSUM_DIS_F | TXPKT_IPCSUM_DIS_F; + ctrl0 = TXPKT_OPCODE_V(CPL_TX_PKT_XT) | TXPKT_INTF_V(pi->tx_chan) | + TXPKT_PF_V(adap->pf); + if (skb_vlan_tag_present(skb)) { + q->vlan_ins++; + cntrl |= TXPKT_VLAN_VLD_F | TXPKT_VLAN_V(skb_vlan_tag_get(skb)); + } + + cpl->ctrl0 = htonl(ctrl0); + cpl->pack = htons(0); + cpl->len = htons(skb->len); + cpl->ctrl1 = cpu_to_be64(cntrl); + + pos += sizeof(struct cpl_tx_pkt_core); + return pos; +} + +inline void *copy_key_cpltx_pktxt(struct sk_buff *skb, + struct net_device *dev, + void *pos, + struct ipsec_sa_entry *sa_entry) +{ + struct adapter *adap; + struct port_info *pi; + struct sge_eth_txq *q; + unsigned int len, qidx; + struct _key_ctx *key_ctx; + int left, eoq, key_len; + + pi = netdev_priv(dev); + adap = pi->adapter; + qidx = skb->queue_mapping; + q = &adap->sge.ethtxq[qidx + pi->first_qset]; + len = sa_entry->enckey_len + sizeof(struct cpl_tx_pkt_core); + key_len = sa_entry->kctx_len; + + /* end of queue, reset pos to start of queue */ + eoq = (void *)q->q.stat - pos; + left = eoq; + if (!eoq) { + pos = q->q.desc; + left = 64 * q->q.size; + } + + /* Copy the Key context header */ + key_ctx = (struct _key_ctx *)pos; + key_ctx->ctx_hdr = sa_entry->key_ctx_hdr; + memcpy(key_ctx->salt, sa_entry->salt, MAX_SALT); + pos += sizeof(struct _key_ctx); + left -= sizeof(struct _key_ctx); + + if (likely(len <= left)) { + memcpy(key_ctx->key, sa_entry->key, key_len); + pos += key_len; + } else { + if (key_len <= left) { + memcpy(pos, sa_entry->key, key_len); + pos += key_len; + } else { + memcpy(pos, sa_entry->key, left); + memcpy(q->q.desc, sa_entry->key + left, + key_len - left); + pos = (u8 *)q->q.desc + (key_len - left); + } + } + /* Copy CPL TX PKT XT */ + pos = copy_cpltx_pktxt(skb, dev, pos); + + return pos; +} + +inline void *chcr_crypto_wreq(struct sk_buff *skb, + struct net_device *dev, + void *pos, + int credits, + struct ipsec_sa_entry *sa_entry) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adap = pi->adapter; + unsigned int immdatalen = 0; + unsigned int ivsize = GCM_ESP_IV_SIZE; + struct chcr_ipsec_wr *wr; + unsigned int flits; + u32 wr_mid; + int qidx = skb_get_queue_mapping(skb); + struct sge_eth_txq *q = &adap->sge.ethtxq[qidx + pi->first_qset]; + unsigned int kctx_len = sa_entry->kctx_len; + int qid = q->q.cntxt_id; + + atomic_inc(&adap->chcr_stats.ipsec_cnt); + + flits = calc_tx_sec_flits(skb, kctx_len); + + if (is_eth_imm(skb, kctx_len)) + immdatalen = skb->len; + + /* WR Header */ + wr = (struct chcr_ipsec_wr *)pos; + wr->wreq.op_to_compl = htonl(FW_WR_OP_V(FW_ULPTX_WR)); + wr_mid = FW_CRYPTO_LOOKASIDE_WR_LEN16_V(DIV_ROUND_UP(flits, 2)); + + if (unlikely(credits < ETHTXQ_STOP_THRES)) { + netif_tx_stop_queue(q->txq); + q->q.stops++; + wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F; + } + wr_mid |= FW_ULPTX_WR_DATA_F; + wr->wreq.flowid_len16 = htonl(wr_mid); + + /* ULPTX */ + wr->req.ulptx.cmd_dest = FILL_ULPTX_CMD_DEST(pi->port_id, qid); + wr->req.ulptx.len = htonl(DIV_ROUND_UP(flits, 2) - 1); + + /* Sub-command */ + wr->req.sc_imm.cmd_more = FILL_CMD_MORE(immdatalen); + wr->req.sc_imm.len = cpu_to_be32(sizeof(struct cpl_tx_sec_pdu) + + sizeof(wr->req.key_ctx) + + kctx_len + + sizeof(struct cpl_tx_pkt_core) + + immdatalen); + + /* CPL_SEC_PDU */ + wr->req.sec_cpl.op_ivinsrtofst = htonl( + CPL_TX_SEC_PDU_OPCODE_V(CPL_TX_SEC_PDU) | + CPL_TX_SEC_PDU_CPLLEN_V(2) | + CPL_TX_SEC_PDU_PLACEHOLDER_V(1) | + CPL_TX_SEC_PDU_IVINSRTOFST_V( + (skb_transport_offset(skb) + + sizeof(struct ip_esp_hdr) + 1))); + + wr->req.sec_cpl.pldlen = htonl(skb->len); + + wr->req.sec_cpl.aadstart_cipherstop_hi = FILL_SEC_CPL_CIPHERSTOP_HI( + (skb_transport_offset(skb) + 1), + (skb_transport_offset(skb) + + sizeof(struct ip_esp_hdr)), + (skb_transport_offset(skb) + + sizeof(struct ip_esp_hdr) + + GCM_ESP_IV_SIZE + 1), 0); + + wr->req.sec_cpl.cipherstop_lo_authinsert = + FILL_SEC_CPL_AUTHINSERT(0, skb_transport_offset(skb) + + sizeof(struct ip_esp_hdr) + + GCM_ESP_IV_SIZE + 1, + sa_entry->authsize, + sa_entry->authsize); + wr->req.sec_cpl.seqno_numivs = + FILL_SEC_CPL_SCMD0_SEQNO(CHCR_ENCRYPT_OP, 1, + CHCR_SCMD_CIPHER_MODE_AES_GCM, + CHCR_SCMD_AUTH_MODE_GHASH, + sa_entry->hmac_ctrl, + ivsize >> 1); + wr->req.sec_cpl.ivgen_hdrlen = FILL_SEC_CPL_IVGEN_HDRLEN(0, 0, 1, + 0, 0, 0); + + pos += sizeof(struct fw_ulptx_wr) + + sizeof(struct ulp_txpkt) + + sizeof(struct ulptx_idata) + + sizeof(struct cpl_tx_sec_pdu); + + pos = copy_key_cpltx_pktxt(skb, dev, pos, sa_entry); + + return pos; +} + +/** + * flits_to_desc - returns the num of Tx descriptors for the given flits + * @n: the number of flits + * + * Returns the number of Tx descriptors needed for the supplied number + * of flits. + */ +static inline unsigned int flits_to_desc(unsigned int n) +{ + WARN_ON(n > SGE_MAX_WR_LEN / 8); + return DIV_ROUND_UP(n, 8); +} + +static inline unsigned int txq_avail(const struct sge_txq *q) +{ + return q->size - 1 - q->in_use; +} + +static void eth_txq_stop(struct sge_eth_txq *q) +{ + netif_tx_stop_queue(q->txq); + q->q.stops++; +} + +static inline void txq_advance(struct sge_txq *q, unsigned int n) +{ + q->in_use += n; + q->pidx += n; + if (q->pidx >= q->size) + q->pidx -= q->size; +} + +/* + * chcr_ipsec_xmit called from ULD Tx handler + */ +int chcr_ipsec_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct xfrm_state *x = xfrm_input_state(skb); + struct ipsec_sa_entry *sa_entry; + u64 *pos, *end, *before, *sgl; + int qidx, left, credits; + unsigned int flits = 0, ndesc, kctx_len; + struct adapter *adap; + struct sge_eth_txq *q; + struct port_info *pi; + dma_addr_t addr[MAX_SKB_FRAGS + 1]; + bool immediate = false; + + if (!x->xso.offload_handle) + return NETDEV_TX_BUSY; + + sa_entry = (struct ipsec_sa_entry *)x->xso.offload_handle; + kctx_len = sa_entry->kctx_len; + + if (skb->sp->len != 1) { +out_free: dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + pi = netdev_priv(dev); + adap = pi->adapter; + qidx = skb->queue_mapping; + q = &adap->sge.ethtxq[qidx + pi->first_qset]; + + cxgb4_reclaim_completed_tx(adap, &q->q, true); + + flits = calc_tx_sec_flits(skb, sa_entry->kctx_len); + ndesc = flits_to_desc(flits); + credits = txq_avail(&q->q) - ndesc; + + if (unlikely(credits < 0)) { + eth_txq_stop(q); + dev_err(adap->pdev_dev, + "%s: Tx ring %u full while queue awake! cred:%d %d %d flits:%d\n", + dev->name, qidx, credits, ndesc, txq_avail(&q->q), + flits); + return NETDEV_TX_BUSY; + } + + if (is_eth_imm(skb, kctx_len)) + immediate = true; + + if (!immediate && + unlikely(cxgb4_map_skb(adap->pdev_dev, skb, addr) < 0)) { + q->mapping_err++; + goto out_free; + } + + pos = (u64 *)&q->q.desc[q->q.pidx]; + before = (u64 *)pos; + end = (u64 *)pos + flits; + /* Setup IPSec CPL */ + pos = (void *)chcr_crypto_wreq(skb, dev, (void *)pos, + credits, sa_entry); + if (before > (u64 *)pos) { + left = (u8 *)end - (u8 *)q->q.stat; + end = (void *)q->q.desc + left; + } + if (pos == (u64 *)q->q.stat) { + left = (u8 *)end - (u8 *)q->q.stat; + end = (void *)q->q.desc + left; + pos = (void *)q->q.desc; + } + + sgl = (void *)pos; + if (immediate) { + cxgb4_inline_tx_skb(skb, &q->q, sgl); + dev_consume_skb_any(skb); + } else { + int last_desc; + + cxgb4_write_sgl(skb, &q->q, (void *)sgl, end, + 0, addr); + skb_orphan(skb); + + last_desc = q->q.pidx + ndesc - 1; + if (last_desc >= q->q.size) + last_desc -= q->q.size; + q->q.sdesc[last_desc].skb = skb; + q->q.sdesc[last_desc].sgl = (struct ulptx_sgl *)sgl; + } + txq_advance(&q->q, ndesc); + + cxgb4_ring_tx_db(adap, &q->q, ndesc); + return NETDEV_TX_OK; +} diff --git a/drivers/crypto/exynos-rng.c b/drivers/crypto/exynos-rng.c index 451620b475a0..86f5f459762e 100644 --- a/drivers/crypto/exynos-rng.c +++ b/drivers/crypto/exynos-rng.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * exynos-rng.c - Random Number Generator driver for the Exynos * @@ -6,15 +7,6 @@ * Loosely based on old driver from drivers/char/hw_random/exynos-rng.c: * Copyright (C) 2012 Samsung Electronics * Jonghwa Lee - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include @@ -22,12 +14,18 @@ #include #include #include +#include +#include #include #include #define EXYNOS_RNG_CONTROL 0x0 #define EXYNOS_RNG_STATUS 0x10 + +#define EXYNOS_RNG_SEED_CONF 0x14 +#define EXYNOS_RNG_GEN_PRNG BIT(1) + #define EXYNOS_RNG_SEED_BASE 0x140 #define EXYNOS_RNG_SEED(n) (EXYNOS_RNG_SEED_BASE + (n * 0x4)) #define EXYNOS_RNG_OUT_BASE 0x160 @@ -43,13 +41,21 @@ #define EXYNOS_RNG_SEED_REGS 5 #define EXYNOS_RNG_SEED_SIZE (EXYNOS_RNG_SEED_REGS * 4) +enum exynos_prng_type { + EXYNOS_PRNG_UNKNOWN = 0, + EXYNOS_PRNG_EXYNOS4, + EXYNOS_PRNG_EXYNOS5, +}; + /* - * Driver re-seeds itself with generated random numbers to increase - * the randomness. + * Driver re-seeds itself with generated random numbers to hinder + * backtracking of the original seed. * * Time for next re-seed in ms. */ -#define EXYNOS_RNG_RESEED_TIME 100 +#define EXYNOS_RNG_RESEED_TIME 1000 +#define EXYNOS_RNG_RESEED_BYTES 65536 + /* * In polling mode, do not wait infinitely for the engine to finish the work. */ @@ -63,13 +69,17 @@ struct exynos_rng_ctx { /* Device associated memory */ struct exynos_rng_dev { struct device *dev; + enum exynos_prng_type type; void __iomem *mem; struct clk *clk; + struct mutex lock; /* Generated numbers stored for seeding during resume */ u8 seed_save[EXYNOS_RNG_SEED_SIZE]; unsigned int seed_save_len; /* Time of last seeding in jiffies */ unsigned long last_seeding; + /* Bytes generated since last seeding */ + unsigned long bytes_seeding; }; static struct exynos_rng_dev *exynos_rng_dev; @@ -114,38 +124,11 @@ static int exynos_rng_set_seed(struct exynos_rng_dev *rng, } rng->last_seeding = jiffies; + rng->bytes_seeding = 0; return 0; } -/* - * Read from output registers and put the data under 'dst' array, - * up to dlen bytes. - * - * Returns number of bytes actually stored in 'dst' (dlen - * or EXYNOS_RNG_SEED_SIZE). - */ -static unsigned int exynos_rng_copy_random(struct exynos_rng_dev *rng, - u8 *dst, unsigned int dlen) -{ - unsigned int cnt = 0; - int i, j; - u32 val; - - for (j = 0; j < EXYNOS_RNG_SEED_REGS; j++) { - val = exynos_rng_readl(rng, EXYNOS_RNG_OUT(j)); - - for (i = 0; i < 4; i++) { - dst[cnt] = val & 0xff; - val >>= 8; - if (++cnt >= dlen) - return cnt; - } - } - - return cnt; -} - /* * Start the engine and poll for finish. Then read from output registers * filling the 'dst' buffer up to 'dlen' bytes or up to size of generated @@ -160,8 +143,13 @@ static int exynos_rng_get_random(struct exynos_rng_dev *rng, { int retry = EXYNOS_RNG_WAIT_RETRIES; - exynos_rng_writel(rng, EXYNOS_RNG_CONTROL_START, - EXYNOS_RNG_CONTROL); + if (rng->type == EXYNOS_PRNG_EXYNOS4) { + exynos_rng_writel(rng, EXYNOS_RNG_CONTROL_START, + EXYNOS_RNG_CONTROL); + } else if (rng->type == EXYNOS_PRNG_EXYNOS5) { + exynos_rng_writel(rng, EXYNOS_RNG_GEN_PRNG, + EXYNOS_RNG_SEED_CONF); + } while (!(exynos_rng_readl(rng, EXYNOS_RNG_STATUS) & EXYNOS_RNG_STATUS_RNG_DONE) && --retry) @@ -173,7 +161,9 @@ static int exynos_rng_get_random(struct exynos_rng_dev *rng, /* Clear status bit */ exynos_rng_writel(rng, EXYNOS_RNG_STATUS_RNG_DONE, EXYNOS_RNG_STATUS); - *read = exynos_rng_copy_random(rng, dst, dlen); + *read = min_t(size_t, dlen, EXYNOS_RNG_SEED_SIZE); + memcpy_fromio(dst, rng->mem + EXYNOS_RNG_OUT_BASE, *read); + rng->bytes_seeding += *read; return 0; } @@ -187,13 +177,18 @@ static void exynos_rng_reseed(struct exynos_rng_dev *rng) unsigned int read = 0; u8 seed[EXYNOS_RNG_SEED_SIZE]; - if (time_before(now, next_seeding)) + if (time_before(now, next_seeding) && + rng->bytes_seeding < EXYNOS_RNG_RESEED_BYTES) return; if (exynos_rng_get_random(rng, seed, sizeof(seed), &read)) return; exynos_rng_set_seed(rng, seed, read); + + /* Let others do some of their job. */ + mutex_unlock(&rng->lock); + mutex_lock(&rng->lock); } static int exynos_rng_generate(struct crypto_rng *tfm, @@ -209,6 +204,7 @@ static int exynos_rng_generate(struct crypto_rng *tfm, if (ret) return ret; + mutex_lock(&rng->lock); do { ret = exynos_rng_get_random(rng, dst, dlen, &read); if (ret) @@ -219,6 +215,7 @@ static int exynos_rng_generate(struct crypto_rng *tfm, exynos_rng_reseed(rng); } while (dlen > 0); + mutex_unlock(&rng->lock); clk_disable_unprepare(rng->clk); @@ -236,7 +233,9 @@ static int exynos_rng_seed(struct crypto_rng *tfm, const u8 *seed, if (ret) return ret; + mutex_lock(&rng->lock); ret = exynos_rng_set_seed(ctx->rng, seed, slen); + mutex_unlock(&rng->lock); clk_disable_unprepare(rng->clk); @@ -259,7 +258,7 @@ static struct rng_alg exynos_rng_alg = { .base = { .cra_name = "stdrng", .cra_driver_name = "exynos_rng", - .cra_priority = 100, + .cra_priority = 300, .cra_ctxsize = sizeof(struct exynos_rng_ctx), .cra_module = THIS_MODULE, .cra_init = exynos_rng_kcapi_init, @@ -279,6 +278,10 @@ static int exynos_rng_probe(struct platform_device *pdev) if (!rng) return -ENOMEM; + rng->type = (enum exynos_prng_type)of_device_get_match_data(&pdev->dev); + + mutex_init(&rng->lock); + rng->dev = &pdev->dev; rng->clk = devm_clk_get(&pdev->dev, "secss"); if (IS_ERR(rng->clk)) { @@ -329,9 +332,14 @@ static int __maybe_unused exynos_rng_suspend(struct device *dev) if (ret) return ret; + mutex_lock(&rng->lock); + /* Get new random numbers and store them for seeding on resume. */ exynos_rng_get_random(rng, rng->seed_save, sizeof(rng->seed_save), &(rng->seed_save_len)); + + mutex_unlock(&rng->lock); + dev_dbg(rng->dev, "Stored %u bytes for seeding on system resume\n", rng->seed_save_len); @@ -354,8 +362,12 @@ static int __maybe_unused exynos_rng_resume(struct device *dev) if (ret) return ret; + mutex_lock(&rng->lock); + ret = exynos_rng_set_seed(rng, rng->seed_save, rng->seed_save_len); + mutex_unlock(&rng->lock); + clk_disable_unprepare(rng->clk); return ret; @@ -367,6 +379,10 @@ static SIMPLE_DEV_PM_OPS(exynos_rng_pm_ops, exynos_rng_suspend, static const struct of_device_id exynos_rng_dt_match[] = { { .compatible = "samsung,exynos4-rng", + .data = (const void *)EXYNOS_PRNG_EXYNOS4, + }, { + .compatible = "samsung,exynos5250-prng", + .data = (const void *)EXYNOS_PRNG_EXYNOS5, }, { }, }; @@ -386,4 +402,4 @@ module_platform_driver(exynos_rng_driver); MODULE_DESCRIPTION("Exynos H/W Random Number Generator driver"); MODULE_AUTHOR("Krzysztof Kozlowski "); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c index e09d4055b19e..a5a36fe7bf2c 100644 --- a/drivers/crypto/hifn_795x.c +++ b/drivers/crypto/hifn_795x.c @@ -2579,6 +2579,7 @@ err_out_unmap_bars: for (i = 0; i < 3; ++i) if (dev->bar[i]) iounmap(dev->bar[i]); + kfree(dev); err_out_free_regions: pci_release_regions(pdev); diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c index 4bcef78a08aa..225e74a7f724 100644 --- a/drivers/crypto/inside-secure/safexcel.c +++ b/drivers/crypto/inside-secure/safexcel.c @@ -108,10 +108,10 @@ static void eip197_write_firmware(struct safexcel_crypto_priv *priv, writel(EIP197_PE_ICE_x_CTRL_SW_RESET | EIP197_PE_ICE_x_CTRL_CLR_ECC_CORR | EIP197_PE_ICE_x_CTRL_CLR_ECC_NON_CORR, - priv->base + ctrl); + EIP197_PE(priv) + ctrl); /* Enable access to the program memory */ - writel(prog_en, priv->base + EIP197_PE_ICE_RAM_CTRL); + writel(prog_en, EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL); /* Write the firmware */ for (i = 0; i < fw->size / sizeof(u32); i++) @@ -119,12 +119,12 @@ static void eip197_write_firmware(struct safexcel_crypto_priv *priv, priv->base + EIP197_CLASSIFICATION_RAMS + i * sizeof(u32)); /* Disable access to the program memory */ - writel(0, priv->base + EIP197_PE_ICE_RAM_CTRL); + writel(0, EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL); /* Release engine from reset */ - val = readl(priv->base + ctrl); + val = readl(EIP197_PE(priv) + ctrl); val &= ~EIP197_PE_ICE_x_CTRL_SW_RESET; - writel(val, priv->base + ctrl); + writel(val, EIP197_PE(priv) + ctrl); } static int eip197_load_firmwares(struct safexcel_crypto_priv *priv) @@ -145,14 +145,14 @@ static int eip197_load_firmwares(struct safexcel_crypto_priv *priv) } /* Clear the scratchpad memory */ - val = readl(priv->base + EIP197_PE_ICE_SCRATCH_CTRL); + val = readl(EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL); val |= EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_TIMER | EIP197_PE_ICE_SCRATCH_CTRL_TIMER_EN | EIP197_PE_ICE_SCRATCH_CTRL_SCRATCH_ACCESS | EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_ACCESS; - writel(val, priv->base + EIP197_PE_ICE_SCRATCH_CTRL); + writel(val, EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL); - memset(priv->base + EIP197_PE_ICE_SCRATCH_RAM, 0, + memset(EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_RAM, 0, EIP197_NUM_OF_SCRATCH_BLOCKS * sizeof(u32)); eip197_write_firmware(priv, fw[FW_IFPP], EIP197_PE_ICE_FPP_CTRL, @@ -173,7 +173,7 @@ static int safexcel_hw_setup_cdesc_rings(struct safexcel_crypto_priv *priv) u32 hdw, cd_size_rnd, val; int i; - hdw = readl(priv->base + EIP197_HIA_OPTIONS); + hdw = readl(EIP197_HIA_AIC_G(priv) + EIP197_HIA_OPTIONS); hdw &= GENMASK(27, 25); hdw >>= 25; @@ -182,26 +182,25 @@ static int safexcel_hw_setup_cdesc_rings(struct safexcel_crypto_priv *priv) for (i = 0; i < priv->config.rings; i++) { /* ring base address */ writel(lower_32_bits(priv->ring[i].cdr.base_dma), - priv->base + EIP197_HIA_CDR(i) + EIP197_HIA_xDR_RING_BASE_ADDR_LO); + EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_LO); writel(upper_32_bits(priv->ring[i].cdr.base_dma), - priv->base + EIP197_HIA_CDR(i) + EIP197_HIA_xDR_RING_BASE_ADDR_HI); + EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_HI); writel(EIP197_xDR_DESC_MODE_64BIT | (priv->config.cd_offset << 16) | priv->config.cd_size, - priv->base + EIP197_HIA_CDR(i) + EIP197_HIA_xDR_DESC_SIZE); + EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_DESC_SIZE); writel(((EIP197_FETCH_COUNT * (cd_size_rnd << hdw)) << 16) | (EIP197_FETCH_COUNT * priv->config.cd_offset), - priv->base + EIP197_HIA_CDR(i) + EIP197_HIA_xDR_CFG); + EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_CFG); /* Configure DMA tx control */ val = EIP197_HIA_xDR_CFG_WR_CACHE(WR_CACHE_3BITS); val |= EIP197_HIA_xDR_CFG_RD_CACHE(RD_CACHE_3BITS); - writel(val, - priv->base + EIP197_HIA_CDR(i) + EIP197_HIA_xDR_DMA_CFG); + writel(val, EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_DMA_CFG); /* clear any pending interrupt */ writel(GENMASK(5, 0), - priv->base + EIP197_HIA_CDR(i) + EIP197_HIA_xDR_STAT); + EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_STAT); } return 0; @@ -212,7 +211,7 @@ static int safexcel_hw_setup_rdesc_rings(struct safexcel_crypto_priv *priv) u32 hdw, rd_size_rnd, val; int i; - hdw = readl(priv->base + EIP197_HIA_OPTIONS); + hdw = readl(EIP197_HIA_AIC_G(priv) + EIP197_HIA_OPTIONS); hdw &= GENMASK(27, 25); hdw >>= 25; @@ -221,33 +220,33 @@ static int safexcel_hw_setup_rdesc_rings(struct safexcel_crypto_priv *priv) for (i = 0; i < priv->config.rings; i++) { /* ring base address */ writel(lower_32_bits(priv->ring[i].rdr.base_dma), - priv->base + EIP197_HIA_RDR(i) + EIP197_HIA_xDR_RING_BASE_ADDR_LO); + EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_LO); writel(upper_32_bits(priv->ring[i].rdr.base_dma), - priv->base + EIP197_HIA_RDR(i) + EIP197_HIA_xDR_RING_BASE_ADDR_HI); + EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_HI); writel(EIP197_xDR_DESC_MODE_64BIT | (priv->config.rd_offset << 16) | priv->config.rd_size, - priv->base + EIP197_HIA_RDR(i) + EIP197_HIA_xDR_DESC_SIZE); + EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_DESC_SIZE); writel(((EIP197_FETCH_COUNT * (rd_size_rnd << hdw)) << 16) | (EIP197_FETCH_COUNT * priv->config.rd_offset), - priv->base + EIP197_HIA_RDR(i) + EIP197_HIA_xDR_CFG); + EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_CFG); /* Configure DMA tx control */ val = EIP197_HIA_xDR_CFG_WR_CACHE(WR_CACHE_3BITS); val |= EIP197_HIA_xDR_CFG_RD_CACHE(RD_CACHE_3BITS); val |= EIP197_HIA_xDR_WR_RES_BUF | EIP197_HIA_xDR_WR_CTRL_BUG; writel(val, - priv->base + EIP197_HIA_RDR(i) + EIP197_HIA_xDR_DMA_CFG); + EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_DMA_CFG); /* clear any pending interrupt */ writel(GENMASK(7, 0), - priv->base + EIP197_HIA_RDR(i) + EIP197_HIA_xDR_STAT); + EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_STAT); /* enable ring interrupt */ - val = readl(priv->base + EIP197_HIA_AIC_R_ENABLE_CTRL(i)); + val = readl(EIP197_HIA_AIC_R(priv) + EIP197_HIA_AIC_R_ENABLE_CTRL(i)); val |= EIP197_RDR_IRQ(i); - writel(val, priv->base + EIP197_HIA_AIC_R_ENABLE_CTRL(i)); + writel(val, EIP197_HIA_AIC_R(priv) + EIP197_HIA_AIC_R_ENABLE_CTRL(i)); } return 0; @@ -259,39 +258,40 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv) int i, ret; /* Determine endianess and configure byte swap */ - version = readl(priv->base + EIP197_HIA_VERSION); - val = readl(priv->base + EIP197_HIA_MST_CTRL); + version = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_VERSION); + val = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); if ((version & 0xffff) == EIP197_HIA_VERSION_BE) val |= EIP197_MST_CTRL_BYTE_SWAP; else if (((version >> 16) & 0xffff) == EIP197_HIA_VERSION_LE) val |= (EIP197_MST_CTRL_NO_BYTE_SWAP >> 24); - writel(val, priv->base + EIP197_HIA_MST_CTRL); - + writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); /* Configure wr/rd cache values */ writel(EIP197_MST_CTRL_RD_CACHE(RD_CACHE_4BITS) | EIP197_MST_CTRL_WD_CACHE(WR_CACHE_4BITS), - priv->base + EIP197_MST_CTRL); + EIP197_HIA_GEN_CFG(priv) + EIP197_MST_CTRL); /* Interrupts reset */ /* Disable all global interrupts */ - writel(0, priv->base + EIP197_HIA_AIC_G_ENABLE_CTRL); + writel(0, EIP197_HIA_AIC_G(priv) + EIP197_HIA_AIC_G_ENABLE_CTRL); /* Clear any pending interrupt */ - writel(GENMASK(31, 0), priv->base + EIP197_HIA_AIC_G_ACK); + writel(GENMASK(31, 0), EIP197_HIA_AIC_G(priv) + EIP197_HIA_AIC_G_ACK); /* Data Fetch Engine configuration */ /* Reset all DFE threads */ writel(EIP197_DxE_THR_CTRL_RESET_PE, - priv->base + EIP197_HIA_DFE_THR_CTRL); + EIP197_HIA_DFE_THR(priv) + EIP197_HIA_DFE_THR_CTRL); - /* Reset HIA input interface arbiter */ - writel(EIP197_HIA_RA_PE_CTRL_RESET, - priv->base + EIP197_HIA_RA_PE_CTRL); + if (priv->version == EIP197) { + /* Reset HIA input interface arbiter */ + writel(EIP197_HIA_RA_PE_CTRL_RESET, + EIP197_HIA_AIC(priv) + EIP197_HIA_RA_PE_CTRL); + } /* DMA transfer size to use */ val = EIP197_HIA_DFE_CFG_DIS_DEBUG; @@ -299,29 +299,32 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv) val |= EIP197_HIA_DxE_CFG_MIN_CTRL_SIZE(5) | EIP197_HIA_DxE_CFG_MAX_CTRL_SIZE(7); val |= EIP197_HIA_DxE_CFG_DATA_CACHE_CTRL(RD_CACHE_3BITS); val |= EIP197_HIA_DxE_CFG_CTRL_CACHE_CTRL(RD_CACHE_3BITS); - writel(val, priv->base + EIP197_HIA_DFE_CFG); + writel(val, EIP197_HIA_DFE(priv) + EIP197_HIA_DFE_CFG); /* Leave the DFE threads reset state */ - writel(0, priv->base + EIP197_HIA_DFE_THR_CTRL); + writel(0, EIP197_HIA_DFE_THR(priv) + EIP197_HIA_DFE_THR_CTRL); /* Configure the procesing engine thresholds */ writel(EIP197_PE_IN_xBUF_THRES_MIN(5) | EIP197_PE_IN_xBUF_THRES_MAX(9), - priv->base + EIP197_PE_IN_DBUF_THRES); + EIP197_PE(priv) + EIP197_PE_IN_DBUF_THRES); writel(EIP197_PE_IN_xBUF_THRES_MIN(5) | EIP197_PE_IN_xBUF_THRES_MAX(7), - priv->base + EIP197_PE_IN_TBUF_THRES); + EIP197_PE(priv) + EIP197_PE_IN_TBUF_THRES); - /* enable HIA input interface arbiter and rings */ - writel(EIP197_HIA_RA_PE_CTRL_EN | GENMASK(priv->config.rings - 1, 0), - priv->base + EIP197_HIA_RA_PE_CTRL); + if (priv->version == EIP197) { + /* enable HIA input interface arbiter and rings */ + writel(EIP197_HIA_RA_PE_CTRL_EN | + GENMASK(priv->config.rings - 1, 0), + EIP197_HIA_AIC(priv) + EIP197_HIA_RA_PE_CTRL); + } /* Data Store Engine configuration */ /* Reset all DSE threads */ writel(EIP197_DxE_THR_CTRL_RESET_PE, - priv->base + EIP197_HIA_DSE_THR_CTRL); + EIP197_HIA_DSE_THR(priv) + EIP197_HIA_DSE_THR_CTRL); /* Wait for all DSE threads to complete */ - while ((readl(priv->base + EIP197_HIA_DSE_THR_STAT) & + while ((readl(EIP197_HIA_DSE_THR(priv) + EIP197_HIA_DSE_THR_STAT) & GENMASK(15, 12)) != GENMASK(15, 12)) ; @@ -330,15 +333,19 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv) val |= EIP197_HIA_DxE_CFG_MIN_DATA_SIZE(7) | EIP197_HIA_DxE_CFG_MAX_DATA_SIZE(8); val |= EIP197_HIA_DxE_CFG_DATA_CACHE_CTRL(WR_CACHE_3BITS); val |= EIP197_HIA_DSE_CFG_ALLWAYS_BUFFERABLE; - val |= EIP197_HIA_DSE_CFG_EN_SINGLE_WR; - writel(val, priv->base + EIP197_HIA_DSE_CFG); + /* FIXME: instability issues can occur for EIP97 but disabling it impact + * performances. + */ + if (priv->version == EIP197) + val |= EIP197_HIA_DSE_CFG_EN_SINGLE_WR; + writel(val, EIP197_HIA_DSE(priv) + EIP197_HIA_DSE_CFG); /* Leave the DSE threads reset state */ - writel(0, priv->base + EIP197_HIA_DSE_THR_CTRL); + writel(0, EIP197_HIA_DSE_THR(priv) + EIP197_HIA_DSE_THR_CTRL); /* Configure the procesing engine thresholds */ writel(EIP197_PE_OUT_DBUF_THRES_MIN(7) | EIP197_PE_OUT_DBUF_THRES_MAX(8), - priv->base + EIP197_PE_OUT_DBUF_THRES); + EIP197_PE(priv) + EIP197_PE_OUT_DBUF_THRES); /* Processing Engine configuration */ @@ -348,73 +355,75 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv) val |= EIP197_ALG_AES_ECB | EIP197_ALG_AES_CBC; val |= EIP197_ALG_SHA1 | EIP197_ALG_HMAC_SHA1; val |= EIP197_ALG_SHA2; - writel(val, priv->base + EIP197_PE_EIP96_FUNCTION_EN); + writel(val, EIP197_PE(priv) + EIP197_PE_EIP96_FUNCTION_EN); /* Command Descriptor Rings prepare */ for (i = 0; i < priv->config.rings; i++) { /* Clear interrupts for this ring */ writel(GENMASK(31, 0), - priv->base + EIP197_HIA_AIC_R_ENABLE_CLR(i)); + EIP197_HIA_AIC_R(priv) + EIP197_HIA_AIC_R_ENABLE_CLR(i)); /* Disable external triggering */ - writel(0, priv->base + EIP197_HIA_CDR(i) + EIP197_HIA_xDR_CFG); + writel(0, EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_CFG); /* Clear the pending prepared counter */ writel(EIP197_xDR_PREP_CLR_COUNT, - priv->base + EIP197_HIA_CDR(i) + EIP197_HIA_xDR_PREP_COUNT); + EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_PREP_COUNT); /* Clear the pending processed counter */ writel(EIP197_xDR_PROC_CLR_COUNT, - priv->base + EIP197_HIA_CDR(i) + EIP197_HIA_xDR_PROC_COUNT); + EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_PROC_COUNT); writel(0, - priv->base + EIP197_HIA_CDR(i) + EIP197_HIA_xDR_PREP_PNTR); + EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_PREP_PNTR); writel(0, - priv->base + EIP197_HIA_CDR(i) + EIP197_HIA_xDR_PROC_PNTR); + EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_PROC_PNTR); writel((EIP197_DEFAULT_RING_SIZE * priv->config.cd_offset) << 2, - priv->base + EIP197_HIA_CDR(i) + EIP197_HIA_xDR_RING_SIZE); + EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_RING_SIZE); } /* Result Descriptor Ring prepare */ for (i = 0; i < priv->config.rings; i++) { /* Disable external triggering*/ - writel(0, priv->base + EIP197_HIA_RDR(i) + EIP197_HIA_xDR_CFG); + writel(0, EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_CFG); /* Clear the pending prepared counter */ writel(EIP197_xDR_PREP_CLR_COUNT, - priv->base + EIP197_HIA_RDR(i) + EIP197_HIA_xDR_PREP_COUNT); + EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_PREP_COUNT); /* Clear the pending processed counter */ writel(EIP197_xDR_PROC_CLR_COUNT, - priv->base + EIP197_HIA_RDR(i) + EIP197_HIA_xDR_PROC_COUNT); + EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_PROC_COUNT); writel(0, - priv->base + EIP197_HIA_RDR(i) + EIP197_HIA_xDR_PREP_PNTR); + EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_PREP_PNTR); writel(0, - priv->base + EIP197_HIA_RDR(i) + EIP197_HIA_xDR_PROC_PNTR); + EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_PROC_PNTR); /* Ring size */ writel((EIP197_DEFAULT_RING_SIZE * priv->config.rd_offset) << 2, - priv->base + EIP197_HIA_RDR(i) + EIP197_HIA_xDR_RING_SIZE); + EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_RING_SIZE); } /* Enable command descriptor rings */ writel(EIP197_DxE_THR_CTRL_EN | GENMASK(priv->config.rings - 1, 0), - priv->base + EIP197_HIA_DFE_THR_CTRL); + EIP197_HIA_DFE_THR(priv) + EIP197_HIA_DFE_THR_CTRL); /* Enable result descriptor rings */ writel(EIP197_DxE_THR_CTRL_EN | GENMASK(priv->config.rings - 1, 0), - priv->base + EIP197_HIA_DSE_THR_CTRL); + EIP197_HIA_DSE_THR(priv) + EIP197_HIA_DSE_THR_CTRL); /* Clear any HIA interrupt */ - writel(GENMASK(30, 20), priv->base + EIP197_HIA_AIC_G_ACK); + writel(GENMASK(30, 20), EIP197_HIA_AIC_G(priv) + EIP197_HIA_AIC_G_ACK); - eip197_trc_cache_init(priv); + if (priv->version == EIP197) { + eip197_trc_cache_init(priv); - ret = eip197_load_firmwares(priv); - if (ret) - return ret; + ret = eip197_load_firmwares(priv); + if (ret) + return ret; + } safexcel_hw_setup_cdesc_rings(priv); safexcel_hw_setup_rdesc_rings(priv); @@ -422,6 +431,23 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv) return 0; } +/* Called with ring's lock taken */ +static int safexcel_try_push_requests(struct safexcel_crypto_priv *priv, + int ring, int reqs) +{ + int coal = min_t(int, reqs, EIP197_MAX_BATCH_SZ); + + if (!coal) + return 0; + + /* Configure when we want an interrupt */ + writel(EIP197_HIA_RDR_THRESH_PKT_MODE | + EIP197_HIA_RDR_THRESH_PROC_PKT(coal), + EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_THRESH); + + return coal; +} + void safexcel_dequeue(struct safexcel_crypto_priv *priv, int ring) { struct crypto_async_request *req, *backlog; @@ -429,34 +455,36 @@ void safexcel_dequeue(struct safexcel_crypto_priv *priv, int ring) struct safexcel_request *request; int ret, nreq = 0, cdesc = 0, rdesc = 0, commands, results; - priv->ring[ring].need_dequeue = false; + /* If a request wasn't properly dequeued because of a lack of resources, + * proceeded it first, + */ + req = priv->ring[ring].req; + backlog = priv->ring[ring].backlog; + if (req) + goto handle_req; - do { + while (true) { spin_lock_bh(&priv->ring[ring].queue_lock); backlog = crypto_get_backlog(&priv->ring[ring].queue); req = crypto_dequeue_request(&priv->ring[ring].queue); spin_unlock_bh(&priv->ring[ring].queue_lock); - if (!req) - goto finalize; - - request = kzalloc(sizeof(*request), EIP197_GFP_FLAGS(*req)); - if (!request) { - spin_lock_bh(&priv->ring[ring].queue_lock); - crypto_enqueue_request(&priv->ring[ring].queue, req); - spin_unlock_bh(&priv->ring[ring].queue_lock); - - priv->ring[ring].need_dequeue = true; + if (!req) { + priv->ring[ring].req = NULL; + priv->ring[ring].backlog = NULL; goto finalize; } +handle_req: + request = kzalloc(sizeof(*request), EIP197_GFP_FLAGS(*req)); + if (!request) + goto request_failed; + ctx = crypto_tfm_ctx(req->tfm); ret = ctx->send(req, ring, request, &commands, &results); if (ret) { kfree(request); - req->complete(req, ret); - priv->ring[ring].need_dequeue = true; - goto finalize; + goto request_failed; } if (backlog) @@ -468,30 +496,39 @@ void safexcel_dequeue(struct safexcel_crypto_priv *priv, int ring) cdesc += commands; rdesc += results; - } while (nreq++ < EIP197_MAX_BATCH_SZ); + nreq++; + } + +request_failed: + /* Not enough resources to handle all the requests. Bail out and save + * the request and the backlog for the next dequeue call (per-ring). + */ + priv->ring[ring].req = req; + priv->ring[ring].backlog = backlog; finalize: - if (nreq == EIP197_MAX_BATCH_SZ) - priv->ring[ring].need_dequeue = true; - else if (!nreq) + if (!nreq) return; - spin_lock_bh(&priv->ring[ring].lock); + spin_lock_bh(&priv->ring[ring].egress_lock); - /* Configure when we want an interrupt */ - writel(EIP197_HIA_RDR_THRESH_PKT_MODE | - EIP197_HIA_RDR_THRESH_PROC_PKT(nreq), - priv->base + EIP197_HIA_RDR(ring) + EIP197_HIA_xDR_THRESH); + if (!priv->ring[ring].busy) { + nreq -= safexcel_try_push_requests(priv, ring, nreq); + if (nreq) + priv->ring[ring].busy = true; + } + + priv->ring[ring].requests_left += nreq; + + spin_unlock_bh(&priv->ring[ring].egress_lock); /* let the RDR know we have pending descriptors */ writel((rdesc * priv->config.rd_offset) << 2, - priv->base + EIP197_HIA_RDR(ring) + EIP197_HIA_xDR_PREP_COUNT); + EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_PREP_COUNT); /* let the CDR know we have pending descriptors */ writel((cdesc * priv->config.cd_offset) << 2, - priv->base + EIP197_HIA_CDR(ring) + EIP197_HIA_xDR_PREP_COUNT); - - spin_unlock_bh(&priv->ring[ring].lock); + EIP197_HIA_CDR(priv, ring) + EIP197_HIA_xDR_PREP_COUNT); } void safexcel_free_context(struct safexcel_crypto_priv *priv, @@ -540,7 +577,6 @@ void safexcel_inv_complete(struct crypto_async_request *req, int error) } int safexcel_invalidate_cache(struct crypto_async_request *async, - struct safexcel_context *ctx, struct safexcel_crypto_priv *priv, dma_addr_t ctxr_dma, int ring, struct safexcel_request *request) @@ -587,14 +623,17 @@ static inline void safexcel_handle_result_descriptor(struct safexcel_crypto_priv { struct safexcel_request *sreq; struct safexcel_context *ctx; - int ret, i, nreq, ndesc = 0; + int ret, i, nreq, ndesc, tot_descs, done; bool should_complete; - nreq = readl(priv->base + EIP197_HIA_RDR(ring) + EIP197_HIA_xDR_PROC_COUNT); - nreq >>= 24; - nreq &= GENMASK(6, 0); +handle_results: + tot_descs = 0; + + nreq = readl(EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_PROC_COUNT); + nreq >>= EIP197_xDR_PROC_xD_PKT_OFFSET; + nreq &= EIP197_xDR_PROC_xD_PKT_MASK; if (!nreq) - return; + goto requests_left; for (i = 0; i < nreq; i++) { spin_lock_bh(&priv->ring[ring].egress_lock); @@ -609,13 +648,9 @@ static inline void safexcel_handle_result_descriptor(struct safexcel_crypto_priv if (ndesc < 0) { kfree(sreq); dev_err(priv->dev, "failed to handle result (%d)", ndesc); - return; + goto acknowledge; } - writel(EIP197_xDR_PROC_xD_PKT(1) | - EIP197_xDR_PROC_xD_COUNT(ndesc * priv->config.rd_offset), - priv->base + EIP197_HIA_RDR(ring) + EIP197_HIA_xDR_PROC_COUNT); - if (should_complete) { local_bh_disable(); sreq->req->complete(sreq->req, ret); @@ -623,19 +658,41 @@ static inline void safexcel_handle_result_descriptor(struct safexcel_crypto_priv } kfree(sreq); + tot_descs += ndesc; } + +acknowledge: + if (i) { + writel(EIP197_xDR_PROC_xD_PKT(i) | + EIP197_xDR_PROC_xD_COUNT(tot_descs * priv->config.rd_offset), + EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_PROC_COUNT); + } + + /* If the number of requests overflowed the counter, try to proceed more + * requests. + */ + if (nreq == EIP197_xDR_PROC_xD_PKT_MASK) + goto handle_results; + +requests_left: + spin_lock_bh(&priv->ring[ring].egress_lock); + + done = safexcel_try_push_requests(priv, ring, + priv->ring[ring].requests_left); + + priv->ring[ring].requests_left -= done; + if (!done && !priv->ring[ring].requests_left) + priv->ring[ring].busy = false; + + spin_unlock_bh(&priv->ring[ring].egress_lock); } -static void safexcel_handle_result_work(struct work_struct *work) +static void safexcel_dequeue_work(struct work_struct *work) { struct safexcel_work_data *data = container_of(work, struct safexcel_work_data, work); - struct safexcel_crypto_priv *priv = data->priv; - safexcel_handle_result_descriptor(priv, data->ring); - - if (priv->ring[data->ring].need_dequeue) - safexcel_dequeue(data->priv, data->ring); + safexcel_dequeue(data->priv, data->ring); } struct safexcel_ring_irq_data { @@ -647,16 +704,16 @@ static irqreturn_t safexcel_irq_ring(int irq, void *data) { struct safexcel_ring_irq_data *irq_data = data; struct safexcel_crypto_priv *priv = irq_data->priv; - int ring = irq_data->ring; + int ring = irq_data->ring, rc = IRQ_NONE; u32 status, stat; - status = readl(priv->base + EIP197_HIA_AIC_R_ENABLED_STAT(ring)); + status = readl(EIP197_HIA_AIC_R(priv) + EIP197_HIA_AIC_R_ENABLED_STAT(ring)); if (!status) - return IRQ_NONE; + return rc; /* RDR interrupts */ if (status & EIP197_RDR_IRQ(ring)) { - stat = readl(priv->base + EIP197_HIA_RDR(ring) + EIP197_HIA_xDR_STAT); + stat = readl(EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_STAT); if (unlikely(stat & EIP197_xDR_ERR)) { /* @@ -666,22 +723,37 @@ static irqreturn_t safexcel_irq_ring(int irq, void *data) */ dev_err(priv->dev, "RDR: fatal error."); } else if (likely(stat & EIP197_xDR_THRESH)) { - queue_work(priv->ring[ring].workqueue, &priv->ring[ring].work_data.work); + rc = IRQ_WAKE_THREAD; } /* ACK the interrupts */ writel(stat & 0xff, - priv->base + EIP197_HIA_RDR(ring) + EIP197_HIA_xDR_STAT); + EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_STAT); } /* ACK the interrupts */ - writel(status, priv->base + EIP197_HIA_AIC_R_ACK(ring)); + writel(status, EIP197_HIA_AIC_R(priv) + EIP197_HIA_AIC_R_ACK(ring)); + + return rc; +} + +static irqreturn_t safexcel_irq_ring_thread(int irq, void *data) +{ + struct safexcel_ring_irq_data *irq_data = data; + struct safexcel_crypto_priv *priv = irq_data->priv; + int ring = irq_data->ring; + + safexcel_handle_result_descriptor(priv, ring); + + queue_work(priv->ring[ring].workqueue, + &priv->ring[ring].work_data.work); return IRQ_HANDLED; } static int safexcel_request_ring_irq(struct platform_device *pdev, const char *name, irq_handler_t handler, + irq_handler_t threaded_handler, struct safexcel_ring_irq_data *ring_irq_priv) { int ret, irq = platform_get_irq_byname(pdev, name); @@ -691,8 +763,9 @@ static int safexcel_request_ring_irq(struct platform_device *pdev, const char *n return irq; } - ret = devm_request_irq(&pdev->dev, irq, handler, 0, - dev_name(&pdev->dev), ring_irq_priv); + ret = devm_request_threaded_irq(&pdev->dev, irq, handler, + threaded_handler, IRQF_ONESHOT, + dev_name(&pdev->dev), ring_irq_priv); if (ret) { dev_err(&pdev->dev, "unable to request IRQ %d\n", irq); return ret; @@ -755,11 +828,11 @@ static void safexcel_configure(struct safexcel_crypto_priv *priv) { u32 val, mask; - val = readl(priv->base + EIP197_HIA_OPTIONS); + val = readl(EIP197_HIA_AIC_G(priv) + EIP197_HIA_OPTIONS); val = (val & GENMASK(27, 25)) >> 25; mask = BIT(val) - 1; - val = readl(priv->base + EIP197_HIA_OPTIONS); + val = readl(EIP197_HIA_AIC_G(priv) + EIP197_HIA_OPTIONS); priv->config.rings = min_t(u32, val & GENMASK(3, 0), max_rings); priv->config.cd_size = (sizeof(struct safexcel_command_desc) / sizeof(u32)); @@ -769,6 +842,35 @@ static void safexcel_configure(struct safexcel_crypto_priv *priv) priv->config.rd_offset = (priv->config.rd_size + mask) & ~mask; } +static void safexcel_init_register_offsets(struct safexcel_crypto_priv *priv) +{ + struct safexcel_register_offsets *offsets = &priv->offsets; + + if (priv->version == EIP197) { + offsets->hia_aic = EIP197_HIA_AIC_BASE; + offsets->hia_aic_g = EIP197_HIA_AIC_G_BASE; + offsets->hia_aic_r = EIP197_HIA_AIC_R_BASE; + offsets->hia_aic_xdr = EIP197_HIA_AIC_xDR_BASE; + offsets->hia_dfe = EIP197_HIA_DFE_BASE; + offsets->hia_dfe_thr = EIP197_HIA_DFE_THR_BASE; + offsets->hia_dse = EIP197_HIA_DSE_BASE; + offsets->hia_dse_thr = EIP197_HIA_DSE_THR_BASE; + offsets->hia_gen_cfg = EIP197_HIA_GEN_CFG_BASE; + offsets->pe = EIP197_PE_BASE; + } else { + offsets->hia_aic = EIP97_HIA_AIC_BASE; + offsets->hia_aic_g = EIP97_HIA_AIC_G_BASE; + offsets->hia_aic_r = EIP97_HIA_AIC_R_BASE; + offsets->hia_aic_xdr = EIP97_HIA_AIC_xDR_BASE; + offsets->hia_dfe = EIP97_HIA_DFE_BASE; + offsets->hia_dfe_thr = EIP97_HIA_DFE_THR_BASE; + offsets->hia_dse = EIP97_HIA_DSE_BASE; + offsets->hia_dse_thr = EIP97_HIA_DSE_THR_BASE; + offsets->hia_gen_cfg = EIP97_HIA_GEN_CFG_BASE; + offsets->pe = EIP97_PE_BASE; + } +} + static int safexcel_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -781,6 +883,9 @@ static int safexcel_probe(struct platform_device *pdev) return -ENOMEM; priv->dev = dev; + priv->version = (enum safexcel_eip_version)of_device_get_match_data(dev); + + safexcel_init_register_offsets(priv); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->base = devm_ioremap_resource(dev, res); @@ -839,6 +944,7 @@ static int safexcel_probe(struct platform_device *pdev) snprintf(irq_name, 6, "ring%d", i); irq = safexcel_request_ring_irq(pdev, irq_name, safexcel_irq_ring, + safexcel_irq_ring_thread, ring_irq); if (irq < 0) { ret = irq; @@ -847,7 +953,7 @@ static int safexcel_probe(struct platform_device *pdev) priv->ring[i].work_data.priv = priv; priv->ring[i].work_data.ring = i; - INIT_WORK(&priv->ring[i].work_data.work, safexcel_handle_result_work); + INIT_WORK(&priv->ring[i].work_data.work, safexcel_dequeue_work); snprintf(wq_name, 9, "wq_ring%d", i); priv->ring[i].workqueue = create_singlethread_workqueue(wq_name); @@ -856,6 +962,9 @@ static int safexcel_probe(struct platform_device *pdev) goto err_clk; } + priv->ring[i].requests_left = 0; + priv->ring[i].busy = false; + crypto_init_queue(&priv->ring[i].queue, EIP197_DEFAULT_RING_SIZE); @@ -903,7 +1012,14 @@ static int safexcel_remove(struct platform_device *pdev) } static const struct of_device_id safexcel_of_match_table[] = { - { .compatible = "inside-secure,safexcel-eip197" }, + { + .compatible = "inside-secure,safexcel-eip97", + .data = (void *)EIP97, + }, + { + .compatible = "inside-secure,safexcel-eip197", + .data = (void *)EIP197, + }, {}, }; diff --git a/drivers/crypto/inside-secure/safexcel.h b/drivers/crypto/inside-secure/safexcel.h index 304c5838c11a..4e219c21608b 100644 --- a/drivers/crypto/inside-secure/safexcel.h +++ b/drivers/crypto/inside-secure/safexcel.h @@ -19,64 +19,103 @@ #define EIP197_HIA_VERSION_BE 0x35ca /* Static configuration */ -#define EIP197_DEFAULT_RING_SIZE 64 +#define EIP197_DEFAULT_RING_SIZE 400 #define EIP197_MAX_TOKENS 5 #define EIP197_MAX_RINGS 4 #define EIP197_FETCH_COUNT 1 -#define EIP197_MAX_BATCH_SZ EIP197_DEFAULT_RING_SIZE +#define EIP197_MAX_BATCH_SZ 64 #define EIP197_GFP_FLAGS(base) ((base).flags & CRYPTO_TFM_REQ_MAY_SLEEP ? \ GFP_KERNEL : GFP_ATOMIC) +/* Register base offsets */ +#define EIP197_HIA_AIC(priv) ((priv)->base + (priv)->offsets.hia_aic) +#define EIP197_HIA_AIC_G(priv) ((priv)->base + (priv)->offsets.hia_aic_g) +#define EIP197_HIA_AIC_R(priv) ((priv)->base + (priv)->offsets.hia_aic_r) +#define EIP197_HIA_AIC_xDR(priv) ((priv)->base + (priv)->offsets.hia_aic_xdr) +#define EIP197_HIA_DFE(priv) ((priv)->base + (priv)->offsets.hia_dfe) +#define EIP197_HIA_DFE_THR(priv) ((priv)->base + (priv)->offsets.hia_dfe_thr) +#define EIP197_HIA_DSE(priv) ((priv)->base + (priv)->offsets.hia_dse) +#define EIP197_HIA_DSE_THR(priv) ((priv)->base + (priv)->offsets.hia_dse_thr) +#define EIP197_HIA_GEN_CFG(priv) ((priv)->base + (priv)->offsets.hia_gen_cfg) +#define EIP197_PE(priv) ((priv)->base + (priv)->offsets.pe) + +/* EIP197 base offsets */ +#define EIP197_HIA_AIC_BASE 0x90000 +#define EIP197_HIA_AIC_G_BASE 0x90000 +#define EIP197_HIA_AIC_R_BASE 0x90800 +#define EIP197_HIA_AIC_xDR_BASE 0x80000 +#define EIP197_HIA_DFE_BASE 0x8c000 +#define EIP197_HIA_DFE_THR_BASE 0x8c040 +#define EIP197_HIA_DSE_BASE 0x8d000 +#define EIP197_HIA_DSE_THR_BASE 0x8d040 +#define EIP197_HIA_GEN_CFG_BASE 0xf0000 +#define EIP197_PE_BASE 0xa0000 + +/* EIP97 base offsets */ +#define EIP97_HIA_AIC_BASE 0x0 +#define EIP97_HIA_AIC_G_BASE 0x0 +#define EIP97_HIA_AIC_R_BASE 0x0 +#define EIP97_HIA_AIC_xDR_BASE 0x0 +#define EIP97_HIA_DFE_BASE 0xf000 +#define EIP97_HIA_DFE_THR_BASE 0xf200 +#define EIP97_HIA_DSE_BASE 0xf400 +#define EIP97_HIA_DSE_THR_BASE 0xf600 +#define EIP97_HIA_GEN_CFG_BASE 0x10000 +#define EIP97_PE_BASE 0x10000 + /* CDR/RDR register offsets */ -#define EIP197_HIA_xDR_OFF(r) (0x80000 + (r) * 0x1000) -#define EIP197_HIA_CDR(r) (EIP197_HIA_xDR_OFF(r)) -#define EIP197_HIA_RDR(r) (EIP197_HIA_xDR_OFF(r) + 0x800) -#define EIP197_HIA_xDR_RING_BASE_ADDR_LO 0x0 -#define EIP197_HIA_xDR_RING_BASE_ADDR_HI 0x4 -#define EIP197_HIA_xDR_RING_SIZE 0x18 -#define EIP197_HIA_xDR_DESC_SIZE 0x1c -#define EIP197_HIA_xDR_CFG 0x20 -#define EIP197_HIA_xDR_DMA_CFG 0x24 -#define EIP197_HIA_xDR_THRESH 0x28 -#define EIP197_HIA_xDR_PREP_COUNT 0x2c -#define EIP197_HIA_xDR_PROC_COUNT 0x30 -#define EIP197_HIA_xDR_PREP_PNTR 0x34 -#define EIP197_HIA_xDR_PROC_PNTR 0x38 -#define EIP197_HIA_xDR_STAT 0x3c +#define EIP197_HIA_xDR_OFF(priv, r) (EIP197_HIA_AIC_xDR(priv) + (r) * 0x1000) +#define EIP197_HIA_CDR(priv, r) (EIP197_HIA_xDR_OFF(priv, r)) +#define EIP197_HIA_RDR(priv, r) (EIP197_HIA_xDR_OFF(priv, r) + 0x800) +#define EIP197_HIA_xDR_RING_BASE_ADDR_LO 0x0000 +#define EIP197_HIA_xDR_RING_BASE_ADDR_HI 0x0004 +#define EIP197_HIA_xDR_RING_SIZE 0x0018 +#define EIP197_HIA_xDR_DESC_SIZE 0x001c +#define EIP197_HIA_xDR_CFG 0x0020 +#define EIP197_HIA_xDR_DMA_CFG 0x0024 +#define EIP197_HIA_xDR_THRESH 0x0028 +#define EIP197_HIA_xDR_PREP_COUNT 0x002c +#define EIP197_HIA_xDR_PROC_COUNT 0x0030 +#define EIP197_HIA_xDR_PREP_PNTR 0x0034 +#define EIP197_HIA_xDR_PROC_PNTR 0x0038 +#define EIP197_HIA_xDR_STAT 0x003c /* register offsets */ -#define EIP197_HIA_DFE_CFG 0x8c000 -#define EIP197_HIA_DFE_THR_CTRL 0x8c040 -#define EIP197_HIA_DFE_THR_STAT 0x8c044 -#define EIP197_HIA_DSE_CFG 0x8d000 -#define EIP197_HIA_DSE_THR_CTRL 0x8d040 -#define EIP197_HIA_DSE_THR_STAT 0x8d044 -#define EIP197_HIA_RA_PE_CTRL 0x90010 -#define EIP197_HIA_RA_PE_STAT 0x90014 +#define EIP197_HIA_DFE_CFG 0x0000 +#define EIP197_HIA_DFE_THR_CTRL 0x0000 +#define EIP197_HIA_DFE_THR_STAT 0x0004 +#define EIP197_HIA_DSE_CFG 0x0000 +#define EIP197_HIA_DSE_THR_CTRL 0x0000 +#define EIP197_HIA_DSE_THR_STAT 0x0004 +#define EIP197_HIA_RA_PE_CTRL 0x0010 +#define EIP197_HIA_RA_PE_STAT 0x0014 #define EIP197_HIA_AIC_R_OFF(r) ((r) * 0x1000) -#define EIP197_HIA_AIC_R_ENABLE_CTRL(r) (0x9e808 - EIP197_HIA_AIC_R_OFF(r)) -#define EIP197_HIA_AIC_R_ENABLED_STAT(r) (0x9e810 - EIP197_HIA_AIC_R_OFF(r)) -#define EIP197_HIA_AIC_R_ACK(r) (0x9e810 - EIP197_HIA_AIC_R_OFF(r)) -#define EIP197_HIA_AIC_R_ENABLE_CLR(r) (0x9e814 - EIP197_HIA_AIC_R_OFF(r)) -#define EIP197_HIA_AIC_G_ENABLE_CTRL 0x9f808 -#define EIP197_HIA_AIC_G_ENABLED_STAT 0x9f810 -#define EIP197_HIA_AIC_G_ACK 0x9f810 -#define EIP197_HIA_MST_CTRL 0x9fff4 -#define EIP197_HIA_OPTIONS 0x9fff8 -#define EIP197_HIA_VERSION 0x9fffc -#define EIP197_PE_IN_DBUF_THRES 0xa0000 -#define EIP197_PE_IN_TBUF_THRES 0xa0100 -#define EIP197_PE_ICE_SCRATCH_RAM 0xa0800 -#define EIP197_PE_ICE_PUE_CTRL 0xa0c80 -#define EIP197_PE_ICE_SCRATCH_CTRL 0xa0d04 -#define EIP197_PE_ICE_FPP_CTRL 0xa0d80 -#define EIP197_PE_ICE_RAM_CTRL 0xa0ff0 -#define EIP197_PE_EIP96_FUNCTION_EN 0xa1004 -#define EIP197_PE_EIP96_CONTEXT_CTRL 0xa1008 -#define EIP197_PE_EIP96_CONTEXT_STAT 0xa100c -#define EIP197_PE_OUT_DBUF_THRES 0xa1c00 -#define EIP197_PE_OUT_TBUF_THRES 0xa1d00 +#define EIP197_HIA_AIC_R_ENABLE_CTRL(r) (0xe008 - EIP197_HIA_AIC_R_OFF(r)) +#define EIP197_HIA_AIC_R_ENABLED_STAT(r) (0xe010 - EIP197_HIA_AIC_R_OFF(r)) +#define EIP197_HIA_AIC_R_ACK(r) (0xe010 - EIP197_HIA_AIC_R_OFF(r)) +#define EIP197_HIA_AIC_R_ENABLE_CLR(r) (0xe014 - EIP197_HIA_AIC_R_OFF(r)) +#define EIP197_HIA_AIC_G_ENABLE_CTRL 0xf808 +#define EIP197_HIA_AIC_G_ENABLED_STAT 0xf810 +#define EIP197_HIA_AIC_G_ACK 0xf810 +#define EIP197_HIA_MST_CTRL 0xfff4 +#define EIP197_HIA_OPTIONS 0xfff8 +#define EIP197_HIA_VERSION 0xfffc +#define EIP197_PE_IN_DBUF_THRES 0x0000 +#define EIP197_PE_IN_TBUF_THRES 0x0100 +#define EIP197_PE_ICE_SCRATCH_RAM 0x0800 +#define EIP197_PE_ICE_PUE_CTRL 0x0c80 +#define EIP197_PE_ICE_SCRATCH_CTRL 0x0d04 +#define EIP197_PE_ICE_FPP_CTRL 0x0d80 +#define EIP197_PE_ICE_RAM_CTRL 0x0ff0 +#define EIP197_PE_EIP96_FUNCTION_EN 0x1004 +#define EIP197_PE_EIP96_CONTEXT_CTRL 0x1008 +#define EIP197_PE_EIP96_CONTEXT_STAT 0x100c +#define EIP197_PE_OUT_DBUF_THRES 0x1c00 +#define EIP197_PE_OUT_TBUF_THRES 0x1d00 +#define EIP197_MST_CTRL 0xfff4 + +/* EIP197-specific registers, no indirection */ #define EIP197_CLASSIFICATION_RAMS 0xe0000 #define EIP197_TRC_CTRL 0xf0800 #define EIP197_TRC_LASTRES 0xf0804 @@ -90,7 +129,6 @@ #define EIP197_TRC_ECCDATASTAT 0xf083c #define EIP197_TRC_ECCDATA 0xf0840 #define EIP197_CS_RAM_CTRL 0xf7ff0 -#define EIP197_MST_CTRL 0xffff4 /* EIP197_HIA_xDR_DESC_SIZE */ #define EIP197_xDR_DESC_MODE_64BIT BIT(31) @@ -117,6 +155,8 @@ #define EIP197_xDR_PREP_CLR_COUNT BIT(31) /* EIP197_HIA_xDR_PROC_COUNT */ +#define EIP197_xDR_PROC_xD_PKT_OFFSET 24 +#define EIP197_xDR_PROC_xD_PKT_MASK GENMASK(6, 0) #define EIP197_xDR_PROC_xD_COUNT(n) ((n) << 2) #define EIP197_xDR_PROC_xD_PKT(n) ((n) << 24) #define EIP197_xDR_PROC_CLR_COUNT BIT(31) @@ -463,12 +503,33 @@ struct safexcel_work_data { int ring; }; +enum safexcel_eip_version { + EIP97, + EIP197, +}; + +struct safexcel_register_offsets { + u32 hia_aic; + u32 hia_aic_g; + u32 hia_aic_r; + u32 hia_aic_xdr; + u32 hia_dfe; + u32 hia_dfe_thr; + u32 hia_dse; + u32 hia_dse_thr; + u32 hia_gen_cfg; + u32 pe; +}; + struct safexcel_crypto_priv { void __iomem *base; struct device *dev; struct clk *clk; struct safexcel_config config; + enum safexcel_eip_version version; + struct safexcel_register_offsets offsets; + /* context DMA pool */ struct dma_pool *context_pool; @@ -489,7 +550,20 @@ struct safexcel_crypto_priv { /* queue */ struct crypto_queue queue; spinlock_t queue_lock; - bool need_dequeue; + + /* Number of requests in the engine that needs the threshold + * interrupt to be set up. + */ + int requests_left; + + /* The ring is currently handling at least one request */ + bool busy; + + /* Store for current requests when bailing out of the dequeueing + * function when no enough resources are available. + */ + struct crypto_async_request *req; + struct crypto_async_request *backlog; } ring[EIP197_MAX_RINGS]; }; @@ -539,7 +613,6 @@ void safexcel_free_context(struct safexcel_crypto_priv *priv, struct crypto_async_request *req, int result_sz); int safexcel_invalidate_cache(struct crypto_async_request *async, - struct safexcel_context *ctx, struct safexcel_crypto_priv *priv, dma_addr_t ctxr_dma, int ring, struct safexcel_request *request); diff --git a/drivers/crypto/inside-secure/safexcel_cipher.c b/drivers/crypto/inside-secure/safexcel_cipher.c index fcc0a606d748..63a8768ed2ae 100644 --- a/drivers/crypto/inside-secure/safexcel_cipher.c +++ b/drivers/crypto/inside-secure/safexcel_cipher.c @@ -27,7 +27,6 @@ struct safexcel_cipher_ctx { struct safexcel_context base; struct safexcel_crypto_priv *priv; - enum safexcel_cipher_direction direction; u32 mode; __le32 key[8]; @@ -35,6 +34,7 @@ struct safexcel_cipher_ctx { }; struct safexcel_cipher_req { + enum safexcel_cipher_direction direction; bool needs_inv; }; @@ -69,6 +69,7 @@ static int safexcel_aes_setkey(struct crypto_skcipher *ctfm, const u8 *key, { struct crypto_tfm *tfm = crypto_skcipher_tfm(ctfm); struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + struct safexcel_crypto_priv *priv = ctx->priv; struct crypto_aes_ctx aes; int ret, i; @@ -78,10 +79,12 @@ static int safexcel_aes_setkey(struct crypto_skcipher *ctfm, const u8 *key, return ret; } - for (i = 0; i < len / sizeof(u32); i++) { - if (ctx->key[i] != cpu_to_le32(aes.key_enc[i])) { - ctx->base.needs_inv = true; - break; + if (priv->version == EIP197 && ctx->base.ctxr_dma) { + for (i = 0; i < len / sizeof(u32); i++) { + if (ctx->key[i] != cpu_to_le32(aes.key_enc[i])) { + ctx->base.needs_inv = true; + break; + } } } @@ -95,12 +98,15 @@ static int safexcel_aes_setkey(struct crypto_skcipher *ctfm, const u8 *key, } static int safexcel_context_control(struct safexcel_cipher_ctx *ctx, + struct crypto_async_request *async, struct safexcel_command_desc *cdesc) { struct safexcel_crypto_priv *priv = ctx->priv; + struct skcipher_request *req = skcipher_request_cast(async); + struct safexcel_cipher_req *sreq = skcipher_request_ctx(req); int ctrl_size; - if (ctx->direction == SAFEXCEL_ENCRYPT) + if (sreq->direction == SAFEXCEL_ENCRYPT) cdesc->control_data.control0 |= CONTEXT_CONTROL_TYPE_CRYPTO_OUT; else cdesc->control_data.control0 |= CONTEXT_CONTROL_TYPE_CRYPTO_IN; @@ -243,7 +249,7 @@ static int safexcel_aes_send(struct crypto_async_request *async, n_cdesc++; if (n_cdesc == 1) { - safexcel_context_control(ctx, cdesc); + safexcel_context_control(ctx, async, cdesc); safexcel_cipher_token(ctx, async, cdesc, req->cryptlen); } @@ -353,8 +359,8 @@ static int safexcel_handle_inv_result(struct safexcel_crypto_priv *priv, if (enq_ret != -EINPROGRESS) *ret = enq_ret; - if (!priv->ring[ring].need_dequeue) - safexcel_dequeue(priv, ring); + queue_work(priv->ring[ring].workqueue, + &priv->ring[ring].work_data.work); *should_complete = false; @@ -390,7 +396,7 @@ static int safexcel_cipher_send_inv(struct crypto_async_request *async, struct safexcel_crypto_priv *priv = ctx->priv; int ret; - ret = safexcel_invalidate_cache(async, &ctx->base, priv, + ret = safexcel_invalidate_cache(async, priv, ctx->base.ctxr_dma, ring, request); if (unlikely(ret)) return ret; @@ -406,9 +412,13 @@ static int safexcel_send(struct crypto_async_request *async, int *commands, int *results) { struct skcipher_request *req = skcipher_request_cast(async); + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm); struct safexcel_cipher_req *sreq = skcipher_request_ctx(req); + struct safexcel_crypto_priv *priv = ctx->priv; int ret; + BUG_ON(priv->version == EIP97 && sreq->needs_inv); + if (sreq->needs_inv) ret = safexcel_cipher_send_inv(async, ring, request, commands, results); @@ -443,8 +453,8 @@ static int safexcel_cipher_exit_inv(struct crypto_tfm *tfm) crypto_enqueue_request(&priv->ring[ring].queue, &req->base); spin_unlock_bh(&priv->ring[ring].queue_lock); - if (!priv->ring[ring].need_dequeue) - safexcel_dequeue(priv, ring); + queue_work(priv->ring[ring].workqueue, + &priv->ring[ring].work_data.work); wait_for_completion_interruptible(&result.completion); @@ -467,11 +477,11 @@ static int safexcel_aes(struct skcipher_request *req, int ret, ring; sreq->needs_inv = false; - ctx->direction = dir; + sreq->direction = dir; ctx->mode = mode; if (ctx->base.ctxr) { - if (ctx->base.needs_inv) { + if (priv->version == EIP197 && ctx->base.needs_inv) { sreq->needs_inv = true; ctx->base.needs_inv = false; } @@ -490,8 +500,8 @@ static int safexcel_aes(struct skcipher_request *req, ret = crypto_enqueue_request(&priv->ring[ring].queue, &req->base); spin_unlock_bh(&priv->ring[ring].queue_lock); - if (!priv->ring[ring].need_dequeue) - safexcel_dequeue(priv, ring); + queue_work(priv->ring[ring].workqueue, + &priv->ring[ring].work_data.work); return ret; } @@ -539,9 +549,14 @@ static void safexcel_skcipher_cra_exit(struct crypto_tfm *tfm) memzero_explicit(ctx->base.ctxr->data, 8 * sizeof(u32)); - ret = safexcel_cipher_exit_inv(tfm); - if (ret) - dev_warn(priv->dev, "cipher: invalidation error %d\n", ret); + if (priv->version == EIP197) { + ret = safexcel_cipher_exit_inv(tfm); + if (ret) + dev_warn(priv->dev, "cipher: invalidation error %d\n", ret); + } else { + dma_pool_free(priv->context_pool, ctx->base.ctxr, + ctx->base.ctxr_dma); + } } struct safexcel_alg_template safexcel_alg_ecb_aes = { diff --git a/drivers/crypto/inside-secure/safexcel_hash.c b/drivers/crypto/inside-secure/safexcel_hash.c index 0c5a5820b06e..122a2a58e98f 100644 --- a/drivers/crypto/inside-secure/safexcel_hash.c +++ b/drivers/crypto/inside-secure/safexcel_hash.c @@ -14,7 +14,6 @@ #include #include - #include "safexcel.h" struct safexcel_ahash_ctx { @@ -34,6 +33,8 @@ struct safexcel_ahash_req { bool hmac; bool needs_inv; + int nents; + u8 state_sz; /* expected sate size, only set once */ u32 state[SHA256_DIGEST_SIZE / sizeof(u32)] __aligned(sizeof(u32)); @@ -152,8 +153,10 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin memcpy(areq->result, sreq->state, crypto_ahash_digestsize(ahash)); - dma_unmap_sg(priv->dev, areq->src, - sg_nents_for_len(areq->src, areq->nbytes), DMA_TO_DEVICE); + if (sreq->nents) { + dma_unmap_sg(priv->dev, areq->src, sreq->nents, DMA_TO_DEVICE); + sreq->nents = 0; + } safexcel_free_context(priv, async, sreq->state_sz); @@ -178,7 +181,7 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring, struct safexcel_command_desc *cdesc, *first_cdesc = NULL; struct safexcel_result_desc *rdesc; struct scatterlist *sg; - int i, nents, queued, len, cache_len, extra, n_cdesc = 0, ret = 0; + int i, queued, len, cache_len, extra, n_cdesc = 0, ret = 0; queued = len = req->len - req->processed; if (queued < crypto_ahash_blocksize(ahash)) @@ -186,17 +189,31 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring, else cache_len = queued - areq->nbytes; - /* - * If this is not the last request and the queued data does not fit - * into full blocks, cache it for the next send() call. - */ - extra = queued & (crypto_ahash_blocksize(ahash) - 1); - if (!req->last_req && extra) { - sg_pcopy_to_buffer(areq->src, sg_nents(areq->src), - req->cache_next, extra, areq->nbytes - extra); + if (!req->last_req) { + /* If this is not the last request and the queued data does not + * fit into full blocks, cache it for the next send() call. + */ + extra = queued & (crypto_ahash_blocksize(ahash) - 1); + if (!extra) + /* If this is not the last request and the queued data + * is a multiple of a block, cache the last one for now. + */ + extra = queued - crypto_ahash_blocksize(ahash); - queued -= extra; - len -= extra; + if (extra) { + sg_pcopy_to_buffer(areq->src, sg_nents(areq->src), + req->cache_next, extra, + areq->nbytes - extra); + + queued -= extra; + len -= extra; + + if (!queued) { + *commands = 0; + *results = 0; + return 0; + } + } } spin_lock_bh(&priv->ring[ring].egress_lock); @@ -234,15 +251,15 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring, } /* Now handle the current ahash request buffer(s) */ - nents = dma_map_sg(priv->dev, areq->src, - sg_nents_for_len(areq->src, areq->nbytes), - DMA_TO_DEVICE); - if (!nents) { + req->nents = dma_map_sg(priv->dev, areq->src, + sg_nents_for_len(areq->src, areq->nbytes), + DMA_TO_DEVICE); + if (!req->nents) { ret = -ENOMEM; goto cdesc_rollback; } - for_each_sg(areq->src, sg, nents, i) { + for_each_sg(areq->src, sg, req->nents, i) { int sglen = sg_dma_len(sg); /* Do not overflow the request */ @@ -382,8 +399,8 @@ static int safexcel_handle_inv_result(struct safexcel_crypto_priv *priv, if (enq_ret != -EINPROGRESS) *ret = enq_ret; - if (!priv->ring[ring].need_dequeue) - safexcel_dequeue(priv, ring); + queue_work(priv->ring[ring].workqueue, + &priv->ring[ring].work_data.work); *should_complete = false; @@ -398,6 +415,8 @@ static int safexcel_handle_result(struct safexcel_crypto_priv *priv, int ring, struct safexcel_ahash_req *req = ahash_request_ctx(areq); int err; + BUG_ON(priv->version == EIP97 && req->needs_inv); + if (req->needs_inv) { req->needs_inv = false; err = safexcel_handle_inv_result(priv, ring, async, @@ -418,7 +437,7 @@ static int safexcel_ahash_send_inv(struct crypto_async_request *async, struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq)); int ret; - ret = safexcel_invalidate_cache(async, &ctx->base, ctx->priv, + ret = safexcel_invalidate_cache(async, ctx->priv, ctx->base.ctxr_dma, ring, request); if (unlikely(ret)) return ret; @@ -471,8 +490,8 @@ static int safexcel_ahash_exit_inv(struct crypto_tfm *tfm) crypto_enqueue_request(&priv->ring[ring].queue, &req->base); spin_unlock_bh(&priv->ring[ring].queue_lock); - if (!priv->ring[ring].need_dequeue) - safexcel_dequeue(priv, ring); + queue_work(priv->ring[ring].workqueue, + &priv->ring[ring].work_data.work); wait_for_completion_interruptible(&result.completion); @@ -485,13 +504,23 @@ static int safexcel_ahash_exit_inv(struct crypto_tfm *tfm) return 0; } +/* safexcel_ahash_cache: cache data until at least one request can be sent to + * the engine, aka. when there is at least 1 block size in the pipe. + */ static int safexcel_ahash_cache(struct ahash_request *areq) { struct safexcel_ahash_req *req = ahash_request_ctx(areq); struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq); int queued, cache_len; + /* cache_len: everyting accepted by the driver but not sent yet, + * tot sz handled by update() - last req sz - tot sz handled by send() + */ cache_len = req->len - areq->nbytes - req->processed; + /* queued: everything accepted by the driver which will be handled by + * the next send() calls. + * tot sz handled by update() - tot sz handled by send() + */ queued = req->len - req->processed; /* @@ -505,7 +534,7 @@ static int safexcel_ahash_cache(struct ahash_request *areq) return areq->nbytes; } - /* We could'nt cache all the data */ + /* We couldn't cache all the data */ return -E2BIG; } @@ -518,10 +547,17 @@ static int safexcel_ahash_enqueue(struct ahash_request *areq) req->needs_inv = false; - if (req->processed && ctx->digest == CONTEXT_CONTROL_DIGEST_PRECOMPUTED) - ctx->base.needs_inv = safexcel_ahash_needs_inv_get(areq); - if (ctx->base.ctxr) { + if (priv->version == EIP197 && + !ctx->base.needs_inv && req->processed && + ctx->digest == CONTEXT_CONTROL_DIGEST_PRECOMPUTED) + /* We're still setting needs_inv here, even though it is + * cleared right away, because the needs_inv flag can be + * set in other functions and we want to keep the same + * logic. + */ + ctx->base.needs_inv = safexcel_ahash_needs_inv_get(areq); + if (ctx->base.needs_inv) { ctx->base.needs_inv = false; req->needs_inv = true; @@ -541,8 +577,8 @@ static int safexcel_ahash_enqueue(struct ahash_request *areq) ret = crypto_enqueue_request(&priv->ring[ring].queue, &areq->base); spin_unlock_bh(&priv->ring[ring].queue_lock); - if (!priv->ring[ring].need_dequeue) - safexcel_dequeue(priv, ring); + queue_work(priv->ring[ring].workqueue, + &priv->ring[ring].work_data.work); return ret; } @@ -625,7 +661,6 @@ static int safexcel_ahash_export(struct ahash_request *areq, void *out) export->processed = req->processed; memcpy(export->state, req->state, req->state_sz); - memset(export->cache, 0, crypto_ahash_blocksize(ahash)); memcpy(export->cache, req->cache, crypto_ahash_blocksize(ahash)); return 0; @@ -707,9 +742,14 @@ static void safexcel_ahash_cra_exit(struct crypto_tfm *tfm) if (!ctx->base.ctxr) return; - ret = safexcel_ahash_exit_inv(tfm); - if (ret) - dev_warn(priv->dev, "hash: invalidation error %d\n", ret); + if (priv->version == EIP197) { + ret = safexcel_ahash_exit_inv(tfm); + if (ret) + dev_warn(priv->dev, "hash: invalidation error %d\n", ret); + } else { + dma_pool_free(priv->context_pool, ctx->base.ctxr, + ctx->base.ctxr_dma); + } } struct safexcel_alg_template safexcel_alg_sha1 = { @@ -848,7 +888,7 @@ static int safexcel_hmac_init_iv(struct ahash_request *areq, req->last_req = true; ret = crypto_ahash_update(areq); - if (ret && ret != -EINPROGRESS) + if (ret && ret != -EINPROGRESS && ret != -EBUSY) return ret; wait_for_completion_interruptible(&result.completion); @@ -913,6 +953,7 @@ static int safexcel_hmac_sha1_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen) { struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm)); + struct safexcel_crypto_priv *priv = ctx->priv; struct safexcel_ahash_export_state istate, ostate; int ret, i; @@ -920,11 +961,13 @@ static int safexcel_hmac_sha1_setkey(struct crypto_ahash *tfm, const u8 *key, if (ret) return ret; - for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++) { - if (ctx->ipad[i] != le32_to_cpu(istate.state[i]) || - ctx->opad[i] != le32_to_cpu(ostate.state[i])) { - ctx->base.needs_inv = true; - break; + if (priv->version == EIP197 && ctx->base.ctxr) { + for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++) { + if (ctx->ipad[i] != le32_to_cpu(istate.state[i]) || + ctx->opad[i] != le32_to_cpu(ostate.state[i])) { + ctx->base.needs_inv = true; + break; + } } } diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c index 8705b28eb02c..717a26607bdb 100644 --- a/drivers/crypto/ixp4xx_crypto.c +++ b/drivers/crypto/ixp4xx_crypto.c @@ -260,12 +260,11 @@ static int setup_crypt_desc(void) { struct device *dev = &pdev->dev; BUILD_BUG_ON(sizeof(struct crypt_ctl) != 64); - crypt_virt = dma_alloc_coherent(dev, - NPE_QLEN * sizeof(struct crypt_ctl), - &crypt_phys, GFP_ATOMIC); + crypt_virt = dma_zalloc_coherent(dev, + NPE_QLEN * sizeof(struct crypt_ctl), + &crypt_phys, GFP_ATOMIC); if (!crypt_virt) return -ENOMEM; - memset(crypt_virt, 0, NPE_QLEN * sizeof(struct crypt_ctl)); return 0; } diff --git a/drivers/crypto/marvell/cesa.c b/drivers/crypto/marvell/cesa.c index 293832488cc9..aca2373fa1de 100644 --- a/drivers/crypto/marvell/cesa.c +++ b/drivers/crypto/marvell/cesa.c @@ -15,6 +15,7 @@ */ #include +#include #include #include #include @@ -24,6 +25,7 @@ #include #include #include +#include /* XXX: drivers shall never use this directly! */ #include #include #include @@ -409,8 +411,11 @@ static int mv_cesa_get_sram(struct platform_device *pdev, int idx) if (IS_ERR(engine->sram)) return PTR_ERR(engine->sram); - engine->sram_dma = phys_to_dma(cesa->dev, - (phys_addr_t)res->start); + engine->sram_dma = dma_map_resource(cesa->dev, res->start, + cesa->sram_size, + DMA_BIDIRECTIONAL, 0); + if (dma_mapping_error(cesa->dev, engine->sram_dma)) + return -ENOMEM; return 0; } @@ -420,11 +425,12 @@ static void mv_cesa_put_sram(struct platform_device *pdev, int idx) struct mv_cesa_dev *cesa = platform_get_drvdata(pdev); struct mv_cesa_engine *engine = &cesa->engines[idx]; - if (!engine->pool) - return; - - gen_pool_free(engine->pool, (unsigned long)engine->sram, - cesa->sram_size); + if (engine->pool) + gen_pool_free(engine->pool, (unsigned long)engine->sram, + cesa->sram_size); + else + dma_unmap_resource(cesa->dev, engine->sram_dma, + cesa->sram_size, DMA_BIDIRECTIONAL, 0); } static int mv_cesa_probe(struct platform_device *pdev) diff --git a/drivers/crypto/nx/nx-842-powernv.c b/drivers/crypto/nx/nx-842-powernv.c index f2246a5abcf6..1e87637c412d 100644 --- a/drivers/crypto/nx/nx-842-powernv.c +++ b/drivers/crypto/nx/nx-842-powernv.c @@ -743,8 +743,8 @@ static int nx842_open_percpu_txwins(void) } if (!per_cpu(cpu_txwin, i)) { - /* shoudn't happen, Each chip will have NX engine */ - pr_err("NX engine is not availavle for CPU %d\n", i); + /* shouldn't happen, Each chip will have NX engine */ + pr_err("NX engine is not available for CPU %d\n", i); return -EINVAL; } } diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c index 5a6dc53b2b9d..4ef52c9d72fc 100644 --- a/drivers/crypto/picoxcell_crypto.c +++ b/drivers/crypto/picoxcell_crypto.c @@ -1618,7 +1618,7 @@ MODULE_DEVICE_TABLE(of, spacc_of_id_table); static int spacc_probe(struct platform_device *pdev) { - int i, err, ret = -EINVAL; + int i, err, ret; struct resource *mem, *irq; struct device_node *np = pdev->dev.of_node; struct spacc_engine *engine = devm_kzalloc(&pdev->dev, sizeof(*engine), @@ -1679,22 +1679,18 @@ static int spacc_probe(struct platform_device *pdev) engine->clk = clk_get(&pdev->dev, "ref"); if (IS_ERR(engine->clk)) { dev_info(&pdev->dev, "clk unavailable\n"); - device_remove_file(&pdev->dev, &dev_attr_stat_irq_thresh); return PTR_ERR(engine->clk); } if (clk_prepare_enable(engine->clk)) { dev_info(&pdev->dev, "unable to prepare/enable clk\n"); - clk_put(engine->clk); - return -EIO; + ret = -EIO; + goto err_clk_put; } - err = device_create_file(&pdev->dev, &dev_attr_stat_irq_thresh); - if (err) { - clk_disable_unprepare(engine->clk); - clk_put(engine->clk); - return err; - } + ret = device_create_file(&pdev->dev, &dev_attr_stat_irq_thresh); + if (ret) + goto err_clk_disable; /* @@ -1725,6 +1721,7 @@ static int spacc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, engine); + ret = -EINVAL; INIT_LIST_HEAD(&engine->registered_algs); for (i = 0; i < engine->num_algs; ++i) { engine->algs[i].engine = engine; @@ -1759,6 +1756,16 @@ static int spacc_probe(struct platform_device *pdev) engine->aeads[i].alg.base.cra_name); } + if (!ret) + return 0; + + del_timer_sync(&engine->packet_timeout); + device_remove_file(&pdev->dev, &dev_attr_stat_irq_thresh); +err_clk_disable: + clk_disable_unprepare(engine->clk); +err_clk_put: + clk_put(engine->clk); + return ret; } diff --git a/drivers/crypto/qat/qat_common/qat_hal.c b/drivers/crypto/qat/qat_common/qat_hal.c index 8c4fd255a601..ff149e176f64 100644 --- a/drivers/crypto/qat/qat_common/qat_hal.c +++ b/drivers/crypto/qat/qat_common/qat_hal.c @@ -117,19 +117,19 @@ void qat_hal_set_live_ctx(struct icp_qat_fw_loader_handle *handle, #define CSR_RETRY_TIMES 500 static int qat_hal_rd_ae_csr(struct icp_qat_fw_loader_handle *handle, - unsigned char ae, unsigned int csr, - unsigned int *value) + unsigned char ae, unsigned int csr) { unsigned int iterations = CSR_RETRY_TIMES; + int value; do { - *value = GET_AE_CSR(handle, ae, csr); + value = GET_AE_CSR(handle, ae, csr); if (!(GET_AE_CSR(handle, ae, LOCAL_CSR_STATUS) & LCS_STATUS)) - return 0; + return value; } while (iterations--); pr_err("QAT: Read CSR timeout\n"); - return -EFAULT; + return 0; } static int qat_hal_wr_ae_csr(struct icp_qat_fw_loader_handle *handle, @@ -154,9 +154,9 @@ static void qat_hal_get_wakeup_event(struct icp_qat_fw_loader_handle *handle, { unsigned int cur_ctx; - qat_hal_rd_ae_csr(handle, ae, CSR_CTX_POINTER, &cur_ctx); + cur_ctx = qat_hal_rd_ae_csr(handle, ae, CSR_CTX_POINTER); qat_hal_wr_ae_csr(handle, ae, CSR_CTX_POINTER, ctx); - qat_hal_rd_ae_csr(handle, ae, CTX_WAKEUP_EVENTS_INDIRECT, events); + *events = qat_hal_rd_ae_csr(handle, ae, CTX_WAKEUP_EVENTS_INDIRECT); qat_hal_wr_ae_csr(handle, ae, CSR_CTX_POINTER, cur_ctx); } @@ -169,13 +169,13 @@ static int qat_hal_wait_cycles(struct icp_qat_fw_loader_handle *handle, int times = MAX_RETRY_TIMES; int elapsed_cycles = 0; - qat_hal_rd_ae_csr(handle, ae, PROFILE_COUNT, &base_cnt); + base_cnt = qat_hal_rd_ae_csr(handle, ae, PROFILE_COUNT); base_cnt &= 0xffff; while ((int)cycles > elapsed_cycles && times--) { if (chk_inactive) - qat_hal_rd_ae_csr(handle, ae, ACTIVE_CTX_STATUS, &csr); + csr = qat_hal_rd_ae_csr(handle, ae, ACTIVE_CTX_STATUS); - qat_hal_rd_ae_csr(handle, ae, PROFILE_COUNT, &cur_cnt); + cur_cnt = qat_hal_rd_ae_csr(handle, ae, PROFILE_COUNT); cur_cnt &= 0xffff; elapsed_cycles = cur_cnt - base_cnt; @@ -207,7 +207,7 @@ int qat_hal_set_ae_ctx_mode(struct icp_qat_fw_loader_handle *handle, } /* Sets the accelaration engine context mode to either four or eight */ - qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES, &csr); + csr = qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES); csr = IGNORE_W1C_MASK & csr; new_csr = (mode == 4) ? SET_BIT(csr, CE_INUSE_CONTEXTS_BITPOS) : @@ -221,7 +221,7 @@ int qat_hal_set_ae_nn_mode(struct icp_qat_fw_loader_handle *handle, { unsigned int csr, new_csr; - qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES, &csr); + csr = qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES); csr &= IGNORE_W1C_MASK; new_csr = (mode) ? @@ -240,7 +240,7 @@ int qat_hal_set_ae_lm_mode(struct icp_qat_fw_loader_handle *handle, { unsigned int csr, new_csr; - qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES, &csr); + csr = qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES); csr &= IGNORE_W1C_MASK; switch (lm_type) { case ICP_LMEM0: @@ -328,7 +328,7 @@ static void qat_hal_wr_indr_csr(struct icp_qat_fw_loader_handle *handle, { unsigned int ctx, cur_ctx; - qat_hal_rd_ae_csr(handle, ae, CSR_CTX_POINTER, &cur_ctx); + cur_ctx = qat_hal_rd_ae_csr(handle, ae, CSR_CTX_POINTER); for (ctx = 0; ctx < ICP_QAT_UCLO_MAX_CTX; ctx++) { if (!(ctx_mask & (1 << ctx))) @@ -340,16 +340,18 @@ static void qat_hal_wr_indr_csr(struct icp_qat_fw_loader_handle *handle, qat_hal_wr_ae_csr(handle, ae, CSR_CTX_POINTER, cur_ctx); } -static void qat_hal_rd_indr_csr(struct icp_qat_fw_loader_handle *handle, +static unsigned int qat_hal_rd_indr_csr(struct icp_qat_fw_loader_handle *handle, unsigned char ae, unsigned char ctx, - unsigned int ae_csr, unsigned int *csr_val) + unsigned int ae_csr) { - unsigned int cur_ctx; + unsigned int cur_ctx, csr_val; - qat_hal_rd_ae_csr(handle, ae, CSR_CTX_POINTER, &cur_ctx); + cur_ctx = qat_hal_rd_ae_csr(handle, ae, CSR_CTX_POINTER); qat_hal_wr_ae_csr(handle, ae, CSR_CTX_POINTER, ctx); - qat_hal_rd_ae_csr(handle, ae, ae_csr, csr_val); + csr_val = qat_hal_rd_ae_csr(handle, ae, ae_csr); qat_hal_wr_ae_csr(handle, ae, CSR_CTX_POINTER, cur_ctx); + + return csr_val; } static void qat_hal_put_sig_event(struct icp_qat_fw_loader_handle *handle, @@ -358,7 +360,7 @@ static void qat_hal_put_sig_event(struct icp_qat_fw_loader_handle *handle, { unsigned int ctx, cur_ctx; - qat_hal_rd_ae_csr(handle, ae, CSR_CTX_POINTER, &cur_ctx); + cur_ctx = qat_hal_rd_ae_csr(handle, ae, CSR_CTX_POINTER); for (ctx = 0; ctx < ICP_QAT_UCLO_MAX_CTX; ctx++) { if (!(ctx_mask & (1 << ctx))) continue; @@ -374,7 +376,7 @@ static void qat_hal_put_wakeup_event(struct icp_qat_fw_loader_handle *handle, { unsigned int ctx, cur_ctx; - qat_hal_rd_ae_csr(handle, ae, CSR_CTX_POINTER, &cur_ctx); + cur_ctx = qat_hal_rd_ae_csr(handle, ae, CSR_CTX_POINTER); for (ctx = 0; ctx < ICP_QAT_UCLO_MAX_CTX; ctx++) { if (!(ctx_mask & (1 << ctx))) continue; @@ -392,13 +394,11 @@ static int qat_hal_check_ae_alive(struct icp_qat_fw_loader_handle *handle) int times = MAX_RETRY_TIMES; for (ae = 0; ae < handle->hal_handle->ae_max_num; ae++) { - qat_hal_rd_ae_csr(handle, ae, PROFILE_COUNT, - (unsigned int *)&base_cnt); + base_cnt = qat_hal_rd_ae_csr(handle, ae, PROFILE_COUNT); base_cnt &= 0xffff; do { - qat_hal_rd_ae_csr(handle, ae, PROFILE_COUNT, - (unsigned int *)&cur_cnt); + cur_cnt = qat_hal_rd_ae_csr(handle, ae, PROFILE_COUNT); cur_cnt &= 0xffff; } while (times-- && (cur_cnt == base_cnt)); @@ -416,8 +416,8 @@ int qat_hal_check_ae_active(struct icp_qat_fw_loader_handle *handle, { unsigned int enable = 0, active = 0; - qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES, &enable); - qat_hal_rd_ae_csr(handle, ae, ACTIVE_CTX_STATUS, &active); + enable = qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES); + active = qat_hal_rd_ae_csr(handle, ae, ACTIVE_CTX_STATUS); if ((enable & (0xff << CE_ENABLE_BITPOS)) || (active & (1 << ACS_ABO_BITPOS))) return 1; @@ -540,7 +540,7 @@ static void qat_hal_disable_ctx(struct icp_qat_fw_loader_handle *handle, { unsigned int ctx; - qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES, &ctx); + ctx = qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES); ctx &= IGNORE_W1C_MASK & (~((ctx_mask & ICP_QAT_UCLO_AE_ALL_CTX) << CE_ENABLE_BITPOS)); qat_hal_wr_ae_csr(handle, ae, CTX_ENABLES, ctx); @@ -583,7 +583,7 @@ void qat_hal_wr_uwords(struct icp_qat_fw_loader_handle *handle, unsigned int ustore_addr; unsigned int i; - qat_hal_rd_ae_csr(handle, ae, USTORE_ADDRESS, &ustore_addr); + ustore_addr = qat_hal_rd_ae_csr(handle, ae, USTORE_ADDRESS); uaddr |= UA_ECS; qat_hal_wr_ae_csr(handle, ae, USTORE_ADDRESS, uaddr); for (i = 0; i < words_num; i++) { @@ -604,7 +604,7 @@ static void qat_hal_enable_ctx(struct icp_qat_fw_loader_handle *handle, { unsigned int ctx; - qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES, &ctx); + ctx = qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES); ctx &= IGNORE_W1C_MASK; ctx_mask &= (ctx & CE_INUSE_CONTEXTS) ? 0x55 : 0xFF; ctx |= (ctx_mask << CE_ENABLE_BITPOS); @@ -636,10 +636,10 @@ static int qat_hal_clear_gpr(struct icp_qat_fw_loader_handle *handle) int ret = 0; for (ae = 0; ae < handle->hal_handle->ae_max_num; ae++) { - qat_hal_rd_ae_csr(handle, ae, AE_MISC_CONTROL, &csr_val); + csr_val = qat_hal_rd_ae_csr(handle, ae, AE_MISC_CONTROL); csr_val &= ~(1 << MMC_SHARE_CS_BITPOS); qat_hal_wr_ae_csr(handle, ae, AE_MISC_CONTROL, csr_val); - qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES, &csr_val); + csr_val = qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES); csr_val &= IGNORE_W1C_MASK; csr_val |= CE_NN_MODE; qat_hal_wr_ae_csr(handle, ae, CTX_ENABLES, csr_val); @@ -648,7 +648,7 @@ static int qat_hal_clear_gpr(struct icp_qat_fw_loader_handle *handle) qat_hal_wr_indr_csr(handle, ae, ctx_mask, CTX_STS_INDIRECT, handle->hal_handle->upc_mask & INIT_PC_VALUE); - qat_hal_rd_ae_csr(handle, ae, ACTIVE_CTX_STATUS, &savctx); + savctx = qat_hal_rd_ae_csr(handle, ae, ACTIVE_CTX_STATUS); qat_hal_wr_ae_csr(handle, ae, ACTIVE_CTX_STATUS, 0); qat_hal_put_wakeup_event(handle, ae, ctx_mask, XCWE_VOLUNTARY); qat_hal_wr_indr_csr(handle, ae, ctx_mask, @@ -760,7 +760,7 @@ int qat_hal_init(struct adf_accel_dev *accel_dev) for (ae = 0; ae < handle->hal_handle->ae_max_num; ae++) { unsigned int csr_val = 0; - qat_hal_rd_ae_csr(handle, ae, SIGNATURE_ENABLE, &csr_val); + csr_val = qat_hal_rd_ae_csr(handle, ae, SIGNATURE_ENABLE); csr_val |= 0x1; qat_hal_wr_ae_csr(handle, ae, SIGNATURE_ENABLE, csr_val); } @@ -826,16 +826,16 @@ static void qat_hal_get_uwords(struct icp_qat_fw_loader_handle *handle, unsigned int i, uwrd_lo, uwrd_hi; unsigned int ustore_addr, misc_control; - qat_hal_rd_ae_csr(handle, ae, AE_MISC_CONTROL, &misc_control); + misc_control = qat_hal_rd_ae_csr(handle, ae, AE_MISC_CONTROL); qat_hal_wr_ae_csr(handle, ae, AE_MISC_CONTROL, misc_control & 0xfffffffb); - qat_hal_rd_ae_csr(handle, ae, USTORE_ADDRESS, &ustore_addr); + ustore_addr = qat_hal_rd_ae_csr(handle, ae, USTORE_ADDRESS); uaddr |= UA_ECS; for (i = 0; i < words_num; i++) { qat_hal_wr_ae_csr(handle, ae, USTORE_ADDRESS, uaddr); uaddr++; - qat_hal_rd_ae_csr(handle, ae, USTORE_DATA_LOWER, &uwrd_lo); - qat_hal_rd_ae_csr(handle, ae, USTORE_DATA_UPPER, &uwrd_hi); + uwrd_lo = qat_hal_rd_ae_csr(handle, ae, USTORE_DATA_LOWER); + uwrd_hi = qat_hal_rd_ae_csr(handle, ae, USTORE_DATA_UPPER); uword[i] = uwrd_hi; uword[i] = (uword[i] << 0x20) | uwrd_lo; } @@ -849,7 +849,7 @@ void qat_hal_wr_umem(struct icp_qat_fw_loader_handle *handle, { unsigned int i, ustore_addr; - qat_hal_rd_ae_csr(handle, ae, USTORE_ADDRESS, &ustore_addr); + ustore_addr = qat_hal_rd_ae_csr(handle, ae, USTORE_ADDRESS); uaddr |= UA_ECS; qat_hal_wr_ae_csr(handle, ae, USTORE_ADDRESS, uaddr); for (i = 0; i < words_num; i++) { @@ -890,26 +890,27 @@ static int qat_hal_exec_micro_inst(struct icp_qat_fw_loader_handle *handle, return -EINVAL; } /* save current context */ - qat_hal_rd_indr_csr(handle, ae, ctx, LM_ADDR_0_INDIRECT, &ind_lm_addr0); - qat_hal_rd_indr_csr(handle, ae, ctx, LM_ADDR_1_INDIRECT, &ind_lm_addr1); - qat_hal_rd_indr_csr(handle, ae, ctx, INDIRECT_LM_ADDR_0_BYTE_INDEX, - &ind_lm_addr_byte0); - qat_hal_rd_indr_csr(handle, ae, ctx, INDIRECT_LM_ADDR_1_BYTE_INDEX, - &ind_lm_addr_byte1); + ind_lm_addr0 = qat_hal_rd_indr_csr(handle, ae, ctx, LM_ADDR_0_INDIRECT); + ind_lm_addr1 = qat_hal_rd_indr_csr(handle, ae, ctx, LM_ADDR_1_INDIRECT); + ind_lm_addr_byte0 = qat_hal_rd_indr_csr(handle, ae, ctx, + INDIRECT_LM_ADDR_0_BYTE_INDEX); + ind_lm_addr_byte1 = qat_hal_rd_indr_csr(handle, ae, ctx, + INDIRECT_LM_ADDR_1_BYTE_INDEX); if (inst_num <= MAX_EXEC_INST) qat_hal_get_uwords(handle, ae, 0, inst_num, savuwords); qat_hal_get_wakeup_event(handle, ae, ctx, &wakeup_events); - qat_hal_rd_indr_csr(handle, ae, ctx, CTX_STS_INDIRECT, &savpc); + savpc = qat_hal_rd_indr_csr(handle, ae, ctx, CTX_STS_INDIRECT); savpc = (savpc & handle->hal_handle->upc_mask) >> 0; - qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES, &ctx_enables); + ctx_enables = qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES); ctx_enables &= IGNORE_W1C_MASK; - qat_hal_rd_ae_csr(handle, ae, CC_ENABLE, &savcc); - qat_hal_rd_ae_csr(handle, ae, ACTIVE_CTX_STATUS, &savctx); - qat_hal_rd_ae_csr(handle, ae, CTX_ARB_CNTL, &ctxarb_ctl); - qat_hal_rd_indr_csr(handle, ae, ctx, FUTURE_COUNT_SIGNAL_INDIRECT, - &ind_cnt_sig); - qat_hal_rd_indr_csr(handle, ae, ctx, CTX_SIG_EVENTS_INDIRECT, &ind_sig); - qat_hal_rd_ae_csr(handle, ae, CTX_SIG_EVENTS_ACTIVE, &act_sig); + savcc = qat_hal_rd_ae_csr(handle, ae, CC_ENABLE); + savctx = qat_hal_rd_ae_csr(handle, ae, ACTIVE_CTX_STATUS); + ctxarb_ctl = qat_hal_rd_ae_csr(handle, ae, CTX_ARB_CNTL); + ind_cnt_sig = qat_hal_rd_indr_csr(handle, ae, ctx, + FUTURE_COUNT_SIGNAL_INDIRECT); + ind_sig = qat_hal_rd_indr_csr(handle, ae, ctx, + CTX_SIG_EVENTS_INDIRECT); + act_sig = qat_hal_rd_ae_csr(handle, ae, CTX_SIG_EVENTS_ACTIVE); /* execute micro codes */ qat_hal_wr_ae_csr(handle, ae, CTX_ENABLES, ctx_enables); qat_hal_wr_uwords(handle, ae, 0, inst_num, micro_inst); @@ -927,8 +928,8 @@ static int qat_hal_exec_micro_inst(struct icp_qat_fw_loader_handle *handle, if (endpc) { unsigned int ctx_status; - qat_hal_rd_indr_csr(handle, ae, ctx, CTX_STS_INDIRECT, - &ctx_status); + ctx_status = qat_hal_rd_indr_csr(handle, ae, ctx, + CTX_STS_INDIRECT); *endpc = ctx_status & handle->hal_handle->upc_mask; } /* retore to saved context */ @@ -938,7 +939,7 @@ static int qat_hal_exec_micro_inst(struct icp_qat_fw_loader_handle *handle, qat_hal_put_wakeup_event(handle, ae, (1 << ctx), wakeup_events); qat_hal_wr_indr_csr(handle, ae, (1 << ctx), CTX_STS_INDIRECT, handle->hal_handle->upc_mask & savpc); - qat_hal_rd_ae_csr(handle, ae, AE_MISC_CONTROL, &csr_val); + csr_val = qat_hal_rd_ae_csr(handle, ae, AE_MISC_CONTROL); newcsr_val = CLR_BIT(csr_val, MMC_SHARE_CS_BITPOS); qat_hal_wr_ae_csr(handle, ae, AE_MISC_CONTROL, newcsr_val); qat_hal_wr_ae_csr(handle, ae, CC_ENABLE, savcc); @@ -986,16 +987,16 @@ static int qat_hal_rd_rel_reg(struct icp_qat_fw_loader_handle *handle, insts = (uint64_t)0xA030000000ull | ((reg_addr & 0x3ff) << 10); break; } - qat_hal_rd_ae_csr(handle, ae, ACTIVE_CTX_STATUS, &savctx); - qat_hal_rd_ae_csr(handle, ae, CTX_ARB_CNTL, &ctxarb_cntl); - qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES, &ctx_enables); + savctx = qat_hal_rd_ae_csr(handle, ae, ACTIVE_CTX_STATUS); + ctxarb_cntl = qat_hal_rd_ae_csr(handle, ae, CTX_ARB_CNTL); + ctx_enables = qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES); ctx_enables &= IGNORE_W1C_MASK; if (ctx != (savctx & ACS_ACNO)) qat_hal_wr_ae_csr(handle, ae, ACTIVE_CTX_STATUS, ctx & ACS_ACNO); qat_hal_get_uwords(handle, ae, 0, 1, &savuword); qat_hal_wr_ae_csr(handle, ae, CTX_ENABLES, ctx_enables); - qat_hal_rd_ae_csr(handle, ae, USTORE_ADDRESS, &ustore_addr); + ustore_addr = qat_hal_rd_ae_csr(handle, ae, USTORE_ADDRESS); uaddr = UA_ECS; qat_hal_wr_ae_csr(handle, ae, USTORE_ADDRESS, uaddr); insts = qat_hal_set_uword_ecc(insts); @@ -1011,7 +1012,7 @@ static int qat_hal_rd_rel_reg(struct icp_qat_fw_loader_handle *handle, * the instruction should have been executed * prior to clearing the ECS in putUwords */ - qat_hal_rd_ae_csr(handle, ae, ALU_OUT, data); + *data = qat_hal_rd_ae_csr(handle, ae, ALU_OUT); qat_hal_wr_ae_csr(handle, ae, USTORE_ADDRESS, ustore_addr); qat_hal_wr_uwords(handle, ae, 0, 1, &savuword); if (ctx != (savctx & ACS_ACNO)) @@ -1188,7 +1189,7 @@ static int qat_hal_put_rel_rd_xfer(struct icp_qat_fw_loader_handle *handle, unsigned short mask; unsigned short dr_offset = 0x10; - status = qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES, &ctx_enables); + status = ctx_enables = qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES); if (CE_INUSE_CONTEXTS & ctx_enables) { if (ctx & 0x1) { pr_err("QAT: bad 4-ctx mode,ctx=0x%x\n", ctx); @@ -1238,7 +1239,7 @@ static int qat_hal_put_rel_wr_xfer(struct icp_qat_fw_loader_handle *handle, const int num_inst = ARRAY_SIZE(micro_inst), code_off = 1; const unsigned short gprnum = 0, dly = num_inst * 0x5; - qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES, &ctx_enables); + ctx_enables = qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES); if (CE_INUSE_CONTEXTS & ctx_enables) { if (ctx & 0x1) { pr_err("QAT: 4-ctx mode,ctx=0x%x\n", ctx); @@ -1282,7 +1283,7 @@ static int qat_hal_put_rel_nn(struct icp_qat_fw_loader_handle *handle, unsigned int ctx_enables; int stat = 0; - qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES, &ctx_enables); + ctx_enables = qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES); ctx_enables &= IGNORE_W1C_MASK; qat_hal_wr_ae_csr(handle, ae, CTX_ENABLES, ctx_enables | CE_NN_MODE); @@ -1299,7 +1300,7 @@ static int qat_hal_convert_abs_to_rel(struct icp_qat_fw_loader_handle { unsigned int ctx_enables; - qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES, &ctx_enables); + ctx_enables = qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES); if (ctx_enables & CE_INUSE_CONTEXTS) { /* 4-ctx mode */ *relreg = absreg_num & 0x1F; diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 142c6020cec7..188f44b7eb27 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -1,17 +1,13 @@ -/* - * Cryptographic API. - * - * Support for Samsung S5PV210 and Exynos HW acceleration. - * - * Copyright (C) 2011 NetUP Inc. All rights reserved. - * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved. - * - * 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. - * - * Hash part based on omap-sham.c driver. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// Cryptographic API. +// +// Support for Samsung S5PV210 and Exynos HW acceleration. +// +// Copyright (C) 2011 NetUP Inc. All rights reserved. +// Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved. +// +// Hash part based on omap-sham.c driver. #include #include @@ -1461,7 +1457,7 @@ static void s5p_hash_tasklet_cb(unsigned long data) &dd->hash_flags)) { /* hash or semi-hash ready */ clear_bit(HASH_FLAGS_DMA_READY, &dd->hash_flags); - goto finish; + goto finish; } } diff --git a/drivers/crypto/stm32/Kconfig b/drivers/crypto/stm32/Kconfig index 602332e02729..63aa78c0b12b 100644 --- a/drivers/crypto/stm32/Kconfig +++ b/drivers/crypto/stm32/Kconfig @@ -1,4 +1,4 @@ -config CRC_DEV_STM32 +config CRYPTO_DEV_STM32_CRC tristate "Support for STM32 crc accelerators" depends on ARCH_STM32 select CRYPTO_HASH @@ -6,7 +6,7 @@ config CRC_DEV_STM32 This enables support for the CRC32 hw accelerator which can be found on STMicroelectronics STM32 SOC. -config HASH_DEV_STM32 +config CRYPTO_DEV_STM32_HASH tristate "Support for STM32 hash accelerators" depends on ARCH_STM32 depends on HAS_DMA @@ -18,3 +18,12 @@ config HASH_DEV_STM32 help This enables support for the HASH hw accelerator which can be found on STMicroelectronics STM32 SOC. + +config CRYPTO_DEV_STM32_CRYP + tristate "Support for STM32 cryp accelerators" + depends on ARCH_STM32 + select CRYPTO_HASH + select CRYPTO_ENGINE + help + This enables support for the CRYP (AES/DES/TDES) hw accelerator which + can be found on STMicroelectronics STM32 SOC. diff --git a/drivers/crypto/stm32/Makefile b/drivers/crypto/stm32/Makefile index 73cd56cad0cc..53d1bb94b221 100644 --- a/drivers/crypto/stm32/Makefile +++ b/drivers/crypto/stm32/Makefile @@ -1,2 +1,3 @@ -obj-$(CONFIG_CRC_DEV_STM32) += stm32_crc32.o -obj-$(CONFIG_HASH_DEV_STM32) += stm32-hash.o \ No newline at end of file +obj-$(CONFIG_CRYPTO_DEV_STM32_CRC) += stm32_crc32.o +obj-$(CONFIG_CRYPTO_DEV_STM32_HASH) += stm32-hash.o +obj-$(CONFIG_CRYPTO_DEV_STM32_CRYP) += stm32-cryp.o diff --git a/drivers/crypto/stm32/stm32-cryp.c b/drivers/crypto/stm32/stm32-cryp.c new file mode 100644 index 000000000000..4a06a7a665ee --- /dev/null +++ b/drivers/crypto/stm32/stm32-cryp.c @@ -0,0 +1,1170 @@ +/* + * Copyright (C) STMicroelectronics SA 2017 + * Author: Fabien Dessenne + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define DRIVER_NAME "stm32-cryp" + +/* Bit [0] encrypt / decrypt */ +#define FLG_ENCRYPT BIT(0) +/* Bit [8..1] algo & operation mode */ +#define FLG_AES BIT(1) +#define FLG_DES BIT(2) +#define FLG_TDES BIT(3) +#define FLG_ECB BIT(4) +#define FLG_CBC BIT(5) +#define FLG_CTR BIT(6) +/* Mode mask = bits [15..0] */ +#define FLG_MODE_MASK GENMASK(15, 0) + +/* Registers */ +#define CRYP_CR 0x00000000 +#define CRYP_SR 0x00000004 +#define CRYP_DIN 0x00000008 +#define CRYP_DOUT 0x0000000C +#define CRYP_DMACR 0x00000010 +#define CRYP_IMSCR 0x00000014 +#define CRYP_RISR 0x00000018 +#define CRYP_MISR 0x0000001C +#define CRYP_K0LR 0x00000020 +#define CRYP_K0RR 0x00000024 +#define CRYP_K1LR 0x00000028 +#define CRYP_K1RR 0x0000002C +#define CRYP_K2LR 0x00000030 +#define CRYP_K2RR 0x00000034 +#define CRYP_K3LR 0x00000038 +#define CRYP_K3RR 0x0000003C +#define CRYP_IV0LR 0x00000040 +#define CRYP_IV0RR 0x00000044 +#define CRYP_IV1LR 0x00000048 +#define CRYP_IV1RR 0x0000004C + +/* Registers values */ +#define CR_DEC_NOT_ENC 0x00000004 +#define CR_TDES_ECB 0x00000000 +#define CR_TDES_CBC 0x00000008 +#define CR_DES_ECB 0x00000010 +#define CR_DES_CBC 0x00000018 +#define CR_AES_ECB 0x00000020 +#define CR_AES_CBC 0x00000028 +#define CR_AES_CTR 0x00000030 +#define CR_AES_KP 0x00000038 +#define CR_AES_UNKNOWN 0xFFFFFFFF +#define CR_ALGO_MASK 0x00080038 +#define CR_DATA32 0x00000000 +#define CR_DATA16 0x00000040 +#define CR_DATA8 0x00000080 +#define CR_DATA1 0x000000C0 +#define CR_KEY128 0x00000000 +#define CR_KEY192 0x00000100 +#define CR_KEY256 0x00000200 +#define CR_FFLUSH 0x00004000 +#define CR_CRYPEN 0x00008000 + +#define SR_BUSY 0x00000010 +#define SR_OFNE 0x00000004 + +#define IMSCR_IN BIT(0) +#define IMSCR_OUT BIT(1) + +#define MISR_IN BIT(0) +#define MISR_OUT BIT(1) + +/* Misc */ +#define AES_BLOCK_32 (AES_BLOCK_SIZE / sizeof(u32)) +#define _walked_in (cryp->in_walk.offset - cryp->in_sg->offset) +#define _walked_out (cryp->out_walk.offset - cryp->out_sg->offset) + +struct stm32_cryp_ctx { + struct stm32_cryp *cryp; + int keylen; + u32 key[AES_KEYSIZE_256 / sizeof(u32)]; + unsigned long flags; +}; + +struct stm32_cryp_reqctx { + unsigned long mode; +}; + +struct stm32_cryp { + struct list_head list; + struct device *dev; + void __iomem *regs; + struct clk *clk; + unsigned long flags; + u32 irq_status; + struct stm32_cryp_ctx *ctx; + + struct crypto_engine *engine; + + struct mutex lock; /* protects req */ + struct ablkcipher_request *req; + + size_t hw_blocksize; + + size_t total_in; + size_t total_in_save; + size_t total_out; + size_t total_out_save; + + struct scatterlist *in_sg; + struct scatterlist *out_sg; + struct scatterlist *out_sg_save; + + struct scatterlist in_sgl; + struct scatterlist out_sgl; + bool sgs_copied; + + int in_sg_len; + int out_sg_len; + + struct scatter_walk in_walk; + struct scatter_walk out_walk; + + u32 last_ctr[4]; +}; + +struct stm32_cryp_list { + struct list_head dev_list; + spinlock_t lock; /* protect dev_list */ +}; + +static struct stm32_cryp_list cryp_list = { + .dev_list = LIST_HEAD_INIT(cryp_list.dev_list), + .lock = __SPIN_LOCK_UNLOCKED(cryp_list.lock), +}; + +static inline bool is_aes(struct stm32_cryp *cryp) +{ + return cryp->flags & FLG_AES; +} + +static inline bool is_des(struct stm32_cryp *cryp) +{ + return cryp->flags & FLG_DES; +} + +static inline bool is_tdes(struct stm32_cryp *cryp) +{ + return cryp->flags & FLG_TDES; +} + +static inline bool is_ecb(struct stm32_cryp *cryp) +{ + return cryp->flags & FLG_ECB; +} + +static inline bool is_cbc(struct stm32_cryp *cryp) +{ + return cryp->flags & FLG_CBC; +} + +static inline bool is_ctr(struct stm32_cryp *cryp) +{ + return cryp->flags & FLG_CTR; +} + +static inline bool is_encrypt(struct stm32_cryp *cryp) +{ + return cryp->flags & FLG_ENCRYPT; +} + +static inline bool is_decrypt(struct stm32_cryp *cryp) +{ + return !is_encrypt(cryp); +} + +static inline u32 stm32_cryp_read(struct stm32_cryp *cryp, u32 ofst) +{ + return readl_relaxed(cryp->regs + ofst); +} + +static inline void stm32_cryp_write(struct stm32_cryp *cryp, u32 ofst, u32 val) +{ + writel_relaxed(val, cryp->regs + ofst); +} + +static inline int stm32_cryp_wait_busy(struct stm32_cryp *cryp) +{ + u32 status; + + return readl_relaxed_poll_timeout(cryp->regs + CRYP_SR, status, + !(status & SR_BUSY), 10, 100000); +} + +static struct stm32_cryp *stm32_cryp_find_dev(struct stm32_cryp_ctx *ctx) +{ + struct stm32_cryp *tmp, *cryp = NULL; + + spin_lock_bh(&cryp_list.lock); + if (!ctx->cryp) { + list_for_each_entry(tmp, &cryp_list.dev_list, list) { + cryp = tmp; + break; + } + ctx->cryp = cryp; + } else { + cryp = ctx->cryp; + } + + spin_unlock_bh(&cryp_list.lock); + + return cryp; +} + +static int stm32_cryp_check_aligned(struct scatterlist *sg, size_t total, + size_t align) +{ + int len = 0; + + if (!total) + return 0; + + if (!IS_ALIGNED(total, align)) + return -EINVAL; + + while (sg) { + if (!IS_ALIGNED(sg->offset, sizeof(u32))) + return -EINVAL; + + if (!IS_ALIGNED(sg->length, align)) + return -EINVAL; + + len += sg->length; + sg = sg_next(sg); + } + + if (len != total) + return -EINVAL; + + return 0; +} + +static int stm32_cryp_check_io_aligned(struct stm32_cryp *cryp) +{ + int ret; + + ret = stm32_cryp_check_aligned(cryp->in_sg, cryp->total_in, + cryp->hw_blocksize); + if (ret) + return ret; + + ret = stm32_cryp_check_aligned(cryp->out_sg, cryp->total_out, + cryp->hw_blocksize); + + return ret; +} + +static void sg_copy_buf(void *buf, struct scatterlist *sg, + unsigned int start, unsigned int nbytes, int out) +{ + struct scatter_walk walk; + + if (!nbytes) + return; + + scatterwalk_start(&walk, sg); + scatterwalk_advance(&walk, start); + scatterwalk_copychunks(buf, &walk, nbytes, out); + scatterwalk_done(&walk, out, 0); +} + +static int stm32_cryp_copy_sgs(struct stm32_cryp *cryp) +{ + void *buf_in, *buf_out; + int pages, total_in, total_out; + + if (!stm32_cryp_check_io_aligned(cryp)) { + cryp->sgs_copied = 0; + return 0; + } + + total_in = ALIGN(cryp->total_in, cryp->hw_blocksize); + pages = total_in ? get_order(total_in) : 1; + buf_in = (void *)__get_free_pages(GFP_ATOMIC, pages); + + total_out = ALIGN(cryp->total_out, cryp->hw_blocksize); + pages = total_out ? get_order(total_out) : 1; + buf_out = (void *)__get_free_pages(GFP_ATOMIC, pages); + + if (!buf_in || !buf_out) { + dev_err(cryp->dev, "Can't allocate pages when unaligned\n"); + cryp->sgs_copied = 0; + return -EFAULT; + } + + sg_copy_buf(buf_in, cryp->in_sg, 0, cryp->total_in, 0); + + sg_init_one(&cryp->in_sgl, buf_in, total_in); + cryp->in_sg = &cryp->in_sgl; + cryp->in_sg_len = 1; + + sg_init_one(&cryp->out_sgl, buf_out, total_out); + cryp->out_sg_save = cryp->out_sg; + cryp->out_sg = &cryp->out_sgl; + cryp->out_sg_len = 1; + + cryp->sgs_copied = 1; + + return 0; +} + +static void stm32_cryp_hw_write_iv(struct stm32_cryp *cryp, u32 *iv) +{ + if (!iv) + return; + + stm32_cryp_write(cryp, CRYP_IV0LR, cpu_to_be32(*iv++)); + stm32_cryp_write(cryp, CRYP_IV0RR, cpu_to_be32(*iv++)); + + if (is_aes(cryp)) { + stm32_cryp_write(cryp, CRYP_IV1LR, cpu_to_be32(*iv++)); + stm32_cryp_write(cryp, CRYP_IV1RR, cpu_to_be32(*iv++)); + } +} + +static void stm32_cryp_hw_write_key(struct stm32_cryp *c) +{ + unsigned int i; + int r_id; + + if (is_des(c)) { + stm32_cryp_write(c, CRYP_K1LR, cpu_to_be32(c->ctx->key[0])); + stm32_cryp_write(c, CRYP_K1RR, cpu_to_be32(c->ctx->key[1])); + } else { + r_id = CRYP_K3RR; + for (i = c->ctx->keylen / sizeof(u32); i > 0; i--, r_id -= 4) + stm32_cryp_write(c, r_id, + cpu_to_be32(c->ctx->key[i - 1])); + } +} + +static u32 stm32_cryp_get_hw_mode(struct stm32_cryp *cryp) +{ + if (is_aes(cryp) && is_ecb(cryp)) + return CR_AES_ECB; + + if (is_aes(cryp) && is_cbc(cryp)) + return CR_AES_CBC; + + if (is_aes(cryp) && is_ctr(cryp)) + return CR_AES_CTR; + + if (is_des(cryp) && is_ecb(cryp)) + return CR_DES_ECB; + + if (is_des(cryp) && is_cbc(cryp)) + return CR_DES_CBC; + + if (is_tdes(cryp) && is_ecb(cryp)) + return CR_TDES_ECB; + + if (is_tdes(cryp) && is_cbc(cryp)) + return CR_TDES_CBC; + + dev_err(cryp->dev, "Unknown mode\n"); + return CR_AES_UNKNOWN; +} + +static int stm32_cryp_hw_init(struct stm32_cryp *cryp) +{ + int ret; + u32 cfg, hw_mode; + + /* Disable interrupt */ + stm32_cryp_write(cryp, CRYP_IMSCR, 0); + + /* Set key */ + stm32_cryp_hw_write_key(cryp); + + /* Set configuration */ + cfg = CR_DATA8 | CR_FFLUSH; + + switch (cryp->ctx->keylen) { + case AES_KEYSIZE_128: + cfg |= CR_KEY128; + break; + + case AES_KEYSIZE_192: + cfg |= CR_KEY192; + break; + + default: + case AES_KEYSIZE_256: + cfg |= CR_KEY256; + break; + } + + hw_mode = stm32_cryp_get_hw_mode(cryp); + if (hw_mode == CR_AES_UNKNOWN) + return -EINVAL; + + /* AES ECB/CBC decrypt: run key preparation first */ + if (is_decrypt(cryp) && + ((hw_mode == CR_AES_ECB) || (hw_mode == CR_AES_CBC))) { + stm32_cryp_write(cryp, CRYP_CR, cfg | CR_AES_KP | CR_CRYPEN); + + /* Wait for end of processing */ + ret = stm32_cryp_wait_busy(cryp); + if (ret) { + dev_err(cryp->dev, "Timeout (key preparation)\n"); + return ret; + } + } + + cfg |= hw_mode; + + if (is_decrypt(cryp)) + cfg |= CR_DEC_NOT_ENC; + + /* Apply config and flush (valid when CRYPEN = 0) */ + stm32_cryp_write(cryp, CRYP_CR, cfg); + + switch (hw_mode) { + case CR_DES_CBC: + case CR_TDES_CBC: + case CR_AES_CBC: + case CR_AES_CTR: + stm32_cryp_hw_write_iv(cryp, (u32 *)cryp->req->info); + break; + + default: + break; + } + + /* Enable now */ + cfg |= CR_CRYPEN; + + stm32_cryp_write(cryp, CRYP_CR, cfg); + + return 0; +} + +static void stm32_cryp_finish_req(struct stm32_cryp *cryp) +{ + int err = 0; + + if (cryp->sgs_copied) { + void *buf_in, *buf_out; + int pages, len; + + buf_in = sg_virt(&cryp->in_sgl); + buf_out = sg_virt(&cryp->out_sgl); + + sg_copy_buf(buf_out, cryp->out_sg_save, 0, + cryp->total_out_save, 1); + + len = ALIGN(cryp->total_in_save, cryp->hw_blocksize); + pages = len ? get_order(len) : 1; + free_pages((unsigned long)buf_in, pages); + + len = ALIGN(cryp->total_out_save, cryp->hw_blocksize); + pages = len ? get_order(len) : 1; + free_pages((unsigned long)buf_out, pages); + } + + crypto_finalize_cipher_request(cryp->engine, cryp->req, err); + cryp->req = NULL; + + memset(cryp->ctx->key, 0, cryp->ctx->keylen); + + mutex_unlock(&cryp->lock); +} + +static int stm32_cryp_cpu_start(struct stm32_cryp *cryp) +{ + /* Enable interrupt and let the IRQ handler do everything */ + stm32_cryp_write(cryp, CRYP_IMSCR, IMSCR_IN | IMSCR_OUT); + + return 0; +} + +static int stm32_cryp_cra_init(struct crypto_tfm *tfm) +{ + tfm->crt_ablkcipher.reqsize = sizeof(struct stm32_cryp_reqctx); + + return 0; +} + +static int stm32_cryp_crypt(struct ablkcipher_request *req, unsigned long mode) +{ + struct stm32_cryp_ctx *ctx = crypto_ablkcipher_ctx( + crypto_ablkcipher_reqtfm(req)); + struct stm32_cryp_reqctx *rctx = ablkcipher_request_ctx(req); + struct stm32_cryp *cryp = stm32_cryp_find_dev(ctx); + + if (!cryp) + return -ENODEV; + + rctx->mode = mode; + + return crypto_transfer_cipher_request_to_engine(cryp->engine, req); +} + +static int stm32_cryp_setkey(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen) +{ + struct stm32_cryp_ctx *ctx = crypto_ablkcipher_ctx(tfm); + + memcpy(ctx->key, key, keylen); + ctx->keylen = keylen; + + return 0; +} + +static int stm32_cryp_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen) +{ + if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 && + keylen != AES_KEYSIZE_256) + return -EINVAL; + else + return stm32_cryp_setkey(tfm, key, keylen); +} + +static int stm32_cryp_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen) +{ + if (keylen != DES_KEY_SIZE) + return -EINVAL; + else + return stm32_cryp_setkey(tfm, key, keylen); +} + +static int stm32_cryp_tdes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen) +{ + if (keylen != (3 * DES_KEY_SIZE)) + return -EINVAL; + else + return stm32_cryp_setkey(tfm, key, keylen); +} + +static int stm32_cryp_aes_ecb_encrypt(struct ablkcipher_request *req) +{ + return stm32_cryp_crypt(req, FLG_AES | FLG_ECB | FLG_ENCRYPT); +} + +static int stm32_cryp_aes_ecb_decrypt(struct ablkcipher_request *req) +{ + return stm32_cryp_crypt(req, FLG_AES | FLG_ECB); +} + +static int stm32_cryp_aes_cbc_encrypt(struct ablkcipher_request *req) +{ + return stm32_cryp_crypt(req, FLG_AES | FLG_CBC | FLG_ENCRYPT); +} + +static int stm32_cryp_aes_cbc_decrypt(struct ablkcipher_request *req) +{ + return stm32_cryp_crypt(req, FLG_AES | FLG_CBC); +} + +static int stm32_cryp_aes_ctr_encrypt(struct ablkcipher_request *req) +{ + return stm32_cryp_crypt(req, FLG_AES | FLG_CTR | FLG_ENCRYPT); +} + +static int stm32_cryp_aes_ctr_decrypt(struct ablkcipher_request *req) +{ + return stm32_cryp_crypt(req, FLG_AES | FLG_CTR); +} + +static int stm32_cryp_des_ecb_encrypt(struct ablkcipher_request *req) +{ + return stm32_cryp_crypt(req, FLG_DES | FLG_ECB | FLG_ENCRYPT); +} + +static int stm32_cryp_des_ecb_decrypt(struct ablkcipher_request *req) +{ + return stm32_cryp_crypt(req, FLG_DES | FLG_ECB); +} + +static int stm32_cryp_des_cbc_encrypt(struct ablkcipher_request *req) +{ + return stm32_cryp_crypt(req, FLG_DES | FLG_CBC | FLG_ENCRYPT); +} + +static int stm32_cryp_des_cbc_decrypt(struct ablkcipher_request *req) +{ + return stm32_cryp_crypt(req, FLG_DES | FLG_CBC); +} + +static int stm32_cryp_tdes_ecb_encrypt(struct ablkcipher_request *req) +{ + return stm32_cryp_crypt(req, FLG_TDES | FLG_ECB | FLG_ENCRYPT); +} + +static int stm32_cryp_tdes_ecb_decrypt(struct ablkcipher_request *req) +{ + return stm32_cryp_crypt(req, FLG_TDES | FLG_ECB); +} + +static int stm32_cryp_tdes_cbc_encrypt(struct ablkcipher_request *req) +{ + return stm32_cryp_crypt(req, FLG_TDES | FLG_CBC | FLG_ENCRYPT); +} + +static int stm32_cryp_tdes_cbc_decrypt(struct ablkcipher_request *req) +{ + return stm32_cryp_crypt(req, FLG_TDES | FLG_CBC); +} + +static int stm32_cryp_prepare_req(struct crypto_engine *engine, + struct ablkcipher_request *req) +{ + struct stm32_cryp_ctx *ctx; + struct stm32_cryp *cryp; + struct stm32_cryp_reqctx *rctx; + int ret; + + if (!req) + return -EINVAL; + + ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req)); + + cryp = ctx->cryp; + + if (!cryp) + return -ENODEV; + + mutex_lock(&cryp->lock); + + rctx = ablkcipher_request_ctx(req); + rctx->mode &= FLG_MODE_MASK; + + ctx->cryp = cryp; + + cryp->flags = (cryp->flags & ~FLG_MODE_MASK) | rctx->mode; + cryp->hw_blocksize = is_aes(cryp) ? AES_BLOCK_SIZE : DES_BLOCK_SIZE; + cryp->ctx = ctx; + + cryp->req = req; + cryp->total_in = req->nbytes; + cryp->total_out = cryp->total_in; + + cryp->total_in_save = cryp->total_in; + cryp->total_out_save = cryp->total_out; + + cryp->in_sg = req->src; + cryp->out_sg = req->dst; + cryp->out_sg_save = cryp->out_sg; + + cryp->in_sg_len = sg_nents_for_len(cryp->in_sg, cryp->total_in); + if (cryp->in_sg_len < 0) { + dev_err(cryp->dev, "Cannot get in_sg_len\n"); + ret = cryp->in_sg_len; + goto out; + } + + cryp->out_sg_len = sg_nents_for_len(cryp->out_sg, cryp->total_out); + if (cryp->out_sg_len < 0) { + dev_err(cryp->dev, "Cannot get out_sg_len\n"); + ret = cryp->out_sg_len; + goto out; + } + + ret = stm32_cryp_copy_sgs(cryp); + if (ret) + goto out; + + scatterwalk_start(&cryp->in_walk, cryp->in_sg); + scatterwalk_start(&cryp->out_walk, cryp->out_sg); + + ret = stm32_cryp_hw_init(cryp); +out: + if (ret) + mutex_unlock(&cryp->lock); + + return ret; +} + +static int stm32_cryp_prepare_cipher_req(struct crypto_engine *engine, + struct ablkcipher_request *req) +{ + return stm32_cryp_prepare_req(engine, req); +} + +static int stm32_cryp_cipher_one_req(struct crypto_engine *engine, + struct ablkcipher_request *req) +{ + struct stm32_cryp_ctx *ctx = crypto_ablkcipher_ctx( + crypto_ablkcipher_reqtfm(req)); + struct stm32_cryp *cryp = ctx->cryp; + + if (!cryp) + return -ENODEV; + + return stm32_cryp_cpu_start(cryp); +} + +static u32 *stm32_cryp_next_out(struct stm32_cryp *cryp, u32 *dst, + unsigned int n) +{ + scatterwalk_advance(&cryp->out_walk, n); + + if (unlikely(cryp->out_sg->length == _walked_out)) { + cryp->out_sg = sg_next(cryp->out_sg); + if (cryp->out_sg) { + scatterwalk_start(&cryp->out_walk, cryp->out_sg); + return (sg_virt(cryp->out_sg) + _walked_out); + } + } + + return (u32 *)((u8 *)dst + n); +} + +static u32 *stm32_cryp_next_in(struct stm32_cryp *cryp, u32 *src, + unsigned int n) +{ + scatterwalk_advance(&cryp->in_walk, n); + + if (unlikely(cryp->in_sg->length == _walked_in)) { + cryp->in_sg = sg_next(cryp->in_sg); + if (cryp->in_sg) { + scatterwalk_start(&cryp->in_walk, cryp->in_sg); + return (sg_virt(cryp->in_sg) + _walked_in); + } + } + + return (u32 *)((u8 *)src + n); +} + +static void stm32_cryp_check_ctr_counter(struct stm32_cryp *cryp) +{ + u32 cr; + + if (unlikely(cryp->last_ctr[3] == 0xFFFFFFFF)) { + cryp->last_ctr[3] = 0; + cryp->last_ctr[2]++; + if (!cryp->last_ctr[2]) { + cryp->last_ctr[1]++; + if (!cryp->last_ctr[1]) + cryp->last_ctr[0]++; + } + + cr = stm32_cryp_read(cryp, CRYP_CR); + stm32_cryp_write(cryp, CRYP_CR, cr & ~CR_CRYPEN); + + stm32_cryp_hw_write_iv(cryp, (u32 *)cryp->last_ctr); + + stm32_cryp_write(cryp, CRYP_CR, cr); + } + + cryp->last_ctr[0] = stm32_cryp_read(cryp, CRYP_IV0LR); + cryp->last_ctr[1] = stm32_cryp_read(cryp, CRYP_IV0RR); + cryp->last_ctr[2] = stm32_cryp_read(cryp, CRYP_IV1LR); + cryp->last_ctr[3] = stm32_cryp_read(cryp, CRYP_IV1RR); +} + +static bool stm32_cryp_irq_read_data(struct stm32_cryp *cryp) +{ + unsigned int i, j; + u32 d32, *dst; + u8 *d8; + + dst = sg_virt(cryp->out_sg) + _walked_out; + + for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) { + if (likely(cryp->total_out >= sizeof(u32))) { + /* Read a full u32 */ + *dst = stm32_cryp_read(cryp, CRYP_DOUT); + + dst = stm32_cryp_next_out(cryp, dst, sizeof(u32)); + cryp->total_out -= sizeof(u32); + } else if (!cryp->total_out) { + /* Empty fifo out (data from input padding) */ + d32 = stm32_cryp_read(cryp, CRYP_DOUT); + } else { + /* Read less than an u32 */ + d32 = stm32_cryp_read(cryp, CRYP_DOUT); + d8 = (u8 *)&d32; + + for (j = 0; j < cryp->total_out; j++) { + *((u8 *)dst) = *(d8++); + dst = stm32_cryp_next_out(cryp, dst, 1); + } + cryp->total_out = 0; + } + } + + return !cryp->total_out || !cryp->total_in; +} + +static void stm32_cryp_irq_write_block(struct stm32_cryp *cryp) +{ + unsigned int i, j; + u32 *src; + u8 d8[4]; + + src = sg_virt(cryp->in_sg) + _walked_in; + + for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) { + if (likely(cryp->total_in >= sizeof(u32))) { + /* Write a full u32 */ + stm32_cryp_write(cryp, CRYP_DIN, *src); + + src = stm32_cryp_next_in(cryp, src, sizeof(u32)); + cryp->total_in -= sizeof(u32); + } else if (!cryp->total_in) { + /* Write padding data */ + stm32_cryp_write(cryp, CRYP_DIN, 0); + } else { + /* Write less than an u32 */ + memset(d8, 0, sizeof(u32)); + for (j = 0; j < cryp->total_in; j++) { + d8[j] = *((u8 *)src); + src = stm32_cryp_next_in(cryp, src, 1); + } + + stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); + cryp->total_in = 0; + } + } +} + +static void stm32_cryp_irq_write_data(struct stm32_cryp *cryp) +{ + if (unlikely(!cryp->total_in)) { + dev_warn(cryp->dev, "No more data to process\n"); + return; + } + + if (is_aes(cryp) && is_ctr(cryp)) + stm32_cryp_check_ctr_counter(cryp); + + stm32_cryp_irq_write_block(cryp); +} + +static irqreturn_t stm32_cryp_irq_thread(int irq, void *arg) +{ + struct stm32_cryp *cryp = arg; + + if (cryp->irq_status & MISR_OUT) + /* Output FIFO IRQ: read data */ + if (unlikely(stm32_cryp_irq_read_data(cryp))) { + /* All bytes processed, finish */ + stm32_cryp_write(cryp, CRYP_IMSCR, 0); + stm32_cryp_finish_req(cryp); + return IRQ_HANDLED; + } + + if (cryp->irq_status & MISR_IN) { + /* Input FIFO IRQ: write data */ + stm32_cryp_irq_write_data(cryp); + } + + return IRQ_HANDLED; +} + +static irqreturn_t stm32_cryp_irq(int irq, void *arg) +{ + struct stm32_cryp *cryp = arg; + + cryp->irq_status = stm32_cryp_read(cryp, CRYP_MISR); + + return IRQ_WAKE_THREAD; +} + +static struct crypto_alg crypto_algs[] = { +{ + .cra_name = "ecb(aes)", + .cra_driver_name = "stm32-ecb-aes", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct stm32_cryp_ctx), + .cra_alignmask = 0xf, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = stm32_cryp_cra_init, + .cra_ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = stm32_cryp_aes_setkey, + .encrypt = stm32_cryp_aes_ecb_encrypt, + .decrypt = stm32_cryp_aes_ecb_decrypt, + } +}, +{ + .cra_name = "cbc(aes)", + .cra_driver_name = "stm32-cbc-aes", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct stm32_cryp_ctx), + .cra_alignmask = 0xf, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = stm32_cryp_cra_init, + .cra_ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = stm32_cryp_aes_setkey, + .encrypt = stm32_cryp_aes_cbc_encrypt, + .decrypt = stm32_cryp_aes_cbc_decrypt, + } +}, +{ + .cra_name = "ctr(aes)", + .cra_driver_name = "stm32-ctr-aes", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct stm32_cryp_ctx), + .cra_alignmask = 0xf, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = stm32_cryp_cra_init, + .cra_ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = stm32_cryp_aes_setkey, + .encrypt = stm32_cryp_aes_ctr_encrypt, + .decrypt = stm32_cryp_aes_ctr_decrypt, + } +}, +{ + .cra_name = "ecb(des)", + .cra_driver_name = "stm32-ecb-des", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct stm32_cryp_ctx), + .cra_alignmask = 0xf, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = stm32_cryp_cra_init, + .cra_ablkcipher = { + .min_keysize = DES_BLOCK_SIZE, + .max_keysize = DES_BLOCK_SIZE, + .setkey = stm32_cryp_des_setkey, + .encrypt = stm32_cryp_des_ecb_encrypt, + .decrypt = stm32_cryp_des_ecb_decrypt, + } +}, +{ + .cra_name = "cbc(des)", + .cra_driver_name = "stm32-cbc-des", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct stm32_cryp_ctx), + .cra_alignmask = 0xf, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = stm32_cryp_cra_init, + .cra_ablkcipher = { + .min_keysize = DES_BLOCK_SIZE, + .max_keysize = DES_BLOCK_SIZE, + .ivsize = DES_BLOCK_SIZE, + .setkey = stm32_cryp_des_setkey, + .encrypt = stm32_cryp_des_cbc_encrypt, + .decrypt = stm32_cryp_des_cbc_decrypt, + } +}, +{ + .cra_name = "ecb(des3_ede)", + .cra_driver_name = "stm32-ecb-des3", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct stm32_cryp_ctx), + .cra_alignmask = 0xf, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = stm32_cryp_cra_init, + .cra_ablkcipher = { + .min_keysize = 3 * DES_BLOCK_SIZE, + .max_keysize = 3 * DES_BLOCK_SIZE, + .setkey = stm32_cryp_tdes_setkey, + .encrypt = stm32_cryp_tdes_ecb_encrypt, + .decrypt = stm32_cryp_tdes_ecb_decrypt, + } +}, +{ + .cra_name = "cbc(des3_ede)", + .cra_driver_name = "stm32-cbc-des3", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct stm32_cryp_ctx), + .cra_alignmask = 0xf, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = stm32_cryp_cra_init, + .cra_ablkcipher = { + .min_keysize = 3 * DES_BLOCK_SIZE, + .max_keysize = 3 * DES_BLOCK_SIZE, + .ivsize = DES_BLOCK_SIZE, + .setkey = stm32_cryp_tdes_setkey, + .encrypt = stm32_cryp_tdes_cbc_encrypt, + .decrypt = stm32_cryp_tdes_cbc_decrypt, + } +}, +}; + +static const struct of_device_id stm32_dt_ids[] = { + { .compatible = "st,stm32f756-cryp", }, + {}, +}; +MODULE_DEVICE_TABLE(of, stm32_dt_ids); + +static int stm32_cryp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct stm32_cryp *cryp; + struct resource *res; + struct reset_control *rst; + int irq, ret; + + cryp = devm_kzalloc(dev, sizeof(*cryp), GFP_KERNEL); + if (!cryp) + return -ENOMEM; + + cryp->dev = dev; + + mutex_init(&cryp->lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + cryp->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(cryp->regs)) + return PTR_ERR(cryp->regs); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "Cannot get IRQ resource\n"); + return irq; + } + + ret = devm_request_threaded_irq(dev, irq, stm32_cryp_irq, + stm32_cryp_irq_thread, IRQF_ONESHOT, + dev_name(dev), cryp); + if (ret) { + dev_err(dev, "Cannot grab IRQ\n"); + return ret; + } + + cryp->clk = devm_clk_get(dev, NULL); + if (IS_ERR(cryp->clk)) { + dev_err(dev, "Could not get clock\n"); + return PTR_ERR(cryp->clk); + } + + ret = clk_prepare_enable(cryp->clk); + if (ret) { + dev_err(cryp->dev, "Failed to enable clock\n"); + return ret; + } + + rst = devm_reset_control_get(dev, NULL); + if (!IS_ERR(rst)) { + reset_control_assert(rst); + udelay(2); + reset_control_deassert(rst); + } + + platform_set_drvdata(pdev, cryp); + + spin_lock(&cryp_list.lock); + list_add(&cryp->list, &cryp_list.dev_list); + spin_unlock(&cryp_list.lock); + + /* Initialize crypto engine */ + cryp->engine = crypto_engine_alloc_init(dev, 1); + if (!cryp->engine) { + dev_err(dev, "Could not init crypto engine\n"); + ret = -ENOMEM; + goto err_engine1; + } + + cryp->engine->prepare_cipher_request = stm32_cryp_prepare_cipher_req; + cryp->engine->cipher_one_request = stm32_cryp_cipher_one_req; + + ret = crypto_engine_start(cryp->engine); + if (ret) { + dev_err(dev, "Could not start crypto engine\n"); + goto err_engine2; + } + + ret = crypto_register_algs(crypto_algs, ARRAY_SIZE(crypto_algs)); + if (ret) { + dev_err(dev, "Could not register algs\n"); + goto err_algs; + } + + dev_info(dev, "Initialized\n"); + + return 0; + +err_algs: +err_engine2: + crypto_engine_exit(cryp->engine); +err_engine1: + spin_lock(&cryp_list.lock); + list_del(&cryp->list); + spin_unlock(&cryp_list.lock); + + clk_disable_unprepare(cryp->clk); + + return ret; +} + +static int stm32_cryp_remove(struct platform_device *pdev) +{ + struct stm32_cryp *cryp = platform_get_drvdata(pdev); + + if (!cryp) + return -ENODEV; + + crypto_unregister_algs(crypto_algs, ARRAY_SIZE(crypto_algs)); + + crypto_engine_exit(cryp->engine); + + spin_lock(&cryp_list.lock); + list_del(&cryp->list); + spin_unlock(&cryp_list.lock); + + clk_disable_unprepare(cryp->clk); + + return 0; +} + +static struct platform_driver stm32_cryp_driver = { + .probe = stm32_cryp_probe, + .remove = stm32_cryp_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = stm32_dt_ids, + }, +}; + +module_platform_driver(stm32_cryp_driver); + +MODULE_AUTHOR("Fabien Dessenne "); +MODULE_DESCRIPTION("STMicrolectronics STM32 CRYP hardware driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/crypto/stm32/stm32_crc32.c b/drivers/crypto/stm32/stm32_crc32.c index 090582baecfe..8f09b8430893 100644 --- a/drivers/crypto/stm32/stm32_crc32.c +++ b/drivers/crypto/stm32/stm32_crc32.c @@ -208,6 +208,7 @@ static struct shash_alg algs[] = { .cra_name = "crc32", .cra_driver_name = DRIVER_NAME, .cra_priority = 200, + .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, .cra_blocksize = CHKSUM_BLOCK_SIZE, .cra_alignmask = 3, .cra_ctxsize = sizeof(struct stm32_crc_ctx), @@ -229,6 +230,7 @@ static struct shash_alg algs[] = { .cra_name = "crc32c", .cra_driver_name = DRIVER_NAME, .cra_priority = 200, + .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, .cra_blocksize = CHKSUM_BLOCK_SIZE, .cra_alignmask = 3, .cra_ctxsize = sizeof(struct stm32_crc_ctx), diff --git a/drivers/dax/device.c b/drivers/dax/device.c index 7b0bf825c4e7..2137dbc29877 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c @@ -133,7 +133,7 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id, dax_region->base = addr; if (sysfs_create_groups(&parent->kobj, dax_region_attribute_groups)) { kfree(dax_region); - return NULL;; + return NULL; } kref_get(&dax_region->kref); diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index 8d8c852ba8f2..31b6ecce4c64 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c @@ -21,6 +21,7 @@ struct dax_pmem { struct device *dev; struct percpu_ref ref; + struct dev_pagemap pgmap; struct completion cmp; }; @@ -69,20 +70,23 @@ static int dax_pmem_probe(struct device *dev) struct nd_namespace_common *ndns; struct nd_dax *nd_dax = to_nd_dax(dev); struct nd_pfn *nd_pfn = &nd_dax->nd_pfn; - struct vmem_altmap __altmap, *altmap = NULL; ndns = nvdimm_namespace_common_probe(dev); if (IS_ERR(ndns)) return PTR_ERR(ndns); nsio = to_nd_namespace_io(&ndns->dev); + dax_pmem = devm_kzalloc(dev, sizeof(*dax_pmem), GFP_KERNEL); + if (!dax_pmem) + return -ENOMEM; + /* parse the 'pfn' info block via ->rw_bytes */ rc = devm_nsio_enable(dev, nsio); if (rc) return rc; - altmap = nvdimm_setup_pfn(nd_pfn, &res, &__altmap); - if (IS_ERR(altmap)) - return PTR_ERR(altmap); + rc = nvdimm_setup_pfn(nd_pfn, &dax_pmem->pgmap); + if (rc) + return rc; devm_nsio_disable(dev, nsio); pfn_sb = nd_pfn->pfn_sb; @@ -94,10 +98,6 @@ static int dax_pmem_probe(struct device *dev) return -EBUSY; } - dax_pmem = devm_kzalloc(dev, sizeof(*dax_pmem), GFP_KERNEL); - if (!dax_pmem) - return -ENOMEM; - dax_pmem->dev = dev; init_completion(&dax_pmem->cmp); rc = percpu_ref_init(&dax_pmem->ref, dax_pmem_percpu_release, 0, @@ -110,7 +110,8 @@ static int dax_pmem_probe(struct device *dev) if (rc) return rc; - addr = devm_memremap_pages(dev, &res, &dax_pmem->ref, altmap); + dax_pmem->pgmap.ref = &dax_pmem->ref; + addr = devm_memremap_pages(dev, &dax_pmem->pgmap); if (IS_ERR(addr)) return PTR_ERR(addr); @@ -120,6 +121,7 @@ static int dax_pmem_probe(struct device *dev) return rc; /* adjust the dax_region resource to the start of data */ + memcpy(&res, &dax_pmem->pgmap.res, sizeof(res)); res.start += le64_to_cpu(pfn_sb->dataoff); rc = sscanf(dev_name(&ndns->dev), "namespace%d.%d", ®ion_id, &id); diff --git a/drivers/dax/super.c b/drivers/dax/super.c index 3ec804672601..473af694ad1c 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -123,6 +124,15 @@ int __bdev_dax_supported(struct super_block *sb, int blocksize) return len < 0 ? len : -EIO; } + if ((IS_ENABLED(CONFIG_FS_DAX_LIMITED) && pfn_t_special(pfn)) + || pfn_t_devmap(pfn)) + /* pass */; + else { + pr_debug("VFS (%s): error: dax support not enabled\n", + sb->s_id); + return -EOPNOTSUPP; + } + return 0; } EXPORT_SYMBOL_GPL(__bdev_dax_supported); diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 78fb496ecb4e..fe2af6aa88fc 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -737,7 +737,7 @@ struct devfreq *devm_devfreq_add_device(struct device *dev, devfreq = devfreq_add_device(dev, profile, governor_name, data); if (IS_ERR(devfreq)) { devres_free(ptr); - return ERR_PTR(-ENOMEM); + return devfreq; } *ptr = devfreq; @@ -996,7 +996,8 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr, if (df->governor == governor) { ret = 0; goto out; - } else if (df->governor->immutable || governor->immutable) { + } else if ((df->governor && df->governor->immutable) || + governor->immutable) { ret = -EINVAL; goto out; } diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 058805b6d164..d78d5fc173dc 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -135,10 +135,10 @@ static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence) * Userspace can query the state of these implicitly tracked fences using poll() * and related system calls: * - * - Checking for POLLIN, i.e. read access, can be use to query the state of the + * - Checking for EPOLLIN, i.e. read access, can be use to query the state of the * most recent write or exclusive fence. * - * - Checking for POLLOUT, i.e. write access, can be used to query the state of + * - Checking for EPOLLOUT, i.e. write access, can be used to query the state of * all attached fences, shared and exclusive ones. * * Note that this only signals the completion of the respective fences, i.e. the @@ -157,24 +157,24 @@ static void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb) spin_unlock_irqrestore(&dcb->poll->lock, flags); } -static unsigned int dma_buf_poll(struct file *file, poll_table *poll) +static __poll_t dma_buf_poll(struct file *file, poll_table *poll) { struct dma_buf *dmabuf; struct reservation_object *resv; struct reservation_object_list *fobj; struct dma_fence *fence_excl; - unsigned long events; + __poll_t events; unsigned shared_count, seq; dmabuf = file->private_data; if (!dmabuf || !dmabuf->resv) - return POLLERR; + return EPOLLERR; resv = dmabuf->resv; poll_wait(file, &dmabuf->poll, poll); - events = poll_requested_events(poll) & (POLLIN | POLLOUT); + events = poll_requested_events(poll) & (EPOLLIN | EPOLLOUT); if (!events) return 0; @@ -193,12 +193,12 @@ retry: goto retry; } - if (fence_excl && (!(events & POLLOUT) || shared_count == 0)) { + if (fence_excl && (!(events & EPOLLOUT) || shared_count == 0)) { struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_excl; - unsigned long pevents = POLLIN; + __poll_t pevents = EPOLLIN; if (shared_count == 0) - pevents |= POLLOUT; + pevents |= EPOLLOUT; spin_lock_irq(&dmabuf->poll.lock); if (dcb->active) { @@ -228,19 +228,19 @@ retry: } } - if ((events & POLLOUT) && shared_count > 0) { + if ((events & EPOLLOUT) && shared_count > 0) { struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_shared; int i; /* Only queue a new callback if no event has fired yet */ spin_lock_irq(&dmabuf->poll.lock); if (dcb->active) - events &= ~POLLOUT; + events &= ~EPOLLOUT; else - dcb->active = POLLOUT; + dcb->active = EPOLLOUT; spin_unlock_irq(&dmabuf->poll.lock); - if (!(events & POLLOUT)) + if (!(events & EPOLLOUT)) goto out; for (i = 0; i < shared_count; ++i) { @@ -253,14 +253,14 @@ retry: * * call dma_buf_poll_cb and force a recheck! */ - events &= ~POLLOUT; + events &= ~EPOLLOUT; dma_buf_poll_cb(NULL, &dcb->cb); break; } if (!dma_fence_add_callback(fence, &dcb->cb, dma_buf_poll_cb)) { dma_fence_put(fence); - events &= ~POLLOUT; + events &= ~EPOLLOUT; break; } dma_fence_put(fence); diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c index 04ebe2204c12..314eb1071cce 100644 --- a/drivers/dma-buf/reservation.c +++ b/drivers/dma-buf/reservation.c @@ -374,8 +374,9 @@ EXPORT_SYMBOL(reservation_object_copy_fences); * @pshared: the array of shared fence ptrs returned (array is krealloc'd to * the required size, and must be freed by caller) * - * RETURNS - * Zero or -errno + * Retrieve all fences from the reservation object. If the pointer for the + * exclusive fence is not specified the fence is put into the array of the + * shared fences as well. Returns either zero or -ENOMEM. */ int reservation_object_get_fences_rcu(struct reservation_object *obj, struct dma_fence **pfence_excl, @@ -389,8 +390,8 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj, do { struct reservation_object_list *fobj; - unsigned seq; - unsigned int i; + unsigned int i, seq; + size_t sz = 0; shared_count = i = 0; @@ -402,9 +403,14 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj, goto unlock; fobj = rcu_dereference(obj->fence); - if (fobj) { + if (fobj) + sz += sizeof(*shared) * fobj->shared_max; + + if (!pfence_excl && fence_excl) + sz += sizeof(*shared); + + if (sz) { struct dma_fence **nshared; - size_t sz = sizeof(*shared) * fobj->shared_max; nshared = krealloc(shared, sz, GFP_NOWAIT | __GFP_NOWARN); @@ -420,13 +426,19 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj, break; } shared = nshared; - shared_count = fobj->shared_count; - + shared_count = fobj ? fobj->shared_count : 0; for (i = 0; i < shared_count; ++i) { shared[i] = rcu_dereference(fobj->shared[i]); if (!dma_fence_get_rcu(shared[i])) break; } + + if (!pfence_excl && fence_excl) { + shared[i] = fence_excl; + fence_excl = NULL; + ++i; + ++shared_count; + } } if (i != shared_count || read_seqcount_retry(&obj->seq, seq)) { @@ -448,7 +460,8 @@ unlock: *pshared_count = shared_count; *pshared = shared; - *pfence_excl = fence_excl; + if (pfence_excl) + *pfence_excl = fence_excl; return ret; } diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index 24f83f9eeaed..3d78ca89a605 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -43,14 +43,14 @@ * timelines. * * Fences can be created with SW_SYNC_IOC_CREATE_FENCE ioctl with struct - * sw_sync_ioctl_create_fence as parameter. + * sw_sync_create_fence_data as parameter. * * To increment the timeline counter, SW_SYNC_IOC_INC ioctl should be used * with the increment as u32. This will update the last signaled value * from the timeline and signal any fence that has a seqno smaller or equal * to it. * - * struct sw_sync_ioctl_create_fence + * struct sw_sync_create_fence_data * @value: the seqno to initialise the fence with * @name: the name of the new sync point * @fence: return the fd of the new sync_file with the created fence @@ -235,10 +235,10 @@ static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) /** * sync_pt_create() - creates a sync pt - * @parent: fence's parent sync_timeline - * @inc: value of the fence + * @obj: parent sync_timeline + * @value: value of the fence * - * Creates a new sync_pt as a child of @parent. @size bytes will be + * Creates a new sync_pt (fence) as a child of @parent. @size bytes will be * allocated allowing for implementation specific data to be kept after * the generic sync_timeline struct. Returns the sync_pt object or * NULL in case of error. diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c index 03830634e141..35dd06479867 100644 --- a/drivers/dma-buf/sync_file.c +++ b/drivers/dma-buf/sync_file.c @@ -312,7 +312,7 @@ static int sync_file_release(struct inode *inode, struct file *file) return 0; } -static unsigned int sync_file_poll(struct file *file, poll_table *wait) +static __poll_t sync_file_poll(struct file *file, poll_table *wait) { struct sync_file *sync_file = file->private_data; @@ -325,7 +325,7 @@ static unsigned int sync_file_poll(struct file *file, poll_table *wait) wake_up_all(&sync_file->wq); } - return dma_fence_is_signaled(sync_file->fence) ? POLLIN : 0; + return dma_fence_is_signaled(sync_file->fence) ? EPOLLIN : 0; } static long sync_file_ioctl_merge(struct sync_file *sync_file, diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index b52b0d55247e..97483df1f82e 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -2182,7 +2182,7 @@ static int pl08x_terminate_all(struct dma_chan *chan) } /* Dequeue jobs and free LLIs */ if (plchan->at) { - pl08x_desc_free(&plchan->at->vd); + vchan_terminate_vdesc(&plchan->at->vd); plchan->at = NULL; } /* Dequeue jobs not yet fired as well */ @@ -2193,6 +2193,13 @@ static int pl08x_terminate_all(struct dma_chan *chan) return 0; } +static void pl08x_synchronize(struct dma_chan *chan) +{ + struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); + + vchan_synchronize(&plchan->vc); +} + static int pl08x_pause(struct dma_chan *chan) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); @@ -2773,6 +2780,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) pl08x->memcpy.device_pause = pl08x_pause; pl08x->memcpy.device_resume = pl08x_resume; pl08x->memcpy.device_terminate_all = pl08x_terminate_all; + pl08x->memcpy.device_synchronize = pl08x_synchronize; pl08x->memcpy.src_addr_widths = PL80X_DMA_BUSWIDTHS; pl08x->memcpy.dst_addr_widths = PL80X_DMA_BUSWIDTHS; pl08x->memcpy.directions = BIT(DMA_MEM_TO_MEM); @@ -2802,6 +2810,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) pl08x->slave.device_pause = pl08x_pause; pl08x->slave.device_resume = pl08x_resume; pl08x->slave.device_terminate_all = pl08x_terminate_all; + pl08x->slave.device_synchronize = pl08x_synchronize; pl08x->slave.src_addr_widths = PL80X_DMA_BUSWIDTHS; pl08x->slave.dst_addr_widths = PL80X_DMA_BUSWIDTHS; pl08x->slave.directions = diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index 6204cc32d09c..847f84a41a69 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -812,7 +812,7 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan) * c->desc is NULL and exit.) */ if (c->desc) { - bcm2835_dma_desc_free(&c->desc->vd); + vchan_terminate_vdesc(&c->desc->vd); c->desc = NULL; bcm2835_dma_abort(c->chan_base); @@ -836,6 +836,13 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan) return 0; } +static void bcm2835_dma_synchronize(struct dma_chan *chan) +{ + struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); + + vchan_synchronize(&c->vc); +} + static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq, unsigned int irq_flags) { @@ -942,6 +949,7 @@ static int bcm2835_dma_probe(struct platform_device *pdev) od->ddev.device_prep_dma_memcpy = bcm2835_dma_prep_dma_memcpy; od->ddev.device_config = bcm2835_dma_slave_config; od->ddev.device_terminate_all = bcm2835_dma_terminate_all; + od->ddev.device_synchronize = bcm2835_dma_synchronize; od->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); od->ddev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); od->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) | diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c index f7e965f63274..d9bee65a18a4 100644 --- a/drivers/dma/cppi41.c +++ b/drivers/dma/cppi41.c @@ -934,7 +934,7 @@ static bool cpp41_dma_filter_fn(struct dma_chan *chan, void *param) BUILD_BUG_ON(ARRAY_SIZE(am335x_usb_queues_rx) != ARRAY_SIZE(am335x_usb_queues_tx)); - if (WARN_ON(cchan->port_num > ARRAY_SIZE(am335x_usb_queues_rx))) + if (WARN_ON(cchan->port_num >= ARRAY_SIZE(am335x_usb_queues_rx))) return false; cchan->q_num = queues[cchan->port_num].submit; diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 7373b7a555ec..85820a2d69d4 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -511,7 +511,7 @@ static int jz4780_dma_terminate_all(struct dma_chan *chan) /* Clear the DMA status and stop the transfer. */ jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), 0); if (jzchan->desc) { - jz4780_dma_desc_free(&jzchan->desc->vdesc); + vchan_terminate_vdesc(&jzchan->desc->vdesc); jzchan->desc = NULL; } @@ -523,6 +523,13 @@ static int jz4780_dma_terminate_all(struct dma_chan *chan) return 0; } +static void jz4780_dma_synchronize(struct dma_chan *chan) +{ + struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan); + + vchan_synchronize(&jzchan->vchan); +} + static int jz4780_dma_config(struct dma_chan *chan, struct dma_slave_config *config) { @@ -813,6 +820,7 @@ static int jz4780_dma_probe(struct platform_device *pdev) dd->device_prep_dma_memcpy = jz4780_dma_prep_dma_memcpy; dd->device_config = jz4780_dma_config; dd->device_terminate_all = jz4780_dma_terminate_all; + dd->device_synchronize = jz4780_dma_synchronize; dd->device_tx_status = jz4780_dma_tx_status; dd->device_issue_pending = jz4780_dma_issue_pending; dd->src_addr_widths = JZ_DMA_BUSWIDTHS; diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index ec5f9d2bc820..80cc2be6483c 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -355,7 +355,7 @@ static void dmatest_callback(void *arg) { struct dmatest_done *done = arg; struct dmatest_thread *thread = - container_of(arg, struct dmatest_thread, done_wait); + container_of(done, struct dmatest_thread, test_done); if (!thread->done) { done->done = true; wake_up_all(done->wait); diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index 9364a3ed345a..948df1ab5f1a 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -860,11 +860,8 @@ static int edma_terminate_all(struct dma_chan *chan) /* Move the cyclic channel back to default queue */ if (!echan->tc && echan->edesc->cyclic) edma_assign_channel_eventq(echan, EVENTQ_DEFAULT); - /* - * free the running request descriptor - * since it is not in any of the vdesc lists - */ - edma_desc_free(&echan->edesc->vdesc); + + vchan_terminate_vdesc(&echan->edesc->vdesc); echan->edesc = NULL; } diff --git a/drivers/dma/img-mdc-dma.c b/drivers/dma/img-mdc-dma.c index 0391f930aecc..25cec9c243e1 100644 --- a/drivers/dma/img-mdc-dma.c +++ b/drivers/dma/img-mdc-dma.c @@ -694,7 +694,6 @@ static unsigned int mdc_get_new_events(struct mdc_chan *mchan) static int mdc_terminate_all(struct dma_chan *chan) { struct mdc_chan *mchan = to_mdc_chan(chan); - struct mdc_tx_desc *mdesc; unsigned long flags; LIST_HEAD(head); @@ -703,21 +702,28 @@ static int mdc_terminate_all(struct dma_chan *chan) mdc_chan_writel(mchan, MDC_CONTROL_AND_STATUS_CANCEL, MDC_CONTROL_AND_STATUS); - mdesc = mchan->desc; - mchan->desc = NULL; + if (mchan->desc) { + vchan_terminate_vdesc(&mchan->desc->vd); + mchan->desc = NULL; + } vchan_get_all_descriptors(&mchan->vc, &head); mdc_get_new_events(mchan); spin_unlock_irqrestore(&mchan->vc.lock, flags); - if (mdesc) - mdc_desc_free(&mdesc->vd); vchan_dma_desc_free_list(&mchan->vc, &head); return 0; } +static void mdc_synchronize(struct dma_chan *chan) +{ + struct mdc_chan *mchan = to_mdc_chan(chan); + + vchan_synchronize(&mchan->vc); +} + static int mdc_slave_config(struct dma_chan *chan, struct dma_slave_config *config) { @@ -952,6 +958,7 @@ static int mdc_dma_probe(struct platform_device *pdev) mdma->dma_dev.device_tx_status = mdc_tx_status; mdma->dma_dev.device_issue_pending = mdc_issue_pending; mdma->dma_dev.device_terminate_all = mdc_terminate_all; + mdma->dma_dev.device_synchronize = mdc_synchronize; mdma->dma_dev.device_config = mdc_slave_config; mdma->dma_dev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 331f863c605e..715b39ae5a46 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -765,7 +765,7 @@ static int imxdma_alloc_chan_resources(struct dma_chan *chan) desc = kzalloc(sizeof(*desc), GFP_KERNEL); if (!desc) break; - __memzero(&desc->desc, sizeof(struct dma_async_tx_descriptor)); + memset(&desc->desc, 0, sizeof(struct dma_async_tx_descriptor)); dma_async_tx_descriptor_init(&desc->desc, chan); desc->desc.tx_submit = imxdma_tx_submit; /* txd.flags will be overwritten in prep funcs */ diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 2184881afe76..e7db24c67030 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1939,4 +1939,10 @@ module_platform_driver(sdma_driver); MODULE_AUTHOR("Sascha Hauer, Pengutronix "); MODULE_DESCRIPTION("i.MX SDMA driver"); +#if IS_ENABLED(CONFIG_SOC_IMX6Q) +MODULE_FIRMWARE("imx/sdma/sdma-imx6q.bin"); +#endif +#if IS_ENABLED(CONFIG_SOC_IMX7D) +MODULE_FIRMWARE("imx/sdma/sdma-imx7d.bin"); +#endif MODULE_LICENSE("GPL"); diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index 58d4ccd33672..8b5b23a8ace9 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -597,7 +597,6 @@ static void __cleanup(struct ioatdma_chan *ioat_chan, dma_addr_t phys_complete) for (i = 0; i < active && !seen_current; i++) { struct dma_async_tx_descriptor *tx; - smp_read_barrier_depends(); prefetch(ioat_get_ring_ent(ioat_chan, idx + i + 1)); desc = ioat_get_ring_ent(ioat_chan, idx + i); dump_desc_dbg(ioat_chan, desc); @@ -715,7 +714,6 @@ static void ioat_abort_descs(struct ioatdma_chan *ioat_chan) for (i = 1; i < active; i++) { struct dma_async_tx_descriptor *tx; - smp_read_barrier_depends(); prefetch(ioat_get_ring_ent(ioat_chan, idx + i + 1)); desc = ioat_get_ring_ent(ioat_chan, idx + i); diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index 01d2a750a621..26b67455208f 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -719,7 +719,7 @@ static int k3_dma_terminate_all(struct dma_chan *chan) c->phy = NULL; p->vchan = NULL; if (p->ds_run) { - k3_dma_free_desc(&p->ds_run->vd); + vchan_terminate_vdesc(&p->ds_run->vd); p->ds_run = NULL; } p->ds_done = NULL; @@ -730,6 +730,13 @@ static int k3_dma_terminate_all(struct dma_chan *chan) return 0; } +static void k3_dma_synchronize(struct dma_chan *chan) +{ + struct k3_dma_chan *c = to_k3_chan(chan); + + vchan_synchronize(&c->vc); +} + static int k3_dma_transfer_pause(struct dma_chan *chan) { struct k3_dma_chan *c = to_k3_chan(chan); @@ -868,6 +875,7 @@ static int k3_dma_probe(struct platform_device *op) d->slave.device_pause = k3_dma_transfer_pause; d->slave.device_resume = k3_dma_transfer_resume; d->slave.device_terminate_all = k3_dma_terminate_all; + d->slave.device_synchronize = k3_dma_synchronize; d->slave.copy_align = DMAENGINE_ALIGN_8_BYTES; /* init virtual channel */ diff --git a/drivers/dma/mic_x100_dma.c b/drivers/dma/mic_x100_dma.c index 5ba5714d0b7c..94d7bd7d2880 100644 --- a/drivers/dma/mic_x100_dma.c +++ b/drivers/dma/mic_x100_dma.c @@ -480,9 +480,7 @@ static int mic_dma_setup_irq(struct mic_dma_chan *ch) to_mbus_hw_ops(ch)->request_threaded_irq(to_mbus_device(ch), mic_dma_intr_handler, mic_dma_thread_fn, "mic dma_channel", ch, ch->ch_num); - if (IS_ERR(ch->cookie)) - return PTR_ERR(ch->cookie); - return 0; + return PTR_ERR_OR_ZERO(ch->cookie); } static inline void mic_dma_free_irq(struct mic_dma_chan *ch) diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index f6dd849159d8..d21c19822feb 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -1311,7 +1311,7 @@ static int omap_dma_terminate_all(struct dma_chan *chan) * c->desc is NULL and exit.) */ if (c->desc) { - omap_dma_desc_free(&c->desc->vd); + vchan_terminate_vdesc(&c->desc->vd); c->desc = NULL; /* Avoid stopping the dma twice */ if (!c->paused) diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index e3669850aef4..963cc5228d05 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -104,6 +105,10 @@ static unsigned int nr_desc_prm; module_param(nr_desc_prm, uint, 0644); MODULE_PARM_DESC(nr_desc_prm, "number of descriptors (default: 0)"); +enum hidma_cap { + HIDMA_MSI_CAP = 1, + HIDMA_IDENTITY_CAP, +}; /* process completed descriptors */ static void hidma_process_completed(struct hidma_chan *mchan) @@ -736,25 +741,12 @@ static int hidma_request_msi(struct hidma_dev *dmadev, #endif } -static bool hidma_msi_capable(struct device *dev) +static bool hidma_test_capability(struct device *dev, enum hidma_cap test_cap) { - struct acpi_device *adev = ACPI_COMPANION(dev); - const char *of_compat; - int ret = -EINVAL; + enum hidma_cap cap; - if (!adev || acpi_disabled) { - ret = device_property_read_string(dev, "compatible", - &of_compat); - if (ret) - return false; - - ret = strcmp(of_compat, "qcom,hidma-1.1"); - } else { -#ifdef CONFIG_ACPI - ret = strcmp(acpi_device_hid(adev), "QCOM8062"); -#endif - } - return ret == 0; + cap = (enum hidma_cap) device_get_match_data(dev); + return cap ? ((cap & test_cap) > 0) : 0; } static int hidma_probe(struct platform_device *pdev) @@ -834,8 +826,7 @@ static int hidma_probe(struct platform_device *pdev) * Determine the MSI capability of the platform. Old HW doesn't * support MSI. */ - msi = hidma_msi_capable(&pdev->dev); - + msi = hidma_test_capability(&pdev->dev, HIDMA_MSI_CAP); device_property_read_u32(&pdev->dev, "desc-count", &dmadev->nr_descriptors); @@ -848,7 +839,10 @@ static int hidma_probe(struct platform_device *pdev) if (!dmadev->nr_descriptors) dmadev->nr_descriptors = HIDMA_NR_DEFAULT_DESC; - dmadev->chidx = readl(dmadev->dev_trca + 0x28); + if (hidma_test_capability(&pdev->dev, HIDMA_IDENTITY_CAP)) + dmadev->chidx = readl(dmadev->dev_trca + 0x40); + else + dmadev->chidx = readl(dmadev->dev_trca + 0x28); /* Set DMA mask to 64 bits. */ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); @@ -953,7 +947,8 @@ static int hidma_remove(struct platform_device *pdev) #if IS_ENABLED(CONFIG_ACPI) static const struct acpi_device_id hidma_acpi_ids[] = { {"QCOM8061"}, - {"QCOM8062"}, + {"QCOM8062", HIDMA_MSI_CAP}, + {"QCOM8063", (HIDMA_MSI_CAP | HIDMA_IDENTITY_CAP)}, {}, }; MODULE_DEVICE_TABLE(acpi, hidma_acpi_ids); @@ -961,7 +956,9 @@ MODULE_DEVICE_TABLE(acpi, hidma_acpi_ids); static const struct of_device_id hidma_match[] = { {.compatible = "qcom,hidma-1.0",}, - {.compatible = "qcom,hidma-1.1",}, + {.compatible = "qcom,hidma-1.1", .data = (void *)(HIDMA_MSI_CAP),}, + {.compatible = "qcom,hidma-1.2", + .data = (void *)(HIDMA_MSI_CAP | HIDMA_IDENTITY_CAP),}, {}, }; MODULE_DEVICE_TABLE(of, hidma_match); diff --git a/drivers/dma/qcom/hidma_ll.c b/drivers/dma/qcom/hidma_ll.c index 4999e266b2de..7c6e2ff212a2 100644 --- a/drivers/dma/qcom/hidma_ll.c +++ b/drivers/dma/qcom/hidma_ll.c @@ -393,6 +393,8 @@ static int hidma_ll_reset(struct hidma_lldev *lldev) */ static void hidma_ll_int_handler_internal(struct hidma_lldev *lldev, int cause) { + unsigned long irqflags; + if (cause & HIDMA_ERR_INT_MASK) { dev_err(lldev->dev, "error 0x%x, disabling...\n", cause); @@ -410,6 +412,10 @@ static void hidma_ll_int_handler_internal(struct hidma_lldev *lldev, int cause) return; } + spin_lock_irqsave(&lldev->lock, irqflags); + writel_relaxed(cause, lldev->evca + HIDMA_EVCA_IRQ_CLR_REG); + spin_unlock_irqrestore(&lldev->lock, irqflags); + /* * Fine tuned for this HW... * @@ -421,9 +427,6 @@ static void hidma_ll_int_handler_internal(struct hidma_lldev *lldev, int cause) * Try to consume as many EVREs as possible. */ hidma_handle_tre_completion(lldev); - - /* We consumed TREs or there are pending TREs or EVREs. */ - writel_relaxed(cause, lldev->evca + HIDMA_EVCA_IRQ_CLR_REG); } irqreturn_t hidma_ll_inthandler(int chirq, void *arg) diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c index 7335e2eb9b72..000c7019ca7d 100644 --- a/drivers/dma/qcom/hidma_mgmt.c +++ b/drivers/dma/qcom/hidma_mgmt.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -356,59 +357,29 @@ static int __init hidma_mgmt_of_populate_channels(struct device_node *np) { struct platform_device *pdev_parent = of_find_device_by_node(np); struct platform_device_info pdevinfo; - struct of_phandle_args out_irq; struct device_node *child; - struct resource *res = NULL; - const __be32 *cell; - int ret = 0, size, i, num; - u64 addr, addr_size; + struct resource *res; + int ret = 0; + + /* allocate a resource array */ + res = kcalloc(3, sizeof(*res), GFP_KERNEL); + if (!res) + return -ENOMEM; for_each_available_child_of_node(np, child) { - struct resource *res_iter; struct platform_device *new_pdev; - cell = of_get_property(child, "reg", &size); - if (!cell) { - ret = -EINVAL; - goto out; - } - - size /= sizeof(*cell); - num = size / - (of_n_addr_cells(child) + of_n_size_cells(child)) + 1; - - /* allocate a resource array */ - res = kcalloc(num, sizeof(*res), GFP_KERNEL); - if (!res) { - ret = -ENOMEM; - goto out; - } - - /* read each reg value */ - i = 0; - res_iter = res; - while (i < size) { - addr = of_read_number(&cell[i], - of_n_addr_cells(child)); - i += of_n_addr_cells(child); - - addr_size = of_read_number(&cell[i], - of_n_size_cells(child)); - i += of_n_size_cells(child); - - res_iter->start = addr; - res_iter->end = res_iter->start + addr_size - 1; - res_iter->flags = IORESOURCE_MEM; - res_iter++; - } - - ret = of_irq_parse_one(child, 0, &out_irq); - if (ret) + ret = of_address_to_resource(child, 0, &res[0]); + if (!ret) goto out; - res_iter->start = irq_create_of_mapping(&out_irq); - res_iter->name = "hidma event irq"; - res_iter->flags = IORESOURCE_IRQ; + ret = of_address_to_resource(child, 1, &res[1]); + if (!ret) + goto out; + + ret = of_irq_to_resource(child, 0, &res[2]); + if (ret <= 0) + goto out; memset(&pdevinfo, 0, sizeof(pdevinfo)); pdevinfo.fwnode = &child->fwnode; @@ -416,7 +387,7 @@ static int __init hidma_mgmt_of_populate_channels(struct device_node *np) pdevinfo.name = child->name; pdevinfo.id = object_counter++; pdevinfo.res = res; - pdevinfo.num_res = num; + pdevinfo.num_res = 3; pdevinfo.data = NULL; pdevinfo.size_data = 0; pdevinfo.dma_mask = DMA_BIT_MASK(64); @@ -434,8 +405,6 @@ static int __init hidma_mgmt_of_populate_channels(struct device_node *np) */ of_msi_configure(&new_pdev->dev, child); of_node_put(child); - kfree(res); - res = NULL; } out: kfree(res); diff --git a/drivers/dma/s3c24xx-dma.c b/drivers/dma/s3c24xx-dma.c index f04c4702d98b..cd92d696bcf9 100644 --- a/drivers/dma/s3c24xx-dma.c +++ b/drivers/dma/s3c24xx-dma.c @@ -732,7 +732,7 @@ static int s3c24xx_dma_terminate_all(struct dma_chan *chan) /* Dequeue current job */ if (s3cchan->at) { - s3c24xx_dma_desc_free(&s3cchan->at->vd); + vchan_terminate_vdesc(&s3cchan->at->vd); s3cchan->at = NULL; } @@ -744,6 +744,13 @@ unlock: return ret; } +static void s3c24xx_dma_synchronize(struct dma_chan *chan) +{ + struct s3c24xx_dma_chan *s3cchan = to_s3c24xx_dma_chan(chan); + + vchan_synchronize(&s3cchan->vc); +} + static void s3c24xx_dma_free_chan_resources(struct dma_chan *chan) { /* Ensure all queued descriptors are freed */ @@ -1282,6 +1289,7 @@ static int s3c24xx_dma_probe(struct platform_device *pdev) s3cdma->memcpy.device_issue_pending = s3c24xx_dma_issue_pending; s3cdma->memcpy.device_config = s3c24xx_dma_set_runtime_config; s3cdma->memcpy.device_terminate_all = s3c24xx_dma_terminate_all; + s3cdma->memcpy.device_synchronize = s3c24xx_dma_synchronize; /* Initialize slave engine for SoC internal dedicated peripherals */ dma_cap_set(DMA_SLAVE, s3cdma->slave.cap_mask); @@ -1296,6 +1304,7 @@ static int s3c24xx_dma_probe(struct platform_device *pdev) s3cdma->slave.device_prep_dma_cyclic = s3c24xx_dma_prep_dma_cyclic; s3cdma->slave.device_config = s3c24xx_dma_set_runtime_config; s3cdma->slave.device_terminate_all = s3c24xx_dma_terminate_all; + s3cdma->slave.device_synchronize = s3c24xx_dma_synchronize; s3cdma->slave.filter.map = pdata->slave_map; s3cdma->slave.filter.mapcnt = pdata->slavecnt; s3cdma->slave.filter.fn = s3c24xx_dma_filter; diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 2b2c7db3e480..e3ff162c03fc 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -741,6 +742,41 @@ static int rcar_dmac_fill_hwdesc(struct rcar_dmac_chan *chan, /* ----------------------------------------------------------------------------- * Stop and reset */ +static void rcar_dmac_chcr_de_barrier(struct rcar_dmac_chan *chan) +{ + u32 chcr; + unsigned int i; + + /* + * Ensure that the setting of the DE bit is actually 0 after + * clearing it. + */ + for (i = 0; i < 1024; i++) { + chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR); + if (!(chcr & RCAR_DMACHCR_DE)) + return; + udelay(1); + } + + dev_err(chan->chan.device->dev, "CHCR DE check error\n"); +} + +static void rcar_dmac_sync_tcr(struct rcar_dmac_chan *chan) +{ + u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR); + + if (!(chcr & RCAR_DMACHCR_DE)) + return; + + /* set DE=0 and flush remaining data */ + rcar_dmac_chan_write(chan, RCAR_DMACHCR, (chcr & ~RCAR_DMACHCR_DE)); + + /* make sure all remaining data was flushed */ + rcar_dmac_chcr_de_barrier(chan); + + /* back DE */ + rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr); +} static void rcar_dmac_chan_halt(struct rcar_dmac_chan *chan) { @@ -749,6 +785,7 @@ static void rcar_dmac_chan_halt(struct rcar_dmac_chan *chan) chcr &= ~(RCAR_DMACHCR_DSE | RCAR_DMACHCR_DSIE | RCAR_DMACHCR_IE | RCAR_DMACHCR_TE | RCAR_DMACHCR_DE); rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr); + rcar_dmac_chcr_de_barrier(chan); } static void rcar_dmac_chan_reinit(struct rcar_dmac_chan *chan) @@ -1309,8 +1346,11 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan, residue += chunk->size; } + if (desc->direction == DMA_DEV_TO_MEM) + rcar_dmac_sync_tcr(chan); + /* Add the residue for the current chunk. */ - residue += rcar_dmac_chan_read(chan, RCAR_DMATCR) << desc->xfer_shift; + residue += rcar_dmac_chan_read(chan, RCAR_DMATCRB) << desc->xfer_shift; return residue; } @@ -1481,6 +1521,8 @@ static irqreturn_t rcar_dmac_isr_channel(int irq, void *dev) if (chcr & RCAR_DMACHCR_TE) mask |= RCAR_DMACHCR_DE; rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr & ~mask); + if (mask & RCAR_DMACHCR_DE) + rcar_dmac_chcr_de_barrier(chan); if (chcr & RCAR_DMACHCR_DSE) ret |= rcar_dmac_isr_desc_stage_end(chan); @@ -1615,22 +1657,6 @@ static struct dma_chan *rcar_dmac_of_xlate(struct of_phandle_args *dma_spec, * Power management */ -#ifdef CONFIG_PM_SLEEP -static int rcar_dmac_sleep_suspend(struct device *dev) -{ - /* - * TODO: Wait for the current transfer to complete and stop the device. - */ - return 0; -} - -static int rcar_dmac_sleep_resume(struct device *dev) -{ - /* TODO: Resume transfers, if any. */ - return 0; -} -#endif - #ifdef CONFIG_PM static int rcar_dmac_runtime_suspend(struct device *dev) { @@ -1646,7 +1672,13 @@ static int rcar_dmac_runtime_resume(struct device *dev) #endif static const struct dev_pm_ops rcar_dmac_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rcar_dmac_sleep_suspend, rcar_dmac_sleep_resume) + /* + * TODO for system sleep/resume: + * - Wait for the current transfer to complete and stop the device, + * - Resume transfers, if any. + */ + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) SET_RUNTIME_PM_OPS(rcar_dmac_runtime_suspend, rcar_dmac_runtime_resume, NULL) }; diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index b652071a2096..b106e8a60af6 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -710,7 +710,7 @@ static int sprd_dma_config(struct dma_chan *chan, struct sprd_dma_desc *sdesc, return 0; } -struct dma_async_tx_descriptor * +static struct dma_async_tx_descriptor * sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, size_t len, unsigned long flags) { diff --git a/drivers/dma/stm32-dmamux.c b/drivers/dma/stm32-dmamux.c index d5db0f6e1ff8..4dbb30cf94ac 100644 --- a/drivers/dma/stm32-dmamux.c +++ b/drivers/dma/stm32-dmamux.c @@ -253,9 +253,6 @@ static int stm32_dmamux_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - iomem = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(iomem)) return PTR_ERR(iomem); diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index b9d75a54c896..9a558e30c461 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -353,7 +353,8 @@ static int tegra_dma_slave_config(struct dma_chan *dc, } memcpy(&tdc->dma_sconfig, sconfig, sizeof(*sconfig)); - if (tdc->slave_id == TEGRA_APBDMA_SLAVE_ID_INVALID) { + if (tdc->slave_id == TEGRA_APBDMA_SLAVE_ID_INVALID && + sconfig->device_fc) { if (sconfig->slave_id > TEGRA_APBDMA_CSR_REQ_SEL_MASK) return -EINVAL; tdc->slave_id = sconfig->slave_id; @@ -970,8 +971,13 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg( TEGRA_APBDMA_AHBSEQ_WRAP_SHIFT; ahb_seq |= TEGRA_APBDMA_AHBSEQ_BUS_WIDTH_32; - csr |= TEGRA_APBDMA_CSR_ONCE | TEGRA_APBDMA_CSR_FLOW; - csr |= tdc->slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT; + csr |= TEGRA_APBDMA_CSR_ONCE; + + if (tdc->slave_id != TEGRA_APBDMA_SLAVE_ID_INVALID) { + csr |= TEGRA_APBDMA_CSR_FLOW; + csr |= tdc->slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT; + } + if (flags & DMA_PREP_INTERRUPT) csr |= TEGRA_APBDMA_CSR_IE_EOC; @@ -1110,10 +1116,13 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic( TEGRA_APBDMA_AHBSEQ_WRAP_SHIFT; ahb_seq |= TEGRA_APBDMA_AHBSEQ_BUS_WIDTH_32; - csr |= TEGRA_APBDMA_CSR_FLOW; + if (tdc->slave_id != TEGRA_APBDMA_SLAVE_ID_INVALID) { + csr |= TEGRA_APBDMA_CSR_FLOW; + csr |= tdc->slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT; + } + if (flags & DMA_PREP_INTERRUPT) csr |= TEGRA_APBDMA_CSR_IE_EOC; - csr |= tdc->slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT; apb_seq |= TEGRA_APBDMA_APBSEQ_WRAP_WORD_1; diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti-dma-crossbar.c index 7df910e7c348..9272b173c746 100644 --- a/drivers/dma/ti-dma-crossbar.c +++ b/drivers/dma/ti-dma-crossbar.c @@ -54,7 +54,15 @@ struct ti_am335x_xbar_map { static inline void ti_am335x_xbar_write(void __iomem *iomem, int event, u8 val) { - writeb_relaxed(val, iomem + event); + /* + * TPCC_EVT_MUX_60_63 register layout is different than the + * rest, in the sense, that event 63 is mapped to lowest byte + * and event 60 is mapped to highest, handle it separately. + */ + if (event >= 60 && event <= 63) + writeb_relaxed(val, iomem + (63 - event % 4)); + else + writeb_relaxed(val, iomem + event); } static void ti_am335x_xbar_free(struct device *dev, void *route_data) diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c index 896bafb7a532..395c698edb4d 100644 --- a/drivers/dma/timb_dma.c +++ b/drivers/dma/timb_dma.c @@ -422,7 +422,7 @@ static int td_alloc_chan_resources(struct dma_chan *chan) break; else { dev_err(chan2dev(chan), - "Couldnt allocate any descriptors\n"); + "Couldn't allocate any descriptors\n"); return -ENOMEM; } } diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c index 545e97279083..88ad8ed2a8d6 100644 --- a/drivers/dma/virt-dma.c +++ b/drivers/dma/virt-dma.c @@ -107,10 +107,7 @@ static void vchan_complete(unsigned long arg) dmaengine_desc_get_callback(&vd->tx, &cb); list_del(&vd->node); - if (dmaengine_desc_test_reuse(&vd->tx)) - list_add(&vd->node, &vc->desc_allocated); - else - vc->desc_free(vd); + vchan_vdesc_fini(vd); dmaengine_desc_callback_invoke(&cb, NULL); } diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h index 3f776a46a29c..b09b75ab0751 100644 --- a/drivers/dma/virt-dma.h +++ b/drivers/dma/virt-dma.h @@ -35,6 +35,7 @@ struct virt_dma_chan { struct list_head desc_completed; struct virt_dma_desc *cyclic; + struct virt_dma_desc *vd_terminated; }; static inline struct virt_dma_chan *to_virt_chan(struct dma_chan *chan) @@ -103,6 +104,20 @@ static inline void vchan_cookie_complete(struct virt_dma_desc *vd) tasklet_schedule(&vc->task); } +/** + * vchan_vdesc_fini - Free or reuse a descriptor + * @vd: virtual descriptor to free/reuse + */ +static inline void vchan_vdesc_fini(struct virt_dma_desc *vd) +{ + struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan); + + if (dmaengine_desc_test_reuse(&vd->tx)) + list_add(&vd->node, &vc->desc_allocated); + else + vc->desc_free(vd); +} + /** * vchan_cyclic_callback - report the completion of a period * @vd: virtual descriptor @@ -115,6 +130,25 @@ static inline void vchan_cyclic_callback(struct virt_dma_desc *vd) tasklet_schedule(&vc->task); } +/** + * vchan_terminate_vdesc - Disable pending cyclic callback + * @vd: virtual descriptor to be terminated + * + * vc.lock must be held by caller + */ +static inline void vchan_terminate_vdesc(struct virt_dma_desc *vd) +{ + struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan); + + /* free up stuck descriptor */ + if (vc->vd_terminated) + vchan_vdesc_fini(vc->vd_terminated); + + vc->vd_terminated = vd; + if (vc->cyclic == vd) + vc->cyclic = NULL; +} + /** * vchan_next_desc - peek at the next descriptor to be processed * @vc: virtual channel to obtain descriptor from @@ -168,10 +202,20 @@ static inline void vchan_free_chan_resources(struct virt_dma_chan *vc) * Makes sure that all scheduled or active callbacks have finished running. For * proper operation the caller has to ensure that no new callbacks are scheduled * after the invocation of this function started. + * Free up the terminated cyclic descriptor to prevent memory leakage. */ static inline void vchan_synchronize(struct virt_dma_chan *vc) { + unsigned long flags; + tasklet_kill(&vc->task); + + spin_lock_irqsave(&vc->lock, flags); + if (vc->vd_terminated) { + vchan_vdesc_fini(vc->vd_terminated); + vc->vd_terminated = NULL; + } + spin_unlock_irqrestore(&vc->lock, flags); } #endif diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index 5eef13380ca8..27b523530c4a 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -99,7 +99,9 @@ #define XILINX_DMA_REG_FRMPTR_STS 0x0024 #define XILINX_DMA_REG_PARK_PTR 0x0028 #define XILINX_DMA_PARK_PTR_WR_REF_SHIFT 8 +#define XILINX_DMA_PARK_PTR_WR_REF_MASK GENMASK(12, 8) #define XILINX_DMA_PARK_PTR_RD_REF_SHIFT 0 +#define XILINX_DMA_PARK_PTR_RD_REF_MASK GENMASK(4, 0) #define XILINX_DMA_REG_VDMA_VERSION 0x002c /* Register Direct Mode Registers */ @@ -163,6 +165,7 @@ #define XILINX_DMA_BD_SOP BIT(27) #define XILINX_DMA_BD_EOP BIT(26) #define XILINX_DMA_COALESCE_MAX 255 +#define XILINX_DMA_NUM_DESCS 255 #define XILINX_DMA_NUM_APP_WORDS 5 /* Multi-Channel DMA Descriptor offsets*/ @@ -211,8 +214,8 @@ struct xilinx_vdma_desc_hw { * @next_desc_msb: MSB of Next Descriptor Pointer @0x04 * @buf_addr: Buffer address @0x08 * @buf_addr_msb: MSB of Buffer address @0x0C - * @pad1: Reserved @0x10 - * @pad2: Reserved @0x14 + * @mcdma_control: Control field for mcdma @0x10 + * @vsize_stride: Vsize and Stride field for mcdma @0x14 * @control: Control field @0x18 * @status: Status field @0x1C * @app: APP Fields @0x20 - 0x30 @@ -232,11 +235,11 @@ struct xilinx_axidma_desc_hw { /** * struct xilinx_cdma_desc_hw - Hardware Descriptor * @next_desc: Next Descriptor Pointer @0x00 - * @next_descmsb: Next Descriptor Pointer MSB @0x04 + * @next_desc_msb: Next Descriptor Pointer MSB @0x04 * @src_addr: Source address @0x08 - * @src_addrmsb: Source address MSB @0x0C + * @src_addr_msb: Source address MSB @0x0C * @dest_addr: Destination address @0x10 - * @dest_addrmsb: Destination address MSB @0x14 + * @dest_addr_msb: Destination address MSB @0x14 * @control: Control field @0x18 * @status: Status field @0x1C */ @@ -310,6 +313,7 @@ struct xilinx_dma_tx_descriptor { * @pending_list: Descriptors waiting * @active_list: Descriptors ready to submit * @done_list: Complete descriptors + * @free_seg_list: Free descriptors * @common: DMA common channel * @desc_pool: Descriptors pool * @dev: The dma device @@ -321,6 +325,7 @@ struct xilinx_dma_tx_descriptor { * @cyclic: Check for cyclic transfers. * @genlock: Support genlock mode * @err: Channel has errors + * @idle: Check for channel idle * @tasklet: Cleanup work after irq * @config: Device configuration info * @flush_on_fsync: Flush on Frame sync @@ -329,9 +334,12 @@ struct xilinx_dma_tx_descriptor { * @desc_submitcount: Descriptor h/w submitted count * @residue: Residue for AXI DMA * @seg_v: Statically allocated segments base + * @seg_p: Physical allocated segments base * @cyclic_seg_v: Statically allocated segment base for cyclic transfers + * @cyclic_seg_p: Physical allocated segments base for cyclic dma * @start_transfer: Differentiate b/w DMA IP's transfer * @stop_transfer: Differentiate b/w DMA IP's quiesce + * @tdest: TDEST value for mcdma */ struct xilinx_dma_chan { struct xilinx_dma_device *xdev; @@ -341,6 +349,7 @@ struct xilinx_dma_chan { struct list_head pending_list; struct list_head active_list; struct list_head done_list; + struct list_head free_seg_list; struct dma_chan common; struct dma_pool *desc_pool; struct device *dev; @@ -352,6 +361,7 @@ struct xilinx_dma_chan { bool cyclic; bool genlock; bool err; + bool idle; struct tasklet_struct tasklet; struct xilinx_vdma_config config; bool flush_on_fsync; @@ -360,18 +370,20 @@ struct xilinx_dma_chan { u32 desc_submitcount; u32 residue; struct xilinx_axidma_tx_segment *seg_v; + dma_addr_t seg_p; struct xilinx_axidma_tx_segment *cyclic_seg_v; + dma_addr_t cyclic_seg_p; void (*start_transfer)(struct xilinx_dma_chan *chan); int (*stop_transfer)(struct xilinx_dma_chan *chan); u16 tdest; }; /** - * enum xdma_ip_type: DMA IP type. + * enum xdma_ip_type - DMA IP type. * - * XDMA_TYPE_AXIDMA: Axi dma ip. - * XDMA_TYPE_CDMA: Axi cdma ip. - * XDMA_TYPE_VDMA: Axi vdma ip. + * @XDMA_TYPE_AXIDMA: Axi dma ip. + * @XDMA_TYPE_CDMA: Axi cdma ip. + * @XDMA_TYPE_VDMA: Axi vdma ip. * */ enum xdma_ip_type { @@ -580,18 +592,32 @@ xilinx_cdma_alloc_tx_segment(struct xilinx_dma_chan *chan) static struct xilinx_axidma_tx_segment * xilinx_axidma_alloc_tx_segment(struct xilinx_dma_chan *chan) { - struct xilinx_axidma_tx_segment *segment; - dma_addr_t phys; + struct xilinx_axidma_tx_segment *segment = NULL; + unsigned long flags; - segment = dma_pool_zalloc(chan->desc_pool, GFP_ATOMIC, &phys); - if (!segment) - return NULL; - - segment->phys = phys; + spin_lock_irqsave(&chan->lock, flags); + if (!list_empty(&chan->free_seg_list)) { + segment = list_first_entry(&chan->free_seg_list, + struct xilinx_axidma_tx_segment, + node); + list_del(&segment->node); + } + spin_unlock_irqrestore(&chan->lock, flags); return segment; } +static void xilinx_dma_clean_hw_desc(struct xilinx_axidma_desc_hw *hw) +{ + u32 next_desc = hw->next_desc; + u32 next_desc_msb = hw->next_desc_msb; + + memset(hw, 0, sizeof(struct xilinx_axidma_desc_hw)); + + hw->next_desc = next_desc; + hw->next_desc_msb = next_desc_msb; +} + /** * xilinx_dma_free_tx_segment - Free transaction segment * @chan: Driver specific DMA channel @@ -600,7 +626,9 @@ xilinx_axidma_alloc_tx_segment(struct xilinx_dma_chan *chan) static void xilinx_dma_free_tx_segment(struct xilinx_dma_chan *chan, struct xilinx_axidma_tx_segment *segment) { - dma_pool_free(chan->desc_pool, segment, segment->phys); + xilinx_dma_clean_hw_desc(&segment->hw); + + list_add_tail(&segment->node, &chan->free_seg_list); } /** @@ -725,16 +753,31 @@ static void xilinx_dma_free_descriptors(struct xilinx_dma_chan *chan) static void xilinx_dma_free_chan_resources(struct dma_chan *dchan) { struct xilinx_dma_chan *chan = to_xilinx_chan(dchan); + unsigned long flags; dev_dbg(chan->dev, "Free all channel resources.\n"); xilinx_dma_free_descriptors(chan); + if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) { - xilinx_dma_free_tx_segment(chan, chan->cyclic_seg_v); - xilinx_dma_free_tx_segment(chan, chan->seg_v); + spin_lock_irqsave(&chan->lock, flags); + INIT_LIST_HEAD(&chan->free_seg_list); + spin_unlock_irqrestore(&chan->lock, flags); + + /* Free memory that is allocated for BD */ + dma_free_coherent(chan->dev, sizeof(*chan->seg_v) * + XILINX_DMA_NUM_DESCS, chan->seg_v, + chan->seg_p); + + /* Free Memory that is allocated for cyclic DMA Mode */ + dma_free_coherent(chan->dev, sizeof(*chan->cyclic_seg_v), + chan->cyclic_seg_v, chan->cyclic_seg_p); + } + + if (chan->xdev->dma_config->dmatype != XDMA_TYPE_AXIDMA) { + dma_pool_destroy(chan->desc_pool); + chan->desc_pool = NULL; } - dma_pool_destroy(chan->desc_pool); - chan->desc_pool = NULL; } /** @@ -817,6 +860,7 @@ static void xilinx_dma_do_tasklet(unsigned long data) static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan) { struct xilinx_dma_chan *chan = to_xilinx_chan(dchan); + int i; /* Has this channel already been allocated? */ if (chan->desc_pool) @@ -827,11 +871,30 @@ static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan) * for meeting Xilinx VDMA specification requirement. */ if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) { - chan->desc_pool = dma_pool_create("xilinx_dma_desc_pool", - chan->dev, - sizeof(struct xilinx_axidma_tx_segment), - __alignof__(struct xilinx_axidma_tx_segment), - 0); + /* Allocate the buffer descriptors. */ + chan->seg_v = dma_zalloc_coherent(chan->dev, + sizeof(*chan->seg_v) * + XILINX_DMA_NUM_DESCS, + &chan->seg_p, GFP_KERNEL); + if (!chan->seg_v) { + dev_err(chan->dev, + "unable to allocate channel %d descriptors\n", + chan->id); + return -ENOMEM; + } + + for (i = 0; i < XILINX_DMA_NUM_DESCS; i++) { + chan->seg_v[i].hw.next_desc = + lower_32_bits(chan->seg_p + sizeof(*chan->seg_v) * + ((i + 1) % XILINX_DMA_NUM_DESCS)); + chan->seg_v[i].hw.next_desc_msb = + upper_32_bits(chan->seg_p + sizeof(*chan->seg_v) * + ((i + 1) % XILINX_DMA_NUM_DESCS)); + chan->seg_v[i].phys = chan->seg_p + + sizeof(*chan->seg_v) * i; + list_add_tail(&chan->seg_v[i].node, + &chan->free_seg_list); + } } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) { chan->desc_pool = dma_pool_create("xilinx_cdma_desc_pool", chan->dev, @@ -846,7 +909,8 @@ static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan) 0); } - if (!chan->desc_pool) { + if (!chan->desc_pool && + (chan->xdev->dma_config->dmatype != XDMA_TYPE_AXIDMA)) { dev_err(chan->dev, "unable to allocate channel %d descriptor pool\n", chan->id); @@ -854,23 +918,21 @@ static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan) } if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) { - /* - * For AXI DMA case after submitting a pending_list, keep - * an extra segment allocated so that the "next descriptor" - * pointer on the tail descriptor always points to a - * valid descriptor, even when paused after reaching taildesc. - * This way, it is possible to issue additional - * transfers without halting and restarting the channel. - */ - chan->seg_v = xilinx_axidma_alloc_tx_segment(chan); - /* * For cyclic DMA mode we need to program the tail Descriptor * register with a value which is not a part of the BD chain * so allocating a desc segment during channel allocation for * programming tail descriptor. */ - chan->cyclic_seg_v = xilinx_axidma_alloc_tx_segment(chan); + chan->cyclic_seg_v = dma_zalloc_coherent(chan->dev, + sizeof(*chan->cyclic_seg_v), + &chan->cyclic_seg_p, GFP_KERNEL); + if (!chan->cyclic_seg_v) { + dev_err(chan->dev, + "unable to allocate desc segment for cyclic DMA\n"); + return -ENOMEM; + } + chan->cyclic_seg_v->phys = chan->cyclic_seg_p; } dma_cookie_init(dchan); @@ -935,35 +997,11 @@ static enum dma_status xilinx_dma_tx_status(struct dma_chan *dchan, return ret; } -/** - * xilinx_dma_is_running - Check if DMA channel is running - * @chan: Driver specific DMA channel - * - * Return: '1' if running, '0' if not. - */ -static bool xilinx_dma_is_running(struct xilinx_dma_chan *chan) -{ - return !(dma_ctrl_read(chan, XILINX_DMA_REG_DMASR) & - XILINX_DMA_DMASR_HALTED) && - (dma_ctrl_read(chan, XILINX_DMA_REG_DMACR) & - XILINX_DMA_DMACR_RUNSTOP); -} - -/** - * xilinx_dma_is_idle - Check if DMA channel is idle - * @chan: Driver specific DMA channel - * - * Return: '1' if idle, '0' if not. - */ -static bool xilinx_dma_is_idle(struct xilinx_dma_chan *chan) -{ - return dma_ctrl_read(chan, XILINX_DMA_REG_DMASR) & - XILINX_DMA_DMASR_IDLE; -} - /** * xilinx_dma_stop_transfer - Halt DMA channel * @chan: Driver specific DMA channel + * + * Return: '0' on success and failure value on error */ static int xilinx_dma_stop_transfer(struct xilinx_dma_chan *chan) { @@ -980,6 +1018,8 @@ static int xilinx_dma_stop_transfer(struct xilinx_dma_chan *chan) /** * xilinx_cdma_stop_transfer - Wait for the current transfer to complete * @chan: Driver specific DMA channel + * + * Return: '0' on success and failure value on error */ static int xilinx_cdma_stop_transfer(struct xilinx_dma_chan *chan) { @@ -1022,13 +1062,16 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan) { struct xilinx_vdma_config *config = &chan->config; struct xilinx_dma_tx_descriptor *desc, *tail_desc; - u32 reg; + u32 reg, j; struct xilinx_vdma_tx_segment *tail_segment; /* This function was invoked with lock held */ if (chan->err) return; + if (!chan->idle) + return; + if (list_empty(&chan->pending_list)) return; @@ -1040,13 +1083,6 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan) tail_segment = list_last_entry(&tail_desc->segments, struct xilinx_vdma_tx_segment, node); - /* If it is SG mode and hardware is busy, cannot submit */ - if (chan->has_sg && xilinx_dma_is_running(chan) && - !xilinx_dma_is_idle(chan)) { - dev_dbg(chan->dev, "DMA controller still busy\n"); - return; - } - /* * If hardware is idle, then all descriptors on the running lists are * done, start new transfers @@ -1063,10 +1099,6 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan) else reg &= ~XILINX_DMA_DMACR_FRAMECNT_EN; - /* Configure channel to allow number frame buffers */ - dma_ctrl_write(chan, XILINX_DMA_REG_FRMSTORE, - chan->desc_pendingcount); - /* * With SG, start with circular mode, so that BDs can be fetched. * In direct register mode, if not parking, enable circular mode @@ -1079,17 +1111,16 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan) dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg); - if (config->park && (config->park_frm >= 0) && - (config->park_frm < chan->num_frms)) { - if (chan->direction == DMA_MEM_TO_DEV) - dma_write(chan, XILINX_DMA_REG_PARK_PTR, - config->park_frm << - XILINX_DMA_PARK_PTR_RD_REF_SHIFT); - else - dma_write(chan, XILINX_DMA_REG_PARK_PTR, - config->park_frm << - XILINX_DMA_PARK_PTR_WR_REF_SHIFT); + j = chan->desc_submitcount; + reg = dma_read(chan, XILINX_DMA_REG_PARK_PTR); + if (chan->direction == DMA_MEM_TO_DEV) { + reg &= ~XILINX_DMA_PARK_PTR_RD_REF_MASK; + reg |= j << XILINX_DMA_PARK_PTR_RD_REF_SHIFT; + } else { + reg &= ~XILINX_DMA_PARK_PTR_WR_REF_MASK; + reg |= j << XILINX_DMA_PARK_PTR_WR_REF_SHIFT; } + dma_write(chan, XILINX_DMA_REG_PARK_PTR, reg); /* Start the hardware */ xilinx_dma_start(chan); @@ -1101,6 +1132,8 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan) if (chan->has_sg) { dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC, tail_segment->phys); + list_splice_tail_init(&chan->pending_list, &chan->active_list); + chan->desc_pendingcount = 0; } else { struct xilinx_vdma_tx_segment *segment, *last = NULL; int i = 0; @@ -1130,19 +1163,16 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan) vdma_desc_write(chan, XILINX_DMA_REG_FRMDLY_STRIDE, last->hw.stride); vdma_desc_write(chan, XILINX_DMA_REG_VSIZE, last->hw.vsize); - } - if (!chan->has_sg) { - list_del(&desc->node); - list_add_tail(&desc->node, &chan->active_list); chan->desc_submitcount++; chan->desc_pendingcount--; + list_del(&desc->node); + list_add_tail(&desc->node, &chan->active_list); if (chan->desc_submitcount == chan->num_frms) chan->desc_submitcount = 0; - } else { - list_splice_tail_init(&chan->pending_list, &chan->active_list); - chan->desc_pendingcount = 0; } + + chan->idle = false; } /** @@ -1158,6 +1188,9 @@ static void xilinx_cdma_start_transfer(struct xilinx_dma_chan *chan) if (chan->err) return; + if (!chan->idle) + return; + if (list_empty(&chan->pending_list)) return; @@ -1176,6 +1209,12 @@ static void xilinx_cdma_start_transfer(struct xilinx_dma_chan *chan) } if (chan->has_sg) { + dma_ctrl_clr(chan, XILINX_DMA_REG_DMACR, + XILINX_CDMA_CR_SGMODE); + + dma_ctrl_set(chan, XILINX_DMA_REG_DMACR, + XILINX_CDMA_CR_SGMODE); + xilinx_write(chan, XILINX_DMA_REG_CURDESC, head_desc->async_tx.phys); @@ -1203,6 +1242,7 @@ static void xilinx_cdma_start_transfer(struct xilinx_dma_chan *chan) list_splice_tail_init(&chan->pending_list, &chan->active_list); chan->desc_pendingcount = 0; + chan->idle = false; } /** @@ -1212,7 +1252,7 @@ static void xilinx_cdma_start_transfer(struct xilinx_dma_chan *chan) static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan) { struct xilinx_dma_tx_descriptor *head_desc, *tail_desc; - struct xilinx_axidma_tx_segment *tail_segment, *old_head, *new_head; + struct xilinx_axidma_tx_segment *tail_segment; u32 reg; if (chan->err) @@ -1221,12 +1261,8 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan) if (list_empty(&chan->pending_list)) return; - /* If it is SG mode and hardware is busy, cannot submit */ - if (chan->has_sg && xilinx_dma_is_running(chan) && - !xilinx_dma_is_idle(chan)) { - dev_dbg(chan->dev, "DMA controller still busy\n"); + if (!chan->idle) return; - } head_desc = list_first_entry(&chan->pending_list, struct xilinx_dma_tx_descriptor, node); @@ -1235,21 +1271,6 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan) tail_segment = list_last_entry(&tail_desc->segments, struct xilinx_axidma_tx_segment, node); - if (chan->has_sg && !chan->xdev->mcdma) { - old_head = list_first_entry(&head_desc->segments, - struct xilinx_axidma_tx_segment, node); - new_head = chan->seg_v; - /* Copy Buffer Descriptor fields. */ - new_head->hw = old_head->hw; - - /* Swap and save new reserve */ - list_replace_init(&old_head->node, &new_head->node); - chan->seg_v = old_head; - - tail_segment->hw.next_desc = chan->seg_v->phys; - head_desc->async_tx.phys = new_head->phys; - } - reg = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR); if (chan->desc_pendingcount <= XILINX_DMA_COALESCE_MAX) { @@ -1324,6 +1345,7 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan) list_splice_tail_init(&chan->pending_list, &chan->active_list); chan->desc_pendingcount = 0; + chan->idle = false; } /** @@ -1388,6 +1410,8 @@ static int xilinx_dma_reset(struct xilinx_dma_chan *chan) } chan->err = false; + chan->idle = true; + chan->desc_submitcount = 0; return err; } @@ -1469,6 +1493,7 @@ static irqreturn_t xilinx_dma_irq_handler(int irq, void *data) if (status & XILINX_DMA_DMASR_FRM_CNT_IRQ) { spin_lock(&chan->lock); xilinx_dma_complete_descriptor(chan); + chan->idle = true; chan->start_transfer(chan); spin_unlock(&chan->lock); } @@ -1591,7 +1616,7 @@ xilinx_vdma_dma_prep_interleaved(struct dma_chan *dchan, { struct xilinx_dma_chan *chan = to_xilinx_chan(dchan); struct xilinx_dma_tx_descriptor *desc; - struct xilinx_vdma_tx_segment *segment, *prev = NULL; + struct xilinx_vdma_tx_segment *segment; struct xilinx_vdma_desc_hw *hw; if (!is_slave_direction(xt->dir)) @@ -1645,8 +1670,6 @@ xilinx_vdma_dma_prep_interleaved(struct dma_chan *dchan, /* Insert the segment into the descriptor segments list. */ list_add_tail(&segment->node, &desc->segments); - prev = segment; - /* Link the last hardware descriptor with the first. */ segment = list_first_entry(&desc->segments, struct xilinx_vdma_tx_segment, node); @@ -1733,7 +1756,7 @@ static struct dma_async_tx_descriptor *xilinx_dma_prep_slave_sg( { struct xilinx_dma_chan *chan = to_xilinx_chan(dchan); struct xilinx_dma_tx_descriptor *desc; - struct xilinx_axidma_tx_segment *segment = NULL, *prev = NULL; + struct xilinx_axidma_tx_segment *segment = NULL; u32 *app_w = (u32 *)context; struct scatterlist *sg; size_t copy; @@ -1784,10 +1807,6 @@ static struct dma_async_tx_descriptor *xilinx_dma_prep_slave_sg( XILINX_DMA_NUM_APP_WORDS); } - if (prev) - prev->hw.next_desc = segment->phys; - - prev = segment; sg_used += copy; /* @@ -1801,7 +1820,6 @@ static struct dma_async_tx_descriptor *xilinx_dma_prep_slave_sg( segment = list_first_entry(&desc->segments, struct xilinx_axidma_tx_segment, node); desc->async_tx.phys = segment->phys; - prev->hw.next_desc = segment->phys; /* For the last DMA_MEM_TO_DEV transfer, set EOP */ if (chan->direction == DMA_MEM_TO_DEV) { @@ -1821,11 +1839,14 @@ error: /** * xilinx_dma_prep_dma_cyclic - prepare descriptors for a DMA_SLAVE transaction - * @chan: DMA channel - * @sgl: scatterlist to transfer to/from - * @sg_len: number of entries in @scatterlist + * @dchan: DMA channel + * @buf_addr: Physical address of the buffer + * @buf_len: Total length of the cyclic buffers + * @period_len: length of individual cyclic buffer * @direction: DMA direction * @flags: transfer ack flags + * + * Return: Async transaction descriptor on success and NULL on failure */ static struct dma_async_tx_descriptor *xilinx_dma_prep_dma_cyclic( struct dma_chan *dchan, dma_addr_t buf_addr, size_t buf_len, @@ -2009,7 +2030,9 @@ error: /** * xilinx_dma_terminate_all - Halt the channel and free descriptors - * @chan: Driver specific DMA Channel pointer + * @dchan: Driver specific DMA Channel pointer + * + * Return: '0' always. */ static int xilinx_dma_terminate_all(struct dma_chan *dchan) { @@ -2029,6 +2052,7 @@ static int xilinx_dma_terminate_all(struct dma_chan *dchan) /* Remove and free all of the descriptors in the lists */ xilinx_dma_free_descriptors(chan); + chan->idle = true; if (chan->cyclic) { reg = dma_ctrl_read(chan, XILINX_DMA_REG_DMACR); @@ -2037,6 +2061,10 @@ static int xilinx_dma_terminate_all(struct dma_chan *dchan) chan->cyclic = false; } + if ((chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) && chan->has_sg) + dma_ctrl_clr(chan, XILINX_DMA_REG_DMACR, + XILINX_CDMA_CR_SGMODE); + return 0; } @@ -2323,6 +2351,7 @@ static void xdma_disable_allclks(struct xilinx_dma_device *xdev) * * @xdev: Driver specific device structure * @node: Device node + * @chan_id: DMA Channel id * * Return: '0' on success and failure value on error */ @@ -2344,11 +2373,18 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev, chan->has_sg = xdev->has_sg; chan->desc_pendingcount = 0x0; chan->ext_addr = xdev->ext_addr; + /* This variable ensures that descriptors are not + * Submitted when dma engine is in progress. This variable is + * Added to avoid polling for a bit in the status register to + * Know dma state in the driver hot path. + */ + chan->idle = true; spin_lock_init(&chan->lock); INIT_LIST_HEAD(&chan->pending_list); INIT_LIST_HEAD(&chan->done_list); INIT_LIST_HEAD(&chan->active_list); + INIT_LIST_HEAD(&chan->free_seg_list); /* Retrieve the channel properties from the device tree */ has_dre = of_property_read_bool(node, "xlnx,include-dre"); @@ -2379,6 +2415,7 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev, chan->ctrl_offset = XILINX_DMA_MM2S_CTRL_OFFSET; if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) { chan->desc_offset = XILINX_VDMA_MM2S_DESC_OFFSET; + chan->config.park = 1; if (xdev->flush_on_fsync == XILINX_DMA_FLUSH_BOTH || xdev->flush_on_fsync == XILINX_DMA_FLUSH_MM2S) @@ -2395,6 +2432,7 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev, chan->ctrl_offset = XILINX_DMA_S2MM_CTRL_OFFSET; if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) { chan->desc_offset = XILINX_VDMA_S2MM_DESC_OFFSET; + chan->config.park = 1; if (xdev->flush_on_fsync == XILINX_DMA_FLUSH_BOTH || xdev->flush_on_fsync == XILINX_DMA_FLUSH_S2MM) @@ -2459,7 +2497,8 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev, * Return: 0 always. */ static int xilinx_dma_child_probe(struct xilinx_dma_device *xdev, - struct device_node *node) { + struct device_node *node) +{ int ret, i, nr_channels = 1; ret = of_property_read_u32(node, "dma-channels", &nr_channels); @@ -2654,7 +2693,12 @@ static int xilinx_dma_probe(struct platform_device *pdev) goto error; } - dev_info(&pdev->dev, "Xilinx AXI VDMA Engine Driver Probed!!\n"); + if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) + dev_info(&pdev->dev, "Xilinx AXI DMA Engine Driver Probed!!\n"); + else if (xdev->dma_config->dmatype == XDMA_TYPE_CDMA) + dev_info(&pdev->dev, "Xilinx AXI CDMA Engine Driver Probed!!\n"); + else + dev_info(&pdev->dev, "Xilinx AXI VDMA Engine Driver Probed!!\n"); return 0; diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c index 1ee1241ca797..f14645817ed8 100644 --- a/drivers/dma/xilinx/zynqmp_dma.c +++ b/drivers/dma/xilinx/zynqmp_dma.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "../dmaengine.h" @@ -47,6 +48,7 @@ #define ZYNQMP_DMA_SRC_START_MSB 0x15C #define ZYNQMP_DMA_DST_START_LSB 0x160 #define ZYNQMP_DMA_DST_START_MSB 0x164 +#define ZYNQMP_DMA_TOTAL_BYTE 0x188 #define ZYNQMP_DMA_RATE_CTRL 0x18C #define ZYNQMP_DMA_IRQ_SRC_ACCT 0x190 #define ZYNQMP_DMA_IRQ_DST_ACCT 0x194 @@ -138,6 +140,8 @@ #define ZYNQMP_DMA_BUS_WIDTH_64 64 #define ZYNQMP_DMA_BUS_WIDTH_128 128 +#define ZDMA_PM_TIMEOUT 100 + #define ZYNQMP_DMA_DESC_SIZE(chan) (chan->desc_size) #define to_chan(chan) container_of(chan, struct zynqmp_dma_chan, \ @@ -211,8 +215,6 @@ struct zynqmp_dma_desc_sw { * @bus_width: Bus width * @src_burst_len: Source burst length * @dst_burst_len: Dest burst length - * @clk_main: Pointer to main clock - * @clk_apb: Pointer to apb clock */ struct zynqmp_dma_chan { struct zynqmp_dma_device *zdev; @@ -237,8 +239,6 @@ struct zynqmp_dma_chan { u32 bus_width; u32 src_burst_len; u32 dst_burst_len; - struct clk *clk_main; - struct clk *clk_apb; }; /** @@ -246,11 +246,15 @@ struct zynqmp_dma_chan { * @dev: Device Structure * @common: DMA device structure * @chan: Driver specific DMA channel + * @clk_main: Pointer to main clock + * @clk_apb: Pointer to apb clock */ struct zynqmp_dma_device { struct device *dev; struct dma_device common; struct zynqmp_dma_chan *chan; + struct clk *clk_main; + struct clk *clk_apb; }; static inline void zynqmp_dma_writeq(struct zynqmp_dma_chan *chan, u32 reg, @@ -461,7 +465,11 @@ static int zynqmp_dma_alloc_chan_resources(struct dma_chan *dchan) { struct zynqmp_dma_chan *chan = to_chan(dchan); struct zynqmp_dma_desc_sw *desc; - int i; + int i, ret; + + ret = pm_runtime_get_sync(chan->dev); + if (ret < 0) + return ret; chan->sw_desc_pool = kzalloc(sizeof(*desc) * ZYNQMP_DMA_NUM_DESCS, GFP_KERNEL); @@ -506,6 +514,7 @@ static int zynqmp_dma_alloc_chan_resources(struct dma_chan *dchan) static void zynqmp_dma_start(struct zynqmp_dma_chan *chan) { writel(ZYNQMP_DMA_INT_EN_DEFAULT_MASK, chan->regs + ZYNQMP_DMA_IER); + writel(0, chan->regs + ZYNQMP_DMA_TOTAL_BYTE); chan->idle = false; writel(ZYNQMP_DMA_ENABLE, chan->regs + ZYNQMP_DMA_CTRL2); } @@ -517,12 +526,12 @@ static void zynqmp_dma_start(struct zynqmp_dma_chan *chan) */ static void zynqmp_dma_handle_ovfl_int(struct zynqmp_dma_chan *chan, u32 status) { - u32 val; - + if (status & ZYNQMP_DMA_BYTE_CNT_OVRFL) + writel(0, chan->regs + ZYNQMP_DMA_TOTAL_BYTE); if (status & ZYNQMP_DMA_IRQ_DST_ACCT_ERR) - val = readl(chan->regs + ZYNQMP_DMA_IRQ_DST_ACCT); + readl(chan->regs + ZYNQMP_DMA_IRQ_DST_ACCT); if (status & ZYNQMP_DMA_IRQ_SRC_ACCT_ERR) - val = readl(chan->regs + ZYNQMP_DMA_IRQ_SRC_ACCT); + readl(chan->regs + ZYNQMP_DMA_IRQ_SRC_ACCT); } static void zynqmp_dma_config(struct zynqmp_dma_chan *chan) @@ -545,6 +554,8 @@ static void zynqmp_dma_config(struct zynqmp_dma_chan *chan) * zynqmp_dma_device_config - Zynqmp dma device configuration * @dchan: DMA channel * @config: DMA device config + * + * Return: 0 always */ static int zynqmp_dma_device_config(struct dma_chan *dchan, struct dma_slave_config *config) @@ -640,7 +651,7 @@ static void zynqmp_dma_issue_pending(struct dma_chan *dchan) /** * zynqmp_dma_free_descriptors - Free channel descriptors - * @dchan: DMA channel pointer + * @chan: ZynqMP DMA channel pointer */ static void zynqmp_dma_free_descriptors(struct zynqmp_dma_chan *chan) { @@ -664,6 +675,8 @@ static void zynqmp_dma_free_chan_resources(struct dma_chan *dchan) (2 * ZYNQMP_DMA_DESC_SIZE(chan) * ZYNQMP_DMA_NUM_DESCS), chan->desc_pool_v, chan->desc_pool_p); kfree(chan->sw_desc_pool); + pm_runtime_mark_last_busy(chan->dev); + pm_runtime_put_autosuspend(chan->dev); } /** @@ -715,7 +728,7 @@ static irqreturn_t zynqmp_dma_irq_handler(int irq, void *data) if (status & ZYNQMP_DMA_INT_OVRFL) { zynqmp_dma_handle_ovfl_int(chan, status); - dev_info(chan->dev, "Channel %p overflow interrupt\n", chan); + dev_dbg(chan->dev, "Channel %p overflow interrupt\n", chan); ret = IRQ_HANDLED; } @@ -838,11 +851,10 @@ static void zynqmp_dma_chan_remove(struct zynqmp_dma_chan *chan) if (!chan) return; - devm_free_irq(chan->zdev->dev, chan->irq, chan); + if (chan->irq) + devm_free_irq(chan->zdev->dev, chan->irq, chan); tasklet_kill(&chan->tasklet); list_del(&chan->common.device_node); - clk_disable_unprepare(chan->clk_apb); - clk_disable_unprepare(chan->clk_main); } /** @@ -907,30 +919,6 @@ static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev, "zynqmp-dma", chan); if (err) return err; - chan->clk_main = devm_clk_get(&pdev->dev, "clk_main"); - if (IS_ERR(chan->clk_main)) { - dev_err(&pdev->dev, "main clock not found.\n"); - return PTR_ERR(chan->clk_main); - } - - chan->clk_apb = devm_clk_get(&pdev->dev, "clk_apb"); - if (IS_ERR(chan->clk_apb)) { - dev_err(&pdev->dev, "apb clock not found.\n"); - return PTR_ERR(chan->clk_apb); - } - - err = clk_prepare_enable(chan->clk_main); - if (err) { - dev_err(&pdev->dev, "Unable to enable main clock.\n"); - return err; - } - - err = clk_prepare_enable(chan->clk_apb); - if (err) { - clk_disable_unprepare(chan->clk_main); - dev_err(&pdev->dev, "Unable to enable apb clock.\n"); - return err; - } chan->desc_size = sizeof(struct zynqmp_dma_desc_ll); chan->idle = true; @@ -952,6 +940,87 @@ static struct dma_chan *of_zynqmp_dma_xlate(struct of_phandle_args *dma_spec, return dma_get_slave_channel(&zdev->chan->common); } +/** + * zynqmp_dma_suspend - Suspend method for the driver + * @dev: Address of the device structure + * + * Put the driver into low power mode. + * Return: 0 on success and failure value on error + */ +static int __maybe_unused zynqmp_dma_suspend(struct device *dev) +{ + if (!device_may_wakeup(dev)) + return pm_runtime_force_suspend(dev); + + return 0; +} + +/** + * zynqmp_dma_resume - Resume from suspend + * @dev: Address of the device structure + * + * Resume operation after suspend. + * Return: 0 on success and failure value on error + */ +static int __maybe_unused zynqmp_dma_resume(struct device *dev) +{ + if (!device_may_wakeup(dev)) + return pm_runtime_force_resume(dev); + + return 0; +} + +/** + * zynqmp_dma_runtime_suspend - Runtime suspend method for the driver + * @dev: Address of the device structure + * + * Put the driver into low power mode. + * Return: 0 always + */ +static int __maybe_unused zynqmp_dma_runtime_suspend(struct device *dev) +{ + struct zynqmp_dma_device *zdev = dev_get_drvdata(dev); + + clk_disable_unprepare(zdev->clk_main); + clk_disable_unprepare(zdev->clk_apb); + + return 0; +} + +/** + * zynqmp_dma_runtime_resume - Runtime suspend method for the driver + * @dev: Address of the device structure + * + * Put the driver into low power mode. + * Return: 0 always + */ +static int __maybe_unused zynqmp_dma_runtime_resume(struct device *dev) +{ + struct zynqmp_dma_device *zdev = dev_get_drvdata(dev); + int err; + + err = clk_prepare_enable(zdev->clk_main); + if (err) { + dev_err(dev, "Unable to enable main clock.\n"); + return err; + } + + err = clk_prepare_enable(zdev->clk_apb); + if (err) { + dev_err(dev, "Unable to enable apb clock.\n"); + clk_disable_unprepare(zdev->clk_main); + return err; + } + + return 0; +} + +static const struct dev_pm_ops zynqmp_dma_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(zynqmp_dma_suspend, zynqmp_dma_resume) + SET_RUNTIME_PM_OPS(zynqmp_dma_runtime_suspend, + zynqmp_dma_runtime_resume, NULL) +}; + /** * zynqmp_dma_probe - Driver probe function * @pdev: Pointer to the platform_device structure @@ -984,12 +1053,33 @@ static int zynqmp_dma_probe(struct platform_device *pdev) p->device_config = zynqmp_dma_device_config; p->dev = &pdev->dev; + zdev->clk_main = devm_clk_get(&pdev->dev, "clk_main"); + if (IS_ERR(zdev->clk_main)) { + dev_err(&pdev->dev, "main clock not found.\n"); + return PTR_ERR(zdev->clk_main); + } + + zdev->clk_apb = devm_clk_get(&pdev->dev, "clk_apb"); + if (IS_ERR(zdev->clk_apb)) { + dev_err(&pdev->dev, "apb clock not found.\n"); + return PTR_ERR(zdev->clk_apb); + } + platform_set_drvdata(pdev, zdev); + pm_runtime_set_autosuspend_delay(zdev->dev, ZDMA_PM_TIMEOUT); + pm_runtime_use_autosuspend(zdev->dev); + pm_runtime_enable(zdev->dev); + pm_runtime_get_sync(zdev->dev); + if (!pm_runtime_enabled(zdev->dev)) { + ret = zynqmp_dma_runtime_resume(zdev->dev); + if (ret) + return ret; + } ret = zynqmp_dma_chan_probe(zdev, pdev); if (ret) { dev_err(&pdev->dev, "Probing channel failed\n"); - goto free_chan_resources; + goto err_disable_pm; } p->dst_addr_widths = BIT(zdev->chan->bus_width / 8); @@ -1005,12 +1095,19 @@ static int zynqmp_dma_probe(struct platform_device *pdev) goto free_chan_resources; } + pm_runtime_mark_last_busy(zdev->dev); + pm_runtime_put_sync_autosuspend(zdev->dev); + dev_info(&pdev->dev, "ZynqMP DMA driver Probe success\n"); return 0; free_chan_resources: zynqmp_dma_chan_remove(zdev->chan); +err_disable_pm: + if (!pm_runtime_enabled(zdev->dev)) + zynqmp_dma_runtime_suspend(zdev->dev); + pm_runtime_disable(zdev->dev); return ret; } @@ -1028,6 +1125,9 @@ static int zynqmp_dma_remove(struct platform_device *pdev) dma_async_device_unregister(&zdev->common); zynqmp_dma_chan_remove(zdev->chan); + pm_runtime_disable(zdev->dev); + if (!pm_runtime_enabled(zdev->dev)) + zynqmp_dma_runtime_suspend(zdev->dev); return 0; } @@ -1042,6 +1142,7 @@ static struct platform_driver zynqmp_dma_driver = { .driver = { .name = "xilinx-zynqmp-dma", .of_match_table = zynqmp_dma_of_match, + .pm = &zynqmp_dma_dev_pm_ops, }, .probe = zynqmp_dma_probe, .remove = zynqmp_dma_remove, diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 96afb2aeed18..3c4017007647 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -457,4 +457,11 @@ config EDAC_XGENE Support for error detection and correction on the APM X-Gene family of SOCs. +config EDAC_TI + tristate "Texas Instruments DDR3 ECC Controller" + depends on ARCH_KEYSTONE || SOC_DRA7XX + help + Support for error detection and correction on the + TI SoCs. + endif # EDAC diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 0fd9ffa63299..b54912eb39af 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -78,3 +78,4 @@ obj-$(CONFIG_EDAC_THUNDERX) += thunderx_edac.o obj-$(CONFIG_EDAC_ALTERA) += altera_edac.o obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o +obj-$(CONFIG_EDAC_TI) += ti_edac.o diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c index ec5d695bbb72..3c68bb525d5d 100644 --- a/drivers/edac/mv64x60_edac.c +++ b/drivers/edac/mv64x60_edac.c @@ -758,7 +758,7 @@ static int mv64x60_mc_err_probe(struct platform_device *pdev) /* Non-ECC RAM? */ printk(KERN_WARNING "%s: No ECC DIMMs discovered\n", __func__); res = -ENODEV; - goto err2; + goto err; } edac_dbg(3, "init mci\n"); diff --git a/drivers/edac/octeon_edac-lmc.c b/drivers/edac/octeon_edac-lmc.c index 9c1ffe3e912b..aeb222ca3ed1 100644 --- a/drivers/edac/octeon_edac-lmc.c +++ b/drivers/edac/octeon_edac-lmc.c @@ -78,6 +78,7 @@ static void octeon_lmc_edac_poll_o2(struct mem_ctl_info *mci) if (!pvt->inject) int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx)); else { + int_reg.u64 = 0; if (pvt->error_type == 1) int_reg.s.sec_err = 1; if (pvt->error_type == 2) diff --git a/drivers/edac/ti_edac.c b/drivers/edac/ti_edac.c new file mode 100644 index 000000000000..6ac26d1b929f --- /dev/null +++ b/drivers/edac/ti_edac.c @@ -0,0 +1,341 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ + * + * Texas Instruments DDR3 ECC error correction and detection driver + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "edac_module.h" + +/* EMIF controller registers */ +#define EMIF_SDRAM_CONFIG 0x008 +#define EMIF_IRQ_STATUS 0x0ac +#define EMIF_IRQ_ENABLE_SET 0x0b4 +#define EMIF_ECC_CTRL 0x110 +#define EMIF_1B_ECC_ERR_CNT 0x130 +#define EMIF_1B_ECC_ERR_THRSH 0x134 +#define EMIF_1B_ECC_ERR_ADDR_LOG 0x13c +#define EMIF_2B_ECC_ERR_ADDR_LOG 0x140 + +/* Bit definitions for EMIF_SDRAM_CONFIG */ +#define SDRAM_TYPE_SHIFT 29 +#define SDRAM_TYPE_MASK GENMASK(31, 29) +#define SDRAM_TYPE_DDR3 (3 << SDRAM_TYPE_SHIFT) +#define SDRAM_TYPE_DDR2 (2 << SDRAM_TYPE_SHIFT) +#define SDRAM_NARROW_MODE_MASK GENMASK(15, 14) +#define SDRAM_K2_NARROW_MODE_SHIFT 12 +#define SDRAM_K2_NARROW_MODE_MASK GENMASK(13, 12) +#define SDRAM_ROWSIZE_SHIFT 7 +#define SDRAM_ROWSIZE_MASK GENMASK(9, 7) +#define SDRAM_IBANK_SHIFT 4 +#define SDRAM_IBANK_MASK GENMASK(6, 4) +#define SDRAM_K2_IBANK_SHIFT 5 +#define SDRAM_K2_IBANK_MASK GENMASK(6, 5) +#define SDRAM_K2_EBANK_SHIFT 3 +#define SDRAM_K2_EBANK_MASK BIT(SDRAM_K2_EBANK_SHIFT) +#define SDRAM_PAGESIZE_SHIFT 0 +#define SDRAM_PAGESIZE_MASK GENMASK(2, 0) +#define SDRAM_K2_PAGESIZE_SHIFT 0 +#define SDRAM_K2_PAGESIZE_MASK GENMASK(1, 0) + +#define EMIF_1B_ECC_ERR_THRSH_SHIFT 24 + +/* IRQ bit definitions */ +#define EMIF_1B_ECC_ERR BIT(5) +#define EMIF_2B_ECC_ERR BIT(4) +#define EMIF_WR_ECC_ERR BIT(3) +#define EMIF_SYS_ERR BIT(0) +/* Bit 31 enables ECC and 28 enables RMW */ +#define ECC_ENABLED (BIT(31) | BIT(28)) + +#define EDAC_MOD_NAME "ti-emif-edac" + +enum { + EMIF_TYPE_DRA7, + EMIF_TYPE_K2 +}; + +struct ti_edac { + void __iomem *reg; +}; + +static u32 ti_edac_readl(struct ti_edac *edac, u16 offset) +{ + return readl_relaxed(edac->reg + offset); +} + +static void ti_edac_writel(struct ti_edac *edac, u32 val, u16 offset) +{ + writel_relaxed(val, edac->reg + offset); +} + +static irqreturn_t ti_edac_isr(int irq, void *data) +{ + struct mem_ctl_info *mci = data; + struct ti_edac *edac = mci->pvt_info; + u32 irq_status; + u32 err_addr; + int err_count; + + irq_status = ti_edac_readl(edac, EMIF_IRQ_STATUS); + + if (irq_status & EMIF_1B_ECC_ERR) { + err_addr = ti_edac_readl(edac, EMIF_1B_ECC_ERR_ADDR_LOG); + err_count = ti_edac_readl(edac, EMIF_1B_ECC_ERR_CNT); + ti_edac_writel(edac, err_count, EMIF_1B_ECC_ERR_CNT); + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, err_count, + err_addr >> PAGE_SHIFT, + err_addr & ~PAGE_MASK, -1, 0, 0, 0, + mci->ctl_name, "1B"); + } + + if (irq_status & EMIF_2B_ECC_ERR) { + err_addr = ti_edac_readl(edac, EMIF_2B_ECC_ERR_ADDR_LOG); + edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, + err_addr >> PAGE_SHIFT, + err_addr & ~PAGE_MASK, -1, 0, 0, 0, + mci->ctl_name, "2B"); + } + + if (irq_status & EMIF_WR_ECC_ERR) + edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, + 0, 0, -1, 0, 0, 0, + mci->ctl_name, "WR"); + + ti_edac_writel(edac, irq_status, EMIF_IRQ_STATUS); + + return IRQ_HANDLED; +} + +static void ti_edac_setup_dimm(struct mem_ctl_info *mci, u32 type) +{ + struct dimm_info *dimm; + struct ti_edac *edac = mci->pvt_info; + int bits; + u32 val; + u32 memsize; + + dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers, 0, 0, 0); + + val = ti_edac_readl(edac, EMIF_SDRAM_CONFIG); + + if (type == EMIF_TYPE_DRA7) { + bits = ((val & SDRAM_PAGESIZE_MASK) >> SDRAM_PAGESIZE_SHIFT) + 8; + bits += ((val & SDRAM_ROWSIZE_MASK) >> SDRAM_ROWSIZE_SHIFT) + 9; + bits += (val & SDRAM_IBANK_MASK) >> SDRAM_IBANK_SHIFT; + + if (val & SDRAM_NARROW_MODE_MASK) { + bits++; + dimm->dtype = DEV_X16; + } else { + bits += 2; + dimm->dtype = DEV_X32; + } + } else { + bits = 16; + bits += ((val & SDRAM_K2_PAGESIZE_MASK) >> + SDRAM_K2_PAGESIZE_SHIFT) + 8; + bits += (val & SDRAM_K2_IBANK_MASK) >> SDRAM_K2_IBANK_SHIFT; + bits += (val & SDRAM_K2_EBANK_MASK) >> SDRAM_K2_EBANK_SHIFT; + + val = (val & SDRAM_K2_NARROW_MODE_MASK) >> + SDRAM_K2_NARROW_MODE_SHIFT; + switch (val) { + case 0: + bits += 3; + dimm->dtype = DEV_X64; + break; + case 1: + bits += 2; + dimm->dtype = DEV_X32; + break; + case 2: + bits++; + dimm->dtype = DEV_X16; + break; + } + } + + memsize = 1 << bits; + + dimm->nr_pages = memsize >> PAGE_SHIFT; + dimm->grain = 4; + if ((val & SDRAM_TYPE_MASK) == SDRAM_TYPE_DDR2) + dimm->mtype = MEM_DDR2; + else + dimm->mtype = MEM_DDR3; + + val = ti_edac_readl(edac, EMIF_ECC_CTRL); + if (val & ECC_ENABLED) + dimm->edac_mode = EDAC_SECDED; + else + dimm->edac_mode = EDAC_NONE; +} + +static const struct of_device_id ti_edac_of_match[] = { + { .compatible = "ti,emif-keystone", .data = (void *)EMIF_TYPE_K2 }, + { .compatible = "ti,emif-dra7xx", .data = (void *)EMIF_TYPE_DRA7 }, + {}, +}; + +static int _emif_get_id(struct device_node *node) +{ + struct device_node *np; + const __be32 *addrp; + u32 addr, my_addr; + int my_id = 0; + + addrp = of_get_address(node, 0, NULL, NULL); + my_addr = (u32)of_translate_address(node, addrp); + + for_each_matching_node(np, ti_edac_of_match) { + if (np == node) + continue; + + addrp = of_get_address(np, 0, NULL, NULL); + addr = (u32)of_translate_address(np, addrp); + + edac_printk(KERN_INFO, EDAC_MOD_NAME, + "addr=%x, my_addr=%x\n", + addr, my_addr); + + if (addr < my_addr) + my_id++; + } + + return my_id; +} + +static int ti_edac_probe(struct platform_device *pdev) +{ + int error_irq = 0, ret = -ENODEV; + struct device *dev = &pdev->dev; + struct resource *res; + void __iomem *reg; + struct mem_ctl_info *mci; + struct edac_mc_layer layers[1]; + const struct of_device_id *id; + struct ti_edac *edac; + int emif_id; + + id = of_match_device(ti_edac_of_match, &pdev->dev); + if (!id) + return -ENODEV; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg = devm_ioremap_resource(dev, res); + if (IS_ERR(reg)) { + edac_printk(KERN_ERR, EDAC_MOD_NAME, + "EMIF controller regs not defined\n"); + return PTR_ERR(reg); + } + + layers[0].type = EDAC_MC_LAYER_ALL_MEM; + layers[0].size = 1; + + /* Allocate ID number for our EMIF controller */ + emif_id = _emif_get_id(pdev->dev.of_node); + if (emif_id < 0) + return -EINVAL; + + mci = edac_mc_alloc(emif_id, 1, layers, sizeof(*edac)); + if (!mci) + return -ENOMEM; + + mci->pdev = &pdev->dev; + edac = mci->pvt_info; + edac->reg = reg; + platform_set_drvdata(pdev, mci); + + mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR2; + mci->edac_ctl_cap = EDAC_FLAG_SECDED | EDAC_FLAG_NONE; + mci->mod_name = EDAC_MOD_NAME; + mci->ctl_name = id->compatible; + mci->dev_name = dev_name(&pdev->dev); + + /* Setup memory layout */ + ti_edac_setup_dimm(mci, (u32)(id->data)); + + /* add EMIF ECC error handler */ + error_irq = platform_get_irq(pdev, 0); + if (!error_irq) { + edac_printk(KERN_ERR, EDAC_MOD_NAME, + "EMIF irq number not defined.\n"); + goto err; + } + + ret = devm_request_irq(dev, error_irq, ti_edac_isr, 0, + "emif-edac-irq", mci); + if (ret) { + edac_printk(KERN_ERR, EDAC_MOD_NAME, + "request_irq fail for EMIF EDAC irq\n"); + goto err; + } + + ret = edac_mc_add_mc(mci); + if (ret) { + edac_printk(KERN_ERR, EDAC_MOD_NAME, + "Failed to register mci: %d.\n", ret); + goto err; + } + + /* Generate an interrupt with each 1b error */ + ti_edac_writel(edac, 1 << EMIF_1B_ECC_ERR_THRSH_SHIFT, + EMIF_1B_ECC_ERR_THRSH); + + /* Enable interrupts */ + ti_edac_writel(edac, + EMIF_1B_ECC_ERR | EMIF_2B_ECC_ERR | EMIF_WR_ECC_ERR, + EMIF_IRQ_ENABLE_SET); + + return 0; + +err: + edac_mc_free(mci); + return ret; +} + +static int ti_edac_remove(struct platform_device *pdev) +{ + struct mem_ctl_info *mci = platform_get_drvdata(pdev); + + edac_mc_del_mc(&pdev->dev); + edac_mc_free(mci); + + return 0; +} + +static struct platform_driver ti_edac_driver = { + .probe = ti_edac_probe, + .remove = ti_edac_remove, + .driver = { + .name = EDAC_MOD_NAME, + .of_match_table = ti_edac_of_match, + }, +}; + +module_platform_driver(ti_edac_driver); + +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_DESCRIPTION("EDAC Driver for Texas Instruments DDR3 MC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c index 612afeaec3cb..1e8062f6dbfc 100644 --- a/drivers/eisa/eisa-bus.c +++ b/drivers/eisa/eisa-bus.c @@ -75,9 +75,9 @@ static void __init eisa_name_device(struct eisa_device *edev) static char __init *decode_eisa_sig(unsigned long addr) { - static char sig_str[EISA_SIG_LEN]; + static char sig_str[EISA_SIG_LEN]; u8 sig[4]; - u16 rev; + u16 rev; int i; for (i = 0; i < 4; i++) { @@ -96,14 +96,14 @@ static char __init *decode_eisa_sig(unsigned long addr) if (!i && (sig[0] & 0x80)) return NULL; } - - sig_str[0] = ((sig[0] >> 2) & 0x1f) + ('A' - 1); - sig_str[1] = (((sig[0] & 3) << 3) | (sig[1] >> 5)) + ('A' - 1); - sig_str[2] = (sig[1] & 0x1f) + ('A' - 1); - rev = (sig[2] << 8) | sig[3]; - sprintf(sig_str + 3, "%04X", rev); - return sig_str; + sig_str[0] = ((sig[0] >> 2) & 0x1f) + ('A' - 1); + sig_str[1] = (((sig[0] & 3) << 3) | (sig[1] >> 5)) + ('A' - 1); + sig_str[2] = (sig[1] & 0x1f) + ('A' - 1); + rev = (sig[2] << 8) | sig[3]; + sprintf(sig_str + 3, "%04X", rev); + + return sig_str; } static int eisa_bus_match(struct device *dev, struct device_driver *drv) @@ -198,7 +198,7 @@ static int __init eisa_init_device(struct eisa_root_device *root, sig = decode_eisa_sig(sig_addr); if (!sig) return -1; /* No EISA device here */ - + memcpy(edev->id.sig, sig, EISA_SIG_LEN); edev->slot = slot; edev->state = inb(SLOT_ADDRESS(root, slot) + EISA_CONFIG_OFFSET) @@ -222,7 +222,7 @@ static int __init eisa_init_device(struct eisa_root_device *root, if (is_forced_dev(enable_dev, enable_dev_count, root, edev)) edev->state = EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED; - + if (is_forced_dev(disable_dev, disable_dev_count, root, edev)) edev->state = EISA_CONFIG_FORCED; @@ -275,7 +275,7 @@ static int __init eisa_request_resources(struct eisa_root_device *root, edev->res[i].start = edev->res[i].end = 0; continue; } - + if (slot) { edev->res[i].name = NULL; edev->res[i].start = SLOT_ADDRESS(root, slot) @@ -295,7 +295,7 @@ static int __init eisa_request_resources(struct eisa_root_device *root, } return 0; - + failed: while (--i >= 0) release_resource(&edev->res[i]); @@ -314,7 +314,7 @@ static void __init eisa_release_resources(struct eisa_device *edev) static int __init eisa_probe(struct eisa_root_device *root) { - int i, c; + int i, c; struct eisa_device *edev; char *enabled_str; @@ -322,16 +322,14 @@ static int __init eisa_probe(struct eisa_root_device *root) /* First try to get hold of slot 0. If there is no device * here, simply fail, unless root->force_probe is set. */ - + edev = kzalloc(sizeof(*edev), GFP_KERNEL); - if (!edev) { - dev_err(root->dev, "EISA: Couldn't allocate mainboard slot\n"); + if (!edev) return -ENOMEM; - } - + if (eisa_request_resources(root, edev, 0)) { dev_warn(root->dev, - "EISA: Cannot allocate resource for mainboard\n"); + "EISA: Cannot allocate resource for mainboard\n"); kfree(edev); if (!root->force_probe) return -EBUSY; @@ -350,14 +348,14 @@ static int __init eisa_probe(struct eisa_root_device *root) if (eisa_register_device(edev)) { dev_err(&edev->dev, "EISA: Failed to register %s\n", - edev->id.sig); + edev->id.sig); eisa_release_resources(edev); kfree(edev); } - + force_probe: - - for (c = 0, i = 1; i <= root->slots; i++) { + + for (c = 0, i = 1; i <= root->slots; i++) { edev = kzalloc(sizeof(*edev), GFP_KERNEL); if (!edev) { dev_err(root->dev, "EISA: Out of memory for slot %d\n", @@ -367,8 +365,8 @@ static int __init eisa_probe(struct eisa_root_device *root) if (eisa_request_resources(root, edev, i)) { dev_warn(root->dev, - "Cannot allocate resource for EISA slot %d\n", - i); + "Cannot allocate resource for EISA slot %d\n", + i); kfree(edev); continue; } @@ -395,11 +393,11 @@ static int __init eisa_probe(struct eisa_root_device *root) if (eisa_register_device(edev)) { dev_err(&edev->dev, "EISA: Failed to register %s\n", - edev->id.sig); + edev->id.sig); eisa_release_resources(edev); kfree(edev); } - } + } dev_info(root->dev, "EISA: Detected %d card%s\n", c, c == 1 ? "" : "s"); return 0; @@ -422,7 +420,7 @@ int __init eisa_root_register(struct eisa_root_device *root) * been already registered. This prevents the virtual root * device from registering after the real one has, for * example... */ - + root->eisa_root_res.name = eisa_root_res.name; root->eisa_root_res.start = root->res->start; root->eisa_root_res.end = root->res->end; @@ -431,7 +429,7 @@ int __init eisa_root_register(struct eisa_root_device *root) err = request_resource(&eisa_root_res, &root->eisa_root_res); if (err) return err; - + root->bus_nr = eisa_bus_count++; err = eisa_probe(root); @@ -444,7 +442,7 @@ int __init eisa_root_register(struct eisa_root_device *root) static int __init eisa_init(void) { int r; - + r = bus_register(&eisa_bus_type); if (r) return r; diff --git a/drivers/eisa/pci_eisa.c b/drivers/eisa/pci_eisa.c index a333bf3517de..b5f367b44413 100644 --- a/drivers/eisa/pci_eisa.c +++ b/drivers/eisa/pci_eisa.c @@ -50,11 +50,11 @@ static int __init pci_eisa_init(struct pci_dev *pdev) return -1; } - pci_eisa_root.dev = &pdev->dev; - pci_eisa_root.res = bus_res; - pci_eisa_root.bus_base_addr = bus_res->start; - pci_eisa_root.slots = EISA_MAX_SLOTS; - pci_eisa_root.dma_mask = pdev->dma_mask; + pci_eisa_root.dev = &pdev->dev; + pci_eisa_root.res = bus_res; + pci_eisa_root.bus_base_addr = bus_res->start; + pci_eisa_root.slots = EISA_MAX_SLOTS; + pci_eisa_root.dma_mask = pdev->dma_mask; dev_set_drvdata(pci_eisa_root.dev, &pci_eisa_root); if (eisa_root_register (&pci_eisa_root)) { diff --git a/drivers/eisa/virtual_root.c b/drivers/eisa/virtual_root.c index 535e4f9c83f4..f1221c1d6319 100644 --- a/drivers/eisa/virtual_root.c +++ b/drivers/eisa/virtual_root.c @@ -35,11 +35,11 @@ static struct platform_device eisa_root_dev = { }; static struct eisa_root_device eisa_bus_root = { - .dev = &eisa_root_dev.dev, - .bus_base_addr = 0, - .res = &ioport_resource, - .slots = EISA_MAX_SLOTS, - .dma_mask = 0xffffffff, + .dev = &eisa_root_dev.dev, + .bus_base_addr = 0, + .res = &ioport_resource, + .slots = EISA_MAX_SLOTS, + .dma_mask = 0xffffffff, }; static void virtual_eisa_release (struct device *dev) @@ -50,13 +50,12 @@ static void virtual_eisa_release (struct device *dev) static int __init virtual_eisa_root_init (void) { int r; - - if ((r = platform_device_register (&eisa_root_dev))) { - return r; - } + + if ((r = platform_device_register (&eisa_root_dev))) + return r; eisa_bus_root.force_probe = force_probe; - + dev_set_drvdata(&eisa_root_dev.dev, &eisa_bus_root); if (eisa_root_register (&eisa_bus_root)) { diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index 3877d86c746a..18026354c332 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -144,7 +144,7 @@ static int adc_jack_probe(struct platform_device *pdev) return err; data->irq = platform_get_irq(pdev, 0); - if (!data->irq) { + if (data->irq < 0) { dev_err(&pdev->dev, "platform_get_irq failed\n"); return -ENODEV; } diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c index 981fba56bc18..0a44d43802fe 100644 --- a/drivers/extcon/extcon-axp288.c +++ b/drivers/extcon/extcon-axp288.c @@ -1,6 +1,7 @@ /* * extcon-axp288.c - X-Power AXP288 PMIC extcon cable detection driver * + * Copyright (C) 2016-2017 Hans de Goede * Copyright (C) 2015 Intel Corporation * Author: Ramakrishna Pallala * @@ -24,8 +25,6 @@ #include #include #include -#include -#include #include /* Power source status register */ @@ -79,11 +78,6 @@ enum axp288_extcon_reg { AXP288_BC_DET_STAT_REG = 0x2f, }; -enum axp288_mux_select { - EXTCON_GPIO_MUX_SEL_PMIC = 0, - EXTCON_GPIO_MUX_SEL_SOC, -}; - enum axp288_extcon_irq { VBUS_FALLING_IRQ = 0, VBUS_RISING_IRQ, @@ -104,11 +98,11 @@ struct axp288_extcon_info { struct device *dev; struct regmap *regmap; struct regmap_irq_chip_data *regmap_irqc; - struct gpio_desc *gpio_mux_cntl; + struct delayed_work det_work; int irq[EXTCON_IRQ_END]; struct extcon_dev *edev; - struct notifier_block extcon_nb; unsigned int previous_cable; + bool first_detect_done; }; /* Power up/down reason string array */ @@ -146,6 +140,25 @@ static void axp288_extcon_log_rsi(struct axp288_extcon_info *info) regmap_write(info->regmap, AXP288_PS_BOOT_REASON_REG, clear_mask); } +static void axp288_chrg_detect_complete(struct axp288_extcon_info *info) +{ + /* + * We depend on other drivers to do things like mux the data lines, + * enable/disable vbus based on the id-pin, etc. Sometimes the BIOS has + * not set these things up correctly resulting in the initial charger + * cable type detection giving a wrong result and we end up not charging + * or charging at only 0.5A. + * + * So we schedule a second cable type detection after 2 seconds to + * give the other drivers time to load and do their thing. + */ + if (!info->first_detect_done) { + queue_delayed_work(system_wq, &info->det_work, + msecs_to_jiffies(2000)); + info->first_detect_done = true; + } +} + static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info) { int ret, stat, cfg, pwr_stat; @@ -192,20 +205,11 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info) cable = EXTCON_CHG_USB_DCP; break; default: - dev_warn(info->dev, - "disconnect or unknown or ID event\n"); + dev_warn(info->dev, "unknown (reserved) bc detect result\n"); + cable = EXTCON_CHG_USB_SDP; } no_vbus: - /* - * If VBUS is absent Connect D+/D- lines to PMIC for BC - * detection. Else connect them to SOC for USB communication. - */ - if (info->gpio_mux_cntl) - gpiod_set_value(info->gpio_mux_cntl, - vbus_attach ? EXTCON_GPIO_MUX_SEL_SOC - : EXTCON_GPIO_MUX_SEL_PMIC); - extcon_set_state_sync(info->edev, info->previous_cable, false); if (info->previous_cable == EXTCON_CHG_USB_SDP) extcon_set_state_sync(info->edev, EXTCON_USB, false); @@ -219,6 +223,8 @@ no_vbus: info->previous_cable = cable; } + axp288_chrg_detect_complete(info); + return 0; dev_det_ret: @@ -240,8 +246,11 @@ static irqreturn_t axp288_extcon_isr(int irq, void *data) return IRQ_HANDLED; } -static void axp288_extcon_enable(struct axp288_extcon_info *info) +static void axp288_extcon_det_work(struct work_struct *work) { + struct axp288_extcon_info *info = + container_of(work, struct axp288_extcon_info, det_work.work); + regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG, BC_GLOBAL_RUN, 0); /* Enable the charger detection logic */ @@ -253,8 +262,7 @@ static int axp288_extcon_probe(struct platform_device *pdev) { struct axp288_extcon_info *info; struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); - struct axp288_extcon_pdata *pdata = pdev->dev.platform_data; - int ret, i, pirq, gpio; + int ret, i, pirq; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (!info) @@ -264,8 +272,7 @@ static int axp288_extcon_probe(struct platform_device *pdev) info->regmap = axp20x->regmap; info->regmap_irqc = axp20x->regmap_irqc; info->previous_cable = EXTCON_NONE; - if (pdata) - info->gpio_mux_cntl = pdata->gpio_mux_cntl; + INIT_DELAYED_WORK(&info->det_work, axp288_extcon_det_work); platform_set_drvdata(pdev, info); @@ -286,21 +293,11 @@ static int axp288_extcon_probe(struct platform_device *pdev) return ret; } - /* Set up gpio control for USB Mux */ - if (info->gpio_mux_cntl) { - gpio = desc_to_gpio(info->gpio_mux_cntl); - ret = devm_gpio_request(&pdev->dev, gpio, "USB_MUX"); - if (ret < 0) { - dev_err(&pdev->dev, - "failed to request the gpio=%d\n", gpio); - return ret; - } - gpiod_direction_output(info->gpio_mux_cntl, - EXTCON_GPIO_MUX_SEL_PMIC); - } - for (i = 0; i < EXTCON_IRQ_END; i++) { pirq = platform_get_irq(pdev, i); + if (pirq < 0) + return pirq; + info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq); if (info->irq[i] < 0) { dev_err(&pdev->dev, @@ -321,7 +318,7 @@ static int axp288_extcon_probe(struct platform_device *pdev) } /* Start charger cable type detection */ - axp288_extcon_enable(info); + queue_delayed_work(system_wq, &info->det_work, 0); return 0; } diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index 643411066ad9..227651ff9666 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -266,7 +266,7 @@ static int max77693_muic_set_debounce_time(struct max77693_muic_info *info, static int max77693_muic_set_path(struct max77693_muic_info *info, u8 val, bool attached) { - int ret = 0; + int ret; unsigned int ctrl1, ctrl2 = 0; if (attached) diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c index 8152790d72e1..9f30f4929b72 100644 --- a/drivers/extcon/extcon-max8997.c +++ b/drivers/extcon/extcon-max8997.c @@ -204,7 +204,7 @@ static int max8997_muic_set_debounce_time(struct max8997_muic_info *info, static int max8997_muic_set_path(struct max8997_muic_info *info, u8 val, bool attached) { - int ret = 0; + int ret; u8 ctrl1, ctrl2 = 0; if (attached) diff --git a/drivers/extcon/extcon-usbc-cros-ec.c b/drivers/extcon/extcon-usbc-cros-ec.c index 6187f731b29d..6721ab01fe7d 100644 --- a/drivers/extcon/extcon-usbc-cros-ec.c +++ b/drivers/extcon/extcon-usbc-cros-ec.c @@ -34,16 +34,26 @@ struct cros_ec_extcon_info { struct notifier_block notifier; + unsigned int dr; /* data role */ + bool pr; /* power role (true if VBUS enabled) */ bool dp; /* DisplayPort enabled */ bool mux; /* SuperSpeed (usb3) enabled */ unsigned int power_type; }; static const unsigned int usb_type_c_cable[] = { + EXTCON_USB, + EXTCON_USB_HOST, EXTCON_DISP_DP, EXTCON_NONE, }; +enum usb_data_roles { + DR_NONE, + DR_HOST, + DR_DEVICE, +}; + /** * cros_ec_pd_command() - Send a command to the EC. * @info: pointer to struct cros_ec_extcon_info @@ -150,6 +160,7 @@ static int cros_ec_usb_get_role(struct cros_ec_extcon_info *info, pd_control.port = info->port_id; pd_control.role = USB_PD_CTRL_ROLE_NO_CHANGE; pd_control.mux = USB_PD_CTRL_MUX_NO_CHANGE; + pd_control.swap = USB_PD_CTRL_SWAP_NONE; ret = cros_ec_pd_command(info, EC_CMD_USB_PD_CONTROL, 1, &pd_control, sizeof(pd_control), &resp, sizeof(resp)); @@ -183,11 +194,72 @@ static int cros_ec_pd_get_num_ports(struct cros_ec_extcon_info *info) return resp.num_ports; } +static const char *cros_ec_usb_role_string(unsigned int role) +{ + return role == DR_NONE ? "DISCONNECTED" : + (role == DR_HOST ? "DFP" : "UFP"); +} + +static const char *cros_ec_usb_power_type_string(unsigned int type) +{ + switch (type) { + case USB_CHG_TYPE_NONE: + return "USB_CHG_TYPE_NONE"; + case USB_CHG_TYPE_PD: + return "USB_CHG_TYPE_PD"; + case USB_CHG_TYPE_PROPRIETARY: + return "USB_CHG_TYPE_PROPRIETARY"; + case USB_CHG_TYPE_C: + return "USB_CHG_TYPE_C"; + case USB_CHG_TYPE_BC12_DCP: + return "USB_CHG_TYPE_BC12_DCP"; + case USB_CHG_TYPE_BC12_CDP: + return "USB_CHG_TYPE_BC12_CDP"; + case USB_CHG_TYPE_BC12_SDP: + return "USB_CHG_TYPE_BC12_SDP"; + case USB_CHG_TYPE_OTHER: + return "USB_CHG_TYPE_OTHER"; + case USB_CHG_TYPE_VBUS: + return "USB_CHG_TYPE_VBUS"; + case USB_CHG_TYPE_UNKNOWN: + return "USB_CHG_TYPE_UNKNOWN"; + default: + return "USB_CHG_TYPE_UNKNOWN"; + } +} + +static bool cros_ec_usb_power_type_is_wall_wart(unsigned int type, + unsigned int role) +{ + switch (type) { + /* FIXME : Guppy, Donnettes, and other chargers will be miscategorized + * because they identify with USB_CHG_TYPE_C, but we can't return true + * here from that code because that breaks Suzy-Q and other kinds of + * USB Type-C cables and peripherals. + */ + case USB_CHG_TYPE_PROPRIETARY: + case USB_CHG_TYPE_BC12_DCP: + return true; + case USB_CHG_TYPE_PD: + case USB_CHG_TYPE_C: + case USB_CHG_TYPE_BC12_CDP: + case USB_CHG_TYPE_BC12_SDP: + case USB_CHG_TYPE_OTHER: + case USB_CHG_TYPE_VBUS: + case USB_CHG_TYPE_UNKNOWN: + case USB_CHG_TYPE_NONE: + default: + return false; + } +} + static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info, bool force) { struct device *dev = info->dev; int role, power_type; + unsigned int dr = DR_NONE; + bool pr = false; bool polarity = false; bool dp = false; bool mux = false; @@ -206,9 +278,12 @@ static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info, dev_err(dev, "failed getting role err = %d\n", role); return role; } + dev_dbg(dev, "disconnected\n"); } else { int pd_mux_state; + dr = (role & PD_CTRL_RESP_ROLE_DATA) ? DR_HOST : DR_DEVICE; + pr = (role & PD_CTRL_RESP_ROLE_POWER); pd_mux_state = cros_ec_usb_get_pd_mux_state(info); if (pd_mux_state < 0) pd_mux_state = USB_PD_MUX_USB_ENABLED; @@ -216,20 +291,62 @@ static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info, dp = pd_mux_state & USB_PD_MUX_DP_ENABLED; mux = pd_mux_state & USB_PD_MUX_USB_ENABLED; hpd = pd_mux_state & USB_PD_MUX_HPD_IRQ; + + dev_dbg(dev, + "connected role 0x%x pwr type %d dr %d pr %d pol %d mux %d dp %d hpd %d\n", + role, power_type, dr, pr, polarity, mux, dp, hpd); } - if (force || info->dp != dp || info->mux != mux || - info->power_type != power_type) { + /* + * When there is no USB host (e.g. USB PD charger), + * we are not really a UFP for the AP. + */ + if (dr == DR_DEVICE && + cros_ec_usb_power_type_is_wall_wart(power_type, role)) + dr = DR_NONE; + if (force || info->dr != dr || info->pr != pr || info->dp != dp || + info->mux != mux || info->power_type != power_type) { + bool host_connected = false, device_connected = false; + + dev_dbg(dev, "Type/Role switch! type = %s role = %s\n", + cros_ec_usb_power_type_string(power_type), + cros_ec_usb_role_string(dr)); + info->dr = dr; + info->pr = pr; info->dp = dp; info->mux = mux; info->power_type = power_type; - extcon_set_state(info->edev, EXTCON_DISP_DP, dp); + if (dr == DR_DEVICE) + device_connected = true; + else if (dr == DR_HOST) + host_connected = true; + extcon_set_state(info->edev, EXTCON_USB, device_connected); + extcon_set_state(info->edev, EXTCON_USB_HOST, host_connected); + extcon_set_state(info->edev, EXTCON_DISP_DP, dp); + extcon_set_property(info->edev, EXTCON_USB, + EXTCON_PROP_USB_VBUS, + (union extcon_property_value)(int)pr); + extcon_set_property(info->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_VBUS, + (union extcon_property_value)(int)pr); + extcon_set_property(info->edev, EXTCON_USB, + EXTCON_PROP_USB_TYPEC_POLARITY, + (union extcon_property_value)(int)polarity); + extcon_set_property(info->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_TYPEC_POLARITY, + (union extcon_property_value)(int)polarity); extcon_set_property(info->edev, EXTCON_DISP_DP, EXTCON_PROP_USB_TYPEC_POLARITY, (union extcon_property_value)(int)polarity); + extcon_set_property(info->edev, EXTCON_USB, + EXTCON_PROP_USB_SS, + (union extcon_property_value)(int)mux); + extcon_set_property(info->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_SS, + (union extcon_property_value)(int)mux); extcon_set_property(info->edev, EXTCON_DISP_DP, EXTCON_PROP_USB_SS, (union extcon_property_value)(int)mux); @@ -237,6 +354,8 @@ static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info, EXTCON_PROP_DISP_HPD, (union extcon_property_value)(int)hpd); + extcon_sync(info->edev, EXTCON_USB); + extcon_sync(info->edev, EXTCON_USB_HOST); extcon_sync(info->edev, EXTCON_DISP_DP); } else if (hpd) { @@ -322,13 +441,28 @@ static int extcon_cros_ec_probe(struct platform_device *pdev) return ret; } + extcon_set_property_capability(info->edev, EXTCON_USB, + EXTCON_PROP_USB_VBUS); + extcon_set_property_capability(info->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_VBUS); + extcon_set_property_capability(info->edev, EXTCON_USB, + EXTCON_PROP_USB_TYPEC_POLARITY); + extcon_set_property_capability(info->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_TYPEC_POLARITY); extcon_set_property_capability(info->edev, EXTCON_DISP_DP, EXTCON_PROP_USB_TYPEC_POLARITY); + extcon_set_property_capability(info->edev, EXTCON_USB, + EXTCON_PROP_USB_SS); + extcon_set_property_capability(info->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_SS); extcon_set_property_capability(info->edev, EXTCON_DISP_DP, EXTCON_PROP_USB_SS); extcon_set_property_capability(info->edev, EXTCON_DISP_DP, EXTCON_PROP_DISP_HPD); + info->dr = DR_NONE; + info->pr = false; + platform_set_drvdata(pdev, info); /* Get PD events from the EC */ diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index a301fcf46e88..f0587273940e 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -1784,17 +1784,17 @@ static int fw_device_op_release(struct inode *inode, struct file *file) return 0; } -static unsigned int fw_device_op_poll(struct file *file, poll_table * pt) +static __poll_t fw_device_op_poll(struct file *file, poll_table * pt) { struct client *client = file->private_data; - unsigned int mask = 0; + __poll_t mask = 0; poll_wait(file, &client->wait, pt); if (fw_device_is_shutdown(client->device)) - mask |= POLLHUP | POLLERR; + mask |= EPOLLHUP | EPOLLERR; if (!list_empty(&client->event_list)) - mask |= POLLIN | POLLRDNORM; + mask |= EPOLLIN | EPOLLRDNORM; return mask; } diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 242359c2d1f1..60e75e6d9104 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -1480,9 +1480,14 @@ static int fwnet_probe(struct fw_unit *unit, goto out; dev->local_fifo = dev->handler.offset; + /* + * default MTU: RFC 2734 cl. 4, RFC 3146 cl. 4 + * maximum MTU: RFC 2734 cl. 4.2, fragment encapsulation header's + * maximum possible datagram_size + 1 = 0xfff + 1 + */ net->mtu = 1500U; net->min_mtu = ETH_MIN_MTU; - net->max_mtu = 0xfff; + net->max_mtu = 4096U; /* Set our hardware address while we're at it */ ha = (union fwnet_hwaddr *)net->dev_addr; diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c index 180f0a96528c..a128dd1126ae 100644 --- a/drivers/firewire/nosy.c +++ b/drivers/firewire/nosy.c @@ -328,19 +328,19 @@ nosy_release(struct inode *inode, struct file *file) return 0; } -static unsigned int +static __poll_t nosy_poll(struct file *file, poll_table *pt) { struct client *client = file->private_data; - unsigned int ret = 0; + __poll_t ret = 0; poll_wait(file, &client->buffer.wait, pt); if (atomic_read(&client->buffer.size) > 0) - ret = POLLIN | POLLRDNORM; + ret = EPOLLIN | EPOLLRDNORM; if (list_empty(&client->lynx->link)) - ret |= POLLHUP; + ret |= EPOLLHUP; return ret; } diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index ccf52368a073..45c048751f3b 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1128,7 +1128,13 @@ static int context_add_buffer(struct context *ctx) return -ENOMEM; offset = (void *)&desc->buffer - (void *)desc; - desc->buffer_size = PAGE_SIZE - offset; + /* + * Some controllers, like JMicron ones, always issue 0x20-byte DMA reads + * for descriptors, even 0x10-byte ones. This can cause page faults when + * an IOMMU is in use and the oversized read crosses a page boundary. + * Work around this by always leaving at least 0x10 bytes of padding. + */ + desc->buffer_size = PAGE_SIZE - offset - 0x10; desc->buffer_bus = bus_addr + offset; desc->used = 0; diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index fa87a055905e..b7c748248e53 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -10,7 +10,7 @@ config ARM_PSCI_FW config ARM_PSCI_CHECKER bool "ARM PSCI checker" - depends on ARM_PSCI_FW && HOTPLUG_CPU && !TORTURE_TEST + depends on ARM_PSCI_FW && HOTPLUG_CPU && CPU_IDLE && !TORTURE_TEST help Run the PSCI checker during startup. This checks that hotplug and suspend operations work correctly when using PSCI. @@ -48,6 +48,14 @@ config ARM_SCPI_POWER_DOMAIN This enables support for the SCPI power domains which can be enabled or disabled via the SCP firmware +config ARM_SDE_INTERFACE + bool "ARM Software Delegated Exception Interface (SDEI)" + depends on ARM64 + help + The Software Delegated Exception Interface (SDEI) is an ARM + standard for registering callbacks from the platform firmware + into the OS. This is typically used to implement RAS notifications. + config EDD tristate "BIOS Enhanced Disk Drive calls determine boot disk" depends on X86 diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index feaa890197f3..b248238ddc6a 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_ARM_PSCI_FW) += psci.o obj-$(CONFIG_ARM_PSCI_CHECKER) += psci_checker.o obj-$(CONFIG_ARM_SCPI_PROTOCOL) += arm_scpi.o obj-$(CONFIG_ARM_SCPI_POWER_DOMAIN) += scpi_pm_domain.o +obj-$(CONFIG_ARM_SDE_INTERFACE) += arm_sdei.o obj-$(CONFIG_DMI) += dmi_scan.o obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o obj-$(CONFIG_EDD) += edd.o diff --git a/drivers/firmware/arm_sdei.c b/drivers/firmware/arm_sdei.c new file mode 100644 index 000000000000..1ea71640fdc2 --- /dev/null +++ b/drivers/firmware/arm_sdei.c @@ -0,0 +1,1092 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2017 Arm Ltd. +#define pr_fmt(fmt) "sdei: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The call to use to reach the firmware. + */ +static asmlinkage void (*sdei_firmware_call)(unsigned long function_id, + unsigned long arg0, unsigned long arg1, + unsigned long arg2, unsigned long arg3, + unsigned long arg4, struct arm_smccc_res *res); + +/* entry point from firmware to arch asm code */ +static unsigned long sdei_entry_point; + +struct sdei_event { + /* These three are protected by the sdei_list_lock */ + struct list_head list; + bool reregister; + bool reenable; + + u32 event_num; + u8 type; + u8 priority; + + /* This pointer is handed to firmware as the event argument. */ + union { + /* Shared events */ + struct sdei_registered_event *registered; + + /* CPU private events */ + struct sdei_registered_event __percpu *private_registered; + }; +}; + +/* Take the mutex for any API call or modification. Take the mutex first. */ +static DEFINE_MUTEX(sdei_events_lock); + +/* and then hold this when modifying the list */ +static DEFINE_SPINLOCK(sdei_list_lock); +static LIST_HEAD(sdei_list); + +/* Private events are registered/enabled via IPI passing one of these */ +struct sdei_crosscall_args { + struct sdei_event *event; + atomic_t errors; + int first_error; +}; + +#define CROSSCALL_INIT(arg, event) (arg.event = event, \ + arg.first_error = 0, \ + atomic_set(&arg.errors, 0)) + +static inline int sdei_do_cross_call(void *fn, struct sdei_event * event) +{ + struct sdei_crosscall_args arg; + + CROSSCALL_INIT(arg, event); + on_each_cpu(fn, &arg, true); + + return arg.first_error; +} + +static inline void +sdei_cross_call_return(struct sdei_crosscall_args *arg, int err) +{ + if (err && (atomic_inc_return(&arg->errors) == 1)) + arg->first_error = err; +} + +static int sdei_to_linux_errno(unsigned long sdei_err) +{ + switch (sdei_err) { + case SDEI_NOT_SUPPORTED: + return -EOPNOTSUPP; + case SDEI_INVALID_PARAMETERS: + return -EINVAL; + case SDEI_DENIED: + return -EPERM; + case SDEI_PENDING: + return -EINPROGRESS; + case SDEI_OUT_OF_RESOURCE: + return -ENOMEM; + } + + /* Not an error value ... */ + return sdei_err; +} + +/* + * If x0 is any of these values, then the call failed, use sdei_to_linux_errno() + * to translate. + */ +static int sdei_is_err(struct arm_smccc_res *res) +{ + switch (res->a0) { + case SDEI_NOT_SUPPORTED: + case SDEI_INVALID_PARAMETERS: + case SDEI_DENIED: + case SDEI_PENDING: + case SDEI_OUT_OF_RESOURCE: + return true; + } + + return false; +} + +static int invoke_sdei_fn(unsigned long function_id, unsigned long arg0, + unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4, + u64 *result) +{ + int err = 0; + struct arm_smccc_res res; + + if (sdei_firmware_call) { + sdei_firmware_call(function_id, arg0, arg1, arg2, arg3, arg4, + &res); + if (sdei_is_err(&res)) + err = sdei_to_linux_errno(res.a0); + } else { + /* + * !sdei_firmware_call means we failed to probe or called + * sdei_mark_interface_broken(). -EIO is not an error returned + * by sdei_to_linux_errno() and is used to suppress messages + * from this driver. + */ + err = -EIO; + res.a0 = SDEI_NOT_SUPPORTED; + } + + if (result) + *result = res.a0; + + return err; +} + +static struct sdei_event *sdei_event_find(u32 event_num) +{ + struct sdei_event *e, *found = NULL; + + lockdep_assert_held(&sdei_events_lock); + + spin_lock(&sdei_list_lock); + list_for_each_entry(e, &sdei_list, list) { + if (e->event_num == event_num) { + found = e; + break; + } + } + spin_unlock(&sdei_list_lock); + + return found; +} + +int sdei_api_event_context(u32 query, u64 *result) +{ + return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_CONTEXT, query, 0, 0, 0, 0, + result); +} +NOKPROBE_SYMBOL(sdei_api_event_context); + +static int sdei_api_event_get_info(u32 event, u32 info, u64 *result) +{ + return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_GET_INFO, event, info, 0, + 0, 0, result); +} + +static struct sdei_event *sdei_event_create(u32 event_num, + sdei_event_callback *cb, + void *cb_arg) +{ + int err; + u64 result; + struct sdei_event *event; + struct sdei_registered_event *reg; + + lockdep_assert_held(&sdei_events_lock); + + event = kzalloc(sizeof(*event), GFP_KERNEL); + if (!event) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&event->list); + event->event_num = event_num; + + err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_PRIORITY, + &result); + if (err) { + kfree(event); + return ERR_PTR(err); + } + event->priority = result; + + err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_TYPE, + &result); + if (err) { + kfree(event); + return ERR_PTR(err); + } + event->type = result; + + if (event->type == SDEI_EVENT_TYPE_SHARED) { + reg = kzalloc(sizeof(*reg), GFP_KERNEL); + if (!reg) { + kfree(event); + return ERR_PTR(-ENOMEM); + } + + reg->event_num = event_num; + reg->priority = event->priority; + + reg->callback = cb; + reg->callback_arg = cb_arg; + event->registered = reg; + } else { + int cpu; + struct sdei_registered_event __percpu *regs; + + regs = alloc_percpu(struct sdei_registered_event); + if (!regs) { + kfree(event); + return ERR_PTR(-ENOMEM); + } + + for_each_possible_cpu(cpu) { + reg = per_cpu_ptr(regs, cpu); + + reg->event_num = event->event_num; + reg->priority = event->priority; + reg->callback = cb; + reg->callback_arg = cb_arg; + } + + event->private_registered = regs; + } + + if (sdei_event_find(event_num)) { + kfree(event->registered); + kfree(event); + event = ERR_PTR(-EBUSY); + } else { + spin_lock(&sdei_list_lock); + list_add(&event->list, &sdei_list); + spin_unlock(&sdei_list_lock); + } + + return event; +} + +static void sdei_event_destroy(struct sdei_event *event) +{ + lockdep_assert_held(&sdei_events_lock); + + spin_lock(&sdei_list_lock); + list_del(&event->list); + spin_unlock(&sdei_list_lock); + + if (event->type == SDEI_EVENT_TYPE_SHARED) + kfree(event->registered); + else + free_percpu(event->private_registered); + + kfree(event); +} + +static int sdei_api_get_version(u64 *version) +{ + return invoke_sdei_fn(SDEI_1_0_FN_SDEI_VERSION, 0, 0, 0, 0, 0, version); +} + +int sdei_mask_local_cpu(void) +{ + int err; + + WARN_ON_ONCE(preemptible()); + + err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_MASK, 0, 0, 0, 0, 0, NULL); + if (err && err != -EIO) { + pr_warn_once("failed to mask CPU[%u]: %d\n", + smp_processor_id(), err); + return err; + } + + return 0; +} + +static void _ipi_mask_cpu(void *ignored) +{ + sdei_mask_local_cpu(); +} + +int sdei_unmask_local_cpu(void) +{ + int err; + + WARN_ON_ONCE(preemptible()); + + err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_UNMASK, 0, 0, 0, 0, 0, NULL); + if (err && err != -EIO) { + pr_warn_once("failed to unmask CPU[%u]: %d\n", + smp_processor_id(), err); + return err; + } + + return 0; +} + +static void _ipi_unmask_cpu(void *ignored) +{ + sdei_unmask_local_cpu(); +} + +static void _ipi_private_reset(void *ignored) +{ + int err; + + err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PRIVATE_RESET, 0, 0, 0, 0, 0, + NULL); + if (err && err != -EIO) + pr_warn_once("failed to reset CPU[%u]: %d\n", + smp_processor_id(), err); +} + +static int sdei_api_shared_reset(void) +{ + return invoke_sdei_fn(SDEI_1_0_FN_SDEI_SHARED_RESET, 0, 0, 0, 0, 0, + NULL); +} + +static void sdei_mark_interface_broken(void) +{ + pr_err("disabling SDEI firmware interface\n"); + on_each_cpu(&_ipi_mask_cpu, NULL, true); + sdei_firmware_call = NULL; +} + +static int sdei_platform_reset(void) +{ + int err; + + on_each_cpu(&_ipi_private_reset, NULL, true); + err = sdei_api_shared_reset(); + if (err) { + pr_err("Failed to reset platform: %d\n", err); + sdei_mark_interface_broken(); + } + + return err; +} + +static int sdei_api_event_enable(u32 event_num) +{ + return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_ENABLE, event_num, 0, 0, 0, + 0, NULL); +} + +/* Called directly by the hotplug callbacks */ +static void _local_event_enable(void *data) +{ + int err; + struct sdei_crosscall_args *arg = data; + + WARN_ON_ONCE(preemptible()); + + err = sdei_api_event_enable(arg->event->event_num); + + sdei_cross_call_return(arg, err); +} + +int sdei_event_enable(u32 event_num) +{ + int err = -EINVAL; + struct sdei_event *event; + + mutex_lock(&sdei_events_lock); + event = sdei_event_find(event_num); + if (!event) { + mutex_unlock(&sdei_events_lock); + return -ENOENT; + } + + spin_lock(&sdei_list_lock); + event->reenable = true; + spin_unlock(&sdei_list_lock); + + if (event->type == SDEI_EVENT_TYPE_SHARED) + err = sdei_api_event_enable(event->event_num); + else + err = sdei_do_cross_call(_local_event_enable, event); + mutex_unlock(&sdei_events_lock); + + return err; +} +EXPORT_SYMBOL(sdei_event_enable); + +static int sdei_api_event_disable(u32 event_num) +{ + return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_DISABLE, event_num, 0, 0, + 0, 0, NULL); +} + +static void _ipi_event_disable(void *data) +{ + int err; + struct sdei_crosscall_args *arg = data; + + err = sdei_api_event_disable(arg->event->event_num); + + sdei_cross_call_return(arg, err); +} + +int sdei_event_disable(u32 event_num) +{ + int err = -EINVAL; + struct sdei_event *event; + + mutex_lock(&sdei_events_lock); + event = sdei_event_find(event_num); + if (!event) { + mutex_unlock(&sdei_events_lock); + return -ENOENT; + } + + spin_lock(&sdei_list_lock); + event->reenable = false; + spin_unlock(&sdei_list_lock); + + if (event->type == SDEI_EVENT_TYPE_SHARED) + err = sdei_api_event_disable(event->event_num); + else + err = sdei_do_cross_call(_ipi_event_disable, event); + mutex_unlock(&sdei_events_lock); + + return err; +} +EXPORT_SYMBOL(sdei_event_disable); + +static int sdei_api_event_unregister(u32 event_num) +{ + return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_UNREGISTER, event_num, 0, + 0, 0, 0, NULL); +} + +/* Called directly by the hotplug callbacks */ +static void _local_event_unregister(void *data) +{ + int err; + struct sdei_crosscall_args *arg = data; + + WARN_ON_ONCE(preemptible()); + + err = sdei_api_event_unregister(arg->event->event_num); + + sdei_cross_call_return(arg, err); +} + +static int _sdei_event_unregister(struct sdei_event *event) +{ + lockdep_assert_held(&sdei_events_lock); + + spin_lock(&sdei_list_lock); + event->reregister = false; + event->reenable = false; + spin_unlock(&sdei_list_lock); + + if (event->type == SDEI_EVENT_TYPE_SHARED) + return sdei_api_event_unregister(event->event_num); + + return sdei_do_cross_call(_local_event_unregister, event); +} + +int sdei_event_unregister(u32 event_num) +{ + int err; + struct sdei_event *event; + + WARN_ON(in_nmi()); + + mutex_lock(&sdei_events_lock); + event = sdei_event_find(event_num); + do { + if (!event) { + pr_warn("Event %u not registered\n", event_num); + err = -ENOENT; + break; + } + + err = _sdei_event_unregister(event); + if (err) + break; + + sdei_event_destroy(event); + } while (0); + mutex_unlock(&sdei_events_lock); + + return err; +} +EXPORT_SYMBOL(sdei_event_unregister); + +/* + * unregister events, but don't destroy them as they are re-registered by + * sdei_reregister_shared(). + */ +static int sdei_unregister_shared(void) +{ + int err = 0; + struct sdei_event *event; + + mutex_lock(&sdei_events_lock); + spin_lock(&sdei_list_lock); + list_for_each_entry(event, &sdei_list, list) { + if (event->type != SDEI_EVENT_TYPE_SHARED) + continue; + + err = _sdei_event_unregister(event); + if (err) + break; + } + spin_unlock(&sdei_list_lock); + mutex_unlock(&sdei_events_lock); + + return err; +} + +static int sdei_api_event_register(u32 event_num, unsigned long entry_point, + void *arg, u64 flags, u64 affinity) +{ + return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_REGISTER, event_num, + (unsigned long)entry_point, (unsigned long)arg, + flags, affinity, NULL); +} + +/* Called directly by the hotplug callbacks */ +static void _local_event_register(void *data) +{ + int err; + struct sdei_registered_event *reg; + struct sdei_crosscall_args *arg = data; + + WARN_ON(preemptible()); + + reg = per_cpu_ptr(arg->event->private_registered, smp_processor_id()); + err = sdei_api_event_register(arg->event->event_num, sdei_entry_point, + reg, 0, 0); + + sdei_cross_call_return(arg, err); +} + +static int _sdei_event_register(struct sdei_event *event) +{ + int err; + + lockdep_assert_held(&sdei_events_lock); + + spin_lock(&sdei_list_lock); + event->reregister = true; + spin_unlock(&sdei_list_lock); + + if (event->type == SDEI_EVENT_TYPE_SHARED) + return sdei_api_event_register(event->event_num, + sdei_entry_point, + event->registered, + SDEI_EVENT_REGISTER_RM_ANY, 0); + + + err = sdei_do_cross_call(_local_event_register, event); + if (err) { + spin_lock(&sdei_list_lock); + event->reregister = false; + event->reenable = false; + spin_unlock(&sdei_list_lock); + + sdei_do_cross_call(_local_event_unregister, event); + } + + return err; +} + +int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg) +{ + int err; + struct sdei_event *event; + + WARN_ON(in_nmi()); + + mutex_lock(&sdei_events_lock); + do { + if (sdei_event_find(event_num)) { + pr_warn("Event %u already registered\n", event_num); + err = -EBUSY; + break; + } + + event = sdei_event_create(event_num, cb, arg); + if (IS_ERR(event)) { + err = PTR_ERR(event); + pr_warn("Failed to create event %u: %d\n", event_num, + err); + break; + } + + err = _sdei_event_register(event); + if (err) { + sdei_event_destroy(event); + pr_warn("Failed to register event %u: %d\n", event_num, + err); + } + } while (0); + mutex_unlock(&sdei_events_lock); + + return err; +} +EXPORT_SYMBOL(sdei_event_register); + +static int sdei_reregister_event(struct sdei_event *event) +{ + int err; + + lockdep_assert_held(&sdei_events_lock); + + err = _sdei_event_register(event); + if (err) { + pr_err("Failed to re-register event %u\n", event->event_num); + sdei_event_destroy(event); + return err; + } + + if (event->reenable) { + if (event->type == SDEI_EVENT_TYPE_SHARED) + err = sdei_api_event_enable(event->event_num); + else + err = sdei_do_cross_call(_local_event_enable, event); + } + + if (err) + pr_err("Failed to re-enable event %u\n", event->event_num); + + return err; +} + +static int sdei_reregister_shared(void) +{ + int err = 0; + struct sdei_event *event; + + mutex_lock(&sdei_events_lock); + spin_lock(&sdei_list_lock); + list_for_each_entry(event, &sdei_list, list) { + if (event->type != SDEI_EVENT_TYPE_SHARED) + continue; + + if (event->reregister) { + err = sdei_reregister_event(event); + if (err) + break; + } + } + spin_unlock(&sdei_list_lock); + mutex_unlock(&sdei_events_lock); + + return err; +} + +static int sdei_cpuhp_down(unsigned int cpu) +{ + struct sdei_event *event; + struct sdei_crosscall_args arg; + + /* un-register private events */ + spin_lock(&sdei_list_lock); + list_for_each_entry(event, &sdei_list, list) { + if (event->type == SDEI_EVENT_TYPE_SHARED) + continue; + + CROSSCALL_INIT(arg, event); + /* call the cross-call function locally... */ + _local_event_unregister(&arg); + if (arg.first_error) + pr_err("Failed to unregister event %u: %d\n", + event->event_num, arg.first_error); + } + spin_unlock(&sdei_list_lock); + + return sdei_mask_local_cpu(); +} + +static int sdei_cpuhp_up(unsigned int cpu) +{ + struct sdei_event *event; + struct sdei_crosscall_args arg; + + /* re-register/enable private events */ + spin_lock(&sdei_list_lock); + list_for_each_entry(event, &sdei_list, list) { + if (event->type == SDEI_EVENT_TYPE_SHARED) + continue; + + if (event->reregister) { + CROSSCALL_INIT(arg, event); + /* call the cross-call function locally... */ + _local_event_register(&arg); + if (arg.first_error) + pr_err("Failed to re-register event %u: %d\n", + event->event_num, arg.first_error); + } + + if (event->reenable) { + CROSSCALL_INIT(arg, event); + _local_event_enable(&arg); + if (arg.first_error) + pr_err("Failed to re-enable event %u: %d\n", + event->event_num, arg.first_error); + } + } + spin_unlock(&sdei_list_lock); + + return sdei_unmask_local_cpu(); +} + +/* When entering idle, mask/unmask events for this cpu */ +static int sdei_pm_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + int rv; + + switch (action) { + case CPU_PM_ENTER: + rv = sdei_mask_local_cpu(); + break; + case CPU_PM_EXIT: + case CPU_PM_ENTER_FAILED: + rv = sdei_unmask_local_cpu(); + break; + default: + return NOTIFY_DONE; + } + + if (rv) + return notifier_from_errno(rv); + + return NOTIFY_OK; +} + +static struct notifier_block sdei_pm_nb = { + .notifier_call = sdei_pm_notifier, +}; + +static int sdei_device_suspend(struct device *dev) +{ + on_each_cpu(_ipi_mask_cpu, NULL, true); + + return 0; +} + +static int sdei_device_resume(struct device *dev) +{ + on_each_cpu(_ipi_unmask_cpu, NULL, true); + + return 0; +} + +/* + * We need all events to be reregistered when we resume from hibernate. + * + * The sequence is freeze->thaw. Reboot. freeze->restore. We unregister + * events during freeze, then re-register and re-enable them during thaw + * and restore. + */ +static int sdei_device_freeze(struct device *dev) +{ + int err; + + /* unregister private events */ + cpuhp_remove_state(CPUHP_AP_ARM_SDEI_STARTING); + + err = sdei_unregister_shared(); + if (err) + return err; + + return 0; +} + +static int sdei_device_thaw(struct device *dev) +{ + int err; + + /* re-register shared events */ + err = sdei_reregister_shared(); + if (err) { + pr_warn("Failed to re-register shared events...\n"); + sdei_mark_interface_broken(); + return err; + } + + err = cpuhp_setup_state(CPUHP_AP_ARM_SDEI_STARTING, "SDEI", + &sdei_cpuhp_up, &sdei_cpuhp_down); + if (err) + pr_warn("Failed to re-register CPU hotplug notifier...\n"); + + return err; +} + +static int sdei_device_restore(struct device *dev) +{ + int err; + + err = sdei_platform_reset(); + if (err) + return err; + + return sdei_device_thaw(dev); +} + +static const struct dev_pm_ops sdei_pm_ops = { + .suspend = sdei_device_suspend, + .resume = sdei_device_resume, + .freeze = sdei_device_freeze, + .thaw = sdei_device_thaw, + .restore = sdei_device_restore, +}; + +/* + * Mask all CPUs and unregister all events on panic, reboot or kexec. + */ +static int sdei_reboot_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + /* + * We are going to reset the interface, after this there is no point + * doing work when we take CPUs offline. + */ + cpuhp_remove_state(CPUHP_AP_ARM_SDEI_STARTING); + + sdei_platform_reset(); + + return NOTIFY_OK; +} + +static struct notifier_block sdei_reboot_nb = { + .notifier_call = sdei_reboot_notifier, +}; + +static void sdei_smccc_smc(unsigned long function_id, + unsigned long arg0, unsigned long arg1, + unsigned long arg2, unsigned long arg3, + unsigned long arg4, struct arm_smccc_res *res) +{ + arm_smccc_smc(function_id, arg0, arg1, arg2, arg3, arg4, 0, 0, res); +} + +static void sdei_smccc_hvc(unsigned long function_id, + unsigned long arg0, unsigned long arg1, + unsigned long arg2, unsigned long arg3, + unsigned long arg4, struct arm_smccc_res *res) +{ + arm_smccc_hvc(function_id, arg0, arg1, arg2, arg3, arg4, 0, 0, res); +} + +static int sdei_get_conduit(struct platform_device *pdev) +{ + const char *method; + struct device_node *np = pdev->dev.of_node; + + sdei_firmware_call = NULL; + if (np) { + if (of_property_read_string(np, "method", &method)) { + pr_warn("missing \"method\" property\n"); + return CONDUIT_INVALID; + } + + if (!strcmp("hvc", method)) { + sdei_firmware_call = &sdei_smccc_hvc; + return CONDUIT_HVC; + } else if (!strcmp("smc", method)) { + sdei_firmware_call = &sdei_smccc_smc; + return CONDUIT_SMC; + } + + pr_warn("invalid \"method\" property: %s\n", method); + } else if (IS_ENABLED(CONFIG_ACPI) && !acpi_disabled) { + if (acpi_psci_use_hvc()) { + sdei_firmware_call = &sdei_smccc_hvc; + return CONDUIT_HVC; + } else { + sdei_firmware_call = &sdei_smccc_smc; + return CONDUIT_SMC; + } + } + + return CONDUIT_INVALID; +} + +static int sdei_probe(struct platform_device *pdev) +{ + int err; + u64 ver = 0; + int conduit; + + conduit = sdei_get_conduit(pdev); + if (!sdei_firmware_call) + return 0; + + err = sdei_api_get_version(&ver); + if (err == -EOPNOTSUPP) + pr_err("advertised but not implemented in platform firmware\n"); + if (err) { + pr_err("Failed to get SDEI version: %d\n", err); + sdei_mark_interface_broken(); + return err; + } + + pr_info("SDEIv%d.%d (0x%x) detected in firmware.\n", + (int)SDEI_VERSION_MAJOR(ver), (int)SDEI_VERSION_MINOR(ver), + (int)SDEI_VERSION_VENDOR(ver)); + + if (SDEI_VERSION_MAJOR(ver) != 1) { + pr_warn("Conflicting SDEI version detected.\n"); + sdei_mark_interface_broken(); + return -EINVAL; + } + + err = sdei_platform_reset(); + if (err) + return err; + + sdei_entry_point = sdei_arch_get_entry_point(conduit); + if (!sdei_entry_point) { + /* Not supported due to hardware or boot configuration */ + sdei_mark_interface_broken(); + return 0; + } + + err = cpu_pm_register_notifier(&sdei_pm_nb); + if (err) { + pr_warn("Failed to register CPU PM notifier...\n"); + goto error; + } + + err = register_reboot_notifier(&sdei_reboot_nb); + if (err) { + pr_warn("Failed to register reboot notifier...\n"); + goto remove_cpupm; + } + + err = cpuhp_setup_state(CPUHP_AP_ARM_SDEI_STARTING, "SDEI", + &sdei_cpuhp_up, &sdei_cpuhp_down); + if (err) { + pr_warn("Failed to register CPU hotplug notifier...\n"); + goto remove_reboot; + } + + return 0; + +remove_reboot: + unregister_reboot_notifier(&sdei_reboot_nb); + +remove_cpupm: + cpu_pm_unregister_notifier(&sdei_pm_nb); + +error: + sdei_mark_interface_broken(); + return err; +} + +static const struct of_device_id sdei_of_match[] = { + { .compatible = "arm,sdei-1.0" }, + {} +}; + +static struct platform_driver sdei_driver = { + .driver = { + .name = "sdei", + .pm = &sdei_pm_ops, + .of_match_table = sdei_of_match, + }, + .probe = sdei_probe, +}; + +static bool __init sdei_present_dt(void) +{ + struct platform_device *pdev; + struct device_node *np, *fw_np; + + fw_np = of_find_node_by_name(NULL, "firmware"); + if (!fw_np) + return false; + + np = of_find_matching_node(fw_np, sdei_of_match); + of_node_put(fw_np); + if (!np) + return false; + + pdev = of_platform_device_create(np, sdei_driver.driver.name, NULL); + of_node_put(np); + if (!pdev) + return false; + + return true; +} + +static bool __init sdei_present_acpi(void) +{ + acpi_status status; + struct platform_device *pdev; + struct acpi_table_header *sdei_table_header; + + if (acpi_disabled) + return false; + + status = acpi_get_table(ACPI_SIG_SDEI, 0, &sdei_table_header); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + const char *msg = acpi_format_exception(status); + + pr_info("Failed to get ACPI:SDEI table, %s\n", msg); + } + if (ACPI_FAILURE(status)) + return false; + + pdev = platform_device_register_simple(sdei_driver.driver.name, 0, NULL, + 0); + if (IS_ERR(pdev)) + return false; + + return true; +} + +static int __init sdei_init(void) +{ + if (sdei_present_dt() || sdei_present_acpi()) + platform_driver_register(&sdei_driver); + + return 0; +} + +/* + * On an ACPI system SDEI needs to be ready before HEST:GHES tries to register + * its events. ACPI is initialised from a subsys_initcall(), GHES is initialised + * by device_initcall(). We want to be called in the middle. + */ +subsys_initcall_sync(sdei_init); + +int sdei_event_handler(struct pt_regs *regs, + struct sdei_registered_event *arg) +{ + int err; + mm_segment_t orig_addr_limit; + u32 event_num = arg->event_num; + + orig_addr_limit = get_fs(); + set_fs(USER_DS); + + err = arg->callback(event_num, regs, arg->callback_arg); + if (err) + pr_err_ratelimited("event %u on CPU %u failed with error: %d\n", + event_num, smp_processor_id(), err); + + set_fs(orig_addr_limit); + + return err; +} +NOKPROBE_SYMBOL(sdei_event_handler); diff --git a/drivers/firmware/dmi-sysfs.c b/drivers/firmware/dmi-sysfs.c index d5de6ee8466d..ecf2eeb5f6f9 100644 --- a/drivers/firmware/dmi-sysfs.c +++ b/drivers/firmware/dmi-sysfs.c @@ -652,7 +652,7 @@ static int __init dmi_sysfs_init(void) int val; if (!dmi_kobj) { - pr_err("dmi-sysfs: dmi entry is absent.\n"); + pr_debug("dmi-sysfs: dmi entry is absent.\n"); error = -ENODATA; goto err; } diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 783041964439..e763e1484331 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -18,7 +18,7 @@ EXPORT_SYMBOL_GPL(dmi_kobj); * of and an antecedent to, SMBIOS, which stands for System * Management BIOS. See further: http://www.dmtf.org/standards */ -static const char dmi_empty_string[] = " "; +static const char dmi_empty_string[] = ""; static u32 dmi_ver __initdata; static u32 dmi_len; @@ -26,11 +26,6 @@ static u16 dmi_num; static u8 smbios_entry_point[32]; static int smbios_entry_point_size; -/* - * Catch too early calls to dmi_check_system(): - */ -static int dmi_initialized; - /* DMI system identification string used during boot */ static char dmi_ids_string[128] __initdata; @@ -44,25 +39,21 @@ static int dmi_memdev_nr; static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) { const u8 *bp = ((u8 *) dm) + dm->length; + const u8 *nsp; if (s) { - s--; - while (s > 0 && *bp) { + while (--s > 0 && *bp) bp += strlen(bp) + 1; - s--; - } - if (*bp != 0) { - size_t len = strlen(bp)+1; - size_t cmp_len = len > 8 ? 8 : len; - - if (!memcmp(bp, dmi_empty_string, cmp_len)) - return dmi_empty_string; + /* Strings containing only spaces are considered empty */ + nsp = bp; + while (*nsp == ' ') + nsp++; + if (*nsp != '\0') return bp; - } } - return ""; + return dmi_empty_string; } static const char * __init dmi_string(const struct dmi_header *dm, u8 s) @@ -633,7 +624,7 @@ void __init dmi_scan_machine(void) if (!dmi_smbios3_present(buf)) { dmi_available = 1; - goto out; + return; } } if (efi.smbios == EFI_INVALID_TABLE_ADDR) @@ -651,7 +642,7 @@ void __init dmi_scan_machine(void) if (!dmi_present(buf)) { dmi_available = 1; - goto out; + return; } } else if (IS_ENABLED(CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK)) { p = dmi_early_remap(0xF0000, 0x10000); @@ -668,7 +659,7 @@ void __init dmi_scan_machine(void) if (!dmi_smbios3_present(buf)) { dmi_available = 1; dmi_early_unmap(p, 0x10000); - goto out; + return; } memcpy(buf, buf + 16, 16); } @@ -686,7 +677,7 @@ void __init dmi_scan_machine(void) if (!dmi_present(buf)) { dmi_available = 1; dmi_early_unmap(p, 0x10000); - goto out; + return; } memcpy(buf, buf + 16, 16); } @@ -694,8 +685,6 @@ void __init dmi_scan_machine(void) } error: pr_info("DMI not present or invalid.\n"); - out: - dmi_initialized = 1; } static ssize_t raw_table_read(struct file *file, struct kobject *kobj, @@ -715,10 +704,8 @@ static int __init dmi_init(void) u8 *dmi_table; int ret = -ENOMEM; - if (!dmi_available) { - ret = -ENODATA; - goto err; - } + if (!dmi_available) + return 0; /* * Set up dmi directory at /sys/firmware/dmi. This entry should stay @@ -784,19 +771,20 @@ static bool dmi_matches(const struct dmi_system_id *dmi) { int i; - WARN(!dmi_initialized, KERN_ERR "dmi check: not initialized yet.\n"); - for (i = 0; i < ARRAY_SIZE(dmi->matches); i++) { int s = dmi->matches[i].slot; if (s == DMI_NONE) break; if (dmi_ident[s]) { - if (!dmi->matches[i].exact_match && - strstr(dmi_ident[s], dmi->matches[i].substr)) - continue; - else if (dmi->matches[i].exact_match && - !strcmp(dmi_ident[s], dmi->matches[i].substr)) - continue; + if (dmi->matches[i].exact_match) { + if (!strcmp(dmi_ident[s], + dmi->matches[i].substr)) + continue; + } else { + if (strstr(dmi_ident[s], + dmi->matches[i].substr)) + continue; + } } /* No match */ @@ -826,6 +814,8 @@ static bool dmi_is_end_of_table(const struct dmi_system_id *dmi) * Walk the blacklist table running matching functions until someone * returns non zero or we hit the end. Callback function is called for * each successful match. Returns the number of matches. + * + * dmi_scan_machine must be called before this function is called. */ int dmi_check_system(const struct dmi_system_id *list) { @@ -854,6 +844,8 @@ EXPORT_SYMBOL(dmi_check_system); * * Walk the blacklist table until the first match is found. Return the * pointer to the matching entry or NULL if there's no match. + * + * dmi_scan_machine must be called before this function is called. */ const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list) { diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index e22957665808..60a8f1363a10 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -669,10 +669,10 @@ edd_get_pci_dev(struct edd_device *edev) struct edd_info *info = edd_dev_get_info(edev); if (edd_dev_is_type(edev, "PCI") || edd_dev_is_type(edev, "XPRS")) { - return pci_get_bus_and_slot(info->params.interface_path.pci.bus, - PCI_DEVFN(info->params.interface_path.pci.slot, - info->params.interface_path.pci. - function)); + return pci_get_domain_bus_and_slot(0, + info->params.interface_path.pci.bus, + PCI_DEVFN(info->params.interface_path.pci.slot, + info->params.interface_path.pci.function)); } return NULL; } diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index 2b4c39fdfa91..3098410abad8 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -113,7 +113,7 @@ config EFI_CAPSULE_LOADER Most users should say N. config EFI_CAPSULE_QUIRK_QUARK_CSH - boolean "Add support for Quark capsules with non-standard headers" + bool "Add support for Quark capsules with non-standard headers" depends on X86 && !64BIT select EFI_CAPSULE_LOADER default y @@ -159,13 +159,21 @@ config RESET_ATTACK_MITIGATION using the TCG Platform Reset Attack Mitigation specification. This protects against an attacker forcibly rebooting the system while it still contains secrets in RAM, booting another OS and extracting the - secrets. + secrets. This should only be enabled when userland is configured to + clear the MemoryOverwriteRequest flag on clean shutdown after secrets + have been evicted, since otherwise it will trigger even on clean + reboots. endmenu config UEFI_CPER bool +config UEFI_CPER_ARM + bool + depends on UEFI_CPER && ( ARM || ARM64 ) + default y + config EFI_DEV_PATH_PARSER bool depends on ACPI diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index 269501dfba53..cb805374f4bc 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -11,7 +11,7 @@ KASAN_SANITIZE_runtime-wrappers.o := n obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o -obj-$(CONFIG_EFI) += efi.o vars.o reboot.o memattr.o +obj-$(CONFIG_EFI) += efi.o vars.o reboot.o memattr.o tpm.o obj-$(CONFIG_EFI) += capsule.o memmap.o obj-$(CONFIG_EFI_VARS) += efivars.o obj-$(CONFIG_EFI_ESRT) += esrt.o @@ -30,3 +30,4 @@ arm-obj-$(CONFIG_EFI) := arm-init.o arm-runtime.o obj-$(CONFIG_ARM) += $(arm-obj-y) obj-$(CONFIG_ARM64) += $(arm-obj-y) obj-$(CONFIG_EFI_CAPSULE_LOADER) += capsule-loader.o +obj-$(CONFIG_UEFI_CPER_ARM) += cper-arm.o diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c index 055e2e8f985a..e456f4602df1 100644 --- a/drivers/firmware/efi/capsule-loader.c +++ b/drivers/firmware/efi/capsule-loader.c @@ -45,7 +45,7 @@ int __efi_capsule_setup_info(struct capsule_info *cap_info) pages_needed = ALIGN(cap_info->total_size, PAGE_SIZE) / PAGE_SIZE; if (pages_needed == 0) { - pr_err("invalid capsule size"); + pr_err("invalid capsule size\n"); return -EINVAL; } diff --git a/drivers/firmware/efi/cper-arm.c b/drivers/firmware/efi/cper-arm.c new file mode 100644 index 000000000000..698e5c8e0c8d --- /dev/null +++ b/drivers/firmware/efi/cper-arm.c @@ -0,0 +1,356 @@ +/* + * UEFI Common Platform Error Record (CPER) support + * + * Copyright (C) 2017, The Linux Foundation. All rights reserved. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define INDENT_SP " " + +static const char * const arm_reg_ctx_strs[] = { + "AArch32 general purpose registers", + "AArch32 EL1 context registers", + "AArch32 EL2 context registers", + "AArch32 secure context registers", + "AArch64 general purpose registers", + "AArch64 EL1 context registers", + "AArch64 EL2 context registers", + "AArch64 EL3 context registers", + "Misc. system register structure", +}; + +static const char * const arm_err_trans_type_strs[] = { + "Instruction", + "Data Access", + "Generic", +}; + +static const char * const arm_bus_err_op_strs[] = { + "Generic error (type cannot be determined)", + "Generic read (type of instruction or data request cannot be determined)", + "Generic write (type of instruction of data request cannot be determined)", + "Data read", + "Data write", + "Instruction fetch", + "Prefetch", +}; + +static const char * const arm_cache_err_op_strs[] = { + "Generic error (type cannot be determined)", + "Generic read (type of instruction or data request cannot be determined)", + "Generic write (type of instruction of data request cannot be determined)", + "Data read", + "Data write", + "Instruction fetch", + "Prefetch", + "Eviction", + "Snooping (processor initiated a cache snoop that resulted in an error)", + "Snooped (processor raised a cache error caused by another processor or device snooping its cache)", + "Management", +}; + +static const char * const arm_tlb_err_op_strs[] = { + "Generic error (type cannot be determined)", + "Generic read (type of instruction or data request cannot be determined)", + "Generic write (type of instruction of data request cannot be determined)", + "Data read", + "Data write", + "Instruction fetch", + "Prefetch", + "Local management operation (processor initiated a TLB management operation that resulted in an error)", + "External management operation (processor raised a TLB error caused by another processor or device broadcasting TLB operations)", +}; + +static const char * const arm_bus_err_part_type_strs[] = { + "Local processor originated request", + "Local processor responded to request", + "Local processor observed", + "Generic", +}; + +static const char * const arm_bus_err_addr_space_strs[] = { + "External Memory Access", + "Internal Memory Access", + "Unknown", + "Device Memory Access", +}; + +static void cper_print_arm_err_info(const char *pfx, u32 type, + u64 error_info) +{ + u8 trans_type, op_type, level, participation_type, address_space; + u16 mem_attributes; + bool proc_context_corrupt, corrected, precise_pc, restartable_pc; + bool time_out, access_mode; + + /* If the type is unknown, bail. */ + if (type > CPER_ARM_MAX_TYPE) + return; + + /* + * Vendor type errors have error information values that are vendor + * specific. + */ + if (type == CPER_ARM_VENDOR_ERROR) + return; + + if (error_info & CPER_ARM_ERR_VALID_TRANSACTION_TYPE) { + trans_type = ((error_info >> CPER_ARM_ERR_TRANSACTION_SHIFT) + & CPER_ARM_ERR_TRANSACTION_MASK); + if (trans_type < ARRAY_SIZE(arm_err_trans_type_strs)) { + printk("%stransaction type: %s\n", pfx, + arm_err_trans_type_strs[trans_type]); + } + } + + if (error_info & CPER_ARM_ERR_VALID_OPERATION_TYPE) { + op_type = ((error_info >> CPER_ARM_ERR_OPERATION_SHIFT) + & CPER_ARM_ERR_OPERATION_MASK); + switch (type) { + case CPER_ARM_CACHE_ERROR: + if (op_type < ARRAY_SIZE(arm_cache_err_op_strs)) { + printk("%soperation type: %s\n", pfx, + arm_cache_err_op_strs[op_type]); + } + break; + case CPER_ARM_TLB_ERROR: + if (op_type < ARRAY_SIZE(arm_tlb_err_op_strs)) { + printk("%soperation type: %s\n", pfx, + arm_tlb_err_op_strs[op_type]); + } + break; + case CPER_ARM_BUS_ERROR: + if (op_type < ARRAY_SIZE(arm_bus_err_op_strs)) { + printk("%soperation type: %s\n", pfx, + arm_bus_err_op_strs[op_type]); + } + break; + } + } + + if (error_info & CPER_ARM_ERR_VALID_LEVEL) { + level = ((error_info >> CPER_ARM_ERR_LEVEL_SHIFT) + & CPER_ARM_ERR_LEVEL_MASK); + switch (type) { + case CPER_ARM_CACHE_ERROR: + printk("%scache level: %d\n", pfx, level); + break; + case CPER_ARM_TLB_ERROR: + printk("%sTLB level: %d\n", pfx, level); + break; + case CPER_ARM_BUS_ERROR: + printk("%saffinity level at which the bus error occurred: %d\n", + pfx, level); + break; + } + } + + if (error_info & CPER_ARM_ERR_VALID_PROC_CONTEXT_CORRUPT) { + proc_context_corrupt = ((error_info >> CPER_ARM_ERR_PC_CORRUPT_SHIFT) + & CPER_ARM_ERR_PC_CORRUPT_MASK); + if (proc_context_corrupt) + printk("%sprocessor context corrupted\n", pfx); + else + printk("%sprocessor context not corrupted\n", pfx); + } + + if (error_info & CPER_ARM_ERR_VALID_CORRECTED) { + corrected = ((error_info >> CPER_ARM_ERR_CORRECTED_SHIFT) + & CPER_ARM_ERR_CORRECTED_MASK); + if (corrected) + printk("%sthe error has been corrected\n", pfx); + else + printk("%sthe error has not been corrected\n", pfx); + } + + if (error_info & CPER_ARM_ERR_VALID_PRECISE_PC) { + precise_pc = ((error_info >> CPER_ARM_ERR_PRECISE_PC_SHIFT) + & CPER_ARM_ERR_PRECISE_PC_MASK); + if (precise_pc) + printk("%sPC is precise\n", pfx); + else + printk("%sPC is imprecise\n", pfx); + } + + if (error_info & CPER_ARM_ERR_VALID_RESTARTABLE_PC) { + restartable_pc = ((error_info >> CPER_ARM_ERR_RESTARTABLE_PC_SHIFT) + & CPER_ARM_ERR_RESTARTABLE_PC_MASK); + if (restartable_pc) + printk("%sProgram execution can be restarted reliably at the PC associated with the error.\n", pfx); + } + + /* The rest of the fields are specific to bus errors */ + if (type != CPER_ARM_BUS_ERROR) + return; + + if (error_info & CPER_ARM_ERR_VALID_PARTICIPATION_TYPE) { + participation_type = ((error_info >> CPER_ARM_ERR_PARTICIPATION_TYPE_SHIFT) + & CPER_ARM_ERR_PARTICIPATION_TYPE_MASK); + if (participation_type < ARRAY_SIZE(arm_bus_err_part_type_strs)) { + printk("%sparticipation type: %s\n", pfx, + arm_bus_err_part_type_strs[participation_type]); + } + } + + if (error_info & CPER_ARM_ERR_VALID_TIME_OUT) { + time_out = ((error_info >> CPER_ARM_ERR_TIME_OUT_SHIFT) + & CPER_ARM_ERR_TIME_OUT_MASK); + if (time_out) + printk("%srequest timed out\n", pfx); + } + + if (error_info & CPER_ARM_ERR_VALID_ADDRESS_SPACE) { + address_space = ((error_info >> CPER_ARM_ERR_ADDRESS_SPACE_SHIFT) + & CPER_ARM_ERR_ADDRESS_SPACE_MASK); + if (address_space < ARRAY_SIZE(arm_bus_err_addr_space_strs)) { + printk("%saddress space: %s\n", pfx, + arm_bus_err_addr_space_strs[address_space]); + } + } + + if (error_info & CPER_ARM_ERR_VALID_MEM_ATTRIBUTES) { + mem_attributes = ((error_info >> CPER_ARM_ERR_MEM_ATTRIBUTES_SHIFT) + & CPER_ARM_ERR_MEM_ATTRIBUTES_MASK); + printk("%smemory access attributes:0x%x\n", pfx, mem_attributes); + } + + if (error_info & CPER_ARM_ERR_VALID_ACCESS_MODE) { + access_mode = ((error_info >> CPER_ARM_ERR_ACCESS_MODE_SHIFT) + & CPER_ARM_ERR_ACCESS_MODE_MASK); + if (access_mode) + printk("%saccess mode: normal\n", pfx); + else + printk("%saccess mode: secure\n", pfx); + } +} + +void cper_print_proc_arm(const char *pfx, + const struct cper_sec_proc_arm *proc) +{ + int i, len, max_ctx_type; + struct cper_arm_err_info *err_info; + struct cper_arm_ctx_info *ctx_info; + char newpfx[64], infopfx[64]; + + printk("%sMIDR: 0x%016llx\n", pfx, proc->midr); + + len = proc->section_length - (sizeof(*proc) + + proc->err_info_num * (sizeof(*err_info))); + if (len < 0) { + printk("%ssection length: %d\n", pfx, proc->section_length); + printk("%ssection length is too small\n", pfx); + printk("%sfirmware-generated error record is incorrect\n", pfx); + printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num); + return; + } + + if (proc->validation_bits & CPER_ARM_VALID_MPIDR) + printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n", + pfx, proc->mpidr); + + if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL) + printk("%serror affinity level: %d\n", pfx, + proc->affinity_level); + + if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) { + printk("%srunning state: 0x%x\n", pfx, proc->running_state); + printk("%sPower State Coordination Interface state: %d\n", + pfx, proc->psci_state); + } + + snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); + + err_info = (struct cper_arm_err_info *)(proc + 1); + for (i = 0; i < proc->err_info_num; i++) { + printk("%sError info structure %d:\n", pfx, i); + + printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1); + + if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) { + if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST) + printk("%sfirst error captured\n", newpfx); + if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST) + printk("%slast error captured\n", newpfx); + if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED) + printk("%spropagated error captured\n", + newpfx); + if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW) + printk("%soverflow occurred, error info is incomplete\n", + newpfx); + } + + printk("%serror_type: %d, %s\n", newpfx, err_info->type, + err_info->type < ARRAY_SIZE(cper_proc_error_type_strs) ? + cper_proc_error_type_strs[err_info->type] : "unknown"); + if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) { + printk("%serror_info: 0x%016llx\n", newpfx, + err_info->error_info); + snprintf(infopfx, sizeof(infopfx), "%s%s", newpfx, INDENT_SP); + cper_print_arm_err_info(infopfx, err_info->type, + err_info->error_info); + } + if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR) + printk("%svirtual fault address: 0x%016llx\n", + newpfx, err_info->virt_fault_addr); + if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR) + printk("%sphysical fault address: 0x%016llx\n", + newpfx, err_info->physical_fault_addr); + err_info += 1; + } + + ctx_info = (struct cper_arm_ctx_info *)err_info; + max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1; + for (i = 0; i < proc->context_info_num; i++) { + int size = sizeof(*ctx_info) + ctx_info->size; + + printk("%sContext info structure %d:\n", pfx, i); + if (len < size) { + printk("%ssection length is too small\n", newpfx); + printk("%sfirmware-generated error record is incorrect\n", pfx); + return; + } + if (ctx_info->type > max_ctx_type) { + printk("%sInvalid context type: %d (max: %d)\n", + newpfx, ctx_info->type, max_ctx_type); + return; + } + printk("%sregister context type: %s\n", newpfx, + arm_reg_ctx_strs[ctx_info->type]); + print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, + (ctx_info + 1), ctx_info->size, 0); + len -= size; + ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size); + } + + if (len > 0) { + printk("%sVendor specific error info has %u bytes:\n", pfx, + len); + print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info, + len, true); + } +} diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index d2fcafcea07e..c165933ebf38 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -122,7 +122,7 @@ static const char * const proc_isa_strs[] = { "ARM A64", }; -static const char * const proc_error_type_strs[] = { +const char * const cper_proc_error_type_strs[] = { "cache error", "TLB error", "bus error", @@ -157,8 +157,8 @@ static void cper_print_proc_generic(const char *pfx, if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) { printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type); cper_print_bits(pfx, proc->proc_error_type, - proc_error_type_strs, - ARRAY_SIZE(proc_error_type_strs)); + cper_proc_error_type_strs, + ARRAY_SIZE(cper_proc_error_type_strs)); } if (proc->validation_bits & CPER_PROC_VALID_OPERATION) printk("%s""operation: %d, %s\n", pfx, proc->operation, @@ -188,122 +188,6 @@ static void cper_print_proc_generic(const char *pfx, printk("%s""IP: 0x%016llx\n", pfx, proc->ip); } -#if defined(CONFIG_ARM64) || defined(CONFIG_ARM) -static const char * const arm_reg_ctx_strs[] = { - "AArch32 general purpose registers", - "AArch32 EL1 context registers", - "AArch32 EL2 context registers", - "AArch32 secure context registers", - "AArch64 general purpose registers", - "AArch64 EL1 context registers", - "AArch64 EL2 context registers", - "AArch64 EL3 context registers", - "Misc. system register structure", -}; - -static void cper_print_proc_arm(const char *pfx, - const struct cper_sec_proc_arm *proc) -{ - int i, len, max_ctx_type; - struct cper_arm_err_info *err_info; - struct cper_arm_ctx_info *ctx_info; - char newpfx[64]; - - printk("%sMIDR: 0x%016llx\n", pfx, proc->midr); - - len = proc->section_length - (sizeof(*proc) + - proc->err_info_num * (sizeof(*err_info))); - if (len < 0) { - printk("%ssection length: %d\n", pfx, proc->section_length); - printk("%ssection length is too small\n", pfx); - printk("%sfirmware-generated error record is incorrect\n", pfx); - printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num); - return; - } - - if (proc->validation_bits & CPER_ARM_VALID_MPIDR) - printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n", - pfx, proc->mpidr); - - if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL) - printk("%serror affinity level: %d\n", pfx, - proc->affinity_level); - - if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) { - printk("%srunning state: 0x%x\n", pfx, proc->running_state); - printk("%sPower State Coordination Interface state: %d\n", - pfx, proc->psci_state); - } - - snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); - - err_info = (struct cper_arm_err_info *)(proc + 1); - for (i = 0; i < proc->err_info_num; i++) { - printk("%sError info structure %d:\n", pfx, i); - - printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1); - - if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) { - if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST) - printk("%sfirst error captured\n", newpfx); - if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST) - printk("%slast error captured\n", newpfx); - if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED) - printk("%spropagated error captured\n", - newpfx); - if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW) - printk("%soverflow occurred, error info is incomplete\n", - newpfx); - } - - printk("%serror_type: %d, %s\n", newpfx, err_info->type, - err_info->type < ARRAY_SIZE(proc_error_type_strs) ? - proc_error_type_strs[err_info->type] : "unknown"); - if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) - printk("%serror_info: 0x%016llx\n", newpfx, - err_info->error_info); - if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR) - printk("%svirtual fault address: 0x%016llx\n", - newpfx, err_info->virt_fault_addr); - if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR) - printk("%sphysical fault address: 0x%016llx\n", - newpfx, err_info->physical_fault_addr); - err_info += 1; - } - - ctx_info = (struct cper_arm_ctx_info *)err_info; - max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1; - for (i = 0; i < proc->context_info_num; i++) { - int size = sizeof(*ctx_info) + ctx_info->size; - - printk("%sContext info structure %d:\n", pfx, i); - if (len < size) { - printk("%ssection length is too small\n", newpfx); - printk("%sfirmware-generated error record is incorrect\n", pfx); - return; - } - if (ctx_info->type > max_ctx_type) { - printk("%sInvalid context type: %d (max: %d)\n", - newpfx, ctx_info->type, max_ctx_type); - return; - } - printk("%sregister context type: %s\n", newpfx, - arm_reg_ctx_strs[ctx_info->type]); - print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, - (ctx_info + 1), ctx_info->size, 0); - len -= size; - ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size); - } - - if (len > 0) { - printk("%sVendor specific error info has %u bytes:\n", pfx, - len); - print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info, - len, true); - } -} -#endif - static const char * const mem_err_type_strs[] = { "unknown", "no error", diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 557a47829d03..cd42f66a7c85 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -52,6 +52,7 @@ struct efi __read_mostly efi = { .properties_table = EFI_INVALID_TABLE_ADDR, .mem_attr_table = EFI_INVALID_TABLE_ADDR, .rng_seed = EFI_INVALID_TABLE_ADDR, + .tpm_log = EFI_INVALID_TABLE_ADDR }; EXPORT_SYMBOL(efi); @@ -464,6 +465,7 @@ static __initdata efi_config_table_type_t common_tables[] = { {EFI_PROPERTIES_TABLE_GUID, "PROP", &efi.properties_table}, {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table}, {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed}, + {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log}, {NULL_GUID, NULL, NULL}, }; @@ -552,6 +554,8 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz, if (efi_enabled(EFI_MEMMAP)) efi_memattr_init(); + efi_tpm_eventlog_init(); + /* Parse the EFI Properties table if it exists */ if (efi.properties_table != EFI_INVALID_TABLE_ADDR) { efi_properties_table_t *tbl; @@ -608,7 +612,7 @@ static int __init efi_load_efivars(void) return 0; pdev = platform_device_register_simple("efivars", 0, NULL, 0); - return IS_ERR(pdev) ? PTR_ERR(pdev) : 0; + return PTR_ERR_OR_ZERO(pdev); } device_initcall(efi_load_efivars); #endif diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index adaa4a964f0c..7b3ba40f0745 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -30,8 +30,7 @@ OBJECT_FILES_NON_STANDARD := y # Prevents link failures: __sanitizer_cov_trace_pc() is not linked in. KCOV_INSTRUMENT := n -lib-y := efi-stub-helper.o gop.o secureboot.o -lib-$(CONFIG_RESET_ATTACK_MITIGATION) += tpm.o +lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o # include the stub's generic dependencies from lib/ when building for ARM/arm64 arm-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c index 6224cdbc9669..da661bf8cb96 100644 --- a/drivers/firmware/efi/libstub/tpm.c +++ b/drivers/firmware/efi/libstub/tpm.c @@ -4,15 +4,18 @@ * Copyright (C) 2016 CoreOS, Inc * Copyright (C) 2017 Google, Inc. * Matthew Garrett + * Thiebaud Weksteen * * This file is part of the Linux kernel, and is made available under the * terms of the GNU General Public License version 2. */ #include +#include #include #include "efistub.h" +#ifdef CONFIG_RESET_ATTACK_MITIGATION static const efi_char16_t efi_MemoryOverWriteRequest_name[] = { 'M', 'e', 'm', 'o', 'r', 'y', 'O', 'v', 'e', 'r', 'w', 'r', 'i', 't', 'e', 'R', 'e', 'q', 'u', 'e', 's', 't', 'C', 'o', 'n', 't', 'r', 'o', @@ -56,3 +59,81 @@ void efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg) EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, sizeof(val), &val); } + +#endif + +void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) +{ + efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; + efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID; + efi_status_t status; + efi_physical_addr_t log_location, log_last_entry; + struct linux_efi_tpm_eventlog *log_tbl; + unsigned long first_entry_addr, last_entry_addr; + size_t log_size, last_entry_size; + efi_bool_t truncated; + void *tcg2_protocol; + + status = efi_call_early(locate_protocol, &tcg2_guid, NULL, + &tcg2_protocol); + if (status != EFI_SUCCESS) + return; + + status = efi_call_proto(efi_tcg2_protocol, get_event_log, tcg2_protocol, + EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2, + &log_location, &log_last_entry, &truncated); + if (status != EFI_SUCCESS) + return; + + if (!log_location) + return; + first_entry_addr = (unsigned long) log_location; + + /* + * We populate the EFI table even if the logs are empty. + */ + if (!log_last_entry) { + log_size = 0; + } else { + last_entry_addr = (unsigned long) log_last_entry; + /* + * get_event_log only returns the address of the last entry. + * We need to calculate its size to deduce the full size of + * the logs. + */ + last_entry_size = sizeof(struct tcpa_event) + + ((struct tcpa_event *) last_entry_addr)->event_size; + log_size = log_last_entry - log_location + last_entry_size; + } + + /* Allocate space for the logs and copy them. */ + status = efi_call_early(allocate_pool, EFI_LOADER_DATA, + sizeof(*log_tbl) + log_size, + (void **) &log_tbl); + + if (status != EFI_SUCCESS) { + efi_printk(sys_table_arg, + "Unable to allocate memory for event log\n"); + return; + } + + memset(log_tbl, 0, sizeof(*log_tbl) + log_size); + log_tbl->size = log_size; + log_tbl->version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; + memcpy(log_tbl->log, (void *) first_entry_addr, log_size); + + status = efi_call_early(install_configuration_table, + &linux_eventlog_guid, log_tbl); + if (status != EFI_SUCCESS) + goto err_free; + return; + +err_free: + efi_call_early(free_pool, log_tbl); +} + +void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg) +{ + /* Only try to retrieve the logs in 1.2 format. */ + efi_retrieve_tpm2_eventlog_1_2(sys_table_arg); +} diff --git a/drivers/firmware/efi/tpm.c b/drivers/firmware/efi/tpm.c new file mode 100644 index 000000000000..0cbeb3d46b18 --- /dev/null +++ b/drivers/firmware/efi/tpm.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017 Google, Inc. + * Thiebaud Weksteen + * + * 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. + */ + +#include +#include +#include + +#include + +/* + * Reserve the memory associated with the TPM Event Log configuration table. + */ +int __init efi_tpm_eventlog_init(void) +{ + struct linux_efi_tpm_eventlog *log_tbl; + unsigned int tbl_size; + + if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) + return 0; + + log_tbl = early_memremap(efi.tpm_log, sizeof(*log_tbl)); + if (!log_tbl) { + pr_err("Failed to map TPM Event Log table @ 0x%lx\n", + efi.tpm_log); + efi.tpm_log = EFI_INVALID_TABLE_ADDR; + return -ENOMEM; + } + + tbl_size = sizeof(*log_tbl) + log_tbl->size; + memblock_reserve(efi.tpm_log, tbl_size); + early_memunmap(log_tbl, sizeof(*log_tbl)); + return 0; +} + diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c index 14042a64bdd5..6bc8e6640d71 100644 --- a/drivers/firmware/iscsi_ibft.c +++ b/drivers/firmware/iscsi_ibft.c @@ -719,8 +719,9 @@ static int __init ibft_create_kobject(struct acpi_table_ibft *header, * executes only devices which are in domain 0. Furthermore, the * iBFT spec doesn't have a domain id field :-( */ - pci_dev = pci_get_bus_and_slot((nic->pci_bdf & 0xff00) >> 8, - (nic->pci_bdf & 0xff)); + pci_dev = pci_get_domain_bus_and_slot(0, + (nic->pci_bdf & 0xff00) >> 8, + (nic->pci_bdf & 0xff)); if (pci_dev) { rc = sysfs_create_link(&boot_kobj->kobj, &pci_dev->dev.kobj, "device"); diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index d687ca3d5049..c80ec1d03274 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -59,7 +59,10 @@ bool psci_tos_resident_on(int cpu) return cpu == resident_cpu; } -struct psci_operations psci_ops; +struct psci_operations psci_ops = { + .conduit = PSCI_CONDUIT_NONE, + .smccc_version = SMCCC_VERSION_1_0, +}; typedef unsigned long (psci_fn)(unsigned long, unsigned long, unsigned long, unsigned long); @@ -210,6 +213,22 @@ static unsigned long psci_migrate_info_up_cpu(void) 0, 0, 0); } +static void set_conduit(enum psci_conduit conduit) +{ + switch (conduit) { + case PSCI_CONDUIT_HVC: + invoke_psci_fn = __invoke_psci_fn_hvc; + break; + case PSCI_CONDUIT_SMC: + invoke_psci_fn = __invoke_psci_fn_smc; + break; + default: + WARN(1, "Unexpected PSCI conduit %d\n", conduit); + } + + psci_ops.conduit = conduit; +} + static int get_set_conduit_method(struct device_node *np) { const char *method; @@ -222,9 +241,9 @@ static int get_set_conduit_method(struct device_node *np) } if (!strcmp("hvc", method)) { - invoke_psci_fn = __invoke_psci_fn_hvc; + set_conduit(PSCI_CONDUIT_HVC); } else if (!strcmp("smc", method)) { - invoke_psci_fn = __invoke_psci_fn_smc; + set_conduit(PSCI_CONDUIT_SMC); } else { pr_warn("invalid \"method\" property: %s\n", method); return -EINVAL; @@ -493,9 +512,36 @@ static void __init psci_init_migrate(void) pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid); } +static void __init psci_init_smccc(void) +{ + u32 ver = ARM_SMCCC_VERSION_1_0; + int feature; + + feature = psci_features(ARM_SMCCC_VERSION_FUNC_ID); + + if (feature != PSCI_RET_NOT_SUPPORTED) { + u32 ret; + ret = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0); + if (ret == ARM_SMCCC_VERSION_1_1) { + psci_ops.smccc_version = SMCCC_VERSION_1_1; + ver = ret; + } + } + + /* + * Conveniently, the SMCCC and PSCI versions are encoded the + * same way. No, this isn't accidental. + */ + pr_info("SMC Calling Convention v%d.%d\n", + PSCI_VERSION_MAJOR(ver), PSCI_VERSION_MINOR(ver)); + +} + static void __init psci_0_2_set_functions(void) { pr_info("Using standard PSCI v0.2 function IDs\n"); + psci_ops.get_version = psci_get_version; + psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_FN_NATIVE(0_2, CPU_SUSPEND); psci_ops.cpu_suspend = psci_cpu_suspend; @@ -539,6 +585,7 @@ static int __init psci_probe(void) psci_init_migrate(); if (PSCI_VERSION_MAJOR(ver) >= 1) { + psci_init_smccc(); psci_init_cpu_suspend(); psci_init_system_suspend(); } @@ -652,9 +699,9 @@ int __init psci_acpi_init(void) pr_info("probing for conduit method from ACPI.\n"); if (acpi_psci_use_hvc()) - invoke_psci_fn = __invoke_psci_fn_hvc; + set_conduit(PSCI_CONDUIT_HVC); else - invoke_psci_fn = __invoke_psci_fn_smc; + set_conduit(PSCI_CONDUIT_SMC); return psci_probe(); } diff --git a/drivers/firmware/psci_checker.c b/drivers/firmware/psci_checker.c index f3f4f810e5df..bb1c068bff19 100644 --- a/drivers/firmware/psci_checker.c +++ b/drivers/firmware/psci_checker.c @@ -77,8 +77,8 @@ static int psci_ops_check(void) return 0; } -static int find_clusters(const struct cpumask *cpus, - const struct cpumask **clusters) +static int find_cpu_groups(const struct cpumask *cpus, + const struct cpumask **cpu_groups) { unsigned int nb = 0; cpumask_var_t tmp; @@ -88,11 +88,11 @@ static int find_clusters(const struct cpumask *cpus, cpumask_copy(tmp, cpus); while (!cpumask_empty(tmp)) { - const struct cpumask *cluster = + const struct cpumask *cpu_group = topology_core_cpumask(cpumask_any(tmp)); - clusters[nb++] = cluster; - cpumask_andnot(tmp, tmp, cluster); + cpu_groups[nb++] = cpu_group; + cpumask_andnot(tmp, tmp, cpu_group); } free_cpumask_var(tmp); @@ -170,24 +170,24 @@ static int hotplug_tests(void) { int err; cpumask_var_t offlined_cpus; - int i, nb_cluster; - const struct cpumask **clusters; + int i, nb_cpu_group; + const struct cpumask **cpu_groups; char *page_buf; err = -ENOMEM; if (!alloc_cpumask_var(&offlined_cpus, GFP_KERNEL)) return err; - /* We may have up to nb_available_cpus clusters. */ - clusters = kmalloc_array(nb_available_cpus, sizeof(*clusters), - GFP_KERNEL); - if (!clusters) + /* We may have up to nb_available_cpus cpu_groups. */ + cpu_groups = kmalloc_array(nb_available_cpus, sizeof(*cpu_groups), + GFP_KERNEL); + if (!cpu_groups) goto out_free_cpus; page_buf = (char *)__get_free_page(GFP_KERNEL); if (!page_buf) - goto out_free_clusters; + goto out_free_cpu_groups; err = 0; - nb_cluster = find_clusters(cpu_online_mask, clusters); + nb_cpu_group = find_cpu_groups(cpu_online_mask, cpu_groups); /* * Of course the last CPU cannot be powered down and cpu_down() should @@ -197,24 +197,22 @@ static int hotplug_tests(void) err += down_and_up_cpus(cpu_online_mask, offlined_cpus); /* - * Take down CPUs by cluster this time. When the last CPU is turned - * off, the cluster itself should shut down. + * Take down CPUs by cpu group this time. When the last CPU is turned + * off, the cpu group itself should shut down. */ - for (i = 0; i < nb_cluster; ++i) { - int cluster_id = - topology_physical_package_id(cpumask_any(clusters[i])); + for (i = 0; i < nb_cpu_group; ++i) { ssize_t len = cpumap_print_to_pagebuf(true, page_buf, - clusters[i]); + cpu_groups[i]); /* Remove trailing newline. */ page_buf[len - 1] = '\0'; - pr_info("Trying to turn off and on again cluster %d " - "(CPUs %s)\n", cluster_id, page_buf); - err += down_and_up_cpus(clusters[i], offlined_cpus); + pr_info("Trying to turn off and on again group %d (CPUs %s)\n", + i, page_buf); + err += down_and_up_cpus(cpu_groups[i], offlined_cpus); } free_page((unsigned long)page_buf); -out_free_clusters: - kfree(clusters); +out_free_cpu_groups: + kfree(cpu_groups); out_free_cpus: free_cpumask_var(offlined_cpus); return err; diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index af4c75217ea6..5a7d693009ef 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -622,30 +622,6 @@ static struct platform_driver qcom_scm_driver = { static int __init qcom_scm_init(void) { - struct device_node *np, *fw_np; - int ret; - - fw_np = of_find_node_by_name(NULL, "firmware"); - - if (!fw_np) - return -ENODEV; - - np = of_find_matching_node(fw_np, qcom_scm_dt_match); - - if (!np) { - of_node_put(fw_np); - return -ENODEV; - } - - of_node_put(np); - - ret = of_platform_populate(fw_np, qcom_scm_dt_match, NULL, NULL); - - of_node_put(fw_np); - - if (ret) - return ret; - return platform_driver_register(&qcom_scm_driver); } subsys_initcall(qcom_scm_init); diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c index deb483064f53..a41b572eeeb1 100644 --- a/drivers/firmware/qemu_fw_cfg.c +++ b/drivers/firmware/qemu_fw_cfg.c @@ -694,10 +694,8 @@ static int fw_cfg_cmdline_set(const char *arg, const struct kernel_param *kp) */ fw_cfg_cmdline_dev = platform_device_register_simple("fw_cfg", PLATFORM_DEVID_NONE, res, processed); - if (IS_ERR(fw_cfg_cmdline_dev)) - return PTR_ERR(fw_cfg_cmdline_dev); - return 0; + return PTR_ERR_OR_ZERO(fw_cfg_cmdline_dev); } static int fw_cfg_cmdline_get(char *buf, const struct kernel_param *kp) diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index dd506cd3a5b8..6692888f04cf 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -174,7 +174,7 @@ rpi_firmware_print_firmware_revision(struct rpi_firmware *fw) if (ret == 0) { struct tm tm; - time_to_tm(packet, 0, &tm); + time64_to_tm(packet, 0, &tm); dev_info(fw->cl.dev, "Attached to firmware from %04ld-%02d-%02d %02d:%02d\n", diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 23b12d99ddfe..5229036dcfbf 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -287,13 +287,13 @@ static void ti_sci_rx_callback(struct mbox_client *cl, void *m) /* Is the message of valid length? */ if (mbox_msg->len > info->desc->max_msg_size) { - dev_err(dev, "Unable to handle %d xfer(max %d)\n", + dev_err(dev, "Unable to handle %zu xfer(max %d)\n", mbox_msg->len, info->desc->max_msg_size); ti_sci_dump_header_dbg(dev, hdr); return; } if (mbox_msg->len < xfer->rx_len) { - dev_err(dev, "Recv xfer %d < expected %d length\n", + dev_err(dev, "Recv xfer %zu < expected %d length\n", mbox_msg->len, xfer->rx_len); ti_sci_dump_header_dbg(dev, hdr); return; diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index ad5448f718b3..f47ef848bcd0 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -11,33 +11,6 @@ menuconfig FPGA if FPGA -config FPGA_REGION - tristate "FPGA Region" - depends on OF && FPGA_BRIDGE - help - FPGA Regions allow loading FPGA images under control of - the Device Tree. - -config FPGA_MGR_ICE40_SPI - tristate "Lattice iCE40 SPI" - depends on OF && SPI - help - FPGA manager driver support for Lattice iCE40 FPGAs over SPI. - -config FPGA_MGR_ALTERA_CVP - tristate "Altera Arria-V/Cyclone-V/Stratix-V CvP FPGA Manager" - depends on PCI - help - FPGA manager driver support for Arria-V, Cyclone-V, Stratix-V - and Arria 10 Altera FPGAs using the CvP interface over PCIe. - -config FPGA_MGR_ALTERA_PS_SPI - tristate "Altera FPGA Passive Serial over SPI" - depends on SPI - help - FPGA manager driver support for Altera Arria/Cyclone/Stratix - using the passive serial interface over SPI. - config FPGA_MGR_SOCFPGA tristate "Altera SOCFPGA FPGA Manager" depends on ARCH_SOCFPGA || COMPILE_TEST @@ -51,19 +24,31 @@ config FPGA_MGR_SOCFPGA_A10 help FPGA manager driver support for Altera Arria10 SoCFPGA. -config FPGA_MGR_TS73XX - tristate "Technologic Systems TS-73xx SBC FPGA Manager" - depends on ARCH_EP93XX && MACH_TS72XX - help - FPGA manager driver support for the Altera Cyclone II FPGA - present on the TS-73xx SBC boards. +config ALTERA_PR_IP_CORE + tristate "Altera Partial Reconfiguration IP Core" + help + Core driver support for Altera Partial Reconfiguration IP component -config FPGA_MGR_XILINX_SPI - tristate "Xilinx Configuration over Slave Serial (SPI)" +config ALTERA_PR_IP_CORE_PLAT + tristate "Platform support of Altera Partial Reconfiguration IP Core" + depends on ALTERA_PR_IP_CORE && OF && HAS_IOMEM + help + Platform driver support for Altera Partial Reconfiguration IP + component + +config FPGA_MGR_ALTERA_PS_SPI + tristate "Altera FPGA Passive Serial over SPI" depends on SPI help - FPGA manager driver support for Xilinx FPGA configuration - over slave serial interface. + FPGA manager driver support for Altera Arria/Cyclone/Stratix + using the passive serial interface over SPI. + +config FPGA_MGR_ALTERA_CVP + tristate "Altera Arria-V/Cyclone-V/Stratix-V CvP FPGA Manager" + depends on PCI + help + FPGA manager driver support for Arria-V, Cyclone-V, Stratix-V + and Arria 10 Altera FPGAs using the CvP interface over PCIe. config FPGA_MGR_ZYNQ_FPGA tristate "Xilinx Zynq FPGA" @@ -72,9 +57,28 @@ config FPGA_MGR_ZYNQ_FPGA help FPGA manager driver support for Xilinx Zynq FPGAs. +config FPGA_MGR_XILINX_SPI + tristate "Xilinx Configuration over Slave Serial (SPI)" + depends on SPI + help + FPGA manager driver support for Xilinx FPGA configuration + over slave serial interface. + +config FPGA_MGR_ICE40_SPI + tristate "Lattice iCE40 SPI" + depends on OF && SPI + help + FPGA manager driver support for Lattice iCE40 FPGAs over SPI. + +config FPGA_MGR_TS73XX + tristate "Technologic Systems TS-73xx SBC FPGA Manager" + depends on ARCH_EP93XX && MACH_TS72XX + help + FPGA manager driver support for the Altera Cyclone II FPGA + present on the TS-73xx SBC boards. + config FPGA_BRIDGE tristate "FPGA Bridge Framework" - depends on OF help Say Y here if you want to support bridges connected between host processors and FPGAs or between FPGAs. @@ -95,18 +99,6 @@ config ALTERA_FREEZE_BRIDGE isolate one region of the FPGA from the busses while that region is being reprogrammed. -config ALTERA_PR_IP_CORE - tristate "Altera Partial Reconfiguration IP Core" - help - Core driver support for Altera Partial Reconfiguration IP component - -config ALTERA_PR_IP_CORE_PLAT - tristate "Platform support of Altera Partial Reconfiguration IP Core" - depends on ALTERA_PR_IP_CORE && OF && HAS_IOMEM - help - Platform driver support for Altera Partial Reconfiguration IP - component - config XILINX_PR_DECOUPLER tristate "Xilinx LogiCORE PR Decoupler" depends on FPGA_BRIDGE @@ -117,4 +109,19 @@ config XILINX_PR_DECOUPLER region of the FPGA from the busses while that region is being reprogrammed during partial reconfig. +config FPGA_REGION + tristate "FPGA Region" + depends on FPGA_BRIDGE + help + FPGA Region common code. A FPGA Region controls a FPGA Manager + and the FPGA Bridges associated with either a reconfigurable + region of an FPGA or a whole FPGA. + +config OF_FPGA_REGION + tristate "FPGA Region Device Tree Overlay Support" + depends on OF && FPGA_REGION + help + Support for loading FPGA images by applying a Device Tree + overlay. + endif # FPGA diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index f98dcf1d89e1..3cb276a0f88d 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -26,3 +26,4 @@ obj-$(CONFIG_XILINX_PR_DECOUPLER) += xilinx-pr-decoupler.o # High Level Interfaces obj-$(CONFIG_FPGA_REGION) += fpga-region.o +obj-$(CONFIG_OF_FPGA_REGION) += of-fpga-region.o diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c index 9651aa56244a..31bd2c59c305 100644 --- a/drivers/fpga/fpga-bridge.c +++ b/drivers/fpga/fpga-bridge.c @@ -2,6 +2,7 @@ * FPGA Bridge Framework Driver * * Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved. + * Copyright (C) 2017 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -70,32 +71,13 @@ int fpga_bridge_disable(struct fpga_bridge *bridge) } EXPORT_SYMBOL_GPL(fpga_bridge_disable); -/** - * of_fpga_bridge_get - get an exclusive reference to a fpga bridge - * - * @np: node pointer of a FPGA bridge - * @info: fpga image specific information - * - * Return fpga_bridge struct if successful. - * Return -EBUSY if someone already has a reference to the bridge. - * Return -ENODEV if @np is not a FPGA Bridge. - */ -struct fpga_bridge *of_fpga_bridge_get(struct device_node *np, - struct fpga_image_info *info) - +static struct fpga_bridge *__fpga_bridge_get(struct device *dev, + struct fpga_image_info *info) { - struct device *dev; struct fpga_bridge *bridge; int ret = -ENODEV; - dev = class_find_device(fpga_bridge_class, NULL, np, - fpga_bridge_of_node_match); - if (!dev) - goto err_dev; - bridge = to_fpga_bridge(dev); - if (!bridge) - goto err_dev; bridge->info = info; @@ -117,8 +99,58 @@ err_dev: put_device(dev); return ERR_PTR(ret); } + +/** + * of_fpga_bridge_get - get an exclusive reference to a fpga bridge + * + * @np: node pointer of a FPGA bridge + * @info: fpga image specific information + * + * Return fpga_bridge struct if successful. + * Return -EBUSY if someone already has a reference to the bridge. + * Return -ENODEV if @np is not a FPGA Bridge. + */ +struct fpga_bridge *of_fpga_bridge_get(struct device_node *np, + struct fpga_image_info *info) +{ + struct device *dev; + + dev = class_find_device(fpga_bridge_class, NULL, np, + fpga_bridge_of_node_match); + if (!dev) + return ERR_PTR(-ENODEV); + + return __fpga_bridge_get(dev, info); +} EXPORT_SYMBOL_GPL(of_fpga_bridge_get); +static int fpga_bridge_dev_match(struct device *dev, const void *data) +{ + return dev->parent == data; +} + +/** + * fpga_bridge_get - get an exclusive reference to a fpga bridge + * @dev: parent device that fpga bridge was registered with + * + * Given a device, get an exclusive reference to a fpga bridge. + * + * Return: fpga manager struct or IS_ERR() condition containing error code. + */ +struct fpga_bridge *fpga_bridge_get(struct device *dev, + struct fpga_image_info *info) +{ + struct device *bridge_dev; + + bridge_dev = class_find_device(fpga_bridge_class, NULL, dev, + fpga_bridge_dev_match); + if (!bridge_dev) + return ERR_PTR(-ENODEV); + + return __fpga_bridge_get(bridge_dev, info); +} +EXPORT_SYMBOL_GPL(fpga_bridge_get); + /** * fpga_bridge_put - release a reference to a bridge * @@ -206,7 +238,7 @@ void fpga_bridges_put(struct list_head *bridge_list) EXPORT_SYMBOL_GPL(fpga_bridges_put); /** - * fpga_bridges_get_to_list - get a bridge, add it to a list + * of_fpga_bridge_get_to_list - get a bridge, add it to a list * * @np: node pointer of a FPGA bridge * @info: fpga image specific information @@ -216,14 +248,44 @@ EXPORT_SYMBOL_GPL(fpga_bridges_put); * * Return 0 for success, error code from of_fpga_bridge_get() othewise. */ -int fpga_bridge_get_to_list(struct device_node *np, +int of_fpga_bridge_get_to_list(struct device_node *np, + struct fpga_image_info *info, + struct list_head *bridge_list) +{ + struct fpga_bridge *bridge; + unsigned long flags; + + bridge = of_fpga_bridge_get(np, info); + if (IS_ERR(bridge)) + return PTR_ERR(bridge); + + spin_lock_irqsave(&bridge_list_lock, flags); + list_add(&bridge->node, bridge_list); + spin_unlock_irqrestore(&bridge_list_lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(of_fpga_bridge_get_to_list); + +/** + * fpga_bridge_get_to_list - given device, get a bridge, add it to a list + * + * @dev: FPGA bridge device + * @info: fpga image specific information + * @bridge_list: list of FPGA bridges + * + * Get an exclusive reference to the bridge and and it to the list. + * + * Return 0 for success, error code from fpga_bridge_get() othewise. + */ +int fpga_bridge_get_to_list(struct device *dev, struct fpga_image_info *info, struct list_head *bridge_list) { struct fpga_bridge *bridge; unsigned long flags; - bridge = of_fpga_bridge_get(np, info); + bridge = fpga_bridge_get(dev, info); if (IS_ERR(bridge)) return PTR_ERR(bridge); @@ -303,6 +365,7 @@ int fpga_bridge_register(struct device *dev, const char *name, bridge->priv = priv; device_initialize(&bridge->dev); + bridge->dev.groups = br_ops->groups; bridge->dev.class = fpga_bridge_class; bridge->dev.parent = dev; bridge->dev.of_node = dev->of_node; @@ -381,7 +444,7 @@ static void __exit fpga_bridge_dev_exit(void) } MODULE_DESCRIPTION("FPGA Bridge Driver"); -MODULE_AUTHOR("Alan Tull "); +MODULE_AUTHOR("Alan Tull "); MODULE_LICENSE("GPL v2"); subsys_initcall(fpga_bridge_dev_init); diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index 188ffefa3cc3..9939d2cbc9a6 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -2,6 +2,7 @@ * FPGA Manager Core * * Copyright (C) 2013-2015 Altera Corporation + * Copyright (C) 2017 Intel Corporation * * With code from the mailing list: * Copyright (C) 2013 Xilinx, Inc. @@ -31,6 +32,40 @@ static DEFINE_IDA(fpga_mgr_ida); static struct class *fpga_mgr_class; +struct fpga_image_info *fpga_image_info_alloc(struct device *dev) +{ + struct fpga_image_info *info; + + get_device(dev); + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) { + put_device(dev); + return NULL; + } + + info->dev = dev; + + return info; +} +EXPORT_SYMBOL_GPL(fpga_image_info_alloc); + +void fpga_image_info_free(struct fpga_image_info *info) +{ + struct device *dev; + + if (!info) + return; + + dev = info->dev; + if (info->firmware_name) + devm_kfree(dev, info->firmware_name); + + devm_kfree(dev, info); + put_device(dev); +} +EXPORT_SYMBOL_GPL(fpga_image_info_free); + /* * Call the low level driver's write_init function. This will do the * device-specific things to get the FPGA into the state where it is ready to @@ -137,8 +172,9 @@ static int fpga_mgr_write_complete(struct fpga_manager *mgr, * * Return: 0 on success, negative error code otherwise. */ -int fpga_mgr_buf_load_sg(struct fpga_manager *mgr, struct fpga_image_info *info, - struct sg_table *sgt) +static int fpga_mgr_buf_load_sg(struct fpga_manager *mgr, + struct fpga_image_info *info, + struct sg_table *sgt) { int ret; @@ -170,7 +206,6 @@ int fpga_mgr_buf_load_sg(struct fpga_manager *mgr, struct fpga_image_info *info, return fpga_mgr_write_complete(mgr, info); } -EXPORT_SYMBOL_GPL(fpga_mgr_buf_load_sg); static int fpga_mgr_buf_load_mapped(struct fpga_manager *mgr, struct fpga_image_info *info, @@ -210,8 +245,9 @@ static int fpga_mgr_buf_load_mapped(struct fpga_manager *mgr, * * Return: 0 on success, negative error code otherwise. */ -int fpga_mgr_buf_load(struct fpga_manager *mgr, struct fpga_image_info *info, - const char *buf, size_t count) +static int fpga_mgr_buf_load(struct fpga_manager *mgr, + struct fpga_image_info *info, + const char *buf, size_t count) { struct page **pages; struct sg_table sgt; @@ -266,7 +302,6 @@ int fpga_mgr_buf_load(struct fpga_manager *mgr, struct fpga_image_info *info, return rc; } -EXPORT_SYMBOL_GPL(fpga_mgr_buf_load); /** * fpga_mgr_firmware_load - request firmware and load to fpga @@ -282,9 +317,9 @@ EXPORT_SYMBOL_GPL(fpga_mgr_buf_load); * * Return: 0 on success, negative error code otherwise. */ -int fpga_mgr_firmware_load(struct fpga_manager *mgr, - struct fpga_image_info *info, - const char *image_name) +static int fpga_mgr_firmware_load(struct fpga_manager *mgr, + struct fpga_image_info *info, + const char *image_name) { struct device *dev = &mgr->dev; const struct firmware *fw; @@ -307,7 +342,18 @@ int fpga_mgr_firmware_load(struct fpga_manager *mgr, return ret; } -EXPORT_SYMBOL_GPL(fpga_mgr_firmware_load); + +int fpga_mgr_load(struct fpga_manager *mgr, struct fpga_image_info *info) +{ + if (info->sgt) + return fpga_mgr_buf_load_sg(mgr, info, info->sgt); + if (info->buf && info->count) + return fpga_mgr_buf_load(mgr, info, info->buf, info->count); + if (info->firmware_name) + return fpga_mgr_firmware_load(mgr, info, info->firmware_name); + return -EINVAL; +} +EXPORT_SYMBOL_GPL(fpga_mgr_load); static const char * const state_str[] = { [FPGA_MGR_STATE_UNKNOWN] = "unknown", @@ -364,28 +410,17 @@ ATTRIBUTE_GROUPS(fpga_mgr); static struct fpga_manager *__fpga_mgr_get(struct device *dev) { struct fpga_manager *mgr; - int ret = -ENODEV; mgr = to_fpga_manager(dev); - if (!mgr) - goto err_dev; - - /* Get exclusive use of fpga manager */ - if (!mutex_trylock(&mgr->ref_mutex)) { - ret = -EBUSY; - goto err_dev; - } if (!try_module_get(dev->parent->driver->owner)) - goto err_ll_mod; + goto err_dev; return mgr; -err_ll_mod: - mutex_unlock(&mgr->ref_mutex); err_dev: put_device(dev); - return ERR_PTR(ret); + return ERR_PTR(-ENODEV); } static int fpga_mgr_dev_match(struct device *dev, const void *data) @@ -394,10 +429,10 @@ static int fpga_mgr_dev_match(struct device *dev, const void *data) } /** - * fpga_mgr_get - get an exclusive reference to a fpga mgr + * fpga_mgr_get - get a reference to a fpga mgr * @dev: parent device that fpga mgr was registered with * - * Given a device, get an exclusive reference to a fpga mgr. + * Given a device, get a reference to a fpga mgr. * * Return: fpga manager struct or IS_ERR() condition containing error code. */ @@ -418,10 +453,10 @@ static int fpga_mgr_of_node_match(struct device *dev, const void *data) } /** - * of_fpga_mgr_get - get an exclusive reference to a fpga mgr + * of_fpga_mgr_get - get a reference to a fpga mgr * @node: device node * - * Given a device node, get an exclusive reference to a fpga mgr. + * Given a device node, get a reference to a fpga mgr. * * Return: fpga manager struct or IS_ERR() condition containing error code. */ @@ -445,11 +480,40 @@ EXPORT_SYMBOL_GPL(of_fpga_mgr_get); void fpga_mgr_put(struct fpga_manager *mgr) { module_put(mgr->dev.parent->driver->owner); - mutex_unlock(&mgr->ref_mutex); put_device(&mgr->dev); } EXPORT_SYMBOL_GPL(fpga_mgr_put); +/** + * fpga_mgr_lock - Lock FPGA manager for exclusive use + * @mgr: fpga manager + * + * Given a pointer to FPGA Manager (from fpga_mgr_get() or + * of_fpga_mgr_put()) attempt to get the mutex. + * + * Return: 0 for success or -EBUSY + */ +int fpga_mgr_lock(struct fpga_manager *mgr) +{ + if (!mutex_trylock(&mgr->ref_mutex)) { + dev_err(&mgr->dev, "FPGA manager is in use.\n"); + return -EBUSY; + } + + return 0; +} +EXPORT_SYMBOL_GPL(fpga_mgr_lock); + +/** + * fpga_mgr_unlock - Unlock FPGA manager + * @mgr: fpga manager + */ +void fpga_mgr_unlock(struct fpga_manager *mgr) +{ + mutex_unlock(&mgr->ref_mutex); +} +EXPORT_SYMBOL_GPL(fpga_mgr_unlock); + /** * fpga_mgr_register - register a low level fpga manager driver * @dev: fpga manager device from pdev @@ -503,6 +567,7 @@ int fpga_mgr_register(struct device *dev, const char *name, device_initialize(&mgr->dev); mgr->dev.class = fpga_mgr_class; + mgr->dev.groups = mops->groups; mgr->dev.parent = dev; mgr->dev.of_node = dev->of_node; mgr->dev.id = id; @@ -578,7 +643,7 @@ static void __exit fpga_mgr_class_exit(void) ida_destroy(&fpga_mgr_ida); } -MODULE_AUTHOR("Alan Tull "); +MODULE_AUTHOR("Alan Tull "); MODULE_DESCRIPTION("FPGA manager framework"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/fpga/fpga-region.c b/drivers/fpga/fpga-region.c index d9ab7c75b14f..edab2a2e03ef 100644 --- a/drivers/fpga/fpga-region.c +++ b/drivers/fpga/fpga-region.c @@ -2,6 +2,7 @@ * FPGA Region - Device Tree support for FPGA programming under Linux * * Copyright (C) 2013-2016 Altera Corporation + * Copyright (C) 2017 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,61 +19,30 @@ #include #include +#include #include #include #include #include -#include #include #include -/** - * struct fpga_region - FPGA Region structure - * @dev: FPGA Region device - * @mutex: enforces exclusive reference to region - * @bridge_list: list of FPGA bridges specified in region - * @info: fpga image specific information - */ -struct fpga_region { - struct device dev; - struct mutex mutex; /* for exclusive reference to region */ - struct list_head bridge_list; - struct fpga_image_info *info; -}; - -#define to_fpga_region(d) container_of(d, struct fpga_region, dev) - static DEFINE_IDA(fpga_region_ida); static struct class *fpga_region_class; -static const struct of_device_id fpga_region_of_match[] = { - { .compatible = "fpga-region", }, - {}, -}; -MODULE_DEVICE_TABLE(of, fpga_region_of_match); - -static int fpga_region_of_node_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - -/** - * fpga_region_find - find FPGA region - * @np: device node of FPGA Region - * Caller will need to put_device(®ion->dev) when done. - * Returns FPGA Region struct or NULL - */ -static struct fpga_region *fpga_region_find(struct device_node *np) +struct fpga_region *fpga_region_class_find( + struct device *start, const void *data, + int (*match)(struct device *, const void *)) { struct device *dev; - dev = class_find_device(fpga_region_class, NULL, np, - fpga_region_of_node_match); + dev = class_find_device(fpga_region_class, start, data, match); if (!dev) return NULL; return to_fpga_region(dev); } +EXPORT_SYMBOL_GPL(fpga_region_class_find); /** * fpga_region_get - get an exclusive reference to a fpga region @@ -94,15 +64,13 @@ static struct fpga_region *fpga_region_get(struct fpga_region *region) } get_device(dev); - of_node_get(dev->of_node); if (!try_module_get(dev->parent->driver->owner)) { - of_node_put(dev->of_node); put_device(dev); mutex_unlock(®ion->mutex); return ERR_PTR(-ENODEV); } - dev_dbg(®ion->dev, "get\n"); + dev_dbg(dev, "get\n"); return region; } @@ -116,403 +84,99 @@ static void fpga_region_put(struct fpga_region *region) { struct device *dev = ®ion->dev; - dev_dbg(®ion->dev, "put\n"); + dev_dbg(dev, "put\n"); module_put(dev->parent->driver->owner); - of_node_put(dev->of_node); put_device(dev); mutex_unlock(®ion->mutex); } -/** - * fpga_region_get_manager - get exclusive reference for FPGA manager - * @region: FPGA region - * - * Get FPGA Manager from "fpga-mgr" property or from ancestor region. - * - * Caller should call fpga_mgr_put() when done with manager. - * - * Return: fpga manager struct or IS_ERR() condition containing error code. - */ -static struct fpga_manager *fpga_region_get_manager(struct fpga_region *region) -{ - struct device *dev = ®ion->dev; - struct device_node *np = dev->of_node; - struct device_node *mgr_node; - struct fpga_manager *mgr; - - of_node_get(np); - while (np) { - if (of_device_is_compatible(np, "fpga-region")) { - mgr_node = of_parse_phandle(np, "fpga-mgr", 0); - if (mgr_node) { - mgr = of_fpga_mgr_get(mgr_node); - of_node_put(np); - return mgr; - } - } - np = of_get_next_parent(np); - } - of_node_put(np); - - return ERR_PTR(-EINVAL); -} - -/** - * fpga_region_get_bridges - create a list of bridges - * @region: FPGA region - * @overlay: device node of the overlay - * - * Create a list of bridges including the parent bridge and the bridges - * specified by "fpga-bridges" property. Note that the - * fpga_bridges_enable/disable/put functions are all fine with an empty list - * if that happens. - * - * Caller should call fpga_bridges_put(®ion->bridge_list) when - * done with the bridges. - * - * Return 0 for success (even if there are no bridges specified) - * or -EBUSY if any of the bridges are in use. - */ -static int fpga_region_get_bridges(struct fpga_region *region, - struct device_node *overlay) -{ - struct device *dev = ®ion->dev; - struct device_node *region_np = dev->of_node; - struct device_node *br, *np, *parent_br = NULL; - int i, ret; - - /* If parent is a bridge, add to list */ - ret = fpga_bridge_get_to_list(region_np->parent, region->info, - ®ion->bridge_list); - if (ret == -EBUSY) - return ret; - - if (!ret) - parent_br = region_np->parent; - - /* If overlay has a list of bridges, use it. */ - if (of_parse_phandle(overlay, "fpga-bridges", 0)) - np = overlay; - else - np = region_np; - - for (i = 0; ; i++) { - br = of_parse_phandle(np, "fpga-bridges", i); - if (!br) - break; - - /* If parent bridge is in list, skip it. */ - if (br == parent_br) - continue; - - /* If node is a bridge, get it and add to list */ - ret = fpga_bridge_get_to_list(br, region->info, - ®ion->bridge_list); - - /* If any of the bridges are in use, give up */ - if (ret == -EBUSY) { - fpga_bridges_put(®ion->bridge_list); - return -EBUSY; - } - } - - return 0; -} - /** * fpga_region_program_fpga - program FPGA * @region: FPGA region - * @firmware_name: name of FPGA image firmware file - * @overlay: device node of the overlay - * Program an FPGA using information in the device tree. - * Function assumes that there is a firmware-name property. + * Program an FPGA using fpga image info (region->info). * Return 0 for success or negative error code. */ -static int fpga_region_program_fpga(struct fpga_region *region, - const char *firmware_name, - struct device_node *overlay) +int fpga_region_program_fpga(struct fpga_region *region) { - struct fpga_manager *mgr; + struct device *dev = ®ion->dev; + struct fpga_image_info *info = region->info; int ret; region = fpga_region_get(region); if (IS_ERR(region)) { - pr_err("failed to get fpga region\n"); + dev_err(dev, "failed to get FPGA region\n"); return PTR_ERR(region); } - mgr = fpga_region_get_manager(region); - if (IS_ERR(mgr)) { - pr_err("failed to get fpga region manager\n"); - ret = PTR_ERR(mgr); + ret = fpga_mgr_lock(region->mgr); + if (ret) { + dev_err(dev, "FPGA manager is busy\n"); goto err_put_region; } - ret = fpga_region_get_bridges(region, overlay); - if (ret) { - pr_err("failed to get fpga region bridges\n"); - goto err_put_mgr; + /* + * In some cases, we already have a list of bridges in the + * fpga region struct. Or we don't have any bridges. + */ + if (region->get_bridges) { + ret = region->get_bridges(region); + if (ret) { + dev_err(dev, "failed to get fpga region bridges\n"); + goto err_unlock_mgr; + } } ret = fpga_bridges_disable(®ion->bridge_list); if (ret) { - pr_err("failed to disable region bridges\n"); + dev_err(dev, "failed to disable bridges\n"); goto err_put_br; } - ret = fpga_mgr_firmware_load(mgr, region->info, firmware_name); + ret = fpga_mgr_load(region->mgr, info); if (ret) { - pr_err("failed to load fpga image\n"); + dev_err(dev, "failed to load FPGA image\n"); goto err_put_br; } ret = fpga_bridges_enable(®ion->bridge_list); if (ret) { - pr_err("failed to enable region bridges\n"); + dev_err(dev, "failed to enable region bridges\n"); goto err_put_br; } - fpga_mgr_put(mgr); + fpga_mgr_unlock(region->mgr); fpga_region_put(region); return 0; err_put_br: - fpga_bridges_put(®ion->bridge_list); -err_put_mgr: - fpga_mgr_put(mgr); + if (region->get_bridges) + fpga_bridges_put(®ion->bridge_list); +err_unlock_mgr: + fpga_mgr_unlock(region->mgr); err_put_region: fpga_region_put(region); return ret; } +EXPORT_SYMBOL_GPL(fpga_region_program_fpga); -/** - * child_regions_with_firmware - * @overlay: device node of the overlay - * - * If the overlay adds child FPGA regions, they are not allowed to have - * firmware-name property. - * - * Return 0 for OK or -EINVAL if child FPGA region adds firmware-name. - */ -static int child_regions_with_firmware(struct device_node *overlay) +int fpga_region_register(struct device *dev, struct fpga_region *region) { - struct device_node *child_region; - const char *child_firmware_name; - int ret = 0; - - of_node_get(overlay); - - child_region = of_find_matching_node(overlay, fpga_region_of_match); - while (child_region) { - if (!of_property_read_string(child_region, "firmware-name", - &child_firmware_name)) { - ret = -EINVAL; - break; - } - child_region = of_find_matching_node(child_region, - fpga_region_of_match); - } - - of_node_put(child_region); - - if (ret) - pr_err("firmware-name not allowed in child FPGA region: %pOF", - child_region); - - return ret; -} - -/** - * fpga_region_notify_pre_apply - pre-apply overlay notification - * - * @region: FPGA region that the overlay was applied to - * @nd: overlay notification data - * - * Called after when an overlay targeted to a FPGA Region is about to be - * applied. Function will check the properties that will be added to the FPGA - * region. If the checks pass, it will program the FPGA. - * - * The checks are: - * The overlay must add either firmware-name or external-fpga-config property - * to the FPGA Region. - * - * firmware-name : program the FPGA - * external-fpga-config : FPGA is already programmed - * encrypted-fpga-config : FPGA bitstream is encrypted - * - * The overlay can add other FPGA regions, but child FPGA regions cannot have a - * firmware-name property since those regions don't exist yet. - * - * If the overlay that breaks the rules, notifier returns an error and the - * overlay is rejected before it goes into the main tree. - * - * Returns 0 for success or negative error code for failure. - */ -static int fpga_region_notify_pre_apply(struct fpga_region *region, - struct of_overlay_notify_data *nd) -{ - const char *firmware_name = NULL; - struct fpga_image_info *info; - int ret; - - info = devm_kzalloc(®ion->dev, sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - region->info = info; - - /* Reject overlay if child FPGA Regions have firmware-name property */ - ret = child_regions_with_firmware(nd->overlay); - if (ret) - return ret; - - /* Read FPGA region properties from the overlay */ - if (of_property_read_bool(nd->overlay, "partial-fpga-config")) - info->flags |= FPGA_MGR_PARTIAL_RECONFIG; - - if (of_property_read_bool(nd->overlay, "external-fpga-config")) - info->flags |= FPGA_MGR_EXTERNAL_CONFIG; - - if (of_property_read_bool(nd->overlay, "encrypted-fpga-config")) - info->flags |= FPGA_MGR_ENCRYPTED_BITSTREAM; - - of_property_read_string(nd->overlay, "firmware-name", &firmware_name); - - of_property_read_u32(nd->overlay, "region-unfreeze-timeout-us", - &info->enable_timeout_us); - - of_property_read_u32(nd->overlay, "region-freeze-timeout-us", - &info->disable_timeout_us); - - of_property_read_u32(nd->overlay, "config-complete-timeout-us", - &info->config_complete_timeout_us); - - /* If FPGA was externally programmed, don't specify firmware */ - if ((info->flags & FPGA_MGR_EXTERNAL_CONFIG) && firmware_name) { - pr_err("error: specified firmware and external-fpga-config"); - return -EINVAL; - } - - /* FPGA is already configured externally. We're done. */ - if (info->flags & FPGA_MGR_EXTERNAL_CONFIG) - return 0; - - /* If we got this far, we should be programming the FPGA */ - if (!firmware_name) { - pr_err("should specify firmware-name or external-fpga-config\n"); - return -EINVAL; - } - - return fpga_region_program_fpga(region, firmware_name, nd->overlay); -} - -/** - * fpga_region_notify_post_remove - post-remove overlay notification - * - * @region: FPGA region that was targeted by the overlay that was removed - * @nd: overlay notification data - * - * Called after an overlay has been removed if the overlay's target was a - * FPGA region. - */ -static void fpga_region_notify_post_remove(struct fpga_region *region, - struct of_overlay_notify_data *nd) -{ - fpga_bridges_disable(®ion->bridge_list); - fpga_bridges_put(®ion->bridge_list); - devm_kfree(®ion->dev, region->info); - region->info = NULL; -} - -/** - * of_fpga_region_notify - reconfig notifier for dynamic DT changes - * @nb: notifier block - * @action: notifier action - * @arg: reconfig data - * - * This notifier handles programming a FPGA when a "firmware-name" property is - * added to a fpga-region. - * - * Returns NOTIFY_OK or error if FPGA programming fails. - */ -static int of_fpga_region_notify(struct notifier_block *nb, - unsigned long action, void *arg) -{ - struct of_overlay_notify_data *nd = arg; - struct fpga_region *region; - int ret; - - switch (action) { - case OF_OVERLAY_PRE_APPLY: - pr_debug("%s OF_OVERLAY_PRE_APPLY\n", __func__); - break; - case OF_OVERLAY_POST_APPLY: - pr_debug("%s OF_OVERLAY_POST_APPLY\n", __func__); - return NOTIFY_OK; /* not for us */ - case OF_OVERLAY_PRE_REMOVE: - pr_debug("%s OF_OVERLAY_PRE_REMOVE\n", __func__); - return NOTIFY_OK; /* not for us */ - case OF_OVERLAY_POST_REMOVE: - pr_debug("%s OF_OVERLAY_POST_REMOVE\n", __func__); - break; - default: /* should not happen */ - return NOTIFY_OK; - } - - region = fpga_region_find(nd->target); - if (!region) - return NOTIFY_OK; - - ret = 0; - switch (action) { - case OF_OVERLAY_PRE_APPLY: - ret = fpga_region_notify_pre_apply(region, nd); - break; - - case OF_OVERLAY_POST_REMOVE: - fpga_region_notify_post_remove(region, nd); - break; - } - - put_device(®ion->dev); - - if (ret) - return notifier_from_errno(ret); - - return NOTIFY_OK; -} - -static struct notifier_block fpga_region_of_nb = { - .notifier_call = of_fpga_region_notify, -}; - -static int fpga_region_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - struct fpga_region *region; int id, ret = 0; - region = kzalloc(sizeof(*region), GFP_KERNEL); - if (!region) - return -ENOMEM; - id = ida_simple_get(&fpga_region_ida, 0, 0, GFP_KERNEL); - if (id < 0) { - ret = id; - goto err_kfree; - } + if (id < 0) + return id; mutex_init(®ion->mutex); INIT_LIST_HEAD(®ion->bridge_list); - device_initialize(®ion->dev); + region->dev.groups = region->groups; region->dev.class = fpga_region_class; region->dev.parent = dev; - region->dev.of_node = np; + region->dev.of_node = dev->of_node; region->dev.id = id; dev_set_drvdata(dev, region); @@ -524,44 +188,27 @@ static int fpga_region_probe(struct platform_device *pdev) if (ret) goto err_remove; - of_platform_populate(np, fpga_region_of_match, NULL, ®ion->dev); - - dev_info(dev, "FPGA Region probed\n"); - return 0; err_remove: ida_simple_remove(&fpga_region_ida, id); -err_kfree: - kfree(region); - return ret; } +EXPORT_SYMBOL_GPL(fpga_region_register); -static int fpga_region_remove(struct platform_device *pdev) +int fpga_region_unregister(struct fpga_region *region) { - struct fpga_region *region = platform_get_drvdata(pdev); - device_unregister(®ion->dev); return 0; } - -static struct platform_driver fpga_region_driver = { - .probe = fpga_region_probe, - .remove = fpga_region_remove, - .driver = { - .name = "fpga-region", - .of_match_table = of_match_ptr(fpga_region_of_match), - }, -}; +EXPORT_SYMBOL_GPL(fpga_region_unregister); static void fpga_region_dev_release(struct device *dev) { struct fpga_region *region = to_fpga_region(dev); ida_simple_remove(&fpga_region_ida, region->dev.id); - kfree(region); } /** @@ -570,36 +217,17 @@ static void fpga_region_dev_release(struct device *dev) */ static int __init fpga_region_init(void) { - int ret; - fpga_region_class = class_create(THIS_MODULE, "fpga_region"); if (IS_ERR(fpga_region_class)) return PTR_ERR(fpga_region_class); fpga_region_class->dev_release = fpga_region_dev_release; - ret = of_overlay_notifier_register(&fpga_region_of_nb); - if (ret) - goto err_class; - - ret = platform_driver_register(&fpga_region_driver); - if (ret) - goto err_plat; - return 0; - -err_plat: - of_overlay_notifier_unregister(&fpga_region_of_nb); -err_class: - class_destroy(fpga_region_class); - ida_destroy(&fpga_region_ida); - return ret; } static void __exit fpga_region_exit(void) { - platform_driver_unregister(&fpga_region_driver); - of_overlay_notifier_unregister(&fpga_region_of_nb); class_destroy(fpga_region_class); ida_destroy(&fpga_region_ida); } @@ -608,5 +236,5 @@ subsys_initcall(fpga_region_init); module_exit(fpga_region_exit); MODULE_DESCRIPTION("FPGA Region"); -MODULE_AUTHOR("Alan Tull "); +MODULE_AUTHOR("Alan Tull "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/fpga/of-fpga-region.c b/drivers/fpga/of-fpga-region.c new file mode 100644 index 000000000000..119ff75522f1 --- /dev/null +++ b/drivers/fpga/of-fpga-region.c @@ -0,0 +1,504 @@ +/* + * FPGA Region - Device Tree support for FPGA programming under Linux + * + * Copyright (C) 2013-2016 Altera Corporation + * Copyright (C) 2017 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct of_device_id fpga_region_of_match[] = { + { .compatible = "fpga-region", }, + {}, +}; +MODULE_DEVICE_TABLE(of, fpga_region_of_match); + +static int fpga_region_of_node_match(struct device *dev, const void *data) +{ + return dev->of_node == data; +} + +/** + * of_fpga_region_find - find FPGA region + * @np: device node of FPGA Region + * + * Caller will need to put_device(®ion->dev) when done. + * + * Returns FPGA Region struct or NULL + */ +static struct fpga_region *of_fpga_region_find(struct device_node *np) +{ + return fpga_region_class_find(NULL, np, fpga_region_of_node_match); +} + +/** + * of_fpga_region_get_mgr - get reference for FPGA manager + * @np: device node of FPGA region + * + * Get FPGA Manager from "fpga-mgr" property or from ancestor region. + * + * Caller should call fpga_mgr_put() when done with manager. + * + * Return: fpga manager struct or IS_ERR() condition containing error code. + */ +static struct fpga_manager *of_fpga_region_get_mgr(struct device_node *np) +{ + struct device_node *mgr_node; + struct fpga_manager *mgr; + + of_node_get(np); + while (np) { + if (of_device_is_compatible(np, "fpga-region")) { + mgr_node = of_parse_phandle(np, "fpga-mgr", 0); + if (mgr_node) { + mgr = of_fpga_mgr_get(mgr_node); + of_node_put(mgr_node); + of_node_put(np); + return mgr; + } + } + np = of_get_next_parent(np); + } + of_node_put(np); + + return ERR_PTR(-EINVAL); +} + +/** + * of_fpga_region_get_bridges - create a list of bridges + * @region: FPGA region + * + * Create a list of bridges including the parent bridge and the bridges + * specified by "fpga-bridges" property. Note that the + * fpga_bridges_enable/disable/put functions are all fine with an empty list + * if that happens. + * + * Caller should call fpga_bridges_put(®ion->bridge_list) when + * done with the bridges. + * + * Return 0 for success (even if there are no bridges specified) + * or -EBUSY if any of the bridges are in use. + */ +static int of_fpga_region_get_bridges(struct fpga_region *region) +{ + struct device *dev = ®ion->dev; + struct device_node *region_np = dev->of_node; + struct fpga_image_info *info = region->info; + struct device_node *br, *np, *parent_br = NULL; + int i, ret; + + /* If parent is a bridge, add to list */ + ret = of_fpga_bridge_get_to_list(region_np->parent, info, + ®ion->bridge_list); + + /* -EBUSY means parent is a bridge that is under use. Give up. */ + if (ret == -EBUSY) + return ret; + + /* Zero return code means parent was a bridge and was added to list. */ + if (!ret) + parent_br = region_np->parent; + + /* If overlay has a list of bridges, use it. */ + br = of_parse_phandle(info->overlay, "fpga-bridges", 0); + if (br) { + of_node_put(br); + np = info->overlay; + } else { + np = region_np; + } + + for (i = 0; ; i++) { + br = of_parse_phandle(np, "fpga-bridges", i); + if (!br) + break; + + /* If parent bridge is in list, skip it. */ + if (br == parent_br) { + of_node_put(br); + continue; + } + + /* If node is a bridge, get it and add to list */ + ret = of_fpga_bridge_get_to_list(br, info, + ®ion->bridge_list); + of_node_put(br); + + /* If any of the bridges are in use, give up */ + if (ret == -EBUSY) { + fpga_bridges_put(®ion->bridge_list); + return -EBUSY; + } + } + + return 0; +} + +/** + * child_regions_with_firmware + * @overlay: device node of the overlay + * + * If the overlay adds child FPGA regions, they are not allowed to have + * firmware-name property. + * + * Return 0 for OK or -EINVAL if child FPGA region adds firmware-name. + */ +static int child_regions_with_firmware(struct device_node *overlay) +{ + struct device_node *child_region; + const char *child_firmware_name; + int ret = 0; + + of_node_get(overlay); + + child_region = of_find_matching_node(overlay, fpga_region_of_match); + while (child_region) { + if (!of_property_read_string(child_region, "firmware-name", + &child_firmware_name)) { + ret = -EINVAL; + break; + } + child_region = of_find_matching_node(child_region, + fpga_region_of_match); + } + + of_node_put(child_region); + + if (ret) + pr_err("firmware-name not allowed in child FPGA region: %pOF", + child_region); + + return ret; +} + +/** + * of_fpga_region_parse_ov - parse and check overlay applied to region + * + * @region: FPGA region + * @overlay: overlay applied to the FPGA region + * + * Given an overlay applied to a FPGA region, parse the FPGA image specific + * info in the overlay and do some checking. + * + * Returns: + * NULL if overlay doesn't direct us to program the FPGA. + * fpga_image_info struct if there is an image to program. + * error code for invalid overlay. + */ +static struct fpga_image_info *of_fpga_region_parse_ov( + struct fpga_region *region, + struct device_node *overlay) +{ + struct device *dev = ®ion->dev; + struct fpga_image_info *info; + const char *firmware_name; + int ret; + + if (region->info) { + dev_err(dev, "Region already has overlay applied.\n"); + return ERR_PTR(-EINVAL); + } + + /* + * Reject overlay if child FPGA Regions added in the overlay have + * firmware-name property (would mean that an FPGA region that has + * not been added to the live tree yet is doing FPGA programming). + */ + ret = child_regions_with_firmware(overlay); + if (ret) + return ERR_PTR(ret); + + info = fpga_image_info_alloc(dev); + if (!info) + return ERR_PTR(-ENOMEM); + + info->overlay = overlay; + + /* Read FPGA region properties from the overlay */ + if (of_property_read_bool(overlay, "partial-fpga-config")) + info->flags |= FPGA_MGR_PARTIAL_RECONFIG; + + if (of_property_read_bool(overlay, "external-fpga-config")) + info->flags |= FPGA_MGR_EXTERNAL_CONFIG; + + if (of_property_read_bool(overlay, "encrypted-fpga-config")) + info->flags |= FPGA_MGR_ENCRYPTED_BITSTREAM; + + if (!of_property_read_string(overlay, "firmware-name", + &firmware_name)) { + info->firmware_name = devm_kstrdup(dev, firmware_name, + GFP_KERNEL); + if (!info->firmware_name) + return ERR_PTR(-ENOMEM); + } + + of_property_read_u32(overlay, "region-unfreeze-timeout-us", + &info->enable_timeout_us); + + of_property_read_u32(overlay, "region-freeze-timeout-us", + &info->disable_timeout_us); + + of_property_read_u32(overlay, "config-complete-timeout-us", + &info->config_complete_timeout_us); + + /* If overlay is not programming the FPGA, don't need FPGA image info */ + if (!info->firmware_name) { + ret = 0; + goto ret_no_info; + } + + /* + * If overlay informs us FPGA was externally programmed, specifying + * firmware here would be ambiguous. + */ + if (info->flags & FPGA_MGR_EXTERNAL_CONFIG) { + dev_err(dev, "error: specified firmware and external-fpga-config"); + ret = -EINVAL; + goto ret_no_info; + } + + return info; +ret_no_info: + fpga_image_info_free(info); + return ERR_PTR(ret); +} + +/** + * of_fpga_region_notify_pre_apply - pre-apply overlay notification + * + * @region: FPGA region that the overlay was applied to + * @nd: overlay notification data + * + * Called when an overlay targeted to a FPGA Region is about to be applied. + * Parses the overlay for properties that influence how the FPGA will be + * programmed and does some checking. If the checks pass, programs the FPGA. + * If the checks fail, overlay is rejected and does not get added to the + * live tree. + * + * Returns 0 for success or negative error code for failure. + */ +static int of_fpga_region_notify_pre_apply(struct fpga_region *region, + struct of_overlay_notify_data *nd) +{ + struct device *dev = ®ion->dev; + struct fpga_image_info *info; + int ret; + + info = of_fpga_region_parse_ov(region, nd->overlay); + if (IS_ERR(info)) + return PTR_ERR(info); + + /* If overlay doesn't program the FPGA, accept it anyway. */ + if (!info) + return 0; + + if (region->info) { + dev_err(dev, "Region already has overlay applied.\n"); + return -EINVAL; + } + + region->info = info; + ret = fpga_region_program_fpga(region); + if (ret) { + /* error; reject overlay */ + fpga_image_info_free(info); + region->info = NULL; + } + + return ret; +} + +/** + * of_fpga_region_notify_post_remove - post-remove overlay notification + * + * @region: FPGA region that was targeted by the overlay that was removed + * @nd: overlay notification data + * + * Called after an overlay has been removed if the overlay's target was a + * FPGA region. + */ +static void of_fpga_region_notify_post_remove(struct fpga_region *region, + struct of_overlay_notify_data *nd) +{ + fpga_bridges_disable(®ion->bridge_list); + fpga_bridges_put(®ion->bridge_list); + fpga_image_info_free(region->info); + region->info = NULL; +} + +/** + * of_fpga_region_notify - reconfig notifier for dynamic DT changes + * @nb: notifier block + * @action: notifier action + * @arg: reconfig data + * + * This notifier handles programming a FPGA when a "firmware-name" property is + * added to a fpga-region. + * + * Returns NOTIFY_OK or error if FPGA programming fails. + */ +static int of_fpga_region_notify(struct notifier_block *nb, + unsigned long action, void *arg) +{ + struct of_overlay_notify_data *nd = arg; + struct fpga_region *region; + int ret; + + switch (action) { + case OF_OVERLAY_PRE_APPLY: + pr_debug("%s OF_OVERLAY_PRE_APPLY\n", __func__); + break; + case OF_OVERLAY_POST_APPLY: + pr_debug("%s OF_OVERLAY_POST_APPLY\n", __func__); + return NOTIFY_OK; /* not for us */ + case OF_OVERLAY_PRE_REMOVE: + pr_debug("%s OF_OVERLAY_PRE_REMOVE\n", __func__); + return NOTIFY_OK; /* not for us */ + case OF_OVERLAY_POST_REMOVE: + pr_debug("%s OF_OVERLAY_POST_REMOVE\n", __func__); + break; + default: /* should not happen */ + return NOTIFY_OK; + } + + region = of_fpga_region_find(nd->target); + if (!region) + return NOTIFY_OK; + + ret = 0; + switch (action) { + case OF_OVERLAY_PRE_APPLY: + ret = of_fpga_region_notify_pre_apply(region, nd); + break; + + case OF_OVERLAY_POST_REMOVE: + of_fpga_region_notify_post_remove(region, nd); + break; + } + + put_device(®ion->dev); + + if (ret) + return notifier_from_errno(ret); + + return NOTIFY_OK; +} + +static struct notifier_block fpga_region_of_nb = { + .notifier_call = of_fpga_region_notify, +}; + +static int of_fpga_region_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct fpga_region *region; + struct fpga_manager *mgr; + int ret; + + /* Find the FPGA mgr specified by region or parent region. */ + mgr = of_fpga_region_get_mgr(np); + if (IS_ERR(mgr)) + return -EPROBE_DEFER; + + region = devm_kzalloc(dev, sizeof(*region), GFP_KERNEL); + if (!region) { + ret = -ENOMEM; + goto eprobe_mgr_put; + } + + region->mgr = mgr; + + /* Specify how to get bridges for this type of region. */ + region->get_bridges = of_fpga_region_get_bridges; + + ret = fpga_region_register(dev, region); + if (ret) + goto eprobe_mgr_put; + + of_platform_populate(np, fpga_region_of_match, NULL, ®ion->dev); + + dev_info(dev, "FPGA Region probed\n"); + + return 0; + +eprobe_mgr_put: + fpga_mgr_put(mgr); + return ret; +} + +static int of_fpga_region_remove(struct platform_device *pdev) +{ + struct fpga_region *region = platform_get_drvdata(pdev); + + fpga_region_unregister(region); + fpga_mgr_put(region->mgr); + + return 0; +} + +static struct platform_driver of_fpga_region_driver = { + .probe = of_fpga_region_probe, + .remove = of_fpga_region_remove, + .driver = { + .name = "of-fpga-region", + .of_match_table = of_match_ptr(fpga_region_of_match), + }, +}; + +/** + * fpga_region_init - init function for fpga_region class + * Creates the fpga_region class and registers a reconfig notifier. + */ +static int __init of_fpga_region_init(void) +{ + int ret; + + ret = of_overlay_notifier_register(&fpga_region_of_nb); + if (ret) + return ret; + + ret = platform_driver_register(&of_fpga_region_driver); + if (ret) + goto err_plat; + + return 0; + +err_plat: + of_overlay_notifier_unregister(&fpga_region_of_nb); + return ret; +} + +static void __exit of_fpga_region_exit(void) +{ + platform_driver_unregister(&of_fpga_region_driver); + of_overlay_notifier_unregister(&fpga_region_of_nb); +} + +subsys_initcall(of_fpga_region_init); +module_exit(of_fpga_region_exit); + +MODULE_DESCRIPTION("FPGA Region"); +MODULE_AUTHOR("Alan Tull "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/fpga/socfpga-a10.c b/drivers/fpga/socfpga-a10.c index f8770af0f6b5..a46e343a5b72 100644 --- a/drivers/fpga/socfpga-a10.c +++ b/drivers/fpga/socfpga-a10.c @@ -519,8 +519,14 @@ static int socfpga_a10_fpga_probe(struct platform_device *pdev) return -EBUSY; } - return fpga_mgr_register(dev, "SoCFPGA Arria10 FPGA Manager", + ret = fpga_mgr_register(dev, "SoCFPGA Arria10 FPGA Manager", &socfpga_a10_fpga_mgr_ops, priv); + if (ret) { + clk_disable_unprepare(priv->clk); + return ret; + } + + return 0; } static int socfpga_a10_fpga_remove(struct platform_device *pdev) diff --git a/drivers/fsi/Kconfig b/drivers/fsi/Kconfig index 6821ed0cd5e8..513e35173aaa 100644 --- a/drivers/fsi/Kconfig +++ b/drivers/fsi/Kconfig @@ -2,9 +2,7 @@ # FSI subsystem # -menu "FSI support" - -config FSI +menuconfig FSI tristate "FSI support" select CRC4 ---help--- @@ -34,5 +32,3 @@ config FSI_SCOM This option enables an FSI based SCOM device driver. endif - -endmenu diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d6a8e851ad13..8dbb2280538d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -122,12 +122,6 @@ config GPIO_ATH79 Select this option to enable GPIO driver for Atheros AR71XX/AR724X/AR913X SoC devices. -config GPIO_AXP209 - tristate "X-Powers AXP209 PMIC GPIO Support" - depends on MFD_AXP20X - help - Say yes to enable GPIO support for the AXP209 PMIC - config GPIO_BCM_KONA bool "Broadcom Kona GPIO" depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST) @@ -704,6 +698,22 @@ config GPIO_TS5500 blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600 LCD port. +config GPIO_WINBOND + tristate "Winbond Super I/O GPIO support" + depends on ISA_BUS_API + help + This option enables support for GPIOs found on Winbond Super I/O + chips. + Currently, only W83627UHG (also known as Nuvoton NCT6627UD) is + supported. + + You will need to provide a module parameter "gpios", or a + boot-time parameter "gpio_winbond.gpios" with a bitmask of GPIO + ports to enable (bit 0 is GPIO1, bit 1 is GPIO2, etc.). + + To compile this driver as a module, choose M here: the module will + be called gpio-winbond. + config GPIO_WS16C48 tristate "WinSystems WS16C48 GPIO support" depends on ISA_BUS_API @@ -1234,6 +1244,16 @@ config GPIO_PCI_IDIO_16 low). Input filter control is not supported by this driver, and the input filters are deactivated by this driver. +config GPIO_PCIE_IDIO_24 + tristate "ACCES PCIe-IDIO-24 GPIO support" + select GPIOLIB_IRQCHIP + help + Enables GPIO support for the ACCES PCIe-IDIO-24 family (PCIe-IDIO-24, + PCIe-IDI-24, PCIe-IDO-24, PCIe-IDIO-12). An interrupt is generated + when any of the inputs change state (low to high or high to low). + Input filter control is not supported by this driver, and the input + filters are deactivated by this driver. + config GPIO_RDC321X tristate "RDC R-321x GPIO support" select MFD_CORE diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 4bc24febb889..cccb0d40846c 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -32,7 +32,6 @@ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o -obj-$(CONFIG_GPIO_AXP209) += gpio-axp209.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o @@ -96,6 +95,7 @@ obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o obj-$(CONFIG_GPIO_PCH) += gpio-pch.o obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o +obj-$(CONFIG_GPIO_PCIE_IDIO_24) += gpio-pcie-idio-24.o obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o @@ -140,6 +140,7 @@ obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.o +obj-$(CONFIG_GPIO_WINBOND) += gpio-winbond.o obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index afbff155a0ba..e82cc763633c 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -124,6 +124,48 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, } EXPORT_SYMBOL(devm_gpiod_get_index); +/** + * devm_gpiod_get_from_of_node() - obtain a GPIO from an OF node + * @dev: device for lifecycle management + * @node: handle of the OF node + * @propname: name of the DT property representing the GPIO + * @index: index of the GPIO to obtain for the consumer + * @dflags: GPIO initialization flags + * @label: label to attach to the requested GPIO + * + * Returns: + * On successful request the GPIO pin is configured in accordance with + * provided @dflags. + * + * In case of error an ERR_PTR() is returned. + */ +struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev, + struct device_node *node, + const char *propname, int index, + enum gpiod_flags dflags, + const char *label) +{ + struct gpio_desc **dr; + struct gpio_desc *desc; + + dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *), + GFP_KERNEL); + if (!dr) + return ERR_PTR(-ENOMEM); + + desc = gpiod_get_from_of_node(node, propname, index, dflags, label); + if (IS_ERR(desc)) { + devres_free(dr); + return desc; + } + + *dr = desc; + devres_add(dev, dr); + + return desc; +} +EXPORT_SYMBOL(devm_gpiod_get_from_of_node); + /** * devm_fwnode_get_index_gpiod_from_child - get a GPIO descriptor from a * device's child node diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index 15a1f4b348c4..fb7b620763a2 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -9,12 +9,11 @@ * published by the Free Software Foundation. */ -#include #include #include #include -#include -#include +#include +#include #include #include diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c index abf199609546..21452622d954 100644 --- a/drivers/gpio/gpio-adp5520.c +++ b/drivers/gpio/gpio-adp5520.c @@ -12,8 +12,7 @@ #include #include #include - -#include +#include struct adp5520_gpio { struct device *master; diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index e717f8dc3966..3530ccd17e04 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c index 8e76d390e653..8c3ff6e2366f 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -18,7 +18,8 @@ #include #include -#include +#include +#include /* For of_mm_gpio_chip */ #include #define ALTERA_GPIO_MAX_NGPIO 32 diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c index 30ad7d7c1678..fdcebe59510d 100644 --- a/drivers/gpio/gpio-amd8111.c +++ b/drivers/gpio/gpio-amd8111.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index d4e6ba0301bc..ba51ea15f379 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index 6b3ca6601af2..77e485557498 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -60,6 +60,7 @@ struct aspeed_gpio_bank { uint16_t val_regs; uint16_t irq_regs; uint16_t debounce_regs; + uint16_t tolerance_regs; const char names[4][3]; }; @@ -70,48 +71,56 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .val_regs = 0x0000, .irq_regs = 0x0008, .debounce_regs = 0x0040, + .tolerance_regs = 0x001c, .names = { "A", "B", "C", "D" }, }, { .val_regs = 0x0020, .irq_regs = 0x0028, .debounce_regs = 0x0048, + .tolerance_regs = 0x003c, .names = { "E", "F", "G", "H" }, }, { .val_regs = 0x0070, .irq_regs = 0x0098, .debounce_regs = 0x00b0, + .tolerance_regs = 0x00ac, .names = { "I", "J", "K", "L" }, }, { .val_regs = 0x0078, .irq_regs = 0x00e8, .debounce_regs = 0x0100, + .tolerance_regs = 0x00fc, .names = { "M", "N", "O", "P" }, }, { .val_regs = 0x0080, .irq_regs = 0x0118, .debounce_regs = 0x0130, + .tolerance_regs = 0x012c, .names = { "Q", "R", "S", "T" }, }, { .val_regs = 0x0088, .irq_regs = 0x0148, .debounce_regs = 0x0160, + .tolerance_regs = 0x015c, .names = { "U", "V", "W", "X" }, }, { .val_regs = 0x01E0, .irq_regs = 0x0178, .debounce_regs = 0x0190, + .tolerance_regs = 0x018c, .names = { "Y", "Z", "AA", "AB" }, }, { - .val_regs = 0x01E8, - .irq_regs = 0x01A8, + .val_regs = 0x01e8, + .irq_regs = 0x01a8, .debounce_regs = 0x01c0, + .tolerance_regs = 0x01bc, .names = { "AC", "", "", "" }, }, }; @@ -140,7 +149,7 @@ static const struct aspeed_gpio_bank *to_bank(unsigned int offset) { unsigned int bank = GPIO_BANK(offset); - WARN_ON(bank > ARRAY_SIZE(aspeed_gpio_banks)); + WARN_ON(bank >= ARRAY_SIZE(aspeed_gpio_banks)); return &aspeed_gpio_banks[bank]; } @@ -534,6 +543,30 @@ static int aspeed_gpio_setup_irqs(struct aspeed_gpio *gpio, return 0; } +static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip, + unsigned int offset, bool enable) +{ + struct aspeed_gpio *gpio = gpiochip_get_data(chip); + const struct aspeed_gpio_bank *bank; + unsigned long flags; + u32 val; + + bank = to_bank(offset); + + spin_lock_irqsave(&gpio->lock, flags); + val = readl(gpio->base + bank->tolerance_regs); + + if (enable) + val |= GPIO_BIT(offset); + else + val &= ~GPIO_BIT(offset); + + writel(val, gpio->base + bank->tolerance_regs); + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + static int aspeed_gpio_request(struct gpio_chip *chip, unsigned int offset) { if (!have_gpio(gpiochip_get_data(chip), offset)) @@ -771,6 +804,8 @@ static int aspeed_gpio_set_config(struct gpio_chip *chip, unsigned int offset, param == PIN_CONFIG_DRIVE_OPEN_SOURCE) /* Return -ENOTSUPP to trigger emulation, as per datasheet */ return -ENOTSUPP; + else if (param == PIN_CONFIG_PERSIST_STATE) + return aspeed_gpio_reset_tolerance(chip, offset, arg); return -ENOTSUPP; } diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c index 5fad89dfab7e..3ae7c1876bf4 100644 --- a/drivers/gpio/gpio-ath79.c +++ b/drivers/gpio/gpio-ath79.c @@ -324,3 +324,6 @@ static struct platform_driver ath79_gpio_driver = { }; module_platform_driver(ath79_gpio_driver); + +MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X GPIO API support"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-axp209.c b/drivers/gpio/gpio-axp209.c deleted file mode 100644 index 4a346b7b4172..000000000000 --- a/drivers/gpio/gpio-axp209.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * AXP20x GPIO driver - * - * Copyright (C) 2016 Maxime Ripard - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define AXP20X_GPIO_FUNCTIONS 0x7 -#define AXP20X_GPIO_FUNCTION_OUT_LOW 0 -#define AXP20X_GPIO_FUNCTION_OUT_HIGH 1 -#define AXP20X_GPIO_FUNCTION_INPUT 2 - -struct axp20x_gpio { - struct gpio_chip chip; - struct regmap *regmap; -}; - -static int axp20x_gpio_get_reg(unsigned offset) -{ - switch (offset) { - case 0: - return AXP20X_GPIO0_CTRL; - case 1: - return AXP20X_GPIO1_CTRL; - case 2: - return AXP20X_GPIO2_CTRL; - } - - return -EINVAL; -} - -static int axp20x_gpio_input(struct gpio_chip *chip, unsigned offset) -{ - struct axp20x_gpio *gpio = gpiochip_get_data(chip); - int reg; - - reg = axp20x_gpio_get_reg(offset); - if (reg < 0) - return reg; - - return regmap_update_bits(gpio->regmap, reg, - AXP20X_GPIO_FUNCTIONS, - AXP20X_GPIO_FUNCTION_INPUT); -} - -static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - struct axp20x_gpio *gpio = gpiochip_get_data(chip); - unsigned int val; - int ret; - - ret = regmap_read(gpio->regmap, AXP20X_GPIO20_SS, &val); - if (ret) - return ret; - - return !!(val & BIT(offset + 4)); -} - -static int axp20x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) -{ - struct axp20x_gpio *gpio = gpiochip_get_data(chip); - unsigned int val; - int reg, ret; - - reg = axp20x_gpio_get_reg(offset); - if (reg < 0) - return reg; - - ret = regmap_read(gpio->regmap, reg, &val); - if (ret) - return ret; - - /* - * This shouldn't really happen if the pin is in use already, - * or if it's not in use yet, it doesn't matter since we're - * going to change the value soon anyway. Default to output. - */ - if ((val & AXP20X_GPIO_FUNCTIONS) > 2) - return 0; - - /* - * The GPIO directions are the three lowest values. - * 2 is input, 0 and 1 are output - */ - return val & 2; -} - -static int axp20x_gpio_output(struct gpio_chip *chip, unsigned offset, - int value) -{ - struct axp20x_gpio *gpio = gpiochip_get_data(chip); - int reg; - - reg = axp20x_gpio_get_reg(offset); - if (reg < 0) - return reg; - - return regmap_update_bits(gpio->regmap, reg, - AXP20X_GPIO_FUNCTIONS, - value ? AXP20X_GPIO_FUNCTION_OUT_HIGH - : AXP20X_GPIO_FUNCTION_OUT_LOW); -} - -static void axp20x_gpio_set(struct gpio_chip *chip, unsigned offset, - int value) -{ - axp20x_gpio_output(chip, offset, value); -} - -static int axp20x_gpio_probe(struct platform_device *pdev) -{ - struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); - struct axp20x_gpio *gpio; - int ret; - - if (!of_device_is_available(pdev->dev.of_node)) - return -ENODEV; - - if (!axp20x) { - dev_err(&pdev->dev, "Parent drvdata not set\n"); - return -EINVAL; - } - - gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); - if (!gpio) - return -ENOMEM; - - gpio->chip.base = -1; - gpio->chip.can_sleep = true; - gpio->chip.parent = &pdev->dev; - gpio->chip.label = dev_name(&pdev->dev); - gpio->chip.owner = THIS_MODULE; - gpio->chip.get = axp20x_gpio_get; - gpio->chip.get_direction = axp20x_gpio_get_direction; - gpio->chip.set = axp20x_gpio_set; - gpio->chip.direction_input = axp20x_gpio_input; - gpio->chip.direction_output = axp20x_gpio_output; - gpio->chip.ngpio = 3; - - gpio->regmap = axp20x->regmap; - - ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); - if (ret) { - dev_err(&pdev->dev, "Failed to register GPIO chip\n"); - return ret; - } - - dev_info(&pdev->dev, "AXP209 GPIO driver loaded\n"); - - return 0; -} - -static const struct of_device_id axp20x_gpio_match[] = { - { .compatible = "x-powers,axp209-gpio" }, - { } -}; -MODULE_DEVICE_TABLE(of, axp20x_gpio_match); - -static struct platform_driver axp20x_gpio_driver = { - .probe = axp20x_gpio_probe, - .driver = { - .name = "axp20x-gpio", - .of_match_table = axp20x_gpio_match, - }, -}; - -module_platform_driver(axp20x_gpio_driver); - -MODULE_AUTHOR("Maxime Ripard "); -MODULE_DESCRIPTION("AXP20x PMIC GPIO driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 76861a00bb92..eb8369b21e90 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -127,7 +127,7 @@ static int bcm_kona_gpio_get_dir(struct gpio_chip *chip, unsigned gpio) u32 val; val = readl(reg_base + GPIO_CONTROL(gpio)) & GPIO_GPCTR0_IOTR_MASK; - return val ? GPIOF_DIR_IN : GPIOF_DIR_OUT; + return !!val; } static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) @@ -144,7 +144,7 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) raw_spin_lock_irqsave(&kona_gpio->lock, flags); /* this function only applies to output pin */ - if (bcm_kona_gpio_get_dir(chip, gpio) == GPIOF_DIR_IN) + if (bcm_kona_gpio_get_dir(chip, gpio) == 1) goto out; reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id); @@ -170,7 +170,7 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) reg_base = kona_gpio->reg_base; raw_spin_lock_irqsave(&kona_gpio->lock, flags); - if (bcm_kona_gpio_get_dir(chip, gpio) == GPIOF_DIR_IN) + if (bcm_kona_gpio_get_dir(chip, gpio) == 1) reg_offset = GPIO_IN_STATUS(bank_id); else reg_offset = GPIO_OUT_STATUS(bank_id); diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index bb4f8cf18bd9..16c7f9f49416 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -19,7 +19,6 @@ #include #include #include -#include enum gio_reg_index { GIO_REG_ODEN = 0, diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c index acefb25e8eca..b8ec75cbd4b5 100644 --- a/drivers/gpio/gpio-bt8xx.c +++ b/drivers/gpio/gpio-bt8xx.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include /* Steal the hardware definitions from the bttv driver. */ diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c index b6f0f729656c..58531d8b8c6e 100644 --- a/drivers/gpio/gpio-crystalcove.c +++ b/drivers/gpio/gpio-crystalcove.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/gpio/gpio-cs5535.c b/drivers/gpio/gpio-cs5535.c index 90278b19aa0e..8814c8f47e57 100644 --- a/drivers/gpio/gpio-cs5535.c +++ b/drivers/gpio/gpio-cs5535.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c index dd8977cf3e85..b6d3e997eb26 100644 --- a/drivers/gpio/gpio-da9052.c +++ b/drivers/gpio/gpio-da9052.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c index 82053b52cba0..2f1b5d23b10c 100644 --- a/drivers/gpio/gpio-da9055.c +++ b/drivers/gpio/gpio-da9055.c @@ -13,7 +13,7 @@ */ #include #include -#include +#include #include #include diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index e4b3d7db68c9..0b951ca78ec4 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -9,7 +9,7 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ -#include +#include #include #include #include diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c index 7b3394fdc624..b7a3a2db699b 100644 --- a/drivers/gpio/gpio-ftgpio010.c +++ b/drivers/gpio/gpio-ftgpio010.c @@ -176,8 +176,8 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) return PTR_ERR(g->base); irq = platform_get_irq(pdev, 0); - if (!irq) - return -EINVAL; + if (irq <= 0) + return irq ? irq : -EINVAL; ret = bgpio_init(&g->gc, dev, 4, g->base + GPIO_DATA_IN, diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c index 98c7ff2a76e7..8d62db447ec1 100644 --- a/drivers/gpio/gpio-iop.c +++ b/drivers/gpio/gpio-iop.c @@ -58,3 +58,7 @@ static int __init iop3xx_gpio_init(void) return platform_driver_register(&iop3xx_gpio_driver); } arch_initcall(iop3xx_gpio_init); + +MODULE_DESCRIPTION("GPIO handling for Intel IOP3xx processors"); +MODULE_AUTHOR("Lennert Buytenhek "); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-it87.c b/drivers/gpio/gpio-it87.c index d43d0a2cc4c5..efb46edff81f 100644 --- a/drivers/gpio/gpio-it87.c +++ b/drivers/gpio/gpio-it87.c @@ -414,6 +414,6 @@ static void __exit it87_gpio_exit(void) module_init(it87_gpio_init); module_exit(it87_gpio_exit); -MODULE_AUTHOR("Diego Elio Pettenò "); +MODULE_AUTHOR("Diego Elio Pettenò "); MODULE_DESCRIPTION("GPIO interface for IT87xx Super I/O chips"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index c04fae1ba32a..9d8bcc69f245 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -709,8 +709,7 @@ static int max732x_probe(struct i2c_client *client, return 0; out_failed: - if (chip->client_dummy) - i2c_unregister_device(chip->client_dummy); + i2c_unregister_device(chip->client_dummy); return ret; } @@ -734,8 +733,7 @@ static int max732x_remove(struct i2c_client *client) gpiochip_remove(&chip->gpio_chip); /* unregister any dummy i2c_client */ - if (chip->client_dummy) - i2c_unregister_device(chip->client_dummy); + i2c_unregister_device(chip->client_dummy); return 0; } diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index dd67a31ac337..c38624ea0251 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -380,9 +381,16 @@ static void mrfld_irq_init_hw(struct mrfld_gpio *priv) } } +static const char *mrfld_gpio_get_pinctrl_dev_name(void) +{ + const char *dev_name = acpi_dev_get_first_match_name("INTC1002", NULL, -1); + return dev_name ? dev_name : "pinctrl-merrifield"; +} + static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) { const struct mrfld_gpio_pinrange *range; + const char *pinctrl_dev_name; struct mrfld_gpio *priv; u32 gpio_base, irq_base; void __iomem *base; @@ -439,10 +447,11 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id return retval; } + pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(); for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) { range = &mrfld_gpio_ranges[i]; retval = gpiochip_add_pin_range(&priv->chip, - "pinctrl-merrifield", + pinctrl_dev_name, range->gpio_base, range->pin_base, range->npins); diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index f9042bcc27a4..7b14d6280e44 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -152,14 +152,13 @@ static int bgpio_get_set_multiple(struct gpio_chip *gc, unsigned long *mask, { unsigned long get_mask = 0; unsigned long set_mask = 0; - int bit = 0; - while ((bit = find_next_bit(mask, gc->ngpio, bit)) != gc->ngpio) { - if (gc->bgpio_dir & BIT(bit)) - set_mask |= BIT(bit); - else - get_mask |= BIT(bit); - } + /* Make sure we first clear any bits that are zero when we read the register */ + *bits &= ~*mask; + + /* Exploit the fact that we know which directions are set */ + set_mask = *mask & gc->bgpio_dir; + get_mask = *mask & ~gc->bgpio_dir; if (set_mask) *bits |= gc->read_reg(gc->reg_set) & set_mask; @@ -176,13 +175,13 @@ static int bgpio_get(struct gpio_chip *gc, unsigned int gpio) /* * This only works if the bits in the GPIO register are in native endianness. - * It is dirt simple and fast in this case. (Also the most common case.) */ static int bgpio_get_multiple(struct gpio_chip *gc, unsigned long *mask, unsigned long *bits) { - - *bits = gc->read_reg(gc->reg_dat) & *mask; + /* Make sure we first clear any bits that are zero when we read the register */ + *bits &= ~*mask; + *bits |= gc->read_reg(gc->reg_dat) & *mask; return 0; } @@ -196,9 +195,12 @@ static int bgpio_get_multiple_be(struct gpio_chip *gc, unsigned long *mask, unsigned long val; int bit; + /* Make sure we first clear any bits that are zero when we read the register */ + *bits &= ~*mask; + /* Create a mirrored mask */ - bit = 0; - while ((bit = find_next_bit(mask, gc->ngpio, bit)) != gc->ngpio) + bit = -1; + while ((bit = find_next_bit(mask, gc->ngpio, bit + 1)) < gc->ngpio) readmask |= bgpio_line2mask(gc, bit); /* Read the register */ @@ -208,8 +210,8 @@ static int bgpio_get_multiple_be(struct gpio_chip *gc, unsigned long *mask, * Mirror the result into the "bits" result, this will give line 0 * in bit 0 ... line 31 in bit 31 for a 32bit register. */ - bit = 0; - while ((bit = find_next_bit(&val, gc->ngpio, bit)) != gc->ngpio) + bit = -1; + while ((bit = find_next_bit(&val, gc->ngpio, bit + 1)) < gc->ngpio) *bits |= bgpio_line2mask(gc, bit); return 0; diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 9532d86a82f7..3a545ad17817 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -27,13 +27,15 @@ #include "gpiolib.h" #define GPIO_MOCKUP_NAME "gpio-mockup" -#define GPIO_MOCKUP_MAX_GC 10 +#define GPIO_MOCKUP_MAX_GC 10 /* * We're storing two values per chip: the GPIO base and the number * of GPIO lines. */ #define GPIO_MOCKUP_MAX_RANGES (GPIO_MOCKUP_MAX_GC * 2) +#define gpio_mockup_err(...) pr_err(GPIO_MOCKUP_NAME ": " __VA_ARGS__) + enum { GPIO_MOCKUP_DIR_OUT = 0, GPIO_MOCKUP_DIR_IN = 1, @@ -46,7 +48,7 @@ enum { */ struct gpio_mockup_line_status { int dir; - bool value; + int value; }; struct gpio_mockup_chip { @@ -62,17 +64,33 @@ struct gpio_mockup_dbgfs_private { int offset; }; +struct gpio_mockup_platform_data { + int base; + int ngpio; + int index; + bool named_lines; +}; + static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_RANGES]; -static int gpio_mockup_params_nr; -module_param_array(gpio_mockup_ranges, int, &gpio_mockup_params_nr, 0400); +static int gpio_mockup_num_ranges; +module_param_array(gpio_mockup_ranges, int, &gpio_mockup_num_ranges, 0400); static bool gpio_mockup_named_lines; module_param_named(gpio_mockup_named_lines, gpio_mockup_named_lines, bool, 0400); -static const char gpio_mockup_name_start = 'A'; static struct dentry *gpio_mockup_dbg_dir; +static int gpio_mockup_range_base(unsigned int index) +{ + return gpio_mockup_ranges[index * 2]; +} + +static int gpio_mockup_range_ngpio(unsigned int index) +{ + return gpio_mockup_ranges[index * 2 + 1]; +} + static int gpio_mockup_get(struct gpio_chip *gc, unsigned int offset) { struct gpio_mockup_chip *chip = gpiochip_get_data(gc); @@ -80,16 +98,26 @@ static int gpio_mockup_get(struct gpio_chip *gc, unsigned int offset) return chip->lines[offset].value; } -static void gpio_mockup_set(struct gpio_chip *gc, unsigned int offset, - int value) +static void gpio_mockup_set(struct gpio_chip *gc, + unsigned int offset, int value) { struct gpio_mockup_chip *chip = gpiochip_get_data(gc); chip->lines[offset].value = !!value; } -static int gpio_mockup_dirout(struct gpio_chip *gc, unsigned int offset, - int value) +static void gpio_mockup_set_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) +{ + unsigned int bit; + + for_each_set_bit(bit, mask, gc->ngpio) + gpio_mockup_set(gc, bit, test_bit(bit, bits)); + +} + +static int gpio_mockup_dirout(struct gpio_chip *gc, + unsigned int offset, int value) { struct gpio_mockup_chip *chip = gpiochip_get_data(gc); @@ -115,29 +143,6 @@ static int gpio_mockup_get_direction(struct gpio_chip *gc, unsigned int offset) return chip->lines[offset].dir; } -static int gpio_mockup_name_lines(struct device *dev, - struct gpio_mockup_chip *chip) -{ - struct gpio_chip *gc = &chip->gc; - char **names; - int i; - - names = devm_kcalloc(dev, gc->ngpio, sizeof(char *), GFP_KERNEL); - if (!names) - return -ENOMEM; - - for (i = 0; i < gc->ngpio; i++) { - names[i] = devm_kasprintf(dev, GFP_KERNEL, - "%s-%d", gc->label, i); - if (!names[i]) - return -ENOMEM; - } - - gc->names = (const char *const *)names; - - return 0; -} - static int gpio_mockup_to_irq(struct gpio_chip *gc, unsigned int offset) { struct gpio_mockup_chip *chip = gpiochip_get_data(gc); @@ -188,15 +193,21 @@ static void gpio_mockup_debugfs_setup(struct device *dev, struct gpio_mockup_chip *chip) { struct gpio_mockup_dbgfs_private *priv; - struct dentry *evfile; + struct dentry *evfile, *link; struct gpio_chip *gc; + const char *devname; char *name; int i; gc = &chip->gc; + devname = dev_name(&gc->gpiodev->dev); - chip->dbg_dir = debugfs_create_dir(gc->label, gpio_mockup_dbg_dir); - if (!chip->dbg_dir) + chip->dbg_dir = debugfs_create_dir(devname, gpio_mockup_dbg_dir); + if (IS_ERR_OR_NULL(chip->dbg_dir)) + goto err; + + link = debugfs_create_symlink(gc->label, gpio_mockup_dbg_dir, devname); + if (IS_ERR_OR_NULL(link)) goto err; for (i = 0; i < gc->ngpio; i++) { @@ -214,23 +225,63 @@ static void gpio_mockup_debugfs_setup(struct device *dev, evfile = debugfs_create_file(name, 0200, chip->dbg_dir, priv, &gpio_mockup_event_ops); - if (!evfile) + if (IS_ERR_OR_NULL(evfile)) goto err; } return; err: - dev_err(dev, "error creating debugfs directory\n"); + dev_err(dev, "error creating debugfs event files\n"); } -static int gpio_mockup_add(struct device *dev, - struct gpio_mockup_chip *chip, - const char *name, int base, int ngpio) +static int gpio_mockup_name_lines(struct device *dev, + struct gpio_mockup_chip *chip) { struct gpio_chip *gc = &chip->gc; - int ret; + char **names; + int i; + names = devm_kcalloc(dev, gc->ngpio, sizeof(char *), GFP_KERNEL); + if (!names) + return -ENOMEM; + + for (i = 0; i < gc->ngpio; i++) { + names[i] = devm_kasprintf(dev, GFP_KERNEL, + "%s-%d", gc->label, i); + if (!names[i]) + return -ENOMEM; + } + + gc->names = (const char *const *)names; + + return 0; +} + +static int gpio_mockup_probe(struct platform_device *pdev) +{ + struct gpio_mockup_platform_data *pdata; + struct gpio_mockup_chip *chip; + struct gpio_chip *gc; + int rv, base, ngpio; + struct device *dev; + char *name; + + dev = &pdev->dev; + pdata = dev_get_platdata(dev); + base = pdata->base; + ngpio = pdata->ngpio; + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + name = devm_kasprintf(dev, GFP_KERNEL, "%s-%c", + pdev->name, pdata->index); + if (!name) + return -ENOMEM; + + gc = &chip->gc; gc->base = base; gc->ngpio = ngpio; gc->label = name; @@ -238,6 +289,7 @@ static int gpio_mockup_add(struct device *dev, gc->parent = dev; gc->get = gpio_mockup_get; gc->set = gpio_mockup_set; + gc->set_multiple = gpio_mockup_set_multiple; gc->direction_output = gpio_mockup_dirout; gc->direction_input = gpio_mockup_dirin; gc->get_direction = gpio_mockup_get_direction; @@ -248,19 +300,19 @@ static int gpio_mockup_add(struct device *dev, if (!chip->lines) return -ENOMEM; - if (gpio_mockup_named_lines) { - ret = gpio_mockup_name_lines(dev, chip); - if (ret) - return ret; + if (pdata->named_lines) { + rv = gpio_mockup_name_lines(dev, chip); + if (rv) + return rv; } - ret = devm_irq_sim_init(dev, &chip->irqsim, gc->ngpio); - if (ret) - return ret; + rv = devm_irq_sim_init(dev, &chip->irqsim, gc->ngpio); + if (rv < 0) + return rv; - ret = devm_gpiochip_add_data(dev, &chip->gc, chip); - if (ret) - return ret; + rv = devm_gpiochip_add_data(dev, &chip->gc, chip); + if (rv) + return rv; if (gpio_mockup_dbg_dir) gpio_mockup_debugfs_setup(dev, chip); @@ -268,58 +320,6 @@ static int gpio_mockup_add(struct device *dev, return 0; } -static int gpio_mockup_probe(struct platform_device *pdev) -{ - int ret, i, base, ngpio, num_chips; - struct device *dev = &pdev->dev; - struct gpio_mockup_chip *chips; - char *chip_name; - - if (gpio_mockup_params_nr < 2 || (gpio_mockup_params_nr % 2)) - return -EINVAL; - - /* Each chip is described by two values. */ - num_chips = gpio_mockup_params_nr / 2; - - chips = devm_kcalloc(dev, num_chips, sizeof(*chips), GFP_KERNEL); - if (!chips) - return -ENOMEM; - - platform_set_drvdata(pdev, chips); - - for (i = 0; i < num_chips; i++) { - base = gpio_mockup_ranges[i * 2]; - - if (base == -1) - ngpio = gpio_mockup_ranges[i * 2 + 1]; - else - ngpio = gpio_mockup_ranges[i * 2 + 1] - base; - - if (ngpio >= 0) { - chip_name = devm_kasprintf(dev, GFP_KERNEL, - "%s-%c", GPIO_MOCKUP_NAME, - gpio_mockup_name_start + i); - if (!chip_name) - return -ENOMEM; - - ret = gpio_mockup_add(dev, &chips[i], - chip_name, base, ngpio); - } else { - ret = -EINVAL; - } - - if (ret) { - dev_err(dev, - "adding gpiochip failed: %d (base: %d, ngpio: %d)\n", - ret, base, base < 0 ? ngpio : base + ngpio); - - return ret; - } - } - - return 0; -} - static struct platform_driver gpio_mockup_driver = { .driver = { .name = GPIO_MOCKUP_NAME, @@ -327,44 +327,88 @@ static struct platform_driver gpio_mockup_driver = { .probe = gpio_mockup_probe, }; -static struct platform_device *pdev; -static int __init mock_device_init(void) +static struct platform_device *gpio_mockup_pdevs[GPIO_MOCKUP_MAX_GC]; + +static void gpio_mockup_unregister_pdevs(void) { - int err; + struct platform_device *pdev; + int i; + + for (i = 0; i < GPIO_MOCKUP_MAX_GC; i++) { + pdev = gpio_mockup_pdevs[i]; + + if (pdev) + platform_device_unregister(pdev); + } +} + +static int __init gpio_mockup_init(void) +{ + int i, num_chips, err = 0, index = 'A'; + struct gpio_mockup_platform_data pdata; + struct platform_device *pdev; + + if ((gpio_mockup_num_ranges < 2) || + (gpio_mockup_num_ranges % 2) || + (gpio_mockup_num_ranges > GPIO_MOCKUP_MAX_RANGES)) + return -EINVAL; + + /* Each chip is described by two values. */ + num_chips = gpio_mockup_num_ranges / 2; + + /* + * The second value in the pair must + * always be greater than 0. + */ + for (i = 0; i < num_chips; i++) { + if (gpio_mockup_range_ngpio(i) < 0) + return -EINVAL; + } gpio_mockup_dbg_dir = debugfs_create_dir("gpio-mockup-event", NULL); - if (!gpio_mockup_dbg_dir) - pr_err("%s: error creating debugfs directory\n", - GPIO_MOCKUP_NAME); - - pdev = platform_device_alloc(GPIO_MOCKUP_NAME, -1); - if (!pdev) - return -ENOMEM; - - err = platform_device_add(pdev); - if (err) { - platform_device_put(pdev); - return err; - } + if (IS_ERR_OR_NULL(gpio_mockup_dbg_dir)) + gpio_mockup_err("error creating debugfs directory\n"); err = platform_driver_register(&gpio_mockup_driver); if (err) { - platform_device_unregister(pdev); + gpio_mockup_err("error registering platform driver\n"); return err; } + for (i = 0; i < num_chips; i++) { + pdata.index = index++; + pdata.base = gpio_mockup_range_base(i); + pdata.ngpio = pdata.base < 0 + ? gpio_mockup_range_ngpio(i) + : gpio_mockup_range_ngpio(i) - pdata.base; + pdata.named_lines = gpio_mockup_named_lines; + + pdev = platform_device_register_resndata(NULL, + GPIO_MOCKUP_NAME, + i, NULL, 0, &pdata, + sizeof(pdata)); + if (IS_ERR(pdev)) { + gpio_mockup_err("error registering device"); + platform_driver_unregister(&gpio_mockup_driver); + gpio_mockup_unregister_pdevs(); + return PTR_ERR(pdev); + } + + gpio_mockup_pdevs[i] = pdev; + } + return 0; } -static void __exit mock_device_exit(void) +static void __exit gpio_mockup_exit(void) { debugfs_remove_recursive(gpio_mockup_dbg_dir); platform_driver_unregister(&gpio_mockup_driver); - platform_device_unregister(pdev); + gpio_mockup_unregister_pdevs(); } -module_init(mock_device_init); -module_exit(mock_device_exit); +module_init(gpio_mockup_init); +module_exit(gpio_mockup_exit); MODULE_AUTHOR("Kamlakant Patel "); MODULE_AUTHOR("Bamvor Jian Zhang "); diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index e136d666f1e5..ab5035b96886 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1058,7 +1058,9 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) { + struct gpio_irq_chip *irq; static int gpio; + const char *label; int irq_base = 0; int ret; @@ -1080,21 +1082,15 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) bank->chip.parent = &omap_mpuio_device.dev; bank->chip.base = OMAP_MPUIO(0); } else { - bank->chip.label = "gpio"; + label = devm_kasprintf(bank->chip.parent, GFP_KERNEL, "gpio-%d-%d", + gpio, gpio + bank->width - 1); + if (!label) + return -ENOMEM; + bank->chip.label = label; bank->chip.base = gpio; } bank->chip.ngpio = bank->width; - ret = gpiochip_add_data(&bank->chip, bank); - if (ret) { - dev_err(bank->chip.parent, - "Could not register gpio chip %d\n", ret); - return ret; - } - - if (!bank->is_mpuio) - gpio += bank->width; - #ifdef CONFIG_ARCH_OMAP1 /* * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop @@ -1115,25 +1111,30 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) irqc->irq_set_wake = NULL; } - ret = gpiochip_irqchip_add(&bank->chip, irqc, - irq_base, handle_bad_irq, - IRQ_TYPE_NONE); + irq = &bank->chip.irq; + irq->chip = irqc; + irq->handler = handle_bad_irq; + irq->default_type = IRQ_TYPE_NONE; + irq->num_parents = 1; + irq->parents = &bank->irq; + irq->first = irq_base; + ret = gpiochip_add_data(&bank->chip, bank); if (ret) { dev_err(bank->chip.parent, - "Couldn't add irqchip to gpiochip %d\n", ret); - gpiochip_remove(&bank->chip); - return -ENODEV; + "Could not register gpio chip %d\n", ret); + return ret; } - gpiochip_set_chained_irqchip(&bank->chip, irqc, bank->irq, NULL); - ret = devm_request_irq(bank->chip.parent, bank->irq, omap_gpio_irq_handler, 0, dev_name(bank->chip.parent), bank); if (ret) gpiochip_remove(&bank->chip); + if (!bank->is_mpuio) + gpio += bank->width; + return ret; } diff --git a/drivers/gpio/gpio-pcie-idio-24.c b/drivers/gpio/gpio-pcie-idio-24.c new file mode 100644 index 000000000000..f666e2e69074 --- /dev/null +++ b/drivers/gpio/gpio-pcie-idio-24.c @@ -0,0 +1,447 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * GPIO driver for the ACCES PCIe-IDIO-24 family + * Copyright (C) 2018 William Breathitt Gray + * + * 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. + * + * This driver supports the following ACCES devices: PCIe-IDIO-24, + * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct idio_24_gpio_reg - GPIO device registers structure + * @out0_7: Read: FET Outputs 0-7 + * Write: FET Outputs 0-7 + * @out8_15: Read: FET Outputs 8-15 + * Write: FET Outputs 8-15 + * @out16_23: Read: FET Outputs 16-23 + * Write: FET Outputs 16-23 + * @ttl_out0_7: Read: TTL/CMOS Outputs 0-7 + * Write: TTL/CMOS Outputs 0-7 + * @in0_7: Read: Isolated Inputs 0-7 + * Write: Reserved + * @in8_15: Read: Isolated Inputs 8-15 + * Write: Reserved + * @in16_23: Read: Isolated Inputs 16-23 + * Write: Reserved + * @ttl_in0_7: Read: TTL/CMOS Inputs 0-7 + * Write: Reserved + * @cos0_7: Read: COS Status Inputs 0-7 + * Write: COS Clear Inputs 0-7 + * @cos8_15: Read: COS Status Inputs 8-15 + * Write: COS Clear Inputs 8-15 + * @cos16_23: Read: COS Status Inputs 16-23 + * Write: COS Clear Inputs 16-23 + * @cos_ttl0_7: Read: COS Status TTL/CMOS 0-7 + * Write: COS Clear TTL/CMOS 0-7 + * @ctl: Read: Control Register + * Write: Control Register + * @reserved: Read: Reserved + * Write: Reserved + * @cos_enable: Read: COS Enable + * Write: COS Enable + * @soft_reset: Read: IRQ Output Pin Status + * Write: Software Board Reset + */ +struct idio_24_gpio_reg { + u8 out0_7; + u8 out8_15; + u8 out16_23; + u8 ttl_out0_7; + u8 in0_7; + u8 in8_15; + u8 in16_23; + u8 ttl_in0_7; + u8 cos0_7; + u8 cos8_15; + u8 cos16_23; + u8 cos_ttl0_7; + u8 ctl; + u8 reserved; + u8 cos_enable; + u8 soft_reset; +}; + +/** + * struct idio_24_gpio - GPIO device private data structure + * @chip: instance of the gpio_chip + * @lock: synchronization lock to prevent I/O race conditions + * @reg: I/O address offset for the GPIO device registers + * @irq_mask: I/O bits affected by interrupts + */ +struct idio_24_gpio { + struct gpio_chip chip; + raw_spinlock_t lock; + struct idio_24_gpio_reg __iomem *reg; + unsigned long irq_mask; +}; + +static int idio_24_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); + const unsigned long out_mode_mask = BIT(1); + + /* FET Outputs */ + if (offset < 24) + return 0; + + /* Isolated Inputs */ + if (offset < 48) + return 1; + + /* TTL/CMOS I/O */ + /* OUT MODE = 1 when TTL/CMOS Output Mode is set */ + return !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask); +} + +static int idio_24_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); + unsigned long flags; + unsigned int ctl_state; + const unsigned long out_mode_mask = BIT(1); + + /* TTL/CMOS I/O */ + if (offset > 47) { + raw_spin_lock_irqsave(&idio24gpio->lock, flags); + + /* Clear TTL/CMOS Output Mode */ + ctl_state = ioread8(&idio24gpio->reg->ctl) & ~out_mode_mask; + iowrite8(ctl_state, &idio24gpio->reg->ctl); + + raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); + } + + return 0; +} + +static int idio_24_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); + unsigned long flags; + unsigned int ctl_state; + const unsigned long out_mode_mask = BIT(1); + + /* TTL/CMOS I/O */ + if (offset > 47) { + raw_spin_lock_irqsave(&idio24gpio->lock, flags); + + /* Set TTL/CMOS Output Mode */ + ctl_state = ioread8(&idio24gpio->reg->ctl) | out_mode_mask; + iowrite8(ctl_state, &idio24gpio->reg->ctl); + + raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); + } + + chip->set(chip, offset, value); + return 0; +} + +static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); + const unsigned long offset_mask = BIT(offset % 8); + const unsigned long out_mode_mask = BIT(1); + + /* FET Outputs */ + if (offset < 8) + return !!(ioread8(&idio24gpio->reg->out0_7) & offset_mask); + + if (offset < 16) + return !!(ioread8(&idio24gpio->reg->out8_15) & offset_mask); + + if (offset < 24) + return !!(ioread8(&idio24gpio->reg->out16_23) & offset_mask); + + /* Isolated Inputs */ + if (offset < 32) + return !!(ioread8(&idio24gpio->reg->in0_7) & offset_mask); + + if (offset < 40) + return !!(ioread8(&idio24gpio->reg->in8_15) & offset_mask); + + if (offset < 48) + return !!(ioread8(&idio24gpio->reg->in16_23) & offset_mask); + + /* TTL/CMOS Outputs */ + if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) + return !!(ioread8(&idio24gpio->reg->ttl_out0_7) & offset_mask); + + /* TTL/CMOS Inputs */ + return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask); +} + +static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); + const unsigned long out_mode_mask = BIT(1); + void __iomem *base; + const unsigned int mask = BIT(offset % 8); + unsigned long flags; + unsigned int out_state; + + /* Isolated Inputs */ + if (offset > 23 && offset < 48) + return; + + /* TTL/CMOS Inputs */ + if (offset > 47 && !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask)) + return; + + /* TTL/CMOS Outputs */ + if (offset > 47) + base = &idio24gpio->reg->ttl_out0_7; + /* FET Outputs */ + else if (offset > 15) + base = &idio24gpio->reg->out16_23; + else if (offset > 7) + base = &idio24gpio->reg->out8_15; + else + base = &idio24gpio->reg->out0_7; + + raw_spin_lock_irqsave(&idio24gpio->lock, flags); + + if (value) + out_state = ioread8(base) | mask; + else + out_state = ioread8(base) & ~mask; + + iowrite8(out_state, base); + + raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); +} + +static void idio_24_irq_ack(struct irq_data *data) +{ +} + +static void idio_24_irq_mask(struct irq_data *data) +{ + struct gpio_chip *const chip = irq_data_get_irq_chip_data(data); + struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); + unsigned long flags; + const unsigned long bit_offset = irqd_to_hwirq(data) - 24; + unsigned char new_irq_mask; + const unsigned long bank_offset = bit_offset/8 * 8; + unsigned char cos_enable_state; + + raw_spin_lock_irqsave(&idio24gpio->lock, flags); + + idio24gpio->irq_mask &= BIT(bit_offset); + new_irq_mask = idio24gpio->irq_mask >> bank_offset; + + if (!new_irq_mask) { + cos_enable_state = ioread8(&idio24gpio->reg->cos_enable); + + /* Disable Rising Edge detection */ + cos_enable_state &= ~BIT(bank_offset); + /* Disable Falling Edge detection */ + cos_enable_state &= ~BIT(bank_offset + 4); + + iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable); + } + + raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); +} + +static void idio_24_irq_unmask(struct irq_data *data) +{ + struct gpio_chip *const chip = irq_data_get_irq_chip_data(data); + struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); + unsigned long flags; + unsigned char prev_irq_mask; + const unsigned long bit_offset = irqd_to_hwirq(data) - 24; + const unsigned long bank_offset = bit_offset/8 * 8; + unsigned char cos_enable_state; + + raw_spin_lock_irqsave(&idio24gpio->lock, flags); + + prev_irq_mask = idio24gpio->irq_mask >> bank_offset; + idio24gpio->irq_mask |= BIT(bit_offset); + + if (!prev_irq_mask) { + cos_enable_state = ioread8(&idio24gpio->reg->cos_enable); + + /* Enable Rising Edge detection */ + cos_enable_state |= BIT(bank_offset); + /* Enable Falling Edge detection */ + cos_enable_state |= BIT(bank_offset + 4); + + iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable); + } + + raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); +} + +static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type) +{ + /* The only valid irq types are none and both-edges */ + if (flow_type != IRQ_TYPE_NONE && + (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) + return -EINVAL; + + return 0; +} + +static struct irq_chip idio_24_irqchip = { + .name = "pcie-idio-24", + .irq_ack = idio_24_irq_ack, + .irq_mask = idio_24_irq_mask, + .irq_unmask = idio_24_irq_unmask, + .irq_set_type = idio_24_irq_set_type +}; + +static irqreturn_t idio_24_irq_handler(int irq, void *dev_id) +{ + struct idio_24_gpio *const idio24gpio = dev_id; + unsigned long irq_status; + struct gpio_chip *const chip = &idio24gpio->chip; + unsigned long irq_mask; + int gpio; + + raw_spin_lock(&idio24gpio->lock); + + /* Read Change-Of-State status */ + irq_status = ioread32(&idio24gpio->reg->cos0_7); + + raw_spin_unlock(&idio24gpio->lock); + + /* Make sure our device generated IRQ */ + if (!irq_status) + return IRQ_NONE; + + /* Handle only unmasked IRQ */ + irq_mask = idio24gpio->irq_mask & irq_status; + + for_each_set_bit(gpio, &irq_mask, chip->ngpio - 24) + generic_handle_irq(irq_find_mapping(chip->irq.domain, + gpio + 24)); + + raw_spin_lock(&idio24gpio->lock); + + /* Clear Change-Of-State status */ + iowrite32(irq_status, &idio24gpio->reg->cos0_7); + + raw_spin_unlock(&idio24gpio->lock); + + return IRQ_HANDLED; +} + +#define IDIO_24_NGPIO 56 +static const char *idio_24_names[IDIO_24_NGPIO] = { + "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7", + "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15", + "OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23", + "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7", + "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15", + "IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23", + "TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7" +}; + +static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct device *const dev = &pdev->dev; + struct idio_24_gpio *idio24gpio; + int err; + const size_t pci_bar_index = 2; + const char *const name = pci_name(pdev); + + idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL); + if (!idio24gpio) + return -ENOMEM; + + err = pcim_enable_device(pdev); + if (err) { + dev_err(dev, "Failed to enable PCI device (%d)\n", err); + return err; + } + + err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name); + if (err) { + dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err); + return err; + } + + idio24gpio->reg = pcim_iomap_table(pdev)[pci_bar_index]; + + idio24gpio->chip.label = name; + idio24gpio->chip.parent = dev; + idio24gpio->chip.owner = THIS_MODULE; + idio24gpio->chip.base = -1; + idio24gpio->chip.ngpio = IDIO_24_NGPIO; + idio24gpio->chip.names = idio_24_names; + idio24gpio->chip.get_direction = idio_24_gpio_get_direction; + idio24gpio->chip.direction_input = idio_24_gpio_direction_input; + idio24gpio->chip.direction_output = idio_24_gpio_direction_output; + idio24gpio->chip.get = idio_24_gpio_get; + idio24gpio->chip.set = idio_24_gpio_set; + + raw_spin_lock_init(&idio24gpio->lock); + + /* Software board reset */ + iowrite8(0, &idio24gpio->reg->soft_reset); + + err = devm_gpiochip_add_data(dev, &idio24gpio->chip, idio24gpio); + if (err) { + dev_err(dev, "GPIO registering failed (%d)\n", err); + return err; + } + + err = gpiochip_irqchip_add(&idio24gpio->chip, &idio_24_irqchip, 0, + handle_edge_irq, IRQ_TYPE_NONE); + if (err) { + dev_err(dev, "Could not add irqchip (%d)\n", err); + return err; + } + + err = devm_request_irq(dev, pdev->irq, idio_24_irq_handler, IRQF_SHARED, + name, idio24gpio); + if (err) { + dev_err(dev, "IRQ handler registering failed (%d)\n", err); + return err; + } + + return 0; +} + +static const struct pci_device_id idio_24_pci_dev_id[] = { + { PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) }, + { PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id); + +static struct pci_driver idio_24_driver = { + .name = "pcie-idio-24", + .id_table = idio_24_pci_dev_id, + .probe = idio_24_probe +}; + +module_pci_driver(idio_24_driver); + +MODULE_AUTHOR("William Breathitt Gray "); +MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index e6e5cca624a7..f8d7d1cd8488 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -190,6 +190,16 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d) }; int i, j; + /* + * STMPE1600: to be able to get IRQ from pins, + * a read must be done on GPMR register, or a write in + * GPSR or GPCR registers + */ + if (stmpe->partnum == STMPE1600) { + stmpe_reg_read(stmpe, stmpe->regs[STMPE_IDX_GPMR_LSB]); + stmpe_reg_read(stmpe, stmpe->regs[STMPE_IDX_GPMR_CSB]); + } + for (i = 0; i < CACHE_NR_REGS; i++) { /* STMPE801 and STMPE1600 don't have RE and FE registers */ if ((stmpe->partnum == STMPE801 || @@ -227,21 +237,11 @@ static void stmpe_gpio_irq_unmask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); - struct stmpe *stmpe = stmpe_gpio->stmpe; int offset = d->hwirq; int regoffset = offset / 8; int mask = BIT(offset % 8); stmpe_gpio->regs[REG_IE][regoffset] |= mask; - - /* - * STMPE1600 workaround: to be able to get IRQ from pins, - * a read must be done on GPMR register, or a write in - * GPSR or GPCR registers - */ - if (stmpe->partnum == STMPE1600) - stmpe_reg_read(stmpe, - stmpe->regs[STMPE_IDX_GPMR_LSB + regoffset]); } static void stmpe_dbg_show_one(struct seq_file *s, @@ -273,15 +273,21 @@ static void stmpe_dbg_show_one(struct seq_file *s, u8 fall_reg; u8 irqen_reg; - char *edge_det_values[] = {"edge-inactive", - "edge-asserted", - "not-supported"}; - char *rise_values[] = {"no-rising-edge-detection", - "rising-edge-detection", - "not-supported"}; - char *fall_values[] = {"no-falling-edge-detection", - "falling-edge-detection", - "not-supported"}; + static const char * const edge_det_values[] = { + "edge-inactive", + "edge-asserted", + "not-supported" + }; + static const char * const rise_values[] = { + "no-rising-edge-detection", + "rising-edge-detection", + "not-supported" + }; + static const char * const fall_values[] = { + "no-falling-edge-detection", + "falling-edge-detection", + "not-supported" + }; #define NOT_SUPPORTED_IDX 2 u8 edge_det = NOT_SUPPORTED_IDX; u8 rise = NOT_SUPPORTED_IDX; @@ -344,7 +350,7 @@ static void stmpe_dbg_show(struct seq_file *s, struct gpio_chip *gc) for (i = 0; i < gc->ngpio; i++, gpio++) { stmpe_dbg_show_one(s, gc, i, gpio); - seq_printf(s, "\n"); + seq_putc(s, '\n'); } } @@ -426,12 +432,9 @@ static int stmpe_gpio_probe(struct platform_device *pdev) struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); struct device_node *np = pdev->dev.of_node; struct stmpe_gpio *stmpe_gpio; - int ret; - int irq = 0; + int ret, irq; - irq = platform_get_irq(pdev, 0); - - stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL); + stmpe_gpio = kzalloc(sizeof(*stmpe_gpio), GFP_KERNEL); if (!stmpe_gpio) return -ENOMEM; @@ -453,6 +456,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev) if (stmpe_gpio->norequest_mask) stmpe_gpio->chip.irq.need_valid_mask = true; + irq = platform_get_irq(pdev, 0); if (irq < 0) dev_info(&pdev->dev, "device configured in no-irq mode: " diff --git a/drivers/gpio/gpio-thunderx.c b/drivers/gpio/gpio-thunderx.c index b5adb79a631a..d16e9d4a129b 100644 --- a/drivers/gpio/gpio-thunderx.c +++ b/drivers/gpio/gpio-thunderx.c @@ -553,8 +553,10 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, txgpio->irqd = irq_domain_create_hierarchy(irq_get_irq_data(txgpio->msix_entries[0].vector)->domain, 0, 0, of_node_to_fwnode(dev->of_node), &thunderx_gpio_irqd_ops, txgpio); - if (!txgpio->irqd) + if (!txgpio->irqd) { + err = -ENOMEM; goto out; + } /* Push on irq_data and the domain for each line. */ for (i = 0; i < ngpio; i++) { diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c index 016d7427ebfa..761d8279abca 100644 --- a/drivers/gpio/gpio-uniphier.c +++ b/drivers/gpio/gpio-uniphier.c @@ -505,4 +505,4 @@ module_platform_driver(uniphier_gpio_driver); MODULE_AUTHOR("Masahiro Yamada "); MODULE_DESCRIPTION("UniPhier GPIO driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-winbond.c b/drivers/gpio/gpio-winbond.c new file mode 100644 index 000000000000..7f8f5b02e31d --- /dev/null +++ b/drivers/gpio/gpio-winbond.c @@ -0,0 +1,732 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * GPIO interface for Winbond Super I/O chips + * Currently, only W83627UHG (Nuvoton NCT6627UD) is supported. + * + * Author: Maciej S. Szmigiero + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include + +#define WB_GPIO_DRIVER_NAME KBUILD_MODNAME + +#define WB_SIO_BASE 0x2e +#define WB_SIO_BASE_HIGH 0x4e + +#define WB_SIO_EXT_ENTER_KEY 0x87 +#define WB_SIO_EXT_EXIT_KEY 0xaa + +/* global chip registers */ + +#define WB_SIO_REG_LOGICAL 0x07 + +#define WB_SIO_REG_CHIP_MSB 0x20 +#define WB_SIO_REG_CHIP_LSB 0x21 + +#define WB_SIO_CHIP_ID_W83627UHG 0xa230 +#define WB_SIO_CHIP_ID_W83627UHG_MASK GENMASK(15, 4) + +#define WB_SIO_REG_DPD 0x22 +#define WB_SIO_REG_DPD_UARTA 4 +#define WB_SIO_REG_DPD_UARTB 5 + +#define WB_SIO_REG_IDPD 0x23 +#define WB_SIO_REG_IDPD_UARTC 4 +#define WB_SIO_REG_IDPD_UARTD 5 +#define WB_SIO_REG_IDPD_UARTE 6 +#define WB_SIO_REG_IDPD_UARTF 7 + +#define WB_SIO_REG_GLOBAL_OPT 0x24 +#define WB_SIO_REG_GO_ENFDC 1 + +#define WB_SIO_REG_OVTGPIO3456 0x29 +#define WB_SIO_REG_OG3456_G3PP 3 +#define WB_SIO_REG_OG3456_G4PP 4 +#define WB_SIO_REG_OG3456_G5PP 5 +#define WB_SIO_REG_OG3456_G6PP 7 + +#define WB_SIO_REG_I2C_PS 0x2a +#define WB_SIO_REG_I2CPS_I2CFS 1 + +#define WB_SIO_REG_GPIO1_MF 0x2c +#define WB_SIO_REG_G1MF_G1PP 6 +#define WB_SIO_REG_G1MF_G2PP 7 +#define WB_SIO_REG_G1MF_FS_MASK GENMASK(1, 0) +#define WB_SIO_REG_G1MF_FS_IR_OFF 0 +#define WB_SIO_REG_G1MF_FS_IR 1 +#define WB_SIO_REG_G1MF_FS_GPIO1 2 +#define WB_SIO_REG_G1MF_FS_UARTB 3 + +/* not an actual device number, just a value meaning 'no device' */ +#define WB_SIO_DEV_NONE 0xff + +/* registers with offsets >= 0x30 are specific for a particular device */ + +/* UART B logical device */ +#define WB_SIO_DEV_UARTB 0x03 +#define WB_SIO_UARTB_REG_ENABLE 0x30 +#define WB_SIO_UARTB_ENABLE_ON 0 + +/* UART C logical device */ +#define WB_SIO_DEV_UARTC 0x06 +#define WB_SIO_UARTC_REG_ENABLE 0x30 +#define WB_SIO_UARTC_ENABLE_ON 0 + +/* GPIO3, GPIO4 logical device */ +#define WB_SIO_DEV_GPIO34 0x07 +#define WB_SIO_GPIO34_REG_ENABLE 0x30 +#define WB_SIO_GPIO34_ENABLE_3 0 +#define WB_SIO_GPIO34_ENABLE_4 1 +#define WB_SIO_GPIO34_REG_IO3 0xe0 +#define WB_SIO_GPIO34_REG_DATA3 0xe1 +#define WB_SIO_GPIO34_REG_INV3 0xe2 +#define WB_SIO_GPIO34_REG_IO4 0xe4 +#define WB_SIO_GPIO34_REG_DATA4 0xe5 +#define WB_SIO_GPIO34_REG_INV4 0xe6 + +/* WDTO, PLED, GPIO5, GPIO6 logical device */ +#define WB_SIO_DEV_WDGPIO56 0x08 +#define WB_SIO_WDGPIO56_REG_ENABLE 0x30 +#define WB_SIO_WDGPIO56_ENABLE_5 1 +#define WB_SIO_WDGPIO56_ENABLE_6 2 +#define WB_SIO_WDGPIO56_REG_IO5 0xe0 +#define WB_SIO_WDGPIO56_REG_DATA5 0xe1 +#define WB_SIO_WDGPIO56_REG_INV5 0xe2 +#define WB_SIO_WDGPIO56_REG_IO6 0xe4 +#define WB_SIO_WDGPIO56_REG_DATA6 0xe5 +#define WB_SIO_WDGPIO56_REG_INV6 0xe6 + +/* GPIO1, GPIO2, SUSLED logical device */ +#define WB_SIO_DEV_GPIO12 0x09 +#define WB_SIO_GPIO12_REG_ENABLE 0x30 +#define WB_SIO_GPIO12_ENABLE_1 0 +#define WB_SIO_GPIO12_ENABLE_2 1 +#define WB_SIO_GPIO12_REG_IO1 0xe0 +#define WB_SIO_GPIO12_REG_DATA1 0xe1 +#define WB_SIO_GPIO12_REG_INV1 0xe2 +#define WB_SIO_GPIO12_REG_IO2 0xe4 +#define WB_SIO_GPIO12_REG_DATA2 0xe5 +#define WB_SIO_GPIO12_REG_INV2 0xe6 + +/* UART D logical device */ +#define WB_SIO_DEV_UARTD 0x0d +#define WB_SIO_UARTD_REG_ENABLE 0x30 +#define WB_SIO_UARTD_ENABLE_ON 0 + +/* UART E logical device */ +#define WB_SIO_DEV_UARTE 0x0e +#define WB_SIO_UARTE_REG_ENABLE 0x30 +#define WB_SIO_UARTE_ENABLE_ON 0 + +/* + * for a description what a particular field of this struct means please see + * a description of the relevant module parameter at the bottom of this file + */ +struct winbond_gpio_params { + unsigned long base; + unsigned long gpios; + unsigned long ppgpios; + unsigned long odgpios; + bool pledgpio; + bool beepgpio; + bool i2cgpio; +}; + +static struct winbond_gpio_params params; + +static int winbond_sio_enter(unsigned long base) +{ + if (!request_muxed_region(base, 2, WB_GPIO_DRIVER_NAME)) + return -EBUSY; + + /* + * datasheet says two successive writes of the "key" value are needed + * in order for chip to enter the "Extended Function Mode" + */ + outb(WB_SIO_EXT_ENTER_KEY, base); + outb(WB_SIO_EXT_ENTER_KEY, base); + + return 0; +} + +static void winbond_sio_select_logical(unsigned long base, u8 dev) +{ + outb(WB_SIO_REG_LOGICAL, base); + outb(dev, base + 1); +} + +static void winbond_sio_leave(unsigned long base) +{ + outb(WB_SIO_EXT_EXIT_KEY, base); + + release_region(base, 2); +} + +static void winbond_sio_reg_write(unsigned long base, u8 reg, u8 data) +{ + outb(reg, base); + outb(data, base + 1); +} + +static u8 winbond_sio_reg_read(unsigned long base, u8 reg) +{ + outb(reg, base); + return inb(base + 1); +} + +static void winbond_sio_reg_bset(unsigned long base, u8 reg, u8 bit) +{ + u8 val; + + val = winbond_sio_reg_read(base, reg); + val |= BIT(bit); + winbond_sio_reg_write(base, reg, val); +} + +static void winbond_sio_reg_bclear(unsigned long base, u8 reg, u8 bit) +{ + u8 val; + + val = winbond_sio_reg_read(base, reg); + val &= ~BIT(bit); + winbond_sio_reg_write(base, reg, val); +} + +static bool winbond_sio_reg_btest(unsigned long base, u8 reg, u8 bit) +{ + return winbond_sio_reg_read(base, reg) & BIT(bit); +} + +/** + * struct winbond_gpio_port_conflict - possibly conflicting device information + * @name: device name (NULL means no conflicting device defined) + * @dev: Super I/O logical device number where the testreg register + * is located (or WB_SIO_DEV_NONE - don't select any + * logical device) + * @testreg: register number where the testbit bit is located + * @testbit: index of a bit to check whether an actual conflict exists + * @warnonly: if set then a conflict isn't fatal (just warn about it), + * otherwise disable the particular GPIO port if a conflict + * is detected + */ +struct winbond_gpio_port_conflict { + const char *name; + u8 dev; + u8 testreg; + u8 testbit; + bool warnonly; +}; + +/** + * struct winbond_gpio_info - information about a particular GPIO port (device) + * @dev: Super I/O logical device number of the registers + * specified below + * @enablereg: port enable bit register number + * @enablebit: index of a port enable bit + * @outputreg: output driver mode bit register number + * @outputppbit: index of a push-pull output driver mode bit + * @ioreg: data direction register number + * @invreg: pin data inversion register number + * @datareg: pin data register number + * @conflict: description of a device that possibly conflicts with + * this port + */ +struct winbond_gpio_info { + u8 dev; + u8 enablereg; + u8 enablebit; + u8 outputreg; + u8 outputppbit; + u8 ioreg; + u8 invreg; + u8 datareg; + struct winbond_gpio_port_conflict conflict; +}; + +static const struct winbond_gpio_info winbond_gpio_infos[6] = { + { /* 0 */ + .dev = WB_SIO_DEV_GPIO12, + .enablereg = WB_SIO_GPIO12_REG_ENABLE, + .enablebit = WB_SIO_GPIO12_ENABLE_1, + .outputreg = WB_SIO_REG_GPIO1_MF, + .outputppbit = WB_SIO_REG_G1MF_G1PP, + .ioreg = WB_SIO_GPIO12_REG_IO1, + .invreg = WB_SIO_GPIO12_REG_INV1, + .datareg = WB_SIO_GPIO12_REG_DATA1, + .conflict = { + .name = "UARTB", + .dev = WB_SIO_DEV_UARTB, + .testreg = WB_SIO_UARTB_REG_ENABLE, + .testbit = WB_SIO_UARTB_ENABLE_ON, + .warnonly = true + } + }, + { /* 1 */ + .dev = WB_SIO_DEV_GPIO12, + .enablereg = WB_SIO_GPIO12_REG_ENABLE, + .enablebit = WB_SIO_GPIO12_ENABLE_2, + .outputreg = WB_SIO_REG_GPIO1_MF, + .outputppbit = WB_SIO_REG_G1MF_G2PP, + .ioreg = WB_SIO_GPIO12_REG_IO2, + .invreg = WB_SIO_GPIO12_REG_INV2, + .datareg = WB_SIO_GPIO12_REG_DATA2 + /* special conflict handling so doesn't use conflict data */ + }, + { /* 2 */ + .dev = WB_SIO_DEV_GPIO34, + .enablereg = WB_SIO_GPIO34_REG_ENABLE, + .enablebit = WB_SIO_GPIO34_ENABLE_3, + .outputreg = WB_SIO_REG_OVTGPIO3456, + .outputppbit = WB_SIO_REG_OG3456_G3PP, + .ioreg = WB_SIO_GPIO34_REG_IO3, + .invreg = WB_SIO_GPIO34_REG_INV3, + .datareg = WB_SIO_GPIO34_REG_DATA3, + .conflict = { + .name = "UARTC", + .dev = WB_SIO_DEV_UARTC, + .testreg = WB_SIO_UARTC_REG_ENABLE, + .testbit = WB_SIO_UARTC_ENABLE_ON, + .warnonly = true + } + }, + { /* 3 */ + .dev = WB_SIO_DEV_GPIO34, + .enablereg = WB_SIO_GPIO34_REG_ENABLE, + .enablebit = WB_SIO_GPIO34_ENABLE_4, + .outputreg = WB_SIO_REG_OVTGPIO3456, + .outputppbit = WB_SIO_REG_OG3456_G4PP, + .ioreg = WB_SIO_GPIO34_REG_IO4, + .invreg = WB_SIO_GPIO34_REG_INV4, + .datareg = WB_SIO_GPIO34_REG_DATA4, + .conflict = { + .name = "UARTD", + .dev = WB_SIO_DEV_UARTD, + .testreg = WB_SIO_UARTD_REG_ENABLE, + .testbit = WB_SIO_UARTD_ENABLE_ON, + .warnonly = true + } + }, + { /* 4 */ + .dev = WB_SIO_DEV_WDGPIO56, + .enablereg = WB_SIO_WDGPIO56_REG_ENABLE, + .enablebit = WB_SIO_WDGPIO56_ENABLE_5, + .outputreg = WB_SIO_REG_OVTGPIO3456, + .outputppbit = WB_SIO_REG_OG3456_G5PP, + .ioreg = WB_SIO_WDGPIO56_REG_IO5, + .invreg = WB_SIO_WDGPIO56_REG_INV5, + .datareg = WB_SIO_WDGPIO56_REG_DATA5, + .conflict = { + .name = "UARTE", + .dev = WB_SIO_DEV_UARTE, + .testreg = WB_SIO_UARTE_REG_ENABLE, + .testbit = WB_SIO_UARTE_ENABLE_ON, + .warnonly = true + } + }, + { /* 5 */ + .dev = WB_SIO_DEV_WDGPIO56, + .enablereg = WB_SIO_WDGPIO56_REG_ENABLE, + .enablebit = WB_SIO_WDGPIO56_ENABLE_6, + .outputreg = WB_SIO_REG_OVTGPIO3456, + .outputppbit = WB_SIO_REG_OG3456_G6PP, + .ioreg = WB_SIO_WDGPIO56_REG_IO6, + .invreg = WB_SIO_WDGPIO56_REG_INV6, + .datareg = WB_SIO_WDGPIO56_REG_DATA6, + .conflict = { + .name = "FDC", + .dev = WB_SIO_DEV_NONE, + .testreg = WB_SIO_REG_GLOBAL_OPT, + .testbit = WB_SIO_REG_GO_ENFDC, + .warnonly = false + } + } +}; + +/* returns whether changing a pin is allowed */ +static bool winbond_gpio_get_info(unsigned int *gpio_num, + const struct winbond_gpio_info **info) +{ + bool allow_changing = true; + unsigned long i; + + for_each_set_bit(i, ¶ms.gpios, BITS_PER_LONG) { + if (*gpio_num < 8) + break; + + *gpio_num -= 8; + } + + *info = &winbond_gpio_infos[i]; + + /* + * GPIO2 (the second port) shares some pins with a basic PC + * functionality, which is very likely controlled by the firmware. + * Don't allow changing these pins by default. + */ + if (i == 1) { + if (*gpio_num == 0 && !params.pledgpio) + allow_changing = false; + else if (*gpio_num == 1 && !params.beepgpio) + allow_changing = false; + else if ((*gpio_num == 5 || *gpio_num == 6) && !params.i2cgpio) + allow_changing = false; + } + + return allow_changing; +} + +static int winbond_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + unsigned long *base = gpiochip_get_data(gc); + const struct winbond_gpio_info *info; + bool val; + + winbond_gpio_get_info(&offset, &info); + + val = winbond_sio_enter(*base); + if (val) + return val; + + winbond_sio_select_logical(*base, info->dev); + + val = winbond_sio_reg_btest(*base, info->datareg, offset); + if (winbond_sio_reg_btest(*base, info->invreg, offset)) + val = !val; + + winbond_sio_leave(*base); + + return val; +} + +static int winbond_gpio_direction_in(struct gpio_chip *gc, unsigned int offset) +{ + unsigned long *base = gpiochip_get_data(gc); + const struct winbond_gpio_info *info; + int ret; + + if (!winbond_gpio_get_info(&offset, &info)) + return -EACCES; + + ret = winbond_sio_enter(*base); + if (ret) + return ret; + + winbond_sio_select_logical(*base, info->dev); + + winbond_sio_reg_bset(*base, info->ioreg, offset); + + winbond_sio_leave(*base); + + return 0; +} + +static int winbond_gpio_direction_out(struct gpio_chip *gc, + unsigned int offset, + int val) +{ + unsigned long *base = gpiochip_get_data(gc); + const struct winbond_gpio_info *info; + int ret; + + if (!winbond_gpio_get_info(&offset, &info)) + return -EACCES; + + ret = winbond_sio_enter(*base); + if (ret) + return ret; + + winbond_sio_select_logical(*base, info->dev); + + winbond_sio_reg_bclear(*base, info->ioreg, offset); + + if (winbond_sio_reg_btest(*base, info->invreg, offset)) + val = !val; + + if (val) + winbond_sio_reg_bset(*base, info->datareg, offset); + else + winbond_sio_reg_bclear(*base, info->datareg, offset); + + winbond_sio_leave(*base); + + return 0; +} + +static void winbond_gpio_set(struct gpio_chip *gc, unsigned int offset, + int val) +{ + unsigned long *base = gpiochip_get_data(gc); + const struct winbond_gpio_info *info; + + if (!winbond_gpio_get_info(&offset, &info)) + return; + + if (winbond_sio_enter(*base) != 0) + return; + + winbond_sio_select_logical(*base, info->dev); + + if (winbond_sio_reg_btest(*base, info->invreg, offset)) + val = !val; + + if (val) + winbond_sio_reg_bset(*base, info->datareg, offset); + else + winbond_sio_reg_bclear(*base, info->datareg, offset); + + winbond_sio_leave(*base); +} + +static struct gpio_chip winbond_gpio_chip = { + .base = -1, + .label = WB_GPIO_DRIVER_NAME, + .owner = THIS_MODULE, + .can_sleep = true, + .get = winbond_gpio_get, + .direction_input = winbond_gpio_direction_in, + .set = winbond_gpio_set, + .direction_output = winbond_gpio_direction_out, +}; + +static void winbond_gpio_configure_port0_pins(unsigned long base) +{ + unsigned int val; + + val = winbond_sio_reg_read(base, WB_SIO_REG_GPIO1_MF); + if ((val & WB_SIO_REG_G1MF_FS_MASK) == WB_SIO_REG_G1MF_FS_GPIO1) + return; + + pr_warn("GPIO1 pins were connected to something else (%.2x), fixing\n", + val); + + val &= ~WB_SIO_REG_G1MF_FS_MASK; + val |= WB_SIO_REG_G1MF_FS_GPIO1; + + winbond_sio_reg_write(base, WB_SIO_REG_GPIO1_MF, val); +} + +static void winbond_gpio_configure_port1_check_i2c(unsigned long base) +{ + params.i2cgpio = !winbond_sio_reg_btest(base, WB_SIO_REG_I2C_PS, + WB_SIO_REG_I2CPS_I2CFS); + if (!params.i2cgpio) + pr_warn("disabling GPIO2.5 and GPIO2.6 as I2C is enabled\n"); +} + +static bool winbond_gpio_configure_port(unsigned long base, unsigned int idx) +{ + const struct winbond_gpio_info *info = &winbond_gpio_infos[idx]; + const struct winbond_gpio_port_conflict *conflict = &info->conflict; + + /* is there a possible conflicting device defined? */ + if (conflict->name != NULL) { + if (conflict->dev != WB_SIO_DEV_NONE) + winbond_sio_select_logical(base, conflict->dev); + + if (winbond_sio_reg_btest(base, conflict->testreg, + conflict->testbit)) { + if (conflict->warnonly) + pr_warn("enabled GPIO%u share pins with active %s\n", + idx + 1, conflict->name); + else { + pr_warn("disabling GPIO%u as %s is enabled\n", + idx + 1, conflict->name); + return false; + } + } + } + + /* GPIO1 and GPIO2 need some (additional) special handling */ + if (idx == 0) + winbond_gpio_configure_port0_pins(base); + else if (idx == 1) + winbond_gpio_configure_port1_check_i2c(base); + + winbond_sio_select_logical(base, info->dev); + + winbond_sio_reg_bset(base, info->enablereg, info->enablebit); + + if (params.ppgpios & BIT(idx)) + winbond_sio_reg_bset(base, info->outputreg, + info->outputppbit); + else if (params.odgpios & BIT(idx)) + winbond_sio_reg_bclear(base, info->outputreg, + info->outputppbit); + else + pr_notice("GPIO%u pins are %s\n", idx + 1, + winbond_sio_reg_btest(base, info->outputreg, + info->outputppbit) ? + "push-pull" : + "open drain"); + + return true; +} + +static int winbond_gpio_configure(unsigned long base) +{ + unsigned long i; + + for_each_set_bit(i, ¶ms.gpios, BITS_PER_LONG) + if (!winbond_gpio_configure_port(base, i)) + __clear_bit(i, ¶ms.gpios); + + if (!params.gpios) { + pr_err("please use 'gpios' module parameter to select some active GPIO ports to enable\n"); + return -EINVAL; + } + + return 0; +} + +static int winbond_gpio_check_chip(unsigned long base) +{ + int ret; + unsigned int chip; + + ret = winbond_sio_enter(base); + if (ret) + return ret; + + chip = winbond_sio_reg_read(base, WB_SIO_REG_CHIP_MSB) << 8; + chip |= winbond_sio_reg_read(base, WB_SIO_REG_CHIP_LSB); + + pr_notice("chip ID at %lx is %.4x\n", base, chip); + + if ((chip & WB_SIO_CHIP_ID_W83627UHG_MASK) != + WB_SIO_CHIP_ID_W83627UHG) { + pr_err("not an our chip\n"); + ret = -ENODEV; + } + + winbond_sio_leave(base); + + return ret; +} + +static int winbond_gpio_imatch(struct device *dev, unsigned int id) +{ + unsigned long gpios_rem; + int ret; + + gpios_rem = params.gpios & ~GENMASK(ARRAY_SIZE(winbond_gpio_infos) - 1, + 0); + if (gpios_rem) { + pr_warn("unknown ports (%lx) enabled in GPIO ports bitmask\n", + gpios_rem); + params.gpios &= ~gpios_rem; + } + + if (params.ppgpios & params.odgpios) { + pr_err("some GPIO ports are set both to push-pull and open drain mode at the same time\n"); + return 0; + } + + if (params.base != 0) + return winbond_gpio_check_chip(params.base) == 0; + + /* + * if the 'base' module parameter is unset probe two chip default + * I/O port bases + */ + params.base = WB_SIO_BASE; + ret = winbond_gpio_check_chip(params.base); + if (ret == 0) + return 1; + if (ret != -ENODEV && ret != -EBUSY) + return 0; + + params.base = WB_SIO_BASE_HIGH; + return winbond_gpio_check_chip(params.base) == 0; +} + +static int winbond_gpio_iprobe(struct device *dev, unsigned int id) +{ + int ret; + + if (params.base == 0) + return -EINVAL; + + ret = winbond_sio_enter(params.base); + if (ret) + return ret; + + ret = winbond_gpio_configure(params.base); + + winbond_sio_leave(params.base); + + if (ret) + return ret; + + /* + * Add 8 gpios for every GPIO port that was enabled in gpios + * module parameter (that wasn't disabled earlier in + * winbond_gpio_configure() & co. due to, for example, a pin conflict). + */ + winbond_gpio_chip.ngpio = hweight_long(params.gpios) * 8; + + /* + * GPIO6 port has only 5 pins, so if it is enabled we have to adjust + * the total count appropriately + */ + if (params.gpios & BIT(5)) + winbond_gpio_chip.ngpio -= (8 - 5); + + winbond_gpio_chip.parent = dev; + + return devm_gpiochip_add_data(dev, &winbond_gpio_chip, ¶ms.base); +} + +static struct isa_driver winbond_gpio_idriver = { + .driver = { + .name = WB_GPIO_DRIVER_NAME, + }, + .match = winbond_gpio_imatch, + .probe = winbond_gpio_iprobe, +}; + +module_isa_driver(winbond_gpio_idriver, 1); + +module_param_named(base, params.base, ulong, 0444); +MODULE_PARM_DESC(base, + "I/O port base (when unset - probe chip default ones)"); + +/* This parameter sets which GPIO devices (ports) we enable */ +module_param_named(gpios, params.gpios, ulong, 0444); +MODULE_PARM_DESC(gpios, + "bitmask of GPIO ports to enable (bit 0 - GPIO1, bit 1 - GPIO2, etc."); + +/* + * These two parameters below set how we configure GPIO ports output drivers. + * It can't be a one bitmask since we need three values per port: push-pull, + * open-drain and keep as-is (this is the default). + */ +module_param_named(ppgpios, params.ppgpios, ulong, 0444); +MODULE_PARM_DESC(ppgpios, + "bitmask of GPIO ports to set to push-pull mode (bit 0 - GPIO1, bit 1 - GPIO2, etc."); + +module_param_named(odgpios, params.odgpios, ulong, 0444); +MODULE_PARM_DESC(odgpios, + "bitmask of GPIO ports to set to open drain mode (bit 0 - GPIO1, bit 1 - GPIO2, etc."); + +/* + * GPIO2.0 and GPIO2.1 control a basic PC functionality that we + * don't allow tinkering with by default (it is very likely that the + * firmware owns these pins). + * These two parameters below allow overriding these prohibitions. + */ +module_param_named(pledgpio, params.pledgpio, bool, 0644); +MODULE_PARM_DESC(pledgpio, + "enable changing value of GPIO2.0 bit (Power LED), default no."); + +module_param_named(beepgpio, params.beepgpio, bool, 0644); +MODULE_PARM_DESC(beepgpio, + "enable changing value of GPIO2.1 bit (BEEP), default no."); + +MODULE_AUTHOR("Maciej S. Szmigiero "); +MODULE_DESCRIPTION("GPIO interface for Winbond Super I/O chips"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index d6f3d9ee1350..e2232cbcec8b 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -58,58 +58,6 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) return ACPI_HANDLE(gc->parent) == data; } -#ifdef CONFIG_PINCTRL -/** - * acpi_gpiochip_pin_to_gpio_offset() - translates ACPI GPIO to Linux GPIO - * @gdev: GPIO device - * @pin: ACPI GPIO pin number from GpioIo/GpioInt resource - * - * Function takes ACPI GpioIo/GpioInt pin number as a parameter and - * translates it to a corresponding offset suitable to be passed to a - * GPIO controller driver. - * - * Typically the returned offset is same as @pin, but if the GPIO - * controller uses pin controller and the mapping is not contiguous the - * offset might be different. - */ -static int acpi_gpiochip_pin_to_gpio_offset(struct gpio_device *gdev, int pin) -{ - struct gpio_pin_range *pin_range; - - /* If there are no ranges in this chip, use 1:1 mapping */ - if (list_empty(&gdev->pin_ranges)) - return pin; - - list_for_each_entry(pin_range, &gdev->pin_ranges, node) { - const struct pinctrl_gpio_range *range = &pin_range->range; - int i; - - if (range->pins) { - for (i = 0; i < range->npins; i++) { - if (range->pins[i] == pin) - return range->base + i - gdev->base; - } - } else { - if (pin >= range->pin_base && - pin < range->pin_base + range->npins) { - unsigned gpio_base; - - gpio_base = range->base - gdev->base; - return gpio_base + pin - range->pin_base; - } - } - } - - return -EINVAL; -} -#else -static inline int acpi_gpiochip_pin_to_gpio_offset(struct gpio_device *gdev, - int pin) -{ - return pin; -} -#endif - /** * acpi_get_gpiod() - Translate ACPI GPIO pin to GPIO descriptor usable with GPIO API * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1") @@ -125,7 +73,6 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin) struct gpio_chip *chip; acpi_handle handle; acpi_status status; - int offset; status = acpi_get_handle(NULL, path, &handle); if (ACPI_FAILURE(status)) @@ -135,11 +82,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin) if (!chip) return ERR_PTR(-EPROBE_DEFER); - offset = acpi_gpiochip_pin_to_gpio_offset(chip->gpiodev, pin); - if (offset < 0) - return ERR_PTR(offset); - - return gpiochip_get_desc(chip, offset); + return gpiochip_get_desc(chip, pin); } static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) @@ -216,10 +159,6 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, if (!handler) return AE_OK; - pin = acpi_gpiochip_pin_to_gpio_offset(chip->gpiodev, pin); - if (pin < 0) - return AE_BAD_PARAMETER; - desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event"); if (IS_ERR(desc)) { dev_err(chip->parent, "Failed to request GPIO\n"); @@ -414,7 +353,8 @@ EXPORT_SYMBOL_GPL(devm_acpi_dev_remove_driver_gpios); static bool acpi_get_driver_gpio_data(struct acpi_device *adev, const char *name, int index, - struct acpi_reference_args *args) + struct acpi_reference_args *args, + unsigned int *quirks) { const struct acpi_gpio_mapping *gm; @@ -430,6 +370,8 @@ static bool acpi_get_driver_gpio_data(struct acpi_device *adev, args->args[1] = par->line_index; args->args[2] = par->active_low; args->nargs = 3; + + *quirks = gm->quirks; return true; } @@ -461,8 +403,8 @@ acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio) } } -int -acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update) +static int +__acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update) { int ret = 0; @@ -489,12 +431,31 @@ acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update) return ret; } +int +acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info) +{ + struct device *dev = &info->adev->dev; + enum gpiod_flags old = *flags; + int ret; + + ret = __acpi_gpio_update_gpiod_flags(&old, info->flags); + if (info->quirks & ACPI_GPIO_QUIRK_NO_IO_RESTRICTION) { + if (ret) + dev_warn(dev, FW_BUG "GPIO not in correct mode, fixing\n"); + } else { + if (ret) + dev_dbg(dev, "Override GPIO initialization flags\n"); + *flags = old; + } + + return ret; +} + struct acpi_gpio_lookup { struct acpi_gpio_info info; int index; int pin_index; bool active_low; - struct acpi_device *adev; struct gpio_desc *desc; int n; }; @@ -531,8 +492,8 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data) lookup->info.triggering = agpio->triggering; } else { lookup->info.flags = acpi_gpio_to_gpiod_flags(agpio); + lookup->info.polarity = lookup->active_low; } - } return 1; @@ -541,12 +502,13 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data) static int acpi_gpio_resource_lookup(struct acpi_gpio_lookup *lookup, struct acpi_gpio_info *info) { + struct acpi_device *adev = lookup->info.adev; struct list_head res_list; int ret; INIT_LIST_HEAD(&res_list); - ret = acpi_dev_get_resources(lookup->adev, &res_list, + ret = acpi_dev_get_resources(adev, &res_list, acpi_populate_gpio_lookup, lookup); if (ret < 0) @@ -557,11 +519,8 @@ static int acpi_gpio_resource_lookup(struct acpi_gpio_lookup *lookup, if (!lookup->desc) return -ENOENT; - if (info) { + if (info) *info = lookup->info; - if (lookup->active_low) - info->polarity = lookup->active_low; - } return 0; } @@ -570,6 +529,7 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, struct acpi_gpio_lookup *lookup) { struct acpi_reference_args args; + unsigned int quirks = 0; int ret; memset(&args, 0, sizeof(args)); @@ -581,14 +541,14 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, if (!adev) return ret; - if (!acpi_get_driver_gpio_data(adev, propname, index, &args)) + if (!acpi_get_driver_gpio_data(adev, propname, index, &args, + &quirks)) return ret; } /* * The property was found and resolved, so need to lookup the GPIO based * on returned args. */ - lookup->adev = args.adev; if (args.nargs != 3) return -EPROTO; @@ -596,6 +556,8 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, lookup->pin_index = args.args[1]; lookup->active_low = !!args.args[2]; + lookup->info.adev = args.adev; + lookup->info.quirks = quirks; return 0; } @@ -643,11 +605,11 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, return ERR_PTR(ret); dev_dbg(&adev->dev, "GPIO: _DSD returned %s %d %d %u\n", - dev_name(&lookup.adev->dev), lookup.index, + dev_name(&lookup.info.adev->dev), lookup.index, lookup.pin_index, lookup.active_low); } else { dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index); - lookup.adev = adev; + lookup.info.adev = adev; } ret = acpi_gpio_resource_lookup(&lookup, info); @@ -664,7 +626,6 @@ struct gpio_desc *acpi_find_gpio(struct device *dev, struct acpi_gpio_info info; struct gpio_desc *desc; char propname[32]; - int err; int i; /* Try first from _DSD */ @@ -703,10 +664,7 @@ struct gpio_desc *acpi_find_gpio(struct device *dev, if (info.polarity == GPIO_ACTIVE_LOW) *lookupflags |= GPIO_ACTIVE_LOW; - err = acpi_gpio_update_gpiod_flags(dflags, info.flags); - if (err) - dev_dbg(dev, "Override GPIO initialization flags\n"); - + acpi_gpio_update_gpiod_flags(dflags, &info); return desc; } @@ -852,12 +810,6 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, struct gpio_desc *desc; bool found; - pin = acpi_gpiochip_pin_to_gpio_offset(chip->gpiodev, pin); - if (pin < 0) { - status = AE_BAD_PARAMETER; - goto out; - } - mutex_lock(&achip->conn_lock); found = false; @@ -990,11 +942,7 @@ static struct gpio_desc *acpi_gpiochip_parse_own_gpio( if (ret < 0) return ERR_PTR(ret); - ret = acpi_gpiochip_pin_to_gpio_offset(chip->gpiodev, gpios[0]); - if (ret < 0) - return ERR_PTR(ret); - - desc = gpiochip_get_desc(chip, ret); + desc = gpiochip_get_desc(chip, gpios[0]); if (IS_ERR(desc)) return desc; diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 72a0695d2ac3..564bb7a31da4 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -56,6 +56,42 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip, return gpiochip_get_desc(chip, ret); } +static void of_gpio_flags_quirks(struct device_node *np, + enum of_gpio_flags *flags) +{ + /* + * Some GPIO fixed regulator quirks. + * Note that active low is the default. + */ + if (IS_ENABLED(CONFIG_REGULATOR) && + (of_device_is_compatible(np, "reg-fixed-voltage") || + of_device_is_compatible(np, "regulator-gpio"))) { + /* + * The regulator GPIO handles are specified such that the + * presence or absence of "enable-active-high" solely controls + * the polarity of the GPIO line. Any phandle flags must + * be actively ignored. + */ + if (*flags & OF_GPIO_ACTIVE_LOW) { + pr_warn("%s GPIO handle specifies active low - ignored\n", + of_node_full_name(np)); + *flags &= ~OF_GPIO_ACTIVE_LOW; + } + if (!of_property_read_bool(np, "enable-active-high")) + *flags |= OF_GPIO_ACTIVE_LOW; + } + /* + * Legacy open drain handling for fixed voltage regulators. + */ + if (IS_ENABLED(CONFIG_REGULATOR) && + of_device_is_compatible(np, "reg-fixed-voltage") && + of_property_read_bool(np, "gpio-open-drain")) { + *flags |= (OF_GPIO_SINGLE_ENDED | OF_GPIO_OPEN_DRAIN); + pr_info("%s uses legacy open drain flag - update the DTS if you can\n", + of_node_full_name(np)); + } +} + /** * of_get_named_gpiod_flags() - Get a GPIO descriptor and flags for GPIO API * @np: device node to get GPIO from @@ -93,6 +129,9 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, if (IS_ERR(desc)) goto out; + if (flags) + of_gpio_flags_quirks(np, flags); + pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n", __func__, propname, np, index, PTR_ERR_OR_ZERO(desc)); @@ -117,6 +156,71 @@ int of_get_named_gpio_flags(struct device_node *np, const char *list_name, } EXPORT_SYMBOL(of_get_named_gpio_flags); +/* + * The SPI GPIO bindings happened before we managed to establish that GPIO + * properties should be named "foo-gpios" so we have this special kludge for + * them. + */ +static struct gpio_desc *of_find_spi_gpio(struct device *dev, const char *con_id, + enum of_gpio_flags *of_flags) +{ + char prop_name[32]; /* 32 is max size of property name */ + struct device_node *np = dev->of_node; + struct gpio_desc *desc; + + /* + * Hopefully the compiler stubs the rest of the function if this + * is false. + */ + if (!IS_ENABLED(CONFIG_SPI_MASTER)) + return ERR_PTR(-ENOENT); + + /* Allow this specifically for "spi-gpio" devices */ + if (!of_device_is_compatible(np, "spi-gpio") || !con_id) + return ERR_PTR(-ENOENT); + + /* Will be "gpio-sck", "gpio-mosi" or "gpio-miso" */ + snprintf(prop_name, sizeof(prop_name), "%s-%s", "gpio", con_id); + + desc = of_get_named_gpiod_flags(np, prop_name, 0, of_flags); + return desc; +} + +/* + * Some regulator bindings happened before we managed to establish that GPIO + * properties should be named "foo-gpios" so we have this special kludge for + * them. + */ +static struct gpio_desc *of_find_regulator_gpio(struct device *dev, const char *con_id, + enum of_gpio_flags *of_flags) +{ + /* These are the connection IDs we accept as legacy GPIO phandles */ + const char *whitelist[] = { + "wlf,ldoena", /* Arizona */ + "wlf,ldo1ena", /* WM8994 */ + "wlf,ldo2ena", /* WM8994 */ + }; + struct device_node *np = dev->of_node; + struct gpio_desc *desc; + int i; + + if (!IS_ENABLED(CONFIG_REGULATOR)) + return ERR_PTR(-ENOENT); + + if (!con_id) + return ERR_PTR(-ENOENT); + + for (i = 0; i < ARRAY_SIZE(whitelist); i++) + if (!strcmp(con_id, whitelist[i])) + break; + + if (i == ARRAY_SIZE(whitelist)) + return ERR_PTR(-ENOENT); + + desc = of_get_named_gpiod_flags(np, con_id, 0, of_flags); + return desc; +} + struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, unsigned int idx, enum gpio_lookup_flags *flags) @@ -126,6 +230,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, struct gpio_desc *desc; unsigned int i; + /* Try GPIO property "foo-gpios" and "foo-gpio" */ for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { if (con_id) snprintf(prop_name, sizeof(prop_name), "%s-%s", con_id, @@ -140,6 +245,14 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, break; } + /* Special handling for SPI GPIOs if used */ + if (IS_ERR(desc)) + desc = of_find_spi_gpio(dev, con_id, &of_flags); + + /* Special handling for regulator GPIOs if used */ + if (IS_ERR(desc)) + desc = of_find_regulator_gpio(dev, con_id, &of_flags); + if (IS_ERR(desc)) return desc; @@ -153,8 +266,8 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, *flags |= GPIO_OPEN_SOURCE; } - if (of_flags & OF_GPIO_SLEEP_MAY_LOSE_VALUE) - *flags |= GPIO_SLEEP_MAY_LOSE_VALUE; + if (of_flags & OF_GPIO_TRANSITORY) + *flags |= GPIO_TRANSITORY; return desc; } @@ -214,6 +327,8 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, if (xlate_flags & OF_GPIO_ACTIVE_LOW) *lflags |= GPIO_ACTIVE_LOW; + if (xlate_flags & OF_GPIO_TRANSITORY) + *lflags |= GPIO_TRANSITORY; if (of_property_read_bool(np, "input")) *dflags |= GPIOD_IN; diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 3f454eaf2101..3dbaf489a8a5 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "gpiolib.h" @@ -106,8 +107,14 @@ static ssize_t value_show(struct device *dev, mutex_lock(&data->mutex); - status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc)); + status = gpiod_get_value_cansleep(desc); + if (status < 0) + goto err; + buf[0] = '0' + status; + buf[1] = '\n'; + status = 2; +err: mutex_unlock(&data->mutex); return status; @@ -118,7 +125,7 @@ static ssize_t value_store(struct device *dev, { struct gpiod_data *data = dev_get_drvdata(dev); struct gpio_desc *desc = data->desc; - ssize_t status; + ssize_t status = 0; mutex_lock(&data->mutex); @@ -127,7 +134,11 @@ static ssize_t value_store(struct device *dev, } else { long value; - status = kstrtol(buf, 0, &value); + if (size <= 2 && isdigit(buf[0]) && + (size == 1 || buf[1] == '\n')) + value = buf[0] - '0'; + else + status = kstrtol(buf, 0, &value); if (status == 0) { gpiod_set_value_cansleep(desc, value); status = size; @@ -138,7 +149,7 @@ static ssize_t value_store(struct device *dev, return status; } -static DEVICE_ATTR_RW(value); +static DEVICE_ATTR_PREALLOC(value, S_IWUSR | S_IRUGO, value_show, value_store); static irqreturn_t gpio_sysfs_irq(int irq, void *priv) { @@ -474,11 +485,15 @@ static ssize_t export_store(struct class *class, status = -ENODEV; goto done; } - status = gpiod_export(desc, true); - if (status < 0) - gpiod_free(desc); - else - set_bit(FLAG_SYSFS, &desc->flags); + + status = gpiod_set_transitory(desc, false); + if (!status) { + status = gpiod_export(desc, true); + if (status < 0) + gpiod_free(desc); + else + set_bit(FLAG_SYSFS, &desc->flags); + } done: if (status) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 14532d9576e4..d66de67ef307 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -162,7 +162,7 @@ EXPORT_SYMBOL_GPL(desc_to_gpio); */ struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) { - if (!desc || !desc->gdev || !desc->gdev->chip) + if (!desc || !desc->gdev) return NULL; return desc->gdev->chip; } @@ -196,7 +196,7 @@ static int gpiochip_find_base(int ngpio) * gpiod_get_direction - return the current direction of a GPIO * @desc: GPIO to get the direction of * - * Return GPIOF_DIR_IN or GPIOF_DIR_OUT, or an error code in case of error. + * Returns 0 for output, 1 for input, or an error code in case of error. * * This function may sleep if gpiod_cansleep() is true. */ @@ -460,6 +460,15 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) return -EINVAL; + /* + * Do not allow OPEN_SOURCE & OPEN_DRAIN flags in a single request. If + * the hardware actually supports enabling both at the same time the + * electrical result would be disastrous. + */ + if ((lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) && + (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)) + return -EINVAL; + /* OPEN_DRAIN and OPEN_SOURCE flags only make sense for output mode. */ if (!(lflags & GPIOHANDLE_REQUEST_OUTPUT) && ((lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) || @@ -506,6 +515,10 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE) set_bit(FLAG_OPEN_SOURCE, &desc->flags); + ret = gpiod_set_transitory(desc, false); + if (ret < 0) + goto out_free_descs; + /* * Lines have to be requested explicitly for input * or output, else the line will be treated "as is". @@ -588,6 +601,9 @@ out_free_lh: * @events: KFIFO for the GPIO events * @read_lock: mutex lock to protect reads from colliding with adding * new events to the FIFO + * @timestamp: cache for the timestamp storing it between hardirq + * and IRQ thread, used to bring the timestamp close to the actual + * event */ struct lineevent_state { struct gpio_device *gdev; @@ -598,22 +614,23 @@ struct lineevent_state { wait_queue_head_t wait; DECLARE_KFIFO(events, struct gpioevent_data, 16); struct mutex read_lock; + u64 timestamp; }; #define GPIOEVENT_REQUEST_VALID_FLAGS \ (GPIOEVENT_REQUEST_RISING_EDGE | \ GPIOEVENT_REQUEST_FALLING_EDGE) -static unsigned int lineevent_poll(struct file *filep, +static __poll_t lineevent_poll(struct file *filep, struct poll_table_struct *wait) { struct lineevent_state *le = filep->private_data; - unsigned int events = 0; + __poll_t events = 0; poll_wait(filep, &le->wait, wait); if (!kfifo_is_empty(&le->events)) - events = POLLIN | POLLRDNORM; + events = EPOLLIN | EPOLLRDNORM; return events; } @@ -732,7 +749,10 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p) struct gpioevent_data ge; int ret, level; - ge.timestamp = ktime_get_real_ns(); + /* Do not leak kernel stack to userspace */ + memset(&ge, 0, sizeof(ge)); + + ge.timestamp = le->timestamp; level = gpiod_get_value_cansleep(le->desc); if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE @@ -755,11 +775,24 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p) ret = kfifo_put(&le->events, ge); if (ret != 0) - wake_up_poll(&le->wait, POLLIN); + wake_up_poll(&le->wait, EPOLLIN); return IRQ_HANDLED; } +static irqreturn_t lineevent_irq_handler(int irq, void *p) +{ + struct lineevent_state *le = p; + + /* + * Just store the timestamp in hardirq context so we get it as + * close in time as possible to the actual event. + */ + le->timestamp = ktime_get_real_ns(); + + return IRQ_WAKE_THREAD; +} + static int lineevent_create(struct gpio_device *gdev, void __user *ip) { struct gpioevent_request eventreq; @@ -852,7 +885,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) /* Request a thread to read the events */ ret = request_threaded_irq(le->irq, - NULL, + lineevent_irq_handler, lineevent_irq_thread, irqflags, le->label, @@ -1050,7 +1083,7 @@ static void gpiodevice_release(struct device *dev) list_del(&gdev->list); ida_simple_remove(&gpio_ida, gdev->id); - kfree(gdev->label); + kfree_const(gdev->label); kfree(gdev->descs); kfree(gdev); } @@ -1159,10 +1192,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, goto err_free_descs; } - if (chip->label) - gdev->label = kstrdup(chip->label, GFP_KERNEL); - else - gdev->label = kstrdup("unknown", GFP_KERNEL); + gdev->label = kstrdup_const(chip->label ?: "unknown", GFP_KERNEL); if (!gdev->label) { status = -ENOMEM; goto err_free_descs; @@ -1209,31 +1239,14 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, struct gpio_desc *desc = &gdev->descs[i]; desc->gdev = gdev; - /* - * REVISIT: most hardware initializes GPIOs as inputs - * (often with pullups enabled) so power usage is - * minimized. Linux code should set the gpio direction - * first thing; but until it does, and in case - * chip->get_direction is not set, we may expose the - * wrong direction in sysfs. + + /* REVISIT: most hardware initializes GPIOs as inputs (often + * with pullups enabled) so power usage is minimized. Linux + * code should set the gpio direction first thing; but until + * it does, and in case chip->get_direction is not set, we may + * expose the wrong direction in sysfs. */ - - if (chip->get_direction) { - /* - * If we have .get_direction, set up the initial - * direction flag from the hardware. - */ - int dir = chip->get_direction(chip, i); - - if (!dir) - set_bit(FLAG_IS_OUT, &desc->flags); - } else if (!chip->direction_input) { - /* - * If the chip lacks the .direction_input callback - * we logically assume all lines are outputs. - */ - set_bit(FLAG_IS_OUT, &desc->flags); - } + desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0; } #ifdef CONFIG_PINCTRL @@ -1283,7 +1296,7 @@ err_remove_from_list: list_del(&gdev->list); spin_unlock_irqrestore(&gpio_lock, flags); err_free_label: - kfree(gdev->label); + kfree_const(gdev->label); err_free_descs: kfree(gdev->descs); err_free_gdev: @@ -1383,7 +1396,7 @@ static int devm_gpio_chip_match(struct device *dev, void *res, void *data) } /** - * devm_gpiochip_add_data() - Resource manager piochip_add_data() + * devm_gpiochip_add_data() - Resource manager gpiochip_add_data() * @dev: the device pointer on which irq_chip belongs to. * @chip: the chip to register, with chip->base initialized * @data: driver-private data associated with this chip @@ -1510,14 +1523,15 @@ static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip) gpiochip->irq.valid_mask = NULL; } -static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, - unsigned int offset) +bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, + unsigned int offset) { /* No mask means all valid */ if (likely(!gpiochip->irq.valid_mask)) return true; return test_bit(offset, gpiochip->irq.valid_mask); } +EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid); /** * gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip @@ -2174,40 +2188,37 @@ done: * macro to avoid endless duplication. If the desc is NULL it is an * optional GPIO and calls should just bail out. */ +static int validate_desc(const struct gpio_desc *desc, const char *func) +{ + if (!desc) + return 0; + if (IS_ERR(desc)) { + pr_warn("%s: invalid GPIO (errorpointer)\n", func); + return PTR_ERR(desc); + } + if (!desc->gdev) { + pr_warn("%s: invalid GPIO (no device)\n", func); + return -EINVAL; + } + if (!desc->gdev->chip) { + dev_warn(&desc->gdev->dev, + "%s: backing chip is gone\n", func); + return 0; + } + return 1; +} + #define VALIDATE_DESC(desc) do { \ - if (!desc) \ - return 0; \ - if (IS_ERR(desc)) { \ - pr_warn("%s: invalid GPIO (errorpointer)\n", __func__); \ - return PTR_ERR(desc); \ - } \ - if (!desc->gdev) { \ - pr_warn("%s: invalid GPIO (no device)\n", __func__); \ - return -EINVAL; \ - } \ - if ( !desc->gdev->chip ) { \ - dev_warn(&desc->gdev->dev, \ - "%s: backing chip is gone\n", __func__); \ - return 0; \ - } } while (0) + int __valid = validate_desc(desc, __func__); \ + if (__valid <= 0) \ + return __valid; \ + } while (0) #define VALIDATE_DESC_VOID(desc) do { \ - if (!desc) \ + int __valid = validate_desc(desc, __func__); \ + if (__valid <= 0) \ return; \ - if (IS_ERR(desc)) { \ - pr_warn("%s: invalid GPIO (errorpointer)\n", __func__); \ - return; \ - } \ - if (!desc->gdev) { \ - pr_warn("%s: invalid GPIO (no device)\n", __func__); \ - return; \ - } \ - if (!desc->gdev->chip) { \ - dev_warn(&desc->gdev->dev, \ - "%s: backing chip is gone\n", __func__); \ - return; \ - } } while (0) - + } while (0) int gpiod_request(struct gpio_desc *desc, const char *label) { @@ -2456,7 +2467,7 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output_raw); */ int gpiod_direction_output(struct gpio_desc *desc, int value) { - struct gpio_chip *gc = desc->gdev->chip; + struct gpio_chip *gc; int ret; VALIDATE_DESC(desc); @@ -2473,6 +2484,7 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) return -EIO; } + gc = desc->gdev->chip; if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) { /* First see if we can enable open drain in hardware */ ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc), @@ -2529,6 +2541,50 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) } EXPORT_SYMBOL_GPL(gpiod_set_debounce); +/** + * gpiod_set_transitory - Lose or retain GPIO state on suspend or reset + * @desc: descriptor of the GPIO for which to configure persistence + * @transitory: True to lose state on suspend or reset, false for persistence + * + * Returns: + * 0 on success, otherwise a negative error code. + */ +int gpiod_set_transitory(struct gpio_desc *desc, bool transitory) +{ + struct gpio_chip *chip; + unsigned long packed; + int gpio; + int rc; + + VALIDATE_DESC(desc); + /* + * Handle FLAG_TRANSITORY first, enabling queries to gpiolib for + * persistence state. + */ + if (transitory) + set_bit(FLAG_TRANSITORY, &desc->flags); + else + clear_bit(FLAG_TRANSITORY, &desc->flags); + + /* If the driver supports it, set the persistence state now */ + chip = desc->gdev->chip; + if (!chip->set_config) + return 0; + + packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE, + !transitory); + gpio = gpio_chip_hwgpio(desc); + rc = chip->set_config(chip, gpio, packed); + if (rc == -ENOTSUPP) { + dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n", + gpio); + return 0; + } + + return rc; +} +EXPORT_SYMBOL_GPL(gpiod_set_transitory); + /** * gpiod_is_active_low - test whether a GPIO is active-low or not * @desc: the gpio descriptor to test @@ -3129,8 +3185,7 @@ bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset) if (offset >= chip->ngpio) return false; - return !test_bit(FLAG_SLEEP_MAY_LOSE_VALUE, - &chip->gpiodev->descs[offset].flags); + return !test_bit(FLAG_TRANSITORY, &chip->gpiodev->descs[offset].flags); } EXPORT_SYMBOL_GPL(gpiochip_line_is_persistent); @@ -3565,8 +3620,10 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, if (lflags & GPIO_OPEN_SOURCE) set_bit(FLAG_OPEN_SOURCE, &desc->flags); - if (lflags & GPIO_SLEEP_MAY_LOSE_VALUE) - set_bit(FLAG_SLEEP_MAY_LOSE_VALUE, &desc->flags); + + status = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY)); + if (status < 0) + return status; /* No particular flag request, return here... */ if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) { @@ -3606,6 +3663,8 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, struct gpio_desc *desc = NULL; int status; enum gpio_lookup_flags lookupflags = 0; + /* Maybe we have a device name, maybe not */ + const char *devname = dev ? dev_name(dev) : "?"; dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id); @@ -3634,7 +3693,11 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, return desc; } - status = gpiod_request(desc, con_id); + /* + * If a connection label was passed use that, else attempt to use + * the device name as label + */ + status = gpiod_request(desc, con_id ? con_id : devname); if (status < 0) return ERR_PTR(status); @@ -3649,18 +3712,89 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, } EXPORT_SYMBOL_GPL(gpiod_get_index); +/** + * gpiod_get_from_of_node() - obtain a GPIO from an OF node + * @node: handle of the OF node + * @propname: name of the DT property representing the GPIO + * @index: index of the GPIO to obtain for the consumer + * @dflags: GPIO initialization flags + * @label: label to attach to the requested GPIO + * + * Returns: + * On successful request the GPIO pin is configured in accordance with + * provided @dflags. If the node does not have the requested GPIO + * property, NULL is returned. + * + * In case of error an ERR_PTR() is returned. + */ +struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, + const char *propname, int index, + enum gpiod_flags dflags, + const char *label) +{ + struct gpio_desc *desc; + unsigned long lflags = 0; + enum of_gpio_flags flags; + bool active_low = false; + bool single_ended = false; + bool open_drain = false; + bool transitory = false; + int ret; + + desc = of_get_named_gpiod_flags(node, propname, + index, &flags); + + if (!desc || IS_ERR(desc)) { + /* If it is not there, just return NULL */ + if (PTR_ERR(desc) == -ENOENT) + return NULL; + return desc; + } + + active_low = flags & OF_GPIO_ACTIVE_LOW; + single_ended = flags & OF_GPIO_SINGLE_ENDED; + open_drain = flags & OF_GPIO_OPEN_DRAIN; + transitory = flags & OF_GPIO_TRANSITORY; + + ret = gpiod_request(desc, label); + if (ret) + return ERR_PTR(ret); + + if (active_low) + lflags |= GPIO_ACTIVE_LOW; + + if (single_ended) { + if (open_drain) + lflags |= GPIO_OPEN_DRAIN; + else + lflags |= GPIO_OPEN_SOURCE; + } + + if (transitory) + lflags |= GPIO_TRANSITORY; + + ret = gpiod_configure_flags(desc, propname, lflags, dflags); + if (ret < 0) { + gpiod_put(desc); + return ERR_PTR(ret); + } + + return desc; +} +EXPORT_SYMBOL(gpiod_get_from_of_node); + /** * fwnode_get_named_gpiod - obtain a GPIO from firmware node * @fwnode: handle of the firmware node * @propname: name of the firmware property representing the GPIO - * @index: index of the GPIO to obtain in the consumer + * @index: index of the GPIO to obtain for the consumer * @dflags: GPIO initialization flags * @label: label to attach to the requested GPIO * * This function can be used for drivers that get their configuration - * from firmware. + * from opaque firmware. * - * Function properly finds the corresponding GPIO using whatever is the + * The function properly finds the corresponding GPIO using whatever is the * underlying firmware interface and then makes sure that the GPIO * descriptor is requested before it is returned to the caller. * @@ -3677,53 +3811,35 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, { struct gpio_desc *desc = ERR_PTR(-ENODEV); unsigned long lflags = 0; - bool active_low = false; - bool single_ended = false; - bool open_drain = false; int ret; if (!fwnode) return ERR_PTR(-EINVAL); if (is_of_node(fwnode)) { - enum of_gpio_flags flags; - - desc = of_get_named_gpiod_flags(to_of_node(fwnode), propname, - index, &flags); - if (!IS_ERR(desc)) { - active_low = flags & OF_GPIO_ACTIVE_LOW; - single_ended = flags & OF_GPIO_SINGLE_ENDED; - open_drain = flags & OF_GPIO_OPEN_DRAIN; - } + desc = gpiod_get_from_of_node(to_of_node(fwnode), + propname, index, + dflags, + label); + return desc; } else if (is_acpi_node(fwnode)) { struct acpi_gpio_info info; desc = acpi_node_get_gpiod(fwnode, propname, index, &info); - if (!IS_ERR(desc)) { - active_low = info.polarity == GPIO_ACTIVE_LOW; - ret = acpi_gpio_update_gpiod_flags(&dflags, info.flags); - if (ret) - pr_debug("Override GPIO initialization flags\n"); - } + if (IS_ERR(desc)) + return desc; + + acpi_gpio_update_gpiod_flags(&dflags, &info); + + if (info.polarity == GPIO_ACTIVE_LOW) + lflags |= GPIO_ACTIVE_LOW; } - if (IS_ERR(desc)) - return desc; - + /* Currently only ACPI takes this path */ ret = gpiod_request(desc, label); if (ret) return ERR_PTR(ret); - if (active_low) - lflags |= GPIO_ACTIVE_LOW; - - if (single_ended) { - if (open_drain) - lflags |= GPIO_OPEN_DRAIN; - else - lflags |= GPIO_OPEN_SOURCE; - } - ret = gpiod_configure_flags(desc, propname, lflags, dflags); if (ret < 0) { gpiod_put(desc); diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 6c44d1652139..b17ec6795c81 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -58,7 +58,7 @@ struct gpio_device { struct gpio_desc *descs; int base; u16 ngpio; - char *label; + const char *label; void *data; struct list_head list; @@ -75,16 +75,20 @@ struct gpio_device { /** * struct acpi_gpio_info - ACPI GPIO specific information + * @adev: reference to ACPI device which consumes GPIO resource * @flags: GPIO initialization flags * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo * @polarity: interrupt polarity as provided by ACPI * @triggering: triggering type as provided by ACPI + * @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping */ struct acpi_gpio_info { + struct acpi_device *adev; enum gpiod_flags flags; bool gpioint; int polarity; int triggering; + unsigned int quirks; }; /* gpio suffixes used for ACPI and device tree lookup */ @@ -124,7 +128,7 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, - enum gpiod_flags update); + struct acpi_gpio_info *info); struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, @@ -149,7 +153,7 @@ static inline void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } static inline int -acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update) +acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info) { return 0; } @@ -189,6 +193,12 @@ void gpiod_set_array_value_complex(bool raw, bool can_sleep, struct gpio_desc **desc_array, int *value_array); +/* This is just passed between gpiolib and devres */ +struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, + const char *propname, int index, + enum gpiod_flags dflags, + const char *label); + extern struct spinlock gpio_lock; extern struct list_head gpio_devices; @@ -205,7 +215,7 @@ struct gpio_desc { #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ #define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ #define FLAG_IS_HOGGED 11 /* GPIO is hogged */ -#define FLAG_SLEEP_MAY_LOSE_VALUE 12 /* GPIO may lose value in sleep */ +#define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */ /* Connection label */ const char *label; diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index d6e5b7273853..be5e5acc3e39 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -63,7 +63,7 @@ amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \ amdgpu-$(CONFIG_DRM_AMDGPU_SI)+= si.o gmc_v6_0.o gfx_v6_0.o si_ih.o si_dma.o dce_v6_0.o si_dpm.o si_smc.o amdgpu-y += \ - vi.o mxgpu_vi.o nbio_v6_1.o soc15.o mxgpu_ai.o nbio_v7_0.o vega10_reg_init.o + vi.o mxgpu_vi.o nbio_v6_1.o soc15.o emu_soc.o mxgpu_ai.o nbio_v7_0.o vega10_reg_init.o # add GMC block amdgpu-y += \ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index d5a2eefd6c3e..1ac81be374dd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -68,6 +68,7 @@ #include "amdgpu_vce.h" #include "amdgpu_vcn.h" #include "amdgpu_mn.h" +#include "amdgpu_gmc.h" #include "amdgpu_dm.h" #include "amdgpu_virt.h" #include "amdgpu_gart.h" @@ -127,6 +128,7 @@ extern int amdgpu_job_hang_limit; extern int amdgpu_lbpw; extern int amdgpu_compute_multipipe; extern int amdgpu_gpu_recovery; +extern int amdgpu_emu_mode; #ifdef CONFIG_DRM_AMDGPU_SI extern int amdgpu_si_support; @@ -318,13 +320,6 @@ struct amdgpu_vm_pte_funcs { void (*write_pte)(struct amdgpu_ib *ib, uint64_t pe, uint64_t value, unsigned count, uint32_t incr); - - /* maximum nums of PTEs/PDEs in a single operation */ - uint32_t set_max_nums_pte_pde; - - /* number of dw to reserve per operation */ - unsigned set_pte_pde_num_dw; - /* for linear pte/pde updates without addr mapping */ void (*set_pte_pde)(struct amdgpu_ib *ib, uint64_t pe, @@ -332,28 +327,6 @@ struct amdgpu_vm_pte_funcs { uint32_t incr, uint64_t flags); }; -/* provided by the gmc block */ -struct amdgpu_gart_funcs { - /* flush the vm tlb via mmio */ - void (*flush_gpu_tlb)(struct amdgpu_device *adev, - uint32_t vmid); - /* write pte/pde updates using the cpu */ - int (*set_pte_pde)(struct amdgpu_device *adev, - void *cpu_pt_addr, /* cpu addr of page table */ - uint32_t gpu_page_idx, /* pte/pde to update */ - uint64_t addr, /* addr to write into pte/pde */ - uint64_t flags); /* access flags */ - /* enable/disable PRT support */ - void (*set_prt)(struct amdgpu_device *adev, bool enable); - /* set pte flags based per asic */ - uint64_t (*get_vm_pte_flags)(struct amdgpu_device *adev, - uint32_t flags); - /* get the pde for a given mc addr */ - void (*get_vm_pde)(struct amdgpu_device *adev, int level, - u64 *dst, u64 *flags); - uint32_t (*get_invalidate_req)(unsigned int vmid); -}; - /* provided by the ih block */ struct amdgpu_ih_funcs { /* ring read/write ptr handling, called from interrupt context */ @@ -418,8 +391,8 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev, struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev, struct drm_gem_object *gobj, int flags); -int amdgpu_gem_prime_pin(struct drm_gem_object *obj); -void amdgpu_gem_prime_unpin(struct drm_gem_object *obj); +struct drm_gem_object *amdgpu_gem_prime_import(struct drm_device *dev, + struct dma_buf *dma_buf); struct reservation_object *amdgpu_gem_prime_res_obj(struct drm_gem_object *); void *amdgpu_gem_prime_vmap(struct drm_gem_object *obj); void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); @@ -493,56 +466,6 @@ int amdgpu_mode_dumb_mmap(struct drm_file *filp, int amdgpu_fence_slab_init(void); void amdgpu_fence_slab_fini(void); -/* - * VMHUB structures, functions & helpers - */ -struct amdgpu_vmhub { - uint32_t ctx0_ptb_addr_lo32; - uint32_t ctx0_ptb_addr_hi32; - uint32_t vm_inv_eng0_req; - uint32_t vm_inv_eng0_ack; - uint32_t vm_context0_cntl; - uint32_t vm_l2_pro_fault_status; - uint32_t vm_l2_pro_fault_cntl; -}; - -/* - * GPU MC structures, functions & helpers - */ -struct amdgpu_mc { - resource_size_t aper_size; - resource_size_t aper_base; - resource_size_t agp_base; - /* for some chips with <= 32MB we need to lie - * about vram size near mc fb location */ - u64 mc_vram_size; - u64 visible_vram_size; - u64 gart_size; - u64 gart_start; - u64 gart_end; - u64 vram_start; - u64 vram_end; - unsigned vram_width; - u64 real_vram_size; - int vram_mtrr; - u64 mc_mask; - const struct firmware *fw; /* MC firmware */ - uint32_t fw_version; - struct amdgpu_irq_src vm_fault; - uint32_t vram_type; - uint32_t srbm_soft_reset; - bool prt_warning; - uint64_t stolen_size; - /* apertures */ - u64 shared_aperture_start; - u64 shared_aperture_end; - u64 private_aperture_start; - u64 private_aperture_end; - /* protects concurrent invalidation */ - spinlock_t invalidate_lock; - bool translate_further; -}; - /* * GPU doorbell structures, functions & helpers */ @@ -1125,8 +1048,9 @@ struct amdgpu_job { void *owner; uint64_t fence_ctx; /* the fence_context this job uses */ bool vm_needs_flush; - unsigned vmid; uint64_t vm_pd_addr; + unsigned vmid; + unsigned pasid; uint32_t gds_base, gds_size; uint32_t gws_base, gws_size; uint32_t oa_base, oa_size; @@ -1288,6 +1212,11 @@ struct amdgpu_asic_funcs { void (*set_pcie_lanes)(struct amdgpu_device *adev, int lanes); /* get config memsize register */ u32 (*get_config_memsize)(struct amdgpu_device *adev); + /* flush hdp write queue */ + void (*flush_hdp)(struct amdgpu_device *adev, struct amdgpu_ring *ring); + /* invalidate hdp read cache */ + void (*invalidate_hdp)(struct amdgpu_device *adev, + struct amdgpu_ring *ring); }; /* @@ -1431,7 +1360,7 @@ struct amdgpu_nbio_funcs { u32 (*get_pcie_data_offset)(struct amdgpu_device *adev); u32 (*get_rev_id)(struct amdgpu_device *adev); void (*mc_access_enable)(struct amdgpu_device *adev, bool enable); - void (*hdp_flush)(struct amdgpu_device *adev); + void (*hdp_flush)(struct amdgpu_device *adev, struct amdgpu_ring *ring); u32 (*get_memsize)(struct amdgpu_device *adev); void (*sdma_doorbell_range)(struct amdgpu_device *adev, int instance, bool use_doorbell, int doorbell_index); @@ -1504,6 +1433,7 @@ struct amdgpu_device { const struct amdgpu_asic_funcs *asic_funcs; bool shutdown; bool need_dma32; + bool need_swiotlb; bool accel_working; struct work_struct reset_work; struct notifier_block acpi_nb; @@ -1573,7 +1503,7 @@ struct amdgpu_device { struct amdgpu_clock clock; /* MC */ - struct amdgpu_mc mc; + struct amdgpu_gmc gmc; struct amdgpu_gart gart; struct amdgpu_dummy_page dummy_page; struct amdgpu_vm_manager vm_manager; @@ -1725,6 +1655,8 @@ void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v); bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type); bool amdgpu_device_has_dc_support(struct amdgpu_device *adev); +int emu_soc_asic_init(struct amdgpu_device *adev); + /* * Registers read & write functions. */ @@ -1837,13 +1769,17 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring) #define amdgpu_asic_read_bios_from_rom(adev, b, l) (adev)->asic_funcs->read_bios_from_rom((adev), (b), (l)) #define amdgpu_asic_read_register(adev, se, sh, offset, v)((adev)->asic_funcs->read_register((adev), (se), (sh), (offset), (v))) #define amdgpu_asic_get_config_memsize(adev) (adev)->asic_funcs->get_config_memsize((adev)) -#define amdgpu_gart_flush_gpu_tlb(adev, vmid) (adev)->gart.gart_funcs->flush_gpu_tlb((adev), (vmid)) -#define amdgpu_gart_set_pte_pde(adev, pt, idx, addr, flags) (adev)->gart.gart_funcs->set_pte_pde((adev), (pt), (idx), (addr), (flags)) -#define amdgpu_gart_get_vm_pde(adev, level, dst, flags) (adev)->gart.gart_funcs->get_vm_pde((adev), (level), (dst), (flags)) +#define amdgpu_asic_flush_hdp(adev, r) (adev)->asic_funcs->flush_hdp((adev), (r)) +#define amdgpu_asic_invalidate_hdp(adev, r) (adev)->asic_funcs->invalidate_hdp((adev), (r)) +#define amdgpu_gmc_flush_gpu_tlb(adev, vmid) (adev)->gmc.gmc_funcs->flush_gpu_tlb((adev), (vmid)) +#define amdgpu_gmc_emit_flush_gpu_tlb(r, vmid, addr) (r)->adev->gmc.gmc_funcs->emit_flush_gpu_tlb((r), (vmid), (addr)) +#define amdgpu_gmc_emit_pasid_mapping(r, vmid, pasid) (r)->adev->gmc.gmc_funcs->emit_pasid_mapping((r), (vmid), (pasid)) +#define amdgpu_gmc_set_pte_pde(adev, pt, idx, addr, flags) (adev)->gmc.gmc_funcs->set_pte_pde((adev), (pt), (idx), (addr), (flags)) +#define amdgpu_gmc_get_vm_pde(adev, level, dst, flags) (adev)->gmc.gmc_funcs->get_vm_pde((adev), (level), (dst), (flags)) +#define amdgpu_gmc_get_pte_flags(adev, flags) (adev)->gmc.gmc_funcs->get_vm_pte_flags((adev),(flags)) #define amdgpu_vm_copy_pte(adev, ib, pe, src, count) ((adev)->vm_manager.vm_pte_funcs->copy_pte((ib), (pe), (src), (count))) #define amdgpu_vm_write_pte(adev, ib, pe, value, count, incr) ((adev)->vm_manager.vm_pte_funcs->write_pte((ib), (pe), (value), (count), (incr))) #define amdgpu_vm_set_pte_pde(adev, ib, pe, addr, count, incr, flags) ((adev)->vm_manager.vm_pte_funcs->set_pte_pde((ib), (pe), (addr), (count), (incr), (flags))) -#define amdgpu_vm_get_pte_flags(adev, flags) (adev)->gart.gart_funcs->get_vm_pte_flags((adev),(flags)) #define amdgpu_ring_parse_cs(r, p, ib) ((r)->funcs->parse_cs((p), (ib))) #define amdgpu_ring_test_ring(r) (r)->funcs->test_ring((r)) #define amdgpu_ring_test_ib(r, t) (r)->funcs->test_ib((r), (t)) @@ -1856,11 +1792,11 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring) #define amdgpu_ring_emit_fence(r, addr, seq, flags) (r)->funcs->emit_fence((r), (addr), (seq), (flags)) #define amdgpu_ring_emit_gds_switch(r, v, db, ds, wb, ws, ab, as) (r)->funcs->emit_gds_switch((r), (v), (db), (ds), (wb), (ws), (ab), (as)) #define amdgpu_ring_emit_hdp_flush(r) (r)->funcs->emit_hdp_flush((r)) -#define amdgpu_ring_emit_hdp_invalidate(r) (r)->funcs->emit_hdp_invalidate((r)) #define amdgpu_ring_emit_switch_buffer(r) (r)->funcs->emit_switch_buffer((r)) #define amdgpu_ring_emit_cntxcntl(r, d) (r)->funcs->emit_cntxcntl((r), (d)) #define amdgpu_ring_emit_rreg(r, d) (r)->funcs->emit_rreg((r), (d)) #define amdgpu_ring_emit_wreg(r, d, v) (r)->funcs->emit_wreg((r), (d), (v)) +#define amdgpu_ring_emit_reg_wait(r, d, v, m) (r)->funcs->emit_reg_wait((r), (d), (v), (m)) #define amdgpu_ring_emit_tmz(r, b) (r)->funcs->emit_tmz((r), (b)) #define amdgpu_ring_pad_ib(r, ib) ((r)->funcs->pad_ib((r), (ib))) #define amdgpu_ring_init_cond_exec(r) (r)->funcs->init_cond_exec((r)) @@ -1870,7 +1806,6 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring) #define amdgpu_ih_decode_iv(adev, iv) (adev)->irq.ih_funcs->decode_iv((adev), (iv)) #define amdgpu_ih_set_rptr(adev) (adev)->irq.ih_funcs->set_rptr((adev)) #define amdgpu_display_vblank_get_counter(adev, crtc) (adev)->mode_info.funcs->vblank_get_counter((adev), (crtc)) -#define amdgpu_display_vblank_wait(adev, crtc) (adev)->mode_info.funcs->vblank_wait((adev), (crtc)) #define amdgpu_display_backlight_set_level(adev, e, l) (adev)->mode_info.funcs->backlight_set_level((e), (l)) #define amdgpu_display_backlight_get_level(adev, e) (adev)->mode_info.funcs->backlight_get_level((e)) #define amdgpu_display_hpd_sense(adev, h) (adev)->mode_info.funcs->hpd_sense((adev), (h)) @@ -1893,16 +1828,16 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, struct amdgpu_job* job, bool force); void amdgpu_device_pci_config_reset(struct amdgpu_device *adev); bool amdgpu_device_need_post(struct amdgpu_device *adev); -void amdgpu_update_display_priority(struct amdgpu_device *adev); +void amdgpu_display_update_priority(struct amdgpu_device *adev); void amdgpu_cs_report_moved_bytes(struct amdgpu_device *adev, u64 num_bytes, u64 num_vis_bytes); void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain); bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo); void amdgpu_device_vram_location(struct amdgpu_device *adev, - struct amdgpu_mc *mc, u64 base); + struct amdgpu_gmc *mc, u64 base); void amdgpu_device_gart_location(struct amdgpu_device *adev, - struct amdgpu_mc *mc); + struct amdgpu_gmc *mc); int amdgpu_device_resize_fb_bar(struct amdgpu_device *adev); void amdgpu_ttm_set_active_vram_size(struct amdgpu_device *adev, u64 size); int amdgpu_ttm_init(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 1d605e1c1d66..450426dbed92 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -216,8 +216,7 @@ int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, return -ENOMEM; r = amdgpu_bo_create(adev, size, PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_GTT, - AMDGPU_GEM_CREATE_CPU_GTT_USWC, NULL, NULL, 0, - &(*mem)->bo); + AMDGPU_GEM_CREATE_CPU_GTT_USWC, NULL, NULL, &(*mem)->bo); if (r) { dev_err(adev->dev, "failed to allocate BO for amdkfd (%d)\n", r); @@ -281,24 +280,29 @@ void get_local_mem_info(struct kgd_dev *kgd, struct amdgpu_device *adev = (struct amdgpu_device *)kgd; uint64_t address_mask = adev->dev->dma_mask ? ~*adev->dev->dma_mask : ~((1ULL << 32) - 1); - resource_size_t aper_limit = adev->mc.aper_base + adev->mc.aper_size; + resource_size_t aper_limit = adev->gmc.aper_base + adev->gmc.aper_size; memset(mem_info, 0, sizeof(*mem_info)); - if (!(adev->mc.aper_base & address_mask || aper_limit & address_mask)) { - mem_info->local_mem_size_public = adev->mc.visible_vram_size; - mem_info->local_mem_size_private = adev->mc.real_vram_size - - adev->mc.visible_vram_size; + if (!(adev->gmc.aper_base & address_mask || aper_limit & address_mask)) { + mem_info->local_mem_size_public = adev->gmc.visible_vram_size; + mem_info->local_mem_size_private = adev->gmc.real_vram_size - + adev->gmc.visible_vram_size; } else { mem_info->local_mem_size_public = 0; - mem_info->local_mem_size_private = adev->mc.real_vram_size; + mem_info->local_mem_size_private = adev->gmc.real_vram_size; } - mem_info->vram_width = adev->mc.vram_width; + mem_info->vram_width = adev->gmc.vram_width; pr_debug("Address base: %pap limit %pap public 0x%llx private 0x%llx\n", - &adev->mc.aper_base, &aper_limit, + &adev->gmc.aper_base, &aper_limit, mem_info->local_mem_size_public, mem_info->local_mem_size_private); + if (amdgpu_emu_mode == 1) { + mem_info->mem_clk_max = 100; + return; + } + if (amdgpu_sriov_vf(adev)) mem_info->mem_clk_max = adev->clock.default_mclk / 100; else @@ -319,6 +323,9 @@ uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd) struct amdgpu_device *adev = (struct amdgpu_device *)kgd; /* the sclk is in quantas of 10kHz */ + if (amdgpu_emu_mode == 1) + return 100; + if (amdgpu_sriov_vf(adev)) return adev->clock.default_sclk / 100; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c index e2c3c5ec42d1..c53095b3b0fb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c @@ -568,6 +568,7 @@ static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = { /* HG _PR3 doesn't seem to work on this A+A weston board */ { 0x1002, 0x6900, 0x1002, 0x0124, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX }, + { 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0, 0, 0, 0, 0 }, }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c index 63ec1e1bb6aa..2fb299afc12b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c @@ -81,7 +81,7 @@ static void amdgpu_benchmark_move(struct amdgpu_device *adev, unsigned size, n = AMDGPU_BENCHMARK_ITERATIONS; r = amdgpu_bo_create(adev, size, PAGE_SIZE, true, sdomain, 0, NULL, - NULL, 0, &sobj); + NULL, &sobj); if (r) { goto out_cleanup; } @@ -94,7 +94,7 @@ static void amdgpu_benchmark_move(struct amdgpu_device *adev, unsigned size, goto out_cleanup; } r = amdgpu_bo_create(adev, size, PAGE_SIZE, true, ddomain, 0, NULL, - NULL, 0, &dobj); + NULL, &dobj); if (r) { goto out_cleanup; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 59089e027f4d..92be7f6de197 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -233,8 +233,10 @@ void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list, for (i = 0; i < list->num_entries; i++) { unsigned priority = list->array[i].priority; - list_add_tail(&list->array[i].tv.head, - &bucket[priority]); + if (!list->array[i].robj->parent) + list_add_tail(&list->array[i].tv.head, + &bucket[priority]); + list->array[i].user_pages = NULL; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c index 4466f3535e2d..dc3360b16bda 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c @@ -109,7 +109,7 @@ static int amdgpu_cgs_alloc_gpu_mem(struct cgs_device *cgs_device, *handle = 0; ret = amdgpu_bo_create(adev, size, align, true, domain, flags, - NULL, NULL, 0, &obj); + NULL, NULL, &obj); if (ret) { DRM_ERROR("(%d) bo create failed\n", ret); return ret; @@ -953,6 +953,11 @@ static int amdgpu_cgs_get_active_displays_info(struct cgs_device *cgs_device, (amdgpu_crtc->v_border * 2); mode_info->vblank_time_us = vblank_lines * line_time_us; mode_info->refresh_rate = drm_mode_vrefresh(&amdgpu_crtc->hw_mode); + /* we have issues with mclk switching with refresh rates + * over 120 hz on the non-DC code. + */ + if (mode_info->refresh_rate > 120) + mode_info->vblank_time_us = 0; mode_info = NULL; } } @@ -1187,6 +1192,18 @@ static int amdgpu_cgs_call_acpi_method(struct cgs_device *cgs_device, return amdgpu_cgs_acpi_eval_object(cgs_device, &info); } +static int amdgpu_cgs_set_temperature_range(struct cgs_device *cgs_device, + int min_temperature, + int max_temperature) +{ + CGS_FUNC_ADEV; + + adev->pm.dpm.thermal.min_temp = min_temperature; + adev->pm.dpm.thermal.max_temp = max_temperature; + + return 0; +} + static const struct cgs_ops amdgpu_cgs_ops = { .alloc_gpu_mem = amdgpu_cgs_alloc_gpu_mem, .free_gpu_mem = amdgpu_cgs_free_gpu_mem, @@ -1214,6 +1231,7 @@ static const struct cgs_ops amdgpu_cgs_ops = { .enter_safe_mode = amdgpu_cgs_enter_safe_mode, .lock_grbm_idx = amdgpu_cgs_lock_grbm_idx, .register_pp_handle = amdgpu_cgs_register_pp_handle, + .set_temperature_range = amdgpu_cgs_set_temperature_range, }; static const struct cgs_os_ops amdgpu_cgs_os_ops = { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index 8ca3783f2deb..ffc1f6f46913 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -877,7 +877,7 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force) ret = connector_status_disconnected; if (amdgpu_connector->ddc_bus) - dret = amdgpu_ddc_probe(amdgpu_connector, false); + dret = amdgpu_display_ddc_probe(amdgpu_connector, false); if (dret) { amdgpu_connector->detected_by_load = false; amdgpu_connector_free_edid(connector); @@ -998,7 +998,7 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) } if (amdgpu_connector->ddc_bus) - dret = amdgpu_ddc_probe(amdgpu_connector, false); + dret = amdgpu_display_ddc_probe(amdgpu_connector, false); if (dret) { amdgpu_connector->detected_by_load = false; amdgpu_connector_free_edid(connector); @@ -1401,7 +1401,8 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force) /* setup ddc on the bridge */ amdgpu_atombios_encoder_setup_ext_encoder_ddc(encoder); /* bridge chips are always aux */ - if (amdgpu_ddc_probe(amdgpu_connector, true)) /* try DDC */ + /* try DDC */ + if (amdgpu_display_ddc_probe(amdgpu_connector, true)) ret = connector_status_connected; else if (amdgpu_connector->dac_load_detect) { /* try load detection */ const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; @@ -1421,7 +1422,8 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force) ret = connector_status_connected; } else { /* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */ - if (amdgpu_ddc_probe(amdgpu_connector, false)) + if (amdgpu_display_ddc_probe(amdgpu_connector, + false)) ret = connector_status_connected; } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index e80fc38141b5..eaa3cb0c3ad1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -257,7 +257,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev, return; } - total_vram = adev->mc.real_vram_size - adev->vram_pin_size; + total_vram = adev->gmc.real_vram_size - adev->vram_pin_size; used_vram = amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); free_vram = used_vram >= total_vram ? 0 : total_vram - used_vram; @@ -302,8 +302,8 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev, *max_bytes = us_to_bytes(adev, adev->mm_stats.accum_us); /* Do the same for visible VRAM if half of it is free */ - if (adev->mc.visible_vram_size < adev->mc.real_vram_size) { - u64 total_vis_vram = adev->mc.visible_vram_size; + if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size) { + u64 total_vis_vram = adev->gmc.visible_vram_size; u64 used_vis_vram = amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); @@ -359,7 +359,7 @@ static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p, * to move it. Don't move anything if the threshold is zero. */ if (p->bytes_moved < p->bytes_moved_threshold) { - if (adev->mc.visible_vram_size < adev->mc.real_vram_size && + if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size && (bo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)) { /* And don't move a CPU_ACCESS_REQUIRED BO to limited * visible VRAM if we've depleted our allowance to do @@ -381,9 +381,9 @@ retry: r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); p->bytes_moved += ctx.bytes_moved; - if (adev->mc.visible_vram_size < adev->mc.real_vram_size && + if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size && bo->tbo.mem.mem_type == TTM_PL_VRAM && - bo->tbo.mem.start < adev->mc.visible_vram_size >> PAGE_SHIFT) + bo->tbo.mem.start < adev->gmc.visible_vram_size >> PAGE_SHIFT) p->bytes_moved_vis += ctx.bytes_moved; if (unlikely(r == -ENOMEM) && domain != bo->allowed_domains) { @@ -437,9 +437,9 @@ static bool amdgpu_cs_try_evict(struct amdgpu_cs_parser *p, /* Good we can try to move this BO somewhere else */ amdgpu_ttm_placement_from_domain(bo, other); update_bytes_moved_vis = - adev->mc.visible_vram_size < adev->mc.real_vram_size && + adev->gmc.visible_vram_size < adev->gmc.real_vram_size && bo->tbo.mem.mem_type == TTM_PL_VRAM && - bo->tbo.mem.start < adev->mc.visible_vram_size >> PAGE_SHIFT; + bo->tbo.mem.start < adev->gmc.visible_vram_size >> PAGE_SHIFT; initial_bytes_moved = atomic64_read(&adev->num_bytes_moved); r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); bytes_moved = atomic64_read(&adev->num_bytes_moved) - @@ -542,7 +542,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, INIT_LIST_HEAD(&duplicates); amdgpu_vm_get_pd_bo(&fpriv->vm, &p->validated, &p->vm_pd); - if (p->uf_entry.robj) + if (p->uf_entry.robj && !p->uf_entry.robj->parent) list_add(&p->uf_entry.tv.head, &p->validated); while (1) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 00a50cc5ec9a..d2a5f48c5767 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -544,7 +544,7 @@ void amdgpu_device_wb_free(struct amdgpu_device *adev, u32 wb) * as parameter. */ void amdgpu_device_vram_location(struct amdgpu_device *adev, - struct amdgpu_mc *mc, u64 base) + struct amdgpu_gmc *mc, u64 base) { uint64_t limit = (uint64_t)amdgpu_vram_limit << 20; @@ -570,11 +570,11 @@ void amdgpu_device_vram_location(struct amdgpu_device *adev, * FIXME: when reducing GTT size align new size on power of 2. */ void amdgpu_device_gart_location(struct amdgpu_device *adev, - struct amdgpu_mc *mc) + struct amdgpu_gmc *mc) { u64 size_af, size_bf; - size_af = adev->mc.mc_mask - mc->vram_end; + size_af = adev->gmc.mc_mask - mc->vram_end; size_bf = mc->vram_start; if (size_bf > size_af) { if (mc->gart_size > size_bf) { @@ -608,7 +608,7 @@ void amdgpu_device_gart_location(struct amdgpu_device *adev, */ int amdgpu_device_resize_fb_bar(struct amdgpu_device *adev) { - u64 space_needed = roundup_pow_of_two(adev->mc.real_vram_size); + u64 space_needed = roundup_pow_of_two(adev->gmc.real_vram_size); u32 rbar_size = order_base_2(((space_needed >> 20) | 1)) - 1; struct pci_bus *root; struct resource *res; @@ -1036,7 +1036,7 @@ int amdgpu_device_ip_block_add(struct amdgpu_device *adev, if (!ip_block_version) return -EINVAL; - DRM_DEBUG("add ip block number %d <%s>\n", adev->num_ip_blocks, + DRM_INFO("add ip block number %d <%s>\n", adev->num_ip_blocks, ip_block_version->funcs->name); adev->ip_blocks[adev->num_ip_blocks++].version = ip_block_version; @@ -1310,6 +1310,7 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) return r; } adev->ip_blocks[i].status.sw = true; + /* need to do gmc hw init early so we can allocate gpu mem */ if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) { r = amdgpu_device_vram_scratch_init(adev); @@ -1343,8 +1344,7 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].status.sw) continue; - /* gmc hw init is done early */ - if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) + if (adev->ip_blocks[i].status.hw) continue; r = adev->ip_blocks[i].version->funcs->hw_init((void *)adev); if (r) { @@ -1378,6 +1378,9 @@ static int amdgpu_device_ip_late_set_cg_state(struct amdgpu_device *adev) { int i = 0, r; + if (amdgpu_emu_mode == 1) + return 0; + for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].status.valid) continue; @@ -1483,6 +1486,9 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev) adev->ip_blocks[i].status.hw = false; } + /* disable all interrupts */ + amdgpu_irq_disable_all(adev); + for (i = adev->num_ip_blocks - 1; i >= 0; i--) { if (!adev->ip_blocks[i].status.sw) continue; @@ -1701,6 +1707,8 @@ bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type) case CHIP_BONAIRE: case CHIP_HAWAII: case CHIP_KAVERI: + case CHIP_KABINI: + case CHIP_MULLINS: case CHIP_CARRIZO: case CHIP_STONEY: case CHIP_POLARIS11: @@ -1711,9 +1719,6 @@ bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type) #if defined(CONFIG_DRM_AMD_DC_PRE_VEGA) return amdgpu_dc != 0; #endif - case CHIP_KABINI: - case CHIP_MULLINS: - return amdgpu_dc > 0; case CHIP_VEGA10: #if defined(CONFIG_DRM_AMD_DC_DCN1_0) case CHIP_RAVEN: @@ -1768,14 +1773,16 @@ int amdgpu_device_init(struct amdgpu_device *adev, adev->flags = flags; adev->asic_type = flags & AMD_ASIC_MASK; adev->usec_timeout = AMDGPU_MAX_USEC_TIMEOUT; - adev->mc.gart_size = 512 * 1024 * 1024; + if (amdgpu_emu_mode == 1) + adev->usec_timeout *= 2; + adev->gmc.gart_size = 512 * 1024 * 1024; adev->accel_working = false; adev->num_rings = 0; adev->mman.buffer_funcs = NULL; adev->mman.buffer_funcs_ring = NULL; adev->vm_manager.vm_pte_funcs = NULL; adev->vm_manager.vm_pte_num_rings = 0; - adev->gart.gart_funcs = NULL; + adev->gmc.gmc_funcs = NULL; adev->fence_context = dma_fence_context_alloc(AMDGPU_MAX_RINGS); bitmap_zero(adev->gfx.pipe_reserve_bitmap, AMDGPU_MAX_COMPUTE_QUEUES); @@ -1882,6 +1889,12 @@ int amdgpu_device_init(struct amdgpu_device *adev, if (runtime) vga_switcheroo_init_domain_pm_ops(adev->dev, &adev->vga_pm_domain); + if (amdgpu_emu_mode == 1) { + /* post the asic on emulation mode */ + emu_soc_asic_init(adev); + goto fence_driver_init; + } + /* Read BIOS */ if (!amdgpu_get_bios(adev)) { r = -EINVAL; @@ -1934,6 +1947,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, amdgpu_atombios_i2c_init(adev); } +fence_driver_init: /* Fence driver */ r = amdgpu_fence_driver_init(adev); if (r) { @@ -2076,7 +2090,10 @@ void amdgpu_device_fini(struct amdgpu_device *adev) /* free i2c buses */ if (!amdgpu_device_has_dc_support(adev)) amdgpu_i2c_fini(adev); - amdgpu_atombios_fini(adev); + + if (amdgpu_emu_mode != 1) + amdgpu_atombios_fini(adev); + kfree(adev->bios); adev->bios = NULL; if (!pci_is_thunderbolt_attached(adev->pdev)) @@ -2284,14 +2301,6 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon) drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); } drm_modeset_unlock_all(dev); - } else { - /* - * There is no equivalent atomic helper to turn on - * display, so we defined our own function for this, - * once suspend resume is supported by the atomic - * framework this will be reworked - */ - amdgpu_dm_display_resume(adev); } } @@ -2726,7 +2735,6 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, if (amdgpu_device_has_dc_support(adev)) { if (drm_atomic_helper_resume(adev->ddev, state)) dev_info(adev->dev, "drm resume failed:%d\n", r); - amdgpu_dm_display_resume(adev); } else { drm_helper_resume_force_mode(adev->ddev); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index c2fa5d55f04e..93f700ab1bfb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -29,6 +29,7 @@ #include "amdgpu_i2c.h" #include "atom.h" #include "amdgpu_connectors.h" +#include "amdgpu_display.h" #include #include @@ -36,7 +37,8 @@ #include #include -static void amdgpu_flip_callback(struct dma_fence *f, struct dma_fence_cb *cb) +static void amdgpu_display_flip_callback(struct dma_fence *f, + struct dma_fence_cb *cb) { struct amdgpu_flip_work *work = container_of(cb, struct amdgpu_flip_work, cb); @@ -45,8 +47,8 @@ static void amdgpu_flip_callback(struct dma_fence *f, struct dma_fence_cb *cb) schedule_work(&work->flip_work.work); } -static bool amdgpu_flip_handle_fence(struct amdgpu_flip_work *work, - struct dma_fence **f) +static bool amdgpu_display_flip_handle_fence(struct amdgpu_flip_work *work, + struct dma_fence **f) { struct dma_fence *fence= *f; @@ -55,14 +57,15 @@ static bool amdgpu_flip_handle_fence(struct amdgpu_flip_work *work, *f = NULL; - if (!dma_fence_add_callback(fence, &work->cb, amdgpu_flip_callback)) + if (!dma_fence_add_callback(fence, &work->cb, + amdgpu_display_flip_callback)) return true; dma_fence_put(fence); return false; } -static void amdgpu_flip_work_func(struct work_struct *__work) +static void amdgpu_display_flip_work_func(struct work_struct *__work) { struct delayed_work *delayed_work = container_of(__work, struct delayed_work, work); @@ -76,20 +79,20 @@ static void amdgpu_flip_work_func(struct work_struct *__work) unsigned i; int vpos, hpos; - if (amdgpu_flip_handle_fence(work, &work->excl)) + if (amdgpu_display_flip_handle_fence(work, &work->excl)) return; for (i = 0; i < work->shared_count; ++i) - if (amdgpu_flip_handle_fence(work, &work->shared[i])) + if (amdgpu_display_flip_handle_fence(work, &work->shared[i])) return; /* Wait until we're out of the vertical blank period before the one * targeted by the flip */ if (amdgpu_crtc->enabled && - (amdgpu_get_crtc_scanoutpos(adev->ddev, work->crtc_id, 0, - &vpos, &hpos, NULL, NULL, - &crtc->hwmode) + (amdgpu_display_get_crtc_scanoutpos(adev->ddev, work->crtc_id, 0, + &vpos, &hpos, NULL, NULL, + &crtc->hwmode) & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) == (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) && (int)(work->target_vblank - @@ -117,7 +120,7 @@ static void amdgpu_flip_work_func(struct work_struct *__work) /* * Handle unpin events outside the interrupt handler proper. */ -static void amdgpu_unpin_work_func(struct work_struct *__work) +static void amdgpu_display_unpin_work_func(struct work_struct *__work) { struct amdgpu_flip_work *work = container_of(__work, struct amdgpu_flip_work, unpin_work); @@ -139,11 +142,11 @@ static void amdgpu_unpin_work_func(struct work_struct *__work) kfree(work); } -int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event, - uint32_t page_flip_flags, uint32_t target, - struct drm_modeset_acquire_ctx *ctx) +int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t page_flip_flags, uint32_t target, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev = crtc->dev; struct amdgpu_device *adev = dev->dev_private; @@ -162,8 +165,8 @@ int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc, if (work == NULL) return -ENOMEM; - INIT_DELAYED_WORK(&work->flip_work, amdgpu_flip_work_func); - INIT_WORK(&work->unpin_work, amdgpu_unpin_work_func); + INIT_DELAYED_WORK(&work->flip_work, amdgpu_display_flip_work_func); + INIT_WORK(&work->unpin_work, amdgpu_display_unpin_work_func); work->event = event; work->adev = adev; @@ -189,7 +192,7 @@ int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc, goto cleanup; } - r = amdgpu_bo_pin(new_abo, AMDGPU_GEM_DOMAIN_VRAM, &base); + r = amdgpu_bo_pin(new_abo, amdgpu_display_framebuffer_domains(adev), &base); if (unlikely(r != 0)) { DRM_ERROR("failed to pin new abo buffer before flip\n"); goto unreserve; @@ -228,7 +231,7 @@ int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc, /* update crtc fb */ crtc->primary->fb = fb; spin_unlock_irqrestore(&crtc->dev->event_lock, flags); - amdgpu_flip_work_func(&work->flip_work.work); + amdgpu_display_flip_work_func(&work->flip_work.work); return 0; pflip_cleanup: @@ -254,8 +257,8 @@ cleanup: return r; } -int amdgpu_crtc_set_config(struct drm_mode_set *set, - struct drm_modeset_acquire_ctx *ctx) +int amdgpu_display_crtc_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev; struct amdgpu_device *adev; @@ -352,7 +355,7 @@ static const char *hpd_names[6] = { "HPD6", }; -void amdgpu_print_display_setup(struct drm_device *dev) +void amdgpu_display_print_display_setup(struct drm_device *dev) { struct drm_connector *connector; struct amdgpu_connector *amdgpu_connector; @@ -429,11 +432,11 @@ void amdgpu_print_display_setup(struct drm_device *dev) } /** - * amdgpu_ddc_probe + * amdgpu_display_ddc_probe * */ -bool amdgpu_ddc_probe(struct amdgpu_connector *amdgpu_connector, - bool use_aux) +bool amdgpu_display_ddc_probe(struct amdgpu_connector *amdgpu_connector, + bool use_aux) { u8 out = 0x0; u8 buf[8]; @@ -479,7 +482,7 @@ bool amdgpu_ddc_probe(struct amdgpu_connector *amdgpu_connector, return true; } -static void amdgpu_user_framebuffer_destroy(struct drm_framebuffer *fb) +static void amdgpu_display_user_framebuffer_destroy(struct drm_framebuffer *fb) { struct amdgpu_framebuffer *amdgpu_fb = to_amdgpu_framebuffer(fb); @@ -488,9 +491,10 @@ static void amdgpu_user_framebuffer_destroy(struct drm_framebuffer *fb) kfree(amdgpu_fb); } -static int amdgpu_user_framebuffer_create_handle(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int *handle) +static int amdgpu_display_user_framebuffer_create_handle( + struct drm_framebuffer *fb, + struct drm_file *file_priv, + unsigned int *handle) { struct amdgpu_framebuffer *amdgpu_fb = to_amdgpu_framebuffer(fb); @@ -498,15 +502,28 @@ static int amdgpu_user_framebuffer_create_handle(struct drm_framebuffer *fb, } static const struct drm_framebuffer_funcs amdgpu_fb_funcs = { - .destroy = amdgpu_user_framebuffer_destroy, - .create_handle = amdgpu_user_framebuffer_create_handle, + .destroy = amdgpu_display_user_framebuffer_destroy, + .create_handle = amdgpu_display_user_framebuffer_create_handle, }; -int -amdgpu_framebuffer_init(struct drm_device *dev, - struct amdgpu_framebuffer *rfb, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj) +uint32_t amdgpu_display_framebuffer_domains(struct amdgpu_device *adev) +{ + uint32_t domain = AMDGPU_GEM_DOMAIN_VRAM; + +#if defined(CONFIG_DRM_AMD_DC) + if (adev->asic_type >= CHIP_CARRIZO && adev->asic_type < CHIP_RAVEN && + adev->flags & AMD_IS_APU && + amdgpu_device_asic_has_dc_support(adev->asic_type)) + domain |= AMDGPU_GEM_DOMAIN_GTT; +#endif + + return domain; +} + +int amdgpu_display_framebuffer_init(struct drm_device *dev, + struct amdgpu_framebuffer *rfb, + const struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_gem_object *obj) { int ret; rfb->obj = obj; @@ -520,9 +537,9 @@ amdgpu_framebuffer_init(struct drm_device *dev, } struct drm_framebuffer * -amdgpu_user_framebuffer_create(struct drm_device *dev, - struct drm_file *file_priv, - const struct drm_mode_fb_cmd2 *mode_cmd) +amdgpu_display_user_framebuffer_create(struct drm_device *dev, + struct drm_file *file_priv, + const struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_gem_object *obj; struct amdgpu_framebuffer *amdgpu_fb; @@ -547,7 +564,7 @@ amdgpu_user_framebuffer_create(struct drm_device *dev, return ERR_PTR(-ENOMEM); } - ret = amdgpu_framebuffer_init(dev, amdgpu_fb, mode_cmd, obj); + ret = amdgpu_display_framebuffer_init(dev, amdgpu_fb, mode_cmd, obj); if (ret) { kfree(amdgpu_fb); drm_gem_object_put_unlocked(obj); @@ -558,7 +575,7 @@ amdgpu_user_framebuffer_create(struct drm_device *dev, } const struct drm_mode_config_funcs amdgpu_mode_funcs = { - .fb_create = amdgpu_user_framebuffer_create, + .fb_create = amdgpu_display_user_framebuffer_create, .output_poll_changed = drm_fb_helper_output_poll_changed, }; @@ -580,7 +597,7 @@ static const struct drm_prop_enum_list amdgpu_dither_enum_list[] = { AMDGPU_FMT_DITHER_ENABLE, "on" }, }; -int amdgpu_modeset_create_props(struct amdgpu_device *adev) +int amdgpu_display_modeset_create_props(struct amdgpu_device *adev) { int sz; @@ -629,7 +646,7 @@ int amdgpu_modeset_create_props(struct amdgpu_device *adev) return 0; } -void amdgpu_update_display_priority(struct amdgpu_device *adev) +void amdgpu_display_update_priority(struct amdgpu_device *adev) { /* adjustment options for the display watermarks */ if ((amdgpu_disp_priority == 0) || (amdgpu_disp_priority > 2)) @@ -639,7 +656,7 @@ void amdgpu_update_display_priority(struct amdgpu_device *adev) } -static bool is_hdtv_mode(const struct drm_display_mode *mode) +static bool amdgpu_display_is_hdtv_mode(const struct drm_display_mode *mode) { /* try and guess if this is a tv or a monitor */ if ((mode->vdisplay == 480 && mode->hdisplay == 720) || /* 480p */ @@ -651,9 +668,9 @@ static bool is_hdtv_mode(const struct drm_display_mode *mode) return false; } -bool amdgpu_crtc_scaling_mode_fixup(struct drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +bool amdgpu_display_crtc_scaling_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { struct drm_device *dev = crtc->dev; struct drm_encoder *encoder; @@ -696,7 +713,7 @@ bool amdgpu_crtc_scaling_mode_fixup(struct drm_crtc *crtc, ((amdgpu_encoder->underscan_type == UNDERSCAN_ON) || ((amdgpu_encoder->underscan_type == UNDERSCAN_AUTO) && drm_detect_hdmi_monitor(amdgpu_connector_edid(connector)) && - is_hdtv_mode(mode)))) { + amdgpu_display_is_hdtv_mode(mode)))) { if (amdgpu_encoder->underscan_hborder != 0) amdgpu_crtc->h_border = amdgpu_encoder->underscan_hborder; else @@ -764,10 +781,10 @@ bool amdgpu_crtc_scaling_mode_fixup(struct drm_crtc *crtc, * unknown small number of scanlines wrt. real scanout position. * */ -int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, - unsigned int flags, int *vpos, int *hpos, - ktime_t *stime, ktime_t *etime, - const struct drm_display_mode *mode) +int amdgpu_display_get_crtc_scanoutpos(struct drm_device *dev, + unsigned int pipe, unsigned int flags, int *vpos, + int *hpos, ktime_t *stime, ktime_t *etime, + const struct drm_display_mode *mode) { u32 vbl = 0, position = 0; int vbl_start, vbl_end, vtotal, ret = 0; @@ -859,7 +876,7 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, return ret; } -int amdgpu_crtc_idx_to_irq_type(struct amdgpu_device *adev, int crtc) +int amdgpu_display_crtc_idx_to_irq_type(struct amdgpu_device *adev, int crtc) { if (crtc < 0 || crtc >= adev->mode_info.num_crtc) return AMDGPU_CRTC_IRQ_NONE; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h index 0bcb6c6e0ca9..2b11d808f297 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h @@ -23,9 +23,10 @@ #ifndef __AMDGPU_DISPLAY_H__ #define __AMDGPU_DISPLAY_H__ +uint32_t amdgpu_display_framebuffer_domains(struct amdgpu_device *adev); struct drm_framebuffer * -amdgpu_user_framebuffer_create(struct drm_device *dev, - struct drm_file *file_priv, - const struct drm_mode_fb_cmd2 *mode_cmd); +amdgpu_display_user_framebuffer_create(struct drm_device *dev, + struct drm_file *file_priv, + const struct drm_mode_fb_cmd2 *mode_cmd); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h index a8437a3296a6..bd745a4fae0c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h @@ -265,9 +265,6 @@ enum amdgpu_pcie_gen { #define amdgpu_dpm_read_sensor(adev, idx, value, size) \ ((adev)->powerplay.pp_funcs->read_sensor((adev)->powerplay.pp_handle, (idx), (value), (size))) -#define amdgpu_dpm_get_temperature(adev) \ - ((adev)->powerplay.pp_funcs->get_temperature((adev)->powerplay.pp_handle)) - #define amdgpu_dpm_set_fan_control_mode(adev, m) \ ((adev)->powerplay.pp_funcs->set_fan_control_mode((adev)->powerplay.pp_handle, (m))) @@ -328,8 +325,8 @@ enum amdgpu_pcie_gen { #define amdgpu_dpm_set_mclk_od(adev, value) \ ((adev)->powerplay.pp_funcs->set_mclk_od((adev)->powerplay.pp_handle, value)) -#define amdgpu_dpm_dispatch_task(adev, task_id, input, output) \ - ((adev)->powerplay.pp_funcs->dispatch_tasks)((adev)->powerplay.pp_handle, (task_id), (input), (output)) +#define amdgpu_dpm_dispatch_task(adev, task_id, user_state) \ + ((adev)->powerplay.pp_funcs->dispatch_tasks)((adev)->powerplay.pp_handle, (task_id), (user_state)) #define amdgpu_dpm_check_state_equal(adev, cps, rps, equal) \ ((adev)->powerplay.pp_funcs->check_state_equal((adev)->powerplay.pp_handle, (cps), (rps), (equal))) @@ -366,6 +363,22 @@ enum amdgpu_pcie_gen { (adev)->powerplay.pp_handle, virtual_addr_low, \ virtual_addr_hi, mc_addr_low, mc_addr_hi, size) +#define amdgpu_dpm_get_power_profile_mode(adev, buf) \ + ((adev)->powerplay.pp_funcs->get_power_profile_mode(\ + (adev)->powerplay.pp_handle, buf)) + +#define amdgpu_dpm_set_power_profile_mode(adev, parameter, size) \ + ((adev)->powerplay.pp_funcs->set_power_profile_mode(\ + (adev)->powerplay.pp_handle, parameter, size)) + +#define amdgpu_dpm_odn_edit_dpm_table(adev, type, parameter, size) \ + ((adev)->powerplay.pp_funcs->odn_edit_dpm_table(\ + (adev)->powerplay.pp_handle, type, parameter, size)) + +#define amdgpu_dpm_set_mmhub_powergating_by_smu(adev) \ + ((adev)->powerplay.pp_funcs->set_mmhub_powergating_by_smu( \ + (adev)->powerplay.pp_handle)) + struct amdgpu_dpm { struct amdgpu_ps *ps; /* number of valid power states */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 50afcf65181a..88ec9280a67a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -73,9 +73,11 @@ * - 3.21.0 - Add DRM_AMDGPU_FENCE_TO_HANDLE ioctl * - 3.22.0 - Add DRM_AMDGPU_SCHED ioctl * - 3.23.0 - Add query for VRAM lost counter + * - 3.24.0 - Add high priority compute support for gfx9 + * - 3.25.0 - Add support for sensor query info (stable pstate sclk/mclk). */ #define KMS_DRIVER_MAJOR 3 -#define KMS_DRIVER_MINOR 23 +#define KMS_DRIVER_MINOR 25 #define KMS_DRIVER_PATCHLEVEL 0 int amdgpu_vram_limit = 0; @@ -119,7 +121,7 @@ uint amdgpu_pg_mask = 0xffffffff; uint amdgpu_sdma_phase_quantum = 32; char *amdgpu_disable_cu = NULL; char *amdgpu_virtual_display = NULL; -uint amdgpu_pp_feature_mask = 0xffffffff; +uint amdgpu_pp_feature_mask = 0x3fff; int amdgpu_ngg = 0; int amdgpu_prim_buf_per_se = 0; int amdgpu_pos_buf_per_se = 0; @@ -129,6 +131,7 @@ int amdgpu_job_hang_limit = 0; int amdgpu_lbpw = -1; int amdgpu_compute_multipipe = -1; int amdgpu_gpu_recovery = -1; /* auto */ +int amdgpu_emu_mode = 0; MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing, in megabytes"); module_param_named(vramlimit, amdgpu_vram_limit, int, 0600); @@ -284,6 +287,9 @@ module_param_named(compute_multipipe, amdgpu_compute_multipipe, int, 0444); MODULE_PARM_DESC(gpu_recovery, "Enable GPU recovery mechanism, (1 = enable, 0 = disable, -1 = auto"); module_param_named(gpu_recovery, amdgpu_gpu_recovery, int, 0444); +MODULE_PARM_DESC(emu_mode, "Emulation mode, (1 = enable, 0 = disable"); +module_param_named(emu_mode, amdgpu_emu_mode, int, 0444); + #ifdef CONFIG_DRM_AMDGPU_SI #if defined(CONFIG_DRM_RADEON) || defined(CONFIG_DRM_RADEON_MODULE) @@ -576,6 +582,11 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, struct drm_device *dev; unsigned long flags = ent->driver_data; int ret, retry = 0; + bool supports_atomic = false; + + if (!amdgpu_virtual_display && + amdgpu_device_asic_has_dc_support(flags & AMD_ASIC_MASK)) + supports_atomic = true; if ((flags & AMD_EXP_HW_SUPPORT) && !amdgpu_exp_hw_support) { DRM_INFO("This hardware requires experimental hardware support.\n" @@ -596,6 +607,13 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, if (ret) return ret; + /* warn the user if they mix atomic and non-atomic capable GPUs */ + if ((kms_driver.driver_features & DRIVER_ATOMIC) && !supports_atomic) + DRM_ERROR("Mixing atomic and non-atomic capable GPUs!\n"); + /* support atomic early so the atomic debugfs stuff gets created */ + if (supports_atomic) + kms_driver.driver_features |= DRIVER_ATOMIC; + dev = drm_dev_alloc(&kms_driver, &pdev->dev); if (IS_ERR(dev)) return PTR_ERR(dev); @@ -835,8 +853,8 @@ amdgpu_get_crtc_scanout_position(struct drm_device *dev, unsigned int pipe, ktime_t *stime, ktime_t *etime, const struct drm_display_mode *mode) { - return amdgpu_get_crtc_scanoutpos(dev, pipe, 0, vpos, hpos, - stime, etime, mode); + return amdgpu_display_get_crtc_scanoutpos(dev, pipe, 0, vpos, hpos, + stime, etime, mode); } static struct drm_driver kms_driver = { @@ -854,9 +872,6 @@ static struct drm_driver kms_driver = { .disable_vblank = amdgpu_disable_vblank_kms, .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos, .get_scanout_position = amdgpu_get_crtc_scanout_position, - .irq_preinstall = amdgpu_irq_preinstall, - .irq_postinstall = amdgpu_irq_postinstall, - .irq_uninstall = amdgpu_irq_uninstall, .irq_handler = amdgpu_irq_handler, .ioctls = amdgpu_ioctls_kms, .gem_free_object_unlocked = amdgpu_gem_object_free, @@ -869,9 +884,7 @@ static struct drm_driver kms_driver = { .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_export = amdgpu_gem_prime_export, - .gem_prime_import = drm_gem_prime_import, - .gem_prime_pin = amdgpu_gem_prime_pin, - .gem_prime_unpin = amdgpu_gem_prime_unpin, + .gem_prime_import = amdgpu_gem_prime_import, .gem_prime_res_obj = amdgpu_gem_prime_res_obj, .gem_prime_get_sg_table = amdgpu_gem_prime_get_sg_table, .gem_prime_import_sg_table = amdgpu_gem_prime_import_sg_table, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c index ff3e9beb7d19..12063019751b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c @@ -38,6 +38,8 @@ #include +#include "amdgpu_display.h" + /* object hierarchy - this contains a helper + a amdgpu fb the helper contains a pointer to amdgpu framebuffer baseclass. @@ -124,7 +126,7 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev, struct drm_gem_object *gobj = NULL; struct amdgpu_bo *abo = NULL; bool fb_tiled = false; /* useful for testing */ - u32 tiling_flags = 0; + u32 tiling_flags = 0, domain; int ret; int aligned_size, size; int height = mode_cmd->height; @@ -135,12 +137,12 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev, /* need to align pitch with crtc limits */ mode_cmd->pitches[0] = amdgpu_align_pitch(adev, mode_cmd->width, cpp, fb_tiled); + domain = amdgpu_display_framebuffer_domains(adev); height = ALIGN(mode_cmd->height, 8); size = mode_cmd->pitches[0] * height; aligned_size = ALIGN(size, PAGE_SIZE); - ret = amdgpu_gem_object_create(adev, aligned_size, 0, - AMDGPU_GEM_DOMAIN_VRAM, + ret = amdgpu_gem_object_create(adev, aligned_size, 0, domain, AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS | AMDGPU_GEM_CREATE_VRAM_CLEARED, @@ -166,7 +168,7 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev, } - ret = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM, NULL); + ret = amdgpu_bo_pin(abo, domain, NULL); if (ret) { amdgpu_bo_unreserve(abo); goto out_unref; @@ -225,7 +227,8 @@ static int amdgpufb_create(struct drm_fb_helper *helper, info->par = rfbdev; info->skip_vt_switch = true; - ret = amdgpu_framebuffer_init(adev->ddev, &rfbdev->rfb, &mode_cmd, gobj); + ret = amdgpu_display_framebuffer_init(adev->ddev, &rfbdev->rfb, + &mode_cmd, gobj); if (ret) { DRM_ERROR("failed to initialize framebuffer %d\n", ret); goto out; @@ -242,8 +245,8 @@ static int amdgpufb_create(struct drm_fb_helper *helper, info->fbops = &amdgpufb_ops; - tmp = amdgpu_bo_gpu_offset(abo) - adev->mc.vram_start; - info->fix.smem_start = adev->mc.aper_base + tmp; + tmp = amdgpu_bo_gpu_offset(abo) - adev->gmc.vram_start; + info->fix.smem_start = adev->gmc.aper_base + tmp; info->fix.smem_len = amdgpu_bo_size(abo); info->screen_base = amdgpu_bo_kptr(abo); info->screen_size = amdgpu_bo_size(abo); @@ -252,7 +255,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper, /* setup aperture base/size for vesafb takeover */ info->apertures->ranges[0].base = adev->ddev->mode_config.fb_base; - info->apertures->ranges[0].size = adev->mc.aper_size; + info->apertures->ranges[0].size = adev->gmc.aper_size; /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ @@ -262,7 +265,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper, } DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); - DRM_INFO("vram apper at 0x%lX\n", (unsigned long)adev->mc.aper_base); + DRM_INFO("vram apper at 0x%lX\n", (unsigned long)adev->gmc.aper_base); DRM_INFO("size %lu\n", (unsigned long)amdgpu_bo_size(abo)); DRM_INFO("fb depth is %d\n", fb->format->depth); DRM_INFO(" pitch is %d\n", fb->pitches[0]); @@ -319,7 +322,7 @@ int amdgpu_fbdev_init(struct amdgpu_device *adev) return 0; /* select 8 bpp console on low vram cards */ - if (adev->mc.real_vram_size <= (32*1024*1024)) + if (adev->gmc.real_vram_size <= (32*1024*1024)) bpp_sel = 8; rfbdev = kzalloc(sizeof(struct amdgpu_fbdev), GFP_KERNEL); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index 0a4f34afaaaa..008eaee57114 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -120,7 +120,7 @@ int amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev) PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS, - NULL, NULL, 0, &adev->gart.robj); + NULL, NULL, &adev->gart.robj); if (r) { return r; } @@ -241,13 +241,14 @@ int amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset, continue; for (j = 0; j < (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); j++, t++) { - amdgpu_gart_set_pte_pde(adev, adev->gart.ptr, - t, page_base, flags); + amdgpu_gmc_set_pte_pde(adev, adev->gart.ptr, + t, page_base, flags); page_base += AMDGPU_GPU_PAGE_SIZE; } } mb(); - amdgpu_gart_flush_gpu_tlb(adev, 0); + amdgpu_asic_flush_hdp(adev, NULL); + amdgpu_gmc_flush_gpu_tlb(adev, 0); return 0; } @@ -279,7 +280,7 @@ int amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset, for (i = 0; i < pages; i++) { page_base = dma_addr[i]; for (j = 0; j < (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); j++, t++) { - amdgpu_gart_set_pte_pde(adev, dst, t, page_base, flags); + amdgpu_gmc_set_pte_pde(adev, dst, t, page_base, flags); page_base += AMDGPU_GPU_PAGE_SIZE; } } @@ -329,7 +330,8 @@ int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset, return r; mb(); - amdgpu_gart_flush_gpu_tlb(adev, 0); + amdgpu_asic_flush_hdp(adev, NULL); + amdgpu_gmc_flush_gpu_tlb(adev, 0); return 0; } @@ -357,8 +359,8 @@ int amdgpu_gart_init(struct amdgpu_device *adev) if (r) return r; /* Compute table size */ - adev->gart.num_cpu_pages = adev->mc.gart_size / PAGE_SIZE; - adev->gart.num_gpu_pages = adev->mc.gart_size / AMDGPU_GPU_PAGE_SIZE; + adev->gart.num_cpu_pages = adev->gmc.gart_size / PAGE_SIZE; + adev->gart.num_gpu_pages = adev->gmc.gart_size / AMDGPU_GPU_PAGE_SIZE; DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n", adev->gart.num_cpu_pages, adev->gart.num_gpu_pages); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h index d4a43302c2be..456295c00291 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h @@ -31,7 +31,6 @@ */ struct amdgpu_device; struct amdgpu_bo; -struct amdgpu_gart_funcs; #define AMDGPU_GPU_PAGE_SIZE 4096 #define AMDGPU_GPU_PAGE_MASK (AMDGPU_GPU_PAGE_SIZE - 1) @@ -52,8 +51,6 @@ struct amdgpu_gart { /* Asic default pte flags */ uint64_t gart_pte_flags; - - const struct amdgpu_gart_funcs *gart_funcs; }; int amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index e48b4ec88c8c..55a840ae6d68 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -60,7 +60,7 @@ int amdgpu_gem_object_create(struct amdgpu_device *adev, unsigned long size, retry: r = amdgpu_bo_create(adev, size, alignment, kernel, initial_domain, - flags, NULL, resv, 0, &bo); + flags, NULL, resv, &bo); if (r) { if (r != -ERESTARTSYS) { if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) { @@ -523,12 +523,13 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev, goto error; if (operation == AMDGPU_VA_OP_MAP || - operation == AMDGPU_VA_OP_REPLACE) + operation == AMDGPU_VA_OP_REPLACE) { r = amdgpu_vm_bo_update(adev, bo_va, false); + if (r) + goto error; + } r = amdgpu_vm_update_directories(adev, vm); - if (r) - goto error; error: if (r && r != -ERESTARTSYS) @@ -634,7 +635,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, if (r) goto error_backoff; - va_flags = amdgpu_vm_get_pte_flags(adev, args->flags); + va_flags = amdgpu_gmc_get_pte_flags(adev, args->flags); r = amdgpu_vm_bo_map(adev, bo_va, args->va_address, args->offset_in_bo, args->map_size, va_flags); @@ -654,7 +655,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, if (r) goto error_backoff; - va_flags = amdgpu_vm_get_pte_flags(adev, args->flags); + va_flags = amdgpu_gmc_get_pte_flags(adev, args->flags); r = amdgpu_vm_bo_replace_map(adev, bo_va, args->va_address, args->offset_in_bo, args->map_size, va_flags); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index bb40d2529a30..239bf2a4b3c6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -179,8 +179,12 @@ static int amdgpu_gfx_kiq_acquire(struct amdgpu_device *adev, amdgpu_gfx_bit_to_queue(adev, queue_bit, &mec, &pipe, &queue); - /* Using pipes 2/3 from MEC 2 seems cause problems */ - if (mec == 1 && pipe > 1) + /* + * 1. Using pipes 2/3 from MEC 2 seems cause problems. + * 2. It must use queue id 0, because CGPG_IDLE/SAVE/LOAD/RUN + * only can be issued on queue 0. + */ + if ((mec == 1 && pipe > 1) || queue != 0) continue; ring->me = mec + 1; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h new file mode 100644 index 000000000000..893c2490b783 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h @@ -0,0 +1,112 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + */ +#ifndef __AMDGPU_GMC_H__ +#define __AMDGPU_GMC_H__ + +#include + +#include "amdgpu_irq.h" + +struct firmware; + +/* + * VMHUB structures, functions & helpers + */ +struct amdgpu_vmhub { + uint32_t ctx0_ptb_addr_lo32; + uint32_t ctx0_ptb_addr_hi32; + uint32_t vm_inv_eng0_req; + uint32_t vm_inv_eng0_ack; + uint32_t vm_context0_cntl; + uint32_t vm_l2_pro_fault_status; + uint32_t vm_l2_pro_fault_cntl; +}; + +/* + * GPU MC structures, functions & helpers + */ +struct amdgpu_gmc_funcs { + /* flush the vm tlb via mmio */ + void (*flush_gpu_tlb)(struct amdgpu_device *adev, + uint32_t vmid); + /* flush the vm tlb via ring */ + uint64_t (*emit_flush_gpu_tlb)(struct amdgpu_ring *ring, unsigned vmid, + uint64_t pd_addr); + /* Change the VMID -> PASID mapping */ + void (*emit_pasid_mapping)(struct amdgpu_ring *ring, unsigned vmid, + unsigned pasid); + /* write pte/pde updates using the cpu */ + int (*set_pte_pde)(struct amdgpu_device *adev, + void *cpu_pt_addr, /* cpu addr of page table */ + uint32_t gpu_page_idx, /* pte/pde to update */ + uint64_t addr, /* addr to write into pte/pde */ + uint64_t flags); /* access flags */ + /* enable/disable PRT support */ + void (*set_prt)(struct amdgpu_device *adev, bool enable); + /* set pte flags based per asic */ + uint64_t (*get_vm_pte_flags)(struct amdgpu_device *adev, + uint32_t flags); + /* get the pde for a given mc addr */ + void (*get_vm_pde)(struct amdgpu_device *adev, int level, + u64 *dst, u64 *flags); +}; + +struct amdgpu_gmc { + resource_size_t aper_size; + resource_size_t aper_base; + /* for some chips with <= 32MB we need to lie + * about vram size near mc fb location */ + u64 mc_vram_size; + u64 visible_vram_size; + u64 gart_size; + u64 gart_start; + u64 gart_end; + u64 vram_start; + u64 vram_end; + unsigned vram_width; + u64 real_vram_size; + int vram_mtrr; + u64 mc_mask; + const struct firmware *fw; /* MC firmware */ + uint32_t fw_version; + struct amdgpu_irq_src vm_fault; + uint32_t vram_type; + uint32_t srbm_soft_reset; + bool prt_warning; + uint64_t stolen_size; + /* apertures */ + u64 shared_aperture_start; + u64 shared_aperture_end; + u64 private_aperture_start; + u64 private_aperture_end; + /* protects concurrent invalidation */ + spinlock_t invalidate_lock; + bool translate_further; + + const struct amdgpu_gmc_funcs *gmc_funcs; +}; + +#endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c index e14ab34d8262..da7b1b92d9cf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c @@ -56,7 +56,7 @@ static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man, return -ENOMEM; start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS; - size = (adev->mc.gart_size >> PAGE_SHIFT) - start; + size = (adev->gmc.gart_size >> PAGE_SHIFT) - start; drm_mm_init(&mgr->mm, start, size); spin_lock_init(&mgr->lock); atomic64_set(&mgr->available, p_size); @@ -75,7 +75,7 @@ static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man, static int amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager *man) { struct amdgpu_gtt_mgr *mgr = man->priv; - + spin_lock(&mgr->lock); drm_mm_takedown(&mgr->mm); spin_unlock(&mgr->lock); kfree(mgr); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index a162d87ca0c8..8ea342dc6376 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -184,12 +184,15 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs, if (ring->funcs->init_cond_exec) patch_offset = amdgpu_ring_init_cond_exec(ring); - if (ring->funcs->emit_hdp_flush #ifdef CONFIG_X86_64 - && !(adev->flags & AMD_IS_APU) + if (!(adev->flags & AMD_IS_APU)) #endif - ) - amdgpu_ring_emit_hdp_flush(ring); + { + if (ring->funcs->emit_hdp_flush) + amdgpu_ring_emit_hdp_flush(ring); + else + amdgpu_asic_flush_hdp(adev, ring); + } skip_preamble = ring->current_ctx == fence_ctx; need_ctx_switch = ring->current_ctx != fence_ctx; @@ -219,12 +222,10 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs, if (ring->funcs->emit_tmz) amdgpu_ring_emit_tmz(ring, false); - if (ring->funcs->emit_hdp_invalidate #ifdef CONFIG_X86_64 - && !(adev->flags & AMD_IS_APU) + if (!(adev->flags & AMD_IS_APU)) #endif - ) - amdgpu_ring_emit_hdp_invalidate(ring); + amdgpu_asic_invalidate_hdp(adev, ring); r = amdgpu_fence_emit(ring, f); if (r) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index 16884a0b677b..a1c78f90eadf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -40,6 +40,12 @@ */ static DEFINE_IDA(amdgpu_pasid_ida); +/* Helper to free pasid from a fence callback */ +struct amdgpu_pasid_cb { + struct dma_fence_cb cb; + unsigned int pasid; +}; + /** * amdgpu_pasid_alloc - Allocate a PASID * @bits: Maximum width of the PASID in bits, must be at least 1 @@ -63,6 +69,9 @@ int amdgpu_pasid_alloc(unsigned int bits) break; } + if (pasid >= 0) + trace_amdgpu_pasid_allocated(pasid); + return pasid; } @@ -72,9 +81,86 @@ int amdgpu_pasid_alloc(unsigned int bits) */ void amdgpu_pasid_free(unsigned int pasid) { + trace_amdgpu_pasid_freed(pasid); ida_simple_remove(&amdgpu_pasid_ida, pasid); } +static void amdgpu_pasid_free_cb(struct dma_fence *fence, + struct dma_fence_cb *_cb) +{ + struct amdgpu_pasid_cb *cb = + container_of(_cb, struct amdgpu_pasid_cb, cb); + + amdgpu_pasid_free(cb->pasid); + dma_fence_put(fence); + kfree(cb); +} + +/** + * amdgpu_pasid_free_delayed - free pasid when fences signal + * + * @resv: reservation object with the fences to wait for + * @pasid: pasid to free + * + * Free the pasid only after all the fences in resv are signaled. + */ +void amdgpu_pasid_free_delayed(struct reservation_object *resv, + unsigned int pasid) +{ + struct dma_fence *fence, **fences; + struct amdgpu_pasid_cb *cb; + unsigned count; + int r; + + r = reservation_object_get_fences_rcu(resv, NULL, &count, &fences); + if (r) + goto fallback; + + if (count == 0) { + amdgpu_pasid_free(pasid); + return; + } + + if (count == 1) { + fence = fences[0]; + kfree(fences); + } else { + uint64_t context = dma_fence_context_alloc(1); + struct dma_fence_array *array; + + array = dma_fence_array_create(count, fences, context, + 1, false); + if (!array) { + kfree(fences); + goto fallback; + } + fence = &array->base; + } + + cb = kmalloc(sizeof(*cb), GFP_KERNEL); + if (!cb) { + /* Last resort when we are OOM */ + dma_fence_wait(fence, false); + dma_fence_put(fence); + amdgpu_pasid_free(pasid); + } else { + cb->pasid = pasid; + if (dma_fence_add_callback(fence, &cb->cb, + amdgpu_pasid_free_cb)) + amdgpu_pasid_free_cb(fence, &cb->cb); + } + + return; + +fallback: + /* Not enough memory for the delayed delete, as last resort + * block for all the fences to complete. + */ + reservation_object_wait_timeout_rcu(resv, true, false, + MAX_SCHEDULE_TIMEOUT); + amdgpu_pasid_free(pasid); +} + /* * VMID manager * @@ -96,64 +182,210 @@ bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev, atomic_read(&adev->gpu_reset_counter); } -/* idr_mgr->lock must be held */ -static int amdgpu_vmid_grab_reserved_locked(struct amdgpu_vm *vm, - struct amdgpu_ring *ring, - struct amdgpu_sync *sync, - struct dma_fence *fence, - struct amdgpu_job *job) +/** + * amdgpu_vm_grab_idle - grab idle VMID + * + * @vm: vm to allocate id for + * @ring: ring we want to submit job to + * @sync: sync object where we add dependencies + * @idle: resulting idle VMID + * + * Try to find an idle VMID, if none is idle add a fence to wait to the sync + * object. Returns -ENOMEM when we are out of memory. + */ +static int amdgpu_vmid_grab_idle(struct amdgpu_vm *vm, + struct amdgpu_ring *ring, + struct amdgpu_sync *sync, + struct amdgpu_vmid **idle) +{ + struct amdgpu_device *adev = ring->adev; + unsigned vmhub = ring->funcs->vmhub; + struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub]; + struct dma_fence **fences; + unsigned i; + int r; + + if (ring->vmid_wait && !dma_fence_is_signaled(ring->vmid_wait)) + return amdgpu_sync_fence(adev, sync, ring->vmid_wait, false); + + fences = kmalloc_array(sizeof(void *), id_mgr->num_ids, GFP_KERNEL); + if (!fences) + return -ENOMEM; + + /* Check if we have an idle VMID */ + i = 0; + list_for_each_entry((*idle), &id_mgr->ids_lru, list) { + fences[i] = amdgpu_sync_peek_fence(&(*idle)->active, ring); + if (!fences[i]) + break; + ++i; + } + + /* If we can't find a idle VMID to use, wait till one becomes available */ + if (&(*idle)->list == &id_mgr->ids_lru) { + u64 fence_context = adev->vm_manager.fence_context + ring->idx; + unsigned seqno = ++adev->vm_manager.seqno[ring->idx]; + struct dma_fence_array *array; + unsigned j; + + *idle = NULL; + for (j = 0; j < i; ++j) + dma_fence_get(fences[j]); + + array = dma_fence_array_create(i, fences, fence_context, + seqno, true); + if (!array) { + for (j = 0; j < i; ++j) + dma_fence_put(fences[j]); + kfree(fences); + return -ENOMEM; + } + + r = amdgpu_sync_fence(adev, sync, &array->base, false); + dma_fence_put(ring->vmid_wait); + ring->vmid_wait = &array->base; + return r; + } + kfree(fences); + + return 0; +} + +/** + * amdgpu_vm_grab_reserved - try to assign reserved VMID + * + * @vm: vm to allocate id for + * @ring: ring we want to submit job to + * @sync: sync object where we add dependencies + * @fence: fence protecting ID from reuse + * @job: job who wants to use the VMID + * + * Try to assign a reserved VMID. + */ +static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm, + struct amdgpu_ring *ring, + struct amdgpu_sync *sync, + struct dma_fence *fence, + struct amdgpu_job *job, + struct amdgpu_vmid **id) { struct amdgpu_device *adev = ring->adev; unsigned vmhub = ring->funcs->vmhub; uint64_t fence_context = adev->fence_context + ring->idx; - struct amdgpu_vmid *id = vm->reserved_vmid[vmhub]; - struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub]; struct dma_fence *updates = sync->last_vm_update; - int r = 0; - struct dma_fence *flushed, *tmp; bool needs_flush = vm->use_cpu_for_update; + int r = 0; + + *id = vm->reserved_vmid[vmhub]; + if (updates && (*id)->flushed_updates && + updates->context == (*id)->flushed_updates->context && + !dma_fence_is_later(updates, (*id)->flushed_updates)) + updates = NULL; + + if ((*id)->owner != vm->entity.fence_context || + job->vm_pd_addr != (*id)->pd_gpu_addr || + updates || !(*id)->last_flush || + ((*id)->last_flush->context != fence_context && + !dma_fence_is_signaled((*id)->last_flush))) { + struct dma_fence *tmp; - flushed = id->flushed_updates; - if ((amdgpu_vmid_had_gpu_reset(adev, id)) || - (atomic64_read(&id->owner) != vm->entity.fence_context) || - (job->vm_pd_addr != id->pd_gpu_addr) || - (updates && (!flushed || updates->context != flushed->context || - dma_fence_is_later(updates, flushed))) || - (!id->last_flush || (id->last_flush->context != fence_context && - !dma_fence_is_signaled(id->last_flush)))) { - needs_flush = true; /* to prevent one context starved by another context */ - id->pd_gpu_addr = 0; - tmp = amdgpu_sync_peek_fence(&id->active, ring); + (*id)->pd_gpu_addr = 0; + tmp = amdgpu_sync_peek_fence(&(*id)->active, ring); if (tmp) { + *id = NULL; r = amdgpu_sync_fence(adev, sync, tmp, false); return r; } + needs_flush = true; } /* Good we can use this VMID. Remember this submission as * user of the VMID. */ - r = amdgpu_sync_fence(ring->adev, &id->active, fence, false); + r = amdgpu_sync_fence(ring->adev, &(*id)->active, fence, false); if (r) - goto out; + return r; - if (updates && (!flushed || updates->context != flushed->context || - dma_fence_is_later(updates, flushed))) { - dma_fence_put(id->flushed_updates); - id->flushed_updates = dma_fence_get(updates); + if (updates) { + dma_fence_put((*id)->flushed_updates); + (*id)->flushed_updates = dma_fence_get(updates); } - id->pd_gpu_addr = job->vm_pd_addr; - atomic64_set(&id->owner, vm->entity.fence_context); job->vm_needs_flush = needs_flush; - if (needs_flush) { - dma_fence_put(id->last_flush); - id->last_flush = NULL; + return 0; +} + +/** + * amdgpu_vm_grab_used - try to reuse a VMID + * + * @vm: vm to allocate id for + * @ring: ring we want to submit job to + * @sync: sync object where we add dependencies + * @fence: fence protecting ID from reuse + * @job: job who wants to use the VMID + * @id: resulting VMID + * + * Try to reuse a VMID for this submission. + */ +static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm, + struct amdgpu_ring *ring, + struct amdgpu_sync *sync, + struct dma_fence *fence, + struct amdgpu_job *job, + struct amdgpu_vmid **id) +{ + struct amdgpu_device *adev = ring->adev; + unsigned vmhub = ring->funcs->vmhub; + struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub]; + uint64_t fence_context = adev->fence_context + ring->idx; + struct dma_fence *updates = sync->last_vm_update; + int r; + + job->vm_needs_flush = vm->use_cpu_for_update; + + /* Check if we can use a VMID already assigned to this VM */ + list_for_each_entry_reverse((*id), &id_mgr->ids_lru, list) { + bool needs_flush = vm->use_cpu_for_update; + struct dma_fence *flushed; + + /* Check all the prerequisites to using this VMID */ + if ((*id)->owner != vm->entity.fence_context) + continue; + + if ((*id)->pd_gpu_addr != job->vm_pd_addr) + continue; + + if (!(*id)->last_flush || + ((*id)->last_flush->context != fence_context && + !dma_fence_is_signaled((*id)->last_flush))) + needs_flush = true; + + flushed = (*id)->flushed_updates; + if (updates && (!flushed || dma_fence_is_later(updates, flushed))) + needs_flush = true; + + /* Concurrent flushes are only possible starting with Vega10 */ + if (adev->asic_type < CHIP_VEGA10 && needs_flush) + continue; + + /* Good, we can use this VMID. Remember this submission as + * user of the VMID. + */ + r = amdgpu_sync_fence(ring->adev, &(*id)->active, fence, false); + if (r) + return r; + + if (updates && (!flushed || dma_fence_is_later(updates, flushed))) { + dma_fence_put((*id)->flushed_updates); + (*id)->flushed_updates = dma_fence_get(updates); + } + + job->vm_needs_flush |= needs_flush; + return 0; } - job->vmid = id - id_mgr->ids; - trace_amdgpu_vm_grab_id(vm, ring, job); -out: - return r; + + *id = NULL; + return 0; } /** @@ -163,6 +395,7 @@ out: * @ring: ring we want to submit job to * @sync: sync object where we add dependencies * @fence: fence protecting ID from reuse + * @job: job who wants to use the VMID * * Allocate an id for the vm, adding fences to the sync obj as necessary. */ @@ -173,135 +406,53 @@ int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring, struct amdgpu_device *adev = ring->adev; unsigned vmhub = ring->funcs->vmhub; struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub]; - uint64_t fence_context = adev->fence_context + ring->idx; - struct dma_fence *updates = sync->last_vm_update; - struct amdgpu_vmid *id, *idle; - struct dma_fence **fences; - unsigned i; + struct amdgpu_vmid *idle = NULL; + struct amdgpu_vmid *id = NULL; int r = 0; mutex_lock(&id_mgr->lock); - if (vm->reserved_vmid[vmhub]) { - r = amdgpu_vmid_grab_reserved_locked(vm, ring, sync, fence, job); - mutex_unlock(&id_mgr->lock); - return r; - } - fences = kmalloc_array(sizeof(void *), id_mgr->num_ids, GFP_KERNEL); - if (!fences) { - mutex_unlock(&id_mgr->lock); - return -ENOMEM; - } - /* Check if we have an idle VMID */ - i = 0; - list_for_each_entry(idle, &id_mgr->ids_lru, list) { - fences[i] = amdgpu_sync_peek_fence(&idle->active, ring); - if (!fences[i]) - break; - ++i; - } - - /* If we can't find a idle VMID to use, wait till one becomes available */ - if (&idle->list == &id_mgr->ids_lru) { - u64 fence_context = adev->vm_manager.fence_context + ring->idx; - unsigned seqno = ++adev->vm_manager.seqno[ring->idx]; - struct dma_fence_array *array; - unsigned j; - - for (j = 0; j < i; ++j) - dma_fence_get(fences[j]); - - array = dma_fence_array_create(i, fences, fence_context, - seqno, true); - if (!array) { - for (j = 0; j < i; ++j) - dma_fence_put(fences[j]); - kfree(fences); - r = -ENOMEM; - goto error; - } - - - r = amdgpu_sync_fence(ring->adev, sync, &array->base, false); - dma_fence_put(&array->base); - if (r) - goto error; - - mutex_unlock(&id_mgr->lock); - return 0; - - } - kfree(fences); - - job->vm_needs_flush = vm->use_cpu_for_update; - /* Check if we can use a VMID already assigned to this VM */ - list_for_each_entry_reverse(id, &id_mgr->ids_lru, list) { - struct dma_fence *flushed; - bool needs_flush = vm->use_cpu_for_update; - - /* Check all the prerequisites to using this VMID */ - if (amdgpu_vmid_had_gpu_reset(adev, id)) - continue; - - if (atomic64_read(&id->owner) != vm->entity.fence_context) - continue; - - if (job->vm_pd_addr != id->pd_gpu_addr) - continue; - - if (!id->last_flush || - (id->last_flush->context != fence_context && - !dma_fence_is_signaled(id->last_flush))) - needs_flush = true; - - flushed = id->flushed_updates; - if (updates && (!flushed || dma_fence_is_later(updates, flushed))) - needs_flush = true; - - /* Concurrent flushes are only possible starting with Vega10 */ - if (adev->asic_type < CHIP_VEGA10 && needs_flush) - continue; - - /* Good we can use this VMID. Remember this submission as - * user of the VMID. - */ - r = amdgpu_sync_fence(ring->adev, &id->active, fence, false); - if (r) - goto error; - - if (updates && (!flushed || dma_fence_is_later(updates, flushed))) { - dma_fence_put(id->flushed_updates); - id->flushed_updates = dma_fence_get(updates); - } - - if (needs_flush) - goto needs_flush; - else - goto no_flush_needed; - - }; - - /* Still no ID to use? Then use the idle one found earlier */ - id = idle; - - /* Remember this submission as user of the VMID */ - r = amdgpu_sync_fence(ring->adev, &id->active, fence, false); - if (r) + r = amdgpu_vmid_grab_idle(vm, ring, sync, &idle); + if (r || !idle) goto error; + if (vm->reserved_vmid[vmhub]) { + r = amdgpu_vmid_grab_reserved(vm, ring, sync, fence, job, &id); + if (r || !id) + goto error; + } else { + r = amdgpu_vmid_grab_used(vm, ring, sync, fence, job, &id); + if (r) + goto error; + + if (!id) { + struct dma_fence *updates = sync->last_vm_update; + + /* Still no ID to use? Then use the idle one found earlier */ + id = idle; + + /* Remember this submission as user of the VMID */ + r = amdgpu_sync_fence(ring->adev, &id->active, + fence, false); + if (r) + goto error; + + dma_fence_put(id->flushed_updates); + id->flushed_updates = dma_fence_get(updates); + job->vm_needs_flush = true; + } + + list_move_tail(&id->list, &id_mgr->ids_lru); + } + id->pd_gpu_addr = job->vm_pd_addr; - dma_fence_put(id->flushed_updates); - id->flushed_updates = dma_fence_get(updates); - atomic64_set(&id->owner, vm->entity.fence_context); - -needs_flush: - job->vm_needs_flush = true; - dma_fence_put(id->last_flush); - id->last_flush = NULL; - -no_flush_needed: - list_move_tail(&id->list, &id_mgr->ids_lru); + id->owner = vm->entity.fence_context; + if (job->vm_needs_flush) { + dma_fence_put(id->last_flush); + id->last_flush = NULL; + } job->vmid = id - id_mgr->ids; + job->pasid = vm->pasid; trace_amdgpu_vm_grab_id(vm, ring, job); error: @@ -370,13 +521,15 @@ void amdgpu_vmid_reset(struct amdgpu_device *adev, unsigned vmhub, struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub]; struct amdgpu_vmid *id = &id_mgr->ids[vmid]; - atomic64_set(&id->owner, 0); + mutex_lock(&id_mgr->lock); + id->owner = 0; id->gds_base = 0; id->gds_size = 0; id->gws_base = 0; id->gws_size = 0; id->oa_base = 0; id->oa_size = 0; + mutex_unlock(&id_mgr->lock); } /** @@ -454,6 +607,7 @@ void amdgpu_vmid_mgr_fini(struct amdgpu_device *adev) amdgpu_sync_free(&id->active); dma_fence_put(id->flushed_updates); dma_fence_put(id->last_flush); + dma_fence_put(id->pasid_mapping); } } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h index ad931fa570b3..7625419f0fc2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h @@ -43,7 +43,7 @@ struct amdgpu_vmid { struct list_head list; struct amdgpu_sync active; struct dma_fence *last_flush; - atomic64_t owner; + uint64_t owner; uint64_t pd_gpu_addr; /* last flushed PD/PT update */ @@ -57,6 +57,9 @@ struct amdgpu_vmid { uint32_t gws_size; uint32_t oa_base; uint32_t oa_size; + + unsigned pasid; + struct dma_fence *pasid_mapping; }; struct amdgpu_vmid_mgr { @@ -69,6 +72,8 @@ struct amdgpu_vmid_mgr { int amdgpu_pasid_alloc(unsigned int bits); void amdgpu_pasid_free(unsigned int pasid); +void amdgpu_pasid_free_delayed(struct reservation_object *resv, + unsigned int pasid); bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev, struct amdgpu_vmid *id); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h index 29cf10927a92..b8a7dba69595 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h @@ -109,7 +109,7 @@ struct amdgpu_iv_entry { unsigned vmid_src; uint64_t timestamp; unsigned timestamp_src; - unsigned pas_id; + unsigned pasid; unsigned pasid_src; unsigned src_data[AMDGPU_IH_SRC_DATA_MAX_SIZE_DW]; const uint32_t *iv_entry; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c index 56bcd59c3399..f6f2a662bb8f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c @@ -92,7 +92,7 @@ static void amdgpu_irq_reset_work_func(struct work_struct *work) } /* Disable *all* interrupts */ -static void amdgpu_irq_disable_all(struct amdgpu_device *adev) +void amdgpu_irq_disable_all(struct amdgpu_device *adev) { unsigned long irqflags; unsigned i, j, k; @@ -122,55 +122,6 @@ static void amdgpu_irq_disable_all(struct amdgpu_device *adev) spin_unlock_irqrestore(&adev->irq.lock, irqflags); } -/** - * amdgpu_irq_preinstall - drm irq preinstall callback - * - * @dev: drm dev pointer - * - * Gets the hw ready to enable irqs (all asics). - * This function disables all interrupt sources on the GPU. - */ -void amdgpu_irq_preinstall(struct drm_device *dev) -{ - struct amdgpu_device *adev = dev->dev_private; - - /* Disable *all* interrupts */ - amdgpu_irq_disable_all(adev); - /* Clear bits */ - amdgpu_ih_process(adev); -} - -/** - * amdgpu_irq_postinstall - drm irq preinstall callback - * - * @dev: drm dev pointer - * - * Handles stuff to be done after enabling irqs (all asics). - * Returns 0 on success. - */ -int amdgpu_irq_postinstall(struct drm_device *dev) -{ - dev->max_vblank_count = 0x00ffffff; - return 0; -} - -/** - * amdgpu_irq_uninstall - drm irq uninstall callback - * - * @dev: drm dev pointer - * - * This function disables all interrupt sources on the GPU (all asics). - */ -void amdgpu_irq_uninstall(struct drm_device *dev) -{ - struct amdgpu_device *adev = dev->dev_private; - - if (adev == NULL) { - return; - } - amdgpu_irq_disable_all(adev); -} - /** * amdgpu_irq_handler - irq handler * @@ -261,6 +212,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev) cancel_work_sync(&adev->reset_work); return r; } + adev->ddev->max_vblank_count = 0x00ffffff; DRM_DEBUG("amdgpu: irq initialized.\n"); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h index 0610cc4a9788..3375ad778edc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h @@ -78,9 +78,7 @@ struct amdgpu_irq { uint32_t srbm_soft_reset; }; -void amdgpu_irq_preinstall(struct drm_device *dev); -int amdgpu_irq_postinstall(struct drm_device *dev); -void amdgpu_irq_uninstall(struct drm_device *dev); +void amdgpu_irq_disable_all(struct amdgpu_device *adev); irqreturn_t amdgpu_irq_handler(int irq, void *arg); int amdgpu_irq_init(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index bd6e9a40f421..e851c66cbb5e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -191,7 +191,7 @@ static int amdgpu_firmware_info(struct drm_amdgpu_info_firmware *fw_info, fw_info->feature = 0; break; case AMDGPU_INFO_FW_GMC: - fw_info->ver = adev->mc.fw_version; + fw_info->ver = adev->gmc.fw_version; fw_info->feature = 0; break; case AMDGPU_INFO_FW_GFX_ME: @@ -470,9 +470,9 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file case AMDGPU_INFO_VRAM_GTT: { struct drm_amdgpu_info_vram_gtt vram_gtt; - vram_gtt.vram_size = adev->mc.real_vram_size; + vram_gtt.vram_size = adev->gmc.real_vram_size; vram_gtt.vram_size -= adev->vram_pin_size; - vram_gtt.vram_cpu_accessible_size = adev->mc.visible_vram_size; + vram_gtt.vram_cpu_accessible_size = adev->gmc.visible_vram_size; vram_gtt.vram_cpu_accessible_size -= (adev->vram_pin_size - adev->invisible_pin_size); vram_gtt.gtt_size = adev->mman.bdev.man[TTM_PL_TT].size; vram_gtt.gtt_size *= PAGE_SIZE; @@ -484,17 +484,17 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file struct drm_amdgpu_memory_info mem; memset(&mem, 0, sizeof(mem)); - mem.vram.total_heap_size = adev->mc.real_vram_size; + mem.vram.total_heap_size = adev->gmc.real_vram_size; mem.vram.usable_heap_size = - adev->mc.real_vram_size - adev->vram_pin_size; + adev->gmc.real_vram_size - adev->vram_pin_size; mem.vram.heap_usage = amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); mem.vram.max_allocation = mem.vram.usable_heap_size * 3 / 4; mem.cpu_accessible_vram.total_heap_size = - adev->mc.visible_vram_size; + adev->gmc.visible_vram_size; mem.cpu_accessible_vram.usable_heap_size = - adev->mc.visible_vram_size - + adev->gmc.visible_vram_size - (adev->vram_pin_size - adev->invisible_pin_size); mem.cpu_accessible_vram.heap_usage = amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); @@ -580,11 +580,16 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file dev_info.ids_flags |= AMDGPU_IDS_FLAGS_PREEMPTION; vm_size = adev->vm_manager.max_pfn * AMDGPU_GPU_PAGE_SIZE; + vm_size -= AMDGPU_VA_RESERVED_SIZE; + + /* Older VCE FW versions are buggy and can handle only 40bits */ + if (adev->vce.fw_version < AMDGPU_VCE_FW_53_45) + vm_size = min(vm_size, 1ULL << 40); + dev_info.virtual_address_offset = AMDGPU_VA_RESERVED_SIZE; dev_info.virtual_address_max = min(vm_size, AMDGPU_VA_HOLE_START); - vm_size -= AMDGPU_VA_RESERVED_SIZE; if (vm_size > AMDGPU_VA_HOLE_START) { dev_info.high_va_offset = AMDGPU_VA_HOLE_END; dev_info.high_va_max = AMDGPU_VA_HOLE_END | vm_size; @@ -599,8 +604,8 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file sizeof(adev->gfx.cu_info.ao_cu_bitmap)); memcpy(&dev_info.cu_bitmap[0], &adev->gfx.cu_info.bitmap[0], sizeof(adev->gfx.cu_info.bitmap)); - dev_info.vram_type = adev->mc.vram_type; - dev_info.vram_bit_width = adev->mc.vram_width; + dev_info.vram_type = adev->gmc.vram_type; + dev_info.vram_bit_width = adev->gmc.vram_width; dev_info.vce_harvest_config = adev->vce.harvest_config; dev_info.gc_double_offchip_lds_buf = adev->gfx.config.double_offchip_lds_buf; @@ -758,6 +763,24 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file return -EINVAL; } break; + case AMDGPU_INFO_SENSOR_STABLE_PSTATE_GFX_SCLK: + /* get stable pstate sclk in Mhz */ + if (amdgpu_dpm_read_sensor(adev, + AMDGPU_PP_SENSOR_STABLE_PSTATE_SCLK, + (void *)&ui32, &ui32_size)) { + return -EINVAL; + } + ui32 /= 100; + break; + case AMDGPU_INFO_SENSOR_STABLE_PSTATE_GFX_MCLK: + /* get stable pstate mclk in Mhz */ + if (amdgpu_dpm_read_sensor(adev, + AMDGPU_PP_SENSOR_STABLE_PSTATE_MCLK, + (void *)&ui32, &ui32_size)) { + return -EINVAL; + } + ui32 /= 100; + break; default: DRM_DEBUG_KMS("Invalid request %d\n", info->sensor_info.type); @@ -805,7 +828,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) { struct amdgpu_device *adev = dev->dev_private; struct amdgpu_fpriv *fpriv; - int r; + int r, pasid; file_priv->driver_priv = NULL; @@ -819,28 +842,25 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) goto out_suspend; } - r = amdgpu_vm_init(adev, &fpriv->vm, - AMDGPU_VM_CONTEXT_GFX, 0); - if (r) { - kfree(fpriv); - goto out_suspend; + pasid = amdgpu_pasid_alloc(16); + if (pasid < 0) { + dev_warn(adev->dev, "No more PASIDs available!"); + pasid = 0; } + r = amdgpu_vm_init(adev, &fpriv->vm, AMDGPU_VM_CONTEXT_GFX, pasid); + if (r) + goto error_pasid; fpriv->prt_va = amdgpu_vm_bo_add(adev, &fpriv->vm, NULL); if (!fpriv->prt_va) { r = -ENOMEM; - amdgpu_vm_fini(adev, &fpriv->vm); - kfree(fpriv); - goto out_suspend; + goto error_vm; } if (amdgpu_sriov_vf(adev)) { r = amdgpu_map_static_csa(adev, &fpriv->vm, &fpriv->csa_va); - if (r) { - amdgpu_vm_fini(adev, &fpriv->vm); - kfree(fpriv); - goto out_suspend; - } + if (r) + goto error_vm; } mutex_init(&fpriv->bo_list_lock); @@ -849,6 +869,16 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) amdgpu_ctx_mgr_init(&fpriv->ctx_mgr); file_priv->driver_priv = fpriv; + goto out_suspend; + +error_vm: + amdgpu_vm_fini(adev, &fpriv->vm); + +error_pasid: + if (pasid) + amdgpu_pasid_free(pasid); + + kfree(fpriv); out_suspend: pm_runtime_mark_last_busy(dev->dev); @@ -871,6 +901,8 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, struct amdgpu_device *adev = dev->dev_private; struct amdgpu_fpriv *fpriv = file_priv->driver_priv; struct amdgpu_bo_list *list; + struct amdgpu_bo *pd; + unsigned int pasid; int handle; if (!fpriv) @@ -895,7 +927,13 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, amdgpu_bo_unreserve(adev->virt.csa_obj); } + pasid = fpriv->vm.pasid; + pd = amdgpu_bo_ref(fpriv->vm.root.base.bo); + amdgpu_vm_fini(adev, &fpriv->vm); + if (pasid) + amdgpu_pasid_free_delayed(pd->tbo.resv, pasid); + amdgpu_bo_unref(&pd); idr_for_each_entry(&fpriv->bo_list_handles, list, handle) amdgpu_bo_list_free(list); @@ -947,11 +985,11 @@ u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe) */ do { count = amdgpu_display_vblank_get_counter(adev, pipe); - /* Ask amdgpu_get_crtc_scanoutpos to return vpos as - * distance to start of vblank, instead of regular - * vertical scanout pos. + /* Ask amdgpu_display_get_crtc_scanoutpos to return + * vpos as distance to start of vblank, instead of + * regular vertical scanout pos. */ - stat = amdgpu_get_crtc_scanoutpos( + stat = amdgpu_display_get_crtc_scanoutpos( dev, pipe, GET_DISTANCE_TO_VBLANKSTART, &vpos, &hpos, NULL, NULL, &adev->mode_info.crtcs[pipe]->base.hwmode); @@ -992,7 +1030,7 @@ u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe) int amdgpu_enable_vblank_kms(struct drm_device *dev, unsigned int pipe) { struct amdgpu_device *adev = dev->dev_private; - int idx = amdgpu_crtc_idx_to_irq_type(adev, pipe); + int idx = amdgpu_display_crtc_idx_to_irq_type(adev, pipe); return amdgpu_irq_get(adev, &adev->crtc_irq, idx); } @@ -1008,7 +1046,7 @@ int amdgpu_enable_vblank_kms(struct drm_device *dev, unsigned int pipe) void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe) { struct amdgpu_device *adev = dev->dev_private; - int idx = amdgpu_crtc_idx_to_irq_type(adev, pipe); + int idx = amdgpu_display_crtc_idx_to_irq_type(adev, pipe); amdgpu_irq_put(adev, &adev->crtc_irq, idx); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 54f06c959340..d9533bbc467c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -267,8 +267,6 @@ struct amdgpu_display_funcs { void (*bandwidth_update)(struct amdgpu_device *adev); /* get frame count */ u32 (*vblank_get_counter)(struct amdgpu_device *adev, int crtc); - /* wait for vblank */ - void (*vblank_wait)(struct amdgpu_device *adev, int crtc); /* set backlight level */ void (*backlight_set_level)(struct amdgpu_encoder *amdgpu_encoder, u8 level); @@ -608,7 +606,7 @@ struct amdgpu_mst_connector { #define ENCODER_MODE_IS_DP(em) (((em) == ATOM_ENCODER_MODE_DP) || \ ((em) == ATOM_ENCODER_MODE_DP_MST)) -/* Driver internal use only flags of amdgpu_get_crtc_scanoutpos() */ +/* Driver internal use only flags of amdgpu_display_get_crtc_scanoutpos() */ #define DRM_SCANOUTPOS_VALID (1 << 0) #define DRM_SCANOUTPOS_IN_VBLANK (1 << 1) #define DRM_SCANOUTPOS_ACCURATE (1 << 2) @@ -627,30 +625,31 @@ bool amdgpu_dig_monitor_is_duallink(struct drm_encoder *encoder, u16 amdgpu_encoder_get_dp_bridge_encoder_id(struct drm_encoder *encoder); struct drm_encoder *amdgpu_get_external_encoder(struct drm_encoder *encoder); -bool amdgpu_ddc_probe(struct amdgpu_connector *amdgpu_connector, bool use_aux); +bool amdgpu_display_ddc_probe(struct amdgpu_connector *amdgpu_connector, + bool use_aux); void amdgpu_encoder_set_active_device(struct drm_encoder *encoder); -int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, - unsigned int flags, int *vpos, int *hpos, - ktime_t *stime, ktime_t *etime, - const struct drm_display_mode *mode); +int amdgpu_display_get_crtc_scanoutpos(struct drm_device *dev, + unsigned int pipe, unsigned int flags, int *vpos, + int *hpos, ktime_t *stime, ktime_t *etime, + const struct drm_display_mode *mode); -int amdgpu_framebuffer_init(struct drm_device *dev, - struct amdgpu_framebuffer *rfb, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj); +int amdgpu_display_framebuffer_init(struct drm_device *dev, + struct amdgpu_framebuffer *rfb, + const struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_gem_object *obj); int amdgpufb_remove(struct drm_device *dev, struct drm_framebuffer *fb); void amdgpu_enc_destroy(struct drm_encoder *encoder); void amdgpu_copy_fb(struct drm_device *dev, struct drm_gem_object *dst_obj); -bool amdgpu_crtc_scaling_mode_fixup(struct drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); +bool amdgpu_display_crtc_scaling_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); void amdgpu_panel_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode); -int amdgpu_crtc_idx_to_irq_type(struct amdgpu_device *adev, int crtc); +int amdgpu_display_crtc_idx_to_irq_type(struct amdgpu_device *adev, int crtc); /* fbdev layer */ int amdgpu_fbdev_init(struct amdgpu_device *adev); @@ -662,15 +661,15 @@ bool amdgpu_fbdev_robj_is_fb(struct amdgpu_device *adev, struct amdgpu_bo *robj) int amdgpu_align_pitch(struct amdgpu_device *adev, int width, int bpp, bool tiled); /* amdgpu_display.c */ -void amdgpu_print_display_setup(struct drm_device *dev); -int amdgpu_modeset_create_props(struct amdgpu_device *adev); -int amdgpu_crtc_set_config(struct drm_mode_set *set, - struct drm_modeset_acquire_ctx *ctx); -int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event, - uint32_t page_flip_flags, uint32_t target, - struct drm_modeset_acquire_ctx *ctx); +void amdgpu_display_print_display_setup(struct drm_device *dev); +int amdgpu_display_modeset_create_props(struct amdgpu_device *adev); +int amdgpu_display_crtc_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx); +int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t page_flip_flags, uint32_t target, + struct drm_modeset_acquire_ctx *ctx); extern const struct drm_mode_config_funcs amdgpu_mode_funcs; #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 5c4c3e0d527b..969de54b62da 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -83,7 +83,7 @@ void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain) u32 c = 0; if (domain & AMDGPU_GEM_DOMAIN_VRAM) { - unsigned visible_pfn = adev->mc.visible_vram_size >> PAGE_SHIFT; + unsigned visible_pfn = adev->gmc.visible_vram_size >> PAGE_SHIFT; places[c].fpfn = 0; places[c].lpfn = 0; @@ -103,7 +103,7 @@ void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain) if (domain & AMDGPU_GEM_DOMAIN_GTT) { places[c].fpfn = 0; if (flags & AMDGPU_GEM_CREATE_SHADOW) - places[c].lpfn = adev->mc.gart_size >> PAGE_SHIFT; + places[c].lpfn = adev->gmc.gart_size >> PAGE_SHIFT; else places[c].lpfn = 0; places[c].flags = TTM_PL_FLAG_TT; @@ -190,7 +190,7 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev, r = amdgpu_bo_create(adev, size, align, true, domain, AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS, - NULL, NULL, 0, bo_ptr); + NULL, NULL, bo_ptr); if (r) { dev_err(adev->dev, "(%d) failed to allocate kernel bo\n", r); @@ -336,7 +336,6 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, bool kernel, u32 domain, u64 flags, struct sg_table *sg, struct reservation_object *resv, - uint64_t init_value, struct amdgpu_bo **bo_ptr) { struct ttm_operation_ctx ctx = { @@ -372,11 +371,7 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, bo = kzalloc(sizeof(struct amdgpu_bo), GFP_KERNEL); if (bo == NULL) return -ENOMEM; - r = drm_gem_object_init(adev->ddev, &bo->gem_base, size); - if (unlikely(r)) { - kfree(bo); - return r; - } + drm_gem_private_object_init(adev->ddev, &bo->gem_base, size); INIT_LIST_HEAD(&bo->shadow_list); INIT_LIST_HEAD(&bo->va); bo->preferred_domains = domain & (AMDGPU_GEM_DOMAIN_VRAM | @@ -428,9 +423,9 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, if (unlikely(r != 0)) return r; - if (adev->mc.visible_vram_size < adev->mc.real_vram_size && + if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size && bo->tbo.mem.mem_type == TTM_PL_VRAM && - bo->tbo.mem.start < adev->mc.visible_vram_size >> PAGE_SHIFT) + bo->tbo.mem.start < adev->gmc.visible_vram_size >> PAGE_SHIFT) amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved, ctx.bytes_moved); else @@ -443,7 +438,7 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, bo->tbo.mem.placement & TTM_PL_FLAG_VRAM) { struct dma_fence *fence; - r = amdgpu_fill_buffer(bo, init_value, bo->tbo.resv, &fence); + r = amdgpu_fill_buffer(bo, 0, bo->tbo.resv, &fence); if (unlikely(r)) goto fail_unreserve; @@ -484,7 +479,7 @@ static int amdgpu_bo_create_shadow(struct amdgpu_device *adev, AMDGPU_GEM_DOMAIN_GTT, AMDGPU_GEM_CREATE_CPU_GTT_USWC | AMDGPU_GEM_CREATE_SHADOW, - NULL, bo->tbo.resv, 0, + NULL, bo->tbo.resv, &bo->shadow); if (!r) { bo->shadow->parent = amdgpu_bo_ref(bo); @@ -496,22 +491,18 @@ static int amdgpu_bo_create_shadow(struct amdgpu_device *adev, return r; } -/* init_value will only take effect when flags contains - * AMDGPU_GEM_CREATE_VRAM_CLEARED. - */ int amdgpu_bo_create(struct amdgpu_device *adev, unsigned long size, int byte_align, bool kernel, u32 domain, u64 flags, struct sg_table *sg, struct reservation_object *resv, - uint64_t init_value, struct amdgpu_bo **bo_ptr) { uint64_t parent_flags = flags & ~AMDGPU_GEM_CREATE_SHADOW; int r; r = amdgpu_bo_do_create(adev, size, byte_align, kernel, domain, - parent_flags, sg, resv, init_value, bo_ptr); + parent_flags, sg, resv, bo_ptr); if (r) return r; @@ -832,25 +823,25 @@ static const char *amdgpu_vram_names[] = { int amdgpu_bo_init(struct amdgpu_device *adev) { /* reserve PAT memory space to WC for VRAM */ - arch_io_reserve_memtype_wc(adev->mc.aper_base, - adev->mc.aper_size); + arch_io_reserve_memtype_wc(adev->gmc.aper_base, + adev->gmc.aper_size); /* Add an MTRR for the VRAM */ - adev->mc.vram_mtrr = arch_phys_wc_add(adev->mc.aper_base, - adev->mc.aper_size); + adev->gmc.vram_mtrr = arch_phys_wc_add(adev->gmc.aper_base, + adev->gmc.aper_size); DRM_INFO("Detected VRAM RAM=%lluM, BAR=%lluM\n", - adev->mc.mc_vram_size >> 20, - (unsigned long long)adev->mc.aper_size >> 20); + adev->gmc.mc_vram_size >> 20, + (unsigned long long)adev->gmc.aper_size >> 20); DRM_INFO("RAM width %dbits %s\n", - adev->mc.vram_width, amdgpu_vram_names[adev->mc.vram_type]); + adev->gmc.vram_width, amdgpu_vram_names[adev->gmc.vram_type]); return amdgpu_ttm_init(adev); } void amdgpu_bo_fini(struct amdgpu_device *adev) { amdgpu_ttm_fini(adev); - arch_phys_wc_del(adev->mc.vram_mtrr); - arch_io_free_memtype_wc(adev->mc.aper_base, adev->mc.aper_size); + arch_phys_wc_del(adev->gmc.vram_mtrr); + arch_io_free_memtype_wc(adev->gmc.aper_base, adev->gmc.aper_size); } int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo, @@ -980,7 +971,7 @@ int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) size = bo->mem.num_pages << PAGE_SHIFT; offset = bo->mem.start << PAGE_SHIFT; - if ((offset + size) <= adev->mc.visible_vram_size) + if ((offset + size) <= adev->gmc.visible_vram_size) return 0; /* Can't move a pinned BO to visible VRAM */ @@ -1003,7 +994,7 @@ int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) offset = bo->mem.start << PAGE_SHIFT; /* this should never happen */ if (bo->mem.mem_type == TTM_PL_VRAM && - (offset + size) > adev->mc.visible_vram_size) + (offset + size) > adev->gmc.visible_vram_size) return -EINVAL; return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index 33615e2ea2e6..c2b02f5c88d2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -206,7 +206,6 @@ int amdgpu_bo_create(struct amdgpu_device *adev, bool kernel, u32 domain, u64 flags, struct sg_table *sg, struct reservation_object *resv, - uint64_t init_value, struct amdgpu_bo **bo_ptr); int amdgpu_bo_create_reserved(struct amdgpu_device *adev, unsigned long size, int align, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 01a996c6b802..9e73cbcfce44 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -116,7 +116,7 @@ static ssize_t amdgpu_set_dpm_state(struct device *dev, } if (adev->powerplay.pp_funcs->dispatch_tasks) { - amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_ENABLE_USER_STATE, &state, NULL); + amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_ENABLE_USER_STATE, &state); } else { mutex_lock(&adev->pm.mutex); adev->pm.dpm.user_state = state; @@ -316,7 +316,7 @@ static ssize_t amdgpu_set_pp_force_state(struct device *dev, if (state != POWER_STATE_TYPE_INTERNAL_BOOT && state != POWER_STATE_TYPE_DEFAULT) { amdgpu_dpm_dispatch_task(adev, - AMD_PP_TASK_ENABLE_USER_STATE, &state, NULL); + AMD_PP_TASK_ENABLE_USER_STATE, &state); adev->pp_force_state_enabled = true; } } @@ -360,6 +360,90 @@ static ssize_t amdgpu_set_pp_table(struct device *dev, return count; } +static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = ddev->dev_private; + int ret; + uint32_t parameter_size = 0; + long parameter[64]; + char buf_cpy[128]; + char *tmp_str; + char *sub_str; + const char delimiter[3] = {' ', '\n', '\0'}; + uint32_t type; + + if (count > 127) + return -EINVAL; + + if (*buf == 's') + type = PP_OD_EDIT_SCLK_VDDC_TABLE; + else if (*buf == 'm') + type = PP_OD_EDIT_MCLK_VDDC_TABLE; + else if(*buf == 'r') + type = PP_OD_RESTORE_DEFAULT_TABLE; + else if (*buf == 'c') + type = PP_OD_COMMIT_DPM_TABLE; + else + return -EINVAL; + + memcpy(buf_cpy, buf, count+1); + + tmp_str = buf_cpy; + + while (isspace(*++tmp_str)); + + while (tmp_str[0]) { + sub_str = strsep(&tmp_str, delimiter); + ret = kstrtol(sub_str, 0, ¶meter[parameter_size]); + if (ret) + return -EINVAL; + parameter_size++; + + while (isspace(*tmp_str)) + tmp_str++; + } + + if (adev->powerplay.pp_funcs->odn_edit_dpm_table) + ret = amdgpu_dpm_odn_edit_dpm_table(adev, type, + parameter, parameter_size); + + if (ret) + return -EINVAL; + + if (type == PP_OD_COMMIT_DPM_TABLE) { + if (adev->powerplay.pp_funcs->dispatch_tasks) { + amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_READJUST_POWER_STATE, NULL); + return count; + } else { + return -EINVAL; + } + } + + return count; +} + +static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = ddev->dev_private; + uint32_t size = 0; + + if (adev->powerplay.pp_funcs->print_clock_levels) { + size = amdgpu_dpm_print_clock_levels(adev, OD_SCLK, buf); + size += amdgpu_dpm_print_clock_levels(adev, OD_MCLK, buf+size); + return size; + } else { + return snprintf(buf, PAGE_SIZE, "\n"); + } + +} + static ssize_t amdgpu_get_pp_dpm_sclk(struct device *dev, struct device_attribute *attr, char *buf) @@ -530,7 +614,7 @@ static ssize_t amdgpu_set_pp_sclk_od(struct device *dev, amdgpu_dpm_set_sclk_od(adev, (uint32_t)value); if (adev->powerplay.pp_funcs->dispatch_tasks) { - amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_READJUST_POWER_STATE, NULL, NULL); + amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_READJUST_POWER_STATE, NULL); } else { adev->pm.dpm.current_ps = adev->pm.dpm.boot_ps; amdgpu_pm_compute_clocks(adev); @@ -574,7 +658,7 @@ static ssize_t amdgpu_set_pp_mclk_od(struct device *dev, amdgpu_dpm_set_mclk_od(adev, (uint32_t)value); if (adev->powerplay.pp_funcs->dispatch_tasks) { - amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_READJUST_POWER_STATE, NULL, NULL); + amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_READJUST_POWER_STATE, NULL); } else { adev->pm.dpm.current_ps = adev->pm.dpm.boot_ps; amdgpu_pm_compute_clocks(adev); @@ -584,6 +668,72 @@ fail: return count; } +static ssize_t amdgpu_get_pp_power_profile_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = ddev->dev_private; + + if (adev->powerplay.pp_funcs->get_power_profile_mode) + return amdgpu_dpm_get_power_profile_mode(adev, buf); + + return snprintf(buf, PAGE_SIZE, "\n"); +} + + +static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + int ret = 0xff; + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = ddev->dev_private; + uint32_t parameter_size = 0; + long parameter[64]; + char *sub_str, buf_cpy[128]; + char *tmp_str; + uint32_t i = 0; + char tmp[2]; + long int profile_mode = 0; + const char delimiter[3] = {' ', '\n', '\0'}; + + tmp[0] = *(buf); + tmp[1] = '\0'; + ret = kstrtol(tmp, 0, &profile_mode); + if (ret) + goto fail; + + if (profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { + if (count < 2 || count > 127) + return -EINVAL; + while (isspace(*++buf)) + i++; + memcpy(buf_cpy, buf, count-i); + tmp_str = buf_cpy; + while (tmp_str[0]) { + sub_str = strsep(&tmp_str, delimiter); + ret = kstrtol(sub_str, 0, ¶meter[parameter_size]); + if (ret) { + count = -EINVAL; + goto fail; + } + parameter_size++; + while (isspace(*tmp_str)) + tmp_str++; + } + } + parameter[parameter_size] = profile_mode; + if (adev->powerplay.pp_funcs->set_power_profile_mode) + ret = amdgpu_dpm_set_power_profile_mode(adev, parameter, parameter_size); + + if (!ret) + return count; +fail: + return -EINVAL; +} + static ssize_t amdgpu_get_pp_power_profile(struct device *dev, char *buf, struct amd_pp_profile *query) { @@ -772,6 +922,12 @@ static DEVICE_ATTR(pp_gfx_power_profile, S_IRUGO | S_IWUSR, static DEVICE_ATTR(pp_compute_power_profile, S_IRUGO | S_IWUSR, amdgpu_get_pp_compute_power_profile, amdgpu_set_pp_compute_power_profile); +static DEVICE_ATTR(pp_power_profile_mode, S_IRUGO | S_IWUSR, + amdgpu_get_pp_power_profile_mode, + amdgpu_set_pp_power_profile_mode); +static DEVICE_ATTR(pp_od_clk_voltage, S_IRUGO | S_IWUSR, + amdgpu_get_pp_od_clk_voltage, + amdgpu_set_pp_od_clk_voltage); static ssize_t amdgpu_hwmon_show_temp(struct device *dev, struct device_attribute *attr, @@ -779,17 +935,23 @@ static ssize_t amdgpu_hwmon_show_temp(struct device *dev, { struct amdgpu_device *adev = dev_get_drvdata(dev); struct drm_device *ddev = adev->ddev; - int temp; + int r, temp, size = sizeof(temp); /* Can't get temperature when the card is off */ if ((adev->flags & AMD_IS_PX) && (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) return -EINVAL; - if (!adev->powerplay.pp_funcs->get_temperature) - temp = 0; - else - temp = amdgpu_dpm_get_temperature(adev); + /* sanity check PP is enabled */ + if (!(adev->powerplay.pp_funcs && + adev->powerplay.pp_funcs->read_sensor)) + return -EINVAL; + + /* get the temperature */ + r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_TEMP, + (void *)&temp, &size); + if (r) + return r; return snprintf(buf, PAGE_SIZE, "%d\n", temp); } @@ -834,6 +996,11 @@ static ssize_t amdgpu_hwmon_set_pwm1_enable(struct device *dev, int err; int value; + /* Can't adjust fan when the card is off */ + if ((adev->flags & AMD_IS_PX) && + (adev->ddev->switch_power_state != DRM_SWITCH_POWER_ON)) + return -EINVAL; + if (!adev->powerplay.pp_funcs->set_fan_control_mode) return -EINVAL; @@ -868,6 +1035,11 @@ static ssize_t amdgpu_hwmon_set_pwm1(struct device *dev, int err; u32 value; + /* Can't adjust fan when the card is off */ + if ((adev->flags & AMD_IS_PX) && + (adev->ddev->switch_power_state != DRM_SWITCH_POWER_ON)) + return -EINVAL; + err = kstrtou32(buf, 10, &value); if (err) return err; @@ -891,6 +1063,11 @@ static ssize_t amdgpu_hwmon_get_pwm1(struct device *dev, int err; u32 speed = 0; + /* Can't adjust fan when the card is off */ + if ((adev->flags & AMD_IS_PX) && + (adev->ddev->switch_power_state != DRM_SWITCH_POWER_ON)) + return -EINVAL; + if (adev->powerplay.pp_funcs->get_fan_speed_percent) { err = amdgpu_dpm_get_fan_speed_percent(adev, &speed); if (err) @@ -910,6 +1087,11 @@ static ssize_t amdgpu_hwmon_get_fan1_input(struct device *dev, int err; u32 speed = 0; + /* Can't adjust fan when the card is off */ + if ((adev->flags & AMD_IS_PX) && + (adev->ddev->switch_power_state != DRM_SWITCH_POWER_ON)) + return -EINVAL; + if (adev->powerplay.pp_funcs->get_fan_speed_rpm) { err = amdgpu_dpm_get_fan_speed_rpm(adev, &speed); if (err) @@ -919,6 +1101,175 @@ static ssize_t amdgpu_hwmon_get_fan1_input(struct device *dev, return sprintf(buf, "%i\n", speed); } +static ssize_t amdgpu_hwmon_show_vddgfx(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct amdgpu_device *adev = dev_get_drvdata(dev); + struct drm_device *ddev = adev->ddev; + u32 vddgfx; + int r, size = sizeof(vddgfx); + + /* Can't get voltage when the card is off */ + if ((adev->flags & AMD_IS_PX) && + (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) + return -EINVAL; + + /* sanity check PP is enabled */ + if (!(adev->powerplay.pp_funcs && + adev->powerplay.pp_funcs->read_sensor)) + return -EINVAL; + + /* get the voltage */ + r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDGFX, + (void *)&vddgfx, &size); + if (r) + return r; + + return snprintf(buf, PAGE_SIZE, "%d\n", vddgfx); +} + +static ssize_t amdgpu_hwmon_show_vddgfx_label(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "vddgfx\n"); +} + +static ssize_t amdgpu_hwmon_show_vddnb(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct amdgpu_device *adev = dev_get_drvdata(dev); + struct drm_device *ddev = adev->ddev; + u32 vddnb; + int r, size = sizeof(vddnb); + + /* only APUs have vddnb */ + if (adev->flags & AMD_IS_APU) + return -EINVAL; + + /* Can't get voltage when the card is off */ + if ((adev->flags & AMD_IS_PX) && + (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) + return -EINVAL; + + /* sanity check PP is enabled */ + if (!(adev->powerplay.pp_funcs && + adev->powerplay.pp_funcs->read_sensor)) + return -EINVAL; + + /* get the voltage */ + r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDNB, + (void *)&vddnb, &size); + if (r) + return r; + + return snprintf(buf, PAGE_SIZE, "%d\n", vddnb); +} + +static ssize_t amdgpu_hwmon_show_vddnb_label(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "vddnb\n"); +} + +static ssize_t amdgpu_hwmon_show_power_avg(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct amdgpu_device *adev = dev_get_drvdata(dev); + struct drm_device *ddev = adev->ddev; + struct pp_gpu_power query = {0}; + int r, size = sizeof(query); + unsigned uw; + + /* Can't get power when the card is off */ + if ((adev->flags & AMD_IS_PX) && + (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) + return -EINVAL; + + /* sanity check PP is enabled */ + if (!(adev->powerplay.pp_funcs && + adev->powerplay.pp_funcs->read_sensor)) + return -EINVAL; + + /* get the voltage */ + r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_POWER, + (void *)&query, &size); + if (r) + return r; + + /* convert to microwatts */ + uw = (query.average_gpu_power >> 8) * 1000000; + + return snprintf(buf, PAGE_SIZE, "%u\n", uw); +} + +static ssize_t amdgpu_hwmon_show_power_cap_min(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%i\n", 0); +} + +static ssize_t amdgpu_hwmon_show_power_cap_max(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct amdgpu_device *adev = dev_get_drvdata(dev); + uint32_t limit = 0; + + if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->get_power_limit) { + adev->powerplay.pp_funcs->get_power_limit(adev->powerplay.pp_handle, &limit, true); + return snprintf(buf, PAGE_SIZE, "%u\n", limit * 1000000); + } else { + return snprintf(buf, PAGE_SIZE, "\n"); + } +} + +static ssize_t amdgpu_hwmon_show_power_cap(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct amdgpu_device *adev = dev_get_drvdata(dev); + uint32_t limit = 0; + + if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->get_power_limit) { + adev->powerplay.pp_funcs->get_power_limit(adev->powerplay.pp_handle, &limit, false); + return snprintf(buf, PAGE_SIZE, "%u\n", limit * 1000000); + } else { + return snprintf(buf, PAGE_SIZE, "\n"); + } +} + + +static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct amdgpu_device *adev = dev_get_drvdata(dev); + int err; + u32 value; + + err = kstrtou32(buf, 10, &value); + if (err) + return err; + + value = value / 1000000; /* convert to Watt */ + if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->set_power_limit) { + err = adev->powerplay.pp_funcs->set_power_limit(adev->powerplay.pp_handle, value); + if (err) + return err; + } else { + return -EINVAL; + } + + return count; +} + static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, amdgpu_hwmon_show_temp, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, amdgpu_hwmon_show_temp_thresh, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, amdgpu_hwmon_show_temp_thresh, NULL, 1); @@ -927,6 +1278,14 @@ static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, amdgpu_hwmon_get_pwm1_ static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO, amdgpu_hwmon_get_pwm1_min, NULL, 0); static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO, amdgpu_hwmon_get_pwm1_max, NULL, 0); static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, amdgpu_hwmon_get_fan1_input, NULL, 0); +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, amdgpu_hwmon_show_vddgfx, NULL, 0); +static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, amdgpu_hwmon_show_vddgfx_label, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, amdgpu_hwmon_show_vddnb, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, amdgpu_hwmon_show_vddnb_label, NULL, 0); +static SENSOR_DEVICE_ATTR(power1_average, S_IRUGO, amdgpu_hwmon_show_power_avg, NULL, 0); +static SENSOR_DEVICE_ATTR(power1_cap_max, S_IRUGO, amdgpu_hwmon_show_power_cap_max, NULL, 0); +static SENSOR_DEVICE_ATTR(power1_cap_min, S_IRUGO, amdgpu_hwmon_show_power_cap_min, NULL, 0); +static SENSOR_DEVICE_ATTR(power1_cap, S_IRUGO | S_IWUSR, amdgpu_hwmon_show_power_cap, amdgpu_hwmon_set_power_cap, 0); static struct attribute *hwmon_attributes[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, @@ -937,6 +1296,14 @@ static struct attribute *hwmon_attributes[] = { &sensor_dev_attr_pwm1_min.dev_attr.attr, &sensor_dev_attr_pwm1_max.dev_attr.attr, &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_label.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_label.dev_attr.attr, + &sensor_dev_attr_power1_average.dev_attr.attr, + &sensor_dev_attr_power1_cap_max.dev_attr.attr, + &sensor_dev_attr_power1_cap_min.dev_attr.attr, + &sensor_dev_attr_power1_cap.dev_attr.attr, NULL }; @@ -947,9 +1314,19 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, struct amdgpu_device *adev = dev_get_drvdata(dev); umode_t effective_mode = attr->mode; - /* no skipping for powerplay */ - if (adev->powerplay.cgs_device) - return effective_mode; + /* handle non-powerplay limitations */ + if (!adev->powerplay.cgs_device) { + /* Skip fan attributes if fan is not present */ + if (adev->pm.no_fan && + (attr == &sensor_dev_attr_pwm1.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_max.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_min.dev_attr.attr)) + return 0; + /* requires powerplay */ + if (attr == &sensor_dev_attr_fan1_input.dev_attr.attr) + return 0; + } /* Skip limit attributes if DPM is not enabled */ if (!adev->pm.dpm_enabled && @@ -961,14 +1338,6 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, attr == &sensor_dev_attr_pwm1_min.dev_attr.attr)) return 0; - /* Skip fan attributes if fan is not present */ - if (adev->pm.no_fan && - (attr == &sensor_dev_attr_pwm1.dev_attr.attr || - attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr || - attr == &sensor_dev_attr_pwm1_max.dev_attr.attr || - attr == &sensor_dev_attr_pwm1_min.dev_attr.attr)) - return 0; - /* mask fan attributes if we have no bindings for this asic to expose */ if ((!adev->powerplay.pp_funcs->get_fan_speed_percent && attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't query fan */ @@ -982,6 +1351,12 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't manage state */ effective_mode &= ~S_IWUSR; + if ((adev->flags & AMD_IS_APU) && + (attr == &sensor_dev_attr_power1_cap_max.dev_attr.attr || + attr == &sensor_dev_attr_power1_cap_min.dev_attr.attr|| + attr == &sensor_dev_attr_power1_cap.dev_attr.attr)) + return 0; + /* hide max/min values if we can't both query and manage the fan */ if ((!adev->powerplay.pp_funcs->set_fan_speed_percent && !adev->powerplay.pp_funcs->get_fan_speed_percent) && @@ -989,8 +1364,10 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, attr == &sensor_dev_attr_pwm1_min.dev_attr.attr)) return 0; - /* requires powerplay */ - if (attr == &sensor_dev_attr_fan1_input.dev_attr.attr) + /* only APUs have vddnb */ + if (!(adev->flags & AMD_IS_APU) && + (attr == &sensor_dev_attr_in1_input.dev_attr.attr || + attr == &sensor_dev_attr_in1_label.dev_attr.attr)) return 0; return effective_mode; @@ -1013,13 +1390,15 @@ void amdgpu_dpm_thermal_work_handler(struct work_struct *work) pm.dpm.thermal.work); /* switch to the thermal state */ enum amd_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL; + int temp, size = sizeof(temp); if (!adev->pm.dpm_enabled) return; - if (adev->powerplay.pp_funcs->get_temperature) { - int temp = amdgpu_dpm_get_temperature(adev); - + if (adev->powerplay.pp_funcs && + adev->powerplay.pp_funcs->read_sensor && + !amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_TEMP, + (void *)&temp, &size)) { if (temp < adev->pm.dpm.thermal.min_temp) /* switch back the user state */ dpm_state = adev->pm.dpm.user_state; @@ -1319,9 +1698,6 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) if (adev->pm.dpm_enabled == 0) return 0; - if (adev->powerplay.pp_funcs->get_temperature == NULL) - return 0; - adev->pm.int_hwmon_dev = hwmon_device_register_with_groups(adev->dev, DRIVER_NAME, adev, hwmon_groups); @@ -1405,6 +1781,20 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) return ret; } + ret = device_create_file(adev->dev, + &dev_attr_pp_power_profile_mode); + if (ret) { + DRM_ERROR("failed to create device file " + "pp_power_profile_mode\n"); + return ret; + } + ret = device_create_file(adev->dev, + &dev_attr_pp_od_clk_voltage); + if (ret) { + DRM_ERROR("failed to create device file " + "pp_od_clk_voltage\n"); + return ret; + } ret = amdgpu_debugfs_pm_init(adev); if (ret) { DRM_ERROR("Failed to register debugfs file for dpm!\n"); @@ -1440,6 +1830,10 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev) &dev_attr_pp_gfx_power_profile); device_remove_file(adev->dev, &dev_attr_pp_compute_power_profile); + device_remove_file(adev->dev, + &dev_attr_pp_power_profile_mode); + device_remove_file(adev->dev, + &dev_attr_pp_od_clk_voltage); } void amdgpu_pm_compute_clocks(struct amdgpu_device *adev) @@ -1462,7 +1856,7 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev) } if (adev->powerplay.pp_funcs->dispatch_tasks) { - amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_DISPLAY_CONFIG_CHANGE, NULL, NULL); + amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_DISPLAY_CONFIG_CHANGE, NULL); } else { mutex_lock(&adev->pm.mutex); adev->pm.dpm.new_active_crtcs = 0; @@ -1512,6 +1906,10 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a seq_printf(m, "\t%u MHz (MCLK)\n", value/100); if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GFX_SCLK, (void *)&value, &size)) seq_printf(m, "\t%u MHz (SCLK)\n", value/100); + if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_STABLE_PSTATE_SCLK, (void *)&value, &size)) + seq_printf(m, "\t%u MHz (PSTATE_SCLK)\n", value/100); + if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_STABLE_PSTATE_MCLK, (void *)&value, &size)) + seq_printf(m, "\t%u MHz (PSTATE_MCLK)\n", value/100); if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDGFX, (void *)&value, &size)) seq_printf(m, "\t%u mV (VDDGFX)\n", value); if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDNB, (void *)&value, &size)) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c index ae9c106979d7..8ce74a1d9966 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c @@ -26,9 +26,12 @@ #include #include "amdgpu.h" +#include "amdgpu_display.h" #include #include +static const struct dma_buf_ops amdgpu_dmabuf_ops; + struct sg_table *amdgpu_gem_prime_get_sg_table(struct drm_gem_object *obj) { struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); @@ -103,7 +106,7 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev, ww_mutex_lock(&resv->lock, NULL); ret = amdgpu_bo_create(adev, attach->dmabuf->size, PAGE_SIZE, false, - AMDGPU_GEM_DOMAIN_GTT, 0, sg, resv, 0, &bo); + AMDGPU_GEM_DOMAIN_GTT, 0, sg, resv, &bo); ww_mutex_unlock(&resv->lock); if (ret) return ERR_PTR(ret); @@ -112,49 +115,72 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev, return &bo->gem_base; } -int amdgpu_gem_prime_pin(struct drm_gem_object *obj) +static int amdgpu_gem_map_attach(struct dma_buf *dma_buf, + struct device *target_dev, + struct dma_buf_attachment *attach) { + struct drm_gem_object *obj = dma_buf->priv; struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); - long ret = 0; + long r; - ret = amdgpu_bo_reserve(bo, false); - if (unlikely(ret != 0)) - return ret; + r = drm_gem_map_attach(dma_buf, target_dev, attach); + if (r) + return r; - /* - * Wait for all shared fences to complete before we switch to future - * use of exclusive fence on this prime shared bo. - */ - ret = reservation_object_wait_timeout_rcu(bo->tbo.resv, true, false, - MAX_SCHEDULE_TIMEOUT); - if (unlikely(ret < 0)) { - DRM_DEBUG_PRIME("Fence wait failed: %li\n", ret); - amdgpu_bo_unreserve(bo); - return ret; + r = amdgpu_bo_reserve(bo, false); + if (unlikely(r != 0)) + goto error_detach; + + + if (dma_buf->ops != &amdgpu_dmabuf_ops) { + /* + * Wait for all shared fences to complete before we switch to future + * use of exclusive fence on this prime shared bo. + */ + r = reservation_object_wait_timeout_rcu(bo->tbo.resv, + true, false, + MAX_SCHEDULE_TIMEOUT); + if (unlikely(r < 0)) { + DRM_DEBUG_PRIME("Fence wait failed: %li\n", r); + goto error_unreserve; + } } /* pin buffer into GTT */ - ret = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT, NULL); - if (likely(ret == 0)) + r = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT, NULL); + if (r) + goto error_unreserve; + + if (dma_buf->ops != &amdgpu_dmabuf_ops) bo->prime_shared_count++; +error_unreserve: amdgpu_bo_unreserve(bo); - return ret; + +error_detach: + if (r) + drm_gem_map_detach(dma_buf, attach); + return r; } -void amdgpu_gem_prime_unpin(struct drm_gem_object *obj) +static void amdgpu_gem_map_detach(struct dma_buf *dma_buf, + struct dma_buf_attachment *attach) { + struct drm_gem_object *obj = dma_buf->priv; struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); int ret = 0; ret = amdgpu_bo_reserve(bo, true); if (unlikely(ret != 0)) - return; + goto error; amdgpu_bo_unpin(bo); - if (bo->prime_shared_count) + if (dma_buf->ops != &amdgpu_dmabuf_ops && bo->prime_shared_count) bo->prime_shared_count--; amdgpu_bo_unreserve(bo); + +error: + drm_gem_map_detach(dma_buf, attach); } struct reservation_object *amdgpu_gem_prime_res_obj(struct drm_gem_object *obj) @@ -164,6 +190,50 @@ struct reservation_object *amdgpu_gem_prime_res_obj(struct drm_gem_object *obj) return bo->tbo.resv; } +static int amdgpu_gem_begin_cpu_access(struct dma_buf *dma_buf, + enum dma_data_direction direction) +{ + struct amdgpu_bo *bo = gem_to_amdgpu_bo(dma_buf->priv); + struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); + struct ttm_operation_ctx ctx = { true, false }; + u32 domain = amdgpu_display_framebuffer_domains(adev); + int ret; + bool reads = (direction == DMA_BIDIRECTIONAL || + direction == DMA_FROM_DEVICE); + + if (!reads || !(domain & AMDGPU_GEM_DOMAIN_GTT)) + return 0; + + /* move to gtt */ + ret = amdgpu_bo_reserve(bo, false); + if (unlikely(ret != 0)) + return ret; + + if (!bo->pin_count && (bo->allowed_domains & AMDGPU_GEM_DOMAIN_GTT)) { + amdgpu_ttm_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_GTT); + ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); + } + + amdgpu_bo_unreserve(bo); + return ret; +} + +static const struct dma_buf_ops amdgpu_dmabuf_ops = { + .attach = amdgpu_gem_map_attach, + .detach = amdgpu_gem_map_detach, + .map_dma_buf = drm_gem_map_dma_buf, + .unmap_dma_buf = drm_gem_unmap_dma_buf, + .release = drm_gem_dmabuf_release, + .begin_cpu_access = amdgpu_gem_begin_cpu_access, + .map = drm_gem_dmabuf_kmap, + .map_atomic = drm_gem_dmabuf_kmap_atomic, + .unmap = drm_gem_dmabuf_kunmap, + .unmap_atomic = drm_gem_dmabuf_kunmap_atomic, + .mmap = drm_gem_dmabuf_mmap, + .vmap = drm_gem_dmabuf_vmap, + .vunmap = drm_gem_dmabuf_vunmap, +}; + struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev, struct drm_gem_object *gobj, int flags) @@ -176,7 +246,30 @@ struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev, return ERR_PTR(-EPERM); buf = drm_gem_prime_export(dev, gobj, flags); - if (!IS_ERR(buf)) + if (!IS_ERR(buf)) { buf->file->f_mapping = dev->anon_inode->i_mapping; + buf->ops = &amdgpu_dmabuf_ops; + } + return buf; } + +struct drm_gem_object *amdgpu_gem_prime_import(struct drm_device *dev, + struct dma_buf *dma_buf) +{ + struct drm_gem_object *obj; + + if (dma_buf->ops == &amdgpu_dmabuf_ops) { + obj = dma_buf->priv; + if (obj->dev == dev) { + /* + * Importing dmabuf exported from out own gem increases + * refcount on gem itself instead of f_count of dmabuf. + */ + drm_gem_object_get(obj); + return obj; + } + } + + return drm_gem_prime_import(dev, dma_buf); +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 2157d4509e84..6e712f12eecd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -51,29 +51,10 @@ static int psp_sw_init(void *handle) switch (adev->asic_type) { case CHIP_VEGA10: - psp->init_microcode = psp_v3_1_init_microcode; - psp->bootloader_load_sysdrv = psp_v3_1_bootloader_load_sysdrv; - psp->bootloader_load_sos = psp_v3_1_bootloader_load_sos; - psp->prep_cmd_buf = psp_v3_1_prep_cmd_buf; - psp->ring_init = psp_v3_1_ring_init; - psp->ring_create = psp_v3_1_ring_create; - psp->ring_stop = psp_v3_1_ring_stop; - psp->ring_destroy = psp_v3_1_ring_destroy; - psp->cmd_submit = psp_v3_1_cmd_submit; - psp->compare_sram_data = psp_v3_1_compare_sram_data; - psp->smu_reload_quirk = psp_v3_1_smu_reload_quirk; - psp->mode1_reset = psp_v3_1_mode1_reset; + psp_v3_1_set_psp_funcs(psp); break; case CHIP_RAVEN: - psp->init_microcode = psp_v10_0_init_microcode; - psp->prep_cmd_buf = psp_v10_0_prep_cmd_buf; - psp->ring_init = psp_v10_0_ring_init; - psp->ring_create = psp_v10_0_ring_create; - psp->ring_stop = psp_v10_0_ring_stop; - psp->ring_destroy = psp_v10_0_ring_destroy; - psp->cmd_submit = psp_v10_0_cmd_submit; - psp->compare_sram_data = psp_v10_0_compare_sram_data; - psp->mode1_reset = psp_v10_0_mode1_reset; + psp_v10_0_set_psp_funcs(psp); break; default: return -EINVAL; @@ -512,19 +493,8 @@ failed: return ret; } -static bool psp_check_reset(void* handle) +int psp_gpu_reset(struct amdgpu_device *adev) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (adev->flags & AMD_IS_APU) - return true; - - return false; -} - -static int psp_reset(void* handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; return psp_mode1_reset(&adev->psp); } @@ -571,9 +541,9 @@ const struct amd_ip_funcs psp_ip_funcs = { .suspend = psp_suspend, .resume = psp_resume, .is_idle = NULL, - .check_soft_reset = psp_check_reset, + .check_soft_reset = NULL, .wait_for_idle = NULL, - .soft_reset = psp_reset, + .soft_reset = NULL, .set_clockgating_state = psp_set_clockgating_state, .set_powergating_state = psp_set_powergating_state, }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h index ce4654550416..129209686848 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h @@ -33,6 +33,8 @@ #define PSP_ASD_SHARED_MEM_SIZE 0x4000 #define PSP_1_MEG 0x100000 +struct psp_context; + enum psp_ring_type { PSP_RING_TYPE__INVALID = 0, @@ -53,12 +55,8 @@ struct psp_ring uint32_t ring_size; }; -struct psp_context +struct psp_funcs { - struct amdgpu_device *adev; - struct psp_ring km_ring; - struct psp_gfx_cmd_resp *cmd; - int (*init_microcode)(struct psp_context *psp); int (*bootloader_load_sysdrv)(struct psp_context *psp); int (*bootloader_load_sos)(struct psp_context *psp); @@ -77,6 +75,15 @@ struct psp_context enum AMDGPU_UCODE_ID ucode_type); bool (*smu_reload_quirk)(struct psp_context *psp); int (*mode1_reset)(struct psp_context *psp); +}; + +struct psp_context +{ + struct amdgpu_device *adev; + struct psp_ring km_ring; + struct psp_gfx_cmd_resp *cmd; + + const struct psp_funcs *funcs; /* fence buffer */ struct amdgpu_bo *fw_pri_bo; @@ -123,25 +130,25 @@ struct amdgpu_psp_funcs { enum AMDGPU_UCODE_ID); }; -#define psp_prep_cmd_buf(ucode, type) (psp)->prep_cmd_buf((ucode), (type)) -#define psp_ring_init(psp, type) (psp)->ring_init((psp), (type)) -#define psp_ring_create(psp, type) (psp)->ring_create((psp), (type)) -#define psp_ring_stop(psp, type) (psp)->ring_stop((psp), (type)) -#define psp_ring_destroy(psp, type) ((psp)->ring_destroy((psp), (type))) +#define psp_prep_cmd_buf(ucode, type) (psp)->funcs->prep_cmd_buf((ucode), (type)) +#define psp_ring_init(psp, type) (psp)->funcs->ring_init((psp), (type)) +#define psp_ring_create(psp, type) (psp)->funcs->ring_create((psp), (type)) +#define psp_ring_stop(psp, type) (psp)->funcs->ring_stop((psp), (type)) +#define psp_ring_destroy(psp, type) ((psp)->funcs->ring_destroy((psp), (type))) #define psp_cmd_submit(psp, ucode, cmd_mc, fence_mc, index) \ - (psp)->cmd_submit((psp), (ucode), (cmd_mc), (fence_mc), (index)) + (psp)->funcs->cmd_submit((psp), (ucode), (cmd_mc), (fence_mc), (index)) #define psp_compare_sram_data(psp, ucode, type) \ - (psp)->compare_sram_data((psp), (ucode), (type)) + (psp)->funcs->compare_sram_data((psp), (ucode), (type)) #define psp_init_microcode(psp) \ - ((psp)->init_microcode ? (psp)->init_microcode((psp)) : 0) + ((psp)->funcs->init_microcode ? (psp)->funcs->init_microcode((psp)) : 0) #define psp_bootloader_load_sysdrv(psp) \ - ((psp)->bootloader_load_sysdrv ? (psp)->bootloader_load_sysdrv((psp)) : 0) + ((psp)->funcs->bootloader_load_sysdrv ? (psp)->funcs->bootloader_load_sysdrv((psp)) : 0) #define psp_bootloader_load_sos(psp) \ - ((psp)->bootloader_load_sos ? (psp)->bootloader_load_sos((psp)) : 0) + ((psp)->funcs->bootloader_load_sos ? (psp)->funcs->bootloader_load_sos((psp)) : 0) #define psp_smu_reload_quirk(psp) \ - ((psp)->smu_reload_quirk ? (psp)->smu_reload_quirk((psp)) : false) + ((psp)->funcs->smu_reload_quirk ? (psp)->funcs->smu_reload_quirk((psp)) : false) #define psp_mode1_reset(psp) \ - ((psp)->mode1_reset ? (psp)->mode1_reset((psp)) : false) + ((psp)->funcs->mode1_reset ? (psp)->funcs->mode1_reset((psp)) : false) extern const struct amd_ip_funcs psp_ip_funcs; @@ -151,4 +158,6 @@ extern int psp_wait_for(struct psp_context *psp, uint32_t reg_index, extern const struct amdgpu_ip_block_version psp_v10_0_ip_block; +int psp_gpu_reset(struct amdgpu_device *adev); + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 13044e66dcaf..e223b0f6417b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -360,6 +360,9 @@ void amdgpu_ring_fini(struct amdgpu_ring *ring) amdgpu_debugfs_ring_fini(ring); + dma_fence_put(ring->vmid_wait); + ring->vmid_wait = NULL; + ring->adev->rings[ring->idx] = NULL; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index 102dad3edf6a..1d0d250cbfdf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -128,7 +128,6 @@ struct amdgpu_ring_funcs { void (*emit_vm_flush)(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr); void (*emit_hdp_flush)(struct amdgpu_ring *ring); - void (*emit_hdp_invalidate)(struct amdgpu_ring *ring); void (*emit_gds_switch)(struct amdgpu_ring *ring, uint32_t vmid, uint32_t gds_base, uint32_t gds_size, uint32_t gws_base, uint32_t gws_size, @@ -151,6 +150,8 @@ struct amdgpu_ring_funcs { void (*emit_cntxcntl) (struct amdgpu_ring *ring, uint32_t flags); void (*emit_rreg)(struct amdgpu_ring *ring, uint32_t reg); void (*emit_wreg)(struct amdgpu_ring *ring, uint32_t reg, uint32_t val); + void (*emit_reg_wait)(struct amdgpu_ring *ring, uint32_t reg, + uint32_t val, uint32_t mask); void (*emit_tmz)(struct amdgpu_ring *ring, bool start); /* priority functions */ void (*set_priority) (struct amdgpu_ring *ring, @@ -195,6 +196,7 @@ struct amdgpu_ring { u64 cond_exe_gpu_addr; volatile u32 *cond_exe_cpu_addr; unsigned vm_inv_eng; + struct dma_fence *vmid_wait; bool has_compute_vm_bug; atomic_t num_jobs[DRM_SCHED_PRIORITY_MAX]; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c index 3144400435b7..5ca75a456ad2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c @@ -64,7 +64,7 @@ int amdgpu_sa_bo_manager_init(struct amdgpu_device *adev, INIT_LIST_HEAD(&sa_manager->flist[i]); r = amdgpu_bo_create(adev, size, align, true, domain, - 0, NULL, NULL, 0, &sa_manager->bo); + 0, NULL, NULL, &sa_manager->bo); if (r) { dev_err(adev->dev, "(%d) failed to allocate bo for manager\n", r); return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c index ed8c3739015b..f3d81b6fb499 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c @@ -42,7 +42,7 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev) /* Number of tests = * (Total GTT - IB pool - writeback page - ring buffers) / test size */ - n = adev->mc.gart_size - AMDGPU_IB_POOL_SIZE*64*1024; + n = adev->gmc.gart_size - AMDGPU_IB_POOL_SIZE*64*1024; for (i = 0; i < AMDGPU_MAX_RINGS; ++i) if (adev->rings[i]) n -= adev->rings[i]->ring_size; @@ -61,7 +61,7 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev) r = amdgpu_bo_create(adev, size, PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, 0, - NULL, NULL, 0, &vram_obj); + NULL, NULL, &vram_obj); if (r) { DRM_ERROR("Failed to create VRAM object\n"); goto out_cleanup; @@ -82,7 +82,7 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev) r = amdgpu_bo_create(adev, size, PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_GTT, 0, NULL, - NULL, 0, gtt_obj + i); + NULL, gtt_obj + i); if (r) { DRM_ERROR("Failed to create GTT object %d\n", i); goto out_lclean; @@ -142,10 +142,10 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev) "0x%16llx/0x%16llx)\n", i, *vram_start, gart_start, (unsigned long long) - (gart_addr - adev->mc.gart_start + + (gart_addr - adev->gmc.gart_start + (void*)gart_start - gtt_map), (unsigned long long) - (vram_addr - adev->mc.vram_start + + (vram_addr - adev->gmc.vram_start + (void*)gart_start - gtt_map)); amdgpu_bo_kunmap(vram_obj); goto out_lclean_unpin; @@ -187,10 +187,10 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev) "0x%16llx/0x%16llx)\n", i, *gart_start, vram_start, (unsigned long long) - (vram_addr - adev->mc.vram_start + + (vram_addr - adev->gmc.vram_start + (void*)vram_start - vram_map), (unsigned long long) - (gart_addr - adev->mc.gart_start + + (gart_addr - adev->gmc.gart_start + (void*)vram_start - vram_map)); amdgpu_bo_kunmap(gtt_obj[i]); goto out_lclean_unpin; @@ -200,7 +200,7 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev) amdgpu_bo_kunmap(gtt_obj[i]); DRM_INFO("Tested GTT->VRAM and VRAM->GTT copy for GTT offset 0x%llx\n", - gart_addr - adev->mc.gart_start); + gart_addr - adev->gmc.gart_start); continue; out_lclean_unpin: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index cace7a93fc94..532263ab6e16 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -86,7 +86,7 @@ TRACE_EVENT(amdgpu_iv, __field(unsigned, vmid_src) __field(uint64_t, timestamp) __field(unsigned, timestamp_src) - __field(unsigned, pas_id) + __field(unsigned, pasid) __array(unsigned, src_data, 4) ), TP_fast_assign( @@ -97,16 +97,16 @@ TRACE_EVENT(amdgpu_iv, __entry->vmid_src = iv->vmid_src; __entry->timestamp = iv->timestamp; __entry->timestamp_src = iv->timestamp_src; - __entry->pas_id = iv->pas_id; + __entry->pasid = iv->pasid; __entry->src_data[0] = iv->src_data[0]; __entry->src_data[1] = iv->src_data[1]; __entry->src_data[2] = iv->src_data[2]; __entry->src_data[3] = iv->src_data[3]; ), - TP_printk("client_id:%u src_id:%u ring:%u vmid:%u timestamp: %llu pas_id:%u src_data: %08x %08x %08x %08x\n", + TP_printk("client_id:%u src_id:%u ring:%u vmid:%u timestamp: %llu pasid:%u src_data: %08x %08x %08x %08x\n", __entry->client_id, __entry->src_id, __entry->ring_id, __entry->vmid, - __entry->timestamp, __entry->pas_id, + __entry->timestamp, __entry->pasid, __entry->src_data[0], __entry->src_data[1], __entry->src_data[2], __entry->src_data[3]) ); @@ -217,7 +217,7 @@ TRACE_EVENT(amdgpu_vm_grab_id, struct amdgpu_job *job), TP_ARGS(vm, ring, job), TP_STRUCT__entry( - __field(struct amdgpu_vm *, vm) + __field(u32, pasid) __field(u32, ring) __field(u32, vmid) __field(u32, vm_hub) @@ -226,15 +226,15 @@ TRACE_EVENT(amdgpu_vm_grab_id, ), TP_fast_assign( - __entry->vm = vm; + __entry->pasid = vm->pasid; __entry->ring = ring->idx; __entry->vmid = job->vmid; __entry->vm_hub = ring->funcs->vmhub, __entry->pd_addr = job->vm_pd_addr; __entry->needs_flush = job->vm_needs_flush; ), - TP_printk("vm=%p, ring=%u, id=%u, hub=%u, pd_addr=%010Lx needs_flush=%u", - __entry->vm, __entry->ring, __entry->vmid, + TP_printk("pasid=%d, ring=%u, id=%u, hub=%u, pd_addr=%010Lx needs_flush=%u", + __entry->pasid, __entry->ring, __entry->vmid, __entry->vm_hub, __entry->pd_addr, __entry->needs_flush) ); @@ -378,6 +378,28 @@ TRACE_EVENT(amdgpu_vm_flush, __entry->vm_hub,__entry->pd_addr) ); +DECLARE_EVENT_CLASS(amdgpu_pasid, + TP_PROTO(unsigned pasid), + TP_ARGS(pasid), + TP_STRUCT__entry( + __field(unsigned, pasid) + ), + TP_fast_assign( + __entry->pasid = pasid; + ), + TP_printk("pasid=%u", __entry->pasid) +); + +DEFINE_EVENT(amdgpu_pasid, amdgpu_pasid_allocated, + TP_PROTO(unsigned pasid), + TP_ARGS(pasid) +); + +DEFINE_EVENT(amdgpu_pasid, amdgpu_pasid_freed, + TP_PROTO(unsigned pasid), + TP_ARGS(pasid) +); + TRACE_EVENT(amdgpu_bo_list_set, TP_PROTO(struct amdgpu_bo_list *list, struct amdgpu_bo *bo), TP_ARGS(list, bo), diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index e4bb435e614b..b372d8d650a5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -161,7 +161,7 @@ static int amdgpu_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, break; case TTM_PL_TT: man->func = &amdgpu_gtt_mgr_func; - man->gpu_offset = adev->mc.gart_start; + man->gpu_offset = adev->gmc.gart_start; man->available_caching = TTM_PL_MASK_CACHING; man->default_caching = TTM_PL_FLAG_CACHED; man->flags = TTM_MEMTYPE_FLAG_MAPPABLE | TTM_MEMTYPE_FLAG_CMA; @@ -169,7 +169,7 @@ static int amdgpu_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, case TTM_PL_VRAM: /* "On-card" video ram */ man->func = &amdgpu_vram_mgr_func; - man->gpu_offset = adev->mc.vram_start; + man->gpu_offset = adev->gmc.vram_start; man->flags = TTM_MEMTYPE_FLAG_FIXED | TTM_MEMTYPE_FLAG_MAPPABLE; man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; @@ -217,9 +217,9 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo, adev->mman.buffer_funcs_ring && adev->mman.buffer_funcs_ring->ready == false) { amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU); - } else if (adev->mc.visible_vram_size < adev->mc.real_vram_size && + } else if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size && !(abo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)) { - unsigned fpfn = adev->mc.visible_vram_size >> PAGE_SHIFT; + unsigned fpfn = adev->gmc.visible_vram_size >> PAGE_SHIFT; struct drm_mm_node *node = bo->mem.mm_node; unsigned long pages_left; @@ -638,9 +638,9 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_ case TTM_PL_VRAM: mem->bus.offset = mem->start << PAGE_SHIFT; /* check if it's visible */ - if ((mem->bus.offset + mem->bus.size) > adev->mc.visible_vram_size) + if ((mem->bus.offset + mem->bus.size) > adev->gmc.visible_vram_size) return -EINVAL; - mem->bus.base = adev->mc.aper_base; + mem->bus.base = adev->gmc.aper_base; mem->bus.is_iomem = true; break; default: @@ -891,7 +891,7 @@ int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo) placement.num_busy_placement = 1; placement.busy_placement = &placements; placements.fpfn = 0; - placements.lpfn = adev->mc.gart_size >> PAGE_SHIFT; + placements.lpfn = adev->gmc.gart_size >> PAGE_SHIFT; placements.flags = (bo->mem.placement & ~TTM_PL_MASK_MEM) | TTM_PL_FLAG_TT; @@ -997,9 +997,6 @@ static int amdgpu_ttm_tt_populate(struct ttm_tt *ttm, struct amdgpu_ttm_tt *gtt = (void *)ttm; bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); - if (ttm->state != tt_unpopulated) - return 0; - if (gtt && gtt->userptr) { ttm->sg = kzalloc(sizeof(struct sg_table), GFP_KERNEL); if (!ttm->sg) @@ -1018,7 +1015,7 @@ static int amdgpu_ttm_tt_populate(struct ttm_tt *ttm, } #ifdef CONFIG_SWIOTLB - if (swiotlb_nr_tbl()) { + if (adev->need_swiotlb && swiotlb_nr_tbl()) { return ttm_dma_populate(>t->ttm, adev->dev, ctx); } #endif @@ -1045,7 +1042,7 @@ static void amdgpu_ttm_tt_unpopulate(struct ttm_tt *ttm) adev = amdgpu_ttm_adev(ttm->bdev); #ifdef CONFIG_SWIOTLB - if (swiotlb_nr_tbl()) { + if (adev->need_swiotlb && swiotlb_nr_tbl()) { ttm_dma_unpopulate(>t->ttm, adev->dev); return; } @@ -1212,7 +1209,7 @@ static int amdgpu_ttm_access_memory(struct ttm_buffer_object *bo, nodes = amdgpu_find_mm_node(&abo->tbo.mem, &offset); pos = (nodes->start << PAGE_SHIFT) + offset; - while (len && pos < adev->mc.mc_vram_size) { + while (len && pos < adev->gmc.mc_vram_size) { uint64_t aligned_pos = pos & ~(uint64_t)3; uint32_t bytes = 4 - (pos & 3); uint32_t shift = (pos & 3) * 8; @@ -1298,7 +1295,7 @@ static int amdgpu_ttm_fw_reserve_vram_init(struct amdgpu_device *adev) struct ttm_operation_ctx ctx = { false, false }; int r = 0; int i; - u64 vram_size = adev->mc.visible_vram_size; + u64 vram_size = adev->gmc.visible_vram_size; u64 offset = adev->fw_vram_usage.start_offset; u64 size = adev->fw_vram_usage.size; struct amdgpu_bo *bo; @@ -1312,7 +1309,7 @@ static int amdgpu_ttm_fw_reserve_vram_init(struct amdgpu_device *adev) r = amdgpu_bo_create(adev, adev->fw_vram_usage.size, PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | - AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS, NULL, NULL, 0, + AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS, NULL, NULL, &adev->fw_vram_usage.reserved_bo); if (r) goto error_create; @@ -1387,8 +1384,12 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) return r; } adev->mman.initialized = true; + + /* We opt to avoid OOM on system pages allocations */ + adev->mman.bdev.no_retry = true; + r = ttm_bo_init_mm(&adev->mman.bdev, TTM_PL_VRAM, - adev->mc.real_vram_size >> PAGE_SHIFT); + adev->gmc.real_vram_size >> PAGE_SHIFT); if (r) { DRM_ERROR("Failed initializing VRAM heap.\n"); return r; @@ -1397,11 +1398,11 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) /* Reduce size of CPU-visible VRAM if requested */ vis_vram_limit = (u64)amdgpu_vis_vram_limit * 1024 * 1024; if (amdgpu_vis_vram_limit > 0 && - vis_vram_limit <= adev->mc.visible_vram_size) - adev->mc.visible_vram_size = vis_vram_limit; + vis_vram_limit <= adev->gmc.visible_vram_size) + adev->gmc.visible_vram_size = vis_vram_limit; /* Change the size here instead of the init above so only lpfn is affected */ - amdgpu_ttm_set_active_vram_size(adev, adev->mc.visible_vram_size); + amdgpu_ttm_set_active_vram_size(adev, adev->gmc.visible_vram_size); /* *The reserved vram for firmware must be pinned to the specified @@ -1412,21 +1413,21 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) return r; } - r = amdgpu_bo_create_kernel(adev, adev->mc.stolen_size, PAGE_SIZE, + r = amdgpu_bo_create_kernel(adev, adev->gmc.stolen_size, PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, &adev->stolen_vga_memory, NULL, NULL); if (r) return r; DRM_INFO("amdgpu: %uM of VRAM memory ready\n", - (unsigned) (adev->mc.real_vram_size / (1024 * 1024))); + (unsigned) (adev->gmc.real_vram_size / (1024 * 1024))); if (amdgpu_gtt_size == -1) { struct sysinfo si; si_meminfo(&si); gtt_size = min(max((AMDGPU_DEFAULT_GTT_SIZE_MB << 20), - adev->mc.mc_vram_size), + adev->gmc.mc_vram_size), ((uint64_t)si.totalram * si.mem_unit * 3/4)); } else @@ -1559,7 +1560,7 @@ static int amdgpu_map_buffer(struct ttm_buffer_object *bo, BUG_ON(adev->mman.buffer_funcs->copy_max_bytes < AMDGPU_GTT_MAX_TRANSFER_SIZE * 8); - *addr = adev->mc.gart_start; + *addr = adev->gmc.gart_start; *addr += (u64)window * AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GPU_PAGE_SIZE; @@ -1677,13 +1678,12 @@ error_free: } int amdgpu_fill_buffer(struct amdgpu_bo *bo, - uint64_t src_data, + uint32_t src_data, struct reservation_object *resv, struct dma_fence **fence) { struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); - uint32_t max_bytes = 8 * - adev->vm_manager.vm_pte_funcs->set_max_nums_pte_pde; + uint32_t max_bytes = adev->mman.buffer_funcs->fill_max_bytes; struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring; struct drm_mm_node *mm_node; @@ -1714,9 +1714,7 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo, num_pages -= mm_node->size; ++mm_node; } - - /* num of dwords for each SDMA_OP_PTEPDE cmd */ - num_dw = num_loops * adev->vm_manager.vm_pte_funcs->set_pte_pde_num_dw; + num_dw = num_loops * adev->mman.buffer_funcs->fill_num_dw; /* for IB padding */ num_dw += 64; @@ -1741,16 +1739,12 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo, uint32_t byte_count = mm_node->size << PAGE_SHIFT; uint64_t dst_addr; - WARN_ONCE(byte_count & 0x7, "size should be a multiple of 8"); - dst_addr = amdgpu_mm_node_addr(&bo->tbo, mm_node, &bo->tbo.mem); while (byte_count) { uint32_t cur_size_in_bytes = min(byte_count, max_bytes); - amdgpu_vm_set_pte_pde(adev, &job->ibs[0], - dst_addr, 0, - cur_size_in_bytes >> 3, 0, - src_data); + amdgpu_emit_fill_buffer(adev, &job->ibs[0], src_data, + dst_addr, cur_size_in_bytes); dst_addr += cur_size_in_bytes; byte_count -= cur_size_in_bytes; @@ -1811,14 +1805,14 @@ static ssize_t amdgpu_ttm_vram_read(struct file *f, char __user *buf, if (size & 0x3 || *pos & 0x3) return -EINVAL; - if (*pos >= adev->mc.mc_vram_size) + if (*pos >= adev->gmc.mc_vram_size) return -ENXIO; while (size) { unsigned long flags; uint32_t value; - if (*pos >= adev->mc.mc_vram_size) + if (*pos >= adev->gmc.mc_vram_size) return result; spin_lock_irqsave(&adev->mmio_idx_lock, flags); @@ -1850,14 +1844,14 @@ static ssize_t amdgpu_ttm_vram_write(struct file *f, const char __user *buf, if (size & 0x3 || *pos & 0x3) return -EINVAL; - if (*pos >= adev->mc.mc_vram_size) + if (*pos >= adev->gmc.mc_vram_size) return -ENXIO; while (size) { unsigned long flags; uint32_t value; - if (*pos >= adev->mc.mc_vram_size) + if (*pos >= adev->gmc.mc_vram_size) return result; r = get_user(value, (uint32_t *)buf); @@ -2001,16 +1995,16 @@ static int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev) if (IS_ERR(ent)) return PTR_ERR(ent); if (ttm_debugfs_entries[count].domain == TTM_PL_VRAM) - i_size_write(ent->d_inode, adev->mc.mc_vram_size); + i_size_write(ent->d_inode, adev->gmc.mc_vram_size); else if (ttm_debugfs_entries[count].domain == TTM_PL_TT) - i_size_write(ent->d_inode, adev->mc.gart_size); + i_size_write(ent->d_inode, adev->gmc.gart_size); adev->mman.debugfs_entries[count] = ent; } count = ARRAY_SIZE(amdgpu_ttm_debugfs_list); #ifdef CONFIG_SWIOTLB - if (!swiotlb_nr_tbl()) + if (!(adev->need_swiotlb && swiotlb_nr_tbl())) --count; #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index 167856f6080f..1e275c7b006b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -86,7 +86,7 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev, struct reservation_object *resv, struct dma_fence **f); int amdgpu_fill_buffer(struct amdgpu_bo *bo, - uint64_t src_data, + uint32_t src_data, struct reservation_object *resv, struct dma_fence **fence); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index b2eae86bf906..9cd5517a4fa9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -952,37 +952,28 @@ int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser, uint32_t ib_idx) static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo, bool direct, struct dma_fence **fence) { - struct ttm_operation_ctx ctx = { true, false }; - struct ttm_validate_buffer tv; - struct ww_acquire_ctx ticket; - struct list_head head; + struct amdgpu_device *adev = ring->adev; + struct dma_fence *f = NULL; struct amdgpu_job *job; struct amdgpu_ib *ib; - struct dma_fence *f = NULL; - struct amdgpu_device *adev = ring->adev; - uint64_t addr; uint32_t data[4]; - int i, r; + uint64_t addr; + long r; + int i; - memset(&tv, 0, sizeof(tv)); - tv.bo = &bo->tbo; - - INIT_LIST_HEAD(&head); - list_add(&tv.head, &head); - - r = ttm_eu_reserve_buffers(&ticket, &head, true, NULL); - if (r) - return r; + amdgpu_bo_kunmap(bo); + amdgpu_bo_unpin(bo); if (!ring->adev->uvd.address_64_bit) { + struct ttm_operation_ctx ctx = { true, false }; + amdgpu_ttm_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_VRAM); amdgpu_uvd_force_into_uvd_segment(bo); + r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); + if (r) + goto err; } - r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); - if (r) - goto err; - r = amdgpu_job_alloc_with_ib(adev, 64, &job); if (r) goto err; @@ -1014,6 +1005,14 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo, ib->length_dw = 16; if (direct) { + r = reservation_object_wait_timeout_rcu(bo->tbo.resv, + true, false, + msecs_to_jiffies(10)); + if (r == 0) + r = -ETIMEDOUT; + if (r < 0) + goto err_free; + r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); job->fence = dma_fence_get(f); if (r) @@ -1021,17 +1020,23 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo, amdgpu_job_free(job); } else { + r = amdgpu_sync_resv(adev, &job->sync, bo->tbo.resv, + AMDGPU_FENCE_OWNER_UNDEFINED, false); + if (r) + goto err_free; + r = amdgpu_job_submit(job, ring, &adev->uvd.entity, AMDGPU_FENCE_OWNER_UNDEFINED, &f); if (r) goto err_free; } - ttm_eu_fence_buffer_objects(&ticket, &head, f); + amdgpu_bo_fence(bo, f, false); + amdgpu_bo_unreserve(bo); + amdgpu_bo_unref(&bo); if (fence) *fence = dma_fence_get(f); - amdgpu_bo_unref(&bo); dma_fence_put(f); return 0; @@ -1040,7 +1045,8 @@ err_free: amdgpu_job_free(job); err: - ttm_eu_backoff_reservation(&ticket, &head); + amdgpu_bo_unreserve(bo); + amdgpu_bo_unref(&bo); return r; } @@ -1051,31 +1057,16 @@ int amdgpu_uvd_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, struct dma_fence **fence) { struct amdgpu_device *adev = ring->adev; - struct amdgpu_bo *bo; + struct amdgpu_bo *bo = NULL; uint32_t *msg; int r, i; - r = amdgpu_bo_create(adev, 1024, PAGE_SIZE, true, - AMDGPU_GEM_DOMAIN_VRAM, - AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | - AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS, - NULL, NULL, 0, &bo); + r = amdgpu_bo_create_reserved(adev, 1024, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &bo, NULL, (void **)&msg); if (r) return r; - r = amdgpu_bo_reserve(bo, false); - if (r) { - amdgpu_bo_unref(&bo); - return r; - } - - r = amdgpu_bo_kmap(bo, (void **)&msg); - if (r) { - amdgpu_bo_unreserve(bo); - amdgpu_bo_unref(&bo); - return r; - } - /* stitch together an UVD create msg */ msg[0] = cpu_to_le32(0x00000de4); msg[1] = cpu_to_le32(0x00000000); @@ -1091,9 +1082,6 @@ int amdgpu_uvd_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, for (i = 11; i < 1024; ++i) msg[i] = cpu_to_le32(0x0); - amdgpu_bo_kunmap(bo); - amdgpu_bo_unreserve(bo); - return amdgpu_uvd_send_msg(ring, bo, true, fence); } @@ -1101,31 +1089,16 @@ int amdgpu_uvd_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, bool direct, struct dma_fence **fence) { struct amdgpu_device *adev = ring->adev; - struct amdgpu_bo *bo; + struct amdgpu_bo *bo = NULL; uint32_t *msg; int r, i; - r = amdgpu_bo_create(adev, 1024, PAGE_SIZE, true, - AMDGPU_GEM_DOMAIN_VRAM, - AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | - AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS, - NULL, NULL, 0, &bo); + r = amdgpu_bo_create_reserved(adev, 1024, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &bo, NULL, (void **)&msg); if (r) return r; - r = amdgpu_bo_reserve(bo, false); - if (r) { - amdgpu_bo_unref(&bo); - return r; - } - - r = amdgpu_bo_kmap(bo, (void **)&msg); - if (r) { - amdgpu_bo_unreserve(bo); - amdgpu_bo_unref(&bo); - return r; - } - /* stitch together an UVD destroy msg */ msg[0] = cpu_to_le32(0x00000de4); msg[1] = cpu_to_le32(0x00000002); @@ -1134,9 +1107,6 @@ int amdgpu_uvd_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, for (i = 4; i < 1024; ++i) msg[i] = cpu_to_le32(0x0); - amdgpu_bo_kunmap(bo); - amdgpu_bo_unreserve(bo); - return amdgpu_uvd_send_msg(ring, bo, direct, fence); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h index 0fd378ae92c3..71781267ee4c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h @@ -30,6 +30,8 @@ #define AMDGPU_VCE_HARVEST_VCE0 (1 << 0) #define AMDGPU_VCE_HARVEST_VCE1 (1 << 1) +#define AMDGPU_VCE_FW_53_45 ((53 << 24) | (45 << 16)) + struct amdgpu_vce { struct amdgpu_bo *vcpu_bo; uint64_t gpu_addr; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index 837962118dbc..58e495330b38 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -270,34 +270,17 @@ int amdgpu_vcn_dec_ring_test_ring(struct amdgpu_ring *ring) return r; } -static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo, - bool direct, struct dma_fence **fence) +static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring, + struct amdgpu_bo *bo, bool direct, + struct dma_fence **fence) { - struct ttm_operation_ctx ctx = { true, false }; - struct ttm_validate_buffer tv; - struct ww_acquire_ctx ticket; - struct list_head head; + struct amdgpu_device *adev = ring->adev; + struct dma_fence *f = NULL; struct amdgpu_job *job; struct amdgpu_ib *ib; - struct dma_fence *f = NULL; - struct amdgpu_device *adev = ring->adev; uint64_t addr; int i, r; - memset(&tv, 0, sizeof(tv)); - tv.bo = &bo->tbo; - - INIT_LIST_HEAD(&head); - list_add(&tv.head, &head); - - r = ttm_eu_reserve_buffers(&ticket, &head, true, NULL); - if (r) - return r; - - r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); - if (r) - goto err; - r = amdgpu_job_alloc_with_ib(adev, 64, &job); if (r) goto err; @@ -330,11 +313,12 @@ static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *b goto err_free; } - ttm_eu_fence_buffer_objects(&ticket, &head, f); + amdgpu_bo_fence(bo, f, false); + amdgpu_bo_unreserve(bo); + amdgpu_bo_unref(&bo); if (fence) *fence = dma_fence_get(f); - amdgpu_bo_unref(&bo); dma_fence_put(f); return 0; @@ -343,7 +327,8 @@ err_free: amdgpu_job_free(job); err: - ttm_eu_backoff_reservation(&ticket, &head); + amdgpu_bo_unreserve(bo); + amdgpu_bo_unref(&bo); return r; } @@ -351,31 +336,16 @@ static int amdgpu_vcn_dec_get_create_msg(struct amdgpu_ring *ring, uint32_t hand struct dma_fence **fence) { struct amdgpu_device *adev = ring->adev; - struct amdgpu_bo *bo; + struct amdgpu_bo *bo = NULL; uint32_t *msg; int r, i; - r = amdgpu_bo_create(adev, 1024, PAGE_SIZE, true, - AMDGPU_GEM_DOMAIN_VRAM, - AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | - AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS, - NULL, NULL, 0, &bo); + r = amdgpu_bo_create_reserved(adev, 1024, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &bo, NULL, (void **)&msg); if (r) return r; - r = amdgpu_bo_reserve(bo, false); - if (r) { - amdgpu_bo_unref(&bo); - return r; - } - - r = amdgpu_bo_kmap(bo, (void **)&msg); - if (r) { - amdgpu_bo_unreserve(bo); - amdgpu_bo_unref(&bo); - return r; - } - msg[0] = cpu_to_le32(0x00000028); msg[1] = cpu_to_le32(0x00000038); msg[2] = cpu_to_le32(0x00000001); @@ -393,9 +363,6 @@ static int amdgpu_vcn_dec_get_create_msg(struct amdgpu_ring *ring, uint32_t hand for (i = 14; i < 1024; ++i) msg[i] = cpu_to_le32(0x0); - amdgpu_bo_kunmap(bo); - amdgpu_bo_unreserve(bo); - return amdgpu_vcn_dec_send_msg(ring, bo, true, fence); } @@ -403,31 +370,16 @@ static int amdgpu_vcn_dec_get_destroy_msg(struct amdgpu_ring *ring, uint32_t han bool direct, struct dma_fence **fence) { struct amdgpu_device *adev = ring->adev; - struct amdgpu_bo *bo; + struct amdgpu_bo *bo = NULL; uint32_t *msg; int r, i; - r = amdgpu_bo_create(adev, 1024, PAGE_SIZE, true, - AMDGPU_GEM_DOMAIN_VRAM, - AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | - AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS, - NULL, NULL, 0, &bo); + r = amdgpu_bo_create_reserved(adev, 1024, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &bo, NULL, (void **)&msg); if (r) return r; - r = amdgpu_bo_reserve(bo, false); - if (r) { - amdgpu_bo_unref(&bo); - return r; - } - - r = amdgpu_bo_kmap(bo, (void **)&msg); - if (r) { - amdgpu_bo_unreserve(bo); - amdgpu_bo_unref(&bo); - return r; - } - msg[0] = cpu_to_le32(0x00000028); msg[1] = cpu_to_le32(0x00000018); msg[2] = cpu_to_le32(0x00000000); @@ -437,9 +389,6 @@ static int amdgpu_vcn_dec_get_destroy_msg(struct amdgpu_ring *ring, uint32_t han for (i = 6; i < 1024; ++i) msg[i] = cpu_to_le32(0x0); - amdgpu_bo_kunmap(bo); - amdgpu_bo_unreserve(bo); - return amdgpu_vcn_dec_send_msg(ring, bo, direct, fence); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index e7dfb7b44b4b..b832651d2137 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -24,6 +24,18 @@ #include "amdgpu.h" #define MAX_KIQ_REG_WAIT 100000000 /* in usecs */ +uint64_t amdgpu_csa_vaddr(struct amdgpu_device *adev) +{ + uint64_t addr = adev->vm_manager.max_pfn << AMDGPU_GPU_PAGE_SHIFT; + + addr -= AMDGPU_VA_RESERVED_SIZE; + + if (addr >= AMDGPU_VA_HOLE_START) + addr |= AMDGPU_VA_HOLE_END; + + return addr; +} + bool amdgpu_virt_mmio_blocked(struct amdgpu_device *adev) { /* By now all MMIO pages except mailbox are blocked */ @@ -55,14 +67,14 @@ void amdgpu_free_static_csa(struct amdgpu_device *adev) { /* * amdgpu_map_static_csa should be called during amdgpu_vm_init - * it maps virtual address "AMDGPU_VA_RESERVED_SIZE - AMDGPU_CSA_SIZE" - * to this VM, and each command submission of GFX should use this virtual - * address within META_DATA init package to support SRIOV gfx preemption. + * it maps virtual address amdgpu_csa_vaddr() to this VM, and each command + * submission of GFX should use this virtual address within META_DATA init + * package to support SRIOV gfx preemption. */ - int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct amdgpu_bo_va **bo_va) { + uint64_t csa_addr = amdgpu_csa_vaddr(adev) & AMDGPU_VA_HOLE_MASK; struct ww_acquire_ctx ticket; struct list_head list; struct amdgpu_bo_list_entry pd; @@ -90,7 +102,7 @@ int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm, return -ENOMEM; } - r = amdgpu_vm_alloc_pts(adev, (*bo_va)->base.vm, AMDGPU_CSA_VADDR, + r = amdgpu_vm_alloc_pts(adev, (*bo_va)->base.vm, csa_addr, AMDGPU_CSA_SIZE); if (r) { DRM_ERROR("failed to allocate pts for static CSA, err=%d\n", r); @@ -99,7 +111,7 @@ int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm, return r; } - r = amdgpu_vm_bo_map(adev, *bo_va, AMDGPU_CSA_VADDR, 0, AMDGPU_CSA_SIZE, + r = amdgpu_vm_bo_map(adev, *bo_va, csa_addr, 0, AMDGPU_CSA_SIZE, AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE | AMDGPU_PTE_EXECUTABLE); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h index 6a83425aa9ed..880ac113a3a9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h @@ -251,8 +251,7 @@ struct amdgpu_virt { uint32_t gim_feature; }; -#define AMDGPU_CSA_SIZE (8 * 1024) -#define AMDGPU_CSA_VADDR (AMDGPU_VA_RESERVED_SIZE - AMDGPU_CSA_SIZE) +#define AMDGPU_CSA_SIZE (8 * 1024) #define amdgpu_sriov_enabled(adev) \ ((adev)->virt.caps & AMDGPU_SRIOV_CAPS_ENABLE_IOV) @@ -279,6 +278,8 @@ static inline bool is_virtual_machine(void) } struct amdgpu_vm; + +uint64_t amdgpu_csa_vaddr(struct amdgpu_device *adev); bool amdgpu_virt_mmio_blocked(struct amdgpu_device *adev); int amdgpu_allocate_static_csa(struct amdgpu_device *adev); int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 6fc16eecf2dc..0b237e027cab 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -75,7 +75,8 @@ struct amdgpu_pte_update_params { /* indirect buffer to fill with commands */ struct amdgpu_ib *ib; /* Function which actually does the update */ - void (*func)(struct amdgpu_pte_update_params *params, uint64_t pe, + void (*func)(struct amdgpu_pte_update_params *params, + struct amdgpu_bo *bo, uint64_t pe, uint64_t addr, unsigned count, uint32_t incr, uint64_t flags); /* The next two are used during VM update by CPU @@ -256,6 +257,104 @@ bool amdgpu_vm_ready(struct amdgpu_vm *vm) return ready; } +/** + * amdgpu_vm_clear_bo - initially clear the PDs/PTs + * + * @adev: amdgpu_device pointer + * @bo: BO to clear + * @level: level this BO is at + * + * Root PD needs to be reserved when calling this. + */ +static int amdgpu_vm_clear_bo(struct amdgpu_device *adev, + struct amdgpu_vm *vm, struct amdgpu_bo *bo, + unsigned level, bool pte_support_ats) +{ + struct ttm_operation_ctx ctx = { true, false }; + struct dma_fence *fence = NULL; + unsigned entries, ats_entries; + struct amdgpu_ring *ring; + struct amdgpu_job *job; + uint64_t addr; + int r; + + addr = amdgpu_bo_gpu_offset(bo); + entries = amdgpu_bo_size(bo) / 8; + + if (pte_support_ats) { + if (level == adev->vm_manager.root_level) { + ats_entries = amdgpu_vm_level_shift(adev, level); + ats_entries += AMDGPU_GPU_PAGE_SHIFT; + ats_entries = AMDGPU_VA_HOLE_START >> ats_entries; + ats_entries = min(ats_entries, entries); + entries -= ats_entries; + } else { + ats_entries = entries; + entries = 0; + } + } else { + ats_entries = 0; + } + + ring = container_of(vm->entity.sched, struct amdgpu_ring, sched); + + r = reservation_object_reserve_shared(bo->tbo.resv); + if (r) + return r; + + r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); + if (r) + goto error; + + r = amdgpu_job_alloc_with_ib(adev, 64, &job); + if (r) + goto error; + + if (ats_entries) { + uint64_t ats_value; + + ats_value = AMDGPU_PTE_DEFAULT_ATC; + if (level != AMDGPU_VM_PTB) + ats_value |= AMDGPU_PDE_PTE; + + amdgpu_vm_set_pte_pde(adev, &job->ibs[0], addr, 0, + ats_entries, 0, ats_value); + addr += ats_entries * 8; + } + + if (entries) + amdgpu_vm_set_pte_pde(adev, &job->ibs[0], addr, 0, + entries, 0, 0); + + amdgpu_ring_pad_ib(ring, &job->ibs[0]); + + WARN_ON(job->ibs[0].length_dw > 64); + r = amdgpu_sync_resv(adev, &job->sync, bo->tbo.resv, + AMDGPU_FENCE_OWNER_UNDEFINED, false); + if (r) + goto error_free; + + r = amdgpu_job_submit(job, ring, &vm->entity, + AMDGPU_FENCE_OWNER_UNDEFINED, &fence); + if (r) + goto error_free; + + amdgpu_bo_fence(bo, fence, true); + dma_fence_put(fence); + + if (bo->shadow) + return amdgpu_vm_clear_bo(adev, vm, bo->shadow, + level, pte_support_ats); + + return 0; + +error_free: + amdgpu_job_free(job); + +error: + return r; +} + /** * amdgpu_vm_alloc_levels - allocate the PD/PT levels * @@ -270,13 +369,12 @@ static int amdgpu_vm_alloc_levels(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct amdgpu_vm_pt *parent, uint64_t saddr, uint64_t eaddr, - unsigned level) + unsigned level, bool ats) { unsigned shift = amdgpu_vm_level_shift(adev, level); unsigned pt_idx, from, to; - int r; u64 flags; - uint64_t init_value = 0; + int r; if (!parent->entries) { unsigned num_entries = amdgpu_vm_num_entries(adev, level); @@ -299,21 +397,13 @@ static int amdgpu_vm_alloc_levels(struct amdgpu_device *adev, saddr = saddr & ((1 << shift) - 1); eaddr = eaddr & ((1 << shift) - 1); - flags = AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS | - AMDGPU_GEM_CREATE_VRAM_CLEARED; + flags = AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; if (vm->use_cpu_for_update) flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; else flags |= (AMDGPU_GEM_CREATE_NO_CPU_ACCESS | AMDGPU_GEM_CREATE_SHADOW); - if (vm->pte_support_ats) { - init_value = AMDGPU_PTE_DEFAULT_ATC; - if (level != AMDGPU_VM_PTB) - init_value |= AMDGPU_PDE_PTE; - - } - /* walk over the address space and allocate the page tables */ for (pt_idx = from; pt_idx <= to; ++pt_idx) { struct reservation_object *resv = vm->root.base.bo->tbo.resv; @@ -324,15 +414,22 @@ static int amdgpu_vm_alloc_levels(struct amdgpu_device *adev, r = amdgpu_bo_create(adev, amdgpu_vm_bo_size(adev, level), AMDGPU_GPU_PAGE_SIZE, true, - AMDGPU_GEM_DOMAIN_VRAM, - flags, - NULL, resv, init_value, &pt); + AMDGPU_GEM_DOMAIN_VRAM, flags, + NULL, resv, &pt); if (r) return r; + r = amdgpu_vm_clear_bo(adev, vm, pt, level, ats); + if (r) { + amdgpu_bo_unref(&pt->shadow); + amdgpu_bo_unref(&pt); + return r; + } + if (vm->use_cpu_for_update) { r = amdgpu_bo_kmap(pt, NULL); if (r) { + amdgpu_bo_unref(&pt->shadow); amdgpu_bo_unref(&pt); return r; } @@ -356,7 +453,7 @@ static int amdgpu_vm_alloc_levels(struct amdgpu_device *adev, uint64_t sub_eaddr = (pt_idx == to) ? eaddr : ((1 << shift) - 1); r = amdgpu_vm_alloc_levels(adev, vm, entry, sub_saddr, - sub_eaddr, level); + sub_eaddr, level, ats); if (r) return r; } @@ -379,26 +476,29 @@ int amdgpu_vm_alloc_pts(struct amdgpu_device *adev, struct amdgpu_vm *vm, uint64_t saddr, uint64_t size) { - uint64_t last_pfn; uint64_t eaddr; + bool ats = false; /* validate the parameters */ if (saddr & AMDGPU_GPU_PAGE_MASK || size & AMDGPU_GPU_PAGE_MASK) return -EINVAL; eaddr = saddr + size - 1; - last_pfn = eaddr / AMDGPU_GPU_PAGE_SIZE; - if (last_pfn >= adev->vm_manager.max_pfn) { - dev_err(adev->dev, "va above limit (0x%08llX >= 0x%08llX)\n", - last_pfn, adev->vm_manager.max_pfn); - return -EINVAL; - } + + if (vm->pte_support_ats) + ats = saddr < AMDGPU_VA_HOLE_START; saddr /= AMDGPU_GPU_PAGE_SIZE; eaddr /= AMDGPU_GPU_PAGE_SIZE; + if (eaddr >= adev->vm_manager.max_pfn) { + dev_err(adev->dev, "va above limit (0x%08llX >= 0x%08llX)\n", + eaddr, adev->vm_manager.max_pfn); + return -EINVAL; + } + return amdgpu_vm_alloc_levels(adev, vm, &vm->root, saddr, eaddr, - adev->vm_manager.root_level); + adev->vm_manager.root_level, ats); } /** @@ -465,7 +565,7 @@ bool amdgpu_vm_need_pipeline_sync(struct amdgpu_ring *ring, static bool amdgpu_vm_is_large_bar(struct amdgpu_device *adev) { - return (adev->mc.real_vram_size == adev->mc.visible_vram_size); + return (adev->gmc.real_vram_size == adev->gmc.visible_vram_size); } /** @@ -491,14 +591,24 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool need_ id->oa_base != job->oa_base || id->oa_size != job->oa_size); bool vm_flush_needed = job->vm_needs_flush; + bool pasid_mapping_needed = id->pasid != job->pasid || + !id->pasid_mapping || + !dma_fence_is_signaled(id->pasid_mapping); + struct dma_fence *fence = NULL; unsigned patch_offset = 0; int r; if (amdgpu_vmid_had_gpu_reset(adev, id)) { gds_switch_needed = true; vm_flush_needed = true; + pasid_mapping_needed = true; } + gds_switch_needed &= !!ring->funcs->emit_gds_switch; + vm_flush_needed &= !!ring->funcs->emit_vm_flush; + pasid_mapping_needed &= adev->gmc.gmc_funcs->emit_pasid_mapping && + ring->funcs->emit_wreg; + if (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync) return 0; @@ -508,23 +618,36 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool need_ if (need_pipe_sync) amdgpu_ring_emit_pipeline_sync(ring); - if (ring->funcs->emit_vm_flush && vm_flush_needed) { - struct dma_fence *fence; - + if (vm_flush_needed) { trace_amdgpu_vm_flush(ring, job->vmid, job->vm_pd_addr); amdgpu_ring_emit_vm_flush(ring, job->vmid, job->vm_pd_addr); + } + if (pasid_mapping_needed) + amdgpu_gmc_emit_pasid_mapping(ring, job->vmid, job->pasid); + + if (vm_flush_needed || pasid_mapping_needed) { r = amdgpu_fence_emit(ring, &fence); if (r) return r; + } + if (vm_flush_needed) { mutex_lock(&id_mgr->lock); dma_fence_put(id->last_flush); - id->last_flush = fence; - id->current_gpu_reset_count = atomic_read(&adev->gpu_reset_counter); + id->last_flush = dma_fence_get(fence); + id->current_gpu_reset_count = + atomic_read(&adev->gpu_reset_counter); mutex_unlock(&id_mgr->lock); } + if (pasid_mapping_needed) { + id->pasid = job->pasid; + dma_fence_put(id->pasid_mapping); + id->pasid_mapping = dma_fence_get(fence); + } + dma_fence_put(fence); + if (ring->funcs->emit_gds_switch && gds_switch_needed) { id->gds_base = job->gds_base; id->gds_size = job->gds_size; @@ -578,6 +701,7 @@ struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm, * amdgpu_vm_do_set_ptes - helper to call the right asic function * * @params: see amdgpu_pte_update_params definition + * @bo: PD/PT to update * @pe: addr of the page entry * @addr: dst addr to write into pe * @count: number of page entries to update @@ -588,10 +712,12 @@ struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm, * to setup the page table using the DMA. */ static void amdgpu_vm_do_set_ptes(struct amdgpu_pte_update_params *params, + struct amdgpu_bo *bo, uint64_t pe, uint64_t addr, unsigned count, uint32_t incr, uint64_t flags) { + pe += amdgpu_bo_gpu_offset(bo); trace_amdgpu_vm_set_ptes(pe, addr, count, incr, flags); if (count < 3) { @@ -608,6 +734,7 @@ static void amdgpu_vm_do_set_ptes(struct amdgpu_pte_update_params *params, * amdgpu_vm_do_copy_ptes - copy the PTEs from the GART * * @params: see amdgpu_pte_update_params definition + * @bo: PD/PT to update * @pe: addr of the page entry * @addr: dst addr to write into pe * @count: number of page entries to update @@ -617,13 +744,14 @@ static void amdgpu_vm_do_set_ptes(struct amdgpu_pte_update_params *params, * Traces the parameters and calls the DMA function to copy the PTEs. */ static void amdgpu_vm_do_copy_ptes(struct amdgpu_pte_update_params *params, + struct amdgpu_bo *bo, uint64_t pe, uint64_t addr, unsigned count, uint32_t incr, uint64_t flags) { uint64_t src = (params->src + (addr >> 12) * 8); - + pe += amdgpu_bo_gpu_offset(bo); trace_amdgpu_vm_copy_ptes(pe, src, count); amdgpu_vm_copy_pte(params->adev, params->ib, pe, src, count); @@ -657,6 +785,7 @@ static uint64_t amdgpu_vm_map_gart(const dma_addr_t *pages_addr, uint64_t addr) * amdgpu_vm_cpu_set_ptes - helper to update page tables via CPU * * @params: see amdgpu_pte_update_params definition + * @bo: PD/PT to update * @pe: kmap addr of the page entry * @addr: dst addr to write into pe * @count: number of page entries to update @@ -666,6 +795,7 @@ static uint64_t amdgpu_vm_map_gart(const dma_addr_t *pages_addr, uint64_t addr) * Write count number of PT/PD entries directly. */ static void amdgpu_vm_cpu_set_ptes(struct amdgpu_pte_update_params *params, + struct amdgpu_bo *bo, uint64_t pe, uint64_t addr, unsigned count, uint32_t incr, uint64_t flags) @@ -673,14 +803,16 @@ static void amdgpu_vm_cpu_set_ptes(struct amdgpu_pte_update_params *params, unsigned int i; uint64_t value; + pe += (unsigned long)amdgpu_bo_kptr(bo); + trace_amdgpu_vm_set_ptes(pe, addr, count, incr, flags); for (i = 0; i < count; i++) { value = params->pages_addr ? amdgpu_vm_map_gart(params->pages_addr, addr) : addr; - amdgpu_gart_set_pte_pde(params->adev, (void *)(uintptr_t)pe, - i, value, flags); + amdgpu_gmc_set_pte_pde(params->adev, (void *)(uintptr_t)pe, + i, value, flags); addr += incr; } } @@ -714,8 +846,7 @@ static void amdgpu_vm_update_pde(struct amdgpu_pte_update_params *params, struct amdgpu_vm_pt *parent, struct amdgpu_vm_pt *entry) { - struct amdgpu_bo *bo = entry->base.bo, *shadow = NULL, *pbo; - uint64_t pd_addr, shadow_addr = 0; + struct amdgpu_bo *bo = parent->base.bo, *pbo; uint64_t pde, pt, flags; unsigned level; @@ -723,29 +854,17 @@ static void amdgpu_vm_update_pde(struct amdgpu_pte_update_params *params, if (entry->huge) return; - if (vm->use_cpu_for_update) { - pd_addr = (unsigned long)amdgpu_bo_kptr(parent->base.bo); - } else { - pd_addr = amdgpu_bo_gpu_offset(parent->base.bo); - shadow = parent->base.bo->shadow; - if (shadow) - shadow_addr = amdgpu_bo_gpu_offset(shadow); - } - - for (level = 0, pbo = parent->base.bo->parent; pbo; ++level) + for (level = 0, pbo = bo->parent; pbo; ++level) pbo = pbo->parent; level += params->adev->vm_manager.root_level; - pt = amdgpu_bo_gpu_offset(bo); + pt = amdgpu_bo_gpu_offset(entry->base.bo); flags = AMDGPU_PTE_VALID; - amdgpu_gart_get_vm_pde(params->adev, level, &pt, &flags); - if (shadow) { - pde = shadow_addr + (entry - parent->entries) * 8; - params->func(params, pde, pt, 1, 0, flags); - } - - pde = pd_addr + (entry - parent->entries) * 8; - params->func(params, pde, pt, 1, 0, flags); + amdgpu_gmc_get_vm_pde(params->adev, level, &pt, &flags); + pde = (entry - parent->entries) * 8; + if (bo->shadow) + params->func(params, bo->shadow, pde, pt, 1, 0, flags); + params->func(params, bo, pde, pt, 1, 0, flags); } /* @@ -856,7 +975,7 @@ restart: if (vm->use_cpu_for_update) { /* Flush HDP */ mb(); - amdgpu_gart_flush_gpu_tlb(adev, 0); + amdgpu_asic_flush_hdp(adev, NULL); } else if (params.ib->length_dw == 0) { amdgpu_job_free(job); } else { @@ -870,11 +989,6 @@ restart: amdgpu_ring_pad_ib(ring, params.ib); amdgpu_sync_resv(adev, &job->sync, root->tbo.resv, AMDGPU_FENCE_OWNER_VM, false); - if (root->shadow) - amdgpu_sync_resv(adev, &job->sync, - root->shadow->tbo.resv, - AMDGPU_FENCE_OWNER_VM, false); - WARN_ON(params.ib->length_dw > ndw); r = amdgpu_job_submit(job, ring, &vm->entity, AMDGPU_FENCE_OWNER_VM, &fence); @@ -946,7 +1060,7 @@ static void amdgpu_vm_handle_huge_pages(struct amdgpu_pte_update_params *p, unsigned nptes, uint64_t dst, uint64_t flags) { - uint64_t pd_addr, pde; + uint64_t pde; /* In the case of a mixed PT the PDE must point to it*/ if (p->adev->asic_type >= CHIP_VEGA10 && !p->src && @@ -967,21 +1081,12 @@ static void amdgpu_vm_handle_huge_pages(struct amdgpu_pte_update_params *p, } entry->huge = true; - amdgpu_gart_get_vm_pde(p->adev, AMDGPU_VM_PDB0, - &dst, &flags); + amdgpu_gmc_get_vm_pde(p->adev, AMDGPU_VM_PDB0, &dst, &flags); - if (p->func == amdgpu_vm_cpu_set_ptes) { - pd_addr = (unsigned long)amdgpu_bo_kptr(parent->base.bo); - } else { - if (parent->base.bo->shadow) { - pd_addr = amdgpu_bo_gpu_offset(parent->base.bo->shadow); - pde = pd_addr + (entry - parent->entries) * 8; - p->func(p, pde, dst, 1, 0, flags); - } - pd_addr = amdgpu_bo_gpu_offset(parent->base.bo); - } - pde = pd_addr + (entry - parent->entries) * 8; - p->func(p, pde, dst, 1, 0, flags); + pde = (entry - parent->entries) * 8; + if (parent->base.bo->shadow) + p->func(p, parent->base.bo->shadow, pde, dst, 1, 0, flags); + p->func(p, parent->base.bo, pde, dst, 1, 0, flags); } /** @@ -1007,7 +1112,6 @@ static int amdgpu_vm_update_ptes(struct amdgpu_pte_update_params *params, uint64_t addr, pe_start; struct amdgpu_bo *pt; unsigned nptes; - bool use_cpu_update = (params->func == amdgpu_vm_cpu_set_ptes); /* walk over the address space and update the page tables */ for (addr = start; addr < end; addr += nptes, @@ -1030,20 +1134,11 @@ static int amdgpu_vm_update_ptes(struct amdgpu_pte_update_params *params, continue; pt = entry->base.bo; - if (use_cpu_update) { - pe_start = (unsigned long)amdgpu_bo_kptr(pt); - } else { - if (pt->shadow) { - pe_start = amdgpu_bo_gpu_offset(pt->shadow); - pe_start += (addr & mask) * 8; - params->func(params, pe_start, dst, nptes, - AMDGPU_GPU_PAGE_SIZE, flags); - } - pe_start = amdgpu_bo_gpu_offset(pt); - } - - pe_start += (addr & mask) * 8; - params->func(params, pe_start, dst, nptes, + pe_start = (addr & mask) * 8; + if (pt->shadow) + params->func(params, pt->shadow, pe_start, dst, nptes, + AMDGPU_GPU_PAGE_SIZE, flags); + params->func(params, pt, pe_start, dst, nptes, AMDGPU_GPU_PAGE_SIZE, flags); } @@ -1204,11 +1299,10 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev, } else { /* set page commands needed */ - ndw += ncmds * adev->vm_manager.vm_pte_funcs->set_pte_pde_num_dw; + ndw += ncmds * 10; /* extra commands for begin/end fragments */ - ndw += 2 * adev->vm_manager.vm_pte_funcs->set_pte_pde_num_dw - * adev->vm_manager.fragment_size; + ndw += 2 * 10 * adev->vm_manager.fragment_size; params.func = amdgpu_vm_do_set_ptes; } @@ -1457,7 +1551,7 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, if (vm->use_cpu_for_update) { /* Flush HDP */ mb(); - amdgpu_gart_flush_gpu_tlb(adev, 0); + amdgpu_asic_flush_hdp(adev, NULL); } spin_lock(&vm->status_lock); @@ -1485,7 +1579,7 @@ static void amdgpu_vm_update_prt_state(struct amdgpu_device *adev) spin_lock_irqsave(&adev->vm_manager.prt_lock, flags); enable = !!atomic_read(&adev->vm_manager.num_prt_users); - adev->gart.gart_funcs->set_prt(adev, enable); + adev->gmc.gmc_funcs->set_prt(adev, enable); spin_unlock_irqrestore(&adev->vm_manager.prt_lock, flags); } @@ -1494,7 +1588,7 @@ static void amdgpu_vm_update_prt_state(struct amdgpu_device *adev) */ static void amdgpu_vm_prt_get(struct amdgpu_device *adev) { - if (!adev->gart.gart_funcs->set_prt) + if (!adev->gmc.gmc_funcs->set_prt) return; if (atomic_inc_return(&adev->vm_manager.num_prt_users) == 1) @@ -1529,7 +1623,7 @@ static void amdgpu_vm_add_prt_cb(struct amdgpu_device *adev, { struct amdgpu_prt_cb *cb; - if (!adev->gart.gart_funcs->set_prt) + if (!adev->gmc.gmc_funcs->set_prt) return; cb = kmalloc(sizeof(struct amdgpu_prt_cb), GFP_KERNEL); @@ -1623,16 +1717,16 @@ int amdgpu_vm_clear_freed(struct amdgpu_device *adev, struct dma_fence **fence) { struct amdgpu_bo_va_mapping *mapping; + uint64_t init_pte_value = 0; struct dma_fence *f = NULL; int r; - uint64_t init_pte_value = 0; while (!list_empty(&vm->freed)) { mapping = list_first_entry(&vm->freed, struct amdgpu_bo_va_mapping, list); list_del(&mapping->list); - if (vm->pte_support_ats) + if (vm->pte_support_ats && mapping->start < AMDGPU_VA_HOLE_START) init_pte_value = AMDGPU_PTE_DEFAULT_ATC; r = amdgpu_vm_bo_update_mapping(adev, NULL, NULL, vm, @@ -2265,9 +2359,9 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, unsigned ring_instance; struct amdgpu_ring *ring; struct drm_sched_rq *rq; + unsigned long size; + uint64_t flags; int r, i; - u64 flags; - uint64_t init_pde_value = 0; vm->va = RB_ROOT_CACHED; for (i = 0; i < AMDGPU_MAX_VMHUBS; i++) @@ -2295,52 +2389,45 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, vm->use_cpu_for_update = !!(adev->vm_manager.vm_update_mode & AMDGPU_VM_USE_CPU_FOR_COMPUTE); - if (adev->asic_type == CHIP_RAVEN) { + if (adev->asic_type == CHIP_RAVEN) vm->pte_support_ats = true; - init_pde_value = AMDGPU_PTE_DEFAULT_ATC - | AMDGPU_PDE_PTE; - - } - } else + } else { vm->use_cpu_for_update = !!(adev->vm_manager.vm_update_mode & AMDGPU_VM_USE_CPU_FOR_GFX); + } DRM_DEBUG_DRIVER("VM update mode is %s\n", vm->use_cpu_for_update ? "CPU" : "SDMA"); WARN_ONCE((vm->use_cpu_for_update & !amdgpu_vm_is_large_bar(adev)), "CPU update of VM recommended only for large BAR system\n"); vm->last_update = NULL; - flags = AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS | - AMDGPU_GEM_CREATE_VRAM_CLEARED; + flags = AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; if (vm->use_cpu_for_update) flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; else flags |= (AMDGPU_GEM_CREATE_NO_CPU_ACCESS | AMDGPU_GEM_CREATE_SHADOW); - r = amdgpu_bo_create(adev, - amdgpu_vm_bo_size(adev, adev->vm_manager.root_level), - align, true, - AMDGPU_GEM_DOMAIN_VRAM, - flags, - NULL, NULL, init_pde_value, &vm->root.base.bo); + size = amdgpu_vm_bo_size(adev, adev->vm_manager.root_level); + r = amdgpu_bo_create(adev, size, align, true, AMDGPU_GEM_DOMAIN_VRAM, + flags, NULL, NULL, &vm->root.base.bo); if (r) goto error_free_sched_entity; + r = amdgpu_bo_reserve(vm->root.base.bo, true); + if (r) + goto error_free_root; + + r = amdgpu_vm_clear_bo(adev, vm, vm->root.base.bo, + adev->vm_manager.root_level, + vm->pte_support_ats); + if (r) + goto error_unreserve; + vm->root.base.vm = vm; list_add_tail(&vm->root.base.bo_list, &vm->root.base.bo->va); - INIT_LIST_HEAD(&vm->root.base.vm_status); - - if (vm->use_cpu_for_update) { - r = amdgpu_bo_reserve(vm->root.base.bo, false); - if (r) - goto error_free_root; - - r = amdgpu_bo_kmap(vm->root.base.bo, NULL); - amdgpu_bo_unreserve(vm->root.base.bo); - if (r) - goto error_free_root; - } + list_add_tail(&vm->root.base.vm_status, &vm->evicted); + amdgpu_bo_unreserve(vm->root.base.bo); if (pasid) { unsigned long flags; @@ -2360,6 +2447,9 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, return 0; +error_unreserve: + amdgpu_bo_unreserve(vm->root.base.bo); + error_free_root: amdgpu_bo_unref(&vm->root.base.bo->shadow); amdgpu_bo_unref(&vm->root.base.bo); @@ -2413,7 +2503,7 @@ static void amdgpu_vm_free_levels(struct amdgpu_device *adev, void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) { struct amdgpu_bo_va_mapping *mapping, *tmp; - bool prt_fini_needed = !!adev->gart.gart_funcs->set_prt; + bool prt_fini_needed = !!adev->gmc.gmc_funcs->set_prt; struct amdgpu_bo *root; u64 fault; int i, r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index 21a80f1bb2b9..fabf44b262be 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -99,7 +99,7 @@ struct amdgpu_bo_list_entry; #define AMDGPU_MMHUB 1 /* hardcode that limit for now */ -#define AMDGPU_VA_RESERVED_SIZE (8ULL << 20) +#define AMDGPU_VA_RESERVED_SIZE (1ULL << 20) /* VA hole for 48bit addresses on Vega10 */ #define AMDGPU_VA_HOLE_START 0x0000800000000000ULL diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index 4acca92f6a52..9aca653bec07 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -89,11 +89,11 @@ static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev, uint64_t start = node->start << PAGE_SHIFT; uint64_t end = (node->size + node->start) << PAGE_SHIFT; - if (start >= adev->mc.visible_vram_size) + if (start >= adev->gmc.visible_vram_size) return 0; - return (end > adev->mc.visible_vram_size ? - adev->mc.visible_vram_size : end) - start; + return (end > adev->gmc.visible_vram_size ? + adev->gmc.visible_vram_size : end) - start; } /** diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c index a0943aa8d1d3..f82f40fb3bea 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c @@ -905,7 +905,7 @@ static bool ci_dpm_vblank_too_short(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 vblank_time = amdgpu_dpm_get_vblank_time(adev); - u32 switch_limit = adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 300; + u32 switch_limit = adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 300; /* disable mclk switching if the refresh is >120Hz, even if the * blanking period would allow it @@ -2954,7 +2954,7 @@ static int ci_calculate_mclk_params(struct amdgpu_device *adev, mpll_ad_func_cntl &= ~MPLL_AD_FUNC_CNTL__YCLK_POST_DIV_MASK; mpll_ad_func_cntl |= (mpll_param.post_div << MPLL_AD_FUNC_CNTL__YCLK_POST_DIV__SHIFT); - if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) { + if (adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) { mpll_dq_func_cntl &= ~(MPLL_DQ_FUNC_CNTL__YCLK_SEL_MASK | MPLL_AD_FUNC_CNTL__YCLK_POST_DIV_MASK); mpll_dq_func_cntl |= (mpll_param.yclk_sel << MPLL_DQ_FUNC_CNTL__YCLK_SEL__SHIFT) | @@ -3077,7 +3077,7 @@ static int ci_populate_single_memory_level(struct amdgpu_device *adev, (memory_clock <= pi->mclk_strobe_mode_threshold)) memory_level->StrobeEnable = 1; - if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) { + if (adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) { memory_level->StrobeRatio = ci_get_mclk_frequency_ratio(memory_clock, memory_level->StrobeEnable); if (pi->mclk_edc_enable_threshold && @@ -3752,7 +3752,7 @@ static int ci_init_smc_table(struct amdgpu_device *adev) if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC; - if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) + if (adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5; if (ulv->supported) { @@ -4549,12 +4549,12 @@ static int ci_set_mc_special_registers(struct amdgpu_device *adev, for (k = 0; k < table->num_entries; k++) { table->mc_reg_table_entry[k].mc_data[j] = (temp_reg & 0xffff0000) | (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff); - if (adev->mc.vram_type != AMDGPU_VRAM_TYPE_GDDR5) + if (adev->gmc.vram_type != AMDGPU_VRAM_TYPE_GDDR5) table->mc_reg_table_entry[k].mc_data[j] |= 0x100; } j++; - if (adev->mc.vram_type != AMDGPU_VRAM_TYPE_GDDR5) { + if (adev->gmc.vram_type != AMDGPU_VRAM_TYPE_GDDR5) { if (j >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE) return -EINVAL; table->mc_reg_address[j].s1 = mmMC_PMG_AUTO_CMD; @@ -6639,9 +6639,10 @@ static int ci_dpm_force_clock_level(void *handle, struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct ci_power_info *pi = ci_get_pi(adev); - if (adev->pm.dpm.forced_level & (AMD_DPM_FORCED_LEVEL_AUTO | - AMD_DPM_FORCED_LEVEL_LOW | - AMD_DPM_FORCED_LEVEL_HIGH)) + if (adev->pm.dpm.forced_level != AMD_DPM_FORCED_LEVEL_MANUAL) + return -EINVAL; + + if (mask == 0) return -EINVAL; switch (type) { @@ -6662,15 +6663,15 @@ static int ci_dpm_force_clock_level(void *handle, case PP_PCIE: { uint32_t tmp = mask & pi->dpm_level_enable_mask.pcie_dpm_enable_mask; - uint32_t level = 0; - while (tmp >>= 1) - level++; - - if (!pi->pcie_dpm_key_disabled) - amdgpu_ci_send_msg_to_smc_with_parameter(adev, + if (!pi->pcie_dpm_key_disabled) { + if (fls(tmp) != ffs(tmp)) + amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_PCIeDPM_UnForceLevel); + else + amdgpu_ci_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_PCIeDPM_ForceLevel, - level); + fls(tmp) - 1); + } break; } default: @@ -7029,7 +7030,6 @@ const struct amd_ip_funcs ci_dpm_ip_funcs = { }; const struct amd_pm_funcs ci_dpm_funcs = { - .get_temperature = &ci_dpm_get_temp, .pre_set_power_state = &ci_dpm_pre_set_power_state, .set_power_state = &ci_dpm_set_power_state, .post_set_power_state = &ci_dpm_post_set_power_state, diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index 8e59e65efd44..4324184996a5 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c @@ -1715,6 +1715,27 @@ static void cik_detect_hw_virtualization(struct amdgpu_device *adev) adev->virt.caps |= AMDGPU_PASSTHROUGH_MODE; } +static void cik_flush_hdp(struct amdgpu_device *adev, struct amdgpu_ring *ring) +{ + if (!ring || !ring->funcs->emit_wreg) { + WREG32(mmHDP_MEM_COHERENCY_FLUSH_CNTL, 1); + RREG32(mmHDP_MEM_COHERENCY_FLUSH_CNTL); + } else { + amdgpu_ring_emit_wreg(ring, mmHDP_MEM_COHERENCY_FLUSH_CNTL, 1); + } +} + +static void cik_invalidate_hdp(struct amdgpu_device *adev, + struct amdgpu_ring *ring) +{ + if (!ring || !ring->funcs->emit_wreg) { + WREG32(mmHDP_DEBUG0, 1); + RREG32(mmHDP_DEBUG0); + } else { + amdgpu_ring_emit_wreg(ring, mmHDP_DEBUG0, 1); + } +} + static const struct amdgpu_asic_funcs cik_asic_funcs = { .read_disabled_bios = &cik_read_disabled_bios, @@ -1726,6 +1747,8 @@ static const struct amdgpu_asic_funcs cik_asic_funcs = .set_uvd_clocks = &cik_set_uvd_clocks, .set_vce_clocks = &cik_set_vce_clocks, .get_config_memsize = &cik_get_config_memsize, + .flush_hdp = &cik_flush_hdp, + .invalidate_hdp = &cik_invalidate_hdp, }; static int cik_common_early_init(void *handle) diff --git a/drivers/gpu/drm/amd/amdgpu/cik.h b/drivers/gpu/drm/amd/amdgpu/cik.h index c4989f51ecef..e49c6f15a0a0 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.h +++ b/drivers/gpu/drm/amd/amdgpu/cik.h @@ -24,6 +24,8 @@ #ifndef __CIK_H__ #define __CIK_H__ +#define CIK_FLUSH_GPU_TLB_NUM_WREG 3 + void cik_srbm_select(struct amdgpu_device *adev, u32 me, u32 pipe, u32 queue, u32 vmid); int cik_set_ip_blocks(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/cik_ih.c b/drivers/gpu/drm/amd/amdgpu/cik_ih.c index d5a05c19708f..07c7852180d0 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_ih.c @@ -281,7 +281,7 @@ static void cik_ih_decode_iv(struct amdgpu_device *adev, entry->src_data[0] = dw[1] & 0xfffffff; entry->ring_id = dw[2] & 0xff; entry->vmid = (dw[2] >> 8) & 0xff; - entry->pas_id = (dw[2] >> 16) & 0xffff; + entry->pasid = (dw[2] >> 16) & 0xffff; /* wptr/rptr are in bytes! */ adev->irq.ih.rptr += 16; diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c index 6e8278e689b1..69568cd1bb99 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c @@ -261,13 +261,6 @@ static void cik_sdma_ring_emit_hdp_flush(struct amdgpu_ring *ring) amdgpu_ring_write(ring, (0xfff << 16) | 10); /* retry count, poll interval */ } -static void cik_sdma_ring_emit_hdp_invalidate(struct amdgpu_ring *ring) -{ - amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); - amdgpu_ring_write(ring, mmHDP_DEBUG0); - amdgpu_ring_write(ring, 1); -} - /** * cik_sdma_ring_emit_fence - emit a fence on the DMA ring * @@ -317,7 +310,7 @@ static void cik_sdma_gfx_stop(struct amdgpu_device *adev) if ((adev->mman.buffer_funcs_ring == sdma0) || (adev->mman.buffer_funcs_ring == sdma1)) - amdgpu_ttm_set_active_vram_size(adev, adev->mc.visible_vram_size); + amdgpu_ttm_set_active_vram_size(adev, adev->gmc.visible_vram_size); for (i = 0; i < adev->sdma.num_instances; i++) { rb_cntl = RREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i]); @@ -517,7 +510,7 @@ static int cik_sdma_gfx_resume(struct amdgpu_device *adev) } if (adev->mman.buffer_funcs_ring == ring) - amdgpu_ttm_set_active_vram_size(adev, adev->mc.real_vram_size); + amdgpu_ttm_set_active_vram_size(adev, adev->gmc.real_vram_size); } return 0; @@ -885,18 +878,7 @@ static void cik_sdma_ring_emit_vm_flush(struct amdgpu_ring *ring, u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(0) | SDMA_POLL_REG_MEM_EXTRA_FUNC(0)); /* always */ - amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); - if (vmid < 8) { - amdgpu_ring_write(ring, (mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR + vmid)); - } else { - amdgpu_ring_write(ring, (mmVM_CONTEXT8_PAGE_TABLE_BASE_ADDR + vmid - 8)); - } - amdgpu_ring_write(ring, pd_addr >> 12); - - /* flush TLB */ - amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); - amdgpu_ring_write(ring, mmVM_INVALIDATE_REQUEST); - amdgpu_ring_write(ring, 1 << vmid); + amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits)); amdgpu_ring_write(ring, mmVM_INVALIDATE_REQUEST << 2); @@ -906,6 +888,14 @@ static void cik_sdma_ring_emit_vm_flush(struct amdgpu_ring *ring, amdgpu_ring_write(ring, (0xfff << 16) | 10); /* retry count, poll interval */ } +static void cik_sdma_ring_emit_wreg(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val) +{ + amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); + amdgpu_ring_write(ring, reg); + amdgpu_ring_write(ring, val); +} + static void cik_enable_sdma_mgcg(struct amdgpu_device *adev, bool enable) { @@ -1279,9 +1269,9 @@ static const struct amdgpu_ring_funcs cik_sdma_ring_funcs = { .set_wptr = cik_sdma_ring_set_wptr, .emit_frame_size = 6 + /* cik_sdma_ring_emit_hdp_flush */ - 3 + /* cik_sdma_ring_emit_hdp_invalidate */ + 3 + /* hdp invalidate */ 6 + /* cik_sdma_ring_emit_pipeline_sync */ - 12 + /* cik_sdma_ring_emit_vm_flush */ + CIK_FLUSH_GPU_TLB_NUM_WREG * 3 + 6 + /* cik_sdma_ring_emit_vm_flush */ 9 + 9 + 9, /* cik_sdma_ring_emit_fence x3 for user fence, vm fence */ .emit_ib_size = 7 + 4, /* cik_sdma_ring_emit_ib */ .emit_ib = cik_sdma_ring_emit_ib, @@ -1289,11 +1279,11 @@ static const struct amdgpu_ring_funcs cik_sdma_ring_funcs = { .emit_pipeline_sync = cik_sdma_ring_emit_pipeline_sync, .emit_vm_flush = cik_sdma_ring_emit_vm_flush, .emit_hdp_flush = cik_sdma_ring_emit_hdp_flush, - .emit_hdp_invalidate = cik_sdma_ring_emit_hdp_invalidate, .test_ring = cik_sdma_ring_test_ring, .test_ib = cik_sdma_ring_test_ib, .insert_nop = cik_sdma_ring_insert_nop, .pad_ib = cik_sdma_ring_pad_ib, + .emit_wreg = cik_sdma_ring_emit_wreg, }; static void cik_sdma_set_ring_funcs(struct amdgpu_device *adev) @@ -1391,9 +1381,6 @@ static const struct amdgpu_vm_pte_funcs cik_sdma_vm_pte_funcs = { .copy_pte = cik_sdma_vm_copy_pte, .write_pte = cik_sdma_vm_write_pte, - - .set_max_nums_pte_pde = 0x1fffff >> 3, - .set_pte_pde_num_dw = 10, .set_pte_pde = cik_sdma_vm_set_pte_pde, }; diff --git a/drivers/gpu/drm/amd/amdgpu/cz_ih.c b/drivers/gpu/drm/amd/amdgpu/cz_ih.c index f576e9cbbc61..cfd0ad03c938 100644 --- a/drivers/gpu/drm/amd/amdgpu/cz_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/cz_ih.c @@ -260,7 +260,7 @@ static void cz_ih_decode_iv(struct amdgpu_device *adev, entry->src_data[0] = dw[1] & 0xfffffff; entry->ring_id = dw[2] & 0xff; entry->vmid = (dw[2] >> 8) & 0xff; - entry->pas_id = (dw[2] >> 16) & 0xffff; + entry->pasid = (dw[2] >> 16) & 0xffff; /* wptr/rptr are in bytes! */ adev->irq.ih.rptr += 16; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index f34bc68aadfb..7ea900010702 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -190,66 +190,6 @@ static void dce_v10_0_audio_endpt_wreg(struct amdgpu_device *adev, spin_unlock_irqrestore(&adev->audio_endpt_idx_lock, flags); } -static bool dce_v10_0_is_in_vblank(struct amdgpu_device *adev, int crtc) -{ - if (RREG32(mmCRTC_STATUS + crtc_offsets[crtc]) & - CRTC_V_BLANK_START_END__CRTC_V_BLANK_START_MASK) - return true; - else - return false; -} - -static bool dce_v10_0_is_counter_moving(struct amdgpu_device *adev, int crtc) -{ - u32 pos1, pos2; - - pos1 = RREG32(mmCRTC_STATUS_POSITION + crtc_offsets[crtc]); - pos2 = RREG32(mmCRTC_STATUS_POSITION + crtc_offsets[crtc]); - - if (pos1 != pos2) - return true; - else - return false; -} - -/** - * dce_v10_0_vblank_wait - vblank wait asic callback. - * - * @adev: amdgpu_device pointer - * @crtc: crtc to wait for vblank on - * - * Wait for vblank on the requested crtc (evergreen+). - */ -static void dce_v10_0_vblank_wait(struct amdgpu_device *adev, int crtc) -{ - unsigned i = 100; - - if (crtc >= adev->mode_info.num_crtc) - return; - - if (!(RREG32(mmCRTC_CONTROL + crtc_offsets[crtc]) & CRTC_CONTROL__CRTC_MASTER_EN_MASK)) - return; - - /* depending on when we hit vblank, we may be close to active; if so, - * wait for another frame. - */ - while (dce_v10_0_is_in_vblank(adev, crtc)) { - if (i++ == 100) { - i = 0; - if (!dce_v10_0_is_counter_moving(adev, crtc)) - break; - } - } - - while (!dce_v10_0_is_in_vblank(adev, crtc)) { - if (i++ == 100) { - i = 0; - if (!dce_v10_0_is_counter_moving(adev, crtc)) - break; - } - } -} - static u32 dce_v10_0_vblank_get_counter(struct amdgpu_device *adev, int crtc) { if (crtc >= adev->mode_info.num_crtc) @@ -1205,7 +1145,7 @@ static void dce_v10_0_bandwidth_update(struct amdgpu_device *adev) u32 num_heads = 0, lb_size; int i; - amdgpu_update_display_priority(adev); + amdgpu_display_update_priority(adev); for (i = 0; i < adev->mode_info.num_crtc; i++) { if (adev->mode_info.crtcs[i]->base.enabled) @@ -2517,9 +2457,9 @@ static const struct drm_crtc_funcs dce_v10_0_crtc_funcs = { .cursor_set2 = dce_v10_0_crtc_cursor_set2, .cursor_move = dce_v10_0_crtc_cursor_move, .gamma_set = dce_v10_0_crtc_gamma_set, - .set_config = amdgpu_crtc_set_config, + .set_config = amdgpu_display_crtc_set_config, .destroy = dce_v10_0_crtc_destroy, - .page_flip_target = amdgpu_crtc_page_flip_target, + .page_flip_target = amdgpu_display_crtc_page_flip_target, }; static void dce_v10_0_crtc_dpms(struct drm_crtc *crtc, int mode) @@ -2537,7 +2477,8 @@ static void dce_v10_0_crtc_dpms(struct drm_crtc *crtc, int mode) amdgpu_atombios_crtc_blank(crtc, ATOM_DISABLE); dce_v10_0_vga_enable(crtc, false); /* Make sure VBLANK and PFLIP interrupts are still enabled */ - type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id); + type = amdgpu_display_crtc_idx_to_irq_type(adev, + amdgpu_crtc->crtc_id); amdgpu_irq_update(adev, &adev->crtc_irq, type); amdgpu_irq_update(adev, &adev->pageflip_irq, type); drm_crtc_vblank_on(crtc); @@ -2676,7 +2617,7 @@ static bool dce_v10_0_crtc_mode_fixup(struct drm_crtc *crtc, amdgpu_crtc->connector = NULL; return false; } - if (!amdgpu_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) + if (!amdgpu_display_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) return false; if (amdgpu_atombios_crtc_prepare_pll(crtc, adjusted_mode)) return false; @@ -2824,9 +2765,9 @@ static int dce_v10_0_sw_init(void *handle) adev->ddev->mode_config.preferred_depth = 24; adev->ddev->mode_config.prefer_shadow = 1; - adev->ddev->mode_config.fb_base = adev->mc.aper_base; + adev->ddev->mode_config.fb_base = adev->gmc.aper_base; - r = amdgpu_modeset_create_props(adev); + r = amdgpu_display_modeset_create_props(adev); if (r) return r; @@ -2841,7 +2782,7 @@ static int dce_v10_0_sw_init(void *handle) } if (amdgpu_atombios_get_connector_info_from_object_table(adev)) - amdgpu_print_display_setup(adev->ddev); + amdgpu_display_print_display_setup(adev->ddev); else return -EINVAL; @@ -3249,7 +3190,7 @@ static int dce_v10_0_crtc_irq(struct amdgpu_device *adev, { unsigned crtc = entry->src_id - 1; uint32_t disp_int = RREG32(interrupt_status_offsets[crtc].reg); - unsigned irq_type = amdgpu_crtc_idx_to_irq_type(adev, crtc); + unsigned int irq_type = amdgpu_display_crtc_idx_to_irq_type(adev, crtc); switch (entry->src_data[0]) { case 0: /* vblank */ @@ -3601,7 +3542,6 @@ static void dce_v10_0_encoder_add(struct amdgpu_device *adev, static const struct amdgpu_display_funcs dce_v10_0_display_funcs = { .bandwidth_update = &dce_v10_0_bandwidth_update, .vblank_get_counter = &dce_v10_0_vblank_get_counter, - .vblank_wait = &dce_v10_0_vblank_wait, .backlight_set_level = &amdgpu_atombios_encoder_set_backlight_level, .backlight_get_level = &amdgpu_atombios_encoder_get_backlight_level, .hpd_sense = &dce_v10_0_hpd_sense, diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 26378bd6aba4..158b92ea435f 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -207,66 +207,6 @@ static void dce_v11_0_audio_endpt_wreg(struct amdgpu_device *adev, spin_unlock_irqrestore(&adev->audio_endpt_idx_lock, flags); } -static bool dce_v11_0_is_in_vblank(struct amdgpu_device *adev, int crtc) -{ - if (RREG32(mmCRTC_STATUS + crtc_offsets[crtc]) & - CRTC_V_BLANK_START_END__CRTC_V_BLANK_START_MASK) - return true; - else - return false; -} - -static bool dce_v11_0_is_counter_moving(struct amdgpu_device *adev, int crtc) -{ - u32 pos1, pos2; - - pos1 = RREG32(mmCRTC_STATUS_POSITION + crtc_offsets[crtc]); - pos2 = RREG32(mmCRTC_STATUS_POSITION + crtc_offsets[crtc]); - - if (pos1 != pos2) - return true; - else - return false; -} - -/** - * dce_v11_0_vblank_wait - vblank wait asic callback. - * - * @adev: amdgpu_device pointer - * @crtc: crtc to wait for vblank on - * - * Wait for vblank on the requested crtc (evergreen+). - */ -static void dce_v11_0_vblank_wait(struct amdgpu_device *adev, int crtc) -{ - unsigned i = 100; - - if (crtc < 0 || crtc >= adev->mode_info.num_crtc) - return; - - if (!(RREG32(mmCRTC_CONTROL + crtc_offsets[crtc]) & CRTC_CONTROL__CRTC_MASTER_EN_MASK)) - return; - - /* depending on when we hit vblank, we may be close to active; if so, - * wait for another frame. - */ - while (dce_v11_0_is_in_vblank(adev, crtc)) { - if (i++ == 100) { - i = 0; - if (!dce_v11_0_is_counter_moving(adev, crtc)) - break; - } - } - - while (!dce_v11_0_is_in_vblank(adev, crtc)) { - if (i++ == 100) { - i = 0; - if (!dce_v11_0_is_counter_moving(adev, crtc)) - break; - } - } -} - static u32 dce_v11_0_vblank_get_counter(struct amdgpu_device *adev, int crtc) { if (crtc < 0 || crtc >= adev->mode_info.num_crtc) @@ -1229,7 +1169,7 @@ static void dce_v11_0_bandwidth_update(struct amdgpu_device *adev) u32 num_heads = 0, lb_size; int i; - amdgpu_update_display_priority(adev); + amdgpu_display_update_priority(adev); for (i = 0; i < adev->mode_info.num_crtc; i++) { if (adev->mode_info.crtcs[i]->base.enabled) @@ -2592,9 +2532,9 @@ static const struct drm_crtc_funcs dce_v11_0_crtc_funcs = { .cursor_set2 = dce_v11_0_crtc_cursor_set2, .cursor_move = dce_v11_0_crtc_cursor_move, .gamma_set = dce_v11_0_crtc_gamma_set, - .set_config = amdgpu_crtc_set_config, + .set_config = amdgpu_display_crtc_set_config, .destroy = dce_v11_0_crtc_destroy, - .page_flip_target = amdgpu_crtc_page_flip_target, + .page_flip_target = amdgpu_display_crtc_page_flip_target, }; static void dce_v11_0_crtc_dpms(struct drm_crtc *crtc, int mode) @@ -2612,7 +2552,8 @@ static void dce_v11_0_crtc_dpms(struct drm_crtc *crtc, int mode) amdgpu_atombios_crtc_blank(crtc, ATOM_DISABLE); dce_v11_0_vga_enable(crtc, false); /* Make sure VBLANK and PFLIP interrupts are still enabled */ - type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id); + type = amdgpu_display_crtc_idx_to_irq_type(adev, + amdgpu_crtc->crtc_id); amdgpu_irq_update(adev, &adev->crtc_irq, type); amdgpu_irq_update(adev, &adev->pageflip_irq, type); drm_crtc_vblank_on(crtc); @@ -2779,7 +2720,7 @@ static bool dce_v11_0_crtc_mode_fixup(struct drm_crtc *crtc, amdgpu_crtc->connector = NULL; return false; } - if (!amdgpu_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) + if (!amdgpu_display_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) return false; if (amdgpu_atombios_crtc_prepare_pll(crtc, adjusted_mode)) return false; @@ -2939,9 +2880,9 @@ static int dce_v11_0_sw_init(void *handle) adev->ddev->mode_config.preferred_depth = 24; adev->ddev->mode_config.prefer_shadow = 1; - adev->ddev->mode_config.fb_base = adev->mc.aper_base; + adev->ddev->mode_config.fb_base = adev->gmc.aper_base; - r = amdgpu_modeset_create_props(adev); + r = amdgpu_display_modeset_create_props(adev); if (r) return r; @@ -2957,7 +2898,7 @@ static int dce_v11_0_sw_init(void *handle) } if (amdgpu_atombios_get_connector_info_from_object_table(adev)) - amdgpu_print_display_setup(adev->ddev); + amdgpu_display_print_display_setup(adev->ddev); else return -EINVAL; @@ -3368,7 +3309,8 @@ static int dce_v11_0_crtc_irq(struct amdgpu_device *adev, { unsigned crtc = entry->src_id - 1; uint32_t disp_int = RREG32(interrupt_status_offsets[crtc].reg); - unsigned irq_type = amdgpu_crtc_idx_to_irq_type(adev, crtc); + unsigned int irq_type = amdgpu_display_crtc_idx_to_irq_type(adev, + crtc); switch (entry->src_data[0]) { case 0: /* vblank */ @@ -3725,7 +3667,6 @@ static void dce_v11_0_encoder_add(struct amdgpu_device *adev, static const struct amdgpu_display_funcs dce_v11_0_display_funcs = { .bandwidth_update = &dce_v11_0_bandwidth_update, .vblank_get_counter = &dce_v11_0_vblank_get_counter, - .vblank_wait = &dce_v11_0_vblank_wait, .backlight_set_level = &amdgpu_atombios_encoder_set_backlight_level, .backlight_get_level = &amdgpu_atombios_encoder_get_backlight_level, .hpd_sense = &dce_v11_0_hpd_sense, diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index bd2c4f727df6..03f19363f8f6 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -142,64 +142,6 @@ static void dce_v6_0_audio_endpt_wreg(struct amdgpu_device *adev, spin_unlock_irqrestore(&adev->audio_endpt_idx_lock, flags); } -static bool dce_v6_0_is_in_vblank(struct amdgpu_device *adev, int crtc) -{ - if (RREG32(mmCRTC_STATUS + crtc_offsets[crtc]) & CRTC_STATUS__CRTC_V_BLANK_MASK) - return true; - else - return false; -} - -static bool dce_v6_0_is_counter_moving(struct amdgpu_device *adev, int crtc) -{ - u32 pos1, pos2; - - pos1 = RREG32(mmCRTC_STATUS_POSITION + crtc_offsets[crtc]); - pos2 = RREG32(mmCRTC_STATUS_POSITION + crtc_offsets[crtc]); - - if (pos1 != pos2) - return true; - else - return false; -} - -/** - * dce_v6_0_wait_for_vblank - vblank wait asic callback. - * - * @crtc: crtc to wait for vblank on - * - * Wait for vblank on the requested crtc (evergreen+). - */ -static void dce_v6_0_vblank_wait(struct amdgpu_device *adev, int crtc) -{ - unsigned i = 100; - - if (crtc >= adev->mode_info.num_crtc) - return; - - if (!(RREG32(mmCRTC_CONTROL + crtc_offsets[crtc]) & CRTC_CONTROL__CRTC_MASTER_EN_MASK)) - return; - - /* depending on when we hit vblank, we may be close to active; if so, - * wait for another frame. - */ - while (dce_v6_0_is_in_vblank(adev, crtc)) { - if (i++ == 100) { - i = 0; - if (!dce_v6_0_is_counter_moving(adev, crtc)) - break; - } - } - - while (!dce_v6_0_is_in_vblank(adev, crtc)) { - if (i++ == 100) { - i = 0; - if (!dce_v6_0_is_counter_moving(adev, crtc)) - break; - } - } -} - static u32 dce_v6_0_vblank_get_counter(struct amdgpu_device *adev, int crtc) { if (crtc >= adev->mode_info.num_crtc) @@ -1108,7 +1050,7 @@ static void dce_v6_0_bandwidth_update(struct amdgpu_device *adev) if (!adev->mode_info.mode_config_initialized) return; - amdgpu_update_display_priority(adev); + amdgpu_display_update_priority(adev); for (i = 0; i < adev->mode_info.num_crtc; i++) { if (adev->mode_info.crtcs[i]->base.enabled) @@ -2407,9 +2349,9 @@ static const struct drm_crtc_funcs dce_v6_0_crtc_funcs = { .cursor_set2 = dce_v6_0_crtc_cursor_set2, .cursor_move = dce_v6_0_crtc_cursor_move, .gamma_set = dce_v6_0_crtc_gamma_set, - .set_config = amdgpu_crtc_set_config, + .set_config = amdgpu_display_crtc_set_config, .destroy = dce_v6_0_crtc_destroy, - .page_flip_target = amdgpu_crtc_page_flip_target, + .page_flip_target = amdgpu_display_crtc_page_flip_target, }; static void dce_v6_0_crtc_dpms(struct drm_crtc *crtc, int mode) @@ -2425,7 +2367,8 @@ static void dce_v6_0_crtc_dpms(struct drm_crtc *crtc, int mode) amdgpu_atombios_crtc_enable(crtc, ATOM_ENABLE); amdgpu_atombios_crtc_blank(crtc, ATOM_DISABLE); /* Make sure VBLANK and PFLIP interrupts are still enabled */ - type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id); + type = amdgpu_display_crtc_idx_to_irq_type(adev, + amdgpu_crtc->crtc_id); amdgpu_irq_update(adev, &adev->crtc_irq, type); amdgpu_irq_update(adev, &adev->pageflip_irq, type); drm_crtc_vblank_on(crtc); @@ -2562,7 +2505,7 @@ static bool dce_v6_0_crtc_mode_fixup(struct drm_crtc *crtc, amdgpu_crtc->connector = NULL; return false; } - if (!amdgpu_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) + if (!amdgpu_display_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) return false; if (amdgpu_atombios_crtc_prepare_pll(crtc, adjusted_mode)) return false; @@ -2693,9 +2636,9 @@ static int dce_v6_0_sw_init(void *handle) adev->ddev->mode_config.max_height = 16384; adev->ddev->mode_config.preferred_depth = 24; adev->ddev->mode_config.prefer_shadow = 1; - adev->ddev->mode_config.fb_base = adev->mc.aper_base; + adev->ddev->mode_config.fb_base = adev->gmc.aper_base; - r = amdgpu_modeset_create_props(adev); + r = amdgpu_display_modeset_create_props(adev); if (r) return r; @@ -2711,7 +2654,7 @@ static int dce_v6_0_sw_init(void *handle) ret = amdgpu_atombios_get_connector_info_from_object_table(adev); if (ret) - amdgpu_print_display_setup(adev->ddev); + amdgpu_display_print_display_setup(adev->ddev); else return -EINVAL; @@ -2966,7 +2909,8 @@ static int dce_v6_0_crtc_irq(struct amdgpu_device *adev, { unsigned crtc = entry->src_id - 1; uint32_t disp_int = RREG32(interrupt_status_offsets[crtc].reg); - unsigned irq_type = amdgpu_crtc_idx_to_irq_type(adev, crtc); + unsigned int irq_type = amdgpu_display_crtc_idx_to_irq_type(adev, + crtc); switch (entry->src_data[0]) { case 0: /* vblank */ @@ -3407,7 +3351,6 @@ static void dce_v6_0_encoder_add(struct amdgpu_device *adev, static const struct amdgpu_display_funcs dce_v6_0_display_funcs = { .bandwidth_update = &dce_v6_0_bandwidth_update, .vblank_get_counter = &dce_v6_0_vblank_get_counter, - .vblank_wait = &dce_v6_0_vblank_wait, .backlight_set_level = &amdgpu_atombios_encoder_set_backlight_level, .backlight_get_level = &amdgpu_atombios_encoder_get_backlight_level, .hpd_sense = &dce_v6_0_hpd_sense, diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index c008dc030687..8dbe97dff58c 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -140,66 +140,6 @@ static void dce_v8_0_audio_endpt_wreg(struct amdgpu_device *adev, spin_unlock_irqrestore(&adev->audio_endpt_idx_lock, flags); } -static bool dce_v8_0_is_in_vblank(struct amdgpu_device *adev, int crtc) -{ - if (RREG32(mmCRTC_STATUS + crtc_offsets[crtc]) & - CRTC_V_BLANK_START_END__CRTC_V_BLANK_START_MASK) - return true; - else - return false; -} - -static bool dce_v8_0_is_counter_moving(struct amdgpu_device *adev, int crtc) -{ - u32 pos1, pos2; - - pos1 = RREG32(mmCRTC_STATUS_POSITION + crtc_offsets[crtc]); - pos2 = RREG32(mmCRTC_STATUS_POSITION + crtc_offsets[crtc]); - - if (pos1 != pos2) - return true; - else - return false; -} - -/** - * dce_v8_0_vblank_wait - vblank wait asic callback. - * - * @adev: amdgpu_device pointer - * @crtc: crtc to wait for vblank on - * - * Wait for vblank on the requested crtc (evergreen+). - */ -static void dce_v8_0_vblank_wait(struct amdgpu_device *adev, int crtc) -{ - unsigned i = 100; - - if (crtc >= adev->mode_info.num_crtc) - return; - - if (!(RREG32(mmCRTC_CONTROL + crtc_offsets[crtc]) & CRTC_CONTROL__CRTC_MASTER_EN_MASK)) - return; - - /* depending on when we hit vblank, we may be close to active; if so, - * wait for another frame. - */ - while (dce_v8_0_is_in_vblank(adev, crtc)) { - if (i++ == 100) { - i = 0; - if (!dce_v8_0_is_counter_moving(adev, crtc)) - break; - } - } - - while (!dce_v8_0_is_in_vblank(adev, crtc)) { - if (i++ == 100) { - i = 0; - if (!dce_v8_0_is_counter_moving(adev, crtc)) - break; - } - } -} - static u32 dce_v8_0_vblank_get_counter(struct amdgpu_device *adev, int crtc) { if (crtc >= adev->mode_info.num_crtc) @@ -1144,7 +1084,7 @@ static void dce_v8_0_bandwidth_update(struct amdgpu_device *adev) u32 num_heads = 0, lb_size; int i; - amdgpu_update_display_priority(adev); + amdgpu_display_update_priority(adev); for (i = 0; i < adev->mode_info.num_crtc; i++) { if (adev->mode_info.crtcs[i]->base.enabled) @@ -2421,9 +2361,9 @@ static const struct drm_crtc_funcs dce_v8_0_crtc_funcs = { .cursor_set2 = dce_v8_0_crtc_cursor_set2, .cursor_move = dce_v8_0_crtc_cursor_move, .gamma_set = dce_v8_0_crtc_gamma_set, - .set_config = amdgpu_crtc_set_config, + .set_config = amdgpu_display_crtc_set_config, .destroy = dce_v8_0_crtc_destroy, - .page_flip_target = amdgpu_crtc_page_flip_target, + .page_flip_target = amdgpu_display_crtc_page_flip_target, }; static void dce_v8_0_crtc_dpms(struct drm_crtc *crtc, int mode) @@ -2441,7 +2381,8 @@ static void dce_v8_0_crtc_dpms(struct drm_crtc *crtc, int mode) amdgpu_atombios_crtc_blank(crtc, ATOM_DISABLE); dce_v8_0_vga_enable(crtc, false); /* Make sure VBLANK and PFLIP interrupts are still enabled */ - type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id); + type = amdgpu_display_crtc_idx_to_irq_type(adev, + amdgpu_crtc->crtc_id); amdgpu_irq_update(adev, &adev->crtc_irq, type); amdgpu_irq_update(adev, &adev->pageflip_irq, type); drm_crtc_vblank_on(crtc); @@ -2587,7 +2528,7 @@ static bool dce_v8_0_crtc_mode_fixup(struct drm_crtc *crtc, amdgpu_crtc->connector = NULL; return false; } - if (!amdgpu_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) + if (!amdgpu_display_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) return false; if (amdgpu_atombios_crtc_prepare_pll(crtc, adjusted_mode)) return false; @@ -2724,9 +2665,9 @@ static int dce_v8_0_sw_init(void *handle) adev->ddev->mode_config.preferred_depth = 24; adev->ddev->mode_config.prefer_shadow = 1; - adev->ddev->mode_config.fb_base = adev->mc.aper_base; + adev->ddev->mode_config.fb_base = adev->gmc.aper_base; - r = amdgpu_modeset_create_props(adev); + r = amdgpu_display_modeset_create_props(adev); if (r) return r; @@ -2741,7 +2682,7 @@ static int dce_v8_0_sw_init(void *handle) } if (amdgpu_atombios_get_connector_info_from_object_table(adev)) - amdgpu_print_display_setup(adev->ddev); + amdgpu_display_print_display_setup(adev->ddev); else return -EINVAL; @@ -3063,7 +3004,8 @@ static int dce_v8_0_crtc_irq(struct amdgpu_device *adev, { unsigned crtc = entry->src_id - 1; uint32_t disp_int = RREG32(interrupt_status_offsets[crtc].reg); - unsigned irq_type = amdgpu_crtc_idx_to_irq_type(adev, crtc); + unsigned int irq_type = amdgpu_display_crtc_idx_to_irq_type(adev, + crtc); switch (entry->src_data[0]) { case 0: /* vblank */ @@ -3491,7 +3433,6 @@ static void dce_v8_0_encoder_add(struct amdgpu_device *adev, static const struct amdgpu_display_funcs dce_v8_0_display_funcs = { .bandwidth_update = &dce_v8_0_bandwidth_update, .vblank_get_counter = &dce_v8_0_vblank_get_counter, - .vblank_wait = &dce_v8_0_vblank_wait, .backlight_set_level = &amdgpu_atombios_encoder_set_backlight_level, .backlight_get_level = &amdgpu_atombios_encoder_get_backlight_level, .hpd_sense = &dce_v8_0_hpd_sense, diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c index 120dd3b26fc2..8201a0929ca2 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c @@ -48,19 +48,6 @@ static void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *ad int crtc, enum amdgpu_interrupt_state state); -/** - * dce_virtual_vblank_wait - vblank wait asic callback. - * - * @adev: amdgpu_device pointer - * @crtc: crtc to wait for vblank on - * - * Wait for vblank on the requested crtc (evergreen+). - */ -static void dce_virtual_vblank_wait(struct amdgpu_device *adev, int crtc) -{ - return; -} - static u32 dce_virtual_vblank_get_counter(struct amdgpu_device *adev, int crtc) { return 0; @@ -130,9 +117,9 @@ static const struct drm_crtc_funcs dce_virtual_crtc_funcs = { .cursor_set2 = NULL, .cursor_move = NULL, .gamma_set = dce_virtual_crtc_gamma_set, - .set_config = amdgpu_crtc_set_config, + .set_config = amdgpu_display_crtc_set_config, .destroy = dce_virtual_crtc_destroy, - .page_flip_target = amdgpu_crtc_page_flip_target, + .page_flip_target = amdgpu_display_crtc_page_flip_target, }; static void dce_virtual_crtc_dpms(struct drm_crtc *crtc, int mode) @@ -149,7 +136,8 @@ static void dce_virtual_crtc_dpms(struct drm_crtc *crtc, int mode) case DRM_MODE_DPMS_ON: amdgpu_crtc->enabled = true; /* Make sure VBLANK interrupts are still enabled */ - type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id); + type = amdgpu_display_crtc_idx_to_irq_type(adev, + amdgpu_crtc->crtc_id); amdgpu_irq_update(adev, &adev->crtc_irq, type); drm_crtc_vblank_on(crtc); break; @@ -406,9 +394,9 @@ static int dce_virtual_sw_init(void *handle) adev->ddev->mode_config.preferred_depth = 24; adev->ddev->mode_config.prefer_shadow = 1; - adev->ddev->mode_config.fb_base = adev->mc.aper_base; + adev->ddev->mode_config.fb_base = adev->gmc.aper_base; - r = amdgpu_modeset_create_props(adev); + r = amdgpu_display_modeset_create_props(adev); if (r) return r; @@ -653,7 +641,6 @@ static int dce_virtual_connector_encoder_init(struct amdgpu_device *adev, static const struct amdgpu_display_funcs dce_virtual_display_funcs = { .bandwidth_update = &dce_virtual_bandwidth_update, .vblank_get_counter = &dce_virtual_vblank_get_counter, - .vblank_wait = &dce_virtual_vblank_wait, .backlight_set_level = NULL, .backlight_get_level = NULL, .hpd_sense = &dce_virtual_hpd_sense, diff --git a/drivers/gpu/drm/amd/amdgpu/emu_soc.c b/drivers/gpu/drm/amd/amdgpu/emu_soc.c new file mode 100644 index 000000000000..d72c25c1b987 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/emu_soc.c @@ -0,0 +1,33 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +#include "amdgpu.h" +#include "soc15.h" + +#include "soc15_common.h" +#include "soc15_hw_ip.h" + +int emu_soc_asic_init(struct amdgpu_device *adev) +{ + return 0; +} + diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c index 9870d83b68c1..0fff5b8cd318 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c @@ -38,6 +38,7 @@ #include "dce/dce_6_0_sh_mask.h" #include "gca/gfx_7_2_enum.h" #include "si_enums.h" +#include "si.h" static void gfx_v6_0_set_ring_funcs(struct amdgpu_device *adev); static void gfx_v6_0_set_irq_funcs(struct amdgpu_device *adev); @@ -1808,17 +1809,6 @@ static int gfx_v6_0_ring_test_ring(struct amdgpu_ring *ring) return r; } -static void gfx_v6_0_ring_emit_hdp_flush(struct amdgpu_ring *ring) -{ - /* flush hdp cache */ - amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) | - WRITE_DATA_DST_SEL(0))); - amdgpu_ring_write(ring, mmHDP_MEM_COHERENCY_FLUSH_CNTL); - amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, 0x1); -} - static void gfx_v6_0_ring_emit_vgt_flush(struct amdgpu_ring *ring) { amdgpu_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE, 0)); @@ -1826,24 +1816,6 @@ static void gfx_v6_0_ring_emit_vgt_flush(struct amdgpu_ring *ring) EVENT_INDEX(0)); } -/** - * gfx_v6_0_ring_emit_hdp_invalidate - emit an hdp invalidate on the cp - * - * @adev: amdgpu_device pointer - * @ridx: amdgpu ring index - * - * Emits an hdp invalidate on the cp. - */ -static void gfx_v6_0_ring_emit_hdp_invalidate(struct amdgpu_ring *ring) -{ - amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) | - WRITE_DATA_DST_SEL(0))); - amdgpu_ring_write(ring, mmHDP_DEBUG0); - amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, 0x1); -} - static void gfx_v6_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq, unsigned flags) { @@ -2358,25 +2330,7 @@ static void gfx_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring, { int usepfp = (ring->funcs->type == AMDGPU_RING_TYPE_GFX); - /* write new base address */ - amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) | - WRITE_DATA_DST_SEL(0))); - if (vmid < 8) { - amdgpu_ring_write(ring, (mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR + vmid )); - } else { - amdgpu_ring_write(ring, (mmVM_CONTEXT8_PAGE_TABLE_BASE_ADDR + (vmid - 8))); - } - amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, pd_addr >> 12); - - /* bits 0-15 are the VM contexts0-15 */ - amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) | - WRITE_DATA_DST_SEL(0))); - amdgpu_ring_write(ring, mmVM_INVALIDATE_REQUEST); - amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, 1 << vmid); + amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); /* wait for the invalidate to complete */ amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); @@ -2401,6 +2355,18 @@ static void gfx_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring, } } +static void gfx_v6_0_ring_emit_wreg(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val) +{ + int usepfp = (ring->funcs->type == AMDGPU_RING_TYPE_GFX); + + amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); + amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | + WRITE_DATA_DST_SEL(0))); + amdgpu_ring_write(ring, reg); + amdgpu_ring_write(ring, 0); + amdgpu_ring_write(ring, val); +} static void gfx_v6_0_rlc_fini(struct amdgpu_device *adev) { @@ -3511,23 +3477,21 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_gfx = { .get_wptr = gfx_v6_0_ring_get_wptr, .set_wptr = gfx_v6_0_ring_set_wptr_gfx, .emit_frame_size = - 5 + /* gfx_v6_0_ring_emit_hdp_flush */ - 5 + /* gfx_v6_0_ring_emit_hdp_invalidate */ + 5 + 5 + /* hdp flush / invalidate */ 14 + 14 + 14 + /* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */ 7 + 4 + /* gfx_v6_0_ring_emit_pipeline_sync */ - 17 + 6 + /* gfx_v6_0_ring_emit_vm_flush */ + SI_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + 6 + /* gfx_v6_0_ring_emit_vm_flush */ 3 + 2, /* gfx_v6_ring_emit_cntxcntl including vgt flush */ .emit_ib_size = 6, /* gfx_v6_0_ring_emit_ib */ .emit_ib = gfx_v6_0_ring_emit_ib, .emit_fence = gfx_v6_0_ring_emit_fence, .emit_pipeline_sync = gfx_v6_0_ring_emit_pipeline_sync, .emit_vm_flush = gfx_v6_0_ring_emit_vm_flush, - .emit_hdp_flush = gfx_v6_0_ring_emit_hdp_flush, - .emit_hdp_invalidate = gfx_v6_0_ring_emit_hdp_invalidate, .test_ring = gfx_v6_0_ring_test_ring, .test_ib = gfx_v6_0_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, .emit_cntxcntl = gfx_v6_ring_emit_cntxcntl, + .emit_wreg = gfx_v6_0_ring_emit_wreg, }; static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_compute = { @@ -3538,21 +3502,19 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_compute = { .get_wptr = gfx_v6_0_ring_get_wptr, .set_wptr = gfx_v6_0_ring_set_wptr_compute, .emit_frame_size = - 5 + /* gfx_v6_0_ring_emit_hdp_flush */ - 5 + /* gfx_v6_0_ring_emit_hdp_invalidate */ + 5 + 5 + /* hdp flush / invalidate */ 7 + /* gfx_v6_0_ring_emit_pipeline_sync */ - 17 + /* gfx_v6_0_ring_emit_vm_flush */ + SI_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + /* gfx_v6_0_ring_emit_vm_flush */ 14 + 14 + 14, /* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */ .emit_ib_size = 6, /* gfx_v6_0_ring_emit_ib */ .emit_ib = gfx_v6_0_ring_emit_ib, .emit_fence = gfx_v6_0_ring_emit_fence, .emit_pipeline_sync = gfx_v6_0_ring_emit_pipeline_sync, .emit_vm_flush = gfx_v6_0_ring_emit_vm_flush, - .emit_hdp_flush = gfx_v6_0_ring_emit_hdp_flush, - .emit_hdp_invalidate = gfx_v6_0_ring_emit_hdp_invalidate, .test_ring = gfx_v6_0_ring_test_ring, .test_ib = gfx_v6_0_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, + .emit_wreg = gfx_v6_0_ring_emit_wreg, }; static void gfx_v6_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index a066c5eda135..972d421caada 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -1946,7 +1946,7 @@ static void gfx_v7_0_gpu_init(struct amdgpu_device *adev) if (i == 0) sh_mem_base = 0; else - sh_mem_base = adev->mc.shared_aperture_start >> 48; + sh_mem_base = adev->gmc.shared_aperture_start >> 48; cik_srbm_select(adev, 0, 0, 0, i); /* CP and shaders */ WREG32(mmSH_MEM_CONFIG, sh_mem_cfg); @@ -2147,26 +2147,6 @@ static void gfx_v7_0_ring_emit_vgt_flush(struct amdgpu_ring *ring) EVENT_INDEX(0)); } - -/** - * gfx_v7_0_ring_emit_hdp_invalidate - emit an hdp invalidate on the cp - * - * @adev: amdgpu_device pointer - * @ridx: amdgpu ring index - * - * Emits an hdp invalidate on the cp. - */ -static void gfx_v7_0_ring_emit_hdp_invalidate(struct amdgpu_ring *ring) -{ - amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | - WRITE_DATA_DST_SEL(0) | - WR_CONFIRM)); - amdgpu_ring_write(ring, mmHDP_DEBUG0); - amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, 1); -} - /** * gfx_v7_0_ring_emit_fence_gfx - emit a fence on the gfx ring * @@ -3243,26 +3223,7 @@ static void gfx_v7_0_ring_emit_vm_flush(struct amdgpu_ring *ring, { int usepfp = (ring->funcs->type == AMDGPU_RING_TYPE_GFX); - amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | - WRITE_DATA_DST_SEL(0))); - if (vmid < 8) { - amdgpu_ring_write(ring, - (mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR + vmid)); - } else { - amdgpu_ring_write(ring, - (mmVM_CONTEXT8_PAGE_TABLE_BASE_ADDR + vmid - 8)); - } - amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, pd_addr >> 12); - - /* bits 0-15 are the VM contexts0-15 */ - amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | - WRITE_DATA_DST_SEL(0))); - amdgpu_ring_write(ring, mmVM_INVALIDATE_REQUEST); - amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, 1 << vmid); + amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); /* wait for the invalidate to complete */ amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); @@ -3289,6 +3250,19 @@ static void gfx_v7_0_ring_emit_vm_flush(struct amdgpu_ring *ring, } } +static void gfx_v7_0_ring_emit_wreg(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val) +{ + int usepfp = (ring->funcs->type == AMDGPU_RING_TYPE_GFX); + + amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); + amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | + WRITE_DATA_DST_SEL(0))); + amdgpu_ring_write(ring, reg); + amdgpu_ring_write(ring, 0); + amdgpu_ring_write(ring, val); +} + /* * RLC * The RLC is a multi-purpose microengine that handles a @@ -5115,10 +5089,10 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_gfx = { .emit_frame_size = 20 + /* gfx_v7_0_ring_emit_gds_switch */ 7 + /* gfx_v7_0_ring_emit_hdp_flush */ - 5 + /* gfx_v7_0_ring_emit_hdp_invalidate */ + 5 + /* hdp invalidate */ 12 + 12 + 12 + /* gfx_v7_0_ring_emit_fence_gfx x3 for user fence, vm fence */ 7 + 4 + /* gfx_v7_0_ring_emit_pipeline_sync */ - 17 + 6 + /* gfx_v7_0_ring_emit_vm_flush */ + CIK_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + 6 + /* gfx_v7_0_ring_emit_vm_flush */ 3 + 4, /* gfx_v7_ring_emit_cntxcntl including vgt flush*/ .emit_ib_size = 4, /* gfx_v7_0_ring_emit_ib_gfx */ .emit_ib = gfx_v7_0_ring_emit_ib_gfx, @@ -5127,12 +5101,12 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_gfx = { .emit_vm_flush = gfx_v7_0_ring_emit_vm_flush, .emit_gds_switch = gfx_v7_0_ring_emit_gds_switch, .emit_hdp_flush = gfx_v7_0_ring_emit_hdp_flush, - .emit_hdp_invalidate = gfx_v7_0_ring_emit_hdp_invalidate, .test_ring = gfx_v7_0_ring_test_ring, .test_ib = gfx_v7_0_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, .pad_ib = amdgpu_ring_generic_pad_ib, .emit_cntxcntl = gfx_v7_ring_emit_cntxcntl, + .emit_wreg = gfx_v7_0_ring_emit_wreg, }; static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_compute = { @@ -5146,9 +5120,9 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_compute = { .emit_frame_size = 20 + /* gfx_v7_0_ring_emit_gds_switch */ 7 + /* gfx_v7_0_ring_emit_hdp_flush */ - 5 + /* gfx_v7_0_ring_emit_hdp_invalidate */ + 5 + /* hdp invalidate */ 7 + /* gfx_v7_0_ring_emit_pipeline_sync */ - 17 + /* gfx_v7_0_ring_emit_vm_flush */ + CIK_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + /* gfx_v7_0_ring_emit_vm_flush */ 7 + 7 + 7, /* gfx_v7_0_ring_emit_fence_compute x3 for user fence, vm fence */ .emit_ib_size = 4, /* gfx_v7_0_ring_emit_ib_compute */ .emit_ib = gfx_v7_0_ring_emit_ib_compute, @@ -5157,11 +5131,11 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_compute = { .emit_vm_flush = gfx_v7_0_ring_emit_vm_flush, .emit_gds_switch = gfx_v7_0_ring_emit_gds_switch, .emit_hdp_flush = gfx_v7_0_ring_emit_hdp_flush, - .emit_hdp_invalidate = gfx_v7_0_ring_emit_hdp_invalidate, .test_ring = gfx_v7_0_ring_test_ring, .test_ib = gfx_v7_0_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, .pad_ib = amdgpu_ring_generic_pad_ib, + .emit_wreg = gfx_v7_0_ring_emit_wreg, }; static void gfx_v7_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 4e694ae9f308..27943e57681c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -3796,7 +3796,7 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev) tmp = REG_SET_FIELD(tmp, SH_MEM_CONFIG, ALIGNMENT_MODE, SH_MEM_ALIGNMENT_MODE_UNALIGNED); WREG32(mmSH_MEM_CONFIG, tmp); - tmp = adev->mc.shared_aperture_start >> 48; + tmp = adev->gmc.shared_aperture_start >> 48; WREG32(mmSH_MEM_BASES, tmp); } @@ -4847,6 +4847,9 @@ static int gfx_v8_0_kcq_init_queue(struct amdgpu_ring *ring) /* reset MQD to a clean status */ if (adev->gfx.mec.mqd_backup[mqd_idx]) memcpy(mqd, adev->gfx.mec.mqd_backup[mqd_idx], sizeof(struct vi_mqd_allocation)); + /* reset ring buffer */ + ring->wptr = 0; + amdgpu_ring_clear_ring(ring); } else { amdgpu_ring_clear_ring(ring); } @@ -4921,13 +4924,6 @@ static int gfx_v8_0_kiq_resume(struct amdgpu_device *adev) /* Test KCQs */ for (i = 0; i < adev->gfx.num_compute_rings; i++) { ring = &adev->gfx.compute_ring[i]; - if (adev->in_gpu_reset) { - /* move reset ring buffer to here to workaround - * compute ring test failed - */ - ring->wptr = 0; - amdgpu_ring_clear_ring(ring); - } ring->ready = true; r = amdgpu_ring_test_ring(ring); if (r) @@ -6230,19 +6226,6 @@ static void gfx_v8_0_ring_emit_vgt_flush(struct amdgpu_ring *ring) EVENT_INDEX(0)); } - -static void gfx_v8_0_ring_emit_hdp_invalidate(struct amdgpu_ring *ring) -{ - amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | - WRITE_DATA_DST_SEL(0) | - WR_CONFIRM)); - amdgpu_ring_write(ring, mmHDP_DEBUG0); - amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, 1); - -} - static void gfx_v8_0_ring_emit_ib_gfx(struct amdgpu_ring *ring, struct amdgpu_ib *ib, unsigned vmid, bool ctx_switch) @@ -6332,28 +6315,7 @@ static void gfx_v8_0_ring_emit_vm_flush(struct amdgpu_ring *ring, { int usepfp = (ring->funcs->type == AMDGPU_RING_TYPE_GFX); - amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | - WRITE_DATA_DST_SEL(0)) | - WR_CONFIRM); - if (vmid < 8) { - amdgpu_ring_write(ring, - (mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR + vmid)); - } else { - amdgpu_ring_write(ring, - (mmVM_CONTEXT8_PAGE_TABLE_BASE_ADDR + vmid - 8)); - } - amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, pd_addr >> 12); - - /* bits 0-15 are the VM contexts0-15 */ - /* invalidate the cache */ - amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | - WRITE_DATA_DST_SEL(0))); - amdgpu_ring_write(ring, mmVM_INVALIDATE_REQUEST); - amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, 1 << vmid); + amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); /* wait for the invalidate to complete */ amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); @@ -6617,8 +6579,22 @@ static void gfx_v8_0_ring_emit_rreg(struct amdgpu_ring *ring, uint32_t reg) static void gfx_v8_0_ring_emit_wreg(struct amdgpu_ring *ring, uint32_t reg, uint32_t val) { + uint32_t cmd; + + switch (ring->funcs->type) { + case AMDGPU_RING_TYPE_GFX: + cmd = WRITE_DATA_ENGINE_SEL(1) | WR_CONFIRM; + break; + case AMDGPU_RING_TYPE_KIQ: + cmd = 1 << 16; /* no inc addr */ + break; + default: + cmd = WR_CONFIRM; + break; + } + amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - amdgpu_ring_write(ring, (1 << 16)); /* no inc addr */ + amdgpu_ring_write(ring, cmd); amdgpu_ring_write(ring, reg); amdgpu_ring_write(ring, 0); amdgpu_ring_write(ring, val); @@ -6871,7 +6847,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_gfx = { .emit_frame_size = /* maximum 215dw if count 16 IBs in */ 5 + /* COND_EXEC */ 7 + /* PIPELINE_SYNC */ - 19 + /* VM_FLUSH */ + VI_FLUSH_GPU_TLB_NUM_WREG * 5 + 9 + /* VM_FLUSH */ 8 + /* FENCE for VM_FLUSH */ 20 + /* GDS switch */ 4 + /* double SWITCH_BUFFER, @@ -6893,7 +6869,6 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_gfx = { .emit_vm_flush = gfx_v8_0_ring_emit_vm_flush, .emit_gds_switch = gfx_v8_0_ring_emit_gds_switch, .emit_hdp_flush = gfx_v8_0_ring_emit_hdp_flush, - .emit_hdp_invalidate = gfx_v8_0_ring_emit_hdp_invalidate, .test_ring = gfx_v8_0_ring_test_ring, .test_ib = gfx_v8_0_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, @@ -6902,6 +6877,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_gfx = { .emit_cntxcntl = gfx_v8_ring_emit_cntxcntl, .init_cond_exec = gfx_v8_0_ring_emit_init_cond_exec, .patch_cond_exec = gfx_v8_0_ring_emit_patch_cond_exec, + .emit_wreg = gfx_v8_0_ring_emit_wreg, }; static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = { @@ -6915,9 +6891,9 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = { .emit_frame_size = 20 + /* gfx_v8_0_ring_emit_gds_switch */ 7 + /* gfx_v8_0_ring_emit_hdp_flush */ - 5 + /* gfx_v8_0_ring_emit_hdp_invalidate */ + 5 + /* hdp_invalidate */ 7 + /* gfx_v8_0_ring_emit_pipeline_sync */ - 17 + /* gfx_v8_0_ring_emit_vm_flush */ + VI_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + /* gfx_v8_0_ring_emit_vm_flush */ 7 + 7 + 7, /* gfx_v8_0_ring_emit_fence_compute x3 for user fence, vm fence */ .emit_ib_size = 4, /* gfx_v8_0_ring_emit_ib_compute */ .emit_ib = gfx_v8_0_ring_emit_ib_compute, @@ -6926,12 +6902,12 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = { .emit_vm_flush = gfx_v8_0_ring_emit_vm_flush, .emit_gds_switch = gfx_v8_0_ring_emit_gds_switch, .emit_hdp_flush = gfx_v8_0_ring_emit_hdp_flush, - .emit_hdp_invalidate = gfx_v8_0_ring_emit_hdp_invalidate, .test_ring = gfx_v8_0_ring_test_ring, .test_ib = gfx_v8_0_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, .pad_ib = amdgpu_ring_generic_pad_ib, .set_priority = gfx_v8_0_ring_set_priority_compute, + .emit_wreg = gfx_v8_0_ring_emit_wreg, }; static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_kiq = { @@ -6945,7 +6921,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_kiq = { .emit_frame_size = 20 + /* gfx_v8_0_ring_emit_gds_switch */ 7 + /* gfx_v8_0_ring_emit_hdp_flush */ - 5 + /* gfx_v8_0_ring_emit_hdp_invalidate */ + 5 + /* hdp_invalidate */ 7 + /* gfx_v8_0_ring_emit_pipeline_sync */ 17 + /* gfx_v8_0_ring_emit_vm_flush */ 7 + 7 + 7, /* gfx_v8_0_ring_emit_fence_kiq x3 for user fence, vm fence */ @@ -7151,12 +7127,12 @@ static void gfx_v8_0_ring_emit_ce_meta(struct amdgpu_ring *ring) } ce_payload = {}; if (ring->adev->virt.chained_ib_support) { - ce_payload_addr = AMDGPU_VA_RESERVED_SIZE - 2 * 4096 + - offsetof(struct vi_gfx_meta_data_chained_ib, ce_payload); + ce_payload_addr = amdgpu_csa_vaddr(ring->adev) + + offsetof(struct vi_gfx_meta_data_chained_ib, ce_payload); cnt_ce = (sizeof(ce_payload.chained) >> 2) + 4 - 2; } else { - ce_payload_addr = AMDGPU_VA_RESERVED_SIZE - 2 * 4096 + - offsetof(struct vi_gfx_meta_data, ce_payload); + ce_payload_addr = amdgpu_csa_vaddr(ring->adev) + + offsetof(struct vi_gfx_meta_data, ce_payload); cnt_ce = (sizeof(ce_payload.regular) >> 2) + 4 - 2; } @@ -7179,7 +7155,7 @@ static void gfx_v8_0_ring_emit_de_meta(struct amdgpu_ring *ring) struct vi_de_ib_state_chained_ib chained; } de_payload = {}; - csa_addr = AMDGPU_VA_RESERVED_SIZE - 2 * 4096; + csa_addr = amdgpu_csa_vaddr(ring->adev); gds_addr = csa_addr + 4096; if (ring->adev->virt.chained_ib_support) { de_payload.chained.gds_backup_addrlo = lower_32_bits(gds_addr); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index c06479615e8a..848008ef46b8 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -1539,7 +1539,7 @@ static void gfx_v9_0_gpu_init(struct amdgpu_device *adev) tmp = REG_SET_FIELD(0, SH_MEM_CONFIG, ALIGNMENT_MODE, SH_MEM_ALIGNMENT_MODE_UNALIGNED); WREG32_SOC15(GC, 0, mmSH_MEM_CONFIG, tmp); - tmp = adev->mc.shared_aperture_start >> 48; + tmp = adev->gmc.shared_aperture_start >> 48; WREG32_SOC15(GC, 0, mmSH_MEM_BASES, tmp); } } @@ -3585,14 +3585,6 @@ static void gfx_v9_0_ring_emit_hdp_flush(struct amdgpu_ring *ring) ref_and_mask, ref_and_mask, 0x20); } -static void gfx_v9_0_ring_emit_hdp_invalidate(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - - gfx_v9_0_write_data_to_reg(ring, 0, true, - SOC15_REG_OFFSET(HDP, 0, mmHDP_READ_CACHE_INVALIDATE), 1); -} - static void gfx_v9_0_ring_emit_ib_gfx(struct amdgpu_ring *ring, struct amdgpu_ib *ib, unsigned vmid, bool ctx_switch) @@ -3686,32 +3678,10 @@ static void gfx_v9_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring) static void gfx_v9_0_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { - struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; - int usepfp = (ring->funcs->type == AMDGPU_RING_TYPE_GFX); - uint32_t req = ring->adev->gart.gart_funcs->get_invalidate_req(vmid); - uint64_t flags = AMDGPU_PTE_VALID; - unsigned eng = ring->vm_inv_eng; - - amdgpu_gart_get_vm_pde(ring->adev, -1, &pd_addr, &flags); - pd_addr |= flags; - - gfx_v9_0_write_data_to_reg(ring, usepfp, true, - hub->ctx0_ptb_addr_lo32 + (2 * vmid), - lower_32_bits(pd_addr)); - - gfx_v9_0_write_data_to_reg(ring, usepfp, true, - hub->ctx0_ptb_addr_hi32 + (2 * vmid), - upper_32_bits(pd_addr)); - - gfx_v9_0_write_data_to_reg(ring, usepfp, true, - hub->vm_inv_eng0_req + eng, req); - - /* wait for the invalidate to complete */ - gfx_v9_0_wait_reg_mem(ring, 0, 0, 0, hub->vm_inv_eng0_ack + - eng, 0, 1 << vmid, 1 << vmid, 0x20); + amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); /* compute doesn't have PFP */ - if (usepfp) { + if (ring->funcs->type == AMDGPU_RING_TYPE_GFX) { /* sync PFP to ME, otherwise we might get invalid PFP reads */ amdgpu_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); amdgpu_ring_write(ring, 0x0); @@ -3735,6 +3705,105 @@ static u64 gfx_v9_0_ring_get_wptr_compute(struct amdgpu_ring *ring) return wptr; } +static void gfx_v9_0_ring_set_pipe_percent(struct amdgpu_ring *ring, + bool acquire) +{ + struct amdgpu_device *adev = ring->adev; + int pipe_num, tmp, reg; + int pipe_percent = acquire ? SPI_WCL_PIPE_PERCENT_GFX__VALUE_MASK : 0x1; + + pipe_num = ring->me * adev->gfx.mec.num_pipe_per_mec + ring->pipe; + + /* first me only has 2 entries, GFX and HP3D */ + if (ring->me > 0) + pipe_num -= 2; + + reg = SOC15_REG_OFFSET(GC, 0, mmSPI_WCL_PIPE_PERCENT_GFX) + pipe_num; + tmp = RREG32(reg); + tmp = REG_SET_FIELD(tmp, SPI_WCL_PIPE_PERCENT_GFX, VALUE, pipe_percent); + WREG32(reg, tmp); +} + +static void gfx_v9_0_pipe_reserve_resources(struct amdgpu_device *adev, + struct amdgpu_ring *ring, + bool acquire) +{ + int i, pipe; + bool reserve; + struct amdgpu_ring *iring; + + mutex_lock(&adev->gfx.pipe_reserve_mutex); + pipe = amdgpu_gfx_queue_to_bit(adev, ring->me, ring->pipe, 0); + if (acquire) + set_bit(pipe, adev->gfx.pipe_reserve_bitmap); + else + clear_bit(pipe, adev->gfx.pipe_reserve_bitmap); + + if (!bitmap_weight(adev->gfx.pipe_reserve_bitmap, AMDGPU_MAX_COMPUTE_QUEUES)) { + /* Clear all reservations - everyone reacquires all resources */ + for (i = 0; i < adev->gfx.num_gfx_rings; ++i) + gfx_v9_0_ring_set_pipe_percent(&adev->gfx.gfx_ring[i], + true); + + for (i = 0; i < adev->gfx.num_compute_rings; ++i) + gfx_v9_0_ring_set_pipe_percent(&adev->gfx.compute_ring[i], + true); + } else { + /* Lower all pipes without a current reservation */ + for (i = 0; i < adev->gfx.num_gfx_rings; ++i) { + iring = &adev->gfx.gfx_ring[i]; + pipe = amdgpu_gfx_queue_to_bit(adev, + iring->me, + iring->pipe, + 0); + reserve = test_bit(pipe, adev->gfx.pipe_reserve_bitmap); + gfx_v9_0_ring_set_pipe_percent(iring, reserve); + } + + for (i = 0; i < adev->gfx.num_compute_rings; ++i) { + iring = &adev->gfx.compute_ring[i]; + pipe = amdgpu_gfx_queue_to_bit(adev, + iring->me, + iring->pipe, + 0); + reserve = test_bit(pipe, adev->gfx.pipe_reserve_bitmap); + gfx_v9_0_ring_set_pipe_percent(iring, reserve); + } + } + + mutex_unlock(&adev->gfx.pipe_reserve_mutex); +} + +static void gfx_v9_0_hqd_set_priority(struct amdgpu_device *adev, + struct amdgpu_ring *ring, + bool acquire) +{ + uint32_t pipe_priority = acquire ? 0x2 : 0x0; + uint32_t queue_priority = acquire ? 0xf : 0x0; + + mutex_lock(&adev->srbm_mutex); + soc15_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0); + + WREG32_SOC15(GC, 0, mmCP_HQD_PIPE_PRIORITY, pipe_priority); + WREG32_SOC15(GC, 0, mmCP_HQD_QUEUE_PRIORITY, queue_priority); + + soc15_grbm_select(adev, 0, 0, 0, 0); + mutex_unlock(&adev->srbm_mutex); +} + +static void gfx_v9_0_ring_set_priority_compute(struct amdgpu_ring *ring, + enum drm_sched_priority priority) +{ + struct amdgpu_device *adev = ring->adev; + bool acquire = priority == DRM_SCHED_PRIORITY_HIGH_HW; + + if (ring->funcs->type != AMDGPU_RING_TYPE_COMPUTE) + return; + + gfx_v9_0_hqd_set_priority(adev, ring, acquire); + gfx_v9_0_pipe_reserve_resources(adev, ring, acquire); +} + static void gfx_v9_0_ring_set_wptr_compute(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; @@ -3788,7 +3857,7 @@ static void gfx_v9_0_ring_emit_ce_meta(struct amdgpu_ring *ring) int cnt; cnt = (sizeof(ce_payload) >> 2) + 4 - 2; - csa_addr = AMDGPU_VA_RESERVED_SIZE - 2 * 4096; + csa_addr = amdgpu_csa_vaddr(ring->adev); amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, cnt)); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(2) | @@ -3806,7 +3875,7 @@ static void gfx_v9_0_ring_emit_de_meta(struct amdgpu_ring *ring) uint64_t csa_addr, gds_addr; int cnt; - csa_addr = AMDGPU_VA_RESERVED_SIZE - 2 * 4096; + csa_addr = amdgpu_csa_vaddr(ring->adev); gds_addr = csa_addr + 4096; de_payload.gds_backup_addrlo = lower_32_bits(gds_addr); de_payload.gds_backup_addrhi = upper_32_bits(gds_addr); @@ -3904,15 +3973,34 @@ static void gfx_v9_0_ring_emit_rreg(struct amdgpu_ring *ring, uint32_t reg) } static void gfx_v9_0_ring_emit_wreg(struct amdgpu_ring *ring, uint32_t reg, - uint32_t val) + uint32_t val) { + uint32_t cmd = 0; + + switch (ring->funcs->type) { + case AMDGPU_RING_TYPE_GFX: + cmd = WRITE_DATA_ENGINE_SEL(1) | WR_CONFIRM; + break; + case AMDGPU_RING_TYPE_KIQ: + cmd = (1 << 16); /* no inc addr */ + break; + default: + cmd = WR_CONFIRM; + break; + } amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - amdgpu_ring_write(ring, (1 << 16)); /* no inc addr */ + amdgpu_ring_write(ring, cmd); amdgpu_ring_write(ring, reg); amdgpu_ring_write(ring, 0); amdgpu_ring_write(ring, val); } +static void gfx_v9_0_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg, + uint32_t val, uint32_t mask) +{ + gfx_v9_0_wait_reg_mem(ring, 0, 0, 0, reg, 0, val, mask, 0x20); +} + static void gfx_v9_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev, enum amdgpu_interrupt_state state) { @@ -4199,7 +4287,9 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_gfx = { .emit_frame_size = /* totally 242 maximum if 16 IBs */ 5 + /* COND_EXEC */ 7 + /* PIPELINE_SYNC */ - 24 + /* VM_FLUSH */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 5 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + + 2 + /* VM_FLUSH */ 8 + /* FENCE for VM_FLUSH */ 20 + /* GDS switch */ 4 + /* double SWITCH_BUFFER, @@ -4221,7 +4311,6 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_gfx = { .emit_vm_flush = gfx_v9_0_ring_emit_vm_flush, .emit_gds_switch = gfx_v9_0_ring_emit_gds_switch, .emit_hdp_flush = gfx_v9_0_ring_emit_hdp_flush, - .emit_hdp_invalidate = gfx_v9_0_ring_emit_hdp_invalidate, .test_ring = gfx_v9_0_ring_test_ring, .test_ib = gfx_v9_0_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, @@ -4231,6 +4320,8 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_gfx = { .init_cond_exec = gfx_v9_0_ring_emit_init_cond_exec, .patch_cond_exec = gfx_v9_0_ring_emit_patch_cond_exec, .emit_tmz = gfx_v9_0_ring_emit_tmz, + .emit_wreg = gfx_v9_0_ring_emit_wreg, + .emit_reg_wait = gfx_v9_0_ring_emit_reg_wait, }; static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_compute = { @@ -4245,9 +4336,11 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_compute = { .emit_frame_size = 20 + /* gfx_v9_0_ring_emit_gds_switch */ 7 + /* gfx_v9_0_ring_emit_hdp_flush */ - 5 + /* gfx_v9_0_ring_emit_hdp_invalidate */ + 5 + /* hdp invalidate */ 7 + /* gfx_v9_0_ring_emit_pipeline_sync */ - 24 + /* gfx_v9_0_ring_emit_vm_flush */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 5 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + + 2 + /* gfx_v9_0_ring_emit_vm_flush */ 8 + 8 + 8, /* gfx_v9_0_ring_emit_fence x3 for user fence, vm fence */ .emit_ib_size = 4, /* gfx_v9_0_ring_emit_ib_compute */ .emit_ib = gfx_v9_0_ring_emit_ib_compute, @@ -4256,11 +4349,13 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_compute = { .emit_vm_flush = gfx_v9_0_ring_emit_vm_flush, .emit_gds_switch = gfx_v9_0_ring_emit_gds_switch, .emit_hdp_flush = gfx_v9_0_ring_emit_hdp_flush, - .emit_hdp_invalidate = gfx_v9_0_ring_emit_hdp_invalidate, .test_ring = gfx_v9_0_ring_test_ring, .test_ib = gfx_v9_0_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, .pad_ib = amdgpu_ring_generic_pad_ib, + .set_priority = gfx_v9_0_ring_set_priority_compute, + .emit_wreg = gfx_v9_0_ring_emit_wreg, + .emit_reg_wait = gfx_v9_0_ring_emit_reg_wait, }; static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_kiq = { @@ -4275,9 +4370,11 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_kiq = { .emit_frame_size = 20 + /* gfx_v9_0_ring_emit_gds_switch */ 7 + /* gfx_v9_0_ring_emit_hdp_flush */ - 5 + /* gfx_v9_0_ring_emit_hdp_invalidate */ + 5 + /* hdp invalidate */ 7 + /* gfx_v9_0_ring_emit_pipeline_sync */ - 24 + /* gfx_v9_0_ring_emit_vm_flush */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 5 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + + 2 + /* gfx_v9_0_ring_emit_vm_flush */ 8 + 8 + 8, /* gfx_v9_0_ring_emit_fence_kiq x3 for user fence, vm fence */ .emit_ib_size = 4, /* gfx_v9_0_ring_emit_ib_compute */ .emit_ib = gfx_v9_0_ring_emit_ib_compute, @@ -4288,6 +4385,7 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_kiq = { .pad_ib = amdgpu_ring_generic_pad_ib, .emit_rreg = gfx_v9_0_ring_emit_rreg, .emit_wreg = gfx_v9_0_ring_emit_wreg, + .emit_reg_wait = gfx_v9_0_ring_emit_reg_wait, }; static void gfx_v9_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c index 56f5fe4e2fee..94a07bcbbdda 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c @@ -40,7 +40,7 @@ static void gfxhub_v1_0_init_gart_pt_regs(struct amdgpu_device *adev) uint64_t value; BUG_ON(adev->gart.table_addr & (~0x0000FFFFFFFFF000ULL)); - value = adev->gart.table_addr - adev->mc.vram_start + value = adev->gart.table_addr - adev->gmc.vram_start + adev->vm_manager.vram_base_offset; value &= 0x0000FFFFFFFFF000ULL; value |= 0x1; /*valid bit*/ @@ -57,14 +57,14 @@ static void gfxhub_v1_0_init_gart_aperture_regs(struct amdgpu_device *adev) gfxhub_v1_0_init_gart_pt_regs(adev); WREG32_SOC15(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32, - (u32)(adev->mc.gart_start >> 12)); + (u32)(adev->gmc.gart_start >> 12)); WREG32_SOC15(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32, - (u32)(adev->mc.gart_start >> 44)); + (u32)(adev->gmc.gart_start >> 44)); WREG32_SOC15(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32, - (u32)(adev->mc.gart_end >> 12)); + (u32)(adev->gmc.gart_end >> 12)); WREG32_SOC15(GC, 0, mmVM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32, - (u32)(adev->mc.gart_end >> 44)); + (u32)(adev->gmc.gart_end >> 44)); } static void gfxhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev) @@ -78,12 +78,12 @@ static void gfxhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev) /* Program the system aperture low logical page number. */ WREG32_SOC15(GC, 0, mmMC_VM_SYSTEM_APERTURE_LOW_ADDR, - adev->mc.vram_start >> 18); + adev->gmc.vram_start >> 18); WREG32_SOC15(GC, 0, mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR, - adev->mc.vram_end >> 18); + adev->gmc.vram_end >> 18); /* Set default page address. */ - value = adev->vram_scratch.gpu_addr - adev->mc.vram_start + value = adev->vram_scratch.gpu_addr - adev->gmc.vram_start + adev->vm_manager.vram_base_offset; WREG32_SOC15(GC, 0, mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, (u32)(value >> 12)); @@ -143,7 +143,7 @@ static void gfxhub_v1_0_init_cache_regs(struct amdgpu_device *adev) WREG32_SOC15(GC, 0, mmVM_L2_CNTL2, tmp); tmp = mmVM_L2_CNTL3_DEFAULT; - if (adev->mc.translate_further) { + if (adev->gmc.translate_further) { tmp = REG_SET_FIELD(tmp, VM_L2_CNTL3, BANK_SELECT, 12); tmp = REG_SET_FIELD(tmp, VM_L2_CNTL3, L2_CACHE_BIGK_FRAGMENT_SIZE, 9); @@ -195,7 +195,7 @@ static void gfxhub_v1_0_setup_vmid_config(struct amdgpu_device *adev) num_level = adev->vm_manager.num_level; block_size = adev->vm_manager.block_size; - if (adev->mc.translate_further) + if (adev->gmc.translate_further) num_level -= 1; else block_size -= 9; @@ -257,9 +257,9 @@ int gfxhub_v1_0_gart_enable(struct amdgpu_device *adev) * SRIOV driver need to program them */ WREG32_SOC15(GC, 0, mmMC_VM_FB_LOCATION_BASE, - adev->mc.vram_start >> 24); + adev->gmc.vram_start >> 24); WREG32_SOC15(GC, 0, mmMC_VM_FB_LOCATION_TOP, - adev->mc.vram_end >> 24); + adev->gmc.vram_end >> 24); } /* GART Enable. */ diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c index 8e28270d1ea9..2c0ed9dd0c91 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c @@ -22,6 +22,7 @@ */ #include #include +#include #include "amdgpu.h" #include "gmc_v6_0.h" #include "amdgpu_ucode.h" @@ -36,7 +37,7 @@ #include "dce/dce_6_0_sh_mask.h" #include "si_enums.h" -static void gmc_v6_0_set_gart_funcs(struct amdgpu_device *adev); +static void gmc_v6_0_set_gmc_funcs(struct amdgpu_device *adev); static void gmc_v6_0_set_irq_funcs(struct amdgpu_device *adev); static int gmc_v6_0_wait_for_idle(void *handle); @@ -136,19 +137,19 @@ static int gmc_v6_0_init_microcode(struct amdgpu_device *adev) snprintf(fw_name, sizeof(fw_name), "radeon/si58_mc.bin"); else snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); - err = request_firmware(&adev->mc.fw, fw_name, adev->dev); + err = request_firmware(&adev->gmc.fw, fw_name, adev->dev); if (err) goto out; - err = amdgpu_ucode_validate(adev->mc.fw); + err = amdgpu_ucode_validate(adev->gmc.fw); out: if (err) { dev_err(adev->dev, "si_mc: Failed to load firmware \"%s\"\n", fw_name); - release_firmware(adev->mc.fw); - adev->mc.fw = NULL; + release_firmware(adev->gmc.fw); + adev->gmc.fw = NULL; } return err; } @@ -161,20 +162,20 @@ static int gmc_v6_0_mc_load_microcode(struct amdgpu_device *adev) int i, regs_size, ucode_size; const struct mc_firmware_header_v1_0 *hdr; - if (!adev->mc.fw) + if (!adev->gmc.fw) return -EINVAL; - hdr = (const struct mc_firmware_header_v1_0 *)adev->mc.fw->data; + hdr = (const struct mc_firmware_header_v1_0 *)adev->gmc.fw->data; amdgpu_ucode_print_mc_hdr(&hdr->header); - adev->mc.fw_version = le32_to_cpu(hdr->header.ucode_version); + adev->gmc.fw_version = le32_to_cpu(hdr->header.ucode_version); regs_size = le32_to_cpu(hdr->io_debug_size_bytes) / (4 * 2); new_io_mc_regs = (const __le32 *) - (adev->mc.fw->data + le32_to_cpu(hdr->io_debug_array_offset_bytes)); + (adev->gmc.fw->data + le32_to_cpu(hdr->io_debug_array_offset_bytes)); ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; new_fw_data = (const __le32 *) - (adev->mc.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + (adev->gmc.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); running = RREG32(mmMC_SEQ_SUP_CNTL) & MC_SEQ_SUP_CNTL__RUN_MASK; @@ -217,12 +218,12 @@ static int gmc_v6_0_mc_load_microcode(struct amdgpu_device *adev) } static void gmc_v6_0_vram_gtt_location(struct amdgpu_device *adev, - struct amdgpu_mc *mc) + struct amdgpu_gmc *mc) { u64 base = RREG32(mmMC_VM_FB_LOCATION) & 0xFFFF; base <<= 24; - amdgpu_device_vram_location(adev, &adev->mc, base); + amdgpu_device_vram_location(adev, &adev->gmc, base); amdgpu_device_gart_location(adev, mc); } @@ -259,9 +260,9 @@ static void gmc_v6_0_mc_program(struct amdgpu_device *adev) } /* Update configuration */ WREG32(mmMC_VM_SYSTEM_APERTURE_LOW_ADDR, - adev->mc.vram_start >> 12); + adev->gmc.vram_start >> 12); WREG32(mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR, - adev->mc.vram_end >> 12); + adev->gmc.vram_end >> 12); WREG32(mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, adev->vram_scratch.gpu_addr >> 12); WREG32(mmMC_VM_AGP_BASE, 0); @@ -319,56 +320,69 @@ static int gmc_v6_0_mc_init(struct amdgpu_device *adev) numchan = 16; break; } - adev->mc.vram_width = numchan * chansize; + adev->gmc.vram_width = numchan * chansize; /* size in MB on si */ - adev->mc.mc_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL; - adev->mc.real_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL; + adev->gmc.mc_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL; + adev->gmc.real_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL; if (!(adev->flags & AMD_IS_APU)) { r = amdgpu_device_resize_fb_bar(adev); if (r) return r; } - adev->mc.aper_base = pci_resource_start(adev->pdev, 0); - adev->mc.aper_size = pci_resource_len(adev->pdev, 0); - adev->mc.visible_vram_size = adev->mc.aper_size; + adev->gmc.aper_base = pci_resource_start(adev->pdev, 0); + adev->gmc.aper_size = pci_resource_len(adev->pdev, 0); + adev->gmc.visible_vram_size = adev->gmc.aper_size; /* set the gart size */ if (amdgpu_gart_size == -1) { switch (adev->asic_type) { case CHIP_HAINAN: /* no MM engines */ default: - adev->mc.gart_size = 256ULL << 20; + adev->gmc.gart_size = 256ULL << 20; break; case CHIP_VERDE: /* UVD, VCE do not support GPUVM */ case CHIP_TAHITI: /* UVD, VCE do not support GPUVM */ case CHIP_PITCAIRN: /* UVD, VCE do not support GPUVM */ case CHIP_OLAND: /* UVD, VCE do not support GPUVM */ - adev->mc.gart_size = 1024ULL << 20; + adev->gmc.gart_size = 1024ULL << 20; break; } } else { - adev->mc.gart_size = (u64)amdgpu_gart_size << 20; + adev->gmc.gart_size = (u64)amdgpu_gart_size << 20; } - gmc_v6_0_vram_gtt_location(adev, &adev->mc); + gmc_v6_0_vram_gtt_location(adev, &adev->gmc); return 0; } -static void gmc_v6_0_gart_flush_gpu_tlb(struct amdgpu_device *adev, - uint32_t vmid) +static void gmc_v6_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid) { - WREG32(mmHDP_MEM_COHERENCY_FLUSH_CNTL, 0); - WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid); } -static int gmc_v6_0_gart_set_pte_pde(struct amdgpu_device *adev, - void *cpu_pt_addr, - uint32_t gpu_page_idx, - uint64_t addr, - uint64_t flags) +static uint64_t gmc_v6_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring, + unsigned vmid, uint64_t pd_addr) +{ + uint32_t reg; + + /* write new base address */ + if (vmid < 8) + reg = mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR + vmid; + else + reg = mmVM_CONTEXT8_PAGE_TABLE_BASE_ADDR + (vmid - 8); + amdgpu_ring_emit_wreg(ring, reg, pd_addr >> 12); + + /* bits 0-15 are the VM contexts0-15 */ + amdgpu_ring_emit_wreg(ring, mmVM_INVALIDATE_REQUEST, 1 << vmid); + + return pd_addr; +} + +static int gmc_v6_0_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr, + uint32_t gpu_page_idx, uint64_t addr, + uint64_t flags) { void __iomem *ptr = (void *)cpu_pt_addr; uint64_t value; @@ -432,9 +446,9 @@ static void gmc_v6_0_set_prt(struct amdgpu_device *adev, bool enable) { u32 tmp; - if (enable && !adev->mc.prt_warning) { + if (enable && !adev->gmc.prt_warning) { dev_warn(adev->dev, "Disabling VM faults because of PRT request!\n"); - adev->mc.prt_warning = true; + adev->gmc.prt_warning = true; } tmp = RREG32(mmVM_PRT_CNTL); @@ -454,7 +468,8 @@ static void gmc_v6_0_set_prt(struct amdgpu_device *adev, bool enable) if (enable) { uint32_t low = AMDGPU_VA_RESERVED_SIZE >> AMDGPU_GPU_PAGE_SHIFT; - uint32_t high = adev->vm_manager.max_pfn; + uint32_t high = adev->vm_manager.max_pfn - + (AMDGPU_VA_RESERVED_SIZE >> AMDGPU_GPU_PAGE_SHIFT); WREG32(mmVM_PRT_APERTURE0_LOW_ADDR, low); WREG32(mmVM_PRT_APERTURE1_LOW_ADDR, low); @@ -514,8 +529,8 @@ static int gmc_v6_0_gart_enable(struct amdgpu_device *adev) (field << VM_L2_CNTL3__BANK_SELECT__SHIFT) | (field << VM_L2_CNTL3__L2_CACHE_BIGK_FRAGMENT_SIZE__SHIFT)); /* setup context0 */ - WREG32(mmVM_CONTEXT0_PAGE_TABLE_START_ADDR, adev->mc.gart_start >> 12); - WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->mc.gart_end >> 12); + WREG32(mmVM_CONTEXT0_PAGE_TABLE_START_ADDR, adev->gmc.gart_start >> 12); + WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->gmc.gart_end >> 12); WREG32(mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR, adev->gart.table_addr >> 12); WREG32(mmVM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR, (u32)(adev->dummy_page.addr >> 12)); @@ -560,9 +575,9 @@ static int gmc_v6_0_gart_enable(struct amdgpu_device *adev) else gmc_v6_0_set_fault_enable_default(adev, true); - gmc_v6_0_gart_flush_gpu_tlb(adev, 0); + gmc_v6_0_flush_gpu_tlb(adev, 0); dev_info(adev->dev, "PCIE GART of %uM enabled (table at 0x%016llX).\n", - (unsigned)(adev->mc.gart_size >> 20), + (unsigned)(adev->gmc.gart_size >> 20), (unsigned long long)adev->gart.table_addr); adev->gart.ready = true; return 0; @@ -794,7 +809,7 @@ static int gmc_v6_0_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - gmc_v6_0_set_gart_funcs(adev); + gmc_v6_0_set_gmc_funcs(adev); gmc_v6_0_set_irq_funcs(adev); return 0; @@ -805,7 +820,7 @@ static int gmc_v6_0_late_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; if (amdgpu_vm_fault_stop != AMDGPU_VM_FAULT_STOP_ALWAYS) - return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0); + return amdgpu_irq_get(adev, &adev->gmc.vm_fault, 0); else return 0; } @@ -817,26 +832,26 @@ static int gmc_v6_0_sw_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; if (adev->flags & AMD_IS_APU) { - adev->mc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN; + adev->gmc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN; } else { u32 tmp = RREG32(mmMC_SEQ_MISC0); tmp &= MC_SEQ_MISC0__MT__MASK; - adev->mc.vram_type = gmc_v6_0_convert_vram_type(tmp); + adev->gmc.vram_type = gmc_v6_0_convert_vram_type(tmp); } - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 146, &adev->mc.vm_fault); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 146, &adev->gmc.vm_fault); if (r) return r; - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 147, &adev->mc.vm_fault); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 147, &adev->gmc.vm_fault); if (r) return r; amdgpu_vm_adjust_size(adev, 64, 9, 1, 40); - adev->mc.mc_mask = 0xffffffffffULL; + adev->gmc.mc_mask = 0xffffffffffULL; - adev->mc.stolen_size = 256 * 1024; + adev->gmc.stolen_size = 256 * 1024; adev->need_dma32 = false; dma_bits = adev->need_dma32 ? 32 : 40; @@ -851,6 +866,7 @@ static int gmc_v6_0_sw_init(void *handle) pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(32)); dev_warn(adev->dev, "amdgpu: No coherent DMA available.\n"); } + adev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits); r = gmc_v6_0_init_microcode(adev); if (r) { @@ -900,8 +916,8 @@ static int gmc_v6_0_sw_fini(void *handle) amdgpu_vm_manager_fini(adev); gmc_v6_0_gart_fini(adev); amdgpu_bo_fini(adev); - release_firmware(adev->mc.fw); - adev->mc.fw = NULL; + release_firmware(adev->gmc.fw); + adev->gmc.fw = NULL; return 0; } @@ -932,7 +948,7 @@ static int gmc_v6_0_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - amdgpu_irq_put(adev, &adev->mc.vm_fault, 0); + amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); gmc_v6_0_gart_disable(adev); return 0; @@ -1127,9 +1143,10 @@ static const struct amd_ip_funcs gmc_v6_0_ip_funcs = { .set_powergating_state = gmc_v6_0_set_powergating_state, }; -static const struct amdgpu_gart_funcs gmc_v6_0_gart_funcs = { - .flush_gpu_tlb = gmc_v6_0_gart_flush_gpu_tlb, - .set_pte_pde = gmc_v6_0_gart_set_pte_pde, +static const struct amdgpu_gmc_funcs gmc_v6_0_gmc_funcs = { + .flush_gpu_tlb = gmc_v6_0_flush_gpu_tlb, + .emit_flush_gpu_tlb = gmc_v6_0_emit_flush_gpu_tlb, + .set_pte_pde = gmc_v6_0_set_pte_pde, .set_prt = gmc_v6_0_set_prt, .get_vm_pde = gmc_v6_0_get_vm_pde, .get_vm_pte_flags = gmc_v6_0_get_vm_pte_flags @@ -1140,16 +1157,16 @@ static const struct amdgpu_irq_src_funcs gmc_v6_0_irq_funcs = { .process = gmc_v6_0_process_interrupt, }; -static void gmc_v6_0_set_gart_funcs(struct amdgpu_device *adev) +static void gmc_v6_0_set_gmc_funcs(struct amdgpu_device *adev) { - if (adev->gart.gart_funcs == NULL) - adev->gart.gart_funcs = &gmc_v6_0_gart_funcs; + if (adev->gmc.gmc_funcs == NULL) + adev->gmc.gmc_funcs = &gmc_v6_0_gmc_funcs; } static void gmc_v6_0_set_irq_funcs(struct amdgpu_device *adev) { - adev->mc.vm_fault.num_types = 1; - adev->mc.vm_fault.funcs = &gmc_v6_0_irq_funcs; + adev->gmc.vm_fault.num_types = 1; + adev->gmc.vm_fault.funcs = &gmc_v6_0_irq_funcs; } const struct amdgpu_ip_block_version gmc_v6_0_ip_block = diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index 86e9d682c59e..4edd17059868 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -22,6 +22,7 @@ */ #include #include +#include #include "amdgpu.h" #include "cikd.h" #include "cik.h" @@ -42,7 +43,7 @@ #include "amdgpu_atombios.h" -static void gmc_v7_0_set_gart_funcs(struct amdgpu_device *adev); +static void gmc_v7_0_set_gmc_funcs(struct amdgpu_device *adev); static void gmc_v7_0_set_irq_funcs(struct amdgpu_device *adev); static int gmc_v7_0_wait_for_idle(void *handle); @@ -151,16 +152,16 @@ static int gmc_v7_0_init_microcode(struct amdgpu_device *adev) else snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); - err = request_firmware(&adev->mc.fw, fw_name, adev->dev); + err = request_firmware(&adev->gmc.fw, fw_name, adev->dev); if (err) goto out; - err = amdgpu_ucode_validate(adev->mc.fw); + err = amdgpu_ucode_validate(adev->gmc.fw); out: if (err) { pr_err("cik_mc: Failed to load firmware \"%s\"\n", fw_name); - release_firmware(adev->mc.fw); - adev->mc.fw = NULL; + release_firmware(adev->gmc.fw); + adev->gmc.fw = NULL; } return err; } @@ -181,19 +182,19 @@ static int gmc_v7_0_mc_load_microcode(struct amdgpu_device *adev) u32 running; int i, ucode_size, regs_size; - if (!adev->mc.fw) + if (!adev->gmc.fw) return -EINVAL; - hdr = (const struct mc_firmware_header_v1_0 *)adev->mc.fw->data; + hdr = (const struct mc_firmware_header_v1_0 *)adev->gmc.fw->data; amdgpu_ucode_print_mc_hdr(&hdr->header); - adev->mc.fw_version = le32_to_cpu(hdr->header.ucode_version); + adev->gmc.fw_version = le32_to_cpu(hdr->header.ucode_version); regs_size = le32_to_cpu(hdr->io_debug_size_bytes) / (4 * 2); io_mc_regs = (const __le32 *) - (adev->mc.fw->data + le32_to_cpu(hdr->io_debug_array_offset_bytes)); + (adev->gmc.fw->data + le32_to_cpu(hdr->io_debug_array_offset_bytes)); ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; fw_data = (const __le32 *) - (adev->mc.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + (adev->gmc.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); running = REG_GET_FIELD(RREG32(mmMC_SEQ_SUP_CNTL), MC_SEQ_SUP_CNTL, RUN); @@ -235,12 +236,12 @@ static int gmc_v7_0_mc_load_microcode(struct amdgpu_device *adev) } static void gmc_v7_0_vram_gtt_location(struct amdgpu_device *adev, - struct amdgpu_mc *mc) + struct amdgpu_gmc *mc) { u64 base = RREG32(mmMC_VM_FB_LOCATION) & 0xFFFF; base <<= 24; - amdgpu_device_vram_location(adev, &adev->mc, base); + amdgpu_device_vram_location(adev, &adev->gmc, base); amdgpu_device_gart_location(adev, mc); } @@ -283,9 +284,9 @@ static void gmc_v7_0_mc_program(struct amdgpu_device *adev) } /* Update configuration */ WREG32(mmMC_VM_SYSTEM_APERTURE_LOW_ADDR, - adev->mc.vram_start >> 12); + adev->gmc.vram_start >> 12); WREG32(mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR, - adev->mc.vram_end >> 12); + adev->gmc.vram_end >> 12); WREG32(mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, adev->vram_scratch.gpu_addr >> 12); WREG32(mmMC_VM_AGP_BASE, 0); @@ -318,8 +319,8 @@ static int gmc_v7_0_mc_init(struct amdgpu_device *adev) { int r; - adev->mc.vram_width = amdgpu_atombios_get_vram_width(adev); - if (!adev->mc.vram_width) { + adev->gmc.vram_width = amdgpu_atombios_get_vram_width(adev); + if (!adev->gmc.vram_width) { u32 tmp; int chansize, numchan; @@ -361,38 +362,38 @@ static int gmc_v7_0_mc_init(struct amdgpu_device *adev) numchan = 16; break; } - adev->mc.vram_width = numchan * chansize; + adev->gmc.vram_width = numchan * chansize; } /* size in MB on si */ - adev->mc.mc_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL; - adev->mc.real_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL; + adev->gmc.mc_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL; + adev->gmc.real_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL; if (!(adev->flags & AMD_IS_APU)) { r = amdgpu_device_resize_fb_bar(adev); if (r) return r; } - adev->mc.aper_base = pci_resource_start(adev->pdev, 0); - adev->mc.aper_size = pci_resource_len(adev->pdev, 0); + adev->gmc.aper_base = pci_resource_start(adev->pdev, 0); + adev->gmc.aper_size = pci_resource_len(adev->pdev, 0); #ifdef CONFIG_X86_64 if (adev->flags & AMD_IS_APU) { - adev->mc.aper_base = ((u64)RREG32(mmMC_VM_FB_OFFSET)) << 22; - adev->mc.aper_size = adev->mc.real_vram_size; + adev->gmc.aper_base = ((u64)RREG32(mmMC_VM_FB_OFFSET)) << 22; + adev->gmc.aper_size = adev->gmc.real_vram_size; } #endif /* In case the PCI BAR is larger than the actual amount of vram */ - adev->mc.visible_vram_size = adev->mc.aper_size; - if (adev->mc.visible_vram_size > adev->mc.real_vram_size) - adev->mc.visible_vram_size = adev->mc.real_vram_size; + adev->gmc.visible_vram_size = adev->gmc.aper_size; + if (adev->gmc.visible_vram_size > adev->gmc.real_vram_size) + adev->gmc.visible_vram_size = adev->gmc.real_vram_size; /* set the gart size */ if (amdgpu_gart_size == -1) { switch (adev->asic_type) { case CHIP_TOPAZ: /* no MM engines */ default: - adev->mc.gart_size = 256ULL << 20; + adev->gmc.gart_size = 256ULL << 20; break; #ifdef CONFIG_DRM_AMDGPU_CIK case CHIP_BONAIRE: /* UVD, VCE do not support GPUVM */ @@ -400,15 +401,15 @@ static int gmc_v7_0_mc_init(struct amdgpu_device *adev) case CHIP_KAVERI: /* UVD, VCE do not support GPUVM */ case CHIP_KABINI: /* UVD, VCE do not support GPUVM */ case CHIP_MULLINS: /* UVD, VCE do not support GPUVM */ - adev->mc.gart_size = 1024ULL << 20; + adev->gmc.gart_size = 1024ULL << 20; break; #endif } } else { - adev->mc.gart_size = (u64)amdgpu_gart_size << 20; + adev->gmc.gart_size = (u64)amdgpu_gart_size << 20; } - gmc_v7_0_vram_gtt_location(adev, &adev->mc); + gmc_v7_0_vram_gtt_location(adev, &adev->gmc); return 0; } @@ -421,25 +422,44 @@ static int gmc_v7_0_mc_init(struct amdgpu_device *adev) */ /** - * gmc_v7_0_gart_flush_gpu_tlb - gart tlb flush callback + * gmc_v7_0_flush_gpu_tlb - gart tlb flush callback * * @adev: amdgpu_device pointer * @vmid: vm instance to flush * * Flush the TLB for the requested page table (CIK). */ -static void gmc_v7_0_gart_flush_gpu_tlb(struct amdgpu_device *adev, - uint32_t vmid) +static void gmc_v7_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid) { - /* flush hdp cache */ - WREG32(mmHDP_MEM_COHERENCY_FLUSH_CNTL, 0); - /* bits 0-15 are the VM contexts0-15 */ WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid); } +static uint64_t gmc_v7_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring, + unsigned vmid, uint64_t pd_addr) +{ + uint32_t reg; + + if (vmid < 8) + reg = mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR + vmid; + else + reg = mmVM_CONTEXT8_PAGE_TABLE_BASE_ADDR + vmid - 8; + amdgpu_ring_emit_wreg(ring, reg, pd_addr >> 12); + + /* bits 0-15 are the VM contexts0-15 */ + amdgpu_ring_emit_wreg(ring, mmVM_INVALIDATE_REQUEST, 1 << vmid); + + return pd_addr; +} + +static void gmc_v7_0_emit_pasid_mapping(struct amdgpu_ring *ring, unsigned vmid, + unsigned pasid) +{ + amdgpu_ring_emit_wreg(ring, mmIH_VMID_0_LUT + vmid, pasid); +} + /** - * gmc_v7_0_gart_set_pte_pde - update the page tables using MMIO + * gmc_v7_0_set_pte_pde - update the page tables using MMIO * * @adev: amdgpu_device pointer * @cpu_pt_addr: cpu address of the page table @@ -449,11 +469,9 @@ static void gmc_v7_0_gart_flush_gpu_tlb(struct amdgpu_device *adev, * * Update the page tables using the CPU. */ -static int gmc_v7_0_gart_set_pte_pde(struct amdgpu_device *adev, - void *cpu_pt_addr, - uint32_t gpu_page_idx, - uint64_t addr, - uint64_t flags) +static int gmc_v7_0_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr, + uint32_t gpu_page_idx, uint64_t addr, + uint64_t flags) { void __iomem *ptr = (void *)cpu_pt_addr; uint64_t value; @@ -523,9 +541,9 @@ static void gmc_v7_0_set_prt(struct amdgpu_device *adev, bool enable) { uint32_t tmp; - if (enable && !adev->mc.prt_warning) { + if (enable && !adev->gmc.prt_warning) { dev_warn(adev->dev, "Disabling VM faults because of PRT request!\n"); - adev->mc.prt_warning = true; + adev->gmc.prt_warning = true; } tmp = RREG32(mmVM_PRT_CNTL); @@ -547,7 +565,8 @@ static void gmc_v7_0_set_prt(struct amdgpu_device *adev, bool enable) if (enable) { uint32_t low = AMDGPU_VA_RESERVED_SIZE >> AMDGPU_GPU_PAGE_SHIFT; - uint32_t high = adev->vm_manager.max_pfn; + uint32_t high = adev->vm_manager.max_pfn - + (AMDGPU_VA_RESERVED_SIZE >> AMDGPU_GPU_PAGE_SHIFT); WREG32(mmVM_PRT_APERTURE0_LOW_ADDR, low); WREG32(mmVM_PRT_APERTURE1_LOW_ADDR, low); @@ -621,8 +640,8 @@ static int gmc_v7_0_gart_enable(struct amdgpu_device *adev) tmp = REG_SET_FIELD(tmp, VM_L2_CNTL3, L2_CACHE_BIGK_FRAGMENT_SIZE, field); WREG32(mmVM_L2_CNTL3, tmp); /* setup context0 */ - WREG32(mmVM_CONTEXT0_PAGE_TABLE_START_ADDR, adev->mc.gart_start >> 12); - WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->mc.gart_end >> 12); + WREG32(mmVM_CONTEXT0_PAGE_TABLE_START_ADDR, adev->gmc.gart_start >> 12); + WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->gmc.gart_end >> 12); WREG32(mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR, adev->gart.table_addr >> 12); WREG32(mmVM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR, (u32)(adev->dummy_page.addr >> 12)); @@ -674,9 +693,9 @@ static int gmc_v7_0_gart_enable(struct amdgpu_device *adev) WREG32(mmCHUB_CONTROL, tmp); } - gmc_v7_0_gart_flush_gpu_tlb(adev, 0); + gmc_v7_0_flush_gpu_tlb(adev, 0); DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n", - (unsigned)(adev->mc.gart_size >> 20), + (unsigned)(adev->gmc.gart_size >> 20), (unsigned long long)adev->gart.table_addr); adev->gart.ready = true; return 0; @@ -749,21 +768,21 @@ static void gmc_v7_0_gart_fini(struct amdgpu_device *adev) * * Print human readable fault information (CIK). */ -static void gmc_v7_0_vm_decode_fault(struct amdgpu_device *adev, - u32 status, u32 addr, u32 mc_client) +static void gmc_v7_0_vm_decode_fault(struct amdgpu_device *adev, u32 status, + u32 addr, u32 mc_client, unsigned pasid) { - u32 mc_id; u32 vmid = REG_GET_FIELD(status, VM_CONTEXT1_PROTECTION_FAULT_STATUS, VMID); u32 protections = REG_GET_FIELD(status, VM_CONTEXT1_PROTECTION_FAULT_STATUS, PROTECTIONS); char block[5] = { mc_client >> 24, (mc_client >> 16) & 0xff, (mc_client >> 8) & 0xff, mc_client & 0xff, 0 }; + u32 mc_id; mc_id = REG_GET_FIELD(status, VM_CONTEXT1_PROTECTION_FAULT_STATUS, MEMORY_CLIENT_ID); - dev_err(adev->dev, "VM fault (0x%02x, vmid %d) at page %u, %s from '%s' (0x%08x) (%d)\n", - protections, vmid, addr, + dev_err(adev->dev, "VM fault (0x%02x, vmid %d, pasid %d) at page %u, %s from '%s' (0x%08x) (%d)\n", + protections, vmid, pasid, addr, REG_GET_FIELD(status, VM_CONTEXT1_PROTECTION_FAULT_STATUS, MEMORY_CLIENT_RW) ? "write" : "read", block, mc_client, mc_id); @@ -921,16 +940,16 @@ static int gmc_v7_0_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - gmc_v7_0_set_gart_funcs(adev); + gmc_v7_0_set_gmc_funcs(adev); gmc_v7_0_set_irq_funcs(adev); - adev->mc.shared_aperture_start = 0x2000000000000000ULL; - adev->mc.shared_aperture_end = - adev->mc.shared_aperture_start + (4ULL << 30) - 1; - adev->mc.private_aperture_start = - adev->mc.shared_aperture_end + 1; - adev->mc.private_aperture_end = - adev->mc.private_aperture_start + (4ULL << 30) - 1; + adev->gmc.shared_aperture_start = 0x2000000000000000ULL; + adev->gmc.shared_aperture_end = + adev->gmc.shared_aperture_start + (4ULL << 30) - 1; + adev->gmc.private_aperture_start = + adev->gmc.shared_aperture_end + 1; + adev->gmc.private_aperture_end = + adev->gmc.private_aperture_start + (4ULL << 30) - 1; return 0; } @@ -940,7 +959,7 @@ static int gmc_v7_0_late_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; if (amdgpu_vm_fault_stop != AMDGPU_VM_FAULT_STOP_ALWAYS) - return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0); + return amdgpu_irq_get(adev, &adev->gmc.vm_fault, 0); else return 0; } @@ -952,18 +971,18 @@ static int gmc_v7_0_sw_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; if (adev->flags & AMD_IS_APU) { - adev->mc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN; + adev->gmc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN; } else { u32 tmp = RREG32(mmMC_SEQ_MISC0); tmp &= MC_SEQ_MISC0__MT__MASK; - adev->mc.vram_type = gmc_v7_0_convert_vram_type(tmp); + adev->gmc.vram_type = gmc_v7_0_convert_vram_type(tmp); } - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 146, &adev->mc.vm_fault); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 146, &adev->gmc.vm_fault); if (r) return r; - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 147, &adev->mc.vm_fault); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 147, &adev->gmc.vm_fault); if (r) return r; @@ -977,9 +996,9 @@ static int gmc_v7_0_sw_init(void *handle) * This is the max address of the GPU's * internal address space. */ - adev->mc.mc_mask = 0xffffffffffULL; /* 40 bit MC */ + adev->gmc.mc_mask = 0xffffffffffULL; /* 40 bit MC */ - adev->mc.stolen_size = 256 * 1024; + adev->gmc.stolen_size = 256 * 1024; /* set DMA mask + need_dma32 flags. * PCIE - can handle 40-bits. @@ -999,6 +1018,7 @@ static int gmc_v7_0_sw_init(void *handle) pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(32)); pr_warn("amdgpu: No coherent DMA available\n"); } + adev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits); r = gmc_v7_0_init_microcode(adev); if (r) { @@ -1049,8 +1069,8 @@ static int gmc_v7_0_sw_fini(void *handle) amdgpu_vm_manager_fini(adev); gmc_v7_0_gart_fini(adev); amdgpu_bo_fini(adev); - release_firmware(adev->mc.fw); - adev->mc.fw = NULL; + release_firmware(adev->gmc.fw); + adev->gmc.fw = NULL; return 0; } @@ -1083,7 +1103,7 @@ static int gmc_v7_0_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - amdgpu_irq_put(adev, &adev->mc.vm_fault, 0); + amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); gmc_v7_0_gart_disable(adev); return 0; @@ -1257,7 +1277,8 @@ static int gmc_v7_0_process_interrupt(struct amdgpu_device *adev, addr); dev_err(adev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n", status); - gmc_v7_0_vm_decode_fault(adev, status, addr, mc_client); + gmc_v7_0_vm_decode_fault(adev, status, addr, mc_client, + entry->pasid); } return 0; @@ -1306,9 +1327,11 @@ static const struct amd_ip_funcs gmc_v7_0_ip_funcs = { .set_powergating_state = gmc_v7_0_set_powergating_state, }; -static const struct amdgpu_gart_funcs gmc_v7_0_gart_funcs = { - .flush_gpu_tlb = gmc_v7_0_gart_flush_gpu_tlb, - .set_pte_pde = gmc_v7_0_gart_set_pte_pde, +static const struct amdgpu_gmc_funcs gmc_v7_0_gmc_funcs = { + .flush_gpu_tlb = gmc_v7_0_flush_gpu_tlb, + .emit_flush_gpu_tlb = gmc_v7_0_emit_flush_gpu_tlb, + .emit_pasid_mapping = gmc_v7_0_emit_pasid_mapping, + .set_pte_pde = gmc_v7_0_set_pte_pde, .set_prt = gmc_v7_0_set_prt, .get_vm_pte_flags = gmc_v7_0_get_vm_pte_flags, .get_vm_pde = gmc_v7_0_get_vm_pde @@ -1319,16 +1342,16 @@ static const struct amdgpu_irq_src_funcs gmc_v7_0_irq_funcs = { .process = gmc_v7_0_process_interrupt, }; -static void gmc_v7_0_set_gart_funcs(struct amdgpu_device *adev) +static void gmc_v7_0_set_gmc_funcs(struct amdgpu_device *adev) { - if (adev->gart.gart_funcs == NULL) - adev->gart.gart_funcs = &gmc_v7_0_gart_funcs; + if (adev->gmc.gmc_funcs == NULL) + adev->gmc.gmc_funcs = &gmc_v7_0_gmc_funcs; } static void gmc_v7_0_set_irq_funcs(struct amdgpu_device *adev) { - adev->mc.vm_fault.num_types = 1; - adev->mc.vm_fault.funcs = &gmc_v7_0_irq_funcs; + adev->gmc.vm_fault.num_types = 1; + adev->gmc.vm_fault.funcs = &gmc_v7_0_irq_funcs; } const struct amdgpu_ip_block_version gmc_v7_0_ip_block = diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 9a813d834f1a..1e0ad0657e96 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -22,6 +22,7 @@ */ #include #include +#include #include "amdgpu.h" #include "gmc_v8_0.h" #include "amdgpu_ucode.h" @@ -44,7 +45,7 @@ #include "amdgpu_atombios.h" -static void gmc_v8_0_set_gart_funcs(struct amdgpu_device *adev); +static void gmc_v8_0_set_gmc_funcs(struct amdgpu_device *adev); static void gmc_v8_0_set_irq_funcs(struct amdgpu_device *adev); static int gmc_v8_0_wait_for_idle(void *handle); @@ -235,16 +236,16 @@ static int gmc_v8_0_init_microcode(struct amdgpu_device *adev) } snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mc.bin", chip_name); - err = request_firmware(&adev->mc.fw, fw_name, adev->dev); + err = request_firmware(&adev->gmc.fw, fw_name, adev->dev); if (err) goto out; - err = amdgpu_ucode_validate(adev->mc.fw); + err = amdgpu_ucode_validate(adev->gmc.fw); out: if (err) { pr_err("mc: Failed to load firmware \"%s\"\n", fw_name); - release_firmware(adev->mc.fw); - adev->mc.fw = NULL; + release_firmware(adev->gmc.fw); + adev->gmc.fw = NULL; } return err; } @@ -273,19 +274,19 @@ static int gmc_v8_0_tonga_mc_load_microcode(struct amdgpu_device *adev) if (amdgpu_sriov_bios(adev)) return 0; - if (!adev->mc.fw) + if (!adev->gmc.fw) return -EINVAL; - hdr = (const struct mc_firmware_header_v1_0 *)adev->mc.fw->data; + hdr = (const struct mc_firmware_header_v1_0 *)adev->gmc.fw->data; amdgpu_ucode_print_mc_hdr(&hdr->header); - adev->mc.fw_version = le32_to_cpu(hdr->header.ucode_version); + adev->gmc.fw_version = le32_to_cpu(hdr->header.ucode_version); regs_size = le32_to_cpu(hdr->io_debug_size_bytes) / (4 * 2); io_mc_regs = (const __le32 *) - (adev->mc.fw->data + le32_to_cpu(hdr->io_debug_array_offset_bytes)); + (adev->gmc.fw->data + le32_to_cpu(hdr->io_debug_array_offset_bytes)); ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; fw_data = (const __le32 *) - (adev->mc.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + (adev->gmc.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); running = REG_GET_FIELD(RREG32(mmMC_SEQ_SUP_CNTL), MC_SEQ_SUP_CNTL, RUN); @@ -349,19 +350,19 @@ static int gmc_v8_0_polaris_mc_load_microcode(struct amdgpu_device *adev) if (vbios_version == 0) return 0; - if (!adev->mc.fw) + if (!adev->gmc.fw) return -EINVAL; - hdr = (const struct mc_firmware_header_v1_0 *)adev->mc.fw->data; + hdr = (const struct mc_firmware_header_v1_0 *)adev->gmc.fw->data; amdgpu_ucode_print_mc_hdr(&hdr->header); - adev->mc.fw_version = le32_to_cpu(hdr->header.ucode_version); + adev->gmc.fw_version = le32_to_cpu(hdr->header.ucode_version); regs_size = le32_to_cpu(hdr->io_debug_size_bytes) / (4 * 2); io_mc_regs = (const __le32 *) - (adev->mc.fw->data + le32_to_cpu(hdr->io_debug_array_offset_bytes)); + (adev->gmc.fw->data + le32_to_cpu(hdr->io_debug_array_offset_bytes)); ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; fw_data = (const __le32 *) - (adev->mc.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + (adev->gmc.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); data = RREG32(mmMC_SEQ_MISC0); data &= ~(0x40); @@ -397,7 +398,7 @@ static int gmc_v8_0_polaris_mc_load_microcode(struct amdgpu_device *adev) } static void gmc_v8_0_vram_gtt_location(struct amdgpu_device *adev, - struct amdgpu_mc *mc) + struct amdgpu_gmc *mc) { u64 base = 0; @@ -405,7 +406,7 @@ static void gmc_v8_0_vram_gtt_location(struct amdgpu_device *adev, base = RREG32(mmMC_VM_FB_LOCATION) & 0xFFFF; base <<= 24; - amdgpu_device_vram_location(adev, &adev->mc, base); + amdgpu_device_vram_location(adev, &adev->gmc, base); amdgpu_device_gart_location(adev, mc); } @@ -448,18 +449,18 @@ static void gmc_v8_0_mc_program(struct amdgpu_device *adev) } /* Update configuration */ WREG32(mmMC_VM_SYSTEM_APERTURE_LOW_ADDR, - adev->mc.vram_start >> 12); + adev->gmc.vram_start >> 12); WREG32(mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR, - adev->mc.vram_end >> 12); + adev->gmc.vram_end >> 12); WREG32(mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, adev->vram_scratch.gpu_addr >> 12); if (amdgpu_sriov_vf(adev)) { - tmp = ((adev->mc.vram_end >> 24) & 0xFFFF) << 16; - tmp |= ((adev->mc.vram_start >> 24) & 0xFFFF); + tmp = ((adev->gmc.vram_end >> 24) & 0xFFFF) << 16; + tmp |= ((adev->gmc.vram_start >> 24) & 0xFFFF); WREG32(mmMC_VM_FB_LOCATION, tmp); /* XXX double check these! */ - WREG32(mmHDP_NONSURFACE_BASE, (adev->mc.vram_start >> 8)); + WREG32(mmHDP_NONSURFACE_BASE, (adev->gmc.vram_start >> 8)); WREG32(mmHDP_NONSURFACE_INFO, (2 << 7) | (1 << 30)); WREG32(mmHDP_NONSURFACE_SIZE, 0x3FFFFFFF); } @@ -494,8 +495,8 @@ static int gmc_v8_0_mc_init(struct amdgpu_device *adev) { int r; - adev->mc.vram_width = amdgpu_atombios_get_vram_width(adev); - if (!adev->mc.vram_width) { + adev->gmc.vram_width = amdgpu_atombios_get_vram_width(adev); + if (!adev->gmc.vram_width) { u32 tmp; int chansize, numchan; @@ -537,31 +538,31 @@ static int gmc_v8_0_mc_init(struct amdgpu_device *adev) numchan = 16; break; } - adev->mc.vram_width = numchan * chansize; + adev->gmc.vram_width = numchan * chansize; } /* size in MB on si */ - adev->mc.mc_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL; - adev->mc.real_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL; + adev->gmc.mc_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL; + adev->gmc.real_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL; if (!(adev->flags & AMD_IS_APU)) { r = amdgpu_device_resize_fb_bar(adev); if (r) return r; } - adev->mc.aper_base = pci_resource_start(adev->pdev, 0); - adev->mc.aper_size = pci_resource_len(adev->pdev, 0); + adev->gmc.aper_base = pci_resource_start(adev->pdev, 0); + adev->gmc.aper_size = pci_resource_len(adev->pdev, 0); #ifdef CONFIG_X86_64 if (adev->flags & AMD_IS_APU) { - adev->mc.aper_base = ((u64)RREG32(mmMC_VM_FB_OFFSET)) << 22; - adev->mc.aper_size = adev->mc.real_vram_size; + adev->gmc.aper_base = ((u64)RREG32(mmMC_VM_FB_OFFSET)) << 22; + adev->gmc.aper_size = adev->gmc.real_vram_size; } #endif /* In case the PCI BAR is larger than the actual amount of vram */ - adev->mc.visible_vram_size = adev->mc.aper_size; - if (adev->mc.visible_vram_size > adev->mc.real_vram_size) - adev->mc.visible_vram_size = adev->mc.real_vram_size; + adev->gmc.visible_vram_size = adev->gmc.aper_size; + if (adev->gmc.visible_vram_size > adev->gmc.real_vram_size) + adev->gmc.visible_vram_size = adev->gmc.real_vram_size; /* set the gart size */ if (amdgpu_gart_size == -1) { @@ -570,20 +571,20 @@ static int gmc_v8_0_mc_init(struct amdgpu_device *adev) case CHIP_POLARIS10: /* all engines support GPUVM */ case CHIP_POLARIS12: /* all engines support GPUVM */ default: - adev->mc.gart_size = 256ULL << 20; + adev->gmc.gart_size = 256ULL << 20; break; case CHIP_TONGA: /* UVD, VCE do not support GPUVM */ case CHIP_FIJI: /* UVD, VCE do not support GPUVM */ case CHIP_CARRIZO: /* UVD, VCE do not support GPUVM, DCE SG support */ case CHIP_STONEY: /* UVD does not support GPUVM, DCE SG support */ - adev->mc.gart_size = 1024ULL << 20; + adev->gmc.gart_size = 1024ULL << 20; break; } } else { - adev->mc.gart_size = (u64)amdgpu_gart_size << 20; + adev->gmc.gart_size = (u64)amdgpu_gart_size << 20; } - gmc_v8_0_vram_gtt_location(adev, &adev->mc); + gmc_v8_0_vram_gtt_location(adev, &adev->gmc); return 0; } @@ -596,25 +597,45 @@ static int gmc_v8_0_mc_init(struct amdgpu_device *adev) */ /** - * gmc_v8_0_gart_flush_gpu_tlb - gart tlb flush callback + * gmc_v8_0_flush_gpu_tlb - gart tlb flush callback * * @adev: amdgpu_device pointer * @vmid: vm instance to flush * * Flush the TLB for the requested page table (CIK). */ -static void gmc_v8_0_gart_flush_gpu_tlb(struct amdgpu_device *adev, +static void gmc_v8_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid) { - /* flush hdp cache */ - WREG32(mmHDP_MEM_COHERENCY_FLUSH_CNTL, 0); - /* bits 0-15 are the VM contexts0-15 */ WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid); } +static uint64_t gmc_v8_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring, + unsigned vmid, uint64_t pd_addr) +{ + uint32_t reg; + + if (vmid < 8) + reg = mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR + vmid; + else + reg = mmVM_CONTEXT8_PAGE_TABLE_BASE_ADDR + vmid - 8; + amdgpu_ring_emit_wreg(ring, reg, pd_addr >> 12); + + /* bits 0-15 are the VM contexts0-15 */ + amdgpu_ring_emit_wreg(ring, mmVM_INVALIDATE_REQUEST, 1 << vmid); + + return pd_addr; +} + +static void gmc_v8_0_emit_pasid_mapping(struct amdgpu_ring *ring, unsigned vmid, + unsigned pasid) +{ + amdgpu_ring_emit_wreg(ring, mmIH_VMID_0_LUT + vmid, pasid); +} + /** - * gmc_v8_0_gart_set_pte_pde - update the page tables using MMIO + * gmc_v8_0_set_pte_pde - update the page tables using MMIO * * @adev: amdgpu_device pointer * @cpu_pt_addr: cpu address of the page table @@ -624,11 +645,9 @@ static void gmc_v8_0_gart_flush_gpu_tlb(struct amdgpu_device *adev, * * Update the page tables using the CPU. */ -static int gmc_v8_0_gart_set_pte_pde(struct amdgpu_device *adev, - void *cpu_pt_addr, - uint32_t gpu_page_idx, - uint64_t addr, - uint64_t flags) +static int gmc_v8_0_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr, + uint32_t gpu_page_idx, uint64_t addr, + uint64_t flags) { void __iomem *ptr = (void *)cpu_pt_addr; uint64_t value; @@ -722,9 +741,9 @@ static void gmc_v8_0_set_prt(struct amdgpu_device *adev, bool enable) { u32 tmp; - if (enable && !adev->mc.prt_warning) { + if (enable && !adev->gmc.prt_warning) { dev_warn(adev->dev, "Disabling VM faults because of PRT request!\n"); - adev->mc.prt_warning = true; + adev->gmc.prt_warning = true; } tmp = RREG32(mmVM_PRT_CNTL); @@ -746,7 +765,8 @@ static void gmc_v8_0_set_prt(struct amdgpu_device *adev, bool enable) if (enable) { uint32_t low = AMDGPU_VA_RESERVED_SIZE >> AMDGPU_GPU_PAGE_SHIFT; - uint32_t high = adev->vm_manager.max_pfn; + uint32_t high = adev->vm_manager.max_pfn - + (AMDGPU_VA_RESERVED_SIZE >> AMDGPU_GPU_PAGE_SHIFT); WREG32(mmVM_PRT_APERTURE0_LOW_ADDR, low); WREG32(mmVM_PRT_APERTURE1_LOW_ADDR, low); @@ -836,8 +856,8 @@ static int gmc_v8_0_gart_enable(struct amdgpu_device *adev) tmp = REG_SET_FIELD(tmp, VM_L2_CNTL4, VMC_TAP_CONTEXT1_PTE_REQUEST_SNOOP, 0); WREG32(mmVM_L2_CNTL4, tmp); /* setup context0 */ - WREG32(mmVM_CONTEXT0_PAGE_TABLE_START_ADDR, adev->mc.gart_start >> 12); - WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->mc.gart_end >> 12); + WREG32(mmVM_CONTEXT0_PAGE_TABLE_START_ADDR, adev->gmc.gart_start >> 12); + WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->gmc.gart_end >> 12); WREG32(mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR, adev->gart.table_addr >> 12); WREG32(mmVM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR, (u32)(adev->dummy_page.addr >> 12)); @@ -890,9 +910,9 @@ static int gmc_v8_0_gart_enable(struct amdgpu_device *adev) else gmc_v8_0_set_fault_enable_default(adev, true); - gmc_v8_0_gart_flush_gpu_tlb(adev, 0); + gmc_v8_0_flush_gpu_tlb(adev, 0); DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n", - (unsigned)(adev->mc.gart_size >> 20), + (unsigned)(adev->gmc.gart_size >> 20), (unsigned long long)adev->gart.table_addr); adev->gart.ready = true; return 0; @@ -965,21 +985,21 @@ static void gmc_v8_0_gart_fini(struct amdgpu_device *adev) * * Print human readable fault information (CIK). */ -static void gmc_v8_0_vm_decode_fault(struct amdgpu_device *adev, - u32 status, u32 addr, u32 mc_client) +static void gmc_v8_0_vm_decode_fault(struct amdgpu_device *adev, u32 status, + u32 addr, u32 mc_client, unsigned pasid) { - u32 mc_id; u32 vmid = REG_GET_FIELD(status, VM_CONTEXT1_PROTECTION_FAULT_STATUS, VMID); u32 protections = REG_GET_FIELD(status, VM_CONTEXT1_PROTECTION_FAULT_STATUS, PROTECTIONS); char block[5] = { mc_client >> 24, (mc_client >> 16) & 0xff, (mc_client >> 8) & 0xff, mc_client & 0xff, 0 }; + u32 mc_id; mc_id = REG_GET_FIELD(status, VM_CONTEXT1_PROTECTION_FAULT_STATUS, MEMORY_CLIENT_ID); - dev_err(adev->dev, "VM fault (0x%02x, vmid %d) at page %u, %s from '%s' (0x%08x) (%d)\n", - protections, vmid, addr, + dev_err(adev->dev, "VM fault (0x%02x, vmid %d, pasid %d) at page %u, %s from '%s' (0x%08x) (%d)\n", + protections, vmid, pasid, addr, REG_GET_FIELD(status, VM_CONTEXT1_PROTECTION_FAULT_STATUS, MEMORY_CLIENT_RW) ? "write" : "read", block, mc_client, mc_id); @@ -1011,16 +1031,16 @@ static int gmc_v8_0_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - gmc_v8_0_set_gart_funcs(adev); + gmc_v8_0_set_gmc_funcs(adev); gmc_v8_0_set_irq_funcs(adev); - adev->mc.shared_aperture_start = 0x2000000000000000ULL; - adev->mc.shared_aperture_end = - adev->mc.shared_aperture_start + (4ULL << 30) - 1; - adev->mc.private_aperture_start = - adev->mc.shared_aperture_end + 1; - adev->mc.private_aperture_end = - adev->mc.private_aperture_start + (4ULL << 30) - 1; + adev->gmc.shared_aperture_start = 0x2000000000000000ULL; + adev->gmc.shared_aperture_end = + adev->gmc.shared_aperture_start + (4ULL << 30) - 1; + adev->gmc.private_aperture_start = + adev->gmc.shared_aperture_end + 1; + adev->gmc.private_aperture_end = + adev->gmc.private_aperture_start + (4ULL << 30) - 1; return 0; } @@ -1030,7 +1050,7 @@ static int gmc_v8_0_late_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; if (amdgpu_vm_fault_stop != AMDGPU_VM_FAULT_STOP_ALWAYS) - return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0); + return amdgpu_irq_get(adev, &adev->gmc.vm_fault, 0); else return 0; } @@ -1044,7 +1064,7 @@ static int gmc_v8_0_sw_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; if (adev->flags & AMD_IS_APU) { - adev->mc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN; + adev->gmc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN; } else { u32 tmp; @@ -1053,14 +1073,14 @@ static int gmc_v8_0_sw_init(void *handle) else tmp = RREG32(mmMC_SEQ_MISC0); tmp &= MC_SEQ_MISC0__MT__MASK; - adev->mc.vram_type = gmc_v8_0_convert_vram_type(tmp); + adev->gmc.vram_type = gmc_v8_0_convert_vram_type(tmp); } - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 146, &adev->mc.vm_fault); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 146, &adev->gmc.vm_fault); if (r) return r; - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 147, &adev->mc.vm_fault); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 147, &adev->gmc.vm_fault); if (r) return r; @@ -1074,9 +1094,9 @@ static int gmc_v8_0_sw_init(void *handle) * This is the max address of the GPU's * internal address space. */ - adev->mc.mc_mask = 0xffffffffffULL; /* 40 bit MC */ + adev->gmc.mc_mask = 0xffffffffffULL; /* 40 bit MC */ - adev->mc.stolen_size = 256 * 1024; + adev->gmc.stolen_size = 256 * 1024; /* set DMA mask + need_dma32 flags. * PCIE - can handle 40-bits. @@ -1085,6 +1105,7 @@ static int gmc_v8_0_sw_init(void *handle) */ adev->need_dma32 = false; dma_bits = adev->need_dma32 ? 32 : 40; + adev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits); r = pci_set_dma_mask(adev->pdev, DMA_BIT_MASK(dma_bits)); if (r) { adev->need_dma32 = true; @@ -1096,6 +1117,7 @@ static int gmc_v8_0_sw_init(void *handle) pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(32)); pr_warn("amdgpu: No coherent DMA available\n"); } + adev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits); r = gmc_v8_0_init_microcode(adev); if (r) { @@ -1146,8 +1168,8 @@ static int gmc_v8_0_sw_fini(void *handle) amdgpu_vm_manager_fini(adev); gmc_v8_0_gart_fini(adev); amdgpu_bo_fini(adev); - release_firmware(adev->mc.fw); - adev->mc.fw = NULL; + release_firmware(adev->gmc.fw); + adev->gmc.fw = NULL; return 0; } @@ -1188,7 +1210,7 @@ static int gmc_v8_0_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - amdgpu_irq_put(adev, &adev->mc.vm_fault, 0); + amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); gmc_v8_0_gart_disable(adev); return 0; @@ -1268,10 +1290,10 @@ static bool gmc_v8_0_check_soft_reset(void *handle) SRBM_SOFT_RESET, SOFT_RESET_MC, 1); } if (srbm_soft_reset) { - adev->mc.srbm_soft_reset = srbm_soft_reset; + adev->gmc.srbm_soft_reset = srbm_soft_reset; return true; } else { - adev->mc.srbm_soft_reset = 0; + adev->gmc.srbm_soft_reset = 0; return false; } } @@ -1280,7 +1302,7 @@ static int gmc_v8_0_pre_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (!adev->mc.srbm_soft_reset) + if (!adev->gmc.srbm_soft_reset) return 0; gmc_v8_0_mc_stop(adev); @@ -1296,9 +1318,9 @@ static int gmc_v8_0_soft_reset(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 srbm_soft_reset; - if (!adev->mc.srbm_soft_reset) + if (!adev->gmc.srbm_soft_reset) return 0; - srbm_soft_reset = adev->mc.srbm_soft_reset; + srbm_soft_reset = adev->gmc.srbm_soft_reset; if (srbm_soft_reset) { u32 tmp; @@ -1326,7 +1348,7 @@ static int gmc_v8_0_post_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (!adev->mc.srbm_soft_reset) + if (!adev->gmc.srbm_soft_reset) return 0; gmc_v8_0_mc_resume(adev); @@ -1407,7 +1429,8 @@ static int gmc_v8_0_process_interrupt(struct amdgpu_device *adev, addr); dev_err(adev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n", status); - gmc_v8_0_vm_decode_fault(adev, status, addr, mc_client); + gmc_v8_0_vm_decode_fault(adev, status, addr, mc_client, + entry->pasid); } return 0; @@ -1639,9 +1662,11 @@ static const struct amd_ip_funcs gmc_v8_0_ip_funcs = { .get_clockgating_state = gmc_v8_0_get_clockgating_state, }; -static const struct amdgpu_gart_funcs gmc_v8_0_gart_funcs = { - .flush_gpu_tlb = gmc_v8_0_gart_flush_gpu_tlb, - .set_pte_pde = gmc_v8_0_gart_set_pte_pde, +static const struct amdgpu_gmc_funcs gmc_v8_0_gmc_funcs = { + .flush_gpu_tlb = gmc_v8_0_flush_gpu_tlb, + .emit_flush_gpu_tlb = gmc_v8_0_emit_flush_gpu_tlb, + .emit_pasid_mapping = gmc_v8_0_emit_pasid_mapping, + .set_pte_pde = gmc_v8_0_set_pte_pde, .set_prt = gmc_v8_0_set_prt, .get_vm_pte_flags = gmc_v8_0_get_vm_pte_flags, .get_vm_pde = gmc_v8_0_get_vm_pde @@ -1652,16 +1677,16 @@ static const struct amdgpu_irq_src_funcs gmc_v8_0_irq_funcs = { .process = gmc_v8_0_process_interrupt, }; -static void gmc_v8_0_set_gart_funcs(struct amdgpu_device *adev) +static void gmc_v8_0_set_gmc_funcs(struct amdgpu_device *adev) { - if (adev->gart.gart_funcs == NULL) - adev->gart.gart_funcs = &gmc_v8_0_gart_funcs; + if (adev->gmc.gmc_funcs == NULL) + adev->gmc.gmc_funcs = &gmc_v8_0_gmc_funcs; } static void gmc_v8_0_set_irq_funcs(struct amdgpu_device *adev) { - adev->mc.vm_fault.num_types = 1; - adev->mc.vm_fault.funcs = &gmc_v8_0_irq_funcs; + adev->gmc.vm_fault.num_types = 1; + adev->gmc.vm_fault.funcs = &gmc_v8_0_irq_funcs; } const struct amdgpu_ip_block_version gmc_v8_0_ip_block = diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 2719937e09d6..bc4bd5e7ac94 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -21,6 +21,7 @@ * */ #include +#include #include "amdgpu.h" #include "gmc_v9_0.h" #include "amdgpu_atomfirmware.h" @@ -33,6 +34,7 @@ #include "vega10_enum.h" #include "mmhub/mmhub_1_0_offset.h" #include "athub/athub_1_0_offset.h" +#include "oss/osssys_4_0_offset.h" #include "soc15.h" #include "soc15_common.h" @@ -262,10 +264,10 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev, if (printk_ratelimit()) { dev_err(adev->dev, - "[%s] VMC page fault (src_id:%u ring:%u vmid:%u pas_id:%u)\n", + "[%s] VMC page fault (src_id:%u ring:%u vmid:%u pasid:%u)\n", entry->vmid_src ? "mmhub" : "gfxhub", entry->src_id, entry->ring_id, entry->vmid, - entry->pas_id); + entry->pasid); dev_err(adev->dev, " at page 0x%016llx from %d\n", addr, entry->client_id); if (!amdgpu_sriov_vf(adev)) @@ -284,8 +286,8 @@ static const struct amdgpu_irq_src_funcs gmc_v9_0_irq_funcs = { static void gmc_v9_0_set_irq_funcs(struct amdgpu_device *adev) { - adev->mc.vm_fault.num_types = 1; - adev->mc.vm_fault.funcs = &gmc_v9_0_irq_funcs; + adev->gmc.vm_fault.num_types = 1; + adev->gmc.vm_fault.funcs = &gmc_v9_0_irq_funcs; } static uint32_t gmc_v9_0_get_invalidate_req(unsigned int vmid) @@ -315,24 +317,21 @@ static uint32_t gmc_v9_0_get_invalidate_req(unsigned int vmid) */ /** - * gmc_v9_0_gart_flush_gpu_tlb - gart tlb flush callback + * gmc_v9_0_flush_gpu_tlb - gart tlb flush callback * * @adev: amdgpu_device pointer * @vmid: vm instance to flush * * Flush the TLB for the requested page table. */ -static void gmc_v9_0_gart_flush_gpu_tlb(struct amdgpu_device *adev, +static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid) { /* Use register 17 for GART */ const unsigned eng = 17; unsigned i, j; - /* flush hdp cache */ - adev->nbio_funcs->hdp_flush(adev); - - spin_lock(&adev->mc.invalidate_lock); + spin_lock(&adev->gmc.invalidate_lock); for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) { struct amdgpu_vmhub *hub = &adev->vmhub[i]; @@ -365,11 +364,52 @@ static void gmc_v9_0_gart_flush_gpu_tlb(struct amdgpu_device *adev, DRM_ERROR("Timeout waiting for VM flush ACK!\n"); } - spin_unlock(&adev->mc.invalidate_lock); + spin_unlock(&adev->gmc.invalidate_lock); +} + +static uint64_t gmc_v9_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring, + unsigned vmid, uint64_t pd_addr) +{ + struct amdgpu_device *adev = ring->adev; + struct amdgpu_vmhub *hub = &adev->vmhub[ring->funcs->vmhub]; + uint32_t req = gmc_v9_0_get_invalidate_req(vmid); + uint64_t flags = AMDGPU_PTE_VALID; + unsigned eng = ring->vm_inv_eng; + + amdgpu_gmc_get_vm_pde(adev, -1, &pd_addr, &flags); + pd_addr |= flags; + + amdgpu_ring_emit_wreg(ring, hub->ctx0_ptb_addr_lo32 + (2 * vmid), + lower_32_bits(pd_addr)); + + amdgpu_ring_emit_wreg(ring, hub->ctx0_ptb_addr_hi32 + (2 * vmid), + upper_32_bits(pd_addr)); + + amdgpu_ring_emit_wreg(ring, hub->vm_inv_eng0_req + eng, req); + + /* wait for the invalidate to complete */ + amdgpu_ring_emit_reg_wait(ring, hub->vm_inv_eng0_ack + eng, + 1 << vmid, 1 << vmid); + + return pd_addr; +} + +static void gmc_v9_0_emit_pasid_mapping(struct amdgpu_ring *ring, unsigned vmid, + unsigned pasid) +{ + struct amdgpu_device *adev = ring->adev; + uint32_t reg; + + if (ring->funcs->vmhub == AMDGPU_GFXHUB) + reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_VMID_0_LUT) + vmid; + else + reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_VMID_0_LUT_MM) + vmid; + + amdgpu_ring_emit_wreg(ring, reg, pasid); } /** - * gmc_v9_0_gart_set_pte_pde - update the page tables using MMIO + * gmc_v9_0_set_pte_pde - update the page tables using MMIO * * @adev: amdgpu_device pointer * @cpu_pt_addr: cpu address of the page table @@ -379,11 +419,9 @@ static void gmc_v9_0_gart_flush_gpu_tlb(struct amdgpu_device *adev, * * Update the page tables using the CPU. */ -static int gmc_v9_0_gart_set_pte_pde(struct amdgpu_device *adev, - void *cpu_pt_addr, - uint32_t gpu_page_idx, - uint64_t addr, - uint64_t flags) +static int gmc_v9_0_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr, + uint32_t gpu_page_idx, uint64_t addr, + uint64_t flags) { void __iomem *ptr = (void *)cpu_pt_addr; uint64_t value; @@ -474,10 +512,10 @@ static void gmc_v9_0_get_vm_pde(struct amdgpu_device *adev, int level, { if (!(*flags & AMDGPU_PDE_PTE)) *addr = adev->vm_manager.vram_base_offset + *addr - - adev->mc.vram_start; + adev->gmc.vram_start; BUG_ON(*addr & 0xFFFF00000000003FULL); - if (!adev->mc.translate_further) + if (!adev->gmc.translate_further) return; if (level == AMDGPU_VM_PDB1) { @@ -493,34 +531,35 @@ static void gmc_v9_0_get_vm_pde(struct amdgpu_device *adev, int level, } } -static const struct amdgpu_gart_funcs gmc_v9_0_gart_funcs = { - .flush_gpu_tlb = gmc_v9_0_gart_flush_gpu_tlb, - .set_pte_pde = gmc_v9_0_gart_set_pte_pde, - .get_invalidate_req = gmc_v9_0_get_invalidate_req, +static const struct amdgpu_gmc_funcs gmc_v9_0_gmc_funcs = { + .flush_gpu_tlb = gmc_v9_0_flush_gpu_tlb, + .emit_flush_gpu_tlb = gmc_v9_0_emit_flush_gpu_tlb, + .emit_pasid_mapping = gmc_v9_0_emit_pasid_mapping, + .set_pte_pde = gmc_v9_0_set_pte_pde, .get_vm_pte_flags = gmc_v9_0_get_vm_pte_flags, .get_vm_pde = gmc_v9_0_get_vm_pde }; -static void gmc_v9_0_set_gart_funcs(struct amdgpu_device *adev) +static void gmc_v9_0_set_gmc_funcs(struct amdgpu_device *adev) { - if (adev->gart.gart_funcs == NULL) - adev->gart.gart_funcs = &gmc_v9_0_gart_funcs; + if (adev->gmc.gmc_funcs == NULL) + adev->gmc.gmc_funcs = &gmc_v9_0_gmc_funcs; } static int gmc_v9_0_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - gmc_v9_0_set_gart_funcs(adev); + gmc_v9_0_set_gmc_funcs(adev); gmc_v9_0_set_irq_funcs(adev); - adev->mc.shared_aperture_start = 0x2000000000000000ULL; - adev->mc.shared_aperture_end = - adev->mc.shared_aperture_start + (4ULL << 30) - 1; - adev->mc.private_aperture_start = - adev->mc.shared_aperture_end + 1; - adev->mc.private_aperture_end = - adev->mc.private_aperture_start + (4ULL << 30) - 1; + adev->gmc.shared_aperture_start = 0x2000000000000000ULL; + adev->gmc.shared_aperture_end = + adev->gmc.shared_aperture_start + (4ULL << 30) - 1; + adev->gmc.private_aperture_start = + adev->gmc.shared_aperture_end + 1; + adev->gmc.private_aperture_end = + adev->gmc.private_aperture_start + (4ULL << 30) - 1; return 0; } @@ -646,16 +685,16 @@ static int gmc_v9_0_late_init(void *handle) } } - return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0); + return amdgpu_irq_get(adev, &adev->gmc.vm_fault, 0); } static void gmc_v9_0_vram_gtt_location(struct amdgpu_device *adev, - struct amdgpu_mc *mc) + struct amdgpu_gmc *mc) { u64 base = 0; if (!amdgpu_sriov_vf(adev)) base = mmhub_v1_0_get_fb_location(adev); - amdgpu_device_vram_location(adev, &adev->mc, base); + amdgpu_device_vram_location(adev, &adev->gmc, base); amdgpu_device_gart_location(adev, mc); /* base offset of vram pages */ if (adev->flags & AMD_IS_APU) @@ -679,8 +718,9 @@ static int gmc_v9_0_mc_init(struct amdgpu_device *adev) int chansize, numchan; int r; - adev->mc.vram_width = amdgpu_atomfirmware_get_vram_width(adev); - if (!adev->mc.vram_width) { + if (amdgpu_emu_mode != 1) + adev->gmc.vram_width = amdgpu_atomfirmware_get_vram_width(adev); + if (!adev->gmc.vram_width) { /* hbm memory channel size */ chansize = 128; @@ -717,43 +757,49 @@ static int gmc_v9_0_mc_init(struct amdgpu_device *adev) numchan = 2; break; } - adev->mc.vram_width = numchan * chansize; + adev->gmc.vram_width = numchan * chansize; } /* size in MB on si */ - adev->mc.mc_vram_size = + adev->gmc.mc_vram_size = adev->nbio_funcs->get_memsize(adev) * 1024ULL * 1024ULL; - adev->mc.real_vram_size = adev->mc.mc_vram_size; + adev->gmc.real_vram_size = adev->gmc.mc_vram_size; if (!(adev->flags & AMD_IS_APU)) { r = amdgpu_device_resize_fb_bar(adev); if (r) return r; } - adev->mc.aper_base = pci_resource_start(adev->pdev, 0); - adev->mc.aper_size = pci_resource_len(adev->pdev, 0); + adev->gmc.aper_base = pci_resource_start(adev->pdev, 0); + adev->gmc.aper_size = pci_resource_len(adev->pdev, 0); +#ifdef CONFIG_X86_64 + if (adev->flags & AMD_IS_APU) { + adev->gmc.aper_base = gfxhub_v1_0_get_mc_fb_offset(adev); + adev->gmc.aper_size = adev->gmc.real_vram_size; + } +#endif /* In case the PCI BAR is larger than the actual amount of vram */ - adev->mc.visible_vram_size = adev->mc.aper_size; - if (adev->mc.visible_vram_size > adev->mc.real_vram_size) - adev->mc.visible_vram_size = adev->mc.real_vram_size; + adev->gmc.visible_vram_size = adev->gmc.aper_size; + if (adev->gmc.visible_vram_size > adev->gmc.real_vram_size) + adev->gmc.visible_vram_size = adev->gmc.real_vram_size; /* set the gart size */ if (amdgpu_gart_size == -1) { switch (adev->asic_type) { case CHIP_VEGA10: /* all engines support GPUVM */ default: - adev->mc.gart_size = 256ULL << 20; + adev->gmc.gart_size = 256ULL << 20; break; case CHIP_RAVEN: /* DCE SG support */ - adev->mc.gart_size = 1024ULL << 20; + adev->gmc.gart_size = 1024ULL << 20; break; } } else { - adev->mc.gart_size = (u64)amdgpu_gart_size << 20; + adev->gmc.gart_size = (u64)amdgpu_gart_size << 20; } - gmc_v9_0_vram_gtt_location(adev, &adev->mc); + gmc_v9_0_vram_gtt_location(adev, &adev->gmc); return 0; } @@ -785,23 +831,23 @@ static int gmc_v9_0_sw_init(void *handle) gfxhub_v1_0_init(adev); mmhub_v1_0_init(adev); - spin_lock_init(&adev->mc.invalidate_lock); + spin_lock_init(&adev->gmc.invalidate_lock); switch (adev->asic_type) { case CHIP_RAVEN: - adev->mc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN; + adev->gmc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN; if (adev->rev_id == 0x0 || adev->rev_id == 0x1) { amdgpu_vm_adjust_size(adev, 256 * 1024, 9, 3, 48); } else { /* vm_size is 128TB + 512GB for legacy 3-level page support */ amdgpu_vm_adjust_size(adev, 128 * 1024 + 512, 9, 2, 48); - adev->mc.translate_further = + adev->gmc.translate_further = adev->vm_manager.num_level > 1; } break; case CHIP_VEGA10: /* XXX Don't know how to get VRAM type yet. */ - adev->mc.vram_type = AMDGPU_VRAM_TYPE_HBM; + adev->gmc.vram_type = AMDGPU_VRAM_TYPE_HBM; /* * To fulfill 4-level page support, * vm size is 256TB (48bit), maximum size of Vega10, @@ -815,9 +861,9 @@ static int gmc_v9_0_sw_init(void *handle) /* This interrupt is VMC page fault.*/ r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_VMC, 0, - &adev->mc.vm_fault); + &adev->gmc.vm_fault); r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_UTCL2, 0, - &adev->mc.vm_fault); + &adev->gmc.vm_fault); if (r) return r; @@ -826,13 +872,13 @@ static int gmc_v9_0_sw_init(void *handle) * This is the max address of the GPU's * internal address space. */ - adev->mc.mc_mask = 0xffffffffffffULL; /* 48 bit MC */ + adev->gmc.mc_mask = 0xffffffffffffULL; /* 48 bit MC */ /* * It needs to reserve 8M stolen memory for vega10 * TODO: Figure out how to avoid that... */ - adev->mc.stolen_size = 8 * 1024 * 1024; + adev->gmc.stolen_size = 8 * 1024 * 1024; /* set DMA mask + need_dma32 flags. * PCIE - can handle 44-bits. @@ -852,6 +898,7 @@ static int gmc_v9_0_sw_init(void *handle) pci_set_consistent_dma_mask(adev->pdev, DMA_BIT_MASK(32)); printk(KERN_WARNING "amdgpu: No coherent DMA available.\n"); } + adev->need_swiotlb = drm_get_max_iomem() > ((u64)1 << dma_bits); r = gmc_v9_0_mc_init(adev); if (r) @@ -973,7 +1020,7 @@ static int gmc_v9_0_gart_enable(struct amdgpu_device *adev) WREG32_SOC15(HDP, 0, mmHDP_HOST_PATH_CNTL, tmp); /* After HDP is initialized, flush HDP.*/ - adev->nbio_funcs->hdp_flush(adev); + adev->nbio_funcs->hdp_flush(adev, NULL); if (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_ALWAYS) value = false; @@ -982,10 +1029,10 @@ static int gmc_v9_0_gart_enable(struct amdgpu_device *adev) gfxhub_v1_0_set_fault_enable_default(adev, value); mmhub_v1_0_set_fault_enable_default(adev, value); - gmc_v9_0_gart_flush_gpu_tlb(adev, 0); + gmc_v9_0_flush_gpu_tlb(adev, 0); DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n", - (unsigned)(adev->mc.gart_size >> 20), + (unsigned)(adev->gmc.gart_size >> 20), (unsigned long long)adev->gart.table_addr); adev->gart.ready = true; return 0; @@ -1036,7 +1083,7 @@ static int gmc_v9_0_hw_fini(void *handle) return 0; } - amdgpu_irq_put(adev, &adev->mc.vm_fault, 0); + amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); gmc_v9_0_gart_disable(adev); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c index c4e4be3dd31d..3237a576692d 100644 --- a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c @@ -260,7 +260,7 @@ static void iceland_ih_decode_iv(struct amdgpu_device *adev, entry->src_data[0] = dw[1] & 0xfffffff; entry->ring_id = dw[2] & 0xff; entry->vmid = (dw[2] >> 8) & 0xff; - entry->pas_id = (dw[2] >> 16) & 0xffff; + entry->pasid = (dw[2] >> 16) & 0xffff; /* wptr/rptr are in bytes! */ adev->irq.ih.rptr += 16; diff --git a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c index d9e9e52a0def..8766681cfd3f 100644 --- a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c @@ -3319,7 +3319,6 @@ const struct amd_ip_funcs kv_dpm_ip_funcs = { }; const struct amd_pm_funcs kv_dpm_funcs = { - .get_temperature = &kv_dpm_get_temp, .pre_set_power_state = &kv_dpm_pre_set_power_state, .set_power_state = &kv_dpm_set_power_state, .post_set_power_state = &kv_dpm_post_set_power_state, diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c index ffd5b7ee49c4..d0ade9fd9fa9 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c @@ -50,7 +50,7 @@ static void mmhub_v1_0_init_gart_pt_regs(struct amdgpu_device *adev) uint64_t value; BUG_ON(adev->gart.table_addr & (~0x0000FFFFFFFFF000ULL)); - value = adev->gart.table_addr - adev->mc.vram_start + + value = adev->gart.table_addr - adev->gmc.vram_start + adev->vm_manager.vram_base_offset; value &= 0x0000FFFFFFFFF000ULL; value |= 0x1; /* valid bit */ @@ -67,14 +67,14 @@ static void mmhub_v1_0_init_gart_aperture_regs(struct amdgpu_device *adev) mmhub_v1_0_init_gart_pt_regs(adev); WREG32_SOC15(MMHUB, 0, mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32, - (u32)(adev->mc.gart_start >> 12)); + (u32)(adev->gmc.gart_start >> 12)); WREG32_SOC15(MMHUB, 0, mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32, - (u32)(adev->mc.gart_start >> 44)); + (u32)(adev->gmc.gart_start >> 44)); WREG32_SOC15(MMHUB, 0, mmVM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32, - (u32)(adev->mc.gart_end >> 12)); + (u32)(adev->gmc.gart_end >> 12)); WREG32_SOC15(MMHUB, 0, mmVM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32, - (u32)(adev->mc.gart_end >> 44)); + (u32)(adev->gmc.gart_end >> 44)); } static void mmhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev) @@ -89,12 +89,12 @@ static void mmhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev) /* Program the system aperture low logical page number. */ WREG32_SOC15(MMHUB, 0, mmMC_VM_SYSTEM_APERTURE_LOW_ADDR, - adev->mc.vram_start >> 18); + adev->gmc.vram_start >> 18); WREG32_SOC15(MMHUB, 0, mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR, - adev->mc.vram_end >> 18); + adev->gmc.vram_end >> 18); /* Set default page address. */ - value = adev->vram_scratch.gpu_addr - adev->mc.vram_start + + value = adev->vram_scratch.gpu_addr - adev->gmc.vram_start + adev->vm_manager.vram_base_offset; WREG32_SOC15(MMHUB, 0, mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, (u32)(value >> 12)); @@ -155,7 +155,7 @@ static void mmhub_v1_0_init_cache_regs(struct amdgpu_device *adev) tmp = REG_SET_FIELD(tmp, VM_L2_CNTL2, INVALIDATE_L2_CACHE, 1); WREG32_SOC15(MMHUB, 0, mmVM_L2_CNTL2, tmp); - if (adev->mc.translate_further) { + if (adev->gmc.translate_further) { tmp = REG_SET_FIELD(tmp, VM_L2_CNTL3, BANK_SELECT, 12); tmp = REG_SET_FIELD(tmp, VM_L2_CNTL3, L2_CACHE_BIGK_FRAGMENT_SIZE, 9); @@ -207,7 +207,7 @@ static void mmhub_v1_0_setup_vmid_config(struct amdgpu_device *adev) num_level = adev->vm_manager.num_level; block_size = adev->vm_manager.block_size; - if (adev->mc.translate_further) + if (adev->gmc.translate_further) num_level -= 1; else block_size -= 9; @@ -272,21 +272,21 @@ static const struct pctl_data pctl0_data[] = { {0x11, 0x6a684}, {0x19, 0xea68e}, {0x29, 0xa69e}, - {0x2b, 0x34a6c0}, - {0x61, 0x83a707}, - {0xe6, 0x8a7a4}, - {0xf0, 0x1a7b8}, - {0xf3, 0xfa7cc}, - {0x104, 0x17a7dd}, - {0x11d, 0xa7dc}, - {0x11f, 0x12a7f5}, - {0x133, 0xa808}, - {0x135, 0x12a810}, - {0x149, 0x7a82c} + {0x2b, 0x0010a6c0}, + {0x3d, 0x83a707}, + {0xc2, 0x8a7a4}, + {0xcc, 0x1a7b8}, + {0xcf, 0xfa7cc}, + {0xe0, 0x17a7dd}, + {0xf9, 0xa7dc}, + {0xfb, 0x12a7f5}, + {0x10f, 0xa808}, + {0x111, 0x12a810}, + {0x125, 0x7a82c} }; #define PCTL0_DATA_LEN (ARRAY_SIZE(pctl0_data)) -#define PCTL0_RENG_EXEC_END_PTR 0x151 +#define PCTL0_RENG_EXEC_END_PTR 0x12d #define PCTL0_STCTRL_REG_SAVE_RANGE0_BASE 0xa640 #define PCTL0_STCTRL_REG_SAVE_RANGE0_LIMIT 0xa833 @@ -385,10 +385,9 @@ void mmhub_v1_0_initialize_power_gating(struct amdgpu_device *adev) if (amdgpu_sriov_vf(adev)) return; + /****************** pctl0 **********************/ pctl0_misc = RREG32_SOC15(MMHUB, 0, mmPCTL0_MISC); pctl0_reng_execute = RREG32_SOC15(MMHUB, 0, mmPCTL0_RENG_EXECUTE); - pctl1_misc = RREG32_SOC15(MMHUB, 0, mmPCTL1_MISC); - pctl1_reng_execute = RREG32_SOC15(MMHUB, 0, mmPCTL1_RENG_EXECUTE); /* Light sleep must be disabled before writing to pctl0 registers */ pctl0_misc &= ~PCTL0_MISC__RENG_MEM_LS_ENABLE_MASK; @@ -402,12 +401,13 @@ void mmhub_v1_0_initialize_power_gating(struct amdgpu_device *adev) pctl0_data[i].data); } - /* Set the reng execute end ptr for pctl0 */ - pctl0_reng_execute = REG_SET_FIELD(pctl0_reng_execute, - PCTL0_RENG_EXECUTE, - RENG_EXECUTE_END_PTR, - PCTL0_RENG_EXEC_END_PTR); - WREG32_SOC15(MMHUB, 0, mmPCTL0_RENG_EXECUTE, pctl0_reng_execute); + /* Re-enable light sleep */ + pctl0_misc |= PCTL0_MISC__RENG_MEM_LS_ENABLE_MASK; + WREG32_SOC15(MMHUB, 0, mmPCTL0_MISC, pctl0_misc); + + /****************** pctl1 **********************/ + pctl1_misc = RREG32_SOC15(MMHUB, 0, mmPCTL1_MISC); + pctl1_reng_execute = RREG32_SOC15(MMHUB, 0, mmPCTL1_RENG_EXECUTE); /* Light sleep must be disabled before writing to pctl1 registers */ pctl1_misc &= ~PCTL1_MISC__RENG_MEM_LS_ENABLE_MASK; @@ -421,20 +421,25 @@ void mmhub_v1_0_initialize_power_gating(struct amdgpu_device *adev) pctl1_data[i].data); } + /* Re-enable light sleep */ + pctl1_misc |= PCTL1_MISC__RENG_MEM_LS_ENABLE_MASK; + WREG32_SOC15(MMHUB, 0, mmPCTL1_MISC, pctl1_misc); + + mmhub_v1_0_power_gating_write_save_ranges(adev); + + /* Set the reng execute end ptr for pctl0 */ + pctl0_reng_execute = REG_SET_FIELD(pctl0_reng_execute, + PCTL0_RENG_EXECUTE, + RENG_EXECUTE_END_PTR, + PCTL0_RENG_EXEC_END_PTR); + WREG32_SOC15(MMHUB, 0, mmPCTL0_RENG_EXECUTE, pctl0_reng_execute); + /* Set the reng execute end ptr for pctl1 */ pctl1_reng_execute = REG_SET_FIELD(pctl1_reng_execute, PCTL1_RENG_EXECUTE, RENG_EXECUTE_END_PTR, PCTL1_RENG_EXEC_END_PTR); WREG32_SOC15(MMHUB, 0, mmPCTL1_RENG_EXECUTE, pctl1_reng_execute); - - mmhub_v1_0_power_gating_write_save_ranges(adev); - - /* Re-enable light sleep */ - pctl0_misc |= PCTL0_MISC__RENG_MEM_LS_ENABLE_MASK; - WREG32_SOC15(MMHUB, 0, mmPCTL0_MISC, pctl0_misc); - pctl1_misc |= PCTL1_MISC__RENG_MEM_LS_ENABLE_MASK; - WREG32_SOC15(MMHUB, 0, mmPCTL1_MISC, pctl1_misc); } void mmhub_v1_0_update_power_gating(struct amdgpu_device *adev, @@ -466,6 +471,9 @@ void mmhub_v1_0_update_power_gating(struct amdgpu_device *adev, RENG_EXECUTE_ON_REG_UPDATE, 1); WREG32_SOC15(MMHUB, 0, mmPCTL1_RENG_EXECUTE, pctl1_reng_execute); + if (adev->powerplay.pp_funcs->set_mmhub_powergating_by_smu) + amdgpu_dpm_set_mmhub_powergating_by_smu(adev); + } else { pctl0_reng_execute = REG_SET_FIELD(pctl0_reng_execute, PCTL0_RENG_EXECUTE, @@ -494,9 +502,9 @@ int mmhub_v1_0_gart_enable(struct amdgpu_device *adev) * SRIOV driver need to program them */ WREG32_SOC15(MMHUB, 0, mmMC_VM_FB_LOCATION_BASE, - adev->mc.vram_start >> 24); + adev->gmc.vram_start >> 24); WREG32_SOC15(MMHUB, 0, mmMC_VM_FB_LOCATION_TOP, - adev->mc.vram_end >> 24); + adev->gmc.vram_end >> 24); } /* GART Enable. */ diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v6_1.c b/drivers/gpu/drm/amd/amdgpu/nbio_v6_1.c index d4da663d5eb0..2daeef6e9345 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v6_1.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v6_1.c @@ -53,9 +53,16 @@ static void nbio_v6_1_mc_access_enable(struct amdgpu_device *adev, bool enable) WREG32_SOC15(NBIO, 0, mmBIF_FB_EN, 0); } -static void nbio_v6_1_hdp_flush(struct amdgpu_device *adev) +static void nbio_v6_1_hdp_flush(struct amdgpu_device *adev, + struct amdgpu_ring *ring) { - WREG32_SOC15_NO_KIQ(NBIO, 0, mmBIF_BX_PF0_HDP_MEM_COHERENCY_FLUSH_CNTL, 0); + if (!ring || !ring->funcs->emit_wreg) + WREG32_SOC15_NO_KIQ(NBIO, 0, + mmBIF_BX_PF0_HDP_MEM_COHERENCY_FLUSH_CNTL, + 0); + else + amdgpu_ring_emit_wreg(ring, SOC15_REG_OFFSET( + NBIO, 0, mmBIF_BX_PF0_HDP_MEM_COHERENCY_FLUSH_CNTL), 0); } static u32 nbio_v6_1_get_memsize(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c index 17a9131a4598..cd10c76a76e2 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c @@ -53,9 +53,14 @@ static void nbio_v7_0_mc_access_enable(struct amdgpu_device *adev, bool enable) WREG32_SOC15(NBIO, 0, mmBIF_FB_EN, 0); } -static void nbio_v7_0_hdp_flush(struct amdgpu_device *adev) +static void nbio_v7_0_hdp_flush(struct amdgpu_device *adev, + struct amdgpu_ring *ring) { - WREG32_SOC15_NO_KIQ(NBIO, 0, mmHDP_MEM_COHERENCY_FLUSH_CNTL, 0); + if (!ring || !ring->funcs->emit_wreg) + WREG32_SOC15_NO_KIQ(NBIO, 0, mmHDP_MEM_COHERENCY_FLUSH_CNTL, 0); + else + amdgpu_ring_emit_wreg(ring, SOC15_REG_OFFSET( + NBIO, 0, mmHDP_MEM_COHERENCY_FLUSH_CNTL), 0); } static u32 nbio_v7_0_get_memsize(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c index 5a9fe24697f9..8873d833a7f7 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c @@ -87,7 +87,7 @@ psp_v10_0_get_fw_type(struct amdgpu_firmware_info *ucode, enum psp_gfx_fw_type * return 0; } -int psp_v10_0_init_microcode(struct psp_context *psp) +static int psp_v10_0_init_microcode(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; const char *chip_name; @@ -133,7 +133,8 @@ out: return err; } -int psp_v10_0_prep_cmd_buf(struct amdgpu_firmware_info *ucode, struct psp_gfx_cmd_resp *cmd) +static int psp_v10_0_prep_cmd_buf(struct amdgpu_firmware_info *ucode, + struct psp_gfx_cmd_resp *cmd) { int ret; uint64_t fw_mem_mc_addr = ucode->mc_addr; @@ -152,7 +153,8 @@ int psp_v10_0_prep_cmd_buf(struct amdgpu_firmware_info *ucode, struct psp_gfx_cm return ret; } -int psp_v10_0_ring_init(struct psp_context *psp, enum psp_ring_type ring_type) +static int psp_v10_0_ring_init(struct psp_context *psp, + enum psp_ring_type ring_type) { int ret = 0; struct psp_ring *ring; @@ -177,7 +179,8 @@ int psp_v10_0_ring_init(struct psp_context *psp, enum psp_ring_type ring_type) return 0; } -int psp_v10_0_ring_create(struct psp_context *psp, enum psp_ring_type ring_type) +static int psp_v10_0_ring_create(struct psp_context *psp, + enum psp_ring_type ring_type) { int ret = 0; unsigned int psp_ring_reg = 0; @@ -208,7 +211,8 @@ int psp_v10_0_ring_create(struct psp_context *psp, enum psp_ring_type ring_type) return ret; } -int psp_v10_0_ring_stop(struct psp_context *psp, enum psp_ring_type ring_type) +static int psp_v10_0_ring_stop(struct psp_context *psp, + enum psp_ring_type ring_type) { int ret = 0; struct psp_ring *ring; @@ -231,7 +235,8 @@ int psp_v10_0_ring_stop(struct psp_context *psp, enum psp_ring_type ring_type) return ret; } -int psp_v10_0_ring_destroy(struct psp_context *psp, enum psp_ring_type ring_type) +static int psp_v10_0_ring_destroy(struct psp_context *psp, + enum psp_ring_type ring_type) { int ret = 0; struct psp_ring *ring = &psp->km_ring; @@ -248,10 +253,10 @@ int psp_v10_0_ring_destroy(struct psp_context *psp, enum psp_ring_type ring_type return ret; } -int psp_v10_0_cmd_submit(struct psp_context *psp, - struct amdgpu_firmware_info *ucode, - uint64_t cmd_buf_mc_addr, uint64_t fence_mc_addr, - int index) +static int psp_v10_0_cmd_submit(struct psp_context *psp, + struct amdgpu_firmware_info *ucode, + uint64_t cmd_buf_mc_addr, uint64_t fence_mc_addr, + int index) { unsigned int psp_write_ptr_reg = 0; struct psp_gfx_rb_frame * write_frame = psp->km_ring.ring_mem; @@ -298,9 +303,9 @@ int psp_v10_0_cmd_submit(struct psp_context *psp, static int psp_v10_0_sram_map(struct amdgpu_device *adev, - unsigned int *sram_offset, unsigned int *sram_addr_reg_offset, - unsigned int *sram_data_reg_offset, - enum AMDGPU_UCODE_ID ucode_id) + unsigned int *sram_offset, unsigned int *sram_addr_reg_offset, + unsigned int *sram_data_reg_offset, + enum AMDGPU_UCODE_ID ucode_id) { int ret = 0; @@ -383,9 +388,9 @@ psp_v10_0_sram_map(struct amdgpu_device *adev, return ret; } -bool psp_v10_0_compare_sram_data(struct psp_context *psp, - struct amdgpu_firmware_info *ucode, - enum AMDGPU_UCODE_ID ucode_type) +static bool psp_v10_0_compare_sram_data(struct psp_context *psp, + struct amdgpu_firmware_info *ucode, + enum AMDGPU_UCODE_ID ucode_type) { int err = 0; unsigned int fw_sram_reg_val = 0; @@ -419,8 +424,25 @@ bool psp_v10_0_compare_sram_data(struct psp_context *psp, } -int psp_v10_0_mode1_reset(struct psp_context *psp) +static int psp_v10_0_mode1_reset(struct psp_context *psp) { DRM_INFO("psp mode 1 reset not supported now! \n"); return -EINVAL; } + +static const struct psp_funcs psp_v10_0_funcs = { + .init_microcode = psp_v10_0_init_microcode, + .prep_cmd_buf = psp_v10_0_prep_cmd_buf, + .ring_init = psp_v10_0_ring_init, + .ring_create = psp_v10_0_ring_create, + .ring_stop = psp_v10_0_ring_stop, + .ring_destroy = psp_v10_0_ring_destroy, + .cmd_submit = psp_v10_0_cmd_submit, + .compare_sram_data = psp_v10_0_compare_sram_data, + .mode1_reset = psp_v10_0_mode1_reset, +}; + +void psp_v10_0_set_psp_funcs(struct psp_context *psp) +{ + psp->funcs = &psp_v10_0_funcs; +} diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.h b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.h index 451e8308303f..20c2a94859d8 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.h +++ b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.h @@ -27,24 +27,6 @@ #include "amdgpu_psp.h" -extern int psp_v10_0_init_microcode(struct psp_context *psp); -extern int psp_v10_0_prep_cmd_buf(struct amdgpu_firmware_info *ucode, - struct psp_gfx_cmd_resp *cmd); -extern int psp_v10_0_ring_init(struct psp_context *psp, - enum psp_ring_type ring_type); -extern int psp_v10_0_ring_create(struct psp_context *psp, - enum psp_ring_type ring_type); -extern int psp_v10_0_ring_stop(struct psp_context *psp, - enum psp_ring_type ring_type); -extern int psp_v10_0_ring_destroy(struct psp_context *psp, - enum psp_ring_type ring_type); -extern int psp_v10_0_cmd_submit(struct psp_context *psp, - struct amdgpu_firmware_info *ucode, - uint64_t cmd_buf_mc_addr, uint64_t fence_mc_addr, - int index); -extern bool psp_v10_0_compare_sram_data(struct psp_context *psp, - struct amdgpu_firmware_info *ucode, - enum AMDGPU_UCODE_ID ucode_type); +void psp_v10_0_set_psp_funcs(struct psp_context *psp); -extern int psp_v10_0_mode1_reset(struct psp_context *psp); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c index 19bd1934e63d..690b9766d8ae 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c @@ -93,7 +93,7 @@ psp_v3_1_get_fw_type(struct amdgpu_firmware_info *ucode, enum psp_gfx_fw_type *t return 0; } -int psp_v3_1_init_microcode(struct psp_context *psp) +static int psp_v3_1_init_microcode(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; const char *chip_name; @@ -161,7 +161,7 @@ out: return err; } -int psp_v3_1_bootloader_load_sysdrv(struct psp_context *psp) +static int psp_v3_1_bootloader_load_sysdrv(struct psp_context *psp) { int ret; uint32_t psp_gfxdrv_command_reg = 0; @@ -202,7 +202,7 @@ int psp_v3_1_bootloader_load_sysdrv(struct psp_context *psp) return ret; } -int psp_v3_1_bootloader_load_sos(struct psp_context *psp) +static int psp_v3_1_bootloader_load_sos(struct psp_context *psp) { int ret; unsigned int psp_gfxdrv_command_reg = 0; @@ -243,7 +243,8 @@ int psp_v3_1_bootloader_load_sos(struct psp_context *psp) return ret; } -int psp_v3_1_prep_cmd_buf(struct amdgpu_firmware_info *ucode, struct psp_gfx_cmd_resp *cmd) +static int psp_v3_1_prep_cmd_buf(struct amdgpu_firmware_info *ucode, + struct psp_gfx_cmd_resp *cmd) { int ret; uint64_t fw_mem_mc_addr = ucode->mc_addr; @@ -262,7 +263,8 @@ int psp_v3_1_prep_cmd_buf(struct amdgpu_firmware_info *ucode, struct psp_gfx_cmd return ret; } -int psp_v3_1_ring_init(struct psp_context *psp, enum psp_ring_type ring_type) +static int psp_v3_1_ring_init(struct psp_context *psp, + enum psp_ring_type ring_type) { int ret = 0; struct psp_ring *ring; @@ -287,7 +289,8 @@ int psp_v3_1_ring_init(struct psp_context *psp, enum psp_ring_type ring_type) return 0; } -int psp_v3_1_ring_create(struct psp_context *psp, enum psp_ring_type ring_type) +static int psp_v3_1_ring_create(struct psp_context *psp, + enum psp_ring_type ring_type) { int ret = 0; unsigned int psp_ring_reg = 0; @@ -318,7 +321,8 @@ int psp_v3_1_ring_create(struct psp_context *psp, enum psp_ring_type ring_type) return ret; } -int psp_v3_1_ring_stop(struct psp_context *psp, enum psp_ring_type ring_type) +static int psp_v3_1_ring_stop(struct psp_context *psp, + enum psp_ring_type ring_type) { int ret = 0; struct psp_ring *ring; @@ -341,7 +345,8 @@ int psp_v3_1_ring_stop(struct psp_context *psp, enum psp_ring_type ring_type) return ret; } -int psp_v3_1_ring_destroy(struct psp_context *psp, enum psp_ring_type ring_type) +static int psp_v3_1_ring_destroy(struct psp_context *psp, + enum psp_ring_type ring_type) { int ret = 0; struct psp_ring *ring = &psp->km_ring; @@ -358,10 +363,10 @@ int psp_v3_1_ring_destroy(struct psp_context *psp, enum psp_ring_type ring_type) return ret; } -int psp_v3_1_cmd_submit(struct psp_context *psp, - struct amdgpu_firmware_info *ucode, - uint64_t cmd_buf_mc_addr, uint64_t fence_mc_addr, - int index) +static int psp_v3_1_cmd_submit(struct psp_context *psp, + struct amdgpu_firmware_info *ucode, + uint64_t cmd_buf_mc_addr, uint64_t fence_mc_addr, + int index) { unsigned int psp_write_ptr_reg = 0; struct psp_gfx_rb_frame * write_frame = psp->km_ring.ring_mem; @@ -410,9 +415,9 @@ int psp_v3_1_cmd_submit(struct psp_context *psp, static int psp_v3_1_sram_map(struct amdgpu_device *adev, - unsigned int *sram_offset, unsigned int *sram_addr_reg_offset, - unsigned int *sram_data_reg_offset, - enum AMDGPU_UCODE_ID ucode_id) + unsigned int *sram_offset, unsigned int *sram_addr_reg_offset, + unsigned int *sram_data_reg_offset, + enum AMDGPU_UCODE_ID ucode_id) { int ret = 0; @@ -495,9 +500,9 @@ psp_v3_1_sram_map(struct amdgpu_device *adev, return ret; } -bool psp_v3_1_compare_sram_data(struct psp_context *psp, - struct amdgpu_firmware_info *ucode, - enum AMDGPU_UCODE_ID ucode_type) +static bool psp_v3_1_compare_sram_data(struct psp_context *psp, + struct amdgpu_firmware_info *ucode, + enum AMDGPU_UCODE_ID ucode_type) { int err = 0; unsigned int fw_sram_reg_val = 0; @@ -530,7 +535,7 @@ bool psp_v3_1_compare_sram_data(struct psp_context *psp, return true; } -bool psp_v3_1_smu_reload_quirk(struct psp_context *psp) +static bool psp_v3_1_smu_reload_quirk(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; uint32_t reg; @@ -541,7 +546,7 @@ bool psp_v3_1_smu_reload_quirk(struct psp_context *psp) return (reg & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) ? true : false; } -int psp_v3_1_mode1_reset(struct psp_context *psp) +static int psp_v3_1_mode1_reset(struct psp_context *psp) { int ret; uint32_t offset; @@ -574,3 +579,23 @@ int psp_v3_1_mode1_reset(struct psp_context *psp) return 0; } + +static const struct psp_funcs psp_v3_1_funcs = { + .init_microcode = psp_v3_1_init_microcode, + .bootloader_load_sysdrv = psp_v3_1_bootloader_load_sysdrv, + .bootloader_load_sos = psp_v3_1_bootloader_load_sos, + .prep_cmd_buf = psp_v3_1_prep_cmd_buf, + .ring_init = psp_v3_1_ring_init, + .ring_create = psp_v3_1_ring_create, + .ring_stop = psp_v3_1_ring_stop, + .ring_destroy = psp_v3_1_ring_destroy, + .cmd_submit = psp_v3_1_cmd_submit, + .compare_sram_data = psp_v3_1_compare_sram_data, + .smu_reload_quirk = psp_v3_1_smu_reload_quirk, + .mode1_reset = psp_v3_1_mode1_reset, +}; + +void psp_v3_1_set_psp_funcs(struct psp_context *psp) +{ + psp->funcs = &psp_v3_1_funcs; +} diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.h b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.h index b05dbada7751..e411e31ba452 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.h +++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.h @@ -32,26 +32,6 @@ enum { PSP_BINARY_ALIGNMENT = 64 }; enum { PSP_BOOTLOADER_1_MEG_ALIGNMENT = 0x100000 }; enum { PSP_BOOTLOADER_8_MEM_ALIGNMENT = 0x800000 }; -extern int psp_v3_1_init_microcode(struct psp_context *psp); -extern int psp_v3_1_bootloader_load_sysdrv(struct psp_context *psp); -extern int psp_v3_1_bootloader_load_sos(struct psp_context *psp); -extern int psp_v3_1_prep_cmd_buf(struct amdgpu_firmware_info *ucode, - struct psp_gfx_cmd_resp *cmd); -extern int psp_v3_1_ring_init(struct psp_context *psp, - enum psp_ring_type ring_type); -extern int psp_v3_1_ring_create(struct psp_context *psp, - enum psp_ring_type ring_type); -extern int psp_v3_1_ring_stop(struct psp_context *psp, - enum psp_ring_type ring_type); -extern int psp_v3_1_ring_destroy(struct psp_context *psp, - enum psp_ring_type ring_type); -extern int psp_v3_1_cmd_submit(struct psp_context *psp, - struct amdgpu_firmware_info *ucode, - uint64_t cmd_buf_mc_addr, uint64_t fence_mc_addr, - int index); -extern bool psp_v3_1_compare_sram_data(struct psp_context *psp, - struct amdgpu_firmware_info *ucode, - enum AMDGPU_UCODE_ID ucode_type); -extern bool psp_v3_1_smu_reload_quirk(struct psp_context *psp); -extern int psp_v3_1_mode1_reset(struct psp_context *psp); +void psp_v3_1_set_psp_funcs(struct psp_context *psp); + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index d4787ad4d346..6ccc9d43a7b8 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -289,13 +289,6 @@ static void sdma_v2_4_ring_emit_hdp_flush(struct amdgpu_ring *ring) SDMA_PKT_POLL_REGMEM_DW5_INTERVAL(10)); /* retry count, poll interval */ } -static void sdma_v2_4_ring_emit_hdp_invalidate(struct amdgpu_ring *ring) -{ - amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_SRBM_WRITE) | - SDMA_PKT_SRBM_WRITE_HEADER_BYTE_EN(0xf)); - amdgpu_ring_write(ring, mmHDP_DEBUG0); - amdgpu_ring_write(ring, 1); -} /** * sdma_v2_4_ring_emit_fence - emit a fence on the DMA ring * @@ -346,7 +339,7 @@ static void sdma_v2_4_gfx_stop(struct amdgpu_device *adev) if ((adev->mman.buffer_funcs_ring == sdma0) || (adev->mman.buffer_funcs_ring == sdma1)) - amdgpu_ttm_set_active_vram_size(adev, adev->mc.visible_vram_size); + amdgpu_ttm_set_active_vram_size(adev, adev->gmc.visible_vram_size); for (i = 0; i < adev->sdma.num_instances; i++) { rb_cntl = RREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i]); @@ -491,7 +484,7 @@ static int sdma_v2_4_gfx_resume(struct amdgpu_device *adev) } if (adev->mman.buffer_funcs_ring == ring) - amdgpu_ttm_set_active_vram_size(adev, adev->mc.real_vram_size); + amdgpu_ttm_set_active_vram_size(adev, adev->gmc.real_vram_size); } return 0; @@ -861,20 +854,7 @@ static void sdma_v2_4_ring_emit_pipeline_sync(struct amdgpu_ring *ring) static void sdma_v2_4_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { - amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_SRBM_WRITE) | - SDMA_PKT_SRBM_WRITE_HEADER_BYTE_EN(0xf)); - if (vmid < 8) { - amdgpu_ring_write(ring, (mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR + vmid)); - } else { - amdgpu_ring_write(ring, (mmVM_CONTEXT8_PAGE_TABLE_BASE_ADDR + vmid - 8)); - } - amdgpu_ring_write(ring, pd_addr >> 12); - - /* flush TLB */ - amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_SRBM_WRITE) | - SDMA_PKT_SRBM_WRITE_HEADER_BYTE_EN(0xf)); - amdgpu_ring_write(ring, mmVM_INVALIDATE_REQUEST); - amdgpu_ring_write(ring, 1 << vmid); + amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); /* wait for flush */ amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_POLL_REGMEM) | @@ -888,6 +868,15 @@ static void sdma_v2_4_ring_emit_vm_flush(struct amdgpu_ring *ring, SDMA_PKT_POLL_REGMEM_DW5_INTERVAL(10)); /* retry count, poll interval */ } +static void sdma_v2_4_ring_emit_wreg(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val) +{ + amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_SRBM_WRITE) | + SDMA_PKT_SRBM_WRITE_HEADER_BYTE_EN(0xf)); + amdgpu_ring_write(ring, reg); + amdgpu_ring_write(ring, val); +} + static int sdma_v2_4_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -1203,9 +1192,9 @@ static const struct amdgpu_ring_funcs sdma_v2_4_ring_funcs = { .set_wptr = sdma_v2_4_ring_set_wptr, .emit_frame_size = 6 + /* sdma_v2_4_ring_emit_hdp_flush */ - 3 + /* sdma_v2_4_ring_emit_hdp_invalidate */ + 3 + /* hdp invalidate */ 6 + /* sdma_v2_4_ring_emit_pipeline_sync */ - 12 + /* sdma_v2_4_ring_emit_vm_flush */ + VI_FLUSH_GPU_TLB_NUM_WREG * 3 + 6 + /* sdma_v2_4_ring_emit_vm_flush */ 10 + 10 + 10, /* sdma_v2_4_ring_emit_fence x3 for user fence, vm fence */ .emit_ib_size = 7 + 6, /* sdma_v2_4_ring_emit_ib */ .emit_ib = sdma_v2_4_ring_emit_ib, @@ -1213,11 +1202,11 @@ static const struct amdgpu_ring_funcs sdma_v2_4_ring_funcs = { .emit_pipeline_sync = sdma_v2_4_ring_emit_pipeline_sync, .emit_vm_flush = sdma_v2_4_ring_emit_vm_flush, .emit_hdp_flush = sdma_v2_4_ring_emit_hdp_flush, - .emit_hdp_invalidate = sdma_v2_4_ring_emit_hdp_invalidate, .test_ring = sdma_v2_4_ring_test_ring, .test_ib = sdma_v2_4_ring_test_ib, .insert_nop = sdma_v2_4_ring_insert_nop, .pad_ib = sdma_v2_4_ring_pad_ib, + .emit_wreg = sdma_v2_4_ring_emit_wreg, }; static void sdma_v2_4_set_ring_funcs(struct amdgpu_device *adev) @@ -1316,9 +1305,6 @@ static const struct amdgpu_vm_pte_funcs sdma_v2_4_vm_pte_funcs = { .copy_pte = sdma_v2_4_vm_copy_pte, .write_pte = sdma_v2_4_vm_write_pte, - - .set_max_nums_pte_pde = 0x1fffff >> 3, - .set_pte_pde_num_dw = 10, .set_pte_pde = sdma_v2_4_vm_set_pte_pde, }; diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index 521978c40537..0c2b12ec0e9f 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -460,14 +460,6 @@ static void sdma_v3_0_ring_emit_hdp_flush(struct amdgpu_ring *ring) SDMA_PKT_POLL_REGMEM_DW5_INTERVAL(10)); /* retry count, poll interval */ } -static void sdma_v3_0_ring_emit_hdp_invalidate(struct amdgpu_ring *ring) -{ - amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_SRBM_WRITE) | - SDMA_PKT_SRBM_WRITE_HEADER_BYTE_EN(0xf)); - amdgpu_ring_write(ring, mmHDP_DEBUG0); - amdgpu_ring_write(ring, 1); -} - /** * sdma_v3_0_ring_emit_fence - emit a fence on the DMA ring * @@ -518,7 +510,7 @@ static void sdma_v3_0_gfx_stop(struct amdgpu_device *adev) if ((adev->mman.buffer_funcs_ring == sdma0) || (adev->mman.buffer_funcs_ring == sdma1)) - amdgpu_ttm_set_active_vram_size(adev, adev->mc.visible_vram_size); + amdgpu_ttm_set_active_vram_size(adev, adev->gmc.visible_vram_size); for (i = 0; i < adev->sdma.num_instances; i++) { rb_cntl = RREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i]); @@ -758,7 +750,7 @@ static int sdma_v3_0_gfx_resume(struct amdgpu_device *adev) } if (adev->mman.buffer_funcs_ring == ring) - amdgpu_ttm_set_active_vram_size(adev, adev->mc.real_vram_size); + amdgpu_ttm_set_active_vram_size(adev, adev->gmc.real_vram_size); } return 0; @@ -1127,20 +1119,7 @@ static void sdma_v3_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring) static void sdma_v3_0_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { - amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_SRBM_WRITE) | - SDMA_PKT_SRBM_WRITE_HEADER_BYTE_EN(0xf)); - if (vmid < 8) { - amdgpu_ring_write(ring, (mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR + vmid)); - } else { - amdgpu_ring_write(ring, (mmVM_CONTEXT8_PAGE_TABLE_BASE_ADDR + vmid - 8)); - } - amdgpu_ring_write(ring, pd_addr >> 12); - - /* flush TLB */ - amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_SRBM_WRITE) | - SDMA_PKT_SRBM_WRITE_HEADER_BYTE_EN(0xf)); - amdgpu_ring_write(ring, mmVM_INVALIDATE_REQUEST); - amdgpu_ring_write(ring, 1 << vmid); + amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); /* wait for flush */ amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_POLL_REGMEM) | @@ -1154,6 +1133,15 @@ static void sdma_v3_0_ring_emit_vm_flush(struct amdgpu_ring *ring, SDMA_PKT_POLL_REGMEM_DW5_INTERVAL(10)); /* retry count, poll interval */ } +static void sdma_v3_0_ring_emit_wreg(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val) +{ + amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_SRBM_WRITE) | + SDMA_PKT_SRBM_WRITE_HEADER_BYTE_EN(0xf)); + amdgpu_ring_write(ring, reg); + amdgpu_ring_write(ring, val); +} + static int sdma_v3_0_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -1637,9 +1625,9 @@ static const struct amdgpu_ring_funcs sdma_v3_0_ring_funcs = { .set_wptr = sdma_v3_0_ring_set_wptr, .emit_frame_size = 6 + /* sdma_v3_0_ring_emit_hdp_flush */ - 3 + /* sdma_v3_0_ring_emit_hdp_invalidate */ + 3 + /* hdp invalidate */ 6 + /* sdma_v3_0_ring_emit_pipeline_sync */ - 12 + /* sdma_v3_0_ring_emit_vm_flush */ + VI_FLUSH_GPU_TLB_NUM_WREG * 3 + 6 + /* sdma_v3_0_ring_emit_vm_flush */ 10 + 10 + 10, /* sdma_v3_0_ring_emit_fence x3 for user fence, vm fence */ .emit_ib_size = 7 + 6, /* sdma_v3_0_ring_emit_ib */ .emit_ib = sdma_v3_0_ring_emit_ib, @@ -1647,11 +1635,11 @@ static const struct amdgpu_ring_funcs sdma_v3_0_ring_funcs = { .emit_pipeline_sync = sdma_v3_0_ring_emit_pipeline_sync, .emit_vm_flush = sdma_v3_0_ring_emit_vm_flush, .emit_hdp_flush = sdma_v3_0_ring_emit_hdp_flush, - .emit_hdp_invalidate = sdma_v3_0_ring_emit_hdp_invalidate, .test_ring = sdma_v3_0_ring_test_ring, .test_ib = sdma_v3_0_ring_test_ib, .insert_nop = sdma_v3_0_ring_insert_nop, .pad_ib = sdma_v3_0_ring_pad_ib, + .emit_wreg = sdma_v3_0_ring_emit_wreg, }; static void sdma_v3_0_set_ring_funcs(struct amdgpu_device *adev) @@ -1750,10 +1738,6 @@ static const struct amdgpu_vm_pte_funcs sdma_v3_0_vm_pte_funcs = { .copy_pte = sdma_v3_0_vm_copy_pte, .write_pte = sdma_v3_0_vm_write_pte, - - /* not 0x3fffff due to HW limitation */ - .set_max_nums_pte_pde = 0x3fffe0 >> 3, - .set_pte_pde_num_dw = 10, .set_pte_pde = sdma_v3_0_vm_set_pte_pde, }; diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index e92fb372bc99..3d5385dda34c 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -375,16 +375,6 @@ static void sdma_v4_0_ring_emit_hdp_flush(struct amdgpu_ring *ring) SDMA_PKT_POLL_REGMEM_DW5_INTERVAL(10)); /* retry count, poll interval */ } -static void sdma_v4_0_ring_emit_hdp_invalidate(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - - amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_SRBM_WRITE) | - SDMA_PKT_SRBM_WRITE_HEADER_BYTE_EN(0xf)); - amdgpu_ring_write(ring, SOC15_REG_OFFSET(HDP, 0, mmHDP_READ_CACHE_INVALIDATE)); - amdgpu_ring_write(ring, 1); -} - /** * sdma_v4_0_ring_emit_fence - emit a fence on the DMA ring * @@ -440,7 +430,7 @@ static void sdma_v4_0_gfx_stop(struct amdgpu_device *adev) if ((adev->mman.buffer_funcs_ring == sdma0) || (adev->mman.buffer_funcs_ring == sdma1)) - amdgpu_ttm_set_active_vram_size(adev, adev->mc.visible_vram_size); + amdgpu_ttm_set_active_vram_size(adev, adev->gmc.visible_vram_size); for (i = 0; i < adev->sdma.num_instances; i++) { rb_cntl = RREG32(sdma_v4_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL)); @@ -682,7 +672,7 @@ static int sdma_v4_0_gfx_resume(struct amdgpu_device *adev) } if (adev->mman.buffer_funcs_ring == ring) - amdgpu_ttm_set_active_vram_size(adev, adev->mc.real_vram_size); + amdgpu_ttm_set_active_vram_size(adev, adev->gmc.real_vram_size); } @@ -1135,38 +1125,28 @@ static void sdma_v4_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring) static void sdma_v4_0_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { - struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; - uint32_t req = ring->adev->gart.gart_funcs->get_invalidate_req(vmid); - uint64_t flags = AMDGPU_PTE_VALID; - unsigned eng = ring->vm_inv_eng; - - amdgpu_gart_get_vm_pde(ring->adev, -1, &pd_addr, &flags); - pd_addr |= flags; + amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); +} +static void sdma_v4_0_ring_emit_wreg(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val) +{ amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_SRBM_WRITE) | SDMA_PKT_SRBM_WRITE_HEADER_BYTE_EN(0xf)); - amdgpu_ring_write(ring, hub->ctx0_ptb_addr_lo32 + vmid * 2); - amdgpu_ring_write(ring, lower_32_bits(pd_addr)); + amdgpu_ring_write(ring, reg); + amdgpu_ring_write(ring, val); +} - amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_SRBM_WRITE) | - SDMA_PKT_SRBM_WRITE_HEADER_BYTE_EN(0xf)); - amdgpu_ring_write(ring, hub->ctx0_ptb_addr_hi32 + vmid * 2); - amdgpu_ring_write(ring, upper_32_bits(pd_addr)); - - /* flush TLB */ - amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_SRBM_WRITE) | - SDMA_PKT_SRBM_WRITE_HEADER_BYTE_EN(0xf)); - amdgpu_ring_write(ring, hub->vm_inv_eng0_req + eng); - amdgpu_ring_write(ring, req); - - /* wait for flush */ +static void sdma_v4_0_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg, + uint32_t val, uint32_t mask) +{ amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_POLL_REGMEM) | SDMA_PKT_POLL_REGMEM_HEADER_HDP_FLUSH(0) | SDMA_PKT_POLL_REGMEM_HEADER_FUNC(3)); /* equal */ - amdgpu_ring_write(ring, (hub->vm_inv_eng0_ack + eng) << 2); + amdgpu_ring_write(ring, reg << 2); amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, 1 << vmid); /* reference */ - amdgpu_ring_write(ring, 1 << vmid); /* mask */ + amdgpu_ring_write(ring, val); /* reference */ + amdgpu_ring_write(ring, mask); /* mask */ amdgpu_ring_write(ring, SDMA_PKT_POLL_REGMEM_DW5_RETRY_COUNT(0xfff) | SDMA_PKT_POLL_REGMEM_DW5_INTERVAL(10)); } @@ -1592,9 +1572,11 @@ static const struct amdgpu_ring_funcs sdma_v4_0_ring_funcs = { .set_wptr = sdma_v4_0_ring_set_wptr, .emit_frame_size = 6 + /* sdma_v4_0_ring_emit_hdp_flush */ - 3 + /* sdma_v4_0_ring_emit_hdp_invalidate */ + 3 + /* hdp invalidate */ 6 + /* sdma_v4_0_ring_emit_pipeline_sync */ - 18 + /* sdma_v4_0_ring_emit_vm_flush */ + /* sdma_v4_0_ring_emit_vm_flush */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 6 + 10 + 10 + 10, /* sdma_v4_0_ring_emit_fence x3 for user fence, vm fence */ .emit_ib_size = 7 + 6, /* sdma_v4_0_ring_emit_ib */ .emit_ib = sdma_v4_0_ring_emit_ib, @@ -1602,11 +1584,12 @@ static const struct amdgpu_ring_funcs sdma_v4_0_ring_funcs = { .emit_pipeline_sync = sdma_v4_0_ring_emit_pipeline_sync, .emit_vm_flush = sdma_v4_0_ring_emit_vm_flush, .emit_hdp_flush = sdma_v4_0_ring_emit_hdp_flush, - .emit_hdp_invalidate = sdma_v4_0_ring_emit_hdp_invalidate, .test_ring = sdma_v4_0_ring_test_ring, .test_ib = sdma_v4_0_ring_test_ib, .insert_nop = sdma_v4_0_ring_insert_nop, .pad_ib = sdma_v4_0_ring_pad_ib, + .emit_wreg = sdma_v4_0_ring_emit_wreg, + .emit_reg_wait = sdma_v4_0_ring_emit_reg_wait, }; static void sdma_v4_0_set_ring_funcs(struct amdgpu_device *adev) @@ -1705,9 +1688,6 @@ static const struct amdgpu_vm_pte_funcs sdma_v4_0_vm_pte_funcs = { .copy_pte = sdma_v4_0_vm_copy_pte, .write_pte = sdma_v4_0_vm_write_pte, - - .set_max_nums_pte_pde = 0x400000 >> 3, - .set_pte_pde_num_dw = 10, .set_pte_pde = sdma_v4_0_vm_set_pte_pde, }; diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index 543101d5a5ed..f20c4b7414e8 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -1230,6 +1230,27 @@ static void si_detect_hw_virtualization(struct amdgpu_device *adev) adev->virt.caps |= AMDGPU_PASSTHROUGH_MODE; } +static void si_flush_hdp(struct amdgpu_device *adev, struct amdgpu_ring *ring) +{ + if (!ring || !ring->funcs->emit_wreg) { + WREG32(mmHDP_MEM_COHERENCY_FLUSH_CNTL, 1); + RREG32(mmHDP_MEM_COHERENCY_FLUSH_CNTL); + } else { + amdgpu_ring_emit_wreg(ring, mmHDP_MEM_COHERENCY_FLUSH_CNTL, 1); + } +} + +static void si_invalidate_hdp(struct amdgpu_device *adev, + struct amdgpu_ring *ring) +{ + if (!ring || !ring->funcs->emit_wreg) { + WREG32(mmHDP_DEBUG0, 1); + RREG32(mmHDP_DEBUG0); + } else { + amdgpu_ring_emit_wreg(ring, mmHDP_DEBUG0, 1); + } +} + static const struct amdgpu_asic_funcs si_asic_funcs = { .read_disabled_bios = &si_read_disabled_bios, @@ -1241,6 +1262,8 @@ static const struct amdgpu_asic_funcs si_asic_funcs = .set_uvd_clocks = &si_set_uvd_clocks, .set_vce_clocks = NULL, .get_config_memsize = &si_get_config_memsize, + .flush_hdp = &si_flush_hdp, + .invalidate_hdp = &si_invalidate_hdp, }; static uint32_t si_get_rev_id(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/si.h b/drivers/gpu/drm/amd/amdgpu/si.h index 589225080c24..06ed7212a0d6 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.h +++ b/drivers/gpu/drm/amd/amdgpu/si.h @@ -24,6 +24,8 @@ #ifndef __SI_H__ #define __SI_H__ +#define SI_FLUSH_GPU_TLB_NUM_WREG 2 + void si_srbm_select(struct amdgpu_device *adev, u32 me, u32 pipe, u32 queue, u32 vmid); int si_set_ip_blocks(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/si_dma.c b/drivers/gpu/drm/amd/amdgpu/si_dma.c index 9a29c1399091..acbf5afa4f38 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dma.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dma.c @@ -24,6 +24,7 @@ #include #include "amdgpu.h" #include "amdgpu_trace.h" +#include "si.h" #include "sid.h" const u32 sdma_offsets[SDMA_MAX_INSTANCE] = @@ -74,20 +75,6 @@ static void si_dma_ring_emit_ib(struct amdgpu_ring *ring, } -static void si_dma_ring_emit_hdp_flush(struct amdgpu_ring *ring) -{ - amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); - amdgpu_ring_write(ring, (0xf << 16) | (HDP_MEM_COHERENCY_FLUSH_CNTL)); - amdgpu_ring_write(ring, 1); -} - -static void si_dma_ring_emit_hdp_invalidate(struct amdgpu_ring *ring) -{ - amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); - amdgpu_ring_write(ring, (0xf << 16) | (HDP_DEBUG0)); - amdgpu_ring_write(ring, 1); -} - /** * si_dma_ring_emit_fence - emit a fence on the DMA ring * @@ -134,7 +121,7 @@ static void si_dma_stop(struct amdgpu_device *adev) WREG32(DMA_RB_CNTL + sdma_offsets[i], rb_cntl); if (adev->mman.buffer_funcs_ring == ring) - amdgpu_ttm_set_active_vram_size(adev, adev->mc.visible_vram_size); + amdgpu_ttm_set_active_vram_size(adev, adev->gmc.visible_vram_size); ring->ready = false; } } @@ -197,7 +184,7 @@ static int si_dma_start(struct amdgpu_device *adev) } if (adev->mman.buffer_funcs_ring == ring) - amdgpu_ttm_set_active_vram_size(adev, adev->mc.real_vram_size); + amdgpu_ttm_set_active_vram_size(adev, adev->gmc.real_vram_size); } return 0; @@ -475,17 +462,7 @@ static void si_dma_ring_emit_pipeline_sync(struct amdgpu_ring *ring) static void si_dma_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { - amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); - if (vmid < 8) - amdgpu_ring_write(ring, (0xf << 16) | (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + vmid)); - else - amdgpu_ring_write(ring, (0xf << 16) | (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + (vmid - 8))); - amdgpu_ring_write(ring, pd_addr >> 12); - - /* bits 0-7 are the VM contexts0-7 */ - amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); - amdgpu_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST)); - amdgpu_ring_write(ring, 1 << vmid); + amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); /* wait for invalidate to complete */ amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_POLL_REG_MEM, 0, 0, 0, 0)); @@ -496,6 +473,14 @@ static void si_dma_ring_emit_vm_flush(struct amdgpu_ring *ring, amdgpu_ring_write(ring, (0 << 28) | 0x20); /* func(always) | poll interval */ } +static void si_dma_ring_emit_wreg(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val) +{ + amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); + amdgpu_ring_write(ring, (0xf << 16) | reg); + amdgpu_ring_write(ring, val); +} + static int si_dma_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -772,22 +757,20 @@ static const struct amdgpu_ring_funcs si_dma_ring_funcs = { .get_wptr = si_dma_ring_get_wptr, .set_wptr = si_dma_ring_set_wptr, .emit_frame_size = - 3 + /* si_dma_ring_emit_hdp_flush */ - 3 + /* si_dma_ring_emit_hdp_invalidate */ + 3 + 3 + /* hdp flush / invalidate */ 6 + /* si_dma_ring_emit_pipeline_sync */ - 12 + /* si_dma_ring_emit_vm_flush */ + SI_FLUSH_GPU_TLB_NUM_WREG * 3 + 6 + /* si_dma_ring_emit_vm_flush */ 9 + 9 + 9, /* si_dma_ring_emit_fence x3 for user fence, vm fence */ .emit_ib_size = 7 + 3, /* si_dma_ring_emit_ib */ .emit_ib = si_dma_ring_emit_ib, .emit_fence = si_dma_ring_emit_fence, .emit_pipeline_sync = si_dma_ring_emit_pipeline_sync, .emit_vm_flush = si_dma_ring_emit_vm_flush, - .emit_hdp_flush = si_dma_ring_emit_hdp_flush, - .emit_hdp_invalidate = si_dma_ring_emit_hdp_invalidate, .test_ring = si_dma_ring_test_ring, .test_ib = si_dma_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, .pad_ib = si_dma_ring_pad_ib, + .emit_wreg = si_dma_ring_emit_wreg, }; static void si_dma_set_ring_funcs(struct amdgpu_device *adev) @@ -891,9 +874,6 @@ static const struct amdgpu_vm_pte_funcs si_dma_vm_pte_funcs = { .copy_pte = si_dma_vm_copy_pte, .write_pte = si_dma_vm_write_pte, - - .set_max_nums_pte_pde = 0xffff8 >> 3, - .set_pte_pde_num_dw = 9, .set_pte_pde = si_dma_vm_set_pte_pde, }; diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c index ce675a7f179a..8138053fcef1 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c @@ -3064,7 +3064,7 @@ static bool si_dpm_vblank_too_short(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 vblank_time = amdgpu_dpm_get_vblank_time(adev); /* we never hit the non-gddr5 limit so disable it */ - u32 switch_limit = adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 0; + u32 switch_limit = adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 0; if (vblank_time < switch_limit) return true; @@ -4350,7 +4350,7 @@ static u8 si_get_strobe_mode_settings(struct amdgpu_device *adev, u32 mclk) if (mclk <= pi->mclk_strobe_mode_threshold) strobe_mode = true; - if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) + if (adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) result = si_get_mclk_frequency_ratio(mclk, strobe_mode); else result = si_get_ddr3_mclk_frequency_ratio(mclk); @@ -4937,7 +4937,7 @@ static int si_populate_smc_initial_state(struct amdgpu_device *adev, table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp); table->initialState.levels[0].gen2PCIE = (u8)si_pi->boot_pcie_gen; - if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) { + if (adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) { table->initialState.levels[0].strobeMode = si_get_strobe_mode_settings(adev, initial_state->performance_levels[0].mclk); @@ -5208,7 +5208,7 @@ static int si_init_smc_table(struct amdgpu_device *adev) if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC; - if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) + if (adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5; if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REVERT_GPIO5_POLARITY) @@ -5385,7 +5385,7 @@ static int si_populate_mclk_value(struct amdgpu_device *adev, mpll_ad_func_cntl &= ~YCLK_POST_DIV_MASK; mpll_ad_func_cntl |= YCLK_POST_DIV(mpll_param.post_div); - if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) { + if (adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) { mpll_dq_func_cntl &= ~(YCLK_SEL_MASK | YCLK_POST_DIV_MASK); mpll_dq_func_cntl |= YCLK_SEL(mpll_param.yclk_sel) | YCLK_POST_DIV(mpll_param.post_div); @@ -5397,7 +5397,7 @@ static int si_populate_mclk_value(struct amdgpu_device *adev, u32 tmp; u32 reference_clock = adev->clock.mpll.reference_freq; - if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) + if (adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) freq_nom = memory_clock * 4; else freq_nom = memory_clock * 2; @@ -5489,7 +5489,7 @@ static int si_convert_power_level_to_smc(struct amdgpu_device *adev, level->mcFlags |= SISLANDS_SMC_MC_PG_EN; } - if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) { + if (adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) { if (pl->mclk > pi->mclk_edc_enable_threshold) level->mcFlags |= SISLANDS_SMC_MC_EDC_RD_FLAG; @@ -5860,12 +5860,12 @@ static int si_set_mc_special_registers(struct amdgpu_device *adev, table->mc_reg_table_entry[k].mc_data[j] = (temp_reg & 0xffff0000) | (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff); - if (adev->mc.vram_type != AMDGPU_VRAM_TYPE_GDDR5) + if (adev->gmc.vram_type != AMDGPU_VRAM_TYPE_GDDR5) table->mc_reg_table_entry[k].mc_data[j] |= 0x100; } j++; - if (adev->mc.vram_type != AMDGPU_VRAM_TYPE_GDDR5) { + if (adev->gmc.vram_type != AMDGPU_VRAM_TYPE_GDDR5) { if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE) return -EINVAL; table->mc_reg_address[j].s1 = MC_PMG_AUTO_CMD; @@ -8056,7 +8056,6 @@ const struct amd_ip_funcs si_dpm_ip_funcs = { }; const struct amd_pm_funcs si_dpm_funcs = { - .get_temperature = &si_dpm_get_temp, .pre_set_power_state = &si_dpm_pre_set_power_state, .set_power_state = &si_dpm_set_power_state, .post_set_power_state = &si_dpm_post_set_power_state, diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index a04a033f57de..8dc8b72ed49b 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -417,12 +417,7 @@ static int soc15_asic_reset(struct amdgpu_device *adev) pci_save_state(adev->pdev); - for (i = 0; i < AMDGPU_MAX_IP_NUM; i++) { - if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP){ - adev->ip_blocks[i].version->funcs->soft_reset((void *)adev); - break; - } - } + psp_gpu_reset(adev); pci_restore_state(adev->pdev); @@ -583,6 +578,21 @@ static uint32_t soc15_get_rev_id(struct amdgpu_device *adev) return adev->nbio_funcs->get_rev_id(adev); } +static void soc15_flush_hdp(struct amdgpu_device *adev, struct amdgpu_ring *ring) +{ + adev->nbio_funcs->hdp_flush(adev, ring); +} + +static void soc15_invalidate_hdp(struct amdgpu_device *adev, + struct amdgpu_ring *ring) +{ + if (!ring || !ring->funcs->emit_wreg) + WREG32_SOC15_NO_KIQ(NBIO, 0, mmHDP_READ_CACHE_INVALIDATE, 1); + else + amdgpu_ring_emit_wreg(ring, SOC15_REG_OFFSET( + HDP, 0, mmHDP_READ_CACHE_INVALIDATE), 1); +} + static const struct amdgpu_asic_funcs soc15_asic_funcs = { .read_disabled_bios = &soc15_read_disabled_bios, @@ -594,6 +604,8 @@ static const struct amdgpu_asic_funcs soc15_asic_funcs = .set_uvd_clocks = &soc15_set_uvd_clocks, .set_vce_clocks = &soc15_set_vce_clocks, .get_config_memsize = &soc15_get_config_memsize, + .flush_hdp = &soc15_flush_hdp, + .invalidate_hdp = &soc15_invalidate_hdp, }; static int soc15_common_early_init(void *handle) diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.h b/drivers/gpu/drm/amd/amdgpu/soc15.h index 26b3feac5d06..f70da8a29f86 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.h +++ b/drivers/gpu/drm/amd/amdgpu/soc15.h @@ -27,6 +27,9 @@ #include "nbio_v6_1.h" #include "nbio_v7_0.h" +#define SOC15_FLUSH_GPU_TLB_NUM_WREG 4 +#define SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT 1 + extern const struct amd_ip_funcs soc15_common_ip_funcs; struct soc15_reg_golden { diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c index 5995ffc183de..18435389bae4 100644 --- a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c @@ -271,7 +271,7 @@ static void tonga_ih_decode_iv(struct amdgpu_device *adev, entry->src_data[0] = dw[1] & 0xfffffff; entry->ring_id = dw[2] & 0xff; entry->vmid = (dw[2] >> 8) & 0xff; - entry->pas_id = (dw[2] >> 16) & 0xffff; + entry->pasid = (dw[2] >> 16) & 0xffff; /* wptr/rptr are in bytes! */ adev->irq.ih.rptr += 16; diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c index 8ab10c220910..948bb9437757 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c @@ -463,32 +463,6 @@ static void uvd_v4_2_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq amdgpu_ring_write(ring, 2); } -/** - * uvd_v4_2_ring_emit_hdp_flush - emit an hdp flush - * - * @ring: amdgpu_ring pointer - * - * Emits an hdp flush. - */ -static void uvd_v4_2_ring_emit_hdp_flush(struct amdgpu_ring *ring) -{ - amdgpu_ring_write(ring, PACKET0(mmHDP_MEM_COHERENCY_FLUSH_CNTL, 0)); - amdgpu_ring_write(ring, 0); -} - -/** - * uvd_v4_2_ring_hdp_invalidate - emit an hdp invalidate - * - * @ring: amdgpu_ring pointer - * - * Emits an hdp invalidate. - */ -static void uvd_v4_2_ring_emit_hdp_invalidate(struct amdgpu_ring *ring) -{ - amdgpu_ring_write(ring, PACKET0(mmHDP_DEBUG0, 0)); - amdgpu_ring_write(ring, 1); -} - /** * uvd_v4_2_ring_test_ring - register write test * @@ -765,14 +739,10 @@ static const struct amdgpu_ring_funcs uvd_v4_2_ring_funcs = { .set_wptr = uvd_v4_2_ring_set_wptr, .parse_cs = amdgpu_uvd_ring_parse_cs, .emit_frame_size = - 2 + /* uvd_v4_2_ring_emit_hdp_flush */ - 2 + /* uvd_v4_2_ring_emit_hdp_invalidate */ 14, /* uvd_v4_2_ring_emit_fence x1 no user fence */ .emit_ib_size = 4, /* uvd_v4_2_ring_emit_ib */ .emit_ib = uvd_v4_2_ring_emit_ib, .emit_fence = uvd_v4_2_ring_emit_fence, - .emit_hdp_flush = uvd_v4_2_ring_emit_hdp_flush, - .emit_hdp_invalidate = uvd_v4_2_ring_emit_hdp_invalidate, .test_ring = uvd_v4_2_ring_test_ring, .test_ib = amdgpu_uvd_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c index c1fe30cdba32..6445d55e7d5a 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c @@ -478,32 +478,6 @@ static void uvd_v5_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq amdgpu_ring_write(ring, 2); } -/** - * uvd_v5_0_ring_emit_hdp_flush - emit an hdp flush - * - * @ring: amdgpu_ring pointer - * - * Emits an hdp flush. - */ -static void uvd_v5_0_ring_emit_hdp_flush(struct amdgpu_ring *ring) -{ - amdgpu_ring_write(ring, PACKET0(mmHDP_MEM_COHERENCY_FLUSH_CNTL, 0)); - amdgpu_ring_write(ring, 0); -} - -/** - * uvd_v5_0_ring_hdp_invalidate - emit an hdp invalidate - * - * @ring: amdgpu_ring pointer - * - * Emits an hdp invalidate. - */ -static void uvd_v5_0_ring_emit_hdp_invalidate(struct amdgpu_ring *ring) -{ - amdgpu_ring_write(ring, PACKET0(mmHDP_DEBUG0, 0)); - amdgpu_ring_write(ring, 1); -} - /** * uvd_v5_0_ring_test_ring - register write test * @@ -873,14 +847,10 @@ static const struct amdgpu_ring_funcs uvd_v5_0_ring_funcs = { .set_wptr = uvd_v5_0_ring_set_wptr, .parse_cs = amdgpu_uvd_ring_parse_cs, .emit_frame_size = - 2 + /* uvd_v5_0_ring_emit_hdp_flush */ - 2 + /* uvd_v5_0_ring_emit_hdp_invalidate */ 14, /* uvd_v5_0_ring_emit_fence x1 no user fence */ .emit_ib_size = 6, /* uvd_v5_0_ring_emit_ib */ .emit_ib = uvd_v5_0_ring_emit_ib, .emit_fence = uvd_v5_0_ring_emit_fence, - .emit_hdp_flush = uvd_v5_0_ring_emit_hdp_flush, - .emit_hdp_invalidate = uvd_v5_0_ring_emit_hdp_invalidate, .test_ring = uvd_v5_0_ring_test_ring, .test_ib = amdgpu_uvd_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index b2bfedaf57f1..a3e64e22c93c 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -963,32 +963,6 @@ static void uvd_v6_0_enc_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, amdgpu_ring_write(ring, HEVC_ENC_CMD_TRAP); } -/** - * uvd_v6_0_ring_emit_hdp_flush - emit an hdp flush - * - * @ring: amdgpu_ring pointer - * - * Emits an hdp flush. - */ -static void uvd_v6_0_ring_emit_hdp_flush(struct amdgpu_ring *ring) -{ - amdgpu_ring_write(ring, PACKET0(mmHDP_MEM_COHERENCY_FLUSH_CNTL, 0)); - amdgpu_ring_write(ring, 0); -} - -/** - * uvd_v6_0_ring_hdp_invalidate - emit an hdp invalidate - * - * @ring: amdgpu_ring pointer - * - * Emits an hdp invalidate. - */ -static void uvd_v6_0_ring_emit_hdp_invalidate(struct amdgpu_ring *ring) -{ - amdgpu_ring_write(ring, PACKET0(mmHDP_DEBUG0, 0)); - amdgpu_ring_write(ring, 1); -} - /** * uvd_v6_0_ring_test_ring - register write test * @@ -1072,29 +1046,21 @@ static void uvd_v6_0_enc_ring_emit_ib(struct amdgpu_ring *ring, amdgpu_ring_write(ring, ib->length_dw); } -static void uvd_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring, - unsigned vmid, uint64_t pd_addr) +static void uvd_v6_0_ring_emit_wreg(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val) { - uint32_t reg; - - if (vmid < 8) - reg = mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR + vmid; - else - reg = mmVM_CONTEXT8_PAGE_TABLE_BASE_ADDR + vmid - 8; - amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_DATA0, 0)); amdgpu_ring_write(ring, reg << 2); amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_DATA1, 0)); - amdgpu_ring_write(ring, pd_addr >> 12); + amdgpu_ring_write(ring, val); amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_CMD, 0)); amdgpu_ring_write(ring, 0x8); +} - amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_DATA0, 0)); - amdgpu_ring_write(ring, mmVM_INVALIDATE_REQUEST << 2); - amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_DATA1, 0)); - amdgpu_ring_write(ring, 1 << vmid); - amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_CMD, 0)); - amdgpu_ring_write(ring, 0x8); +static void uvd_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring, + unsigned vmid, uint64_t pd_addr) +{ + amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); amdgpu_ring_write(ring, PACKET0(mmUVD_GPCOM_VCPU_DATA0, 0)); amdgpu_ring_write(ring, mmVM_INVALIDATE_REQUEST << 2); @@ -1140,7 +1106,7 @@ static void uvd_v6_0_enc_ring_insert_end(struct amdgpu_ring *ring) } static void uvd_v6_0_enc_ring_emit_vm_flush(struct amdgpu_ring *ring, - unsigned int vmid, uint64_t pd_addr) + unsigned int vmid, uint64_t pd_addr) { amdgpu_ring_write(ring, HEVC_ENC_CMD_UPDATE_PTB); amdgpu_ring_write(ring, vmid); @@ -1562,21 +1528,19 @@ static const struct amdgpu_ring_funcs uvd_v6_0_ring_phys_funcs = { .set_wptr = uvd_v6_0_ring_set_wptr, .parse_cs = amdgpu_uvd_ring_parse_cs, .emit_frame_size = - 2 + /* uvd_v6_0_ring_emit_hdp_flush */ - 2 + /* uvd_v6_0_ring_emit_hdp_invalidate */ + 6 + 6 + /* hdp flush / invalidate */ 10 + /* uvd_v6_0_ring_emit_pipeline_sync */ 14, /* uvd_v6_0_ring_emit_fence x1 no user fence */ .emit_ib_size = 8, /* uvd_v6_0_ring_emit_ib */ .emit_ib = uvd_v6_0_ring_emit_ib, .emit_fence = uvd_v6_0_ring_emit_fence, - .emit_hdp_flush = uvd_v6_0_ring_emit_hdp_flush, - .emit_hdp_invalidate = uvd_v6_0_ring_emit_hdp_invalidate, .test_ring = uvd_v6_0_ring_test_ring, .test_ib = amdgpu_uvd_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, .pad_ib = amdgpu_ring_generic_pad_ib, .begin_use = amdgpu_uvd_ring_begin_use, .end_use = amdgpu_uvd_ring_end_use, + .emit_wreg = uvd_v6_0_ring_emit_wreg, }; static const struct amdgpu_ring_funcs uvd_v6_0_ring_vm_funcs = { @@ -1588,24 +1552,22 @@ static const struct amdgpu_ring_funcs uvd_v6_0_ring_vm_funcs = { .get_wptr = uvd_v6_0_ring_get_wptr, .set_wptr = uvd_v6_0_ring_set_wptr, .emit_frame_size = - 2 + /* uvd_v6_0_ring_emit_hdp_flush */ - 2 + /* uvd_v6_0_ring_emit_hdp_invalidate */ + 6 + 6 + /* hdp flush / invalidate */ 10 + /* uvd_v6_0_ring_emit_pipeline_sync */ - 20 + /* uvd_v6_0_ring_emit_vm_flush */ + VI_FLUSH_GPU_TLB_NUM_WREG * 6 + 8 + /* uvd_v6_0_ring_emit_vm_flush */ 14 + 14, /* uvd_v6_0_ring_emit_fence x2 vm fence */ .emit_ib_size = 8, /* uvd_v6_0_ring_emit_ib */ .emit_ib = uvd_v6_0_ring_emit_ib, .emit_fence = uvd_v6_0_ring_emit_fence, .emit_vm_flush = uvd_v6_0_ring_emit_vm_flush, .emit_pipeline_sync = uvd_v6_0_ring_emit_pipeline_sync, - .emit_hdp_flush = uvd_v6_0_ring_emit_hdp_flush, - .emit_hdp_invalidate = uvd_v6_0_ring_emit_hdp_invalidate, .test_ring = uvd_v6_0_ring_test_ring, .test_ib = amdgpu_uvd_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, .pad_ib = amdgpu_ring_generic_pad_ib, .begin_use = amdgpu_uvd_ring_begin_use, .end_use = amdgpu_uvd_ring_end_use, + .emit_wreg = uvd_v6_0_ring_emit_wreg, }; static const struct amdgpu_ring_funcs uvd_v6_0_enc_ring_vm_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c index 6b95f4f344b5..e54cc3ca2303 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c @@ -25,6 +25,7 @@ #include #include "amdgpu.h" #include "amdgpu_uvd.h" +#include "soc15.h" #include "soc15d.h" #include "soc15_common.h" #include "mmsch_v1_0.h" @@ -1134,37 +1135,6 @@ static void uvd_v7_0_enc_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, amdgpu_ring_write(ring, HEVC_ENC_CMD_TRAP); } -/** - * uvd_v7_0_ring_emit_hdp_flush - emit an hdp flush - * - * @ring: amdgpu_ring pointer - * - * Emits an hdp flush. - */ -static void uvd_v7_0_ring_emit_hdp_flush(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - - amdgpu_ring_write(ring, PACKET0(SOC15_REG_OFFSET(NBIF, 0, - mmHDP_MEM_COHERENCY_FLUSH_CNTL), 0)); - amdgpu_ring_write(ring, 0); -} - -/** - * uvd_v7_0_ring_hdp_invalidate - emit an hdp invalidate - * - * @ring: amdgpu_ring pointer - * - * Emits an hdp invalidate. - */ -static void uvd_v7_0_ring_emit_hdp_invalidate(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - - amdgpu_ring_write(ring, PACKET0(SOC15_REG_OFFSET(HDP, 0, mmHDP_READ_CACHE_INVALIDATE), 0)); - amdgpu_ring_write(ring, 1); -} - /** * uvd_v7_0_ring_test_ring - register write test * @@ -1255,33 +1225,33 @@ static void uvd_v7_0_enc_ring_emit_ib(struct amdgpu_ring *ring, amdgpu_ring_write(ring, ib->length_dw); } -static void uvd_v7_0_vm_reg_write(struct amdgpu_ring *ring, - uint32_t data0, uint32_t data1) +static void uvd_v7_0_ring_emit_wreg(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val) { struct amdgpu_device *adev = ring->adev; amdgpu_ring_write(ring, PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_GPCOM_VCPU_DATA0), 0)); - amdgpu_ring_write(ring, data0); + amdgpu_ring_write(ring, reg << 2); amdgpu_ring_write(ring, PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_GPCOM_VCPU_DATA1), 0)); - amdgpu_ring_write(ring, data1); + amdgpu_ring_write(ring, val); amdgpu_ring_write(ring, PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_GPCOM_VCPU_CMD), 0)); amdgpu_ring_write(ring, 8); } -static void uvd_v7_0_vm_reg_wait(struct amdgpu_ring *ring, - uint32_t data0, uint32_t data1, uint32_t mask) +static void uvd_v7_0_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg, + uint32_t val, uint32_t mask) { struct amdgpu_device *adev = ring->adev; amdgpu_ring_write(ring, PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_GPCOM_VCPU_DATA0), 0)); - amdgpu_ring_write(ring, data0); + amdgpu_ring_write(ring, reg << 2); amdgpu_ring_write(ring, PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_GPCOM_VCPU_DATA1), 0)); - amdgpu_ring_write(ring, data1); + amdgpu_ring_write(ring, val); amdgpu_ring_write(ring, PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_GP_SCRATCH8), 0)); amdgpu_ring_write(ring, mask); @@ -1294,37 +1264,15 @@ static void uvd_v7_0_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; - uint32_t req = ring->adev->gart.gart_funcs->get_invalidate_req(vmid); - uint64_t flags = AMDGPU_PTE_VALID; - unsigned eng = ring->vm_inv_eng; uint32_t data0, data1, mask; - amdgpu_gart_get_vm_pde(ring->adev, -1, &pd_addr, &flags); - pd_addr |= flags; + pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); - data0 = (hub->ctx0_ptb_addr_hi32 + vmid * 2) << 2; - data1 = upper_32_bits(pd_addr); - uvd_v7_0_vm_reg_write(ring, data0, data1); - - data0 = (hub->ctx0_ptb_addr_lo32 + vmid * 2) << 2; - data1 = lower_32_bits(pd_addr); - uvd_v7_0_vm_reg_write(ring, data0, data1); - - data0 = (hub->ctx0_ptb_addr_lo32 + vmid * 2) << 2; + /* wait for reg writes */ + data0 = hub->ctx0_ptb_addr_lo32 + vmid * 2; data1 = lower_32_bits(pd_addr); mask = 0xffffffff; - uvd_v7_0_vm_reg_wait(ring, data0, data1, mask); - - /* flush TLB */ - data0 = (hub->vm_inv_eng0_req + eng) << 2; - data1 = req; - uvd_v7_0_vm_reg_write(ring, data0, data1); - - /* wait for flush */ - data0 = (hub->vm_inv_eng0_ack + eng) << 2; - data1 = 1 << vmid; - mask = 1 << vmid; - uvd_v7_0_vm_reg_wait(ring, data0, data1, mask); + uvd_v7_0_ring_emit_reg_wait(ring, data0, data1, mask); } static void uvd_v7_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count) @@ -1342,40 +1290,34 @@ static void uvd_v7_0_enc_ring_insert_end(struct amdgpu_ring *ring) amdgpu_ring_write(ring, HEVC_ENC_CMD_END); } +static void uvd_v7_0_enc_ring_emit_reg_wait(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val, + uint32_t mask) +{ + amdgpu_ring_write(ring, HEVC_ENC_CMD_REG_WAIT); + amdgpu_ring_write(ring, reg << 2); + amdgpu_ring_write(ring, mask); + amdgpu_ring_write(ring, val); +} + static void uvd_v7_0_enc_ring_emit_vm_flush(struct amdgpu_ring *ring, - unsigned int vmid, uint64_t pd_addr) + unsigned int vmid, uint64_t pd_addr) { struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; - uint32_t req = ring->adev->gart.gart_funcs->get_invalidate_req(vmid); - uint64_t flags = AMDGPU_PTE_VALID; - unsigned eng = ring->vm_inv_eng; - amdgpu_gart_get_vm_pde(ring->adev, -1, &pd_addr, &flags); - pd_addr |= flags; + pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); + /* wait for reg writes */ + uvd_v7_0_enc_ring_emit_reg_wait(ring, hub->ctx0_ptb_addr_lo32 + vmid * 2, + lower_32_bits(pd_addr), 0xffffffff); +} + +static void uvd_v7_0_enc_ring_emit_wreg(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val) +{ amdgpu_ring_write(ring, HEVC_ENC_CMD_REG_WRITE); - amdgpu_ring_write(ring, (hub->ctx0_ptb_addr_hi32 + vmid * 2) << 2); - amdgpu_ring_write(ring, upper_32_bits(pd_addr)); - - amdgpu_ring_write(ring, HEVC_ENC_CMD_REG_WRITE); - amdgpu_ring_write(ring, (hub->ctx0_ptb_addr_lo32 + vmid * 2) << 2); - amdgpu_ring_write(ring, lower_32_bits(pd_addr)); - - amdgpu_ring_write(ring, HEVC_ENC_CMD_REG_WAIT); - amdgpu_ring_write(ring, (hub->ctx0_ptb_addr_lo32 + vmid * 2) << 2); - amdgpu_ring_write(ring, 0xffffffff); - amdgpu_ring_write(ring, lower_32_bits(pd_addr)); - - /* flush TLB */ - amdgpu_ring_write(ring, HEVC_ENC_CMD_REG_WRITE); - amdgpu_ring_write(ring, (hub->vm_inv_eng0_req + eng) << 2); - amdgpu_ring_write(ring, req); - - /* wait for flush */ - amdgpu_ring_write(ring, HEVC_ENC_CMD_REG_WAIT); - amdgpu_ring_write(ring, (hub->vm_inv_eng0_ack + eng) << 2); - amdgpu_ring_write(ring, 1 << vmid); - amdgpu_ring_write(ring, 1 << vmid); + amdgpu_ring_write(ring, reg << 2); + amdgpu_ring_write(ring, val); } #if 0 @@ -1712,22 +1654,23 @@ static const struct amdgpu_ring_funcs uvd_v7_0_ring_vm_funcs = { .get_wptr = uvd_v7_0_ring_get_wptr, .set_wptr = uvd_v7_0_ring_set_wptr, .emit_frame_size = - 2 + /* uvd_v7_0_ring_emit_hdp_flush */ - 2 + /* uvd_v7_0_ring_emit_hdp_invalidate */ - 34 + /* uvd_v7_0_ring_emit_vm_flush */ + 6 + 6 + /* hdp flush / invalidate */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 8 + + 8 + /* uvd_v7_0_ring_emit_vm_flush */ 14 + 14, /* uvd_v7_0_ring_emit_fence x2 vm fence */ .emit_ib_size = 8, /* uvd_v7_0_ring_emit_ib */ .emit_ib = uvd_v7_0_ring_emit_ib, .emit_fence = uvd_v7_0_ring_emit_fence, .emit_vm_flush = uvd_v7_0_ring_emit_vm_flush, - .emit_hdp_flush = uvd_v7_0_ring_emit_hdp_flush, - .emit_hdp_invalidate = uvd_v7_0_ring_emit_hdp_invalidate, .test_ring = uvd_v7_0_ring_test_ring, .test_ib = amdgpu_uvd_ring_test_ib, .insert_nop = uvd_v7_0_ring_insert_nop, .pad_ib = amdgpu_ring_generic_pad_ib, .begin_use = amdgpu_uvd_ring_begin_use, .end_use = amdgpu_uvd_ring_end_use, + .emit_wreg = uvd_v7_0_ring_emit_wreg, + .emit_reg_wait = uvd_v7_0_ring_emit_reg_wait, }; static const struct amdgpu_ring_funcs uvd_v7_0_enc_ring_vm_funcs = { @@ -1740,7 +1683,10 @@ static const struct amdgpu_ring_funcs uvd_v7_0_enc_ring_vm_funcs = { .get_wptr = uvd_v7_0_enc_ring_get_wptr, .set_wptr = uvd_v7_0_enc_ring_set_wptr, .emit_frame_size = - 17 + /* uvd_v7_0_enc_ring_emit_vm_flush */ + 3 + 3 + /* hdp flush / invalidate */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 4 + + 4 + /* uvd_v7_0_enc_ring_emit_vm_flush */ 5 + 5 + /* uvd_v7_0_enc_ring_emit_fence x2 vm fence */ 1, /* uvd_v7_0_enc_ring_insert_end */ .emit_ib_size = 5, /* uvd_v7_0_enc_ring_emit_ib */ @@ -1754,6 +1700,8 @@ static const struct amdgpu_ring_funcs uvd_v7_0_enc_ring_vm_funcs = { .pad_ib = amdgpu_ring_generic_pad_ib, .begin_use = amdgpu_uvd_ring_begin_use, .end_use = amdgpu_uvd_ring_end_use, + .emit_wreg = uvd_v7_0_enc_ring_emit_wreg, + .emit_reg_wait = uvd_v7_0_enc_ring_emit_reg_wait, }; static void uvd_v7_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index a5355eb689f1..428d1928e44e 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c @@ -844,7 +844,7 @@ static void vce_v3_0_ring_emit_ib(struct amdgpu_ring *ring, } static void vce_v3_0_emit_vm_flush(struct amdgpu_ring *ring, - unsigned int vmid, uint64_t pd_addr) + unsigned int vmid, uint64_t pd_addr) { amdgpu_ring_write(ring, VCE_CMD_UPDATE_PTB); amdgpu_ring_write(ring, vmid); diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c index 7cf2eef68cf2..2329b310ccf2 100755 --- a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c @@ -28,6 +28,7 @@ #include #include "amdgpu.h" #include "amdgpu_vce.h" +#include "soc15.h" #include "soc15d.h" #include "soc15_common.h" #include "mmsch_v1_0.h" @@ -964,40 +965,33 @@ static void vce_v4_0_ring_insert_end(struct amdgpu_ring *ring) amdgpu_ring_write(ring, VCE_CMD_END); } +static void vce_v4_0_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg, + uint32_t val, uint32_t mask) +{ + amdgpu_ring_write(ring, VCE_CMD_REG_WAIT); + amdgpu_ring_write(ring, reg << 2); + amdgpu_ring_write(ring, mask); + amdgpu_ring_write(ring, val); +} + static void vce_v4_0_emit_vm_flush(struct amdgpu_ring *ring, - unsigned int vmid, uint64_t pd_addr) + unsigned int vmid, uint64_t pd_addr) { struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; - uint32_t req = ring->adev->gart.gart_funcs->get_invalidate_req(vmid); - uint64_t flags = AMDGPU_PTE_VALID; - unsigned eng = ring->vm_inv_eng; - amdgpu_gart_get_vm_pde(ring->adev, -1, &pd_addr, &flags); - pd_addr |= flags; + pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); + /* wait for reg writes */ + vce_v4_0_emit_reg_wait(ring, hub->ctx0_ptb_addr_lo32 + vmid * 2, + lower_32_bits(pd_addr), 0xffffffff); +} + +static void vce_v4_0_emit_wreg(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val) +{ amdgpu_ring_write(ring, VCE_CMD_REG_WRITE); - amdgpu_ring_write(ring, (hub->ctx0_ptb_addr_hi32 + vmid * 2) << 2); - amdgpu_ring_write(ring, upper_32_bits(pd_addr)); - - amdgpu_ring_write(ring, VCE_CMD_REG_WRITE); - amdgpu_ring_write(ring, (hub->ctx0_ptb_addr_lo32 + vmid * 2) << 2); - amdgpu_ring_write(ring, lower_32_bits(pd_addr)); - - amdgpu_ring_write(ring, VCE_CMD_REG_WAIT); - amdgpu_ring_write(ring, (hub->ctx0_ptb_addr_lo32 + vmid * 2) << 2); - amdgpu_ring_write(ring, 0xffffffff); - amdgpu_ring_write(ring, lower_32_bits(pd_addr)); - - /* flush TLB */ - amdgpu_ring_write(ring, VCE_CMD_REG_WRITE); - amdgpu_ring_write(ring, (hub->vm_inv_eng0_req + eng) << 2); - amdgpu_ring_write(ring, req); - - /* wait for flush */ - amdgpu_ring_write(ring, VCE_CMD_REG_WAIT); - amdgpu_ring_write(ring, (hub->vm_inv_eng0_ack + eng) << 2); - amdgpu_ring_write(ring, 1 << vmid); - amdgpu_ring_write(ring, 1 << vmid); + amdgpu_ring_write(ring, reg << 2); + amdgpu_ring_write(ring, val); } static int vce_v4_0_set_interrupt_state(struct amdgpu_device *adev, @@ -1069,7 +1063,9 @@ static const struct amdgpu_ring_funcs vce_v4_0_ring_vm_funcs = { .set_wptr = vce_v4_0_ring_set_wptr, .parse_cs = amdgpu_vce_ring_parse_cs_vm, .emit_frame_size = - 17 + /* vce_v4_0_emit_vm_flush */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 4 + + 4 + /* vce_v4_0_emit_vm_flush */ 5 + 5 + /* amdgpu_vce_ring_emit_fence x2 vm fence */ 1, /* vce_v4_0_ring_insert_end */ .emit_ib_size = 5, /* vce_v4_0_ring_emit_ib */ @@ -1083,6 +1079,8 @@ static const struct amdgpu_ring_funcs vce_v4_0_ring_vm_funcs = { .pad_ib = amdgpu_ring_generic_pad_ib, .begin_use = amdgpu_vce_ring_begin_use, .end_use = amdgpu_vce_ring_end_use, + .emit_wreg = vce_v4_0_emit_wreg, + .emit_reg_wait = vce_v4_0_emit_reg_wait, }; static void vce_v4_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index b99e15c43e45..fdf4ac9313cf 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -25,6 +25,7 @@ #include #include "amdgpu.h" #include "amdgpu_vcn.h" +#include "soc15.h" #include "soc15d.h" #include "soc15_common.h" @@ -808,21 +809,6 @@ static void vcn_v1_0_dec_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 amdgpu_ring_write(ring, VCN_DEC_CMD_TRAP << 1); } -/** - * vcn_v1_0_dec_ring_hdp_invalidate - emit an hdp invalidate - * - * @ring: amdgpu_ring pointer - * - * Emits an hdp invalidate. - */ -static void vcn_v1_0_dec_ring_emit_hdp_invalidate(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - - amdgpu_ring_write(ring, PACKET0(SOC15_REG_OFFSET(HDP, 0, mmHDP_READ_CACHE_INVALIDATE), 0)); - amdgpu_ring_write(ring, 1); -} - /** * vcn_v1_0_dec_ring_emit_ib - execute indirect buffer * @@ -852,33 +838,18 @@ static void vcn_v1_0_dec_ring_emit_ib(struct amdgpu_ring *ring, amdgpu_ring_write(ring, ib->length_dw); } -static void vcn_v1_0_dec_vm_reg_write(struct amdgpu_ring *ring, - uint32_t data0, uint32_t data1) +static void vcn_v1_0_dec_ring_emit_reg_wait(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val, + uint32_t mask) { struct amdgpu_device *adev = ring->adev; amdgpu_ring_write(ring, PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_GPCOM_VCPU_DATA0), 0)); - amdgpu_ring_write(ring, data0); + amdgpu_ring_write(ring, reg << 2); amdgpu_ring_write(ring, PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_GPCOM_VCPU_DATA1), 0)); - amdgpu_ring_write(ring, data1); - amdgpu_ring_write(ring, - PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_GPCOM_VCPU_CMD), 0)); - amdgpu_ring_write(ring, VCN_DEC_CMD_WRITE_REG << 1); -} - -static void vcn_v1_0_dec_vm_reg_wait(struct amdgpu_ring *ring, - uint32_t data0, uint32_t data1, uint32_t mask) -{ - struct amdgpu_device *adev = ring->adev; - - amdgpu_ring_write(ring, - PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_GPCOM_VCPU_DATA0), 0)); - amdgpu_ring_write(ring, data0); - amdgpu_ring_write(ring, - PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_GPCOM_VCPU_DATA1), 0)); - amdgpu_ring_write(ring, data1); + amdgpu_ring_write(ring, val); amdgpu_ring_write(ring, PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_GP_SCRATCH8), 0)); amdgpu_ring_write(ring, mask); @@ -888,40 +859,34 @@ static void vcn_v1_0_dec_vm_reg_wait(struct amdgpu_ring *ring, } static void vcn_v1_0_dec_ring_emit_vm_flush(struct amdgpu_ring *ring, - unsigned vmid, uint64_t pd_addr) + unsigned vmid, uint64_t pd_addr) { struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; - uint32_t req = ring->adev->gart.gart_funcs->get_invalidate_req(vmid); - uint64_t flags = AMDGPU_PTE_VALID; - unsigned eng = ring->vm_inv_eng; uint32_t data0, data1, mask; - amdgpu_gart_get_vm_pde(ring->adev, -1, &pd_addr, &flags); - pd_addr |= flags; + pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); - data0 = (hub->ctx0_ptb_addr_hi32 + vmid * 2) << 2; - data1 = upper_32_bits(pd_addr); - vcn_v1_0_dec_vm_reg_write(ring, data0, data1); - - data0 = (hub->ctx0_ptb_addr_lo32 + vmid * 2) << 2; - data1 = lower_32_bits(pd_addr); - vcn_v1_0_dec_vm_reg_write(ring, data0, data1); - - data0 = (hub->ctx0_ptb_addr_lo32 + vmid * 2) << 2; + /* wait for register write */ + data0 = hub->ctx0_ptb_addr_lo32 + vmid * 2; data1 = lower_32_bits(pd_addr); mask = 0xffffffff; - vcn_v1_0_dec_vm_reg_wait(ring, data0, data1, mask); + vcn_v1_0_dec_ring_emit_reg_wait(ring, data0, data1, mask); +} - /* flush TLB */ - data0 = (hub->vm_inv_eng0_req + eng) << 2; - data1 = req; - vcn_v1_0_dec_vm_reg_write(ring, data0, data1); +static void vcn_v1_0_dec_ring_emit_wreg(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val) +{ + struct amdgpu_device *adev = ring->adev; - /* wait for flush */ - data0 = (hub->vm_inv_eng0_ack + eng) << 2; - data1 = 1 << vmid; - mask = 1 << vmid; - vcn_v1_0_dec_vm_reg_wait(ring, data0, data1, mask); + amdgpu_ring_write(ring, + PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_GPCOM_VCPU_DATA0), 0)); + amdgpu_ring_write(ring, reg << 2); + amdgpu_ring_write(ring, + PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_GPCOM_VCPU_DATA1), 0)); + amdgpu_ring_write(ring, val); + amdgpu_ring_write(ring, + PACKET0(SOC15_REG_OFFSET(UVD, 0, mmUVD_GPCOM_VCPU_CMD), 0)); + amdgpu_ring_write(ring, VCN_DEC_CMD_WRITE_REG << 1); } /** @@ -1020,43 +985,34 @@ static void vcn_v1_0_enc_ring_emit_ib(struct amdgpu_ring *ring, amdgpu_ring_write(ring, ib->length_dw); } +static void vcn_v1_0_enc_ring_emit_reg_wait(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val, + uint32_t mask) +{ + amdgpu_ring_write(ring, VCN_ENC_CMD_REG_WAIT); + amdgpu_ring_write(ring, reg << 2); + amdgpu_ring_write(ring, mask); + amdgpu_ring_write(ring, val); +} + static void vcn_v1_0_enc_ring_emit_vm_flush(struct amdgpu_ring *ring, - unsigned int vmid, uint64_t pd_addr) + unsigned int vmid, uint64_t pd_addr) { struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; - uint32_t req = ring->adev->gart.gart_funcs->get_invalidate_req(vmid); - uint64_t flags = AMDGPU_PTE_VALID; - unsigned eng = ring->vm_inv_eng; - amdgpu_gart_get_vm_pde(ring->adev, -1, &pd_addr, &flags); - pd_addr |= flags; + pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); + /* wait for reg writes */ + vcn_v1_0_enc_ring_emit_reg_wait(ring, hub->ctx0_ptb_addr_lo32 + vmid * 2, + lower_32_bits(pd_addr), 0xffffffff); +} + +static void vcn_v1_0_enc_ring_emit_wreg(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val) +{ amdgpu_ring_write(ring, VCN_ENC_CMD_REG_WRITE); - amdgpu_ring_write(ring, - (hub->ctx0_ptb_addr_hi32 + vmid * 2) << 2); - amdgpu_ring_write(ring, upper_32_bits(pd_addr)); - - amdgpu_ring_write(ring, VCN_ENC_CMD_REG_WRITE); - amdgpu_ring_write(ring, - (hub->ctx0_ptb_addr_lo32 + vmid * 2) << 2); - amdgpu_ring_write(ring, lower_32_bits(pd_addr)); - - amdgpu_ring_write(ring, VCN_ENC_CMD_REG_WAIT); - amdgpu_ring_write(ring, - (hub->ctx0_ptb_addr_lo32 + vmid * 2) << 2); - amdgpu_ring_write(ring, 0xffffffff); - amdgpu_ring_write(ring, lower_32_bits(pd_addr)); - - /* flush TLB */ - amdgpu_ring_write(ring, VCN_ENC_CMD_REG_WRITE); - amdgpu_ring_write(ring, (hub->vm_inv_eng0_req + eng) << 2); - amdgpu_ring_write(ring, req); - - /* wait for flush */ - amdgpu_ring_write(ring, VCN_ENC_CMD_REG_WAIT); - amdgpu_ring_write(ring, (hub->vm_inv_eng0_ack + eng) << 2); - amdgpu_ring_write(ring, 1 << vmid); - amdgpu_ring_write(ring, 1 << vmid); + amdgpu_ring_write(ring, reg << 2); + amdgpu_ring_write(ring, val); } static int vcn_v1_0_set_interrupt_state(struct amdgpu_device *adev, @@ -1133,15 +1089,16 @@ static const struct amdgpu_ring_funcs vcn_v1_0_dec_ring_vm_funcs = { .get_wptr = vcn_v1_0_dec_ring_get_wptr, .set_wptr = vcn_v1_0_dec_ring_set_wptr, .emit_frame_size = - 2 + /* vcn_v1_0_dec_ring_emit_hdp_invalidate */ - 34 + /* vcn_v1_0_dec_ring_emit_vm_flush */ + 6 + 6 + /* hdp invalidate / flush */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 8 + + 8 + /* vcn_v1_0_dec_ring_emit_vm_flush */ 14 + 14 + /* vcn_v1_0_dec_ring_emit_fence x2 vm fence */ 6, .emit_ib_size = 8, /* vcn_v1_0_dec_ring_emit_ib */ .emit_ib = vcn_v1_0_dec_ring_emit_ib, .emit_fence = vcn_v1_0_dec_ring_emit_fence, .emit_vm_flush = vcn_v1_0_dec_ring_emit_vm_flush, - .emit_hdp_invalidate = vcn_v1_0_dec_ring_emit_hdp_invalidate, .test_ring = amdgpu_vcn_dec_ring_test_ring, .test_ib = amdgpu_vcn_dec_ring_test_ib, .insert_nop = vcn_v1_0_ring_insert_nop, @@ -1150,6 +1107,8 @@ static const struct amdgpu_ring_funcs vcn_v1_0_dec_ring_vm_funcs = { .pad_ib = amdgpu_ring_generic_pad_ib, .begin_use = amdgpu_vcn_ring_begin_use, .end_use = amdgpu_vcn_ring_end_use, + .emit_wreg = vcn_v1_0_dec_ring_emit_wreg, + .emit_reg_wait = vcn_v1_0_dec_ring_emit_reg_wait, }; static const struct amdgpu_ring_funcs vcn_v1_0_enc_ring_vm_funcs = { @@ -1162,7 +1121,9 @@ static const struct amdgpu_ring_funcs vcn_v1_0_enc_ring_vm_funcs = { .get_wptr = vcn_v1_0_enc_ring_get_wptr, .set_wptr = vcn_v1_0_enc_ring_set_wptr, .emit_frame_size = - 17 + /* vcn_v1_0_enc_ring_emit_vm_flush */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 4 + + 4 + /* vcn_v1_0_enc_ring_emit_vm_flush */ 5 + 5 + /* vcn_v1_0_enc_ring_emit_fence x2 vm fence */ 1, /* vcn_v1_0_enc_ring_insert_end */ .emit_ib_size = 5, /* vcn_v1_0_enc_ring_emit_ib */ @@ -1176,6 +1137,8 @@ static const struct amdgpu_ring_funcs vcn_v1_0_enc_ring_vm_funcs = { .pad_ib = amdgpu_ring_generic_pad_ib, .begin_use = amdgpu_vcn_ring_begin_use, .end_use = amdgpu_vcn_ring_end_use, + .emit_wreg = vcn_v1_0_enc_ring_emit_wreg, + .emit_reg_wait = vcn_v1_0_enc_ring_emit_reg_wait, }; static void vcn_v1_0_set_dec_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c index b69ceafb7888..cc8ce7e352a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c @@ -278,9 +278,9 @@ static bool vega10_ih_prescreen_iv(struct amdgpu_device *adev) /* Track retry faults in per-VM fault FIFO. */ spin_lock(&adev->vm_manager.pasid_lock); vm = idr_find(&adev->vm_manager.pasid_idr, pasid); - spin_unlock(&adev->vm_manager.pasid_lock); - if (WARN_ON_ONCE(!vm)) { + if (!vm) { /* VM not found, process it normally */ + spin_unlock(&adev->vm_manager.pasid_lock); amdgpu_ih_clear_fault(adev, key); return true; } @@ -288,9 +288,11 @@ static bool vega10_ih_prescreen_iv(struct amdgpu_device *adev) r = kfifo_put(&vm->faults, key); if (!r) { /* FIFO is full. Ignore it until there is space */ + spin_unlock(&adev->vm_manager.pasid_lock); amdgpu_ih_clear_fault(adev, key); goto ignore_iv; } + spin_unlock(&adev->vm_manager.pasid_lock); /* It's the first fault for this address, process it normally */ return true; @@ -331,7 +333,7 @@ static void vega10_ih_decode_iv(struct amdgpu_device *adev, entry->vmid_src = (dw[0] >> 31); entry->timestamp = dw[1] | ((u64)(dw[2] & 0xffff) << 32); entry->timestamp_src = dw[2] >> 31; - entry->pas_id = dw[3] & 0xffff; + entry->pasid = dw[3] & 0xffff; entry->pasid_src = dw[3] >> 31; entry->src_data[0] = dw[4]; entry->src_data[1] = dw[5]; diff --git a/drivers/gpu/drm/amd/amdgpu/vega10_reg_init.c b/drivers/gpu/drm/amd/amdgpu/vega10_reg_init.c index b7bdd04793d6..4c45db7f1157 100644 --- a/drivers/gpu/drm/amd/amdgpu/vega10_reg_init.c +++ b/drivers/gpu/drm/amd/amdgpu/vega10_reg_init.c @@ -24,7 +24,8 @@ #include "soc15.h" #include "soc15_common.h" -#include "soc15ip.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" int vega10_reg_base_init(struct amdgpu_device *adev) { diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index da2b99c2d95f..61360a1552d8 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -856,6 +856,27 @@ static uint32_t vi_get_rev_id(struct amdgpu_device *adev) >> PCIE_EFUSE4__STRAP_BIF_ATI_REV_ID__SHIFT; } +static void vi_flush_hdp(struct amdgpu_device *adev, struct amdgpu_ring *ring) +{ + if (!ring || !ring->funcs->emit_wreg) { + WREG32(mmHDP_MEM_COHERENCY_FLUSH_CNTL, 1); + RREG32(mmHDP_MEM_COHERENCY_FLUSH_CNTL); + } else { + amdgpu_ring_emit_wreg(ring, mmHDP_MEM_COHERENCY_FLUSH_CNTL, 1); + } +} + +static void vi_invalidate_hdp(struct amdgpu_device *adev, + struct amdgpu_ring *ring) +{ + if (!ring || !ring->funcs->emit_wreg) { + WREG32(mmHDP_DEBUG0, 1); + RREG32(mmHDP_DEBUG0); + } else { + amdgpu_ring_emit_wreg(ring, mmHDP_DEBUG0, 1); + } +} + static const struct amdgpu_asic_funcs vi_asic_funcs = { .read_disabled_bios = &vi_read_disabled_bios, @@ -867,6 +888,8 @@ static const struct amdgpu_asic_funcs vi_asic_funcs = .set_uvd_clocks = &vi_set_uvd_clocks, .set_vce_clocks = &vi_set_vce_clocks, .get_config_memsize = &vi_get_config_memsize, + .flush_hdp = &vi_flush_hdp, + .invalidate_hdp = &vi_invalidate_hdp, }; #define CZ_REV_BRISTOL(rev) \ @@ -1049,7 +1072,6 @@ static int vi_common_early_init(void *handle) AMD_CG_SUPPORT_GFX_CP_LS | AMD_CG_SUPPORT_GFX_CGTS | AMD_CG_SUPPORT_GFX_CGTS_LS | - AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_CGLS | AMD_CG_SUPPORT_BIF_LS | AMD_CG_SUPPORT_HDP_MGCG | diff --git a/drivers/gpu/drm/amd/amdgpu/vi.h b/drivers/gpu/drm/amd/amdgpu/vi.h index 575d7aed5d32..0429fe332269 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.h +++ b/drivers/gpu/drm/amd/amdgpu/vi.h @@ -24,6 +24,8 @@ #ifndef __VI_H__ #define __VI_H__ +#define VI_FLUSH_GPU_TLB_NUM_WREG 3 + void vi_srbm_select(struct amdgpu_device *adev, u32 me, u32 pipe, u32 queue, u32 vmid); int vi_set_ip_blocks(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/display/Makefile b/drivers/gpu/drm/amd/display/Makefile index c27c81cdeed3..3d14478913de 100644 --- a/drivers/gpu/drm/amd/display/Makefile +++ b/drivers/gpu/drm/amd/display/Makefile @@ -32,11 +32,12 @@ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/inc/ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/inc/hw subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/inc subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/freesync +subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/color #TODO: remove when Timing Sync feature is complete subdir-ccflags-y += -DBUILD_FEATURE_TIMING_SYNC=0 -DAL_LIBS = amdgpu_dm dc modules/freesync +DAL_LIBS = amdgpu_dm dc modules/freesync modules/color AMD_DAL = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DISPLAY_PATH)/,$(DAL_LIBS))) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile index 2b72009844f8..af16973f2c41 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile @@ -25,12 +25,16 @@ -AMDGPUDM = amdgpu_dm.o amdgpu_dm_irq.o amdgpu_dm_mst_types.o +AMDGPUDM = amdgpu_dm.o amdgpu_dm_irq.o amdgpu_dm_mst_types.o amdgpu_dm_color.o ifneq ($(CONFIG_DRM_AMD_DC),) AMDGPUDM += amdgpu_dm_services.o amdgpu_dm_helpers.o endif +ifneq ($(CONFIG_DEBUG_FS),) +AMDGPUDM += amdgpu_dm_crc.o +endif + subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc AMDGPU_DM = $(addprefix $(AMDDALPATH)/amdgpu_dm/,$(AMDGPUDM)) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index b7254a29b34a..246fff33c7bf 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -61,7 +61,8 @@ #include "dcn/dcn_1_0_offset.h" #include "dcn/dcn_1_0_sh_mask.h" -#include "soc15ip.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" #include "soc15_common.h" #endif @@ -319,6 +320,7 @@ static void dm_crtc_high_irq(void *interrupt_params) crtc_index = acrtc->crtc_id; drm_handle_vblank(adev->ddev, crtc_index); + amdgpu_dm_crtc_handle_crc_irq(&acrtc->base); } static int dm_set_clockgating_state(void *handle, @@ -345,23 +347,43 @@ static void hotplug_notify_work_func(struct work_struct *work) } #if defined(CONFIG_DRM_AMD_DC_FBC) -#include "dal_asic_id.h" /* Allocate memory for FBC compressed data */ -/* TODO: Dynamic allocation */ -#define AMDGPU_FBC_SIZE (3840 * 2160 * 4) - -static void amdgpu_dm_initialize_fbc(struct amdgpu_device *adev) +static void amdgpu_dm_fbc_init(struct drm_connector *connector) { - int r; + struct drm_device *dev = connector->dev; + struct amdgpu_device *adev = dev->dev_private; struct dm_comressor_info *compressor = &adev->dm.compressor; + struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(connector); + struct drm_display_mode *mode; + unsigned long max_size = 0; - if (!compressor->bo_ptr) { - r = amdgpu_bo_create_kernel(adev, AMDGPU_FBC_SIZE, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, &compressor->bo_ptr, - &compressor->gpu_addr, &compressor->cpu_addr); + if (adev->dm.dc->fbc_compressor == NULL) + return; + + if (aconn->dc_link->connector_signal != SIGNAL_TYPE_EDP) + return; + + if (compressor->bo_ptr) + return; + + + list_for_each_entry(mode, &connector->modes, head) { + if (max_size < mode->htotal * mode->vtotal) + max_size = mode->htotal * mode->vtotal; + } + + if (max_size) { + int r = amdgpu_bo_create_kernel(adev, max_size * 4, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, &compressor->bo_ptr, + &compressor->gpu_addr, &compressor->cpu_addr); if (r) - DRM_ERROR("DM: Failed to initialize fbc\n"); + DRM_ERROR("DM: Failed to initialize FBC\n"); + else { + adev->dm.dc->ctx->fbc_gpu_addr = compressor->gpu_addr; + DRM_INFO("DM: FBC alloc %lu\n", max_size*4); + } + } } @@ -381,12 +403,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) /* Zero all the fields */ memset(&init_data, 0, sizeof(init_data)); - /* initialize DAL's lock (for SYNC context use) */ - spin_lock_init(&adev->dm.dal_lock); - - /* initialize DAL's mutex */ - mutex_init(&adev->dm.dal_mutex); - if(amdgpu_dm_irq_init(adev)) { DRM_ERROR("amdgpu: failed to initialize DM IRQ support.\n"); goto error; @@ -397,7 +413,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) init_data.asic_id.pci_revision_id = adev->rev_id; init_data.asic_id.hw_internal_rev = adev->external_rev_id; - init_data.asic_id.vram_width = adev->mc.vram_width; + init_data.asic_id.vram_width = adev->gmc.vram_width; /* TODO: initialize init_data.asic_id.vram_type here!!!! */ init_data.asic_id.atombios_base_address = adev->mode_info.atom_context->bios; @@ -422,11 +438,14 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) else init_data.log_mask = DC_MIN_LOG_MASK; -#if defined(CONFIG_DRM_AMD_DC_FBC) - if (adev->family == FAMILY_CZ) - amdgpu_dm_initialize_fbc(adev); - init_data.fbc_gpu_addr = adev->dm.compressor.gpu_addr; -#endif + /* + * TODO debug why this doesn't work on Raven + */ + if (adev->flags & AMD_IS_APU && + adev->asic_type >= CHIP_CARRIZO && + adev->asic_type < CHIP_RAVEN) + init_data.flags.gpu_vm_support = true; + /* Display Core create. */ adev->dm.dc = dc_create(&init_data); @@ -447,6 +466,8 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) DRM_DEBUG_DRIVER("amdgpu: freesync_module init done %p.\n", adev->dm.freesync_module); + amdgpu_dm_init_color_mod(); + if (amdgpu_dm_initialize_drm_device(adev)) { DRM_ERROR( "amdgpu: failed to initialize sw for display support.\n"); @@ -540,9 +561,9 @@ static int detect_mst_link_for_all_connectors(struct drm_device *dev) static int dm_late_init(void *handle) { - struct drm_device *dev = ((struct amdgpu_device *)handle)->ddev; + struct amdgpu_device *adev = (struct amdgpu_device *)handle; - return detect_mst_link_for_all_connectors(dev); + return detect_mst_link_for_all_connectors(adev->ddev); } static void s3_handle_mst(struct drm_device *dev, bool suspend) @@ -629,11 +650,13 @@ static int dm_resume(void *handle) { struct amdgpu_device *adev = handle; struct amdgpu_display_manager *dm = &adev->dm; + int ret = 0; /* power on hardware */ dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0); - return 0; + ret = amdgpu_dm_display_resume(adev); + return ret; } int amdgpu_dm_display_resume(struct amdgpu_device *adev) @@ -791,7 +814,7 @@ dm_atomic_state_alloc_free(struct drm_atomic_state *state) } static const struct drm_mode_config_funcs amdgpu_dm_mode_funcs = { - .fb_create = amdgpu_user_framebuffer_create, + .fb_create = amdgpu_display_user_framebuffer_create, .output_poll_changed = drm_fb_helper_output_poll_changed, .atomic_check = amdgpu_dm_atomic_check, .atomic_commit = amdgpu_dm_atomic_commit, @@ -1279,9 +1302,9 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev) /* indicate support of immediate flip */ adev->ddev->mode_config.async_page_flip = true; - adev->ddev->mode_config.fb_base = adev->mc.aper_base; + adev->ddev->mode_config.fb_base = adev->gmc.aper_base; - r = amdgpu_modeset_create_props(adev); + r = amdgpu_display_modeset_create_props(adev); if (r) return r; @@ -1538,7 +1561,6 @@ static int amdgpu_notify_freesync(struct drm_device *dev, void *data, static const struct amdgpu_display_funcs dm_display_funcs = { .bandwidth_update = dm_bandwidth_update, /* called unconditionally */ .vblank_get_counter = dm_vblank_get_counter,/* called unconditionally */ - .vblank_wait = NULL, .backlight_set_level = dm_set_backlight_level,/* called unconditionally */ .backlight_get_level = @@ -1589,8 +1611,6 @@ static int dm_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - adev->ddev->driver->driver_features |= DRIVER_ATOMIC; - switch (adev->asic_type) { case CHIP_BONAIRE: case CHIP_HAWAII: @@ -1924,32 +1944,6 @@ static int fill_plane_attributes_from_fb(struct amdgpu_device *adev, } -static void fill_gamma_from_crtc_state(const struct drm_crtc_state *crtc_state, - struct dc_plane_state *plane_state) -{ - int i; - struct dc_gamma *gamma; - struct drm_color_lut *lut = - (struct drm_color_lut *) crtc_state->gamma_lut->data; - - gamma = dc_create_gamma(); - - if (gamma == NULL) { - WARN_ON(1); - return; - } - - gamma->type = GAMMA_RGB_256; - gamma->num_entries = GAMMA_RGB_256_ENTRIES; - for (i = 0; i < GAMMA_RGB_256_ENTRIES; i++) { - gamma->entries.red[i] = dal_fixed31_32_from_int(lut[i].red); - gamma->entries.green[i] = dal_fixed31_32_from_int(lut[i].green); - gamma->entries.blue[i] = dal_fixed31_32_from_int(lut[i].blue); - } - - plane_state->gamma_correction = gamma; -} - static int fill_plane_attributes(struct amdgpu_device *adev, struct dc_plane_state *dc_plane_state, struct drm_plane_state *plane_state, @@ -1977,14 +1971,13 @@ static int fill_plane_attributes(struct amdgpu_device *adev, if (input_tf == NULL) return -ENOMEM; - input_tf->type = TF_TYPE_PREDEFINED; - input_tf->tf = TRANSFER_FUNCTION_SRGB; - dc_plane_state->in_transfer_func = input_tf; - /* In case of gamma set, update gamma value */ - if (crtc_state->gamma_lut) - fill_gamma_from_crtc_state(crtc_state, dc_plane_state); + /* + * Always set input transfer function, since plane state is refreshed + * every time. + */ + ret = amdgpu_dm_set_degamma_lut(crtc_state, dc_plane_state); return ret; } @@ -2010,30 +2003,32 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode, dst.width = stream->timing.h_addressable; dst.height = stream->timing.v_addressable; - rmx_type = dm_state->scaling; - if (rmx_type == RMX_ASPECT || rmx_type == RMX_OFF) { - if (src.width * dst.height < - src.height * dst.width) { - /* height needs less upscaling/more downscaling */ - dst.width = src.width * - dst.height / src.height; - } else { - /* width needs less upscaling/more downscaling */ - dst.height = src.height * - dst.width / src.width; + if (dm_state) { + rmx_type = dm_state->scaling; + if (rmx_type == RMX_ASPECT || rmx_type == RMX_OFF) { + if (src.width * dst.height < + src.height * dst.width) { + /* height needs less upscaling/more downscaling */ + dst.width = src.width * + dst.height / src.height; + } else { + /* width needs less upscaling/more downscaling */ + dst.height = src.height * + dst.width / src.width; + } + } else if (rmx_type == RMX_CENTER) { + dst = src; } - } else if (rmx_type == RMX_CENTER) { - dst = src; - } - dst.x = (stream->timing.h_addressable - dst.width) / 2; - dst.y = (stream->timing.v_addressable - dst.height) / 2; + dst.x = (stream->timing.h_addressable - dst.width) / 2; + dst.y = (stream->timing.v_addressable - dst.height) / 2; - if (dm_state->underscan_enable) { - dst.x += dm_state->underscan_hborder / 2; - dst.y += dm_state->underscan_vborder / 2; - dst.width -= dm_state->underscan_hborder; - dst.height -= dm_state->underscan_vborder; + if (dm_state->underscan_enable) { + dst.x += dm_state->underscan_hborder / 2; + dst.y += dm_state->underscan_vborder / 2; + dst.width -= dm_state->underscan_hborder; + dst.height -= dm_state->underscan_vborder; + } } stream->src = src; @@ -2322,7 +2317,7 @@ static void set_master_stream(struct dc_stream_state *stream_set[], } } for (j = 0; j < stream_count; j++) { - if (stream_set[j] && j != master_stream) + if (stream_set[j]) stream_set[j]->triggered_crtc_reset.event_source = stream_set[master_stream]; } } @@ -2358,12 +2353,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, if (aconnector == NULL) { DRM_ERROR("aconnector is NULL!\n"); - goto drm_connector_null; - } - - if (dm_state == NULL) { - DRM_ERROR("dm_state is NULL!\n"); - goto dm_state_null; + return stream; } drm_connector = &aconnector->base; @@ -2375,18 +2365,18 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, */ if (aconnector->mst_port) { dm_dp_mst_dc_sink_create(drm_connector); - goto mst_dc_sink_create_done; + return stream; } if (create_fake_sink(aconnector)) - goto stream_create_fail; + return stream; } stream = dc_create_stream_for_sink(aconnector->dc_sink); if (stream == NULL) { DRM_ERROR("Failed to create stream for sink!\n"); - goto stream_create_fail; + return stream; } list_for_each_entry(preferred_mode, &aconnector->base.modes, head) { @@ -2412,9 +2402,12 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, } else { decide_crtc_timing_for_drm_display_mode( &mode, preferred_mode, - dm_state->scaling != RMX_OFF); + dm_state ? (dm_state->scaling != RMX_OFF) : false); } + if (!dm_state) + drm_mode_set_crtcinfo(&mode, 0); + fill_stream_properties_from_drm_display_mode(stream, &mode, &aconnector->base); update_stream_scaling_settings(&mode, dm_state, stream); @@ -2424,10 +2417,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, drm_connector, aconnector->dc_sink); -stream_create_fail: -dm_state_null: -drm_connector_null: -mst_dc_sink_create_done: + update_stream_signal(stream); + return stream; } @@ -2504,6 +2495,7 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { .page_flip = drm_atomic_helper_page_flip, .atomic_duplicate_state = dm_crtc_duplicate_state, .atomic_destroy_state = dm_crtc_destroy_state, + .set_crc_source = amdgpu_dm_crtc_set_crc_source, }; static enum drm_connector_status @@ -2779,6 +2771,7 @@ int amdgpu_dm_connector_mode_valid(struct drm_connector *connector, /* TODO: Unhardcode stream count */ struct dc_stream_state *stream; struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + enum dc_status dc_result = DC_OK; if ((mode->flags & DRM_MODE_FLAG_INTERLACE) || (mode->flags & DRM_MODE_FLAG_DBLSCAN)) @@ -2798,21 +2791,22 @@ int amdgpu_dm_connector_mode_valid(struct drm_connector *connector, goto fail; } - stream = dc_create_stream_for_sink(dc_sink); + stream = create_stream_for_sink(aconnector, mode, NULL); if (stream == NULL) { DRM_ERROR("Failed to create stream for sink!\n"); goto fail; } - drm_mode_set_crtcinfo(mode, 0); - fill_stream_properties_from_drm_display_mode(stream, mode, connector); + dc_result = dc_validate_stream(adev->dm.dc, stream); - stream->src.width = mode->hdisplay; - stream->src.height = mode->vdisplay; - stream->dst = stream->src; - - if (dc_validate_stream(adev->dm.dc, stream) == DC_OK) + if (dc_result == DC_OK) result = MODE_OK; + else + DRM_DEBUG_KMS("Mode %dx%d (clk %d) failed DC validation with error %d\n", + mode->vdisplay, + mode->hdisplay, + mode->clock, + dc_result); dc_stream_release(stream); @@ -2954,11 +2948,13 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, { struct amdgpu_framebuffer *afb; struct drm_gem_object *obj; + struct amdgpu_device *adev; struct amdgpu_bo *rbo; uint64_t chroma_addr = 0; - int r; struct dm_plane_state *dm_plane_state_new, *dm_plane_state_old; unsigned int awidth; + uint32_t domain; + int r; dm_plane_state_old = to_dm_plane_state(plane->state); dm_plane_state_new = to_dm_plane_state(new_state); @@ -2972,12 +2968,17 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, obj = afb->obj; rbo = gem_to_amdgpu_bo(obj); + adev = amdgpu_ttm_adev(rbo->tbo.bdev); r = amdgpu_bo_reserve(rbo, false); if (unlikely(r != 0)) return r; - r = amdgpu_bo_pin(rbo, AMDGPU_GEM_DOMAIN_VRAM, &afb->address); + if (plane->type != DRM_PLANE_TYPE_CURSOR) + domain = amdgpu_display_framebuffer_domains(adev); + else + domain = AMDGPU_GEM_DOMAIN_VRAM; + r = amdgpu_bo_pin(rbo, domain, &afb->address); amdgpu_bo_unreserve(rbo); @@ -3190,7 +3191,9 @@ static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm, acrtc->base.enabled = false; dm->adev->mode_info.crtcs[crtc_index] = acrtc; - drm_mode_crtc_set_gamma_size(&acrtc->base, 256); + drm_crtc_enable_color_mgmt(&acrtc->base, MAX_COLOR_LUT_ENTRIES, + true, MAX_COLOR_LUT_ENTRIES); + drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LUT_ENTRIES); return 0; @@ -3366,9 +3369,12 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector) struct edid *edid = amdgpu_dm_connector->edid; encoder = helper->best_encoder(connector); - amdgpu_dm_connector_ddc_get_modes(connector, edid); amdgpu_dm_connector_add_common_modes(encoder, connector); + +#if defined(CONFIG_DRM_AMD_DC_FBC) + amdgpu_dm_fbc_init(connector); +#endif return amdgpu_dm_connector->num_modes; } @@ -3641,7 +3647,7 @@ static void manage_dm_interrupts(struct amdgpu_device *adev, * constant is the same as PFLIP */ int irq_type = - amdgpu_crtc_idx_to_irq_type( + amdgpu_display_crtc_idx_to_irq_type( adev, acrtc->crtc_id); @@ -3860,9 +3866,9 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc, * targeted by the flip */ while ((acrtc->enabled && - (amdgpu_get_crtc_scanoutpos(adev->ddev, acrtc->crtc_id, 0, - &vpos, &hpos, NULL, NULL, - &crtc->hwmode) + (amdgpu_display_get_crtc_scanoutpos(adev->ddev, acrtc->crtc_id, + 0, &vpos, &hpos, NULL, + NULL, &crtc->hwmode) & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) == (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) && (int)(target_vblank - @@ -4603,6 +4609,30 @@ next_crtc: /* Release extra reference */ if (new_stream) dc_stream_release(new_stream); + + /* + * We want to do dc stream updates that do not require a + * full modeset below. + */ + if (!enable || !aconnector || modereset_required(new_crtc_state)) + continue; + /* + * Given above conditions, the dc state cannot be NULL because: + * 1. We're attempting to enable a CRTC. Which has a... + * 2. Valid connector attached, and + * 3. User does not want to reset it (disable or mark inactive, + * which can happen on a CRTC that's already disabled). + * => It currently exists. + */ + BUG_ON(dm_new_crtc_state->stream == NULL); + + /* Color managment settings */ + if (dm_new_crtc_state->base.color_mgmt_changed) { + ret = amdgpu_dm_set_regamma_lut(dm_new_crtc_state); + if (ret) + goto fail; + amdgpu_dm_set_ctm(dm_new_crtc_state); + } } return ret; @@ -4711,7 +4741,6 @@ static int dm_update_planes_state(struct dc *dc, if (ret) return ret; - if (!dc_add_plane_to_context( dc, dm_new_crtc_state->stream, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 2faa77a7eeda..aa7df5775545 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -85,8 +85,6 @@ struct amdgpu_display_manager { struct dal *dal; struct dc *dc; struct cgs_device *cgs_device; - /* lock to be used when DAL is called from SYNC IRQ context */ - spinlock_t dal_lock; struct amdgpu_device *adev; /*AMD base driver*/ struct drm_device *ddev; /*DRM base driver*/ @@ -119,17 +117,6 @@ struct amdgpu_display_manager { /* this spin lock synchronizes access to 'irq_handler_list_table' */ spinlock_t irq_handler_list_table_lock; - /* Timer-related data. */ - struct list_head timer_handler_list; - struct workqueue_struct *timer_workqueue; - - /* Use dal_mutex for any activity which is NOT syncronized by - * DRM mode setting locks. - * For example: amdgpu_dm_hpd_low_irq() calls into DAL *without* - * DRM mode setting locks being acquired. This is where dal_mutex - * is acquired before calling into DAL. */ - struct mutex dal_mutex; - struct backlight_device *backlight_dev; const struct dc_link *backlight_link; @@ -210,6 +197,9 @@ struct dm_plane_state { struct dm_crtc_state { struct drm_crtc_state base; struct dc_stream_state *stream; + + int crc_skip_count; + bool crc_enabled; }; #define to_dm_crtc_state(x) container_of(x, struct dm_crtc_state, base) @@ -268,6 +258,24 @@ void amdgpu_dm_add_sink_to_freesync_module(struct drm_connector *connector, void amdgpu_dm_remove_sink_from_freesync_module(struct drm_connector *connector); +/* amdgpu_dm_crc.c */ +#ifdef CONFIG_DEBUG_FS +int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name, + size_t *values_cnt); +void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc); +#else +#define amdgpu_dm_crtc_set_crc_source NULL +#define amdgpu_dm_crtc_handle_crc_irq(x) +#endif + +#define MAX_COLOR_LUT_ENTRIES 256 + +void amdgpu_dm_init_color_mod(void); +int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state, + struct dc_plane_state *dc_plane_state); +void amdgpu_dm_set_ctm(struct dm_crtc_state *crtc); +int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc); + extern const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs; #endif /* __AMDGPU_DM_H__ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c new file mode 100644 index 000000000000..62bb72fe9aa5 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -0,0 +1,228 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "amdgpu_mode.h" +#include "amdgpu_dm.h" +#include "modules/color/color_gamma.h" + +/* + * Initialize the color module. + * + * We're not using the full color module, only certain components. + * Only call setup functions for components that we need. + */ +void amdgpu_dm_init_color_mod(void) +{ + setup_x_points_distribution(); +} + + +/* + * Return true if the given lut is a linear mapping of values, i.e. it acts + * like a bypass LUT. + * + * It is considered linear if the lut represents: + * f(a) = (0xFF00/MAX_COLOR_LUT_ENTRIES-1)a; for integer a in + * [0, MAX_COLOR_LUT_ENTRIES) + */ +static bool __is_lut_linear(struct drm_color_lut *lut) +{ + int i; + uint32_t max_os = 0xFF00; + uint32_t expected; + int delta; + + for (i = 0; i < MAX_COLOR_LUT_ENTRIES; i++) { + /* All color values should equal */ + if ((lut[i].red != lut[i].green) || (lut[i].green != lut[i].blue)) + return false; + + expected = i * max_os / (MAX_COLOR_LUT_ENTRIES-1); + + /* Allow a +/-1 error. */ + delta = lut[i].red - expected; + if (delta < -1 || 1 < delta) + return false; + } + return true; +} + +/** + * amdgpu_dm_set_regamma_lut: Set regamma lut for the given CRTC. + * @crtc: amdgpu_dm crtc state + * + * Update the underlying dc_stream_state's output transfer function (OTF) in + * preparation for hardware commit. If no lut is specified by user, we default + * to SRGB. + * + * RETURNS: + * 0 on success, -ENOMEM if memory cannot be allocated to calculate the OTF. + */ +int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc) +{ + struct drm_property_blob *blob = crtc->base.gamma_lut; + struct dc_stream_state *stream = crtc->stream; + struct drm_color_lut *lut; + struct dc_gamma *gamma; + enum dc_transfer_func_type old_type = stream->out_transfer_func->type; + + uint32_t r, g, b; + int i; + bool ret; + + if (!blob) { + /* By default, use the SRGB predefined curve.*/ + stream->out_transfer_func->type = TF_TYPE_PREDEFINED; + stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB; + return 0; + } + + lut = (struct drm_color_lut *)blob->data; + + if (__is_lut_linear(lut)) { + /* Set to bypass if lut is set to linear */ + stream->out_transfer_func->type = TF_TYPE_BYPASS; + stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; + return 0; + } + + gamma = dc_create_gamma(); + if (!gamma) + return -ENOMEM; + + gamma->num_entries = MAX_COLOR_LUT_ENTRIES; + gamma->type = GAMMA_RGB_256; + + /* Truncate, and store in dc_gamma for output tf calculation */ + for (i = 0; i < gamma->num_entries; i++) { + r = drm_color_lut_extract(lut[i].red, 16); + g = drm_color_lut_extract(lut[i].green, 16); + b = drm_color_lut_extract(lut[i].blue, 16); + + gamma->entries.red[i] = dal_fixed31_32_from_int(r); + gamma->entries.green[i] = dal_fixed31_32_from_int(g); + gamma->entries.blue[i] = dal_fixed31_32_from_int(b); + } + + /* Call color module to translate into something DC understands. Namely + * a transfer function. + */ + stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; + ret = mod_color_calculate_regamma_params(stream->out_transfer_func, + gamma, true); + dc_gamma_release(&gamma); + if (!ret) { + stream->out_transfer_func->type = old_type; + DRM_ERROR("Out of memory when calculating regamma params\n"); + return -ENOMEM; + } + + return 0; +} + +/** + * amdgpu_dm_set_ctm: Set the color transform matrix for the given CRTC. + * @crtc: amdgpu_dm crtc state + * + * Update the underlying dc_stream_state's gamut remap matrix in preparation + * for hardware commit. If no matrix is specified by user, gamut remap will be + * disabled. + */ +void amdgpu_dm_set_ctm(struct dm_crtc_state *crtc) +{ + + struct drm_property_blob *blob = crtc->base.ctm; + struct dc_stream_state *stream = crtc->stream; + struct drm_color_ctm *ctm; + int i; + + if (!blob) { + stream->gamut_remap_matrix.enable_remap = false; + return; + } + + stream->gamut_remap_matrix.enable_remap = true; + ctm = (struct drm_color_ctm *)blob->data; + /* + * DRM gives a 3x3 matrix, but DC wants 3x4. Assuming we're operating + * with homogeneous coordinates, augment the matrix with 0's. + * + * The format provided is S31.32, which is the same as our fixed31_32. + */ + for (i = 0; i < 12; i++) { + /* Skip 4th element */ + if (i % 4 == 3) { + stream->gamut_remap_matrix.matrix[i] = dal_fixed31_32_zero; + continue; + } + /* csc[i] = ctm[i - floor(i/4)] */ + stream->gamut_remap_matrix.matrix[i].value = ctm->matrix[i - (i/4)]; + } +} + + +/** + * amdgpu_dm_set_degamma_lut: Set degamma lut for the given CRTC. + * @crtc: amdgpu_dm crtc state + * + * Update the underlying dc_stream_state's input transfer function (ITF) in + * preparation for hardware commit. If no lut is specified by user, we default + * to SRGB degamma. + * + * Currently, we only support degamma bypass, or preprogrammed SRGB degamma. + * Programmable degamma is not supported, and an attempt to do so will return + * -EINVAL. + * + * RETURNS: + * 0 on success, -EINVAL if custom degamma curve is given. + */ +int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state, + struct dc_plane_state *dc_plane_state) +{ + struct drm_property_blob *blob = crtc_state->degamma_lut; + struct drm_color_lut *lut; + + if (!blob) { + /* Default to SRGB */ + dc_plane_state->in_transfer_func->type = TF_TYPE_PREDEFINED; + dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_SRGB; + return 0; + } + + lut = (struct drm_color_lut *)blob->data; + if (__is_lut_linear(lut)) { + dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS; + dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; + return 0; + } + + /* Otherwise, assume SRGB, since programmable degamma is not + * supported. + */ + dc_plane_state->in_transfer_func->type = TF_TYPE_PREDEFINED; + dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_SRGB; + return -EINVAL; +} + diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c new file mode 100644 index 000000000000..52f2c01349e3 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -0,0 +1,126 @@ +/* + * Copyright 2015 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include + +#include "amdgpu.h" +#include "amdgpu_dm.h" +#include "dc.h" + +enum amdgpu_dm_pipe_crc_source { + AMDGPU_DM_PIPE_CRC_SOURCE_NONE = 0, + AMDGPU_DM_PIPE_CRC_SOURCE_AUTO, + AMDGPU_DM_PIPE_CRC_SOURCE_MAX, + AMDGPU_DM_PIPE_CRC_SOURCE_INVALID = -1, +}; + +static enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source) +{ + if (!source || !strcmp(source, "none")) + return AMDGPU_DM_PIPE_CRC_SOURCE_NONE; + if (!strcmp(source, "auto")) + return AMDGPU_DM_PIPE_CRC_SOURCE_AUTO; + + return AMDGPU_DM_PIPE_CRC_SOURCE_INVALID; +} + +int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name, + size_t *values_cnt) +{ + struct dm_crtc_state *crtc_state = to_dm_crtc_state(crtc->state); + struct dc_stream_state *stream_state = crtc_state->stream; + + enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name); + + if (source < 0) { + DRM_DEBUG_DRIVER("Unknown CRC source %s for CRTC%d\n", + src_name, crtc->index); + return -EINVAL; + } + + /* When enabling CRC, we should also disable dithering. */ + if (source == AMDGPU_DM_PIPE_CRC_SOURCE_AUTO) { + if (dc_stream_configure_crc(stream_state->ctx->dc, + stream_state, + true, true)) { + crtc_state->crc_enabled = true; + dc_stream_set_dither_option(stream_state, + DITHER_OPTION_TRUN8); + } + else + return -EINVAL; + } else { + if (dc_stream_configure_crc(stream_state->ctx->dc, + stream_state, + false, false)) { + crtc_state->crc_enabled = false; + dc_stream_set_dither_option(stream_state, + DITHER_OPTION_DEFAULT); + } + else + return -EINVAL; + } + + *values_cnt = 3; + /* Reset crc_skipped on dm state */ + crtc_state->crc_skip_count = 0; + return 0; +} + +/** + * amdgpu_dm_crtc_handle_crc_irq: Report to DRM the CRC on given CRTC. + * @crtc: DRM CRTC object. + * + * This function should be called at the end of a vblank, when the fb has been + * fully processed through the pipe. + */ +void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc) +{ + struct dm_crtc_state *crtc_state = to_dm_crtc_state(crtc->state); + struct dc_stream_state *stream_state = crtc_state->stream; + uint32_t crcs[3]; + + /* Early return if CRC capture is not enabled. */ + if (!crtc_state->crc_enabled) + return; + + /* + * Since flipping and crc enablement happen asynchronously, we - more + * often than not - will be returning an 'uncooked' crc on first frame. + * Probably because hw isn't ready yet. For added security, skip the + * first two CRC values. + */ + if (crtc_state->crc_skip_count < 2) { + crtc_state->crc_skip_count += 1; + return; + } + + if (!dc_stream_get_crc(stream_state->ctx->dc, stream_state, + &crcs[0], &crcs[1], &crcs[2])) + return; + + drm_crtc_add_crc_entry(crtc, true, + drm_crtc_accurate_vblank_count(crtc), crcs); +} diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c index 1874b6cee6af..490017df371d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c @@ -51,11 +51,6 @@ struct amdgpu_dm_irq_handler_data { enum dc_irq_source irq_source; }; -struct amdgpu_dm_timer_handler_data { - struct handler_common_data hcd; - struct delayed_work d_work; -}; - #define DM_IRQ_TABLE_LOCK(adev, flags) \ spin_lock_irqsave(&adev->dm.irq_handler_list_table_lock, flags) @@ -169,62 +164,6 @@ static struct list_head *remove_irq_handler(struct amdgpu_device *adev, return hnd_list; } -/* If 'handler_in == NULL' then remove ALL handlers. */ -static void remove_timer_handler(struct amdgpu_device *adev, - struct amdgpu_dm_timer_handler_data *handler_in) -{ - struct amdgpu_dm_timer_handler_data *handler_temp; - struct list_head *handler_list; - struct list_head *entry, *tmp; - unsigned long irq_table_flags; - bool handler_removed = false; - - DM_IRQ_TABLE_LOCK(adev, irq_table_flags); - - handler_list = &adev->dm.timer_handler_list; - - list_for_each_safe(entry, tmp, handler_list) { - /* Note that list_for_each_safe() guarantees that - * handler_temp is NOT null. */ - handler_temp = list_entry(entry, - struct amdgpu_dm_timer_handler_data, hcd.list); - - if (handler_in == NULL || handler_in == handler_temp) { - list_del(&handler_temp->hcd.list); - DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags); - - DRM_DEBUG_KMS("DM_IRQ: removing timer handler: %p\n", - handler_temp); - - if (handler_in == NULL) { - /* Since it is still in the queue, it must - * be cancelled. */ - cancel_delayed_work_sync(&handler_temp->d_work); - } - - kfree(handler_temp); - handler_removed = true; - - DM_IRQ_TABLE_LOCK(adev, irq_table_flags); - } - - /* Remove ALL handlers. */ - if (handler_in == NULL) - continue; - - /* Remove a SPECIFIC handler. - * Found our handler - we can stop here. */ - if (handler_in == handler_temp) - break; - } - - DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags); - - if (handler_in != NULL && handler_removed == false) - DRM_ERROR("DM_IRQ: handler: %p is not in the list!\n", - handler_in); -} - static bool validate_irq_registration_params(struct dc_interrupt_params *int_params, void (*ih)(void *)) @@ -382,16 +321,6 @@ int amdgpu_dm_irq_init(struct amdgpu_device *adev) INIT_LIST_HEAD(&adev->dm.irq_handler_list_high_tab[src]); } - INIT_LIST_HEAD(&adev->dm.timer_handler_list); - - /* allocate and initialize the workqueue for DM timer */ - adev->dm.timer_workqueue = create_singlethread_workqueue( - "dm_timer_queue"); - if (adev->dm.timer_workqueue == NULL) { - DRM_ERROR("DM_IRQ: unable to create timer queue!\n"); - return -1; - } - return 0; } @@ -410,11 +339,6 @@ void amdgpu_dm_irq_fini(struct amdgpu_device *adev) lh = &adev->dm.irq_handler_list_low_tab[src]; flush_work(&lh->work); } - - /* Cancel ALL timers and release handlers (if any). */ - remove_timer_handler(adev, NULL); - /* Release the queue itself. */ - destroy_workqueue(adev->dm.timer_workqueue); } int amdgpu_dm_irq_suspend(struct amdgpu_device *adev) @@ -683,10 +607,8 @@ static const struct amdgpu_irq_src_funcs dm_hpd_irq_funcs = { void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev) { - if (adev->mode_info.num_crtc > 0) - adev->crtc_irq.num_types = AMDGPU_CRTC_IRQ_VLINE1 + adev->mode_info.num_crtc; - else - adev->crtc_irq.num_types = 0; + + adev->crtc_irq.num_types = adev->mode_info.num_crtc; adev->crtc_irq.funcs = &dm_crtc_irq_funcs; adev->pageflip_irq.num_types = adev->mode_info.num_crtc; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index f3d87f418d2e..1e8a21b67df7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -174,12 +174,6 @@ static const struct drm_connector_funcs dm_dp_mst_connector_funcs = { .atomic_get_property = amdgpu_dm_connector_atomic_get_property }; -static int dm_connector_update_modes(struct drm_connector *connector, - struct edid *edid) -{ - return drm_add_edid_modes(connector, edid); -} - void dm_dp_mst_dc_sink_create(struct drm_connector *connector) { struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); @@ -189,6 +183,12 @@ void dm_dp_mst_dc_sink_create(struct drm_connector *connector) .link = aconnector->dc_link, .sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST }; + /* + * TODO: Need to further figure out why ddc.algo is NULL while MST port exists + */ + if (!aconnector->port || !aconnector->port->aux.ddc.algo) + return; + edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port); if (!edid) { @@ -222,7 +222,7 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) int ret = 0; if (!aconnector) - return dm_connector_update_modes(connector, NULL); + return drm_add_edid_modes(connector, NULL); if (!aconnector->edid) { struct edid *edid; @@ -258,7 +258,7 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) &aconnector->base, edid); } - ret = dm_connector_update_modes(connector, aconnector->edid); + ret = drm_add_edid_modes(connector, aconnector->edid); return ret; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index 56e549249134..89342b48be6b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -71,15 +71,6 @@ bool dm_read_persistent_data(struct dc_context *ctx, /**** power component interfaces ****/ -bool dm_pp_pre_dce_clock_change( - struct dc_context *ctx, - struct dm_pp_gpu_clock_range *requested_state, - struct dm_pp_gpu_clock_range *actual_state) -{ - /*TODO*/ - return false; -} - bool dm_pp_apply_display_requirements( const struct dc_context *ctx, const struct dm_pp_display_configuration *pp_display_cfg) @@ -151,30 +142,6 @@ bool dm_pp_apply_display_requirements( return true; } -bool dc_service_get_system_clocks_range( - const struct dc_context *ctx, - struct dm_pp_gpu_clock_range *sys_clks) -{ - struct amdgpu_device *adev = ctx->driver_context; - - /* Default values, in case PPLib is not compiled-in. */ - sys_clks->mclk.max_khz = 800000; - sys_clks->mclk.min_khz = 800000; - - sys_clks->sclk.max_khz = 600000; - sys_clks->sclk.min_khz = 300000; - - if (adev->pm.dpm_enabled) { - sys_clks->mclk.max_khz = amdgpu_dpm_get_mclk(adev, false); - sys_clks->mclk.min_khz = amdgpu_dpm_get_mclk(adev, true); - - sys_clks->sclk.max_khz = amdgpu_dpm_get_sclk(adev, false); - sys_clks->sclk.min_khz = amdgpu_dpm_get_sclk(adev, true); - } - - return true; -} - static void get_default_clock_levels( enum dm_pp_clock_type clk_type, struct dm_pp_clock_levels *clks) diff --git a/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c b/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c index 011a97f82fb6..8a9bba879207 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c +++ b/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c @@ -593,3 +593,12 @@ uint32_t dal_fixed31_32_clamp_u0d10( { return clamp_ux_dy(arg.value, 0, 10, 1); } + +int32_t dal_fixed31_32_s4d19( + struct fixed31_32 arg) +{ + if (arg.value < 0) + return -(int32_t)ux_dy(dal_fixed31_32_abs(arg).value, 4, 19); + else + return ux_dy(arg.value, 4, 19); +} diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c index c00e405b63e8..69c59e050a96 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c @@ -3795,14 +3795,11 @@ static const struct dc_vbios_funcs vbios_funcs = { .get_gpio_pin_info = bios_parser_get_gpio_pin_info, - .get_embedded_panel_info = bios_parser_get_embedded_panel_info, - - .get_gpio_pin_info = bios_parser_get_gpio_pin_info, - .get_encoder_cap_info = bios_parser_get_encoder_cap_info, /* bios scratch register communication */ .is_accelerated_mode = bios_is_accelerated_mode, + .get_vga_enabled_displays = bios_get_vga_enabled_displays, .set_scratch_critical_state = bios_parser_set_scratch_critical_state, diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index 1ee1717f2e6f..1689c670ca6f 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -1280,6 +1280,12 @@ static bool bios_parser_is_accelerated_mode( return bios_is_accelerated_mode(dcb); } +static uint32_t bios_parser_get_vga_enabled_displays( + struct dc_bios *bios) +{ + return bios_get_vga_enabled_displays(bios); +} + /** * bios_parser_set_scratch_critical_state @@ -1800,6 +1806,7 @@ static const struct dc_vbios_funcs vbios_funcs = { .is_accelerated_mode = bios_parser_is_accelerated_mode, + .get_vga_enabled_displays = bios_parser_get_vga_enabled_displays, .set_scratch_critical_state = bios_parser_set_scratch_critical_state, diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c index 5c9e5108c32c..d4589470985c 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c @@ -78,5 +78,13 @@ void bios_set_scratch_critical_state( REG_UPDATE(BIOS_SCRATCH_6, S6_CRITICAL_STATE, critial_state); } +uint32_t bios_get_vga_enabled_displays( + struct dc_bios *bios) +{ + uint32_t active_disp = 1; + if (bios->regs->BIOS_SCRATCH_3) /*follow up with other asic, todo*/ + active_disp = REG_READ(BIOS_SCRATCH_3) & 0XFFFF; + return active_disp; +} diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h index c0047efeb006..75a29e68fb27 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h @@ -34,6 +34,7 @@ uint8_t *bios_get_image(struct dc_bios *bp, uint32_t offset, bool bios_is_accelerated_mode(struct dc_bios *bios); void bios_set_scratch_acc_mode_change(struct dc_bios *bios); void bios_set_scratch_critical_state(struct dc_bios *bios, bool state); +uint32_t bios_get_vga_enabled_displays(struct dc_bios *bios); #define GET_IMAGE(type, offset) ((type *) bios_get_image(&bp->base, offset, sizeof(type))) diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.h b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.h index 1fab634b66be..4c3789df253d 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.h +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.h @@ -29,38 +29,7 @@ #include "dce80/command_table_helper_dce80.h" #include "dce110/command_table_helper_dce110.h" #include "dce112/command_table_helper_dce112.h" - -struct command_table_helper { - bool (*controller_id_to_atom)(enum controller_id id, uint8_t *atom_id); - uint8_t (*encoder_action_to_atom)( - enum bp_encoder_control_action action); - uint32_t (*encoder_mode_bp_to_atom)(enum signal_type s, - bool enable_dp_audio); - bool (*engine_bp_to_atom)(enum engine_id engine_id, - uint32_t *atom_engine_id); - void (*assign_control_parameter)( - const struct command_table_helper *h, - struct bp_encoder_control *control, - DIG_ENCODER_CONTROL_PARAMETERS_V2 *ctrl_param); - bool (*clock_source_id_to_atom)(enum clock_source_id id, - uint32_t *atom_pll_id); - bool (*clock_source_id_to_ref_clk_src)( - enum clock_source_id id, - uint32_t *ref_clk_src_id); - uint8_t (*transmitter_bp_to_atom)(enum transmitter t); - uint8_t (*encoder_id_to_atom)(enum encoder_id id); - uint8_t (*clock_source_id_to_atom_phy_clk_src_id)( - enum clock_source_id id); - uint8_t (*signal_type_to_atom_dig_mode)(enum signal_type s); - uint8_t (*hpd_sel_to_atom)(enum hpd_source_id id); - uint8_t (*dig_encoder_sel_to_atom)(enum engine_id engine_id); - uint8_t (*phy_id_to_atom)(enum transmitter t); - uint8_t (*disp_power_gating_action_to_atom)( - enum bp_pipe_control_action action); - bool (*dc_clock_type_to_atom)(enum bp_dce_clock_type id, - uint32_t *atom_clock_type); - uint8_t (*transmitter_color_depth_to_atom)(enum transmitter_color_depth id); -}; +#include "command_table_helper_struct.h" bool dal_bios_parser_init_cmd_tbl_helper(const struct command_table_helper **h, enum dce_version dce); diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h index 9f587c91d843..785fcb20a1b9 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h @@ -29,35 +29,7 @@ #include "dce80/command_table_helper_dce80.h" #include "dce110/command_table_helper_dce110.h" #include "dce112/command_table_helper2_dce112.h" - -struct command_table_helper { - bool (*controller_id_to_atom)(enum controller_id id, uint8_t *atom_id); - uint8_t (*encoder_action_to_atom)( - enum bp_encoder_control_action action); - uint32_t (*encoder_mode_bp_to_atom)(enum signal_type s, - bool enable_dp_audio); - bool (*engine_bp_to_atom)(enum engine_id engine_id, - uint32_t *atom_engine_id); - bool (*clock_source_id_to_atom)(enum clock_source_id id, - uint32_t *atom_pll_id); - bool (*clock_source_id_to_ref_clk_src)( - enum clock_source_id id, - uint32_t *ref_clk_src_id); - uint8_t (*transmitter_bp_to_atom)(enum transmitter t); - uint8_t (*encoder_id_to_atom)(enum encoder_id id); - uint8_t (*clock_source_id_to_atom_phy_clk_src_id)( - enum clock_source_id id); - uint8_t (*signal_type_to_atom_dig_mode)(enum signal_type s); - uint8_t (*hpd_sel_to_atom)(enum hpd_source_id id); - uint8_t (*dig_encoder_sel_to_atom)(enum engine_id engine_id); - uint8_t (*phy_id_to_atom)(enum transmitter t); - uint8_t (*disp_power_gating_action_to_atom)( - enum bp_pipe_control_action action); - bool (*dc_clock_type_to_atom)(enum bp_dce_clock_type id, - uint32_t *atom_clock_type); - uint8_t (*transmitter_color_depth_to_atom)( - enum transmitter_color_depth id); -}; +#include "command_table_helper_struct.h" bool dal_bios_parser_init_cmd_tbl_helper2(const struct command_table_helper **h, enum dce_version dce); diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper_struct.h b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper_struct.h new file mode 100644 index 000000000000..1f2c0a3f06f9 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper_struct.h @@ -0,0 +1,66 @@ +/* + * Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DAL_COMMAND_TABLE_HELPER_STRUCT_H__ +#define __DAL_COMMAND_TABLE_HELPER_STRUCT_H__ + +#include "dce80/command_table_helper_dce80.h" +#include "dce110/command_table_helper_dce110.h" +#include "dce112/command_table_helper_dce112.h" + +struct _DIG_ENCODER_CONTROL_PARAMETERS_V2; +struct command_table_helper { + bool (*controller_id_to_atom)(enum controller_id id, uint8_t *atom_id); + uint8_t (*encoder_action_to_atom)( + enum bp_encoder_control_action action); + uint32_t (*encoder_mode_bp_to_atom)(enum signal_type s, + bool enable_dp_audio); + bool (*engine_bp_to_atom)(enum engine_id engine_id, + uint32_t *atom_engine_id); + void (*assign_control_parameter)( + const struct command_table_helper *h, + struct bp_encoder_control *control, + struct _DIG_ENCODER_CONTROL_PARAMETERS_V2 *ctrl_param); + bool (*clock_source_id_to_atom)(enum clock_source_id id, + uint32_t *atom_pll_id); + bool (*clock_source_id_to_ref_clk_src)( + enum clock_source_id id, + uint32_t *ref_clk_src_id); + uint8_t (*transmitter_bp_to_atom)(enum transmitter t); + uint8_t (*encoder_id_to_atom)(enum encoder_id id); + uint8_t (*clock_source_id_to_atom_phy_clk_src_id)( + enum clock_source_id id); + uint8_t (*signal_type_to_atom_dig_mode)(enum signal_type s); + uint8_t (*hpd_sel_to_atom)(enum hpd_source_id id); + uint8_t (*dig_encoder_sel_to_atom)(enum engine_id engine_id); + uint8_t (*phy_id_to_atom)(enum transmitter t); + uint8_t (*disp_power_gating_action_to_atom)( + enum bp_pipe_control_action action); + bool (*dc_clock_type_to_atom)(enum bp_dce_clock_type id, + uint32_t *atom_clock_type); + uint8_t (*transmitter_color_depth_to_atom)(enum transmitter_color_depth id); +}; + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/calcs/Makefile b/drivers/gpu/drm/amd/display/dc/calcs/Makefile index 7959e382ed28..95f332ee3e7e 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/Makefile +++ b/drivers/gpu/drm/amd/display/dc/calcs/Makefile @@ -24,9 +24,17 @@ # It calculates Bandwidth and Watermarks values for HW programming # -CFLAGS_dcn_calcs.o := -mhard-float -msse -mpreferred-stack-boundary=4 -CFLAGS_dcn_calc_auto.o := -mhard-float -msse -mpreferred-stack-boundary=4 -CFLAGS_dcn_calc_math.o := -mhard-float -msse -mpreferred-stack-boundary=4 -Wno-tautological-compare +ifneq ($(call cc-option, -mpreferred-stack-boundary=4),) + cc_stack_align := -mpreferred-stack-boundary=4 +else ifneq ($(call cc-option, -mstack-alignment=16),) + cc_stack_align := -mstack-alignment=16 +endif + +calcs_ccflags := -mhard-float -msse $(cc_stack_align) + +CFLAGS_dcn_calcs.o := $(calcs_ccflags) +CFLAGS_dcn_calc_auto.o := $(calcs_ccflags) +CFLAGS_dcn_calc_math.o := $(calcs_ccflags) -Wno-tautological-compare BW_CALCS = dce_calcs.o bw_fixed.o custom_float.o diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c index 2e11fac2a63d..6d38b8f43198 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c @@ -623,7 +623,7 @@ static void calculate_bandwidth( } else { /*graphics portrait tiling mode*/ - if ((data->graphics_micro_tile_mode == bw_def_rotated_micro_tiling)) { + if (data->graphics_micro_tile_mode == bw_def_rotated_micro_tiling) { data->orthogonal_rotation[i] = 0; } else { @@ -634,7 +634,7 @@ static void calculate_bandwidth( else { if ((i < 4)) { /*underlay landscape tiling mode is only supported*/ - if ((data->underlay_micro_tile_mode == bw_def_display_micro_tiling)) { + if (data->underlay_micro_tile_mode == bw_def_display_micro_tiling) { data->orthogonal_rotation[i] = 0; } else { @@ -643,7 +643,7 @@ static void calculate_bandwidth( } else { /*graphics landscape tiling mode*/ - if ((data->graphics_micro_tile_mode == bw_def_display_micro_tiling)) { + if (data->graphics_micro_tile_mode == bw_def_display_micro_tiling) { data->orthogonal_rotation[i] = 0; } else { @@ -947,14 +947,14 @@ static void calculate_bandwidth( } for (i = 0; i <= maximum_number_of_surfaces - 1; i++) { if (data->enable[i]) { - if ((data->number_of_displays == 1 && data->number_of_underlay_surfaces == 0)) { + if (data->number_of_displays == 1 && data->number_of_underlay_surfaces == 0) { /*set maximum chunk limit if only one graphic pipe is enabled*/ data->outstanding_chunk_request_limit[i] = bw_int_to_fixed(127); } else { data->outstanding_chunk_request_limit[i] = bw_ceil2(bw_div(data->adjusted_data_buffer_size[i], data->pipe_chunk_size_in_bytes[i]), bw_int_to_fixed(1)); /*clamp maximum chunk limit in the graphic display pipe*/ - if ((i >= 4)) { + if (i >= 4) { data->outstanding_chunk_request_limit[i] = bw_max2(bw_int_to_fixed(127), data->outstanding_chunk_request_limit[i]); } } @@ -1337,7 +1337,7 @@ static void calculate_bandwidth( /*if stutter and dram clock state change are gated before cursor then the cursor latency hiding does not limit stutter or dram clock state change*/ for (i = 0; i <= maximum_number_of_surfaces - 1; i++) { if (data->enable[i]) { - if ((dceip->graphics_lb_nodownscaling_multi_line_prefetching == 1)) { + if (dceip->graphics_lb_nodownscaling_multi_line_prefetching == 1) { data->maximum_latency_hiding[i] = bw_add(data->minimum_latency_hiding[i], bw_mul(bw_frc_to_fixed(8, 10), data->total_dmifmc_urgent_latency)); } else { @@ -1396,7 +1396,7 @@ static void calculate_bandwidth( } /*determine the number of displays with margin to switch in the v_active region*/ for (k = 0; k <= maximum_number_of_surfaces - 1; k++) { - if ((data->enable[k] == 1 && data->display_pstate_change_enable[k] == 1)) { + if (data->enable[k] == 1 && data->display_pstate_change_enable[k] == 1) { number_of_displays_enabled_with_margin = number_of_displays_enabled_with_margin + 1; } } @@ -1442,7 +1442,7 @@ static void calculate_bandwidth( data->nbp_state_change_enable = bw_def_no; } /*dram clock change is possible only in vblank if all displays are aligned and have no margin*/ - if ((number_of_aligned_displays_with_no_margin == number_of_displays_enabled)) { + if (number_of_aligned_displays_with_no_margin == number_of_displays_enabled) { nbp_state_change_enable_blank = bw_def_yes; } else { @@ -1470,7 +1470,7 @@ static void calculate_bandwidth( } } /*compute minimum time to read one chunk from the dmif buffer*/ - if ((number_of_displays_enabled > 2)) { + if (number_of_displays_enabled > 2) { data->chunk_request_delay = 0; } else { @@ -1804,7 +1804,7 @@ static void calculate_bandwidth( data->stutter_exit_watermark[i] = bw_add(bw_sub(vbios->stutter_self_refresh_exit_latency, data->total_dmifmc_urgent_latency), data->urgent_watermark[i]); data->stutter_entry_watermark[i] = bw_add(bw_sub(bw_add(vbios->stutter_self_refresh_exit_latency, vbios->stutter_self_refresh_entry_latency), data->total_dmifmc_urgent_latency), data->urgent_watermark[i]); /*unconditionally remove black out time from the nb p_state watermark*/ - if ((data->display_pstate_change_enable[i] == 1)) { + if (data->display_pstate_change_enable[i] == 1) { data->nbp_state_change_watermark[i] = bw_add(bw_add(vbios->nbp_state_change_latency, data->dmif_burst_time[data->y_clk_level][data->sclk_level]), bw_max2(data->line_source_pixels_transfer_time, data->dram_speed_change_line_source_transfer_time[i][data->y_clk_level][data->sclk_level])); } else { @@ -1816,7 +1816,7 @@ static void calculate_bandwidth( data->urgent_watermark[i] = bw_add(bw_add(bw_add(bw_add(bw_add(vbios->mcifwrmc_urgent_latency, data->mcifwr_burst_time[data->y_clk_level][data->sclk_level]), bw_max2(data->line_source_pixels_transfer_time, data->line_source_transfer_time[i][data->y_clk_level][data->sclk_level])), vbios->blackout_duration), data->chunk_request_time), data->cursor_request_time); data->stutter_exit_watermark[i] = bw_int_to_fixed(0); data->stutter_entry_watermark[i] = bw_int_to_fixed(0); - if ((data->display_pstate_change_enable[i] == 1)) { + if (data->display_pstate_change_enable[i] == 1) { data->nbp_state_change_watermark[i] = bw_add(bw_add(vbios->nbp_state_change_latency, data->mcifwr_burst_time[data->y_clk_level][data->sclk_level]), bw_max2(data->line_source_pixels_transfer_time, data->dram_speed_change_line_source_transfer_time[i][data->y_clk_level][data->sclk_level])); } else { @@ -2033,8 +2033,8 @@ void bw_calcs_init(struct bw_calcs_dceip *bw_dceip, vbios.cursor_width = 32; vbios.average_compression_rate = 4; vbios.number_of_request_slots_gmc_reserves_for_dmif_per_channel = 256; - vbios.blackout_duration = bw_int_to_fixed(18); /* us */ - vbios.maximum_blackout_recovery_time = bw_int_to_fixed(20); + vbios.blackout_duration = bw_int_to_fixed(0); /* us */ + vbios.maximum_blackout_recovery_time = bw_int_to_fixed(0); dceip.large_cursor = false; dceip.dmif_request_buffer_size = bw_int_to_fixed(768); @@ -2366,8 +2366,8 @@ void bw_calcs_init(struct bw_calcs_dceip *bw_dceip, vbios.cursor_width = 32; vbios.average_compression_rate = 4; vbios.number_of_request_slots_gmc_reserves_for_dmif_per_channel = 256; - vbios.blackout_duration = bw_int_to_fixed(18); /* us */ - vbios.maximum_blackout_recovery_time = bw_int_to_fixed(20); + vbios.blackout_duration = bw_int_to_fixed(0); /* us */ + vbios.maximum_blackout_recovery_time = bw_int_to_fixed(0); dceip.large_cursor = false; dceip.dmif_request_buffer_size = bw_int_to_fixed(768); diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index 331891c2c71a..c9aa686d16b9 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -486,6 +486,7 @@ static void split_stream_across_pipes( secondary_pipe->plane_res.ipp = pool->ipps[secondary_pipe->pipe_idx]; secondary_pipe->plane_res.xfm = pool->transforms[secondary_pipe->pipe_idx]; secondary_pipe->plane_res.dpp = pool->dpps[secondary_pipe->pipe_idx]; + secondary_pipe->plane_res.mpcc_inst = pool->dpps[secondary_pipe->pipe_idx]->inst; if (primary_pipe->bottom_pipe) { ASSERT(primary_pipe->bottom_pipe != secondary_pipe); secondary_pipe->bottom_pipe = primary_pipe->bottom_pipe; @@ -625,7 +626,7 @@ static bool dcn_bw_apply_registry_override(struct dc *dc) return updated; } -void hack_disable_optional_pipe_split(struct dcn_bw_internal_vars *v) +static void hack_disable_optional_pipe_split(struct dcn_bw_internal_vars *v) { /* * disable optional pipe split by lower dispclk bounding box @@ -634,7 +635,7 @@ void hack_disable_optional_pipe_split(struct dcn_bw_internal_vars *v) v->max_dispclk[0] = v->max_dppclk_vmin0p65; } -void hack_force_pipe_split(struct dcn_bw_internal_vars *v, +static void hack_force_pipe_split(struct dcn_bw_internal_vars *v, unsigned int pixel_rate_khz) { float pixel_rate_mhz = pixel_rate_khz / 1000; @@ -647,25 +648,20 @@ void hack_force_pipe_split(struct dcn_bw_internal_vars *v, v->max_dppclk[0] = pixel_rate_mhz; } -void hack_bounding_box(struct dcn_bw_internal_vars *v, +static void hack_bounding_box(struct dcn_bw_internal_vars *v, struct dc_debug *dbg, struct dc_state *context) { - if (dbg->pipe_split_policy == MPC_SPLIT_AVOID) { + if (dbg->pipe_split_policy == MPC_SPLIT_AVOID) hack_disable_optional_pipe_split(v); - } if (dbg->pipe_split_policy == MPC_SPLIT_AVOID_MULT_DISP && - context->stream_count >= 2) { + context->stream_count >= 2) hack_disable_optional_pipe_split(v); - } if (context->stream_count == 1 && - dbg->force_single_disp_pipe_split) { - struct dc_stream_state *stream0 = context->streams[0]; - - hack_force_pipe_split(v, stream0->timing.pix_clk_khz); - } + dbg->force_single_disp_pipe_split) + hack_force_pipe_split(v, context->streams[0]->timing.pix_clk_khz); } bool dcn_validate_bandwidth( @@ -799,23 +795,10 @@ bool dcn_validate_bandwidth( v->phyclk_per_state[2] = v->phyclkv_nom0p8; v->phyclk_per_state[1] = v->phyclkv_mid0p72; v->phyclk_per_state[0] = v->phyclkv_min0p65; - - hack_bounding_box(v, &dc->debug, context); - - if (v->voltage_override == dcn_bw_v_max0p9) { - v->voltage_override_level = number_of_states - 1; - } else if (v->voltage_override == dcn_bw_v_nom0p8) { - v->voltage_override_level = number_of_states - 2; - } else if (v->voltage_override == dcn_bw_v_mid0p72) { - v->voltage_override_level = number_of_states - 3; - } else { - v->voltage_override_level = 0; - } v->synchronized_vblank = dcn_bw_no; v->ta_pscalculation = dcn_bw_override; v->allow_different_hratio_vratio = dcn_bw_yes; - for (i = 0, input_idx = 0; i < pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; @@ -948,8 +931,19 @@ bool dcn_validate_bandwidth( v->number_of_active_planes = input_idx; scaler_settings_calculation(v); + + hack_bounding_box(v, &dc->debug, context); + mode_support_and_system_configuration(v); + /* Unhack dppclk: dont bother with trying to pipe split if we cannot maintain dpm0 */ + if (v->voltage_level != 0 + && context->stream_count == 1 + && dc->debug.force_single_disp_pipe_split) { + v->max_dppclk[0] = v->max_dppclk_vmin0p65; + mode_support_and_system_configuration(v); + } + if (v->voltage_level == 0 && (dc->debug.sr_exit_time_dpm0_ns || dc->debug.sr_enter_plus_exit_time_dpm0_ns)) { diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 35e84ed031de..77a1bf233c3c 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -29,6 +29,7 @@ #include "core_status.h" #include "core_types.h" #include "hw_sequencer.h" +#include "dce/dce_hwseq.h" #include "resource.h" @@ -38,6 +39,7 @@ #include "bios_parser_interface.h" #include "include/irq_service_interface.h" #include "transform.h" +#include "dmcu.h" #include "dpp.h" #include "timing_generator.h" #include "virtual/virtual_link_encoder.h" @@ -214,6 +216,130 @@ bool dc_stream_get_crtc_position(struct dc *dc, return ret; } +/** + * dc_stream_configure_crc: Configure CRC capture for the given stream. + * @dc: DC Object + * @stream: The stream to configure CRC on. + * @enable: Enable CRC if true, disable otherwise. + * @continuous: Capture CRC on every frame if true. Otherwise, only capture + * once. + * + * By default, only CRC0 is configured, and the entire frame is used to + * calculate the crc. + */ +bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream, + bool enable, bool continuous) +{ + int i; + struct pipe_ctx *pipe; + struct crc_params param; + struct timing_generator *tg; + + for (i = 0; i < MAX_PIPES; i++) { + pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe->stream == stream) + break; + } + /* Stream not found */ + if (i == MAX_PIPES) + return false; + + /* Always capture the full frame */ + param.windowa_x_start = 0; + param.windowa_y_start = 0; + param.windowa_x_end = pipe->stream->timing.h_addressable; + param.windowa_y_end = pipe->stream->timing.v_addressable; + param.windowb_x_start = 0; + param.windowb_y_start = 0; + param.windowb_x_end = pipe->stream->timing.h_addressable; + param.windowb_y_end = pipe->stream->timing.v_addressable; + + /* Default to the union of both windows */ + param.selection = UNION_WINDOW_A_B; + param.continuous_mode = continuous; + param.enable = enable; + + tg = pipe->stream_res.tg; + + /* Only call if supported */ + if (tg->funcs->configure_crc) + return tg->funcs->configure_crc(tg, ¶m); + dm_logger_write(dc->ctx->logger, LOG_WARNING, "CRC capture not supported."); + return false; +} + +/** + * dc_stream_get_crc: Get CRC values for the given stream. + * @dc: DC object + * @stream: The DC stream state of the stream to get CRCs from. + * @r_cr, g_y, b_cb: CRC values for the three channels are stored here. + * + * dc_stream_configure_crc needs to be called beforehand to enable CRCs. + * Return false if stream is not found, or if CRCs are not enabled. + */ +bool dc_stream_get_crc(struct dc *dc, struct dc_stream_state *stream, + uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb) +{ + int i; + struct pipe_ctx *pipe; + struct timing_generator *tg; + + for (i = 0; i < MAX_PIPES; i++) { + pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe->stream == stream) + break; + } + /* Stream not found */ + if (i == MAX_PIPES) + return false; + + tg = pipe->stream_res.tg; + + if (tg->funcs->get_crc) + return tg->funcs->get_crc(tg, r_cr, g_y, b_cb); + dm_logger_write(dc->ctx->logger, LOG_WARNING, "CRC capture not supported."); + return false; +} + +void dc_stream_set_dither_option(struct dc_stream_state *stream, + enum dc_dither_option option) +{ + struct bit_depth_reduction_params params; + struct dc_link *link = stream->status.link; + struct pipe_ctx *pipes = NULL; + int i; + + for (i = 0; i < MAX_PIPES; i++) { + if (link->dc->current_state->res_ctx.pipe_ctx[i].stream == + stream) { + pipes = &link->dc->current_state->res_ctx.pipe_ctx[i]; + break; + } + } + + if (!pipes) + return; + if (option > DITHER_OPTION_MAX) + return; + + stream->dither_option = option; + + memset(¶ms, 0, sizeof(params)); + resource_build_bit_depth_reduction_params(stream, ¶ms); + stream->bit_depth_params = params; + + if (pipes->plane_res.xfm && + pipes->plane_res.xfm->funcs->transform_set_pixel_storage_depth) { + pipes->plane_res.xfm->funcs->transform_set_pixel_storage_depth( + pipes->plane_res.xfm, + pipes->plane_res.scl_data.lb_params.depth, + &stream->bit_depth_params); + } + + pipes->stream_res.opp->funcs-> + opp_program_bit_depth_reduction(pipes->stream_res.opp, ¶ms); +} + void dc_stream_set_static_screen_events(struct dc *dc, struct dc_stream_state **streams, int num_streams, @@ -359,9 +485,6 @@ static bool construct(struct dc *dc, dc_version = resource_parse_asic_id(init_params->asic_id); dc_ctx->dce_version = dc_version; -#if defined(CONFIG_DRM_AMD_DC_FBC) - dc->ctx->fbc_gpu_addr = init_params->fbc_gpu_addr; -#endif /* Resource should construct all asic specific resources. * This should be the only place where we need to parse the asic id */ @@ -487,6 +610,12 @@ struct dc *dc_create(const struct dc_init_data *init_params) dc->caps.max_audios = dc->res_pool->audio_count; dc->caps.linear_pitch_alignment = 64; + /* Populate versioning information */ + dc->versions.dc_ver = DC_VER; + + if (dc->res_pool->dmcu != NULL) + dc->versions.dmcu_version = dc->res_pool->dmcu->dmcu_version; + dc->config = init_params->flags; dm_logger_write(dc->ctx->logger, LOG_DC, @@ -524,11 +653,13 @@ static void enable_timing_multisync( if (!ctx->res_ctx.pipe_ctx[i].stream || !ctx->res_ctx.pipe_ctx[i].stream->triggered_crtc_reset.enabled) continue; + if (ctx->res_ctx.pipe_ctx[i].stream == ctx->res_ctx.pipe_ctx[i].stream->triggered_crtc_reset.event_source) + continue; multisync_pipes[multisync_count] = &ctx->res_ctx.pipe_ctx[i]; multisync_count++; } - if (multisync_count > 1) { + if (multisync_count > 0) { dc->hwss.enable_per_frame_crtc_position_reset( dc, multisync_count, multisync_pipes); } @@ -650,7 +781,6 @@ bool dc_enable_stereo( return ret; } - /* * Applies given context to HW and copy it into current context. * It's up to the user to release the src context afterwards. @@ -669,7 +799,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c dc_streams[i] = context->streams[i]; if (!dcb->funcs->is_accelerated_mode(dcb)) - dc->hwss.enable_accelerated_mode(dc); + dc->hwss.enable_accelerated_mode(dc, context); /* re-program planes for existing stream, in case we need to * free up plane resource for later use @@ -973,12 +1103,18 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa if (u->plane_info->input_tf != u->surface->input_tf) update_flags->bits.input_tf_change = 1; + if (u->plane_info->sdr_white_level != u->surface->sdr_white_level) + update_flags->bits.output_tf_change = 1; + if (u->plane_info->horizontal_mirror != u->surface->horizontal_mirror) update_flags->bits.horizontal_mirror_change = 1; if (u->plane_info->rotation != u->surface->rotation) update_flags->bits.rotation_change = 1; + if (u->plane_info->format != u->surface->format) + update_flags->bits.pixel_format_change = 1; + if (u->plane_info->stereo_format != u->surface->stereo_format) update_flags->bits.stereo_format_change = 1; @@ -997,6 +1133,9 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa */ update_flags->bits.bpp_change = 1; + if (u->gamma && dce_use_lut(u->plane_info->format)) + update_flags->bits.gamma_change = 1; + if (memcmp(&u->plane_info->tiling_info, &u->surface->tiling_info, sizeof(union dc_tiling_info)) != 0) { update_flags->bits.swizzle_change = 1; @@ -1012,8 +1151,11 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa if (update_flags->bits.rotation_change || update_flags->bits.stereo_format_change + || update_flags->bits.pixel_format_change + || update_flags->bits.gamma_change || update_flags->bits.bpp_change - || update_flags->bits.bandwidth_change) + || update_flags->bits.bandwidth_change + || update_flags->bits.output_tf_change) return UPDATE_TYPE_FULL; return UPDATE_TYPE_MED; @@ -1092,12 +1234,12 @@ static enum surface_update_type det_surface_update(const struct dc *dc, elevate_update_type(&overall_type, type); if (u->in_transfer_func) - update_flags->bits.in_transfer_func = 1; + update_flags->bits.in_transfer_func_change = 1; if (u->input_csc_color_matrix) update_flags->bits.input_csc_change = 1; - if (update_flags->bits.in_transfer_func + if (update_flags->bits.in_transfer_func_change || update_flags->bits.input_csc_change) { type = UPDATE_TYPE_MED; elevate_update_type(&overall_type, type); @@ -1183,6 +1325,7 @@ static void commit_planes_for_stream(struct dc *dc, struct dc_state *context) { int i, j; + struct pipe_ctx *top_pipe_to_program = NULL; if (update_type == UPDATE_TYPE_FULL) { dc->hwss.set_bandwidth(dc, context, false); @@ -1202,13 +1345,17 @@ static void commit_planes_for_stream(struct dc *dc, for (j = 0; j < dc->res_pool->pipe_count; j++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; - if (update_type == UPDATE_TYPE_FAST || !pipe_ctx->plane_state) - continue; - if (!pipe_ctx->top_pipe && - pipe_ctx->stream && - pipe_ctx->stream == stream) { - struct dc_stream_status *stream_status = + pipe_ctx->stream && + pipe_ctx->stream == stream) { + struct dc_stream_status *stream_status = NULL; + + top_pipe_to_program = pipe_ctx; + + if (update_type == UPDATE_TYPE_FAST || !pipe_ctx->plane_state) + continue; + + stream_status = stream_get_status(context, pipe_ctx->stream); dc->hwss.apply_ctx_for_surface( @@ -1219,22 +1366,32 @@ static void commit_planes_for_stream(struct dc *dc, if (update_type == UPDATE_TYPE_FULL) context_timing_trace(dc, &context->res_ctx); - /* Perform requested Updates */ - for (i = 0; i < surface_count; i++) { - struct dc_plane_state *plane_state = srf_updates[i].surface; + /* Lock the top pipe while updating plane addrs, since freesync requires + * plane addr update event triggers to be synchronized. + * top_pipe_to_program is expected to never be NULL + */ + if (update_type == UPDATE_TYPE_FAST) { + dc->hwss.pipe_control_lock(dc, top_pipe_to_program, true); - for (j = 0; j < dc->res_pool->pipe_count; j++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; + /* Perform requested Updates */ + for (i = 0; i < surface_count; i++) { + struct dc_plane_state *plane_state = srf_updates[i].surface; - if (pipe_ctx->stream != stream) - continue; + for (j = 0; j < dc->res_pool->pipe_count; j++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; - if (pipe_ctx->plane_state != plane_state) - continue; + if (pipe_ctx->stream != stream) + continue; - if (update_type == UPDATE_TYPE_FAST && srf_updates[i].flip_addr) + if (pipe_ctx->plane_state != plane_state) + continue; + + if (srf_updates[i].flip_addr) dc->hwss.update_plane_addr(dc, pipe_ctx); + } } + + dc->hwss.pipe_control_lock(dc, top_pipe_to_program, false); } if (stream && stream_update && update_type > UPDATE_TYPE_FAST) @@ -1487,12 +1644,17 @@ struct dc_sink *dc_link_add_remote_sink( &dc_sink->dc_edid, &dc_sink->edid_caps); - if (edid_status != EDID_OK) - goto fail; + /* + * Treat device as no EDID device if EDID + * parsing fails + */ + if (edid_status != EDID_OK) { + dc_sink->dc_edid.length = 0; + dm_error("Bad EDID, status%d!\n", edid_status); + } return dc_sink; -fail: - dc_link_remove_remote_sink(link, dc_sink); + fail_add_sink: dc_sink_release(dc_sink); return NULL; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index a37428271573..95955ade4012 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -126,6 +126,8 @@ static bool program_hpd_filter( int delay_on_connect_in_ms = 0; int delay_on_disconnect_in_ms = 0; + if (link->is_hpd_filter_disabled) + return false; /* Verify feature is supported */ switch (link->connector_signal) { case SIGNAL_TYPE_DVI_SINGLE_LINK: @@ -464,7 +466,7 @@ static void link_disconnect_sink(struct dc_link *link) link->dpcd_sink_count = 0; } -static void detect_dp( +static bool detect_dp( struct dc_link *link, struct display_sink_capability *sink_caps, bool *converter_disable_audio, @@ -478,7 +480,8 @@ static void detect_dp( if (sink_caps->transaction_type == DDC_TRANSACTION_TYPE_I2C_OVER_AUX) { sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT; - detect_dp_sink_caps(link); + if (!detect_dp_sink_caps(link)) + return false; if (is_mst_supported(link)) { sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT_MST; @@ -529,7 +532,7 @@ static void detect_dp( * active dongle unplug processing for short irq */ link_disconnect_sink(link); - return; + return true; } if (link->dpcd_caps.dongle_type != DISPLAY_DONGLE_DP_HDMI_CONVERTER) @@ -541,6 +544,8 @@ static void detect_dp( sink_caps, audio_support); } + + return true; } bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) @@ -604,11 +609,12 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) } case SIGNAL_TYPE_DISPLAY_PORT: { - detect_dp( + if (!detect_dp( link, &sink_caps, &converter_disable_audio, - aud_support, reason); + aud_support, reason)) + return false; /* Active dongle downstream unplug */ if (link->type == dc_connection_active_dongle @@ -677,8 +683,6 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) case EDID_NO_RESPONSE: dm_logger_write(link->ctx->logger, LOG_ERROR, "No EDID read.\n"); - return false; - default: break; } @@ -1248,6 +1252,12 @@ static enum dc_status enable_link_dp( pipe_ctx->clock_source->id, &link_settings); + if (stream->sink->edid_caps.panel_patch.dppowerup_delay > 0) { + int delay_dp_power_up_in_ms = stream->sink->edid_caps.panel_patch.dppowerup_delay; + + msleep(delay_dp_power_up_in_ms); + } + panel_mode = dp_get_panel_mode(link); dpcd_configure_panel_mode(link, panel_mode); @@ -1279,13 +1289,12 @@ static enum dc_status enable_link_edp( enum dc_status status; struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->sink->link; - + /*in case it is not on*/ link->dc->hwss.edp_power_control(link, true); link->dc->hwss.edp_wait_for_hpd_ready(link, true); status = enable_link_dp(state, pipe_ctx); - link->dc->hwss.edp_backlight_control(link, true); return status; } @@ -1749,8 +1758,7 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx) link->link_enc, pipe_ctx->clock_source->id, display_color_depth, - pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_TYPE_A, - pipe_ctx->stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK, + pipe_ctx->stream->signal, stream->phy_pix_clk); if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) @@ -1788,9 +1796,21 @@ static enum dc_status enable_link( } if (pipe_ctx->stream_res.audio && status == DC_OK) { + struct dc *core_dc = pipe_ctx->stream->ctx->dc; /* notify audio driver for audio modes of monitor */ + struct pp_smu_funcs_rv *pp_smu = core_dc->res_pool->pp_smu; + unsigned int i, num_audio = 1; + for (i = 0; i < MAX_PIPES; i++) { + /*current_state not updated yet*/ + if (core_dc->current_state->res_ctx.pipe_ctx[i].stream_res.audio != NULL) + num_audio++; + } + pipe_ctx->stream_res.audio->funcs->az_enable(pipe_ctx->stream_res.audio); + if (num_audio == 1 && pp_smu != NULL && pp_smu->set_pme_wa_enable != NULL) + /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/ + pp_smu->set_pme_wa_enable(&pp_smu->pp_smu); /* un-mute audio */ /* TODO: audio should be per stream rather than per link */ pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control( @@ -2268,7 +2288,16 @@ void core_link_enable_stream( { struct dc *core_dc = pipe_ctx->stream->ctx->dc; - enum dc_status status = enable_link(state, pipe_ctx); + enum dc_status status; + + /* eDP lit up by bios already, no need to enable again. */ + if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP && + core_dc->apply_edp_fast_boot_optimization) { + core_dc->apply_edp_fast_boot_optimization = false; + return; + } + + status = enable_link(state, pipe_ctx); if (status != DC_OK) { dm_logger_write(pipe_ctx->stream->ctx->logger, @@ -2298,9 +2327,8 @@ void core_link_enable_stream( if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) allocate_mst_payload(pipe_ctx); - if (dc_is_dp_signal(pipe_ctx->stream->signal)) - core_dc->hwss.unblank_stream(pipe_ctx, - &pipe_ctx->stream->sink->link->cur_link_settings); + core_dc->hwss.unblank_stream(pipe_ctx, + &pipe_ctx->stream->sink->link->cur_link_settings); } void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option) @@ -2310,8 +2338,7 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option) if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) deallocate_mst_payload(pipe_ctx); - if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP) - core_dc->hwss.edp_backlight_control(pipe_ctx->stream->sink->link, false); + core_dc->hwss.blank_stream(pipe_ctx); core_dc->hwss.disable_stream(pipe_ctx, option); @@ -2328,3 +2355,33 @@ void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) core_dc->hwss.set_avmute(pipe_ctx, enable); } +void dc_link_disable_hpd_filter(struct dc_link *link) +{ + struct gpio *hpd; + + if (!link->is_hpd_filter_disabled) { + link->is_hpd_filter_disabled = true; + /* Obtain HPD handle */ + hpd = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service); + + if (!hpd) + return; + + /* Setup HPD filtering */ + if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) { + struct gpio_hpd_config config; + + config.delay_on_connect = 0; + config.delay_on_disconnect = 0; + + dal_irq_setup_hpd_filter(hpd, &config); + + dal_gpio_close(hpd); + } else { + ASSERT_CRITICAL(false); + } + /* Release HPD handle */ + dal_gpio_destroy_irq(&hpd); + } +} + diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 61e8c3e02d16..604fb0171ee3 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -718,7 +718,7 @@ static enum link_training_result perform_channel_equalization_sequence( uint32_t retries_ch_eq; enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; union lane_align_status_updated dpcd_lane_status_updated = {{0}}; - union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {{{0}}};; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {{{0}}}; hw_tr_pattern = get_supported_tp(link); @@ -1465,7 +1465,7 @@ void decide_link_settings(struct dc_stream_state *stream, /* MST doesn't perform link training for now * TODO: add MST specific link training routine */ - if (is_mst_supported(link)) { + if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { *link_setting = link->verified_link_cap; return; } @@ -2235,13 +2235,14 @@ static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data, link->wa_flags.dp_keep_receiver_powered = false; } -static void retrieve_link_cap(struct dc_link *link) +static bool retrieve_link_cap(struct dc_link *link) { uint8_t dpcd_data[DP_TRAINING_AUX_RD_INTERVAL - DP_DPCD_REV + 1]; union down_stream_port_count down_strm_port_count; union edp_configuration_cap edp_config_cap; union dp_downstream_port_present ds_port = { 0 }; + enum dc_status status = DC_ERROR_UNEXPECTED; memset(dpcd_data, '\0', sizeof(dpcd_data)); memset(&down_strm_port_count, @@ -2249,11 +2250,16 @@ static void retrieve_link_cap(struct dc_link *link) memset(&edp_config_cap, '\0', sizeof(union edp_configuration_cap)); - core_link_read_dpcd( - link, - DP_DPCD_REV, - dpcd_data, - sizeof(dpcd_data)); + status = core_link_read_dpcd( + link, + DP_DPCD_REV, + dpcd_data, + sizeof(dpcd_data)); + + if (status != DC_OK) { + dm_error("%s: Read dpcd data failed.\n", __func__); + return false; + } { union training_aux_rd_interval aux_rd_interval; @@ -2315,11 +2321,13 @@ static void retrieve_link_cap(struct dc_link *link) /* Connectivity log: detection */ CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: "); + + return true; } -void detect_dp_sink_caps(struct dc_link *link) +bool detect_dp_sink_caps(struct dc_link *link) { - retrieve_link_cap(link); + return retrieve_link_cap(link); /* dc init_hw has power encoder using default * signal for connector. For native DP, no diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c index 2096f2a179f2..bae9b0587e12 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c @@ -102,7 +102,7 @@ void dp_enable_link_phy( dp_receiver_power_ctrl(link, true); } -static bool edp_receiver_ready_T9(struct dc_link *link) +bool edp_receiver_ready_T9(struct dc_link *link) { unsigned int tries = 0; unsigned char sinkstatus = 0; @@ -123,6 +123,28 @@ static bool edp_receiver_ready_T9(struct dc_link *link) } while (++tries < 50); return result; } +bool edp_receiver_ready_T7(struct dc_link *link) +{ + unsigned int tries = 0; + unsigned char sinkstatus = 0; + unsigned char edpRev = 0; + enum dc_status result = DC_OK; + + result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev)); + if (result == DC_OK && edpRev < DP_EDP_12) + return true; + /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/ + do { + sinkstatus = 0; + result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus)); + if (sinkstatus == 1) + break; + if (result != DC_OK) + break; + udelay(25); //MAx T7 is 50ms + } while (++tries < 300); + return result; +} void dp_disable_link_phy(struct dc_link *link, enum signal_type signal) { @@ -130,7 +152,6 @@ void dp_disable_link_phy(struct dc_link *link, enum signal_type signal) dp_receiver_power_ctrl(link, false); if (signal == SIGNAL_TYPE_EDP) { - edp_receiver_ready_T9(link); link->link_enc->funcs->disable_output(link->link_enc, signal); link->dc->hwss.edp_power_control(link, false); } else diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 95b8dd0e53c6..ce0e9e76eb35 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -35,6 +35,7 @@ #include "core_types.h" #include "set_mode_types.h" #include "virtual/virtual_stream_encoder.h" +#include "dpcd_defs.h" #include "dce80/dce80_resource.h" #include "dce100/dce100_resource.h" @@ -696,7 +697,7 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r /* Adjust for viewport end clip-off */ - if ((data->viewport.x + data->viewport.width) < (src.x + src.width)) { + if ((data->viewport.x + data->viewport.width) < (src.x + src.width) && !flip_horz_scan_dir) { int vp_clip = src.x + src.width - data->viewport.width - data->viewport.x; int int_part = dal_fixed31_32_floor( dal_fixed31_32_sub(data->inits.h, data->ratios.horz)); @@ -704,7 +705,7 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r int_part = int_part > 0 ? int_part : 0; data->viewport.width += int_part < vp_clip ? int_part : vp_clip; } - if ((data->viewport.y + data->viewport.height) < (src.y + src.height)) { + if ((data->viewport.y + data->viewport.height) < (src.y + src.height) && !flip_vert_scan_dir) { int vp_clip = src.y + src.height - data->viewport.height - data->viewport.y; int int_part = dal_fixed31_32_floor( dal_fixed31_32_sub(data->inits.v, data->ratios.vert)); @@ -712,7 +713,7 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r int_part = int_part > 0 ? int_part : 0; data->viewport.height += int_part < vp_clip ? int_part : vp_clip; } - if ((data->viewport_c.x + data->viewport_c.width) < (src.x + src.width) / vpc_div) { + if ((data->viewport_c.x + data->viewport_c.width) < (src.x + src.width) / vpc_div && !flip_horz_scan_dir) { int vp_clip = (src.x + src.width) / vpc_div - data->viewport_c.width - data->viewport_c.x; int int_part = dal_fixed31_32_floor( @@ -721,7 +722,7 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r int_part = int_part > 0 ? int_part : 0; data->viewport_c.width += int_part < vp_clip ? int_part : vp_clip; } - if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div) { + if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div && !flip_vert_scan_dir) { int vp_clip = (src.y + src.height) / vpc_div - data->viewport_c.height - data->viewport_c.y; int int_part = dal_fixed31_32_floor( @@ -1054,6 +1055,7 @@ static int acquire_first_split_pipe( pipe_ctx->plane_res.ipp = pool->ipps[i]; pipe_ctx->plane_res.dpp = pool->dpps[i]; pipe_ctx->stream_res.opp = pool->opps[i]; + pipe_ctx->plane_res.mpcc_inst = pool->dpps[i]->inst; pipe_ctx->pipe_idx = i; pipe_ctx->stream = stream; @@ -1360,9 +1362,6 @@ bool dc_is_stream_scaling_unchanged( return true; } -/* Maximum TMDS single link pixel clock 165MHz */ -#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ 165000 - static void update_stream_engine_usage( struct resource_context *res_ctx, const struct resource_pool *pool, @@ -1409,6 +1408,8 @@ static int acquire_first_free_pipe( pipe_ctx->plane_res.xfm = pool->transforms[i]; pipe_ctx->plane_res.dpp = pool->dpps[i]; pipe_ctx->stream_res.opp = pool->opps[i]; + if (pool->dpps[i]) + pipe_ctx->plane_res.mpcc_inst = pool->dpps[i]->inst; pipe_ctx->pipe_idx = i; @@ -1555,6 +1556,9 @@ enum dc_status dc_remove_stream_from_ctx( dc->res_pool, del_pipe->clock_source); + if (dc->res_pool->funcs->remove_stream_from_ctx) + dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream); + memset(del_pipe, 0, sizeof(*del_pipe)); break; @@ -2431,7 +2435,8 @@ static void set_vsc_info_packet( unsigned int vscPacketRevision = 0; unsigned int i; - if (stream->sink->link->psr_enabled) { + /*VSC packet set to 2 when DP revision >= 1.2*/ + if (stream->sink->link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) { vscPacketRevision = 2; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 261811e0c094..87a193ac2883 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -33,8 +33,7 @@ /******************************************************************************* * Private functions ******************************************************************************/ -#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST 297000 -static void update_stream_signal(struct dc_stream_state *stream) +void update_stream_signal(struct dc_stream_state *stream) { struct dc_sink *dc_sink = stream->sink; @@ -45,8 +44,9 @@ static void update_stream_signal(struct dc_stream_state *stream) stream->signal = dc_sink->sink_signal; if (dc_is_dvi_signal(stream->signal)) { - if (stream->timing.pix_clk_khz > TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST && - stream->sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) + if (stream->ctx->dc->caps.dual_link_dvi && + stream->timing.pix_clk_khz > TMDS_MAX_PIXEL_CLOCK && + stream->sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) stream->signal = SIGNAL_TYPE_DVI_DUAL_LINK; else stream->signal = SIGNAL_TYPE_DVI_SINGLE_LINK; @@ -193,6 +193,7 @@ bool dc_stream_set_cursor_attributes( core_dc = stream->ctx->dc; res_ctx = &core_dc->current_state->res_ctx; + stream->cursor_attributes = *attributes; for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; @@ -203,34 +204,8 @@ bool dc_stream_set_cursor_attributes( continue; - if (pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes != NULL) - pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes( - pipe_ctx->plane_res.ipp, attributes); - - if (pipe_ctx->plane_res.hubp != NULL && - pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes != NULL) - pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( - pipe_ctx->plane_res.hubp, attributes); - - if (pipe_ctx->plane_res.mi != NULL && - pipe_ctx->plane_res.mi->funcs->set_cursor_attributes != NULL) - pipe_ctx->plane_res.mi->funcs->set_cursor_attributes( - pipe_ctx->plane_res.mi, attributes); - - - if (pipe_ctx->plane_res.xfm != NULL && - pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes != NULL) - pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes( - pipe_ctx->plane_res.xfm, attributes); - - if (pipe_ctx->plane_res.dpp != NULL && - pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes != NULL) - pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( - pipe_ctx->plane_res.dpp, attributes->color_format); + core_dc->hwss.set_cursor_attribute(pipe_ctx); } - - stream->cursor_attributes = *attributes; - return true; } @@ -254,21 +229,10 @@ bool dc_stream_set_cursor_position( core_dc = stream->ctx->dc; res_ctx = &core_dc->current_state->res_ctx; + stream->cursor_position = *position; for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; - struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; - struct mem_input *mi = pipe_ctx->plane_res.mi; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct dpp *dpp = pipe_ctx->plane_res.dpp; - struct dc_cursor_position pos_cpy = *position; - struct dc_cursor_mi_param param = { - .pixel_clk_khz = stream->timing.pix_clk_khz, - .ref_clk_khz = core_dc->res_pool->ref_clock_inKhz, - .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, - .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, - .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz - }; if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.mi && !pipe_ctx->plane_res.hubp) || @@ -276,33 +240,9 @@ bool dc_stream_set_cursor_position( (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp)) continue; - if (pipe_ctx->plane_state->address.type - == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) - pos_cpy.enable = false; - - if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) - pos_cpy.enable = false; - - - if (ipp != NULL && ipp->funcs->ipp_cursor_set_position != NULL) - ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, ¶m); - - if (mi != NULL && mi->funcs->set_cursor_position != NULL) - mi->funcs->set_cursor_position(mi, &pos_cpy, ¶m); - - if (!hubp) - continue; - - if (hubp->funcs->set_cursor_position != NULL) - hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); - - if (dpp != NULL && dpp->funcs->set_cursor_position != NULL) - dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width); - + core_dc->hwss.set_cursor_position(pipe_ctx); } - stream->cursor_position = *position; - return true; } diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index e2e3c9df79ea..5bb0e5defaf4 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -38,7 +38,7 @@ #include "inc/compressor.h" #include "dml/display_mode_lib.h" -#define DC_VER "3.1.27" +#define DC_VER "3.1.34" #define MAX_SURFACES 3 #define MAX_STREAMS 6 @@ -48,6 +48,18 @@ /******************************************************************************* * Display Core Interfaces ******************************************************************************/ +struct dmcu_version { + unsigned int date; + unsigned int month; + unsigned int year; + unsigned int interface_version; +}; + +struct dc_versions { + const char *dc_ver; + struct dmcu_version dmcu_version; +}; + struct dc_caps { uint32_t max_streams; uint32_t max_links; @@ -62,6 +74,7 @@ struct dc_caps { bool dcc_const_color; bool dynamic_audio; bool is_apu; + bool dual_link_dvi; }; struct dc_dcc_surface_param { @@ -94,6 +107,7 @@ struct dc_surface_dcc_cap { }; struct dc_static_screen_events { + bool force_trigger; bool cursor_update; bool surface_update; bool overlay_update; @@ -211,11 +225,15 @@ struct dc_debug { bool disable_stereo_support; bool vsr_support; bool performance_trace; + bool az_endpoint_mute_only; + bool always_use_regamma; + bool p010_mpo_support; }; struct dc_state; struct resource_pool; struct dce_hwseq; struct dc { + struct dc_versions versions; struct dc_caps caps; struct dc_cap_funcs cap_funcs; struct dc_config config; @@ -252,6 +270,8 @@ struct dc { bool optimized_required; + bool apply_edp_fast_boot_optimization; + /* FBC compressor */ #if defined(CONFIG_DRM_AMD_DC_FBC) struct compressor *fbc_compressor; @@ -288,9 +308,6 @@ struct dc_init_data { struct dc_config flags; uint32_t log_mask; -#if defined(CONFIG_DRM_AMD_DC_FBC) - uint64_t fbc_gpu_addr; -#endif }; struct dc *dc_create(const struct dc_init_data *init_params); @@ -369,6 +386,8 @@ struct dc_transfer_func { struct dc_transfer_func_distributed_points tf_pts; enum dc_transfer_func_type type; enum dc_transfer_func_predefined tf; + /* FP16 1.0 reference level in nits, default is 80 nits, only for PQ*/ + uint32_t sdr_ref_white_level; struct dc_context *ctx; }; @@ -397,12 +416,15 @@ union surface_update_flags { uint32_t swizzle_change:1; uint32_t scaling_change:1; uint32_t position_change:1; - uint32_t in_transfer_func:1; + uint32_t in_transfer_func_change:1; uint32_t input_csc_change:1; + uint32_t output_tf_change:1; + uint32_t pixel_format_change:1; /* Full updates */ uint32_t new_plane:1; uint32_t bpp_change:1; + uint32_t gamma_change:1; uint32_t bandwidth_change:1; uint32_t clock_change:1; uint32_t stereo_format_change:1; @@ -429,6 +451,7 @@ struct dc_plane_state { struct dc_bias_and_scale *bias_and_scale; struct csc_transform input_csc_color_matrix; struct fixed31_32 coeff_reduction_factor; + uint32_t sdr_white_level; // TODO: No longer used, remove struct dc_hdr_static_metadata hdr_static_ctx; @@ -465,6 +488,7 @@ struct dc_plane_info { enum plane_stereo_format stereo_format; enum dc_color_space color_space; enum color_transfer_func input_tf; + unsigned int sdr_white_level; bool horizontal_mirror; bool visible; bool per_pixel_alpha; @@ -489,10 +513,8 @@ struct dc_surface_update { /* following updates require alloc/sleep/spin that is not isr safe, * null means no updates */ - /* gamma TO BE REMOVED */ struct dc_gamma *gamma; enum color_transfer_func color_input_tf; - enum color_transfer_func color_output_tf; struct dc_transfer_func *in_transfer_func; struct csc_transform *input_csc_color_matrix; diff --git a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h index 273d80a4ebce..d9b84ec7954c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h @@ -111,6 +111,8 @@ struct dc_vbios_funcs { struct dc_bios *bios); bool (*is_accelerated_mode)( struct dc_bios *bios); + uint32_t (*get_vga_enabled_displays)( + struct dc_bios *bios); void (*get_bios_event_info)( struct dc_bios *bios, struct bios_event_info *info); @@ -199,6 +201,7 @@ struct dc_vbios_funcs { }; struct bios_registers { + uint32_t BIOS_SCRATCH_3; uint32_t BIOS_SCRATCH_6; }; diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index 03029f72dc3f..e91ac6811990 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -413,12 +413,14 @@ struct dc_cursor_mi_param { enum { GAMMA_RGB_256_ENTRIES = 256, GAMMA_RGB_FLOAT_1024_ENTRIES = 1024, - GAMMA_MAX_ENTRIES = 1024 + GAMMA_CS_TFM_1D_ENTRIES = 4096, + GAMMA_MAX_ENTRIES = 4096 }; enum dc_gamma_type { GAMMA_RGB_256 = 1, - GAMMA_RGB_FLOAT_1024 = 2 + GAMMA_RGB_FLOAT_1024 = 2, + GAMMA_CS_TFM_1D = 3, }; struct dc_gamma { @@ -434,6 +436,8 @@ struct dc_gamma { /* private to DC core */ struct dc_context *ctx; + + bool is_identity; }; /* Used by both ipp amd opp functions*/ diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index f11a734da1db..ac0f617b43c9 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -64,6 +64,8 @@ struct dc_link { enum signal_type connector_signal; enum dc_irq_source irq_source_hpd; enum dc_irq_source irq_source_hpd_rx;/* aka DP Short Pulse */ + bool is_hpd_filter_disabled; + /* caps is the same as reported_link_cap. link_traing use * reported_link_cap. Will clean up. TODO */ @@ -195,6 +197,8 @@ bool dc_link_dp_set_test_pattern( const unsigned char *p_custom_pattern, unsigned int cust_pattern_size); +void dc_link_disable_hpd_filter(struct dc_link *link); + /* * DPCD access interfaces */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 01c60f11b2bd..78a2bbe0b272 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -65,6 +65,7 @@ struct dc_stream_state { enum dc_dither_option dither_option; enum view_3d_format view_format; + enum color_transfer_func output_tf; bool ignore_msa_timing_param; /* TODO: custom INFO packets */ @@ -103,6 +104,7 @@ struct dc_stream_update { struct rect dst; struct dc_transfer_func *out_transfer_func; struct dc_hdr_static_metadata *hdr_static_metadata; + enum color_transfer_func color_output_tf; }; bool dc_is_stream_unchanged( @@ -152,7 +154,7 @@ struct dc_stream_state *dc_get_stream_at_index(struct dc *dc, uint8_t i); uint32_t dc_stream_get_vblank_counter(const struct dc_stream_state *stream); /* TODO: Return parsed values rather than direct register read - * This has a dependency on the caller (amdgpu_get_crtc_scanoutpos) + * This has a dependency on the caller (amdgpu_display_get_crtc_scanoutpos) * being refactored properly to be dce-specific */ bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream, @@ -237,6 +239,8 @@ enum surface_update_type dc_check_update_surfaces_for_stream( */ struct dc_stream_state *dc_create_stream_for_sink(struct dc_sink *dc_sink); +void update_stream_signal(struct dc_stream_state *stream); + void dc_stream_retain(struct dc_stream_state *dc_stream); void dc_stream_release(struct dc_stream_state *dc_stream); @@ -267,11 +271,25 @@ bool dc_stream_get_crtc_position(struct dc *dc, unsigned int *v_pos, unsigned int *nom_v_pos); +bool dc_stream_configure_crc(struct dc *dc, + struct dc_stream_state *stream, + bool enable, + bool continuous); + +bool dc_stream_get_crc(struct dc *dc, + struct dc_stream_state *stream, + uint32_t *r_cr, + uint32_t *g_y, + uint32_t *b_cb); + void dc_stream_set_static_screen_events(struct dc *dc, struct dc_stream_state **stream, int num_streams, const struct dc_static_screen_events *events); +void dc_stream_set_dither_option(struct dc_stream_state *stream, + enum dc_dither_option option); + bool dc_stream_adjust_vmin_vmax(struct dc *dc, struct dc_stream_state **stream, diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 9faddfae241d..8811b6f86bff 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -193,6 +193,10 @@ union display_content_support { } bits; }; +struct dc_panel_patch { + unsigned int dppowerup_delay; +}; + struct dc_edid_caps { /* sink identification */ uint16_t manufacturer_id; @@ -219,6 +223,8 @@ struct dc_edid_caps { bool edid_hdmi; bool hdr_supported; + + struct dc_panel_patch panel_patch; }; struct view { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c index b48190f54907..b231bd53613e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c @@ -323,6 +323,15 @@ static bool dce_abm_immediate_disable(struct abm *abm) /* notifyDMCUMsg */ REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); + abm->stored_backlight_registers.BL_PWM_CNTL = + REG_READ(BL_PWM_CNTL); + abm->stored_backlight_registers.BL_PWM_CNTL2 = + REG_READ(BL_PWM_CNTL2); + abm->stored_backlight_registers.BL_PWM_PERIOD_CNTL = + REG_READ(BL_PWM_PERIOD_CNTL); + + REG_GET(LVTMA_PWRSEQ_REF_DIV, BL_PWM_REF_DIV, + &abm->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV); return true; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c index 0df9ecb2710c..e366bfd7cf6f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c @@ -359,7 +359,10 @@ void dce_aud_az_enable(struct audio *audio) AUDIO_ENABLED); AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value); - value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL); + set_reg_field_value(value, 0, + AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, + CLOCK_GATING_DISABLE); + AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value); dm_logger_write(CTX->logger, LOG_HW_AUDIO, "\n\t========= AUDIO:dce_aud_az_enable: index: %u data: 0x%x\n", @@ -372,6 +375,10 @@ void dce_aud_az_disable(struct audio *audio) struct dce_audio *aud = DCE_AUD(audio); value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL); + set_reg_field_value(value, 1, + AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, + CLOCK_GATING_DISABLE); + AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value); set_reg_field_value(value, 0, AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, @@ -716,6 +723,11 @@ void dce_aud_az_configure( DESCRIPTION17); AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8, value); + value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL); + set_reg_field_value(value, 0, + AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, + CLOCK_GATING_DISABLE); + AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value); } /* @@ -897,6 +909,10 @@ void dce_aud_hw_init( REG_UPDATE_2(AZALIA_F0_CODEC_FUNCTION_PARAMETER_POWER_STATES, CLKSTOP, 1, EPSS, 1); + set_reg_field_value(value, 0, + AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, + CLOCK_GATING_DISABLE); + AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value); } static const struct audio_funcs funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c index 31280d252753..5036b674f68b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c @@ -908,19 +908,9 @@ static bool dce110_program_pix_clk( #if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (IS_FPGA_MAXIMUS_DC(clock_source->ctx->dce_environment)) { unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0; - unsigned dp_dto_ref_kHz = 600000; - /* DPREF clock from FPGA TODO: Does FPGA have this value? */ + unsigned dp_dto_ref_kHz = 700000; unsigned clock_kHz = pll_settings->actual_pix_clk; - /* For faster simulation, if mode pixe clock less than 290MHz, - * pixel clock can be hard coded to 290Mhz. For 4K mode, pixel clock - * is greater than 500Mhz, need real pixel clock - * clock_kHz = 290000; - */ - /* TODO: un-hardcode when we can set display clock properly*/ - /*clock_kHz = pix_clk_params->requested_pix_clk;*/ - clock_kHz = 290000; - /* Set DTO values: phase = target clock, modulo = reference clock */ REG_WRITE(PHASE[inst], clock_kHz); REG_WRITE(MODULO[inst], dp_dto_ref_kHz); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 9e98a5f39a6d..046658c8498a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -34,6 +34,7 @@ #include "dcn_calcs.h" #endif #include "core_types.h" +#include "dc_types.h" #define TO_DCE_CLOCKS(clocks)\ @@ -292,7 +293,10 @@ static enum dm_pp_clocks_state dce_get_required_clocks_state( low_req_clk = i + 1; if (low_req_clk > clk->max_clks_state) { dm_logger_write(clk->ctx->logger, LOG_WARNING, - "%s: clocks unsupported", __func__); + "%s: clocks unsupported disp_clk %d pix_clk %d", + __func__, + req_clocks->display_clk_khz, + req_clocks->pixel_clk_khz); low_req_clk = DM_PP_CLOCKS_STATE_INVALID; } @@ -415,9 +419,12 @@ static int dce112_set_clock( bp->funcs->set_dce_clock(bp, &dce_clk_params); - if (clk_dce->dfs_bypass_disp_clk != actual_clock) - dmcu->funcs->set_psr_wait_loop(dmcu, - actual_clock / 1000 / 7); + if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + if (clk_dce->dfs_bypass_disp_clk != actual_clock) + dmcu->funcs->set_psr_wait_loop(dmcu, + actual_clock / 1000 / 7); + } + clk_dce->dfs_bypass_disp_clk = actual_clock; return actual_clock; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c index f663adb33584..2ee3d9bf1062 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c @@ -360,7 +360,7 @@ static void dcn10_get_dmcu_version(struct dmcu *dmcu) dmcu->dmcu_version.year = ((REG_READ(DMCU_IRAM_RD_DATA) << 8) | REG_READ(DMCU_IRAM_RD_DATA)); dmcu->dmcu_version.month = REG_READ(DMCU_IRAM_RD_DATA); - dmcu->dmcu_version.day = REG_READ(DMCU_IRAM_RD_DATA); + dmcu->dmcu_version.date = REG_READ(DMCU_IRAM_RD_DATA); /* Disable write access to IRAM to allow dynamic sleep state */ REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL, @@ -521,6 +521,9 @@ static void dcn10_dmcu_set_psr_enable(struct dmcu *dmcu, bool enable, bool wait) if (dmcu->dmcu_state != DMCU_RUNNING) return; + dcn10_get_dmcu_psr_state(dmcu, &psr_state); + if (psr_state == 0 && !enable) + return; /* waitDMCUReadyForCmd */ REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, dmcu_wait_reg_ready_interval, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c index d2e66b1bc0ef..4b8e7ce2de8c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c @@ -197,9 +197,9 @@ void dce_crtc_switch_to_clk_src(struct dce_hwseq *hws, } /* Only use LUT for 8 bit formats */ -bool dce_use_lut(const struct dc_plane_state *plane_state) +bool dce_use_lut(enum surface_pixel_format format) { - switch (plane_state->format) { + switch (format) { case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: return true; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h index b73db9e78437..3336428b1fed 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -140,42 +140,8 @@ BL_REG_LIST() #define HWSEQ_DCN_REG_LIST()\ - SRII(DCHUBP_CNTL, HUBP, 0), \ - SRII(DCHUBP_CNTL, HUBP, 1), \ - SRII(DCHUBP_CNTL, HUBP, 2), \ - SRII(DCHUBP_CNTL, HUBP, 3), \ - SRII(HUBP_CLK_CNTL, HUBP, 0), \ - SRII(HUBP_CLK_CNTL, HUBP, 1), \ - SRII(HUBP_CLK_CNTL, HUBP, 2), \ - SRII(HUBP_CLK_CNTL, HUBP, 3), \ - SRII(DPP_CONTROL, DPP_TOP, 0), \ - SRII(DPP_CONTROL, DPP_TOP, 1), \ - SRII(DPP_CONTROL, DPP_TOP, 2), \ - SRII(DPP_CONTROL, DPP_TOP, 3), \ - SRII(OPP_PIPE_CONTROL, OPP_PIPE, 0), \ - SRII(OPP_PIPE_CONTROL, OPP_PIPE, 1), \ - SRII(OPP_PIPE_CONTROL, OPP_PIPE, 2), \ - SRII(OPP_PIPE_CONTROL, OPP_PIPE, 3), \ SR(REFCLK_CNTL), \ - SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A),\ - SR(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A),\ - SR(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A),\ - SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B),\ - SR(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B),\ - SR(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B),\ - SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C),\ - SR(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C),\ - SR(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C),\ - SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D),\ - SR(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D),\ - SR(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D),\ - SR(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL),\ - SR(DCHUBBUB_ARB_DRAM_STATE_CNTL),\ - SR(DCHUBBUB_ARB_SAT_LEVEL),\ - SR(DCHUBBUB_ARB_DF_REQ_OUTSTAND),\ SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ - SR(DCHUBBUB_TEST_DEBUG_INDEX), \ - SR(DCHUBBUB_TEST_DEBUG_DATA), \ SR(DIO_MEM_PWR_CTRL), \ SR(DCCG_GATE_DISABLE_CNTL), \ SR(DCCG_GATE_DISABLE_CNTL2), \ @@ -195,22 +161,10 @@ MMHUB_SR(MC_VM_SYSTEM_APERTURE_LOW_ADDR),\ MMHUB_SR(MC_VM_SYSTEM_APERTURE_HIGH_ADDR) -#define HWSEQ_SR_WATERMARK_REG_LIST()\ - SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A),\ - SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A),\ - SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B),\ - SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B),\ - SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C),\ - SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C),\ - SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D),\ - SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D) - #define HWSEQ_DCN1_REG_LIST()\ HWSEQ_DCN_REG_LIST(), \ - HWSEQ_SR_WATERMARK_REG_LIST(), \ HWSEQ_PIXEL_RATE_REG_LIST(OTG), \ HWSEQ_PHYPLL_REG_LIST(OTG), \ - SR(DCHUBBUB_SDPIF_FB_TOP),\ SR(DCHUBBUB_SDPIF_FB_BASE),\ SR(DCHUBBUB_SDPIF_FB_OFFSET),\ SR(DCHUBBUB_SDPIF_AGP_BASE),\ @@ -260,39 +214,9 @@ struct dce_hwseq_registers { uint32_t DCHUB_AGP_BOT; uint32_t DCHUB_AGP_TOP; - uint32_t DCHUBP_CNTL[4]; - uint32_t HUBP_CLK_CNTL[4]; - uint32_t DPP_CONTROL[4]; - uint32_t OPP_PIPE_CONTROL[4]; uint32_t REFCLK_CNTL; - uint32_t DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A; - uint32_t DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A; - uint32_t DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A; - uint32_t DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A; - uint32_t DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A; - uint32_t DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B; - uint32_t DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B; - uint32_t DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B; - uint32_t DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B; - uint32_t DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B; - uint32_t DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C; - uint32_t DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C; - uint32_t DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C; - uint32_t DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C; - uint32_t DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C; - uint32_t DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D; - uint32_t DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D; - uint32_t DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D; - uint32_t DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D; - uint32_t DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D; - uint32_t DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL; - uint32_t DCHUBBUB_ARB_SAT_LEVEL; - uint32_t DCHUBBUB_ARB_DF_REQ_OUTSTAND; + uint32_t DCHUBBUB_GLOBAL_TIMER_CNTL; - uint32_t DCHUBBUB_ARB_DRAM_STATE_CNTL; - uint32_t DCHUBBUB_TEST_DEBUG_INDEX; - uint32_t DCHUBBUB_TEST_DEBUG_DATA; - uint32_t DCHUBBUB_SDPIF_FB_TOP; uint32_t DCHUBBUB_SDPIF_FB_BASE; uint32_t DCHUBBUB_SDPIF_FB_OFFSET; uint32_t DCHUBBUB_SDPIF_AGP_BASE; @@ -433,31 +357,17 @@ struct dce_hwseq_registers { #define HWSEQ_DCN_MASK_SH_LIST(mask_sh)\ HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, OTG0_),\ HWS_SF1(OTG0_, PHYPLL_PIXEL_RATE_CNTL, PHYPLL_PIXEL_RATE_SOURCE, mask_sh), \ - HWS_SF(HUBP0_, DCHUBP_CNTL, HUBP_VTG_SEL, mask_sh), \ - HWS_SF(HUBP0_, HUBP_CLK_CNTL, HUBP_CLOCK_ENABLE, mask_sh), \ - HWS_SF(DPP_TOP0_, DPP_CONTROL, DPP_CLOCK_ENABLE, mask_sh), \ - HWS_SF(OPP_PIPE0_, OPP_PIPE_CONTROL, OPP_PIPE_CLOCK_EN, mask_sh),\ HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, mask_sh), \ - HWS_SF(, DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, mask_sh), \ - HWS_SF(, DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, DCHUBBUB_ARB_WATERMARK_CHANGE_DONE_INTERRUPT_DISABLE, mask_sh), \ - HWS_SF(, DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, mask_sh), \ - HWS_SF(, DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, mask_sh), \ - HWS_SF(, DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, mask_sh), \ - HWS_SF(, DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, mask_sh), \ - HWS_SF(, DCHUBBUB_ARB_SAT_LEVEL, DCHUBBUB_ARB_SAT_LEVEL, mask_sh), \ - HWS_SF(, DCHUBBUB_ARB_DF_REQ_OUTSTAND, DCHUBBUB_ARB_MIN_REQ_OUTSTAND, mask_sh), \ HWS_SF(, DCFCLK_CNTL, DCFCLK_GATE_DIS, mask_sh) #define HWSEQ_DCN1_MASK_SH_LIST(mask_sh)\ HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ HWS_SF1(OTG0_, PHYPLL_PIXEL_RATE_CNTL, PIXEL_RATE_PLL_SOURCE, mask_sh), \ - HWS_SF(, DCHUBBUB_SDPIF_FB_TOP, SDPIF_FB_TOP, mask_sh), \ HWS_SF(, DCHUBBUB_SDPIF_FB_BASE, SDPIF_FB_BASE, mask_sh), \ HWS_SF(, DCHUBBUB_SDPIF_FB_OFFSET, SDPIF_FB_OFFSET, mask_sh), \ HWS_SF(, DCHUBBUB_SDPIF_AGP_BASE, SDPIF_AGP_BASE, mask_sh), \ HWS_SF(, DCHUBBUB_SDPIF_AGP_BOT, SDPIF_AGP_BOT, mask_sh), \ HWS_SF(, DCHUBBUB_SDPIF_AGP_TOP, SDPIF_AGP_TOP, mask_sh), \ - HWS_SF(DPP_TOP0_, DPP_CONTROL, DPPCLK_RATE_CONTROL, mask_sh), \ /* todo: get these from GVM instead of reading registers ourselves */\ HWS_SF(, VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32, PAGE_DIRECTORY_ENTRY_HI32, mask_sh),\ HWS_SF(, VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32, PAGE_DIRECTORY_ENTRY_LO32, mask_sh),\ @@ -532,8 +442,6 @@ struct dce_hwseq_registers { type HUBP_VTG_SEL; \ type HUBP_CLOCK_ENABLE; \ type DPP_CLOCK_ENABLE; \ - type DPPCLK_RATE_CONTROL; \ - type SDPIF_FB_TOP;\ type SDPIF_FB_BASE;\ type SDPIF_FB_OFFSET;\ type SDPIF_AGP_BASE;\ @@ -546,14 +454,6 @@ struct dce_hwseq_registers { type AGP_BOT;\ type AGP_TOP;\ type DCHUBBUB_GLOBAL_TIMER_ENABLE; \ - type DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST;\ - type DCHUBBUB_ARB_WATERMARK_CHANGE_DONE_INTERRUPT_DISABLE;\ - type DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE;\ - type DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE;\ - type DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE;\ - type DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE;\ - type DCHUBBUB_ARB_SAT_LEVEL;\ - type DCHUBBUB_ARB_MIN_REQ_OUTSTAND;\ type OPP_PIPE_CLOCK_EN;\ type IP_REQUEST_EN; \ type DOMAIN0_POWER_FORCEON; \ @@ -619,5 +519,5 @@ void dce_crtc_switch_to_clk_src(struct dce_hwseq *hws, struct clock_source *clk_src, unsigned int tg_inst); -bool dce_use_lut(const struct dc_plane_state *plane_state); +bool dce_use_lut(enum surface_pixel_format format); #endif /*__DCE_HWSEQ_H__*/ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c index a266e3f5e75f..11f50588b3f4 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c @@ -82,13 +82,6 @@ #define DCE110_DIG_FE_SOURCE_SELECT_DIGF 0x20 #define DCE110_DIG_FE_SOURCE_SELECT_DIGG 0x40 -/* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */ -#define TMDS_MIN_PIXEL_CLOCK 25000 -/* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */ -#define TMDS_MAX_PIXEL_CLOCK 165000 -/* For current ASICs pixel clock - 600MHz */ -#define MAX_ENCODER_CLOCK 600000 - enum { DP_MST_UPDATE_MAX_RETRY = 50 }; @@ -828,6 +821,9 @@ void dce110_link_encoder_hw_init( cntl.coherent = false; cntl.hpd_sel = enc110->base.hpd_source; + if (enc110->base.connector.id == CONNECTOR_ID_EDP) + cntl.signal = SIGNAL_TYPE_EDP; + result = link_transmitter_control(enc110, &cntl); if (result != BP_RESULT_OK) { @@ -904,8 +900,7 @@ void dce110_link_encoder_enable_tmds_output( struct link_encoder *enc, enum clock_source_id clock_source, enum dc_color_depth color_depth, - bool hdmi, - bool dual_link, + enum signal_type signal, uint32_t pixel_clock) { struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); @@ -919,16 +914,12 @@ void dce110_link_encoder_enable_tmds_output( cntl.engine_id = enc->preferred_engine; cntl.transmitter = enc110->base.transmitter; cntl.pll_id = clock_source; - if (hdmi) { - cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A; - cntl.lanes_number = 4; - } else if (dual_link) { - cntl.signal = SIGNAL_TYPE_DVI_DUAL_LINK; + cntl.signal = signal; + if (cntl.signal == SIGNAL_TYPE_DVI_DUAL_LINK) cntl.lanes_number = 8; - } else { - cntl.signal = SIGNAL_TYPE_DVI_SINGLE_LINK; + else cntl.lanes_number = 4; - } + cntl.hpd_sel = enc110->base.hpd_source; cntl.pixel_clock = pixel_clock; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h index 8ca9afe47a2b..0ec3433d34b6 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h @@ -210,8 +210,7 @@ void dce110_link_encoder_enable_tmds_output( struct link_encoder *enc, enum clock_source_id clock_source, enum dc_color_depth color_depth, - bool hdmi, - bool dual_link, + enum signal_type signal, uint32_t pixel_clock); /* enables DP PHY output */ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c index 83bae207371d..8146b9079d51 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c @@ -920,6 +920,7 @@ static void dce110_stream_encoder_dp_blank( { struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); uint32_t retries = 0; + uint32_t reg1 = 0; uint32_t max_retries = DP_BLANK_MAX_RETRY * 10; /* Note: For CZ, we are changing driver default to disable @@ -928,7 +929,10 @@ static void dce110_stream_encoder_dp_blank( * handful of panels that cannot handle disable stream at * HBLANK and will result in a white line flash across the * screen on stream disable. */ - + REG_GET(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, ®1); + if ((reg1 & 0x1) == 0) + /*stream not enabled*/ + return; /* Specify the video stream disable point * (2 = start of the next vertical blank) */ REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_DIS_DEFER, 2); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c index 0f662e6ee9bd..ad411dac5639 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c @@ -618,80 +618,48 @@ static void program_bit_depth_reduction( enum dc_color_depth depth, const struct bit_depth_reduction_params *bit_depth_params) { - enum dcp_bit_depth_reduction_mode depth_reduction_mode; - enum dcp_spatial_dither_mode spatial_dither_mode; - bool frame_random_enable; - bool rgb_random_enable; - bool highpass_random_enable; + enum dcp_out_trunc_round_depth trunc_round_depth; + enum dcp_out_trunc_round_mode trunc_mode; + bool spatial_dither_enable; ASSERT(depth < COLOR_DEPTH_121212); /* Invalid clamp bit depth */ - if (bit_depth_params->flags.SPATIAL_DITHER_ENABLED) { - depth_reduction_mode = DCP_BIT_DEPTH_REDUCTION_MODE_DITHER; - frame_random_enable = true; - rgb_random_enable = true; - highpass_random_enable = true; + spatial_dither_enable = bit_depth_params->flags.SPATIAL_DITHER_ENABLED; + /* Default to 12 bit truncation without rounding */ + trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_12BIT; + trunc_mode = DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE; - } else { - depth_reduction_mode = DCP_BIT_DEPTH_REDUCTION_MODE_DISABLED; - frame_random_enable = false; - rgb_random_enable = false; - highpass_random_enable = false; + if (bit_depth_params->flags.TRUNCATE_ENABLED) { + /* Don't enable dithering if truncation is enabled */ + spatial_dither_enable = false; + trunc_mode = bit_depth_params->flags.TRUNCATE_MODE ? + DCP_OUT_TRUNC_ROUND_MODE_ROUND : + DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE; + + if (bit_depth_params->flags.TRUNCATE_DEPTH == 0 || + bit_depth_params->flags.TRUNCATE_DEPTH == 1) + trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_8BIT; + else if (bit_depth_params->flags.TRUNCATE_DEPTH == 2) + trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_10BIT; + else { + /* + * Invalid truncate/round depth. Setting here to 12bit + * to prevent use-before-initialize errors. + */ + trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_12BIT; + BREAK_TO_DEBUGGER(); + } } - spatial_dither_mode = DCP_SPATIAL_DITHER_MODE_A_AA_A; - set_clamp(xfm_dce, depth); - - switch (depth_reduction_mode) { - case DCP_BIT_DEPTH_REDUCTION_MODE_DITHER: - /* Spatial Dither: Set round/truncate to bypass (12bit), - * enable Dither (30bpp) */ - set_round(xfm_dce, - DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE, - DCP_OUT_TRUNC_ROUND_DEPTH_12BIT); - - set_dither(xfm_dce, true, spatial_dither_mode, - DCP_SPATIAL_DITHER_DEPTH_30BPP, frame_random_enable, - rgb_random_enable, highpass_random_enable); - break; - case DCP_BIT_DEPTH_REDUCTION_MODE_ROUND: - /* Round: Enable round (10bit), disable Dither */ - set_round(xfm_dce, - DCP_OUT_TRUNC_ROUND_MODE_ROUND, - DCP_OUT_TRUNC_ROUND_DEPTH_10BIT); - - set_dither(xfm_dce, false, spatial_dither_mode, - DCP_SPATIAL_DITHER_DEPTH_30BPP, frame_random_enable, - rgb_random_enable, highpass_random_enable); - break; - case DCP_BIT_DEPTH_REDUCTION_MODE_TRUNCATE: /* Truncate */ - /* Truncate: Enable truncate (10bit), disable Dither */ - set_round(xfm_dce, - DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE, - DCP_OUT_TRUNC_ROUND_DEPTH_10BIT); - - set_dither(xfm_dce, false, spatial_dither_mode, - DCP_SPATIAL_DITHER_DEPTH_30BPP, frame_random_enable, - rgb_random_enable, highpass_random_enable); - break; - - case DCP_BIT_DEPTH_REDUCTION_MODE_DISABLED: /* Disabled */ - /* Truncate: Set round/truncate to bypass (12bit), - * disable Dither */ - set_round(xfm_dce, - DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE, - DCP_OUT_TRUNC_ROUND_DEPTH_12BIT); - - set_dither(xfm_dce, false, spatial_dither_mode, - DCP_SPATIAL_DITHER_DEPTH_30BPP, frame_random_enable, - rgb_random_enable, highpass_random_enable); - break; - default: - /* Invalid DCP Depth reduction mode */ - BREAK_TO_DEBUGGER(); - break; - } + set_round(xfm_dce, trunc_mode, trunc_round_depth); + set_dither(xfm_dce, + spatial_dither_enable, + DCP_SPATIAL_DITHER_MODE_A_AA_A, + DCP_SPATIAL_DITHER_DEPTH_30BPP, + bit_depth_params->flags.FRAME_RANDOM, + bit_depth_params->flags.RGB_RANDOM, + bit_depth_params->flags.HIGHPASS_RANDOM); } static int dce_transform_get_max_num_of_supported_lines( @@ -879,6 +847,7 @@ static void dce_transform_set_gamut_remap( const struct xfm_grph_csc_adjustment *adjust) { struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); + int i = 0; if (adjust->gamut_adjust_type != GRAPHICS_GAMUT_ADJUST_TYPE_SW) /* Bypass if type is bypass or hw */ @@ -887,20 +856,8 @@ static void dce_transform_set_gamut_remap( struct fixed31_32 arr_matrix[GAMUT_MATRIX_SIZE]; uint16_t arr_reg_val[GAMUT_MATRIX_SIZE]; - arr_matrix[0] = adjust->temperature_matrix[0]; - arr_matrix[1] = adjust->temperature_matrix[1]; - arr_matrix[2] = adjust->temperature_matrix[2]; - arr_matrix[3] = dal_fixed31_32_zero; - - arr_matrix[4] = adjust->temperature_matrix[3]; - arr_matrix[5] = adjust->temperature_matrix[4]; - arr_matrix[6] = adjust->temperature_matrix[5]; - arr_matrix[7] = dal_fixed31_32_zero; - - arr_matrix[8] = adjust->temperature_matrix[6]; - arr_matrix[9] = adjust->temperature_matrix[7]; - arr_matrix[10] = adjust->temperature_matrix[8]; - arr_matrix[11] = dal_fixed31_32_zero; + for (i = 0; i < GAMUT_MATRIX_SIZE; i++) + arr_matrix[i] = adjust->temperature_matrix[i]; convert_float_matrix( arr_reg_val, arr_matrix, GAMUT_MATRIX_SIZE); @@ -1126,7 +1083,7 @@ void dce110_opp_set_csc_adjustment( CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC; program_color_matrix( - xfm_dce, tbl_entry, GRAPHICS_CSC_ADJUST_TYPE_SW); + xfm_dce, tbl_entry, GRPH_COLOR_MATRIX_SW); /* We did everything ,now program DxOUTPUT_CSC_CONTROL */ configure_graphics_mode(xfm_dce, config, GRAPHICS_CSC_ADJUST_TYPE_SW, diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c index 469af0587604..41f83ecd7469 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c @@ -69,7 +69,7 @@ static const struct dce100_hw_seq_reg_offsets reg_offsets[] = { ******************************************************************************/ /***************************PIPE_CONTROL***********************************/ -static bool dce100_enable_display_power_gating( +bool dce100_enable_display_power_gating( struct dc *dc, uint8_t controller_id, struct dc_bios *dcb, diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h index cb5384ef46c3..c6ec0ed6ec3d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h @@ -38,5 +38,9 @@ void dce100_set_bandwidth( struct dc_state *context, bool decrease_allowed); +bool dce100_enable_display_power_gating(struct dc *dc, uint8_t controller_id, + struct dc_bios *dcb, + enum pipe_gating_control power_gating); + #endif /* __DC_HWSS_DCE100_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index 3ea43e2a9450..3bdbed80f7f8 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -849,9 +849,11 @@ static bool construct( *************************************************/ pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; pool->base.pipe_count = res_cap.num_timing_generator; + pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator; dc->caps.max_downscale_ratio = 200; dc->caps.i2c_speed_in_khz = 40; dc->caps.max_cursor_size = 128; + dc->caps.dual_link_dvi = true; for (i = 0; i < pool->base.pipe_count; i++) { pool->base.timing_generators[i] = diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 86cdd7b4811f..0422c72a7579 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -57,6 +57,8 @@ #include "dce/dce_11_0_sh_mask.h" #include "custom_float.h" +#include "atomfirmware.h" + /* * All values are in milliseconds; * For eDP, after power-up/power/down, @@ -275,7 +277,7 @@ dce110_set_input_transfer_func(struct pipe_ctx *pipe_ctx, build_prescale_params(&prescale_params, plane_state); ipp->funcs->ipp_program_prescale(ipp, &prescale_params); - if (plane_state->gamma_correction && dce_use_lut(plane_state)) + if (plane_state->gamma_correction && dce_use_lut(plane_state->format)) ipp->funcs->ipp_program_input_lut(ipp, plane_state->gamma_correction); if (tf == NULL) { @@ -407,6 +409,10 @@ static bool convert_to_custom_float(struct pwl_result_data *rgb_resulted, return true; } +#define MAX_LOW_POINT 25 +#define NUMBER_REGIONS 16 +#define NUMBER_SW_SEGMENTS 16 + static bool dce110_translate_regamma_to_hw_format(const struct dc_transfer_func *output_tf, struct pwl_params *regamma_params) @@ -421,8 +427,8 @@ dce110_translate_regamma_to_hw_format(const struct dc_transfer_func *output_tf, struct fixed31_32 y1_min; struct fixed31_32 y3_max; - int32_t segment_start, segment_end; - uint32_t i, j, k, seg_distr[16], increment, start_index, hw_points; + int32_t region_start, region_end; + uint32_t i, j, k, seg_distr[NUMBER_REGIONS], increment, start_index, hw_points; if (output_tf == NULL || regamma_params == NULL || output_tf->type == TF_TYPE_BYPASS) return false; @@ -437,34 +443,20 @@ dce110_translate_regamma_to_hw_format(const struct dc_transfer_func *output_tf, /* 16 segments * segments are from 2^-11 to 2^5 */ - segment_start = -11; - segment_end = 5; + region_start = -11; + region_end = region_start + NUMBER_REGIONS; - seg_distr[0] = 2; - seg_distr[1] = 2; - seg_distr[2] = 2; - seg_distr[3] = 2; - seg_distr[4] = 2; - seg_distr[5] = 2; - seg_distr[6] = 3; - seg_distr[7] = 4; - seg_distr[8] = 4; - seg_distr[9] = 4; - seg_distr[10] = 4; - seg_distr[11] = 5; - seg_distr[12] = 5; - seg_distr[13] = 5; - seg_distr[14] = 5; - seg_distr[15] = 5; + for (i = 0; i < NUMBER_REGIONS; i++) + seg_distr[i] = 4; } else { /* 10 segments * segment is from 2^-10 to 2^0 */ - segment_start = -10; - segment_end = 0; + region_start = -10; + region_end = 0; - seg_distr[0] = 3; + seg_distr[0] = 4; seg_distr[1] = 4; seg_distr[2] = 4; seg_distr[3] = 4; @@ -472,8 +464,8 @@ dce110_translate_regamma_to_hw_format(const struct dc_transfer_func *output_tf, seg_distr[5] = 4; seg_distr[6] = 4; seg_distr[7] = 4; - seg_distr[8] = 5; - seg_distr[9] = 5; + seg_distr[8] = 4; + seg_distr[9] = 4; seg_distr[10] = -1; seg_distr[11] = -1; seg_distr[12] = -1; @@ -488,10 +480,12 @@ dce110_translate_regamma_to_hw_format(const struct dc_transfer_func *output_tf, } j = 0; - for (k = 0; k < (segment_end - segment_start); k++) { - increment = 32 / (1 << seg_distr[k]); - start_index = (segment_start + k + 25) * 32; - for (i = start_index; i < start_index + 32; i += increment) { + for (k = 0; k < (region_end - region_start); k++) { + increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]); + start_index = (region_start + k + MAX_LOW_POINT) * + NUMBER_SW_SEGMENTS; + for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS; + i += increment) { if (j == hw_points - 1) break; rgb_resulted[j].red = output_tf->tf_pts.red[i]; @@ -502,15 +496,15 @@ dce110_translate_regamma_to_hw_format(const struct dc_transfer_func *output_tf, } /* last point */ - start_index = (segment_end + 25) * 32; + start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS; rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index]; rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index]; rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index]; arr_points[0].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), - dal_fixed31_32_from_int(segment_start)); + dal_fixed31_32_from_int(region_start)); arr_points[1].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), - dal_fixed31_32_from_int(segment_end)); + dal_fixed31_32_from_int(region_end)); y_r = rgb_resulted[0].red; y_g = rgb_resulted[0].green; @@ -625,7 +619,7 @@ static enum dc_status bios_parser_crtc_source_select( const struct dc_sink *sink = pipe_ctx->stream->sink; crtc_source_select.engine_id = pipe_ctx->stream_res.stream_enc->id; - crtc_source_select.controller_id = pipe_ctx->pipe_idx + 1; + crtc_source_select.controller_id = pipe_ctx->stream_res.tg->inst + 1; /*TODO: Need to un-hardcode color depth, dp_audio and account for * the case where signal and sink signal is different (translator * encoder)*/ @@ -914,6 +908,7 @@ void hwss_edp_backlight_control( /*todo: unhardcode*/ cntl.lanes_number = LANE_COUNT_FOUR; cntl.hpd_sel = link->link_enc->hpd_source; + cntl.signal = SIGNAL_TYPE_EDP; /* For eDP, the following delays might need to be considered * after link training completed: @@ -926,7 +921,13 @@ void hwss_edp_backlight_control( * Enable it in the future if necessary. */ /* dc_service_sleep_in_milliseconds(50); */ + /*edp 1.2*/ + if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) + edp_receiver_ready_T7(link); link_transmitter_control(ctx->dc_bios, &cntl); + /*edp 1.2*/ + if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF) + edp_receiver_ready_T9(link); } void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option) @@ -946,7 +947,11 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option) pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control( pipe_ctx->stream_res.stream_enc, true); if (pipe_ctx->stream_res.audio) { - pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); + if (option != KEEP_ACQUIRED_RESOURCE || + !dc->debug.az_endpoint_mute_only) { + /*only disalbe az_endpoint if power down or free*/ + pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); + } if (dc_is_dp_signal(pipe_ctx->stream->signal)) pipe_ctx->stream_res.stream_enc->funcs->dp_audio_disable( @@ -969,9 +974,6 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option) */ } - /* blank at encoder level */ - if (dc_is_dp_signal(pipe_ctx->stream->signal)) - pipe_ctx->stream_res.stream_enc->funcs->dp_blank(pipe_ctx->stream_res.stream_enc); link->link_enc->funcs->connect_dig_be_to_fe( link->link_enc, @@ -984,12 +986,30 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, struct dc_link_settings *link_settings) { struct encoder_unblank_param params = { { 0 } }; + struct dc_stream_state *stream = pipe_ctx->stream; + struct dc_link *link = stream->sink->link; /* only 3 items below are used by unblank */ params.pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz; params.link_settings.link_rate = link_settings->link_rate; - pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, ¶ms); + + if (dc_is_dp_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, ¶ms); + + if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) + link->dc->hwss.edp_backlight_control(link, true); +} +void dce110_blank_stream(struct pipe_ctx *pipe_ctx) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + struct dc_link *link = stream->sink->link; + + if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) + link->dc->hwss.edp_backlight_control(link, false); + + if (dc_is_dp_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream_res.stream_enc->funcs->dp_blank(pipe_ctx->stream_res.stream_enc); } @@ -1091,7 +1111,7 @@ static void build_audio_output( audio_output->pll_info.dto_source = translate_to_dto_source( - pipe_ctx->pipe_idx + 1); + pipe_ctx->stream_res.tg->inst + 1); /* TODO hard code to enable for now. Need get from stream */ audio_output->pll_info.ss_enabled = true; @@ -1407,6 +1427,31 @@ static void disable_vga_and_power_gate_all_controllers( } } +static struct dc_link *get_link_for_edp_not_in_use( + struct dc *dc, + struct dc_state *context) +{ + int i; + struct dc_link *link = NULL; + + /* check if eDP panel is suppose to be set mode, if yes, no need to disable */ + for (i = 0; i < context->stream_count; i++) { + if (context->streams[i]->signal == SIGNAL_TYPE_EDP) + return NULL; + } + + /* check if there is an eDP panel not in use */ + for (i = 0; i < dc->link_count; i++) { + if (dc->links[i]->local_sink && + dc->links[i]->local_sink->sink_signal == SIGNAL_TYPE_EDP) { + link = dc->links[i]; + break; + } + } + + return link; +} + /** * When ASIC goes from VBIOS/VGA mode to driver/accelerated mode we need: * 1. Power down all DC HW blocks @@ -1414,11 +1459,37 @@ static void disable_vga_and_power_gate_all_controllers( * 3. Enable power gating for controller * 4. Set acc_mode_change bit (VBIOS will clear this bit when going to FSDOS) */ -void dce110_enable_accelerated_mode(struct dc *dc) +void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context) { - power_down_all_hw_blocks(dc); + struct dc_bios *dcb = dc->ctx->dc_bios; - disable_vga_and_power_gate_all_controllers(dc); + /* vbios already light up eDP, so we can leverage vbios and skip eDP + * programming + */ + bool can_eDP_fast_boot_optimize = + (dcb->funcs->get_vga_enabled_displays(dc->ctx->dc_bios) == ATOM_DISPLAY_LCD1_ACTIVE); + + /* if OS doesn't light up eDP and eDP link is available, we want to disable */ + struct dc_link *edp_link_to_turnoff = NULL; + + if (can_eDP_fast_boot_optimize) { + edp_link_to_turnoff = get_link_for_edp_not_in_use(dc, context); + + if (!edp_link_to_turnoff) + dc->apply_edp_fast_boot_optimization = true; + } + + if (!dc->apply_edp_fast_boot_optimization) { + if (edp_link_to_turnoff) { + /*turn off backlight before DP_blank and encoder powered down*/ + dc->hwss.edp_backlight_control(edp_link_to_turnoff, false); + } + /*resume from S3, no vbios posting, no need to power down again*/ + power_down_all_hw_blocks(dc); + disable_vga_and_power_gate_all_controllers(dc); + if (edp_link_to_turnoff) + dc->hwss.edp_power_control(edp_link_to_turnoff, false); + } bios_set_scratch_acc_mode_change(dc->ctx->dc_bios); } @@ -1439,7 +1510,7 @@ static uint32_t compute_pstate_blackout_duration( return total_dest_line_time_ns; } -void dce110_set_displaymarks( +static void dce110_set_displaymarks( const struct dc *dc, struct dc_state *context) { @@ -1553,6 +1624,8 @@ static void set_static_screen_control(struct pipe_ctx **pipe_ctx, value |= 0x80; if (events->cursor_update) value |= 0x2; + if (events->force_trigger) + value |= 0x1; #if defined(CONFIG_DRM_AMD_DC_FBC) value |= 0x84; @@ -1690,9 +1763,13 @@ static void apply_min_clocks( * Check if FBC can be enabled */ static bool should_enable_fbc(struct dc *dc, - struct dc_state *context) + struct dc_state *context, + uint32_t *pipe_idx) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[0]; + uint32_t i; + struct pipe_ctx *pipe_ctx = NULL; + struct resource_context *res_ctx = &context->res_ctx; + ASSERT(dc->fbc_compressor); @@ -1704,6 +1781,14 @@ static bool should_enable_fbc(struct dc *dc, if (context->stream_count != 1) return false; + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (res_ctx->pipe_ctx[i].stream) { + pipe_ctx = &res_ctx->pipe_ctx[i]; + *pipe_idx = i; + break; + } + } + /* Only supports eDP */ if (pipe_ctx->stream->sink->link->connector_signal != SIGNAL_TYPE_EDP) return false; @@ -1729,11 +1814,14 @@ static bool should_enable_fbc(struct dc *dc, static void enable_fbc(struct dc *dc, struct dc_state *context) { - if (should_enable_fbc(dc, context)) { + uint32_t pipe_idx = 0; + + if (should_enable_fbc(dc, context, &pipe_idx)) { /* Program GRPH COMPRESSED ADDRESS and PITCH */ struct compr_addr_and_pitch_params params = {0, 0, 0}; struct compressor *compr = dc->fbc_compressor; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[0]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx]; + params.source_view_width = pipe_ctx->stream->timing.h_addressable; params.source_view_height = pipe_ctx->stream->timing.v_addressable; @@ -1748,36 +1836,6 @@ static void enable_fbc(struct dc *dc, } #endif -static enum dc_status apply_ctx_to_hw_fpga( - struct dc *dc, - struct dc_state *context) -{ - enum dc_status status = DC_ERROR_UNEXPECTED; - int i; - - for (i = 0; i < MAX_PIPES; i++) { - struct pipe_ctx *pipe_ctx_old = - &dc->current_state->res_ctx.pipe_ctx[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (pipe_ctx->stream == NULL) - continue; - - if (pipe_ctx->stream == pipe_ctx_old->stream) - continue; - - status = apply_single_controller_ctx_to_hw( - pipe_ctx, - context, - dc); - - if (status != DC_OK) - return status; - } - - return DC_OK; -} - static void dce110_reset_hw_ctx_wrap( struct dc *dc, struct dc_state *context) @@ -1847,11 +1905,6 @@ enum dc_status dce110_apply_ctx_to_hw( if (context->stream_count <= 0) return DC_OK; - if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { - apply_ctx_to_hw_fpga(dc, context); - return DC_OK; - } - /* Apply new context */ dcb->funcs->set_scratch_critical_state(dcb, true); @@ -2134,13 +2187,14 @@ static void program_surface_visibility(const struct dc *dc, } else if (!pipe_ctx->plane_state->visible) blank_target = true; - dce_set_blender_mode(dc->hwseq, pipe_ctx->pipe_idx, blender_mode); + dce_set_blender_mode(dc->hwseq, pipe_ctx->stream_res.tg->inst, blender_mode); pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, blank_target); } static void program_gamut_remap(struct pipe_ctx *pipe_ctx) { + int i = 0; struct xfm_grph_csc_adjustment adjust; memset(&adjust, 0, sizeof(adjust)); adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; @@ -2148,33 +2202,10 @@ static void program_gamut_remap(struct pipe_ctx *pipe_ctx) if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; - adjust.temperature_matrix[0] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[0]; - adjust.temperature_matrix[1] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[1]; - adjust.temperature_matrix[2] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[2]; - adjust.temperature_matrix[3] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[4]; - adjust.temperature_matrix[4] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[5]; - adjust.temperature_matrix[5] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[6]; - adjust.temperature_matrix[6] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[8]; - adjust.temperature_matrix[7] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[9]; - adjust.temperature_matrix[8] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[10]; + + for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) + adjust.temperature_matrix[i] = + pipe_ctx->stream->gamut_remap_matrix.matrix[i]; } pipe_ctx->plane_res.xfm->funcs->transform_set_gamut_remap(pipe_ctx->plane_res.xfm, &adjust); @@ -2198,7 +2229,7 @@ static void set_plane_config( memset(&tbl_entry, 0, sizeof(tbl_entry)); adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; - dce_enable_fe_clock(dc->hwseq, pipe_ctx->pipe_idx, true); + dce_enable_fe_clock(dc->hwseq, mi->inst, true); set_default_colors(pipe_ctx); if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { @@ -2215,33 +2246,10 @@ static void set_plane_config( if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; - adjust.temperature_matrix[0] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[0]; - adjust.temperature_matrix[1] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[1]; - adjust.temperature_matrix[2] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[2]; - adjust.temperature_matrix[3] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[4]; - adjust.temperature_matrix[4] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[5]; - adjust.temperature_matrix[5] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[6]; - adjust.temperature_matrix[6] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[8]; - adjust.temperature_matrix[7] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[9]; - adjust.temperature_matrix[8] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[10]; + + for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) + adjust.temperature_matrix[i] = + pipe_ctx->stream->gamut_remap_matrix.matrix[i]; } pipe_ctx->plane_res.xfm->funcs->transform_set_gamut_remap(pipe_ctx->plane_res.xfm, &adjust); @@ -2286,7 +2294,7 @@ static void update_plane_addr(const struct dc *dc, plane_state->status.requested_address = plane_state->address; } -void dce110_update_pending_status(struct pipe_ctx *pipe_ctx) +static void dce110_update_pending_status(struct pipe_ctx *pipe_ctx) { struct dc_plane_state *plane_state = pipe_ctx->plane_state; @@ -2527,7 +2535,7 @@ void dce110_fill_display_configs( num_cfgs++; cfg->signal = pipe_ctx->stream->signal; - cfg->pipe_idx = pipe_ctx->pipe_idx; + cfg->pipe_idx = pipe_ctx->stream_res.tg->inst; cfg->src_height = stream->src.height; cfg->src_width = stream->src.width; cfg->ddi_channel_mapping = @@ -2680,7 +2688,6 @@ static void dce110_program_front_end_for_pipe( struct dc_plane_state *plane_state = pipe_ctx->plane_state; struct xfm_grph_csc_adjustment adjust; struct out_csc_color_matrix tbl_entry; - struct pipe_ctx *cur_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx]; unsigned int i; memset(&tbl_entry, 0, sizeof(tbl_entry)); @@ -2691,7 +2698,7 @@ static void dce110_program_front_end_for_pipe( memset(&adjust, 0, sizeof(adjust)); adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; - dce_enable_fe_clock(dc->hwseq, pipe_ctx->pipe_idx, true); + dce_enable_fe_clock(dc->hwseq, mi->inst, true); set_default_colors(pipe_ctx); if (pipe_ctx->stream->csc_color_matrix.enable_adjustment @@ -2709,33 +2716,10 @@ static void dce110_program_front_end_for_pipe( if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; - adjust.temperature_matrix[0] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[0]; - adjust.temperature_matrix[1] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[1]; - adjust.temperature_matrix[2] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[2]; - adjust.temperature_matrix[3] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[4]; - adjust.temperature_matrix[4] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[5]; - adjust.temperature_matrix[5] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[6]; - adjust.temperature_matrix[6] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[8]; - adjust.temperature_matrix[7] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[9]; - adjust.temperature_matrix[8] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[10]; + + for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) + adjust.temperature_matrix[i] = + pipe_ctx->stream->gamut_remap_matrix.matrix[i]; } pipe_ctx->plane_res.xfm->funcs->transform_set_gamut_remap(pipe_ctx->plane_res.xfm, &adjust); @@ -2772,10 +2756,13 @@ static void dce110_program_front_end_for_pipe( plane_state->rotation); /* Moved programming gamma from dc to hwss */ - if (cur_pipe_ctx->plane_state != pipe_ctx->plane_state) { + if (pipe_ctx->plane_state->update_flags.bits.full_update || + pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || + pipe_ctx->plane_state->update_flags.bits.gamma_change) dc->hwss.set_input_transfer_func(pipe_ctx, pipe_ctx->plane_state); + + if (pipe_ctx->plane_state->update_flags.bits.full_update) dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); - } dm_logger_write(dc->ctx->logger, LOG_SURFACE, "Pipe:%d 0x%x: addr hi:0x%x, " @@ -2872,7 +2859,8 @@ static void dce110_apply_ctx_for_surface( static void dce110_power_down_fe(struct dc *dc, struct pipe_ctx *pipe_ctx) { - int fe_idx = pipe_ctx->pipe_idx; + int fe_idx = pipe_ctx->plane_res.mi ? + pipe_ctx->plane_res.mi->inst : pipe_ctx->pipe_idx; /* Do not power down fe when stream is active on dce*/ if (dc->current_state->res_ctx.pipe_ctx[fe_idx].stream) @@ -2915,6 +2903,49 @@ static void program_csc_matrix(struct pipe_ctx *pipe_ctx, } } +void dce110_set_cursor_position(struct pipe_ctx *pipe_ctx) +{ + struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; + struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; + struct mem_input *mi = pipe_ctx->plane_res.mi; + struct dc_cursor_mi_param param = { + .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz, + .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz, + .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, + .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, + .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz + }; + + if (pipe_ctx->plane_state->address.type + == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) + pos_cpy.enable = false; + + if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) + pos_cpy.enable = false; + + if (ipp->funcs->ipp_cursor_set_position) + ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, ¶m); + if (mi->funcs->set_cursor_position) + mi->funcs->set_cursor_position(mi, &pos_cpy, ¶m); +} + +void dce110_set_cursor_attribute(struct pipe_ctx *pipe_ctx) +{ + struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; + + if (pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes) + pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes( + pipe_ctx->plane_res.ipp, attributes); + + if (pipe_ctx->plane_res.mi->funcs->set_cursor_attributes) + pipe_ctx->plane_res.mi->funcs->set_cursor_attributes( + pipe_ctx->plane_res.mi, attributes); + + if (pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes) + pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes( + pipe_ctx->plane_res.xfm, attributes); +} + static void ready_shared_resources(struct dc *dc, struct dc_state *context) {} static void optimize_shared_resources(struct dc *dc) {} @@ -2938,6 +2969,7 @@ static const struct hw_sequencer_funcs dce110_funcs = { .enable_stream = dce110_enable_stream, .disable_stream = dce110_disable_stream, .unblank_stream = dce110_unblank_stream, + .blank_stream = dce110_blank_stream, .enable_display_pipe_clock_gating = enable_display_pipe_clock_gating, .enable_display_power_gating = dce110_enable_display_power_gating, .disable_plane = dce110_power_down_fe, @@ -2957,6 +2989,8 @@ static const struct hw_sequencer_funcs dce110_funcs = { .edp_backlight_control = hwss_edp_backlight_control, .edp_power_control = hwss_edp_power_control, .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, + .set_cursor_position = dce110_set_cursor_position, + .set_cursor_attribute = dce110_set_cursor_attribute }; void dce110_hw_sequencer_construct(struct dc *dc) diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h index fc637647f643..5d7e9f516827 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h @@ -39,11 +39,7 @@ enum dc_status dce110_apply_ctx_to_hw( struct dc *dc, struct dc_state *context); -void dce110_set_display_clock(struct dc_state *context); -void dce110_set_displaymarks( - const struct dc *dc, - struct dc_state *context); void dce110_enable_stream(struct pipe_ctx *pipe_ctx); @@ -52,15 +48,14 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option); void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, struct dc_link_settings *link_settings); +void dce110_blank_stream(struct pipe_ctx *pipe_ctx); void dce110_update_info_frame(struct pipe_ctx *pipe_ctx); void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable); -void dce110_enable_accelerated_mode(struct dc *dc); +void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context); void dce110_power_down(struct dc *dc); -void dce110_update_pending_status(struct pipe_ctx *pipe_ctx); - void dce110_fill_display_configs( const struct dc_state *context, struct dm_pp_display_configuration *pp_display_cfg); diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c index feb397b5c1a3..4245e1f818a3 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c @@ -727,7 +727,7 @@ void dce110_opp_v_set_csc_adjustment( CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC; program_color_matrix_v( - xfm_dce, tbl_entry, GRAPHICS_CSC_ADJUST_TYPE_SW); + xfm_dce, tbl_entry, GRPH_COLOR_MATRIX_SW); /* We did everything ,now program DxOUTPUT_CSC_CONTROL */ configure_graphics_mode_v(xfm_dce, config, GRAPHICS_CSC_ADJUST_TYPE_SW, diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index 7c4779578fb7..c4e877ac95d3 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -700,7 +700,7 @@ static void get_pixel_clock_parameters( pixel_clk_params->requested_pix_clk = stream->timing.pix_clk_khz; pixel_clk_params->encoder_object_id = stream->sink->link->link_enc->id; pixel_clk_params->signal_type = pipe_ctx->stream->signal; - pixel_clk_params->controller_id = pipe_ctx->pipe_idx + 1; + pixel_clk_params->controller_id = pipe_ctx->stream_res.tg->inst + 1; /* TODO: un-hardcode*/ pixel_clk_params->requested_sym_clk = LINK_RATE_LOW * LINK_RATE_REF_FREQ_IN_KHZ; @@ -973,7 +973,7 @@ static struct pipe_ctx *dce110_acquire_underlay( dc->hwss.enable_display_power_gating( dc, - pipe_ctx->pipe_idx, + pipe_ctx->stream_res.tg->inst, dcb, PIPE_GATING_CONTROL_DISABLE); /* @@ -1152,7 +1152,7 @@ static bool construct( pool->base.pipe_count = pool->base.res_cap->num_timing_generator; pool->base.underlay_pipe_index = pool->base.pipe_count; - + pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator; dc->caps.max_downscale_ratio = 150; dc->caps.i2c_speed_in_khz = 100; dc->caps.max_cursor_size = 128; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c index 25ca72139e5f..be7153924a70 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c @@ -2077,6 +2077,125 @@ bool dce110_arm_vert_intr(struct timing_generator *tg, uint8_t width) return true; } +static bool dce110_is_tg_enabled(struct timing_generator *tg) +{ + uint32_t addr = 0; + uint32_t value = 0; + uint32_t field = 0; + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + addr = CRTC_REG(mmCRTC_CONTROL); + value = dm_read_reg(tg->ctx, addr); + field = get_reg_field_value(value, CRTC_CONTROL, + CRTC_CURRENT_MASTER_EN_STATE); + return field == 1; +} + +bool dce110_configure_crc(struct timing_generator *tg, + const struct crc_params *params) +{ + uint32_t cntl_addr = 0; + uint32_t addr = 0; + uint32_t value; + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + /* Cannot configure crc on a CRTC that is disabled */ + if (!dce110_is_tg_enabled(tg)) + return false; + + cntl_addr = CRTC_REG(mmCRTC_CRC_CNTL); + + /* First, disable CRC before we configure it. */ + dm_write_reg(tg->ctx, cntl_addr, 0); + + if (!params->enable) + return true; + + /* Program frame boundaries */ + /* Window A x axis start and end. */ + value = 0; + addr = CRTC_REG(mmCRTC_CRC0_WINDOWA_X_CONTROL); + set_reg_field_value(value, params->windowa_x_start, + CRTC_CRC0_WINDOWA_X_CONTROL, + CRTC_CRC0_WINDOWA_X_START); + set_reg_field_value(value, params->windowa_x_end, + CRTC_CRC0_WINDOWA_X_CONTROL, + CRTC_CRC0_WINDOWA_X_END); + dm_write_reg(tg->ctx, addr, value); + + /* Window A y axis start and end. */ + value = 0; + addr = CRTC_REG(mmCRTC_CRC0_WINDOWA_Y_CONTROL); + set_reg_field_value(value, params->windowa_y_start, + CRTC_CRC0_WINDOWA_Y_CONTROL, + CRTC_CRC0_WINDOWA_Y_START); + set_reg_field_value(value, params->windowa_y_end, + CRTC_CRC0_WINDOWA_Y_CONTROL, + CRTC_CRC0_WINDOWA_Y_END); + dm_write_reg(tg->ctx, addr, value); + + /* Window B x axis start and end. */ + value = 0; + addr = CRTC_REG(mmCRTC_CRC0_WINDOWB_X_CONTROL); + set_reg_field_value(value, params->windowb_x_start, + CRTC_CRC0_WINDOWB_X_CONTROL, + CRTC_CRC0_WINDOWB_X_START); + set_reg_field_value(value, params->windowb_x_end, + CRTC_CRC0_WINDOWB_X_CONTROL, + CRTC_CRC0_WINDOWB_X_END); + dm_write_reg(tg->ctx, addr, value); + + /* Window B y axis start and end. */ + value = 0; + addr = CRTC_REG(mmCRTC_CRC0_WINDOWB_Y_CONTROL); + set_reg_field_value(value, params->windowb_y_start, + CRTC_CRC0_WINDOWB_Y_CONTROL, + CRTC_CRC0_WINDOWB_Y_START); + set_reg_field_value(value, params->windowb_y_end, + CRTC_CRC0_WINDOWB_Y_CONTROL, + CRTC_CRC0_WINDOWB_Y_END); + dm_write_reg(tg->ctx, addr, value); + + /* Set crc mode and selection, and enable. Only using CRC0*/ + value = 0; + set_reg_field_value(value, params->continuous_mode ? 1 : 0, + CRTC_CRC_CNTL, CRTC_CRC_CONT_EN); + set_reg_field_value(value, params->selection, + CRTC_CRC_CNTL, CRTC_CRC0_SELECT); + set_reg_field_value(value, 1, CRTC_CRC_CNTL, CRTC_CRC_EN); + dm_write_reg(tg->ctx, cntl_addr, value); + + return true; +} + +bool dce110_get_crc(struct timing_generator *tg, + uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb) +{ + uint32_t addr = 0; + uint32_t value = 0; + uint32_t field = 0; + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + addr = CRTC_REG(mmCRTC_CRC_CNTL); + value = dm_read_reg(tg->ctx, addr); + field = get_reg_field_value(value, CRTC_CRC_CNTL, CRTC_CRC_EN); + + /* Early return if CRC is not enabled for this CRTC */ + if (!field) + return false; + + addr = CRTC_REG(mmCRTC_CRC0_DATA_RG); + value = dm_read_reg(tg->ctx, addr); + *r_cr = get_reg_field_value(value, CRTC_CRC0_DATA_RG, CRC0_R_CR); + *g_y = get_reg_field_value(value, CRTC_CRC0_DATA_RG, CRC0_G_Y); + + addr = CRTC_REG(mmCRTC_CRC0_DATA_B); + value = dm_read_reg(tg->ctx, addr); + *b_cb = get_reg_field_value(value, CRTC_CRC0_DATA_B, CRC0_B_CB); + + return true; +} + static const struct timing_generator_funcs dce110_tg_funcs = { .validate_timing = dce110_tg_validate_timing, .program_timing = dce110_tg_program_timing, @@ -2112,6 +2231,9 @@ static const struct timing_generator_funcs dce110_tg_funcs = { dce110_timing_generator_set_static_screen_control, .set_test_pattern = dce110_timing_generator_set_test_pattern, .arm_vert_intr = dce110_arm_vert_intr, + .is_tg_enabled = dce110_is_tg_enabled, + .configure_crc = dce110_configure_crc, + .get_crc = dce110_get_crc, }; void dce110_timing_generator_construct( diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.h index 232747c7c60b..734d4965dab1 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.h @@ -276,4 +276,10 @@ void dce110_tg_set_colors(struct timing_generator *tg, bool dce110_arm_vert_intr( struct timing_generator *tg, uint8_t width); +bool dce110_configure_crc(struct timing_generator *tg, + const struct crc_params *params); + +bool dce110_get_crc(struct timing_generator *tg, + uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb); + #endif /* __DC_TIMING_GENERATOR_DCE110_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index 663e0a047a4b..c0757dd6c03c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -1100,9 +1100,12 @@ static bool construct( *************************************************/ pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; pool->base.pipe_count = pool->base.res_cap->num_timing_generator; + pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator; dc->caps.max_downscale_ratio = 200; dc->caps.i2c_speed_in_khz = 100; dc->caps.max_cursor_size = 128; + dc->caps.dual_link_dvi = true; + /************************************************* * Create resources * diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c index 75d029742f96..e96ff86d2fc3 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c @@ -33,7 +33,8 @@ #include "dce/dce_12_0_offset.h" #include "dce/dce_12_0_sh_mask.h" -#include "soc15ip.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" #include "reg_helper.h" #define CTX \ diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c index 57cd67359567..4659a4bfabaa 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c @@ -56,7 +56,8 @@ #include "dce/dce_12_0_offset.h" #include "dce/dce_12_0_sh_mask.h" -#include "soc15ip.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" #include "nbio/nbio_6_1_offset.h" #include "reg_helper.h" @@ -830,11 +831,14 @@ static bool construct( /* TODO: Fill more data from GreenlandAsicCapability.cpp */ pool->base.pipe_count = res_cap.num_timing_generator; + pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator; pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; dc->caps.max_downscale_ratio = 200; dc->caps.i2c_speed_in_khz = 100; dc->caps.max_cursor_size = 128; + dc->caps.dual_link_dvi = true; + dc->debug = debug_defaults; /************************************************* diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c index 0aa60e5727e0..7bee78172d85 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c @@ -27,7 +27,8 @@ #include "dce/dce_12_0_offset.h" #include "dce/dce_12_0_sh_mask.h" -#include "soc15ip.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" #include "dc_types.h" #include "dc_bios_types.h" diff --git a/drivers/gpu/drm/amd/display/dc/dce80/Makefile b/drivers/gpu/drm/amd/display/dc/dce80/Makefile index bc388aa4b2f5..666fcb2bdbba 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce80/Makefile @@ -23,7 +23,7 @@ # Makefile for the 'controller' sub-component of DAL. # It provides the control and status of HW CRTC block. -DCE80 = dce80_timing_generator.o dce80_compressor.o dce80_hw_sequencer.o \ +DCE80 = dce80_timing_generator.o dce80_hw_sequencer.o \ dce80_resource.o AMD_DAL_DCE80 = $(addprefix $(AMDDALPATH)/dc/dce80/,$(DCE80)) diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_compressor.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_compressor.c deleted file mode 100644 index 951f2caba9b3..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_compressor.c +++ /dev/null @@ -1,834 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" - -#include "dce/dce_8_0_d.h" -#include "dce/dce_8_0_sh_mask.h" -#include "gmc/gmc_7_1_sh_mask.h" -#include "gmc/gmc_7_1_d.h" - -#include "include/logger_interface.h" -#include "dce80_compressor.h" - -#define DCP_REG(reg)\ - (reg + cp80->offsets.dcp_offset) -#define DMIF_REG(reg)\ - (reg + cp80->offsets.dmif_offset) - -static const struct dce80_compressor_reg_offsets reg_offsets[] = { -{ - .dcp_offset = (mmDCP0_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), - .dmif_offset = (mmDMIF_PG0_DPG_PIPE_DPM_CONTROL - - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL), -}, -{ - .dcp_offset = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), - .dmif_offset = (mmDMIF_PG1_DPG_PIPE_DPM_CONTROL - - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL), -}, -{ - .dcp_offset = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), - .dmif_offset = (mmDMIF_PG2_DPG_PIPE_DPM_CONTROL - - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL), -}, -{ - .dcp_offset = (mmDCP3_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), - .dmif_offset = (mmDMIF_PG3_DPG_PIPE_DPM_CONTROL - - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL), -}, -{ - .dcp_offset = (mmDCP4_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), - .dmif_offset = (mmDMIF_PG4_DPG_PIPE_DPM_CONTROL - - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL), -}, -{ - .dcp_offset = (mmDCP5_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), - .dmif_offset = (mmDMIF_PG5_DPG_PIPE_DPM_CONTROL - - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL), -} -}; - -static const uint32_t dce8_one_lpt_channel_max_resolution = 2048 * 1200; - -enum fbc_idle_force { - /* Bit 0 - Display registers updated */ - FBC_IDLE_FORCE_DISPLAY_REGISTER_UPDATE = 0x00000001, - - /* Bit 2 - FBC_GRPH_COMP_EN register updated */ - FBC_IDLE_FORCE_GRPH_COMP_EN = 0x00000002, - /* Bit 3 - FBC_SRC_SEL register updated */ - FBC_IDLE_FORCE_SRC_SEL_CHANGE = 0x00000004, - /* Bit 4 - FBC_MIN_COMPRESSION register updated */ - FBC_IDLE_FORCE_MIN_COMPRESSION_CHANGE = 0x00000008, - /* Bit 5 - FBC_ALPHA_COMP_EN register updated */ - FBC_IDLE_FORCE_ALPHA_COMP_EN = 0x00000010, - /* Bit 6 - FBC_ZERO_ALPHA_CHUNK_SKIP_EN register updated */ - FBC_IDLE_FORCE_ZERO_ALPHA_CHUNK_SKIP_EN = 0x00000020, - /* Bit 7 - FBC_FORCE_COPY_TO_COMP_BUF register updated */ - FBC_IDLE_FORCE_FORCE_COPY_TO_COMP_BUF = 0x00000040, - - /* Bit 24 - Memory write to region 0 defined by MC registers. */ - FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION0 = 0x01000000, - /* Bit 25 - Memory write to region 1 defined by MC registers */ - FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION1 = 0x02000000, - /* Bit 26 - Memory write to region 2 defined by MC registers */ - FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION2 = 0x04000000, - /* Bit 27 - Memory write to region 3 defined by MC registers. */ - FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION3 = 0x08000000, - - /* Bit 28 - Memory write from any client other than MCIF */ - FBC_IDLE_FORCE_MEMORY_WRITE_OTHER_THAN_MCIF = 0x10000000, - /* Bit 29 - CG statics screen signal is inactive */ - FBC_IDLE_FORCE_CG_STATIC_SCREEN_IS_INACTIVE = 0x20000000, -}; - -static uint32_t lpt_size_alignment(struct dce80_compressor *cp80) -{ - /*LPT_ALIGNMENT (in bytes) = ROW_SIZE * #BANKS * # DRAM CHANNELS. */ - return cp80->base.raw_size * cp80->base.banks_num * - cp80->base.dram_channels_num; -} - -static uint32_t lpt_memory_control_config(struct dce80_compressor *cp80, - uint32_t lpt_control) -{ - /*LPT MC Config */ - if (cp80->base.options.bits.LPT_MC_CONFIG == 1) { - /* POSSIBLE VALUES for LPT NUM_PIPES (DRAM CHANNELS): - * 00 - 1 CHANNEL - * 01 - 2 CHANNELS - * 02 - 4 OR 6 CHANNELS - * (Only for discrete GPU, N/A for CZ) - * 03 - 8 OR 12 CHANNELS - * (Only for discrete GPU, N/A for CZ) */ - switch (cp80->base.dram_channels_num) { - case 2: - set_reg_field_value( - lpt_control, - 1, - LOW_POWER_TILING_CONTROL, - LOW_POWER_TILING_NUM_PIPES); - break; - case 1: - set_reg_field_value( - lpt_control, - 0, - LOW_POWER_TILING_CONTROL, - LOW_POWER_TILING_NUM_PIPES); - break; - default: - dm_logger_write( - cp80->base.ctx->logger, LOG_WARNING, - "%s: Invalid LPT NUM_PIPES!!!", - __func__); - break; - } - - /* The mapping for LPT NUM_BANKS is in - * GRPH_CONTROL.GRPH_NUM_BANKS register field - * Specifies the number of memory banks for tiling - * purposes. Only applies to 2D and 3D tiling modes. - * POSSIBLE VALUES: - * 00 - DCP_GRPH_NUM_BANKS_2BANK: ADDR_SURF_2_BANK - * 01 - DCP_GRPH_NUM_BANKS_4BANK: ADDR_SURF_4_BANK - * 02 - DCP_GRPH_NUM_BANKS_8BANK: ADDR_SURF_8_BANK - * 03 - DCP_GRPH_NUM_BANKS_16BANK: ADDR_SURF_16_BANK */ - switch (cp80->base.banks_num) { - case 16: - set_reg_field_value( - lpt_control, - 3, - LOW_POWER_TILING_CONTROL, - LOW_POWER_TILING_NUM_BANKS); - break; - case 8: - set_reg_field_value( - lpt_control, - 2, - LOW_POWER_TILING_CONTROL, - LOW_POWER_TILING_NUM_BANKS); - break; - case 4: - set_reg_field_value( - lpt_control, - 1, - LOW_POWER_TILING_CONTROL, - LOW_POWER_TILING_NUM_BANKS); - break; - case 2: - set_reg_field_value( - lpt_control, - 0, - LOW_POWER_TILING_CONTROL, - LOW_POWER_TILING_NUM_BANKS); - break; - default: - dm_logger_write( - cp80->base.ctx->logger, LOG_WARNING, - "%s: Invalid LPT NUM_BANKS!!!", - __func__); - break; - } - - /* The mapping is in DMIF_ADDR_CALC. - * ADDR_CONFIG_PIPE_INTERLEAVE_SIZE register field for - * Carrizo specifies the memory interleave per pipe. - * It effectively specifies the location of pipe bits in - * the memory address. - * POSSIBLE VALUES: - * 00 - ADDR_CONFIG_PIPE_INTERLEAVE_256B: 256 byte - * interleave - * 01 - ADDR_CONFIG_PIPE_INTERLEAVE_512B: 512 byte - * interleave - */ - switch (cp80->base.channel_interleave_size) { - case 256: /*256B */ - set_reg_field_value( - lpt_control, - 0, - LOW_POWER_TILING_CONTROL, - LOW_POWER_TILING_PIPE_INTERLEAVE_SIZE); - break; - case 512: /*512B */ - set_reg_field_value( - lpt_control, - 1, - LOW_POWER_TILING_CONTROL, - LOW_POWER_TILING_PIPE_INTERLEAVE_SIZE); - break; - default: - dm_logger_write( - cp80->base.ctx->logger, LOG_WARNING, - "%s: Invalid LPT INTERLEAVE_SIZE!!!", - __func__); - break; - } - - /* The mapping for LOW_POWER_TILING_ROW_SIZE is in - * DMIF_ADDR_CALC.ADDR_CONFIG_ROW_SIZE register field - * for Carrizo. Specifies the size of dram row in bytes. - * This should match up with NOOFCOLS field in - * MC_ARB_RAMCFG (ROW_SIZE = 4 * 2 ^^ columns). - * This register DMIF_ADDR_CALC is not used by the - * hardware as it is only used for addrlib assertions. - * POSSIBLE VALUES: - * 00 - ADDR_CONFIG_1KB_ROW: Treat 1KB as DRAM row - * boundary - * 01 - ADDR_CONFIG_2KB_ROW: Treat 2KB as DRAM row - * boundary - * 02 - ADDR_CONFIG_4KB_ROW: Treat 4KB as DRAM row - * boundary */ - switch (cp80->base.raw_size) { - case 4096: /*4 KB */ - set_reg_field_value( - lpt_control, - 2, - LOW_POWER_TILING_CONTROL, - LOW_POWER_TILING_ROW_SIZE); - break; - case 2048: - set_reg_field_value( - lpt_control, - 1, - LOW_POWER_TILING_CONTROL, - LOW_POWER_TILING_ROW_SIZE); - break; - case 1024: - set_reg_field_value( - lpt_control, - 0, - LOW_POWER_TILING_CONTROL, - LOW_POWER_TILING_ROW_SIZE); - break; - default: - dm_logger_write( - cp80->base.ctx->logger, LOG_WARNING, - "%s: Invalid LPT ROW_SIZE!!!", - __func__); - break; - } - } else { - dm_logger_write( - cp80->base.ctx->logger, LOG_WARNING, - "%s: LPT MC Configuration is not provided", - __func__); - } - - return lpt_control; -} - -static bool is_source_bigger_than_epanel_size( - struct dce80_compressor *cp80, - uint32_t source_view_width, - uint32_t source_view_height) -{ - if (cp80->base.embedded_panel_h_size != 0 && - cp80->base.embedded_panel_v_size != 0 && - ((source_view_width * source_view_height) > - (cp80->base.embedded_panel_h_size * - cp80->base.embedded_panel_v_size))) - return true; - - return false; -} - -static uint32_t align_to_chunks_number_per_line( - struct dce80_compressor *cp80, - uint32_t pixels) -{ - return 256 * ((pixels + 255) / 256); -} - -static void wait_for_fbc_state_changed( - struct dce80_compressor *cp80, - bool enabled) -{ - uint8_t counter = 0; - uint32_t addr = mmFBC_STATUS; - uint32_t value; - - while (counter < 10) { - value = dm_read_reg(cp80->base.ctx, addr); - if (get_reg_field_value( - value, - FBC_STATUS, - FBC_ENABLE_STATUS) == enabled) - break; - udelay(10); - counter++; - } - - if (counter == 10) { - dm_logger_write( - cp80->base.ctx->logger, LOG_WARNING, - "%s: wait counter exceeded, changes to HW not applied", - __func__); - } -} - -void dce80_compressor_power_up_fbc(struct compressor *compressor) -{ - uint32_t value; - uint32_t addr; - - addr = mmFBC_CNTL; - value = dm_read_reg(compressor->ctx, addr); - set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN); - set_reg_field_value(value, 1, FBC_CNTL, FBC_EN); - set_reg_field_value(value, 2, FBC_CNTL, FBC_COHERENCY_MODE); - dm_write_reg(compressor->ctx, addr, value); - - addr = mmFBC_COMP_MODE; - value = dm_read_reg(compressor->ctx, addr); - set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_RLE_EN); - set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_DPCM4_RGB_EN); - set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_IND_EN); - dm_write_reg(compressor->ctx, addr, value); - - addr = mmFBC_COMP_CNTL; - value = dm_read_reg(compressor->ctx, addr); - set_reg_field_value(value, 1, FBC_COMP_CNTL, FBC_DEPTH_RGB08_EN); - dm_write_reg(compressor->ctx, addr, value); - /*FBC_MIN_COMPRESSION 0 ==> 2:1 */ - /* 1 ==> 4:1 */ - /* 2 ==> 8:1 */ - /* 0xF ==> 1:1 */ - set_reg_field_value(value, 0xF, FBC_COMP_CNTL, FBC_MIN_COMPRESSION); - dm_write_reg(compressor->ctx, addr, value); - compressor->min_compress_ratio = FBC_COMPRESS_RATIO_1TO1; - - value = 0; - dm_write_reg(compressor->ctx, mmFBC_IND_LUT0, value); - - value = 0xFFFFFF; - dm_write_reg(compressor->ctx, mmFBC_IND_LUT1, value); -} - -void dce80_compressor_enable_fbc( - struct compressor *compressor, - uint32_t paths_num, - struct compr_addr_and_pitch_params *params) -{ - struct dce80_compressor *cp80 = TO_DCE80_COMPRESSOR(compressor); - - if (compressor->options.bits.FBC_SUPPORT && - (compressor->options.bits.DUMMY_BACKEND == 0) && - (!dce80_compressor_is_fbc_enabled_in_hw(compressor, NULL)) && - (!is_source_bigger_than_epanel_size( - cp80, - params->source_view_width, - params->source_view_height))) { - - uint32_t addr; - uint32_t value; - - /* Before enabling FBC first need to enable LPT if applicable - * LPT state should always be changed (enable/disable) while FBC - * is disabled */ - if (compressor->options.bits.LPT_SUPPORT && (paths_num < 2) && - (params->source_view_width * - params->source_view_height <= - dce8_one_lpt_channel_max_resolution)) { - dce80_compressor_enable_lpt(compressor); - } - - addr = mmFBC_CNTL; - value = dm_read_reg(compressor->ctx, addr); - set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN); - set_reg_field_value( - value, - params->inst, - FBC_CNTL, FBC_SRC_SEL); - dm_write_reg(compressor->ctx, addr, value); - - /* Keep track of enum controller_id FBC is attached to */ - compressor->is_enabled = true; - compressor->attached_inst = params->inst; - cp80->offsets = reg_offsets[params->inst]; - - /*Toggle it as there is bug in HW */ - set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN); - dm_write_reg(compressor->ctx, addr, value); - set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN); - dm_write_reg(compressor->ctx, addr, value); - - wait_for_fbc_state_changed(cp80, true); - } -} - -void dce80_compressor_disable_fbc(struct compressor *compressor) -{ - struct dce80_compressor *cp80 = TO_DCE80_COMPRESSOR(compressor); - - if (compressor->options.bits.FBC_SUPPORT && - dce80_compressor_is_fbc_enabled_in_hw(compressor, NULL)) { - uint32_t reg_data; - /* Turn off compression */ - reg_data = dm_read_reg(compressor->ctx, mmFBC_CNTL); - set_reg_field_value(reg_data, 0, FBC_CNTL, FBC_GRPH_COMP_EN); - dm_write_reg(compressor->ctx, mmFBC_CNTL, reg_data); - - /* Reset enum controller_id to undefined */ - compressor->attached_inst = 0; - compressor->is_enabled = false; - - /* Whenever disabling FBC make sure LPT is disabled if LPT - * supported */ - if (compressor->options.bits.LPT_SUPPORT) - dce80_compressor_disable_lpt(compressor); - - wait_for_fbc_state_changed(cp80, false); - } -} - -bool dce80_compressor_is_fbc_enabled_in_hw( - struct compressor *compressor, - uint32_t *inst) -{ - /* Check the hardware register */ - uint32_t value; - - value = dm_read_reg(compressor->ctx, mmFBC_STATUS); - if (get_reg_field_value(value, FBC_STATUS, FBC_ENABLE_STATUS)) { - if (inst != NULL) - *inst = compressor->attached_inst; - return true; - } - - value = dm_read_reg(compressor->ctx, mmFBC_CNTL); - if (get_reg_field_value(value, FBC_CNTL, FBC_GRPH_COMP_EN)) { - if (inst != NULL) - *inst = compressor->attached_inst; - return true; - } - - return false; -} - -bool dce80_compressor_is_lpt_enabled_in_hw(struct compressor *compressor) -{ - /* Check the hardware register */ - uint32_t value = dm_read_reg(compressor->ctx, - mmLOW_POWER_TILING_CONTROL); - - return get_reg_field_value( - value, - LOW_POWER_TILING_CONTROL, - LOW_POWER_TILING_ENABLE); -} - -void dce80_compressor_program_compressed_surface_address_and_pitch( - struct compressor *compressor, - struct compr_addr_and_pitch_params *params) -{ - struct dce80_compressor *cp80 = TO_DCE80_COMPRESSOR(compressor); - uint32_t value = 0; - uint32_t fbc_pitch = 0; - uint32_t compressed_surf_address_low_part = - compressor->compr_surface_address.addr.low_part; - - /* Clear content first. */ - dm_write_reg( - compressor->ctx, - DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH), - 0); - dm_write_reg(compressor->ctx, - DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS), 0); - - if (compressor->options.bits.LPT_SUPPORT) { - uint32_t lpt_alignment = lpt_size_alignment(cp80); - - if (lpt_alignment != 0) { - compressed_surf_address_low_part = - ((compressed_surf_address_low_part - + (lpt_alignment - 1)) / lpt_alignment) - * lpt_alignment; - } - } - - /* Write address, HIGH has to be first. */ - dm_write_reg(compressor->ctx, - DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH), - compressor->compr_surface_address.addr.high_part); - dm_write_reg(compressor->ctx, - DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS), - compressed_surf_address_low_part); - - fbc_pitch = align_to_chunks_number_per_line( - cp80, - params->source_view_width); - - if (compressor->min_compress_ratio == FBC_COMPRESS_RATIO_1TO1) - fbc_pitch = fbc_pitch / 8; - else - dm_logger_write( - compressor->ctx->logger, LOG_WARNING, - "%s: Unexpected DCE8 compression ratio", - __func__); - - /* Clear content first. */ - dm_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), 0); - - /* Write FBC Pitch. */ - set_reg_field_value( - value, - fbc_pitch, - GRPH_COMPRESS_PITCH, - GRPH_COMPRESS_PITCH); - dm_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), value); - -} - -void dce80_compressor_disable_lpt(struct compressor *compressor) -{ - struct dce80_compressor *cp80 = TO_DCE80_COMPRESSOR(compressor); - uint32_t value; - uint32_t addr; - uint32_t inx; - - /* Disable all pipes LPT Stutter */ - for (inx = 0; inx < 3; inx++) { - value = - dm_read_reg( - compressor->ctx, - DMIF_REG(mmDPG_PIPE_STUTTER_CONTROL_NONLPTCH)); - set_reg_field_value( - value, - 0, - DPG_PIPE_STUTTER_CONTROL_NONLPTCH, - STUTTER_ENABLE_NONLPTCH); - dm_write_reg( - compressor->ctx, - DMIF_REG(mmDPG_PIPE_STUTTER_CONTROL_NONLPTCH), - value); - } - - /* Disable LPT */ - addr = mmLOW_POWER_TILING_CONTROL; - value = dm_read_reg(compressor->ctx, addr); - set_reg_field_value( - value, - 0, - LOW_POWER_TILING_CONTROL, - LOW_POWER_TILING_ENABLE); - dm_write_reg(compressor->ctx, addr, value); - - /* Clear selection of Channel(s) containing Compressed Surface */ - addr = mmGMCON_LPT_TARGET; - value = dm_read_reg(compressor->ctx, addr); - set_reg_field_value( - value, - 0xFFFFFFFF, - GMCON_LPT_TARGET, - STCTRL_LPT_TARGET); - dm_write_reg(compressor->ctx, mmGMCON_LPT_TARGET, value); -} - -void dce80_compressor_enable_lpt(struct compressor *compressor) -{ - struct dce80_compressor *cp80 = TO_DCE80_COMPRESSOR(compressor); - uint32_t value; - uint32_t addr; - uint32_t value_control; - uint32_t channels; - - /* Enable LPT Stutter from Display pipe */ - value = dm_read_reg(compressor->ctx, - DMIF_REG(mmDPG_PIPE_STUTTER_CONTROL_NONLPTCH)); - set_reg_field_value( - value, - 1, - DPG_PIPE_STUTTER_CONTROL_NONLPTCH, - STUTTER_ENABLE_NONLPTCH); - dm_write_reg(compressor->ctx, - DMIF_REG(mmDPG_PIPE_STUTTER_CONTROL_NONLPTCH), value); - - /* Selection of Channel(s) containing Compressed Surface: 0xfffffff - * will disable LPT. - * STCTRL_LPT_TARGETn corresponds to channel n. */ - addr = mmLOW_POWER_TILING_CONTROL; - value_control = dm_read_reg(compressor->ctx, addr); - channels = get_reg_field_value(value_control, - LOW_POWER_TILING_CONTROL, - LOW_POWER_TILING_MODE); - - addr = mmGMCON_LPT_TARGET; - value = dm_read_reg(compressor->ctx, addr); - set_reg_field_value( - value, - channels + 1, /* not mentioned in programming guide, - but follow DCE8.1 */ - GMCON_LPT_TARGET, - STCTRL_LPT_TARGET); - dm_write_reg(compressor->ctx, addr, value); - - /* Enable LPT */ - addr = mmLOW_POWER_TILING_CONTROL; - value = dm_read_reg(compressor->ctx, addr); - set_reg_field_value( - value, - 1, - LOW_POWER_TILING_CONTROL, - LOW_POWER_TILING_ENABLE); - dm_write_reg(compressor->ctx, addr, value); -} - -void dce80_compressor_program_lpt_control( - struct compressor *compressor, - struct compr_addr_and_pitch_params *params) -{ - struct dce80_compressor *cp80 = TO_DCE80_COMPRESSOR(compressor); - uint32_t rows_per_channel; - uint32_t lpt_alignment; - uint32_t source_view_width; - uint32_t source_view_height; - uint32_t lpt_control = 0; - - if (!compressor->options.bits.LPT_SUPPORT) - return; - - lpt_control = dm_read_reg(compressor->ctx, - mmLOW_POWER_TILING_CONTROL); - - /* POSSIBLE VALUES for Low Power Tiling Mode: - * 00 - Use channel 0 - * 01 - Use Channel 0 and 1 - * 02 - Use Channel 0,1,2,3 - * 03 - reserved */ - switch (compressor->lpt_channels_num) { - /* case 2: - * Use Channel 0 & 1 / Not used for DCE 11 */ - case 1: - /*Use Channel 0 for LPT for DCE 11 */ - set_reg_field_value( - lpt_control, - 0, - LOW_POWER_TILING_CONTROL, - LOW_POWER_TILING_MODE); - break; - default: - dm_logger_write( - compressor->ctx->logger, LOG_WARNING, - "%s: Invalid selected DRAM channels for LPT!!!", - __func__); - break; - } - - lpt_control = lpt_memory_control_config(cp80, lpt_control); - - /* Program LOW_POWER_TILING_ROWS_PER_CHAN field which depends on - * FBC compressed surface pitch. - * LOW_POWER_TILING_ROWS_PER_CHAN = Roundup ((Surface Height * - * Surface Pitch) / (Row Size * Number of Channels * - * Number of Banks)). */ - rows_per_channel = 0; - lpt_alignment = lpt_size_alignment(cp80); - source_view_width = - align_to_chunks_number_per_line( - cp80, - params->source_view_width); - source_view_height = (params->source_view_height + 1) & (~0x1); - - if (lpt_alignment != 0) { - rows_per_channel = source_view_width * source_view_height * 4; - rows_per_channel = - (rows_per_channel % lpt_alignment) ? - (rows_per_channel / lpt_alignment + 1) : - rows_per_channel / lpt_alignment; - } - - set_reg_field_value( - lpt_control, - rows_per_channel, - LOW_POWER_TILING_CONTROL, - LOW_POWER_TILING_ROWS_PER_CHAN); - - dm_write_reg(compressor->ctx, - mmLOW_POWER_TILING_CONTROL, lpt_control); -} - -/* - * DCE 11 Frame Buffer Compression Implementation - */ - -void dce80_compressor_set_fbc_invalidation_triggers( - struct compressor *compressor, - uint32_t fbc_trigger) -{ - /* Disable region hit event, FBC_MEMORY_REGION_MASK = 0 (bits 16-19) - * for DCE 11 regions cannot be used - does not work with S/G - */ - uint32_t addr = mmFBC_CLIENT_REGION_MASK; - uint32_t value = dm_read_reg(compressor->ctx, addr); - - set_reg_field_value( - value, - 0, - FBC_CLIENT_REGION_MASK, - FBC_MEMORY_REGION_MASK); - dm_write_reg(compressor->ctx, addr, value); - - /* Setup events when to clear all CSM entries (effectively marking - * current compressed data invalid) - * For DCE 11 CSM metadata 11111 means - "Not Compressed" - * Used as the initial value of the metadata sent to the compressor - * after invalidation, to indicate that the compressor should attempt - * to compress all chunks on the current pass. Also used when the chunk - * is not successfully written to memory. - * When this CSM value is detected, FBC reads from the uncompressed - * buffer. Set events according to passed in value, these events are - * valid for DCE8: - * - bit 0 - display register updated - * - bit 28 - memory write from any client except from MCIF - * - bit 29 - CG static screen signal is inactive - * In addition, DCE8.1 also needs to set new DCE8.1 specific events - * that are used to trigger invalidation on certain register changes, - * for example enabling of Alpha Compression may trigger invalidation of - * FBC once bit is set. These events are as follows: - * - Bit 2 - FBC_GRPH_COMP_EN register updated - * - Bit 3 - FBC_SRC_SEL register updated - * - Bit 4 - FBC_MIN_COMPRESSION register updated - * - Bit 5 - FBC_ALPHA_COMP_EN register updated - * - Bit 6 - FBC_ZERO_ALPHA_CHUNK_SKIP_EN register updated - * - Bit 7 - FBC_FORCE_COPY_TO_COMP_BUF register updated - */ - addr = mmFBC_IDLE_FORCE_CLEAR_MASK; - value = dm_read_reg(compressor->ctx, addr); - set_reg_field_value( - value, - fbc_trigger | - FBC_IDLE_FORCE_GRPH_COMP_EN | - FBC_IDLE_FORCE_SRC_SEL_CHANGE | - FBC_IDLE_FORCE_MIN_COMPRESSION_CHANGE | - FBC_IDLE_FORCE_ALPHA_COMP_EN | - FBC_IDLE_FORCE_ZERO_ALPHA_CHUNK_SKIP_EN | - FBC_IDLE_FORCE_FORCE_COPY_TO_COMP_BUF, - FBC_IDLE_FORCE_CLEAR_MASK, - FBC_IDLE_FORCE_CLEAR_MASK); - dm_write_reg(compressor->ctx, addr, value); -} - -void dce80_compressor_construct(struct dce80_compressor *compressor, - struct dc_context *ctx) -{ - struct dc_bios *bp = ctx->dc_bios; - struct embedded_panel_info panel_info; - - compressor->base.options.raw = 0; - compressor->base.options.bits.FBC_SUPPORT = true; - compressor->base.options.bits.LPT_SUPPORT = true; - /* For DCE 11 always use one DRAM channel for LPT */ - compressor->base.lpt_channels_num = 1; - compressor->base.options.bits.DUMMY_BACKEND = false; - - /* Check if this system has more than 1 DRAM channel; if only 1 then LPT - * should not be supported */ - if (compressor->base.memory_bus_width == 64) - compressor->base.options.bits.LPT_SUPPORT = false; - - compressor->base.options.bits.CLK_GATING_DISABLED = false; - - compressor->base.ctx = ctx; - compressor->base.embedded_panel_h_size = 0; - compressor->base.embedded_panel_v_size = 0; - compressor->base.memory_bus_width = ctx->asic_id.vram_width; - compressor->base.allocated_size = 0; - compressor->base.preferred_requested_size = 0; - compressor->base.min_compress_ratio = FBC_COMPRESS_RATIO_INVALID; - compressor->base.banks_num = 0; - compressor->base.raw_size = 0; - compressor->base.channel_interleave_size = 0; - compressor->base.dram_channels_num = 0; - compressor->base.lpt_channels_num = 0; - compressor->base.attached_inst = 0; - compressor->base.is_enabled = false; - - if (BP_RESULT_OK == - bp->funcs->get_embedded_panel_info(bp, &panel_info)) { - compressor->base.embedded_panel_h_size = - panel_info.lcd_timing.horizontal_addressable; - compressor->base.embedded_panel_v_size = - panel_info.lcd_timing.vertical_addressable; - } -} - -struct compressor *dce80_compressor_create(struct dc_context *ctx) -{ - struct dce80_compressor *cp80 = - kzalloc(sizeof(struct dce80_compressor), GFP_KERNEL); - - if (!cp80) - return NULL; - - dce80_compressor_construct(cp80, ctx); - return &cp80->base; -} - -void dce80_compressor_destroy(struct compressor **compressor) -{ - kfree(TO_DCE80_COMPRESSOR(*compressor)); - *compressor = NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_compressor.h b/drivers/gpu/drm/amd/display/dc/dce80/dce80_compressor.h deleted file mode 100644 index cca58b044402..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_compressor.h +++ /dev/null @@ -1,78 +0,0 @@ -/* Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_COMPRESSOR_DCE80_H__ -#define __DC_COMPRESSOR_DCE80_H__ - -#include "../inc/compressor.h" - -#define TO_DCE80_COMPRESSOR(compressor)\ - container_of(compressor, struct dce80_compressor, base) - -struct dce80_compressor_reg_offsets { - uint32_t dcp_offset; - uint32_t dmif_offset; -}; - -struct dce80_compressor { - struct compressor base; - struct dce80_compressor_reg_offsets offsets; -}; - -struct compressor *dce80_compressor_create(struct dc_context *ctx); - -void dce80_compressor_construct(struct dce80_compressor *cp80, - struct dc_context *ctx); - -void dce80_compressor_destroy(struct compressor **cp); - -/* FBC RELATED */ -void dce80_compressor_power_up_fbc(struct compressor *cp); - -void dce80_compressor_enable_fbc(struct compressor *cp, uint32_t paths_num, - struct compr_addr_and_pitch_params *params); - -void dce80_compressor_disable_fbc(struct compressor *cp); - -void dce80_compressor_set_fbc_invalidation_triggers(struct compressor *cp, - uint32_t fbc_trigger); - -void dce80_compressor_program_compressed_surface_address_and_pitch( - struct compressor *cp, - struct compr_addr_and_pitch_params *params); - -bool dce80_compressor_is_fbc_enabled_in_hw(struct compressor *cp, - uint32_t *fbc_mapped_crtc_id); - -/* LPT RELATED */ -void dce80_compressor_enable_lpt(struct compressor *cp); - -void dce80_compressor_disable_lpt(struct compressor *cp); - -void dce80_compressor_program_lpt_control(struct compressor *cp, - struct compr_addr_and_pitch_params *params); - -bool dce80_compressor_is_lpt_enabled_in_hw(struct compressor *cp); - -#endif diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c index ccfcf1c0eeb3..6c6a1a16af19 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c @@ -70,47 +70,11 @@ static const struct dce80_hw_seq_reg_offsets reg_offsets[] = { /***************************PIPE_CONTROL***********************************/ -static bool dce80_enable_display_power_gating( - struct dc *dc, - uint8_t controller_id, - struct dc_bios *dcb, - enum pipe_gating_control power_gating) -{ - enum bp_result bp_result = BP_RESULT_OK; - enum bp_pipe_control_action cntl; - struct dc_context *ctx = dc->ctx; - - if (power_gating == PIPE_GATING_CONTROL_INIT) - cntl = ASIC_PIPE_INIT; - else if (power_gating == PIPE_GATING_CONTROL_ENABLE) - cntl = ASIC_PIPE_ENABLE; - else - cntl = ASIC_PIPE_DISABLE; - - if (!(power_gating == PIPE_GATING_CONTROL_INIT && controller_id != 0)){ - - bp_result = dcb->funcs->enable_disp_power_gating( - dcb, controller_id + 1, cntl); - - /* Revert MASTER_UPDATE_MODE to 0 because bios sets it 2 - * by default when command table is called - */ - dm_write_reg(ctx, - HW_REG_CRTC(mmMASTER_UPDATE_MODE, controller_id), - 0); - } - - if (bp_result == BP_RESULT_OK) - return true; - else - return false; -} - void dce80_hw_sequencer_construct(struct dc *dc) { dce110_hw_sequencer_construct(dc); - dc->hwss.enable_display_power_gating = dce80_enable_display_power_gating; + dc->hwss.enable_display_power_gating = dce100_enable_display_power_gating; dc->hwss.pipe_control_lock = dce_pipe_control_lock; dc->hwss.set_bandwidth = dce100_set_bandwidth; } diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c index 8f2bd56f3461..a36c14d3d9a8 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c @@ -790,9 +790,11 @@ static bool dce80_construct( *************************************************/ pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; pool->base.pipe_count = res_cap.num_timing_generator; + pool->base.timing_generator_count = res_cap.num_timing_generator; dc->caps.max_downscale_ratio = 200; dc->caps.i2c_speed_in_khz = 40; dc->caps.max_cursor_size = 128; + dc->caps.dual_link_dvi = true; /************************************************* * Create resources * @@ -954,6 +956,7 @@ static bool dce81_construct( *************************************************/ pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; pool->base.pipe_count = res_cap_81.num_timing_generator; + pool->base.timing_generator_count = res_cap_81.num_timing_generator; dc->caps.max_downscale_ratio = 200; dc->caps.i2c_speed_in_khz = 40; dc->caps.max_cursor_size = 128; @@ -1119,6 +1122,7 @@ static bool dce83_construct( *************************************************/ pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; pool->base.pipe_count = res_cap_83.num_timing_generator; + pool->base.timing_generator_count = res_cap_83.num_timing_generator; dc->caps.max_downscale_ratio = 200; dc->caps.i2c_speed_in_khz = 40; dc->caps.max_cursor_size = 128; diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c index 265894851493..3ba4712a35ab 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c @@ -84,7 +84,7 @@ static const struct dce110_timing_generator_offsets reg_offsets[] = { #define DCP_REG(reg) (reg + tg110->offsets.dcp) #define DMIF_REG(reg) (reg + tg110->offsets.dmif) -void program_pix_dur(struct timing_generator *tg, uint32_t pix_clk_khz) +static void program_pix_dur(struct timing_generator *tg, uint32_t pix_clk_khz) { uint64_t pix_dur; uint32_t addr = mmDMIF_PG0_DPG_PIPE_ARBITRATION_CONTROL1 @@ -115,68 +115,7 @@ static void program_timing(struct timing_generator *tg, dce110_tg_program_timing(tg, timing, use_vbios); } -static const struct timing_generator_funcs dce80_tg_funcs = { - .validate_timing = dce110_tg_validate_timing, - .program_timing = program_timing, - .enable_crtc = dce110_timing_generator_enable_crtc, - .disable_crtc = dce110_timing_generator_disable_crtc, - .is_counter_moving = dce110_timing_generator_is_counter_moving, - .get_position = dce110_timing_generator_get_position, - .get_frame_count = dce110_timing_generator_get_vblank_counter, - .get_scanoutpos = dce110_timing_generator_get_crtc_scanoutpos, - .set_early_control = dce110_timing_generator_set_early_control, - .wait_for_state = dce110_tg_wait_for_state, - .set_blank = dce110_tg_set_blank, - .is_blanked = dce110_tg_is_blanked, - .set_colors = dce110_tg_set_colors, - .set_overscan_blank_color = - dce110_timing_generator_set_overscan_color_black, - .set_blank_color = dce110_timing_generator_program_blank_color, - .disable_vga = dce110_timing_generator_disable_vga, - .did_triggered_reset_occur = - dce110_timing_generator_did_triggered_reset_occur, - .setup_global_swap_lock = - dce110_timing_generator_setup_global_swap_lock, - .enable_reset_trigger = dce110_timing_generator_enable_reset_trigger, - .disable_reset_trigger = dce110_timing_generator_disable_reset_trigger, - .tear_down_global_swap_lock = - dce110_timing_generator_tear_down_global_swap_lock, - .set_drr = dce110_timing_generator_set_drr, - .set_static_screen_control = - dce110_timing_generator_set_static_screen_control, - .set_test_pattern = dce110_timing_generator_set_test_pattern, - .arm_vert_intr = dce110_arm_vert_intr, - - /* DCE8.0 overrides */ - .enable_advanced_request = - dce80_timing_generator_enable_advanced_request, -}; - -void dce80_timing_generator_construct( - struct dce110_timing_generator *tg110, - struct dc_context *ctx, - uint32_t instance, - const struct dce110_timing_generator_offsets *offsets) -{ - tg110->controller_id = CONTROLLER_ID_D0 + instance; - tg110->base.inst = instance; - tg110->offsets = *offsets; - tg110->derived_offsets = reg_offsets[instance]; - - tg110->base.funcs = &dce80_tg_funcs; - - tg110->base.ctx = ctx; - tg110->base.bp = ctx->dc_bios; - - tg110->max_h_total = CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1; - tg110->max_v_total = CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1; - - tg110->min_h_blank = 56; - tg110->min_h_front_porch = 4; - tg110->min_h_back_porch = 4; -} - -void dce80_timing_generator_enable_advanced_request( +static void dce80_timing_generator_enable_advanced_request( struct timing_generator *tg, bool enable, const struct dc_crtc_timing *timing) @@ -237,3 +176,67 @@ void dce80_timing_generator_enable_advanced_request( dm_write_reg(tg->ctx, addr, value); } + +static const struct timing_generator_funcs dce80_tg_funcs = { + .validate_timing = dce110_tg_validate_timing, + .program_timing = program_timing, + .enable_crtc = dce110_timing_generator_enable_crtc, + .disable_crtc = dce110_timing_generator_disable_crtc, + .is_counter_moving = dce110_timing_generator_is_counter_moving, + .get_position = dce110_timing_generator_get_position, + .get_frame_count = dce110_timing_generator_get_vblank_counter, + .get_scanoutpos = dce110_timing_generator_get_crtc_scanoutpos, + .set_early_control = dce110_timing_generator_set_early_control, + .wait_for_state = dce110_tg_wait_for_state, + .set_blank = dce110_tg_set_blank, + .is_blanked = dce110_tg_is_blanked, + .set_colors = dce110_tg_set_colors, + .set_overscan_blank_color = + dce110_timing_generator_set_overscan_color_black, + .set_blank_color = dce110_timing_generator_program_blank_color, + .disable_vga = dce110_timing_generator_disable_vga, + .did_triggered_reset_occur = + dce110_timing_generator_did_triggered_reset_occur, + .setup_global_swap_lock = + dce110_timing_generator_setup_global_swap_lock, + .enable_reset_trigger = dce110_timing_generator_enable_reset_trigger, + .disable_reset_trigger = dce110_timing_generator_disable_reset_trigger, + .tear_down_global_swap_lock = + dce110_timing_generator_tear_down_global_swap_lock, + .set_drr = dce110_timing_generator_set_drr, + .set_static_screen_control = + dce110_timing_generator_set_static_screen_control, + .set_test_pattern = dce110_timing_generator_set_test_pattern, + .arm_vert_intr = dce110_arm_vert_intr, + + /* DCE8.0 overrides */ + .enable_advanced_request = + dce80_timing_generator_enable_advanced_request, + .configure_crc = dce110_configure_crc, + .get_crc = dce110_get_crc, +}; + +void dce80_timing_generator_construct( + struct dce110_timing_generator *tg110, + struct dc_context *ctx, + uint32_t instance, + const struct dce110_timing_generator_offsets *offsets) +{ + tg110->controller_id = CONTROLLER_ID_D0 + instance; + tg110->base.inst = instance; + tg110->offsets = *offsets; + tg110->derived_offsets = reg_offsets[instance]; + + tg110->base.funcs = &dce80_tg_funcs; + + tg110->base.ctx = ctx; + tg110->base.bp = ctx->dc_bios; + + tg110->max_h_total = CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1; + tg110->max_v_total = CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1; + + tg110->min_h_blank = 56; + tg110->min_h_front_porch = 4; + tg110->min_h_back_porch = 4; +} + diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.h b/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.h index 9cebb24c94c8..8ff1b06bcd8b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.h @@ -36,10 +36,4 @@ void dce80_timing_generator_construct( uint32_t instance, const struct dce110_timing_generator_offsets *offsets); -/******** HW programming ************/ -void dce80_timing_generator_enable_advanced_request( - struct timing_generator *tg, - bool enable, - const struct dc_crtc_timing *timing); - #endif /* __DC_TIMING_GENERATOR_DCE80_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c index 53ba3600ee6a..b3db6397d353 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c @@ -232,10 +232,11 @@ bool cm_helper_convert_to_custom_float( return true; } - +/* driver uses 32 regions or less, but DCN HW has 34, extra 2 are set to 0 */ #define MAX_REGIONS_NUMBER 34 #define MAX_LOW_POINT 25 -#define NUMBER_SEGMENTS 32 +#define NUMBER_REGIONS 32 +#define NUMBER_SW_SEGMENTS 16 bool cm_helper_translate_curve_to_hw_format( const struct dc_transfer_func *output_tf, @@ -251,7 +252,7 @@ bool cm_helper_translate_curve_to_hw_format( struct fixed31_32 y1_min; struct fixed31_32 y3_max; - int32_t segment_start, segment_end; + int32_t region_start, region_end; int32_t i; uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points; @@ -271,11 +272,11 @@ bool cm_helper_translate_curve_to_hw_format( /* 32 segments * segments are from 2^-25 to 2^7 */ - for (i = 0; i < 32 ; i++) + for (i = 0; i < NUMBER_REGIONS ; i++) seg_distr[i] = 3; - segment_start = -25; - segment_end = 7; + region_start = -MAX_LOW_POINT; + region_end = NUMBER_REGIONS - MAX_LOW_POINT; } else { /* 10 segments * segment is from 2^-10 to 2^0 @@ -289,14 +290,14 @@ bool cm_helper_translate_curve_to_hw_format( seg_distr[5] = 4; seg_distr[6] = 4; seg_distr[7] = 4; - seg_distr[8] = 5; - seg_distr[9] = 5; + seg_distr[8] = 4; + seg_distr[9] = 4; - segment_start = -10; - segment_end = 0; + region_start = -10; + region_end = 0; } - for (i = segment_end - segment_start; i < MAX_REGIONS_NUMBER ; i++) + for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++) seg_distr[i] = -1; for (k = 0; k < MAX_REGIONS_NUMBER; k++) { @@ -305,10 +306,12 @@ bool cm_helper_translate_curve_to_hw_format( } j = 0; - for (k = 0; k < (segment_end - segment_start); k++) { - increment = NUMBER_SEGMENTS / (1 << seg_distr[k]); - start_index = (segment_start + k + MAX_LOW_POINT) * NUMBER_SEGMENTS; - for (i = start_index; i < start_index + NUMBER_SEGMENTS; i += increment) { + for (k = 0; k < (region_end - region_start); k++) { + increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]); + start_index = (region_start + k + MAX_LOW_POINT) * + NUMBER_SW_SEGMENTS; + for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS; + i += increment) { if (j == hw_points - 1) break; rgb_resulted[j].red = output_tf->tf_pts.red[i]; @@ -319,15 +322,15 @@ bool cm_helper_translate_curve_to_hw_format( } /* last point */ - start_index = (segment_end + MAX_LOW_POINT) * NUMBER_SEGMENTS; + start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS; rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index]; rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index]; rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index]; arr_points[0].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), - dal_fixed31_32_from_int(segment_start)); + dal_fixed31_32_from_int(region_start)); arr_points[1].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), - dal_fixed31_32_from_int(segment_end)); + dal_fixed31_32_from_int(region_end)); y_r = rgb_resulted[0].red; y_g = rgb_resulted[0].green; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c index f2a08b156cf0..8725cab9ec00 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -196,7 +196,7 @@ static void dpp1_cm_set_regamma_pwl( case OPP_REGAMMA_SRGB: re_mode = 1; break; - case OPP_REGAMMA_3_6: + case OPP_REGAMMA_XVYCC: re_mode = 2; break; case OPP_REGAMMA_USER: @@ -424,6 +424,26 @@ void dpp1_set_cursor_position( } +void dpp1_dppclk_control( + struct dpp *dpp_base, + bool dppclk_div, + bool enable) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + if (enable) { + if (dpp->tf_mask->DPPCLK_RATE_CONTROL) { + REG_UPDATE_2(DPP_CONTROL, + DPPCLK_RATE_CONTROL, dppclk_div, + DPP_CLOCK_ENABLE, 1); + } else { + ASSERT(dppclk_div == false); + REG_UPDATE(DPP_CONTROL, DPP_CLOCK_ENABLE, 1); + } + } else + REG_UPDATE(DPP_CONTROL, DPP_CLOCK_ENABLE, 0); +} + static const struct dpp_funcs dcn10_dpp_funcs = { .dpp_reset = dpp_reset, .dpp_set_scaler = dpp1_dscl_set_scaler_manual_scale, @@ -445,6 +465,7 @@ static const struct dpp_funcs dcn10_dpp_funcs = { .dpp_full_bypass = dpp1_full_bypass, .set_cursor_attributes = dpp1_set_cursor_attributes, .set_cursor_position = dpp1_set_cursor_position, + .dpp_dppclk_control = dpp1_dppclk_control, }; static struct dpp_caps dcn10_dpp_cap = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h index f56ee4d08d89..07003d9c6bba 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h @@ -112,7 +112,8 @@ SRI(CNVC_SURFACE_PIXEL_FORMAT, CNVC_CFG, id), \ SRI(CURSOR0_CONTROL, CNVC_CUR, id), \ SRI(CURSOR0_COLOR0, CNVC_CUR, id), \ - SRI(CURSOR0_COLOR1, CNVC_CUR, id) + SRI(CURSOR0_COLOR1, CNVC_CUR, id), \ + SRI(DPP_CONTROL, DPP_TOP, id) @@ -306,7 +307,8 @@ TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_EXPANSION_MODE, mask_sh), \ TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_ENABLE, mask_sh), \ TF_SF(CNVC_CUR0_CURSOR0_COLOR0, CUR0_COLOR0, mask_sh), \ - TF_SF(CNVC_CUR0_CURSOR0_COLOR1, CUR0_COLOR1, mask_sh) + TF_SF(CNVC_CUR0_CURSOR0_COLOR1, CUR0_COLOR1, mask_sh), \ + TF_SF(DPP_TOP0_DPP_CONTROL, DPP_CLOCK_ENABLE, mask_sh) #define TF_REG_LIST_SH_MASK_DCN10(mask_sh)\ TF_REG_LIST_SH_MASK_DCN(mask_sh),\ @@ -410,7 +412,8 @@ TF_SF(CURSOR0_CURSOR_CONTROL, CURSOR_MODE, mask_sh), \ TF_SF(CURSOR0_CURSOR_CONTROL, CURSOR_PITCH, mask_sh), \ TF_SF(CURSOR0_CURSOR_CONTROL, CURSOR_LINES_PER_CHUNK, mask_sh), \ - TF_SF(CURSOR0_CURSOR_CONTROL, CURSOR_ENABLE, mask_sh) + TF_SF(CURSOR0_CURSOR_CONTROL, CURSOR_ENABLE, mask_sh), \ + TF_SF(DPP_TOP0_DPP_CONTROL, DPPCLK_RATE_CONTROL, mask_sh) #define TF_REG_FIELD_LIST(type) \ type EXT_OVERSCAN_LEFT; \ @@ -1007,7 +1010,9 @@ type CM_BYPASS; \ type FORMAT_CONTROL__ALPHA_EN; \ type CUR0_COLOR0; \ - type CUR0_COLOR1; + type CUR0_COLOR1; \ + type DPPCLK_RATE_CONTROL; \ + type DPP_CLOCK_ENABLE; struct dcn_dpp_shift { TF_REG_FIELD_LIST(uint8_t) @@ -1252,7 +1257,8 @@ struct dcn_dpp_mask { uint32_t CURSOR_CONTROL; \ uint32_t CURSOR0_CONTROL; \ uint32_t CURSOR0_COLOR0; \ - uint32_t CURSOR0_COLOR1; + uint32_t CURSOR0_COLOR1; \ + uint32_t DPP_CONTROL; struct dcn_dpp_registers { DPP_COMMON_REG_VARIABLE_LIST @@ -1287,6 +1293,12 @@ void dpp1_set_cursor_attributes( struct dpp *dpp_base, enum dc_cursor_color_format color_format); +void dpp1_set_cursor_position( + struct dpp *dpp_base, + const struct dc_cursor_position *pos, + const struct dc_cursor_mi_param *param, + uint32_t width); + bool dpp1_dscl_is_lb_conf_valid( int ceil_vratio, int num_partitions, @@ -1397,6 +1409,11 @@ void dpp1_cnv_setup ( void dpp1_full_bypass(struct dpp *dpp_base); +void dpp1_dppclk_control( + struct dpp *dpp_base, + bool dppclk_div, + bool enable); + void dpp1_construct(struct dcn10_dpp *dpp1, struct dc_context *ctx, uint32_t inst, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c index a5b099023652..bd3fcdfb79c5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c @@ -193,6 +193,7 @@ void dpp1_cm_set_gamut_remap( const struct dpp_grph_csc_adjustment *adjust) { struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + int i = 0; if (adjust->gamut_adjust_type != GRAPHICS_GAMUT_ADJUST_TYPE_SW) /* Bypass if type is bypass or hw */ @@ -201,20 +202,8 @@ void dpp1_cm_set_gamut_remap( struct fixed31_32 arr_matrix[12]; uint16_t arr_reg_val[12]; - arr_matrix[0] = adjust->temperature_matrix[0]; - arr_matrix[1] = adjust->temperature_matrix[1]; - arr_matrix[2] = adjust->temperature_matrix[2]; - arr_matrix[3] = dal_fixed31_32_zero; - - arr_matrix[4] = adjust->temperature_matrix[3]; - arr_matrix[5] = adjust->temperature_matrix[4]; - arr_matrix[6] = adjust->temperature_matrix[5]; - arr_matrix[7] = dal_fixed31_32_zero; - - arr_matrix[8] = adjust->temperature_matrix[6]; - arr_matrix[9] = adjust->temperature_matrix[7]; - arr_matrix[10] = adjust->temperature_matrix[8]; - arr_matrix[11] = dal_fixed31_32_zero; + for (i = 0; i < 12; i++) + arr_matrix[i] = adjust->temperature_matrix[i]; convert_float_matrix( arr_reg_val, arr_matrix, 12); @@ -309,6 +298,32 @@ static void dpp1_cm_get_reg_field( reg->masks.exp_resion_start_segment = dpp->tf_mask->CM_RGAM_RAMB_EXP_REGION_START_SEGMENT_B; } +static void dpp1_cm_get_degamma_reg_field( + struct dcn10_dpp *dpp, + struct xfer_func_reg *reg) +{ + reg->shifts.exp_region0_lut_offset = dpp->tf_shift->CM_DGAM_RAMA_EXP_REGION0_LUT_OFFSET; + reg->masks.exp_region0_lut_offset = dpp->tf_mask->CM_DGAM_RAMA_EXP_REGION0_LUT_OFFSET; + reg->shifts.exp_region0_num_segments = dpp->tf_shift->CM_DGAM_RAMA_EXP_REGION0_NUM_SEGMENTS; + reg->masks.exp_region0_num_segments = dpp->tf_mask->CM_DGAM_RAMA_EXP_REGION0_NUM_SEGMENTS; + reg->shifts.exp_region1_lut_offset = dpp->tf_shift->CM_DGAM_RAMA_EXP_REGION1_LUT_OFFSET; + reg->masks.exp_region1_lut_offset = dpp->tf_mask->CM_DGAM_RAMA_EXP_REGION1_LUT_OFFSET; + reg->shifts.exp_region1_num_segments = dpp->tf_shift->CM_DGAM_RAMA_EXP_REGION1_NUM_SEGMENTS; + reg->masks.exp_region1_num_segments = dpp->tf_mask->CM_DGAM_RAMA_EXP_REGION1_NUM_SEGMENTS; + + reg->shifts.field_region_end = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_END_B; + reg->masks.field_region_end = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_END_B; + reg->shifts.field_region_end_slope = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_END_SLOPE_B; + reg->masks.field_region_end_slope = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_END_SLOPE_B; + reg->shifts.field_region_end_base = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_END_BASE_B; + reg->masks.field_region_end_base = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_END_BASE_B; + reg->shifts.field_region_linear_slope = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B; + reg->masks.field_region_linear_slope = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B; + reg->shifts.exp_region_start = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_START_B; + reg->masks.exp_region_start = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_START_B; + reg->shifts.exp_resion_start_segment = dpp->tf_shift->CM_DGAM_RAMB_EXP_REGION_START_SEGMENT_B; + reg->masks.exp_resion_start_segment = dpp->tf_mask->CM_DGAM_RAMB_EXP_REGION_START_SEGMENT_B; +} void dpp1_cm_set_output_csc_adjustment( struct dpp *dpp_base, const uint16_t *regval) @@ -513,7 +528,7 @@ void dpp1_program_degamma_lutb_settings( struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); struct xfer_func_reg gam_regs; - dpp1_cm_get_reg_field(dpp, &gam_regs); + dpp1_cm_get_degamma_reg_field(dpp, &gam_regs); gam_regs.start_cntl_b = REG(CM_DGAM_RAMB_START_CNTL_B); gam_regs.start_cntl_g = REG(CM_DGAM_RAMB_START_CNTL_G); @@ -542,7 +557,7 @@ void dpp1_program_degamma_luta_settings( struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); struct xfer_func_reg gam_regs; - dpp1_cm_get_reg_field(dpp, &gam_regs); + dpp1_cm_get_degamma_reg_field(dpp, &gam_regs); gam_regs.start_cntl_b = REG(CM_DGAM_RAMA_START_CNTL_B); gam_regs.start_cntl_g = REG(CM_DGAM_RAMA_START_CNTL_G); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c index 585b33384002..39b72f696ae9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -73,6 +73,9 @@ static void hubp1_disconnect(struct hubp *hubp) REG_UPDATE(DCHUBP_CNTL, HUBP_TTU_DISABLE, 1); + + REG_UPDATE(CURSOR_CONTROL, + CURSOR_ENABLE, 0); } static void hubp1_set_hubp_blank_en(struct hubp *hubp, bool blank) @@ -296,8 +299,9 @@ bool hubp1_program_surface_flip_and_addr( if (address->grph.addr.quad_part == 0) break; - REG_UPDATE(DCSURF_SURFACE_CONTROL, - PRIMARY_SURFACE_TMZ, address->tmz_surface); + REG_UPDATE_2(DCSURF_SURFACE_CONTROL, + PRIMARY_SURFACE_TMZ, address->tmz_surface, + PRIMARY_META_SURFACE_TMZ, address->tmz_surface); if (address->grph.meta_addr.quad_part != 0) { REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH, 0, @@ -322,8 +326,11 @@ bool hubp1_program_surface_flip_and_addr( || address->video_progressive.chroma_addr.quad_part == 0) break; - REG_UPDATE(DCSURF_SURFACE_CONTROL, - PRIMARY_SURFACE_TMZ, address->tmz_surface); + REG_UPDATE_4(DCSURF_SURFACE_CONTROL, + PRIMARY_SURFACE_TMZ, address->tmz_surface, + PRIMARY_SURFACE_TMZ_C, address->tmz_surface, + PRIMARY_META_SURFACE_TMZ, address->tmz_surface, + PRIMARY_META_SURFACE_TMZ_C, address->tmz_surface); if (address->video_progressive.luma_meta_addr.quad_part != 0) { REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH_C, 0, @@ -365,8 +372,11 @@ bool hubp1_program_surface_flip_and_addr( if (address->grph_stereo.right_addr.quad_part == 0) break; - REG_UPDATE(DCSURF_SURFACE_CONTROL, - PRIMARY_SURFACE_TMZ, address->tmz_surface); + REG_UPDATE_4(DCSURF_SURFACE_CONTROL, + PRIMARY_SURFACE_TMZ, address->tmz_surface, + PRIMARY_SURFACE_TMZ_C, address->tmz_surface, + PRIMARY_META_SURFACE_TMZ, address->tmz_surface, + PRIMARY_META_SURFACE_TMZ_C, address->tmz_surface); if (address->grph_stereo.right_meta_addr.quad_part != 0) { @@ -909,6 +919,21 @@ void hubp1_cursor_set_position( /* TODO Handle surface pixel formats other than 4:4:4 */ } +void hubp1_clk_cntl(struct hubp *hubp, bool enable) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + uint32_t clk_enable = enable ? 1 : 0; + + REG_UPDATE(HUBP_CLK_CNTL, HUBP_CLOCK_ENABLE, clk_enable); +} + +void hubp1_vtg_sel(struct hubp *hubp, uint32_t otg_inst) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + + REG_UPDATE(DCHUBP_CNTL, HUBP_VTG_SEL, otg_inst); +} + static struct hubp_funcs dcn10_hubp_funcs = { .hubp_program_surface_flip_and_addr = hubp1_program_surface_flip_and_addr, @@ -925,6 +950,8 @@ static struct hubp_funcs dcn10_hubp_funcs = { .set_cursor_attributes = hubp1_cursor_set_attributes, .set_cursor_position = hubp1_cursor_set_position, .hubp_disconnect = hubp1_disconnect, + .hubp_clk_cntl = hubp1_clk_cntl, + .hubp_vtg_sel = hubp1_vtg_sel, }; /*****************************************/ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h index 33e91d9c010f..4a3703e12ea1 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h @@ -96,7 +96,8 @@ SRI(DCN_SURF0_TTU_CNTL1, HUBPREQ, id),\ SRI(DCN_SURF1_TTU_CNTL0, HUBPREQ, id),\ SRI(DCN_SURF1_TTU_CNTL1, HUBPREQ, id),\ - SRI(DCN_VM_MX_L1_TLB_CNTL, HUBPREQ, id) + SRI(DCN_VM_MX_L1_TLB_CNTL, HUBPREQ, id),\ + SRI(HUBP_CLK_CNTL, HUBP, id) #define HUBP_REG_LIST_DCN10(id)\ HUBP_REG_LIST_DCN(id),\ @@ -230,7 +231,8 @@ uint32_t CURSOR_CONTROL; \ uint32_t CURSOR_POSITION; \ uint32_t CURSOR_HOT_SPOT; \ - uint32_t CURSOR_DST_OFFSET + uint32_t CURSOR_DST_OFFSET; \ + uint32_t HUBP_CLK_CNTL #define HUBP_SF(reg_name, field_name, post_fix)\ .field_name = reg_name ## __ ## field_name ## post_fix @@ -240,6 +242,7 @@ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_TTU_DISABLE, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_UNDERFLOW_STATUS, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_NO_OUTSTANDING_REQ, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_VTG_SEL, mask_sh),\ HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, NUM_PIPES, mask_sh),\ HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, NUM_BANKS, mask_sh),\ HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, PIPE_INTERLEAVE, mask_sh),\ @@ -293,6 +296,9 @@ HUBP_SF(HUBPREQ0_DCSURF_SURFACE_EARLIEST_INUSE_C, SURFACE_EARLIEST_INUSE_ADDRESS_C, mask_sh),\ HUBP_SF(HUBPREQ0_DCSURF_SURFACE_EARLIEST_INUSE_HIGH_C, SURFACE_EARLIEST_INUSE_ADDRESS_HIGH_C, mask_sh),\ HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_TMZ, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_TMZ_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_META_SURFACE_TMZ, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_META_SURFACE_TMZ_C, mask_sh),\ HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_DCC_EN, mask_sh),\ HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_DCC_IND_64B_BLK, mask_sh),\ HUBP_SF(HUBPRET0_HUBPRET_CONTROL, DET_BUF_PLANE1_BASE_ADDRESS, mask_sh),\ @@ -352,7 +358,8 @@ HUBP_SF(HUBPREQ0_DCN_SURF0_TTU_CNTL0, QoS_RAMP_DISABLE, mask_sh),\ HUBP_SF(HUBPREQ0_DCN_SURF0_TTU_CNTL1, REFCYC_PER_REQ_DELIVERY_PRE, mask_sh),\ HUBP_SF(HUBPREQ0_DCN_VM_MX_L1_TLB_CNTL, ENABLE_L1_TLB, mask_sh),\ - HUBP_SF(HUBPREQ0_DCN_VM_MX_L1_TLB_CNTL, SYSTEM_ACCESS_MODE, mask_sh) + HUBP_SF(HUBPREQ0_DCN_VM_MX_L1_TLB_CNTL, SYSTEM_ACCESS_MODE, mask_sh),\ + HUBP_SF(HUBP0_HUBP_CLK_CNTL, HUBP_CLOCK_ENABLE, mask_sh) #define HUBP_MASK_SH_LIST_DCN10(mask_sh)\ HUBP_MASK_SH_LIST_DCN(mask_sh),\ @@ -398,6 +405,7 @@ type HUBP_BLANK_EN;\ type HUBP_TTU_DISABLE;\ type HUBP_NO_OUTSTANDING_REQ;\ + type HUBP_VTG_SEL;\ type HUBP_UNDERFLOW_STATUS;\ type NUM_PIPES;\ type NUM_BANKS;\ @@ -452,6 +460,13 @@ type SURFACE_EARLIEST_INUSE_ADDRESS_C;\ type SURFACE_EARLIEST_INUSE_ADDRESS_HIGH_C;\ type PRIMARY_SURFACE_TMZ;\ + type PRIMARY_SURFACE_TMZ_C;\ + type SECONDARY_SURFACE_TMZ;\ + type SECONDARY_SURFACE_TMZ_C;\ + type PRIMARY_META_SURFACE_TMZ;\ + type PRIMARY_META_SURFACE_TMZ_C;\ + type SECONDARY_META_SURFACE_TMZ;\ + type SECONDARY_META_SURFACE_TMZ_C;\ type PRIMARY_SURFACE_DCC_EN;\ type PRIMARY_SURFACE_DCC_IND_64B_BLK;\ type DET_BUF_PLANE1_BASE_ADDRESS;\ @@ -524,6 +539,7 @@ type VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_LSB;\ type ENABLE_L1_TLB;\ type SYSTEM_ACCESS_MODE;\ + type HUBP_CLOCK_ENABLE;\ type MC_VM_SYSTEM_APERTURE_DEFAULT_SYSTEM;\ type MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB;\ type MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB;\ @@ -653,6 +669,9 @@ void min_set_viewport(struct hubp *hubp, const struct rect *viewport, const struct rect *viewport_c); +void hubp1_clk_cntl(struct hubp *hubp, bool enable); +void hubp1_vtg_sel(struct hubp *hubp, uint32_t otg_inst); + void dcn10_hubp_construct( struct dcn10_hubp *hubp1, struct dc_context *ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 82572863acab..29dc37fbdb26 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -133,7 +133,7 @@ void dcn10_log_hw_state(struct dc *dc) DTN_INFO("[%d]:\t %xh \t %xh \t %d \t %d \t " "%xh \t %xh \t %xh \t " "%d \t %d \t %d \t %xh \t", - i, + hubp->inst, s.pixel_format, s.inuse_addr_hi, s.viewport_width, @@ -155,7 +155,7 @@ void dcn10_log_hw_state(struct dc *dc) DTN_INFO("OTG:\t v_bs \t v_be \t v_ss \t v_se \t vpol \t vmax \t vmin \t " "h_bs \t h_be \t h_ss \t h_se \t hpol \t htot \t vtot \t underflow\n"); - for (i = 0; i < pool->res_cap->num_timing_generator; i++) { + for (i = 0; i < pool->timing_generator_count; i++) { struct timing_generator *tg = pool->timing_generators[i]; struct dcn_otg_state s = {0}; @@ -168,7 +168,7 @@ void dcn10_log_hw_state(struct dc *dc) DTN_INFO("[%d]:\t %d \t %d \t %d \t %d \t " "%d \t %d \t %d \t %d \t %d \t %d \t " "%d \t %d \t %d \t %d \t %d \t ", - i, + tg->inst, s.v_blank_start, s.v_blank_end, s.v_sync_a_start, @@ -193,26 +193,6 @@ void dcn10_log_hw_state(struct dc *dc) DTN_INFO_END(); } -static void enable_dppclk( - struct dce_hwseq *hws, - uint8_t plane_id, - uint32_t requested_pix_clk, - bool dppclk_div) -{ - dm_logger_write(hws->ctx->logger, LOG_SURFACE, - "dppclk_rate_control for pipe %d programed to %d\n", - plane_id, - dppclk_div); - - if (hws->shifts->DPPCLK_RATE_CONTROL) - REG_UPDATE_2(DPP_CONTROL[plane_id], - DPPCLK_RATE_CONTROL, dppclk_div, - DPP_CLOCK_ENABLE, 1); - else - REG_UPDATE(DPP_CONTROL[plane_id], - DPP_CLOCK_ENABLE, 1); -} - static void enable_power_gating_plane( struct dce_hwseq *hws, bool enable) @@ -597,29 +577,22 @@ static void dcn10_verify_allow_pstate_change_high(struct dc *dc) /* trigger HW to start disconnect plane from stream on the next vsync */ static void plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) { - int fe_idx = pipe_ctx->pipe_idx; - struct hubp *hubp = dc->res_pool->hubps[fe_idx]; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + int dpp_id = pipe_ctx->plane_res.dpp->inst; struct mpc *mpc = dc->res_pool->mpc; - int opp_id; struct mpc_tree *mpc_tree_params; struct mpcc *mpcc_to_remove = NULL; + struct output_pixel_processor *opp = pipe_ctx->stream_res.opp; - /* look at tree rather than mi here to know if we already reset */ - for (opp_id = 0; opp_id < dc->res_pool->pipe_count; opp_id++) { - struct output_pixel_processor *opp = dc->res_pool->opps[opp_id]; - - mpc_tree_params = &(opp->mpc_tree_params); - mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, fe_idx); - if (mpcc_to_remove != NULL) - break; - } + mpc_tree_params = &(opp->mpc_tree_params); + mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id); /*Already reset*/ - if (opp_id == dc->res_pool->pipe_count) + if (mpcc_to_remove == NULL) return; mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove); - dc->res_pool->opps[opp_id]->mpcc_disconnect_pending[fe_idx] = true; + opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; dc->optimized_required = true; @@ -630,21 +603,21 @@ static void plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) dcn10_verify_allow_pstate_change_high(dc); } -static void plane_atomic_power_down(struct dc *dc, int fe_idx) +static void plane_atomic_power_down(struct dc *dc, struct pipe_ctx *pipe_ctx) { struct dce_hwseq *hws = dc->hwseq; - struct dpp *dpp = dc->res_pool->dpps[fe_idx]; + struct dpp *dpp = pipe_ctx->plane_res.dpp; if (REG(DC_IP_REQUEST_CNTL)) { REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - dpp_pg_control(hws, fe_idx, false); - hubp_pg_control(hws, fe_idx, false); + dpp_pg_control(hws, dpp->inst, false); + hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, false); dpp->funcs->dpp_reset(dpp); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); dm_logger_write(dc->ctx->logger, LOG_DEBUG, - "Power gated front end %d\n", fe_idx); + "Power gated front end %d\n", pipe_ctx->pipe_idx); } } @@ -653,26 +626,25 @@ static void plane_atomic_power_down(struct dc *dc, int fe_idx) */ static void plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) { - int fe_idx = pipe_ctx->pipe_idx; - struct dce_hwseq *hws = dc->hwseq; - struct hubp *hubp = dc->res_pool->hubps[fe_idx]; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct dpp *dpp = pipe_ctx->plane_res.dpp; int opp_id = hubp->opp_id; dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx); - REG_UPDATE(HUBP_CLK_CNTL[fe_idx], - HUBP_CLOCK_ENABLE, 0); - REG_UPDATE(DPP_CONTROL[fe_idx], - DPP_CLOCK_ENABLE, 0); + hubp->funcs->hubp_clk_cntl(hubp, false); - if (opp_id != 0xf && dc->res_pool->opps[opp_id]->mpc_tree_params.opp_list == NULL) - REG_UPDATE(OPP_PIPE_CONTROL[opp_id], - OPP_PIPE_CLOCK_EN, 0); + dpp->funcs->dpp_dppclk_control(dpp, false, false); + + if (opp_id != 0xf && pipe_ctx->stream_res.opp->mpc_tree_params.opp_list == NULL) + pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( + pipe_ctx->stream_res.opp, + false); hubp->power_gated = true; dc->optimized_required = false; /* We're powering off, no need to optimize */ - plane_atomic_power_down(dc, fe_idx); + plane_atomic_power_down(dc, pipe_ctx); pipe_ctx->stream = NULL; memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); @@ -684,7 +656,7 @@ static void plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) static void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) { - if (dc->res_pool->hubps[pipe_ctx->pipe_idx]->power_gated) + if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) return; plane_atomic_disable(dc, pipe_ctx); @@ -720,26 +692,25 @@ static void dcn10_init_hw(struct dc *dc) } enable_power_gating_plane(dc->hwseq, true); - return; - } - /* end of FPGA. Below if real ASIC */ + } else { - if (!dcb->funcs->is_accelerated_mode(dcb)) { - bios_golden_init(dc); - disable_vga(dc->hwseq); - } + if (!dcb->funcs->is_accelerated_mode(dcb)) { + bios_golden_init(dc); + disable_vga(dc->hwseq); + } - for (i = 0; i < dc->link_count; i++) { - /* Power up AND update implementation according to the - * required signal (which may be different from the - * default signal on connector). - */ - struct dc_link *link = dc->links[i]; + for (i = 0; i < dc->link_count; i++) { + /* Power up AND update implementation according to the + * required signal (which may be different from the + * default signal on connector). + */ + struct dc_link *link = dc->links[i]; - if (link->link_enc->connector.id == CONNECTOR_ID_EDP) - dc->hwss.edp_power_control(link, true); + if (link->link_enc->connector.id == CONNECTOR_ID_EDP) + dc->hwss.edp_power_control(link, true); - link->link_enc->funcs->hw_init(link->link_enc); + link->link_enc->funcs->hw_init(link->link_enc); + } } for (i = 0; i < dc->res_pool->pipe_count; i++) { @@ -768,18 +739,21 @@ static void dcn10_init_hw(struct dc *dc) struct timing_generator *tg = dc->res_pool->timing_generators[i]; struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; struct hubp *hubp = dc->res_pool->hubps[i]; + struct dpp *dpp = dc->res_pool->dpps[i]; pipe_ctx->stream_res.tg = tg; pipe_ctx->pipe_idx = i; pipe_ctx->plane_res.hubp = hubp; - hubp->mpcc_id = i; + pipe_ctx->plane_res.dpp = dpp; + pipe_ctx->plane_res.mpcc_inst = dpp->inst; + hubp->mpcc_id = dpp->inst; hubp->opp_id = 0xf; hubp->power_gated = false; dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; - dc->res_pool->opps[i]->mpcc_disconnect_pending[i] = true; + dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; plane_atomic_disconnect(dc, pipe_ctx); @@ -804,6 +778,10 @@ static void dcn10_init_hw(struct dc *dc) tg->funcs->tg_init(tg); } + /* end of FPGA. Below if real ASIC */ + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) + return; + for (i = 0; i < dc->res_pool->audio_count; i++) { struct audio *audio = dc->res_pool->audios[i]; @@ -922,7 +900,10 @@ static bool dcn10_set_input_transfer_func(struct pipe_ctx *pipe_ctx, if (plane_state->in_transfer_func) tf = plane_state->in_transfer_func; - if (plane_state->gamma_correction && dce_use_lut(plane_state)) + if (plane_state->gamma_correction && + plane_state->gamma_correction->is_identity) + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); + else if (plane_state->gamma_correction && dce_use_lut(plane_state->format)) dpp_base->funcs->dpp_program_input_lut(dpp_base, plane_state->gamma_correction); if (tf == NULL) @@ -993,8 +974,6 @@ static void dcn10_pipe_control_lock( struct pipe_ctx *pipe, bool lock) { - struct hubp *hubp = NULL; - hubp = dc->res_pool->hubps[pipe->pipe_idx]; /* use TG master update lock to lock everything on the TG * therefore only top pipe need to lock */ @@ -1097,7 +1076,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( DC_SYNC_INFO("Waiting for trigger\n"); - for (i = 1; i < group_size; i++) + for (i = 0; i < group_size; i++) wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg); DC_SYNC_INFO("Multi-display sync is complete\n"); @@ -1323,15 +1302,15 @@ static void dcn10_enable_plane( undo_DEGVIDCN10_253_wa(dc); power_on_plane(dc->hwseq, - pipe_ctx->pipe_idx); + pipe_ctx->plane_res.hubp->inst); /* enable DCFCLK current DCHUB */ - REG_UPDATE(HUBP_CLK_CNTL[pipe_ctx->pipe_idx], - HUBP_CLOCK_ENABLE, 1); + pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true); /* make sure OPP_PIPE_CLOCK_EN = 1 */ - REG_UPDATE(OPP_PIPE_CONTROL[pipe_ctx->stream_res.tg->inst], - OPP_PIPE_CLOCK_EN, 1); + pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( + pipe_ctx->stream_res.opp, + true); /* TODO: enable/disable in dm as per update type. if (plane_state) { @@ -1380,6 +1359,7 @@ static void dcn10_enable_plane( static void program_gamut_remap(struct pipe_ctx *pipe_ctx) { + int i = 0; struct dpp_grph_csc_adjustment adjust; memset(&adjust, 0, sizeof(adjust)); adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; @@ -1387,33 +1367,9 @@ static void program_gamut_remap(struct pipe_ctx *pipe_ctx) if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; - adjust.temperature_matrix[0] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[0]; - adjust.temperature_matrix[1] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[1]; - adjust.temperature_matrix[2] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[2]; - adjust.temperature_matrix[3] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[4]; - adjust.temperature_matrix[4] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[5]; - adjust.temperature_matrix[5] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[6]; - adjust.temperature_matrix[6] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[8]; - adjust.temperature_matrix[7] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[9]; - adjust.temperature_matrix[8] = - pipe_ctx->stream-> - gamut_remap_matrix.matrix[10]; + for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) + adjust.temperature_matrix[i] = + pipe_ctx->stream->gamut_remap_matrix.matrix[i]; } pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust); @@ -1474,7 +1430,7 @@ static bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx) return false; } -static bool is_rgb_cspace(enum dc_color_space output_color_space) +bool is_rgb_cspace(enum dc_color_space output_color_space) { switch (output_color_space) { case COLOR_SPACE_SRGB: @@ -1702,7 +1658,6 @@ static void update_dchubp_dpp( struct pipe_ctx *pipe_ctx, struct dc_state *context) { - struct dce_hwseq *hws = dc->hwseq; struct hubp *hubp = pipe_ctx->plane_res.hubp; struct dpp *dpp = pipe_ctx->plane_res.dpp; struct dc_plane_state *plane_state = pipe_ctx->plane_state; @@ -1710,11 +1665,11 @@ static void update_dchubp_dpp( /* depends on DML calculation, DPP clock value may change dynamically */ if (plane_state->update_flags.bits.full_update) { - enable_dppclk( - dc->hwseq, - pipe_ctx->pipe_idx, - pipe_ctx->stream_res.pix_clk_params.requested_pix_clk, - context->bw.dcn.calc_clk.dppclk_div); + dpp->funcs->dpp_dppclk_control( + dpp, + context->bw.dcn.calc_clk.dppclk_div, + true); + dc->current_state->bw.dcn.cur_clk.dppclk_div = context->bw.dcn.calc_clk.dppclk_div; context->bw.dcn.cur_clk.dppclk_div = context->bw.dcn.calc_clk.dppclk_div; @@ -1725,7 +1680,7 @@ static void update_dchubp_dpp( * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG */ if (plane_state->update_flags.bits.full_update) { - REG_UPDATE(DCHUBP_CNTL[pipe_ctx->pipe_idx], HUBP_VTG_SEL, pipe_ctx->stream_res.tg->inst); + hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst); hubp->funcs->hubp_setup( hubp, @@ -1761,6 +1716,11 @@ static void update_dchubp_dpp( &pipe_ctx->plane_res.scl_data.viewport_c); } + if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) { + dc->hwss.set_cursor_position(pipe_ctx); + dc->hwss.set_cursor_attribute(pipe_ctx); + } + if (plane_state->update_flags.bits.full_update) { /*gamut remap*/ program_gamut_remap(pipe_ctx); @@ -1773,6 +1733,7 @@ static void update_dchubp_dpp( } if (plane_state->update_flags.bits.full_update || + plane_state->update_flags.bits.pixel_format_change || plane_state->update_flags.bits.horizontal_mirror_change || plane_state->update_flags.bits.rotation_change || plane_state->update_flags.bits.swizzle_change || @@ -1822,15 +1783,14 @@ static void program_all_pipe_in_tree( } if (pipe_ctx->plane_state != NULL) { - struct pipe_ctx *cur_pipe_ctx = - &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx]; - if (pipe_ctx->plane_state->update_flags.bits.full_update) dcn10_enable_plane(dc, pipe_ctx, context); update_dchubp_dpp(dc, pipe_ctx, context); - if (cur_pipe_ctx->plane_state != pipe_ctx->plane_state) + if (pipe_ctx->plane_state->update_flags.bits.full_update || + pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || + pipe_ctx->plane_state->update_flags.bits.gamma_change) dc->hwss.set_input_transfer_func(pipe_ctx, pipe_ctx->plane_state); /* dcn10_translate_regamma_to_hw_format takes 750us to finish @@ -1940,7 +1900,7 @@ static void dcn10_apply_ctx_for_surface( tg = top_pipe_to_program->stream_res.tg; - tg->funcs->lock(tg); + dcn10_pipe_control_lock(dc, top_pipe_to_program, true); if (num_planes == 0) { @@ -1989,7 +1949,7 @@ static void dcn10_apply_ctx_for_surface( if (num_planes > 0) program_all_pipe_in_tree(dc, top_pipe_to_program, context); - tg->funcs->unlock(tg); + dcn10_pipe_control_lock(dc, top_pipe_to_program, false); if (num_planes == 0) false_optc_underflow_wa(dc, stream, tg); @@ -2184,6 +2144,8 @@ static void set_static_screen_control(struct pipe_ctx **pipe_ctx, value |= 0x80; if (events->cursor_update) value |= 0x2; + if (events->force_trigger) + value |= 0x1; for (i = 0; i < num_pipes; i++) pipe_ctx[i]->stream_res.tg->funcs-> @@ -2256,12 +2218,24 @@ static void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc) return; } +static struct hubp *get_hubp_by_inst(struct resource_pool *res_pool, int mpcc_inst) +{ + int i; + + for (i = 0; i < res_pool->pipe_count; i++) { + if (res_pool->hubps[i]->inst == mpcc_inst) + return res_pool->hubps[i]; + } + ASSERT(false); + return NULL; +} + static void dcn10_wait_for_mpcc_disconnect( struct dc *dc, struct resource_pool *res_pool, struct pipe_ctx *pipe_ctx) { - int i; + int mpcc_inst; if (dc->debug.sanity_checks) { dcn10_verify_allow_pstate_change_high(dc); @@ -2270,11 +2244,13 @@ static void dcn10_wait_for_mpcc_disconnect( if (!pipe_ctx->stream_res.opp) return; - for (i = 0; i < MAX_PIPES; i++) { - if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[i]) { - res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, i); - pipe_ctx->stream_res.opp->mpcc_disconnect_pending[i] = false; - res_pool->hubps[i]->funcs->set_blank(res_pool->hubps[i], true); + for (mpcc_inst = 0; mpcc_inst < MAX_PIPES; mpcc_inst++) { + if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst]) { + struct hubp *hubp = get_hubp_by_inst(res_pool, mpcc_inst); + + res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, mpcc_inst); + pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false; + hubp->funcs->set_blank(hubp, true); /*dm_logger_write(dc->ctx->logger, LOG_ERROR, "[debug_mpo: wait_for_mpcc finished waiting on mpcc %d]\n", i);*/ @@ -2296,7 +2272,7 @@ static bool dcn10_dummy_display_power_gating( return true; } -void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) +static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) { struct dc_plane_state *plane_state = pipe_ctx->plane_state; struct timing_generator *tg = pipe_ctx->stream_res.tg; @@ -2316,12 +2292,46 @@ void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) } } -void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) +static void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) { if (hws->ctx->dc->res_pool->hubbub != NULL) hubbub1_update_dchub(hws->ctx->dc->res_pool->hubbub, dh_data); } +static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) +{ + struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct dpp *dpp = pipe_ctx->plane_res.dpp; + struct dc_cursor_mi_param param = { + .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz, + .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz, + .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, + .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, + .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz + }; + + if (pipe_ctx->plane_state->address.type + == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) + pos_cpy.enable = false; + + if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) + pos_cpy.enable = false; + + hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); + dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width); +} + +static void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) +{ + struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; + + pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( + pipe_ctx->plane_res.hubp, attributes); + pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( + pipe_ctx->plane_res.dpp, attributes->color_format); +} + static const struct hw_sequencer_funcs dcn10_funcs = { .program_gamut_remap = program_gamut_remap, .program_csc_matrix = program_csc_matrix, @@ -2342,6 +2352,7 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .enable_stream = dce110_enable_stream, .disable_stream = dce110_disable_stream, .unblank_stream = dce110_unblank_stream, + .blank_stream = dce110_blank_stream, .enable_display_power_gating = dcn10_dummy_display_power_gating, .disable_plane = dcn10_disable_plane, .pipe_control_lock = dcn10_pipe_control_lock, @@ -2362,6 +2373,8 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .edp_backlight_control = hwss_edp_backlight_control, .edp_power_control = hwss_edp_power_control, .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, + .set_cursor_position = dcn10_set_cursor_position, + .set_cursor_attribute = dcn10_set_cursor_attribute }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h index b9d326082717..6c526b5095d9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h @@ -35,5 +35,6 @@ extern void fill_display_configs( const struct dc_state *context, struct dm_pp_display_configuration *pp_display_cfg); +bool is_rgb_cspace(enum dc_color_space output_color_space); #endif /* __DC_HWSS_DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h index d7b5bd20352a..819b749c6e31 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h @@ -33,7 +33,6 @@ #define IPP_REG_LIST_DCN(id) \ SRI(FORMAT_CONTROL, CNVC_CFG, id), \ - SRI(DPP_CONTROL, DPP_TOP, id), \ SRI(CNVC_SURFACE_PIXEL_FORMAT, CNVC_CFG, id), \ SRI(CURSOR0_CONTROL, CNVC_CUR, id), \ SRI(CURSOR0_COLOR0, CNVC_CUR, id), \ @@ -130,7 +129,6 @@ struct dcn10_ipp_mask { }; struct dcn10_ipp_registers { - uint32_t DPP_CONTROL; uint32_t CURSOR_SETTINS; uint32_t CURSOR_SETTINGS; uint32_t CNVC_SURFACE_PIXEL_FORMAT; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c index f6ba0eef4489..77a1a9d541a4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c @@ -367,6 +367,14 @@ void opp1_program_oppbuf( } +void opp1_pipe_clock_control(struct output_pixel_processor *opp, bool enable) +{ + struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp); + uint32_t regval = enable ? 1 : 0; + + REG_UPDATE(OPP_PIPE_CONTROL, OPP_PIPE_CLOCK_EN, regval); +} + /*****************************************/ /* Constructor, Destructor */ /*****************************************/ @@ -382,6 +390,7 @@ static struct opp_funcs dcn10_opp_funcs = { .opp_program_fmt = opp1_program_fmt, .opp_program_bit_depth_reduction = opp1_program_bit_depth_reduction, .opp_program_stereo = opp1_program_stereo, + .opp_pipe_clock_control = opp1_pipe_clock_control, .opp_destroy = opp1_destroy }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.h index bc5058af6266..0f10adea000c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.h @@ -44,7 +44,8 @@ SRI(FMT_MAP420_MEMORY_CONTROL, FMT, id), \ SRI(OPPBUF_CONTROL, OPPBUF, id),\ SRI(OPPBUF_3D_PARAMETERS_0, OPPBUF, id), \ - SRI(OPPBUF_3D_PARAMETERS_1, OPPBUF, id) + SRI(OPPBUF_3D_PARAMETERS_1, OPPBUF, id), \ + SRI(OPP_PIPE_CONTROL, OPP_PIPE, id) #define OPP_REG_LIST_DCN10(id) \ OPP_REG_LIST_DCN(id) @@ -61,7 +62,8 @@ uint32_t OPPBUF_CONTROL; \ uint32_t OPPBUF_CONTROL1; \ uint32_t OPPBUF_3D_PARAMETERS_0; \ - uint32_t OPPBUF_3D_PARAMETERS_1 + uint32_t OPPBUF_3D_PARAMETERS_1; \ + uint32_t OPP_PIPE_CONTROL #define OPP_MASK_SH_LIST_DCN(mask_sh) \ OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_EN, mask_sh), \ @@ -89,7 +91,8 @@ OPP_SF(OPPBUF0_OPPBUF_CONTROL, OPPBUF_ACTIVE_WIDTH, mask_sh),\ OPP_SF(OPPBUF0_OPPBUF_CONTROL, OPPBUF_PIXEL_REPETITION, mask_sh),\ OPP_SF(OPPBUF0_OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE1_SIZE, mask_sh), \ - OPP_SF(OPPBUF0_OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE2_SIZE, mask_sh) + OPP_SF(OPPBUF0_OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE2_SIZE, mask_sh), \ + OPP_SF(OPP_PIPE0_OPP_PIPE_CONTROL, OPP_PIPE_CLOCK_EN, mask_sh) #define OPP_MASK_SH_LIST_DCN10(mask_sh) \ OPP_MASK_SH_LIST_DCN(mask_sh), \ @@ -125,7 +128,8 @@ type OPPBUF_OVERLAP_PIXEL_NUM;\ type OPPBUF_NUM_SEGMENT_PADDED_PIXELS; \ type OPPBUF_3D_VACT_SPACE1_SIZE; \ - type OPPBUF_3D_VACT_SPACE2_SIZE + type OPPBUF_3D_VACT_SPACE2_SIZE; \ + type OPP_PIPE_CLOCK_EN struct dcn10_opp_registers { OPP_COMMON_REG_VARIABLE_LIST; @@ -176,6 +180,8 @@ void opp1_program_stereo( bool enable, const struct dc_crtc_timing *timing); +void opp1_pipe_clock_control(struct output_pixel_processor *opp, bool enable); + void opp1_destroy(struct output_pixel_processor **opp); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h index a3c7c2012f05..014543235df8 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -131,7 +131,6 @@ struct dcn_optc_registers { uint32_t OTG_GSL_WINDOW_X; uint32_t OTG_GSL_WINDOW_Y; uint32_t OTG_VUPDATE_KEEPOUT; - uint32_t OTG_DSC_START_POSITION; }; #define TG_COMMON_MASK_SH_LIST_DCN(mask_sh)\ @@ -241,7 +240,7 @@ struct dcn_optc_registers { SF(OTG0_OTG_TEST_PATTERN_COLOR, OTG_TEST_PATTERN_DATA, mask_sh),\ SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SRC_SEL, mask_sh) -#define TG_REG_FIELD_LIST(type) \ +#define TG_REG_FIELD_LIST_DCN1_0(type) \ type VSTARTUP_START;\ type VUPDATE_OFFSET;\ type VUPDATE_WIDTH;\ @@ -352,10 +351,11 @@ struct dcn_optc_registers { type OTG_MASTER_UPDATE_LOCK_GSL_EN;\ type MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET;\ type MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET;\ - type OTG_DSC_START_POSITION_X;\ - type OTG_DSC_START_POSITION_LINE_NUM;\ type OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN; +#define TG_REG_FIELD_LIST(type) \ + TG_REG_FIELD_LIST_DCN1_0(type) + struct dcn_optc_shift { TG_REG_FIELD_LIST(uint8_t) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 44825e2c9ebb..c4a564cb56b9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -50,7 +50,8 @@ #include "dcn10_hubp.h" #include "dcn10_hubbub.h" -#include "soc15ip.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" #include "dcn/dcn_1_0_offset.h" #include "dcn/dcn_1_0_sh_mask.h" @@ -365,6 +366,7 @@ static const struct dcn_optc_mask tg_mask = { static const struct bios_registers bios_regs = { + NBIO_SR(BIOS_SCRATCH_3), NBIO_SR(BIOS_SCRATCH_6) }; @@ -450,6 +452,7 @@ static const struct dc_debug debug_defaults_drv = { .disable_stereo_support = true, .vsr_support = true, .performance_trace = false, + .az_endpoint_mute_only = true, }; static const struct dc_debug debug_defaults_diags = { @@ -818,7 +821,7 @@ static void get_pixel_clock_parameters( pixel_clk_params->requested_pix_clk = stream->timing.pix_clk_khz; pixel_clk_params->encoder_object_id = stream->sink->link->link_enc->id; pixel_clk_params->signal_type = pipe_ctx->stream->signal; - pixel_clk_params->controller_id = pipe_ctx->pipe_idx + 1; + pixel_clk_params->controller_id = pipe_ctx->stream_res.tg->inst + 1; /* TODO: un-hardcode*/ pixel_clk_params->requested_sym_clk = LINK_RATE_LOW * LINK_RATE_REF_FREQ_IN_KHZ; @@ -965,6 +968,7 @@ static struct pipe_ctx *dcn10_acquire_idle_pipe_for_layer( idle_pipe->plane_res.hubp = pool->hubps[idle_pipe->pipe_idx]; idle_pipe->plane_res.ipp = pool->ipps[idle_pipe->pipe_idx]; idle_pipe->plane_res.dpp = pool->dpps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.mpcc_inst = pool->dpps[idle_pipe->pipe_idx]->inst; return idle_pipe; } @@ -1316,13 +1320,11 @@ static bool construct( } } - if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { - pool->base.display_clock = dce120_disp_clk_create(ctx); - if (pool->base.display_clock == NULL) { - dm_error("DC: failed to create display clock!\n"); - BREAK_TO_DEBUGGER(); - goto fail; - } + pool->base.display_clock = dce120_disp_clk_create(ctx); + if (pool->base.display_clock == NULL) { + dm_error("DC: failed to create display clock!\n"); + BREAK_TO_DEBUGGER(); + goto fail; } pool->base.dmcu = dcn10_dmcu_create(ctx, @@ -1445,6 +1447,7 @@ static bool construct( /* valid pipe num */ pool->base.pipe_count = j; + pool->base.timing_generator_count = j; /* within dml lib, it is hard code to 4. If ASIC pipe is fused, * the value may be changed diff --git a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h index bbfa83252fc1..eac4bfe12257 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h +++ b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h @@ -91,7 +91,8 @@ struct pp_smu_funcs_rv { /* which SMU message? are reader and writer WM separate SMU msg? */ void (*set_wm_ranges)(struct pp_smu *pp, struct pp_smu_wm_range_sets *ranges); - + /* PME w/a */ + void (*set_pme_wa_enable)(struct pp_smu *pp); }; #if 0 diff --git a/drivers/gpu/drm/amd/display/dc/dm_services.h b/drivers/gpu/drm/amd/display/dc/dm_services.h index 225b7bfb09a9..22e7ee7dcd26 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_services.h +++ b/drivers/gpu/drm/amd/display/dc/dm_services.h @@ -192,37 +192,6 @@ unsigned int generic_reg_wait(const struct dc_context *ctx, * Power Play (PP) interfaces **************************************/ -/* DAL calls this function to notify PP about clocks it needs for the Mode Set. - * This is done *before* it changes DCE clock. - * - * If required clock is higher than current, then PP will increase the voltage. - * - * If required clock is lower than current, then PP will defer reduction of - * voltage until the call to dc_service_pp_post_dce_clock_change(). - * - * \input - Contains clocks needed for Mode Set. - * - * \output - Contains clocks adjusted by PP which DAL should use for Mode Set. - * Valid only if function returns zero. - * - * \returns true - call is successful - * false - call failed - */ -bool dm_pp_pre_dce_clock_change( - struct dc_context *ctx, - struct dm_pp_gpu_clock_range *requested_state, - struct dm_pp_gpu_clock_range *actual_state); - -/* The returned clocks range are 'static' system clocks which will be used for - * mode validation purposes. - * - * \returns true - call is successful - * false - call failed - */ -bool dc_service_get_system_clocks_range( - const struct dc_context *ctx, - struct dm_pp_gpu_clock_range *sys_clks); - /* Gets valid clocks levels from pplib * * input: clk_type - display clk / sclk / mem clk diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index 3488af2b5786..f83a608f93e9 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -24,19 +24,23 @@ # It provides the general basic services required by other DAL # subcomponents. -CFLAGS_display_mode_vba.o := -mhard-float -msse -mpreferred-stack-boundary=4 -CFLAGS_display_mode_lib.o := -mhard-float -msse -mpreferred-stack-boundary=4 -CFLAGS_display_pipe_clocks.o := -mhard-float -msse -mpreferred-stack-boundary=4 -CFLAGS_display_rq_dlg_calc.o := -mhard-float -msse -mpreferred-stack-boundary=4 -CFLAGS_dml1_display_rq_dlg_calc.o := -mhard-float -msse -mpreferred-stack-boundary=4 -CFLAGS_display_rq_dlg_helpers.o := -mhard-float -msse -mpreferred-stack-boundary=4 -CFLAGS_soc_bounding_box.o := -mhard-float -msse -mpreferred-stack-boundary=4 -CFLAGS_dml_common_defs.o := -mhard-float -msse -mpreferred-stack-boundary=4 +ifneq ($(call cc-option, -mpreferred-stack-boundary=4),) + cc_stack_align := -mpreferred-stack-boundary=4 +else ifneq ($(call cc-option, -mstack-alignment=16),) + cc_stack_align := -mstack-alignment=16 +endif +dml_ccflags := -mhard-float -msse $(cc_stack_align) -DML = display_mode_lib.o display_rq_dlg_calc.o \ - display_rq_dlg_helpers.o dml1_display_rq_dlg_calc.o \ - soc_bounding_box.o dml_common_defs.o display_mode_vba.o +CFLAGS_display_mode_lib.o := $(dml_ccflags) +CFLAGS_display_pipe_clocks.o := $(dml_ccflags) +CFLAGS_dml1_display_rq_dlg_calc.o := $(dml_ccflags) +CFLAGS_display_rq_dlg_helpers.o := $(dml_ccflags) +CFLAGS_soc_bounding_box.o := $(dml_ccflags) +CFLAGS_dml_common_defs.o := $(dml_ccflags) + +DML = display_mode_lib.o display_rq_dlg_helpers.o dml1_display_rq_dlg_calc.o \ + soc_bounding_box.o dml_common_defs.o AMD_DAL_DML = $(addprefix $(AMDDALPATH)/dc/dml/,$(DML)) diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h index 26f4f2a3d90d..3c2abcb8a1b0 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h @@ -28,8 +28,6 @@ #include "dml_common_defs.h" #include "soc_bounding_box.h" -#include "display_mode_vba.h" -#include "display_rq_dlg_calc.h" #include "dml1_display_rq_dlg_calc.h" enum dml_project { @@ -41,7 +39,6 @@ struct display_mode_lib { struct _vcs_dpi_ip_params_st ip; struct _vcs_dpi_soc_bounding_box_st soc; enum dml_project project; - struct vba_vars_st vba; struct dal_logger *logger; }; diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h index aeebd8bee628..09affa16cc43 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h @@ -140,7 +140,6 @@ struct _vcs_dpi_ip_params_st { unsigned int max_hscl_taps; unsigned int max_vscl_taps; unsigned int xfc_supported; - unsigned int ptoi_supported; unsigned int xfc_fill_constant_bytes; double dispclk_ramp_margin_percent; double xfc_fill_bw_overhead_percent; diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c deleted file mode 100644 index 260e113fcc02..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c +++ /dev/null @@ -1,6085 +0,0 @@ -/* - * Copyright 2017 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "display_mode_lib.h" -#include "display_mode_vba.h" - -#include "dml_inline_defs.h" - -/* - * NOTE: - * This file is gcc-parseable HW gospel, coming straight from HW engineers. - * - * It doesn't adhere to Linux kernel style and sometimes will do things in odd - * ways. Unless there is something clearly wrong with it the code should - * remain as-is as it provides us with a guarantee from HW that it is correct. - */ - -#define BPP_INVALID 0 -#define BPP_BLENDED_PIPE 0xffffffff -static const unsigned int NumberOfStates = DC__VOLTAGE_STATES; - -static void fetch_socbb_params(struct display_mode_lib *mode_lib); -static void fetch_ip_params(struct display_mode_lib *mode_lib); -static void fetch_pipe_params(struct display_mode_lib *mode_lib); -static void recalculate_params( - struct display_mode_lib *mode_lib, - const display_e2e_pipe_params_st *pipes, - unsigned int num_pipes); -static void recalculate(struct display_mode_lib *mode_lib); -static double adjust_ReturnBW( - struct display_mode_lib *mode_lib, - double ReturnBW, - bool DCCEnabledAnyPlane, - double ReturnBandwidthToDCN); -static void ModeSupportAndSystemConfiguration(struct display_mode_lib *mode_lib); -static void DisplayPipeConfiguration(struct display_mode_lib *mode_lib); -static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation( - struct display_mode_lib *mode_lib); -static unsigned int dscceComputeDelay( - unsigned int bpc, - double bpp, - unsigned int sliceWidth, - unsigned int numSlices, - enum output_format_class pixelFormat); -static unsigned int dscComputeDelay(enum output_format_class pixelFormat); -// Super monster function with some 45 argument -static bool CalculatePrefetchSchedule( - struct display_mode_lib *mode_lib, - double DPPCLK, - double DISPCLK, - double PixelClock, - double DCFClkDeepSleep, - unsigned int DSCDelay, - unsigned int DPPPerPlane, - bool ScalerEnabled, - unsigned int NumberOfCursors, - double DPPCLKDelaySubtotal, - double DPPCLKDelaySCL, - double DPPCLKDelaySCLLBOnly, - double DPPCLKDelayCNVCFormater, - double DPPCLKDelayCNVCCursor, - double DISPCLKDelaySubtotal, - unsigned int ScalerRecoutWidth, - enum output_format_class OutputFormat, - unsigned int VBlank, - unsigned int HTotal, - unsigned int MaxInterDCNTileRepeaters, - unsigned int VStartup, - unsigned int PageTableLevels, - bool VirtualMemoryEnable, - bool DynamicMetadataEnable, - unsigned int DynamicMetadataLinesBeforeActiveRequired, - unsigned int DynamicMetadataTransmittedBytes, - bool DCCEnable, - double UrgentLatency, - double UrgentExtraLatency, - double TCalc, - unsigned int PDEAndMetaPTEBytesFrame, - unsigned int MetaRowByte, - unsigned int PixelPTEBytesPerRow, - double PrefetchSourceLinesY, - unsigned int SwathWidthY, - double BytePerPixelDETY, - double VInitPreFillY, - unsigned int MaxNumSwathY, - double PrefetchSourceLinesC, - double BytePerPixelDETC, - double VInitPreFillC, - unsigned int MaxNumSwathC, - unsigned int SwathHeightY, - unsigned int SwathHeightC, - double TWait, - bool XFCEnabled, - double XFCRemoteSurfaceFlipDelay, - bool InterlaceEnable, - bool ProgressiveToInterlaceUnitInOPP, - double *DSTXAfterScaler, - double *DSTYAfterScaler, - double *DestinationLinesForPrefetch, - double *PrefetchBandwidth, - double *DestinationLinesToRequestVMInVBlank, - double *DestinationLinesToRequestRowInVBlank, - double *VRatioPrefetchY, - double *VRatioPrefetchC, - double *RequiredPrefetchPixDataBW, - unsigned int *VStartupRequiredWhenNotEnoughTimeForDynamicMetadata, - double *Tno_bw, - unsigned int *VUpdateOffsetPix, - unsigned int *VUpdateWidthPix, - unsigned int *VReadyOffsetPix); -static double RoundToDFSGranularityUp(double Clock, double VCOSpeed); -static double RoundToDFSGranularityDown(double Clock, double VCOSpeed); -static double CalculatePrefetchSourceLines( - struct display_mode_lib *mode_lib, - double VRatio, - double vtaps, - bool Interlace, - bool ProgressiveToInterlaceUnitInOPP, - unsigned int SwathHeight, - unsigned int ViewportYStart, - double *VInitPreFill, - unsigned int *MaxNumSwath); -static unsigned int CalculateVMAndRowBytes( - struct display_mode_lib *mode_lib, - bool DCCEnable, - unsigned int BlockHeight256Bytes, - unsigned int BlockWidth256Bytes, - enum source_format_class SourcePixelFormat, - unsigned int SurfaceTiling, - unsigned int BytePerPixel, - enum scan_direction_class ScanDirection, - unsigned int ViewportWidth, - unsigned int ViewportHeight, - unsigned int SwathWidthY, - bool VirtualMemoryEnable, - unsigned int VMMPageSize, - unsigned int PTEBufferSizeInRequests, - unsigned int PDEProcessingBufIn64KBReqs, - unsigned int Pitch, - unsigned int DCCMetaPitch, - unsigned int *MacroTileWidth, - unsigned int *MetaRowByte, - unsigned int *PixelPTEBytesPerRow, - bool *PTEBufferSizeNotExceeded, - unsigned int *dpte_row_height, - unsigned int *meta_row_height); -static double CalculateTWait( - unsigned int PrefetchMode, - double DRAMClockChangeLatency, - double UrgentLatency, - double SREnterPlusExitTime); -static double CalculateRemoteSurfaceFlipDelay( - struct display_mode_lib *mode_lib, - double VRatio, - double SwathWidth, - double Bpp, - double LineTime, - double XFCTSlvVupdateOffset, - double XFCTSlvVupdateWidth, - double XFCTSlvVreadyOffset, - double XFCXBUFLatencyTolerance, - double XFCFillBWOverhead, - double XFCSlvChunkSize, - double XFCBusTransportTime, - double TCalc, - double TWait, - double *SrcActiveDrainRate, - double *TInitXFill, - double *TslvChk); -static double CalculateWriteBackDISPCLK( - enum source_format_class WritebackPixelFormat, - double PixelClock, - double WritebackHRatio, - double WritebackVRatio, - unsigned int WritebackLumaHTaps, - unsigned int WritebackLumaVTaps, - unsigned int WritebackChromaHTaps, - unsigned int WritebackChromaVTaps, - double WritebackDestinationWidth, - unsigned int HTotal, - unsigned int WritebackChromaLineBufferWidth); -static void CalculateActiveRowBandwidth( - bool VirtualMemoryEnable, - enum source_format_class SourcePixelFormat, - double VRatio, - bool DCCEnable, - double LineTime, - unsigned int MetaRowByteLuma, - unsigned int MetaRowByteChroma, - unsigned int meta_row_height_luma, - unsigned int meta_row_height_chroma, - unsigned int PixelPTEBytesPerRowLuma, - unsigned int PixelPTEBytesPerRowChroma, - unsigned int dpte_row_height_luma, - unsigned int dpte_row_height_chroma, - double *meta_row_bw, - double *dpte_row_bw, - double *qual_row_bw); -static void CalculateFlipSchedule( - struct display_mode_lib *mode_lib, - double UrgentExtraLatency, - double UrgentLatency, - unsigned int MaxPageTableLevels, - bool VirtualMemoryEnable, - double BandwidthAvailableForImmediateFlip, - unsigned int TotImmediateFlipBytes, - enum source_format_class SourcePixelFormat, - unsigned int ImmediateFlipBytes, - double LineTime, - double Tno_bw, - double VRatio, - double PDEAndMetaPTEBytesFrame, - unsigned int MetaRowByte, - unsigned int PixelPTEBytesPerRow, - bool DCCEnable, - unsigned int dpte_row_height, - unsigned int meta_row_height, - double qual_row_bw, - double *DestinationLinesToRequestVMInImmediateFlip, - double *DestinationLinesToRequestRowInImmediateFlip, - double *final_flip_bw, - bool *ImmediateFlipSupportedForPipe); -static double CalculateWriteBackDelay( - enum source_format_class WritebackPixelFormat, - double WritebackHRatio, - double WritebackVRatio, - unsigned int WritebackLumaHTaps, - unsigned int WritebackLumaVTaps, - unsigned int WritebackChromaHTaps, - unsigned int WritebackChromaVTaps, - unsigned int WritebackDestinationWidth); -static void PixelClockAdjustmentForProgressiveToInterlaceUnit(struct display_mode_lib *mode_lib); -static unsigned int CursorBppEnumToBits(enum cursor_bpp ebpp); -static void ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib); - -void set_prefetch_mode( - struct display_mode_lib *mode_lib, - bool cstate_en, - bool pstate_en, - bool ignore_viewport_pos, - bool immediate_flip_support) -{ - unsigned int prefetch_mode; - - if (cstate_en && pstate_en) - prefetch_mode = 0; - else if (cstate_en) - prefetch_mode = 1; - else - prefetch_mode = 2; - if (prefetch_mode != mode_lib->vba.PrefetchMode - || ignore_viewport_pos != mode_lib->vba.IgnoreViewportPositioning - || immediate_flip_support != mode_lib->vba.ImmediateFlipSupport) { - DTRACE( - " Prefetch mode has changed from %i to %i. Recalculating.", - prefetch_mode, - mode_lib->vba.PrefetchMode); - mode_lib->vba.PrefetchMode = prefetch_mode; - mode_lib->vba.IgnoreViewportPositioning = ignore_viewport_pos; - mode_lib->vba.ImmediateFlipSupport = immediate_flip_support; - recalculate(mode_lib); - } -} - -unsigned int dml_get_voltage_level( - struct display_mode_lib *mode_lib, - const display_e2e_pipe_params_st *pipes, - unsigned int num_pipes) -{ - bool need_recalculate = memcmp(&mode_lib->soc, &mode_lib->vba.soc, sizeof(mode_lib->vba.soc)) != 0 - || memcmp(&mode_lib->ip, &mode_lib->vba.ip, sizeof(mode_lib->vba.ip)) != 0 - || num_pipes != mode_lib->vba.cache_num_pipes - || memcmp(pipes, mode_lib->vba.cache_pipes, - sizeof(display_e2e_pipe_params_st) * num_pipes) != 0; - - mode_lib->vba.soc = mode_lib->soc; - mode_lib->vba.ip = mode_lib->ip; - memcpy(mode_lib->vba.cache_pipes, pipes, sizeof(*pipes) * num_pipes); - mode_lib->vba.cache_num_pipes = num_pipes; - - if (need_recalculate && pipes[0].clks_cfg.dppclk_mhz != 0) - recalculate(mode_lib); - else { - fetch_socbb_params(mode_lib); - fetch_ip_params(mode_lib); - fetch_pipe_params(mode_lib); - } - ModeSupportAndSystemConfigurationFull(mode_lib); - - return mode_lib->vba.VoltageLevel; -} - -#define dml_get_attr_func(attr, var) double get_##attr(struct display_mode_lib *mode_lib, const display_e2e_pipe_params_st *pipes, unsigned int num_pipes) \ -{ \ - recalculate_params(mode_lib, pipes, num_pipes); \ - return var; \ -} - -dml_get_attr_func(clk_dcf_deepsleep, mode_lib->vba.DCFClkDeepSleep); -dml_get_attr_func(wm_urgent, mode_lib->vba.UrgentWatermark); -dml_get_attr_func(wm_memory_trip, mode_lib->vba.MemoryTripWatermark); -dml_get_attr_func(wm_writeback_urgent, mode_lib->vba.WritebackUrgentWatermark); -dml_get_attr_func(wm_stutter_exit, mode_lib->vba.StutterExitWatermark); -dml_get_attr_func(wm_stutter_enter_exit, mode_lib->vba.StutterEnterPlusExitWatermark); -dml_get_attr_func(wm_dram_clock_change, mode_lib->vba.DRAMClockChangeWatermark); -dml_get_attr_func(wm_writeback_dram_clock_change, mode_lib->vba.WritebackDRAMClockChangeWatermark); -dml_get_attr_func(wm_xfc_underflow, mode_lib->vba.UrgentWatermark); // xfc_underflow maps to urgent -dml_get_attr_func(stutter_efficiency, mode_lib->vba.StutterEfficiency); -dml_get_attr_func(stutter_efficiency_no_vblank, mode_lib->vba.StutterEfficiencyNotIncludingVBlank); -dml_get_attr_func(urgent_latency, mode_lib->vba.MinUrgentLatencySupportUs); -dml_get_attr_func(urgent_extra_latency, mode_lib->vba.UrgentExtraLatency); -dml_get_attr_func(nonurgent_latency, mode_lib->vba.NonUrgentLatencyTolerance); -dml_get_attr_func( - dram_clock_change_latency, - mode_lib->vba.MinActiveDRAMClockChangeLatencySupported); -dml_get_attr_func(dispclk_calculated, mode_lib->vba.DISPCLK_calculated); -dml_get_attr_func(total_data_read_bw, mode_lib->vba.TotalDataReadBandwidth); -dml_get_attr_func(return_bw, mode_lib->vba.ReturnBW); -dml_get_attr_func(tcalc, mode_lib->vba.TCalc); - -#define dml_get_pipe_attr_func(attr, var) double get_##attr(struct display_mode_lib *mode_lib, const display_e2e_pipe_params_st *pipes, unsigned int num_pipes, unsigned int which_pipe) \ -{\ - unsigned int which_plane; \ - recalculate_params(mode_lib, pipes, num_pipes); \ - which_plane = mode_lib->vba.pipe_plane[which_pipe]; \ - return var[which_plane]; \ -} - -dml_get_pipe_attr_func(dsc_delay, mode_lib->vba.DSCDelay); -dml_get_pipe_attr_func(dppclk_calculated, mode_lib->vba.DPPCLK_calculated); -dml_get_pipe_attr_func(dscclk_calculated, mode_lib->vba.DSCCLK_calculated); -dml_get_pipe_attr_func(min_ttu_vblank, mode_lib->vba.MinTTUVBlank); -dml_get_pipe_attr_func(vratio_prefetch_l, mode_lib->vba.VRatioPrefetchY); -dml_get_pipe_attr_func(vratio_prefetch_c, mode_lib->vba.VRatioPrefetchC); -dml_get_pipe_attr_func(dst_x_after_scaler, mode_lib->vba.DSTXAfterScaler); -dml_get_pipe_attr_func(dst_y_after_scaler, mode_lib->vba.DSTYAfterScaler); -dml_get_pipe_attr_func(dst_y_per_vm_vblank, mode_lib->vba.DestinationLinesToRequestVMInVBlank); -dml_get_pipe_attr_func(dst_y_per_row_vblank, mode_lib->vba.DestinationLinesToRequestRowInVBlank); -dml_get_pipe_attr_func(dst_y_prefetch, mode_lib->vba.DestinationLinesForPrefetch); -dml_get_pipe_attr_func(dst_y_per_vm_flip, mode_lib->vba.DestinationLinesToRequestVMInImmediateFlip); -dml_get_pipe_attr_func( - dst_y_per_row_flip, - mode_lib->vba.DestinationLinesToRequestRowInImmediateFlip); - -dml_get_pipe_attr_func(xfc_transfer_delay, mode_lib->vba.XFCTransferDelay); -dml_get_pipe_attr_func(xfc_precharge_delay, mode_lib->vba.XFCPrechargeDelay); -dml_get_pipe_attr_func(xfc_remote_surface_flip_latency, mode_lib->vba.XFCRemoteSurfaceFlipLatency); -dml_get_pipe_attr_func(xfc_prefetch_margin, mode_lib->vba.XFCPrefetchMargin); - -unsigned int get_vstartup_calculated( - struct display_mode_lib *mode_lib, - const display_e2e_pipe_params_st *pipes, - unsigned int num_pipes, - unsigned int which_pipe) -{ - unsigned int which_plane; - - recalculate_params(mode_lib, pipes, num_pipes); - which_plane = mode_lib->vba.pipe_plane[which_pipe]; - return mode_lib->vba.VStartup[which_plane]; -} - -double get_total_immediate_flip_bytes( - struct display_mode_lib *mode_lib, - const display_e2e_pipe_params_st *pipes, - unsigned int num_pipes) -{ - recalculate_params(mode_lib, pipes, num_pipes); - return mode_lib->vba.TotImmediateFlipBytes; -} - -double get_total_immediate_flip_bw( - struct display_mode_lib *mode_lib, - const display_e2e_pipe_params_st *pipes, - unsigned int num_pipes) -{ - recalculate_params(mode_lib, pipes, num_pipes); - return mode_lib->vba.ImmediateFlipBW; -} - -double get_total_prefetch_bw( - struct display_mode_lib *mode_lib, - const display_e2e_pipe_params_st *pipes, - unsigned int num_pipes) -{ - unsigned int k; - double total_prefetch_bw = 0.0; - - recalculate_params(mode_lib, pipes, num_pipes); - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) - total_prefetch_bw += mode_lib->vba.PrefetchBandwidth[k]; - return total_prefetch_bw; -} - -static void fetch_socbb_params(struct display_mode_lib *mode_lib) -{ - soc_bounding_box_st *soc = &mode_lib->vba.soc; - unsigned int i; - - // SOC Bounding Box Parameters - mode_lib->vba.ReturnBusWidth = soc->return_bus_width_bytes; - mode_lib->vba.NumberOfChannels = soc->num_chans; - mode_lib->vba.PercentOfIdealDRAMAndFabricBWReceivedAfterUrgLatency = - soc->ideal_dram_bw_after_urgent_percent; // there's always that one bastard variable that's so long it throws everything out of alignment! - mode_lib->vba.UrgentLatency = soc->urgent_latency_us; - mode_lib->vba.RoundTripPingLatencyCycles = soc->round_trip_ping_latency_dcfclk_cycles; - mode_lib->vba.UrgentOutOfOrderReturnPerChannel = - soc->urgent_out_of_order_return_per_channel_bytes; - mode_lib->vba.WritebackLatency = soc->writeback_latency_us; - mode_lib->vba.SRExitTime = soc->sr_exit_time_us; - mode_lib->vba.SREnterPlusExitTime = soc->sr_enter_plus_exit_time_us; - mode_lib->vba.DRAMClockChangeLatency = soc->dram_clock_change_latency_us; - mode_lib->vba.Downspreading = soc->downspread_percent; - mode_lib->vba.DRAMChannelWidth = soc->dram_channel_width_bytes; // new! - mode_lib->vba.FabricDatapathToDCNDataReturn = soc->fabric_datapath_to_dcn_data_return_bytes; // new! - mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading = soc->dcn_downspread_percent; // new - mode_lib->vba.DISPCLKDPPCLKVCOSpeed = soc->dispclk_dppclk_vco_speed_mhz; // new - mode_lib->vba.VMMPageSize = soc->vmm_page_size_bytes; - // Set the voltage scaling clocks as the defaults. Most of these will - // be set to different values by the test - for (i = 0; i < DC__VOLTAGE_STATES; i++) - if (soc->clock_limits[i].state == mode_lib->vba.VoltageLevel) - break; - - mode_lib->vba.DCFCLK = soc->clock_limits[i].dcfclk_mhz; - mode_lib->vba.SOCCLK = soc->clock_limits[i].socclk_mhz; - mode_lib->vba.DRAMSpeed = soc->clock_limits[i].dram_speed_mhz; - mode_lib->vba.FabricClock = soc->clock_limits[i].fabricclk_mhz; - - mode_lib->vba.XFCBusTransportTime = soc->xfc_bus_transport_time_us; - mode_lib->vba.XFCXBUFLatencyTolerance = soc->xfc_xbuf_latency_tolerance_us; - - mode_lib->vba.SupportGFX7CompatibleTilingIn32bppAnd64bpp = false; - mode_lib->vba.MaxHSCLRatio = 4; - mode_lib->vba.MaxVSCLRatio = 4; - mode_lib->vba.MaxNumWriteback = 0; /*TODO*/ - mode_lib->vba.WritebackLumaAndChromaScalingSupported = true; - mode_lib->vba.Cursor64BppSupport = true; - for (i = 0; i <= DC__VOLTAGE_STATES; i++) { - mode_lib->vba.DCFCLKPerState[i] = soc->clock_limits[i].dcfclk_mhz; - mode_lib->vba.FabricClockPerState[i] = soc->clock_limits[i].fabricclk_mhz; - mode_lib->vba.SOCCLKPerState[i] = soc->clock_limits[i].socclk_mhz; - mode_lib->vba.PHYCLKPerState[i] = soc->clock_limits[i].phyclk_mhz; - mode_lib->vba.MaxDppclk[i] = soc->clock_limits[i].dppclk_mhz; - mode_lib->vba.MaxDSCCLK[i] = soc->clock_limits[i].dscclk_mhz; - mode_lib->vba.DRAMSpeedPerState[i] = soc->clock_limits[i].dram_speed_mhz; - mode_lib->vba.MaxDispclk[i] = soc->clock_limits[i].dispclk_mhz; - } -} - -static void fetch_ip_params(struct display_mode_lib *mode_lib) -{ - ip_params_st *ip = &mode_lib->vba.ip; - - // IP Parameters - mode_lib->vba.MaxNumDPP = ip->max_num_dpp; - mode_lib->vba.MaxNumOTG = ip->max_num_otg; - mode_lib->vba.CursorChunkSize = ip->cursor_chunk_size; - mode_lib->vba.CursorBufferSize = ip->cursor_buffer_size; - - mode_lib->vba.MaxDCHUBToPSCLThroughput = ip->max_dchub_pscl_bw_pix_per_clk; - mode_lib->vba.MaxPSCLToLBThroughput = ip->max_pscl_lb_bw_pix_per_clk; - mode_lib->vba.ROBBufferSizeInKByte = ip->rob_buffer_size_kbytes; - mode_lib->vba.DETBufferSizeInKByte = ip->det_buffer_size_kbytes; - mode_lib->vba.PixelChunkSizeInKByte = ip->pixel_chunk_size_kbytes; - mode_lib->vba.MetaChunkSize = ip->meta_chunk_size_kbytes; - mode_lib->vba.PTEChunkSize = ip->pte_chunk_size_kbytes; - mode_lib->vba.WritebackChunkSize = ip->writeback_chunk_size_kbytes; - mode_lib->vba.LineBufferSize = ip->line_buffer_size_bits; - mode_lib->vba.MaxLineBufferLines = ip->max_line_buffer_lines; - mode_lib->vba.PTEBufferSizeInRequests = ip->dpte_buffer_size_in_pte_reqs; - mode_lib->vba.DPPOutputBufferPixels = ip->dpp_output_buffer_pixels; - mode_lib->vba.OPPOutputBufferLines = ip->opp_output_buffer_lines; - mode_lib->vba.WritebackInterfaceLumaBufferSize = ip->writeback_luma_buffer_size_kbytes; - mode_lib->vba.WritebackInterfaceChromaBufferSize = ip->writeback_chroma_buffer_size_kbytes; - mode_lib->vba.WritebackChromaLineBufferWidth = - ip->writeback_chroma_line_buffer_width_pixels; - mode_lib->vba.MaxPageTableLevels = ip->max_page_table_levels; - mode_lib->vba.MaxInterDCNTileRepeaters = ip->max_inter_dcn_tile_repeaters; - mode_lib->vba.NumberOfDSC = ip->num_dsc; - mode_lib->vba.ODMCapability = ip->odm_capable; - mode_lib->vba.DISPCLKRampingMargin = ip->dispclk_ramp_margin_percent; - - mode_lib->vba.XFCSupported = ip->xfc_supported; - mode_lib->vba.XFCFillBWOverhead = ip->xfc_fill_bw_overhead_percent; - mode_lib->vba.XFCFillConstant = ip->xfc_fill_constant_bytes; - mode_lib->vba.DPPCLKDelaySubtotal = ip->dppclk_delay_subtotal; - mode_lib->vba.DPPCLKDelaySCL = ip->dppclk_delay_scl; - mode_lib->vba.DPPCLKDelaySCLLBOnly = ip->dppclk_delay_scl_lb_only; - mode_lib->vba.DPPCLKDelayCNVCFormater = ip->dppclk_delay_cnvc_formatter; - mode_lib->vba.DPPCLKDelayCNVCCursor = ip->dppclk_delay_cnvc_cursor; - mode_lib->vba.DISPCLKDelaySubtotal = ip->dispclk_delay_subtotal; - - mode_lib->vba.ProgressiveToInterlaceUnitInOPP = ip->ptoi_supported; - - mode_lib->vba.PDEProcessingBufIn64KBReqs = ip->pde_proc_buffer_size_64k_reqs; -} - -static void fetch_pipe_params(struct display_mode_lib *mode_lib) -{ - display_e2e_pipe_params_st *pipes = mode_lib->vba.cache_pipes; - ip_params_st *ip = &mode_lib->vba.ip; - - unsigned int OTGInstPlane[DC__NUM_DPP__MAX]; - unsigned int j, k; - bool PlaneVisited[DC__NUM_DPP__MAX]; - bool visited[DC__NUM_DPP__MAX]; - - // Convert Pipes to Planes - for (k = 0; k < mode_lib->vba.cache_num_pipes; ++k) - visited[k] = false; - - mode_lib->vba.NumberOfActivePlanes = 0; - for (j = 0; j < mode_lib->vba.cache_num_pipes; ++j) { - display_pipe_source_params_st *src = &pipes[j].pipe.src; - display_pipe_dest_params_st *dst = &pipes[j].pipe.dest; - scaler_ratio_depth_st *scl = &pipes[j].pipe.scale_ratio_depth; - scaler_taps_st *taps = &pipes[j].pipe.scale_taps; - display_output_params_st *dout = &pipes[j].dout; - display_clocks_and_cfg_st *clks = &pipes[j].clks_cfg; - - if (visited[j]) - continue; - visited[j] = true; - - mode_lib->vba.pipe_plane[j] = mode_lib->vba.NumberOfActivePlanes; - - mode_lib->vba.DPPPerPlane[mode_lib->vba.NumberOfActivePlanes] = 1; - mode_lib->vba.SourceScan[mode_lib->vba.NumberOfActivePlanes] = - (enum scan_direction_class) (src->source_scan); - mode_lib->vba.ViewportWidth[mode_lib->vba.NumberOfActivePlanes] = - src->viewport_width; - mode_lib->vba.ViewportHeight[mode_lib->vba.NumberOfActivePlanes] = - src->viewport_height; - mode_lib->vba.ViewportYStartY[mode_lib->vba.NumberOfActivePlanes] = - src->viewport_y_y; - mode_lib->vba.ViewportYStartC[mode_lib->vba.NumberOfActivePlanes] = - src->viewport_y_c; - mode_lib->vba.PitchY[mode_lib->vba.NumberOfActivePlanes] = src->data_pitch; - mode_lib->vba.PitchC[mode_lib->vba.NumberOfActivePlanes] = src->data_pitch_c; - mode_lib->vba.DCCMetaPitchY[mode_lib->vba.NumberOfActivePlanes] = src->meta_pitch; - mode_lib->vba.HRatio[mode_lib->vba.NumberOfActivePlanes] = scl->hscl_ratio; - mode_lib->vba.VRatio[mode_lib->vba.NumberOfActivePlanes] = scl->vscl_ratio; - mode_lib->vba.ScalerEnabled[mode_lib->vba.NumberOfActivePlanes] = scl->scl_enable; - mode_lib->vba.Interlace[mode_lib->vba.NumberOfActivePlanes] = dst->interlaced; - if (mode_lib->vba.Interlace[mode_lib->vba.NumberOfActivePlanes]) - mode_lib->vba.VRatio[mode_lib->vba.NumberOfActivePlanes] *= 2.0; - mode_lib->vba.htaps[mode_lib->vba.NumberOfActivePlanes] = taps->htaps; - mode_lib->vba.vtaps[mode_lib->vba.NumberOfActivePlanes] = taps->vtaps; - mode_lib->vba.HTAPsChroma[mode_lib->vba.NumberOfActivePlanes] = taps->htaps_c; - mode_lib->vba.VTAPsChroma[mode_lib->vba.NumberOfActivePlanes] = taps->vtaps_c; - mode_lib->vba.HTotal[mode_lib->vba.NumberOfActivePlanes] = dst->htotal; - mode_lib->vba.VTotal[mode_lib->vba.NumberOfActivePlanes] = dst->vtotal; - mode_lib->vba.DCCEnable[mode_lib->vba.NumberOfActivePlanes] = - src->dcc_use_global ? - ip->dcc_supported : src->dcc && ip->dcc_supported; - mode_lib->vba.DCCRate[mode_lib->vba.NumberOfActivePlanes] = src->dcc_rate; - mode_lib->vba.SourcePixelFormat[mode_lib->vba.NumberOfActivePlanes] = - (enum source_format_class) (src->source_format); - mode_lib->vba.HActive[mode_lib->vba.NumberOfActivePlanes] = dst->hactive; - mode_lib->vba.VActive[mode_lib->vba.NumberOfActivePlanes] = dst->vactive; - mode_lib->vba.SurfaceTiling[mode_lib->vba.NumberOfActivePlanes] = - (enum dm_swizzle_mode) (src->sw_mode); - mode_lib->vba.ScalerRecoutWidth[mode_lib->vba.NumberOfActivePlanes] = - dst->recout_width; // TODO: or should this be full_recout_width???...maybe only when in hsplit mode? - mode_lib->vba.ODMCombineEnabled[mode_lib->vba.NumberOfActivePlanes] = - dst->odm_combine; - mode_lib->vba.OutputFormat[mode_lib->vba.NumberOfActivePlanes] = - (enum output_format_class) (dout->output_format); - mode_lib->vba.Output[mode_lib->vba.NumberOfActivePlanes] = - (enum output_encoder_class) (dout->output_type); - mode_lib->vba.OutputBpp[mode_lib->vba.NumberOfActivePlanes] = dout->output_bpp; - mode_lib->vba.OutputLinkDPLanes[mode_lib->vba.NumberOfActivePlanes] = - dout->dp_lanes; - mode_lib->vba.DSCEnabled[mode_lib->vba.NumberOfActivePlanes] = dout->dsc_enable; - mode_lib->vba.NumberOfDSCSlices[mode_lib->vba.NumberOfActivePlanes] = - dout->dsc_slices; - mode_lib->vba.DSCInputBitPerComponent[mode_lib->vba.NumberOfActivePlanes] = - dout->opp_input_bpc == 0 ? 12 : dout->opp_input_bpc; - mode_lib->vba.WritebackEnable[mode_lib->vba.NumberOfActivePlanes] = dout->wb_enable; - mode_lib->vba.WritebackSourceHeight[mode_lib->vba.NumberOfActivePlanes] = - dout->wb.wb_src_height; - mode_lib->vba.WritebackDestinationWidth[mode_lib->vba.NumberOfActivePlanes] = - dout->wb.wb_dst_width; - mode_lib->vba.WritebackDestinationHeight[mode_lib->vba.NumberOfActivePlanes] = - dout->wb.wb_dst_height; - mode_lib->vba.WritebackPixelFormat[mode_lib->vba.NumberOfActivePlanes] = - (enum source_format_class) (dout->wb.wb_pixel_format); - mode_lib->vba.WritebackLumaHTaps[mode_lib->vba.NumberOfActivePlanes] = - dout->wb.wb_htaps_luma; - mode_lib->vba.WritebackLumaVTaps[mode_lib->vba.NumberOfActivePlanes] = - dout->wb.wb_vtaps_luma; - mode_lib->vba.WritebackChromaHTaps[mode_lib->vba.NumberOfActivePlanes] = - dout->wb.wb_htaps_chroma; - mode_lib->vba.WritebackChromaVTaps[mode_lib->vba.NumberOfActivePlanes] = - dout->wb.wb_vtaps_chroma; - mode_lib->vba.WritebackHRatio[mode_lib->vba.NumberOfActivePlanes] = - dout->wb.wb_hratio; - mode_lib->vba.WritebackVRatio[mode_lib->vba.NumberOfActivePlanes] = - dout->wb.wb_vratio; - - mode_lib->vba.DynamicMetadataEnable[mode_lib->vba.NumberOfActivePlanes] = - src->dynamic_metadata_enable; - mode_lib->vba.DynamicMetadataLinesBeforeActiveRequired[mode_lib->vba.NumberOfActivePlanes] = - src->dynamic_metadata_lines_before_active; - mode_lib->vba.DynamicMetadataTransmittedBytes[mode_lib->vba.NumberOfActivePlanes] = - src->dynamic_metadata_xmit_bytes; - - mode_lib->vba.XFCEnabled[mode_lib->vba.NumberOfActivePlanes] = src->xfc_enable - && ip->xfc_supported; - mode_lib->vba.XFCSlvChunkSize = src->xfc_params.xfc_slv_chunk_size_bytes; - mode_lib->vba.XFCTSlvVupdateOffset = src->xfc_params.xfc_tslv_vupdate_offset_us; - mode_lib->vba.XFCTSlvVupdateWidth = src->xfc_params.xfc_tslv_vupdate_width_us; - mode_lib->vba.XFCTSlvVreadyOffset = src->xfc_params.xfc_tslv_vready_offset_us; - mode_lib->vba.PixelClock[mode_lib->vba.NumberOfActivePlanes] = dst->pixel_rate_mhz; - mode_lib->vba.DPPCLK[mode_lib->vba.NumberOfActivePlanes] = clks->dppclk_mhz; - if (ip->is_line_buffer_bpp_fixed) - mode_lib->vba.LBBitPerPixel[mode_lib->vba.NumberOfActivePlanes] = - ip->line_buffer_fixed_bpp; - else { - unsigned int lb_depth; - - switch (scl->lb_depth) { - case dm_lb_6: - lb_depth = 18; - break; - case dm_lb_8: - lb_depth = 24; - break; - case dm_lb_10: - lb_depth = 30; - break; - case dm_lb_12: - lb_depth = 36; - break; - case dm_lb_16: - lb_depth = 48; - break; - default: - lb_depth = 36; - } - mode_lib->vba.LBBitPerPixel[mode_lib->vba.NumberOfActivePlanes] = lb_depth; - } - mode_lib->vba.NumberOfCursors[mode_lib->vba.NumberOfActivePlanes] = 0; - // The DML spreadsheet assumes that the two cursors utilize the same amount of bandwidth. We'll - // calculate things a little more accurately - for (k = 0; k < DC__NUM_CURSOR__MAX; ++k) { - switch (k) { - case 0: - mode_lib->vba.CursorBPP[mode_lib->vba.NumberOfActivePlanes][0] = - CursorBppEnumToBits( - (enum cursor_bpp) (src->cur0_bpp)); - mode_lib->vba.CursorWidth[mode_lib->vba.NumberOfActivePlanes][0] = - src->cur0_src_width; - if (src->cur0_src_width > 0) - mode_lib->vba.NumberOfCursors[mode_lib->vba.NumberOfActivePlanes]++; - break; - case 1: - mode_lib->vba.CursorBPP[mode_lib->vba.NumberOfActivePlanes][1] = - CursorBppEnumToBits( - (enum cursor_bpp) (src->cur1_bpp)); - mode_lib->vba.CursorWidth[mode_lib->vba.NumberOfActivePlanes][1] = - src->cur1_src_width; - if (src->cur1_src_width > 0) - mode_lib->vba.NumberOfCursors[mode_lib->vba.NumberOfActivePlanes]++; - break; - default: - dml_print( - "ERROR: Number of cursors specified exceeds supported maximum\n") - ; - } - } - - OTGInstPlane[mode_lib->vba.NumberOfActivePlanes] = dst->otg_inst; - - if (dst->odm_combine && !src->is_hsplit) - dml_print( - "ERROR: ODM Combine is specified but is_hsplit has not be specified for pipe %i\n", - j); - - if (src->is_hsplit) { - for (k = j + 1; k < mode_lib->vba.cache_num_pipes; ++k) { - display_pipe_source_params_st *src_k = &pipes[k].pipe.src; - display_output_params_st *dout_k = &pipes[k].dout; - - if (src_k->is_hsplit && !visited[k] - && src->hsplit_grp == src_k->hsplit_grp) { - mode_lib->vba.pipe_plane[k] = - mode_lib->vba.NumberOfActivePlanes; - mode_lib->vba.DPPPerPlane[mode_lib->vba.NumberOfActivePlanes]++; - if (mode_lib->vba.SourceScan[mode_lib->vba.NumberOfActivePlanes] - == dm_horz) - mode_lib->vba.ViewportWidth[mode_lib->vba.NumberOfActivePlanes] += - src_k->viewport_width; - else - mode_lib->vba.ViewportHeight[mode_lib->vba.NumberOfActivePlanes] += - src_k->viewport_height; - - mode_lib->vba.NumberOfDSCSlices[mode_lib->vba.NumberOfActivePlanes] += - dout_k->dsc_slices; - visited[k] = true; - } - } - } - - mode_lib->vba.NumberOfActivePlanes++; - } - - // handle overlays through dml_ml->vba.BlendingAndTiming - // dml_ml->vba.BlendingAndTiming tells you which instance to look at to get timing, the so called 'master' - - for (j = 0; j < mode_lib->vba.NumberOfActivePlanes; ++j) - PlaneVisited[j] = false; - - for (j = 0; j < mode_lib->vba.NumberOfActivePlanes; ++j) { - for (k = j + 1; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (!PlaneVisited[k] && OTGInstPlane[j] == OTGInstPlane[k]) { - // doesn't matter, so choose the smaller one - mode_lib->vba.BlendingAndTiming[j] = j; - PlaneVisited[j] = true; - mode_lib->vba.BlendingAndTiming[k] = j; - PlaneVisited[k] = true; - } - } - - if (!PlaneVisited[j]) { - mode_lib->vba.BlendingAndTiming[j] = j; - PlaneVisited[j] = true; - } - } - - // TODO: dml_ml->vba.ODMCombineEnabled => 2 * dml_ml->vba.DPPPerPlane...actually maybe not since all pipes are specified - // Do we want the dscclk to automatically be halved? Guess not since the value is specified - - mode_lib->vba.SynchronizedVBlank = pipes[0].pipe.dest.synchronized_vblank_all_planes; - for (k = 1; k < mode_lib->vba.cache_num_pipes; ++k) - ASSERT(mode_lib->vba.SynchronizedVBlank == pipes[k].pipe.dest.synchronized_vblank_all_planes); - - mode_lib->vba.VirtualMemoryEnable = false; - mode_lib->vba.OverridePageTableLevels = 0; - - for (k = 0; k < mode_lib->vba.cache_num_pipes; ++k) { - mode_lib->vba.VirtualMemoryEnable = mode_lib->vba.VirtualMemoryEnable - || !!pipes[k].pipe.src.vm; - mode_lib->vba.OverridePageTableLevels = - (pipes[k].pipe.src.vm_levels_force_en - && mode_lib->vba.OverridePageTableLevels - < pipes[k].pipe.src.vm_levels_force) ? - pipes[k].pipe.src.vm_levels_force : - mode_lib->vba.OverridePageTableLevels; - } - - if (mode_lib->vba.OverridePageTableLevels) - mode_lib->vba.MaxPageTableLevels = mode_lib->vba.OverridePageTableLevels; - - mode_lib->vba.VirtualMemoryEnable = mode_lib->vba.VirtualMemoryEnable && !!ip->pte_enable; - - mode_lib->vba.FabricAndDRAMBandwidth = dml_min( - mode_lib->vba.DRAMSpeed * mode_lib->vba.NumberOfChannels - * mode_lib->vba.DRAMChannelWidth, - mode_lib->vba.FabricClock * mode_lib->vba.FabricDatapathToDCNDataReturn) - / 1000.0; - - // TODO: Must be consistent across all pipes - // DCCProgrammingAssumesScanDirectionUnknown = src.dcc_scan_dir_unknown; -} - -static void recalculate(struct display_mode_lib *mode_lib) -{ - ModeSupportAndSystemConfiguration(mode_lib); - PixelClockAdjustmentForProgressiveToInterlaceUnit(mode_lib); - DisplayPipeConfiguration(mode_lib); - DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation(mode_lib); -} - -// in wm mode we pull the parameters needed from the display_e2e_pipe_params_st structs -// rather than working them out as in recalculate_ms -static void recalculate_params( - struct display_mode_lib *mode_lib, - const display_e2e_pipe_params_st *pipes, - unsigned int num_pipes) -{ - // This is only safe to use memcmp because there are non-POD types in struct display_mode_lib - if (memcmp(&mode_lib->soc, &mode_lib->vba.soc, sizeof(mode_lib->vba.soc)) != 0 - || memcmp(&mode_lib->ip, &mode_lib->vba.ip, sizeof(mode_lib->vba.ip)) != 0 - || num_pipes != mode_lib->vba.cache_num_pipes - || memcmp( - pipes, - mode_lib->vba.cache_pipes, - sizeof(display_e2e_pipe_params_st) * num_pipes) != 0) { - mode_lib->vba.soc = mode_lib->soc; - mode_lib->vba.ip = mode_lib->ip; - memcpy(mode_lib->vba.cache_pipes, pipes, sizeof(*pipes) * num_pipes); - mode_lib->vba.cache_num_pipes = num_pipes; - recalculate(mode_lib); - } -} - -static void ModeSupportAndSystemConfiguration(struct display_mode_lib *mode_lib) -{ - soc_bounding_box_st *soc = &mode_lib->vba.soc; - unsigned int i, k; - unsigned int total_pipes = 0; - - mode_lib->vba.VoltageLevel = mode_lib->vba.cache_pipes[0].clks_cfg.voltage; - for (i = 1; i < mode_lib->vba.cache_num_pipes; ++i) - ASSERT(mode_lib->vba.VoltageLevel == -1 || mode_lib->vba.VoltageLevel == mode_lib->vba.cache_pipes[i].clks_cfg.voltage); - - mode_lib->vba.DCFCLK = mode_lib->vba.cache_pipes[0].clks_cfg.dcfclk_mhz; - mode_lib->vba.SOCCLK = mode_lib->vba.cache_pipes[0].clks_cfg.socclk_mhz; - - if (mode_lib->vba.cache_pipes[0].clks_cfg.dispclk_mhz > 0.0) - mode_lib->vba.DISPCLK = mode_lib->vba.cache_pipes[0].clks_cfg.dispclk_mhz; - else - mode_lib->vba.DISPCLK = soc->clock_limits[mode_lib->vba.VoltageLevel].dispclk_mhz; - - fetch_socbb_params(mode_lib); - fetch_ip_params(mode_lib); - fetch_pipe_params(mode_lib); - - // Total Available Pipes Support Check - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) - total_pipes += mode_lib->vba.DPPPerPlane[k]; - ASSERT(total_pipes <= DC__NUM_DPP__MAX); -} - -static double adjust_ReturnBW( - struct display_mode_lib *mode_lib, - double ReturnBW, - bool DCCEnabledAnyPlane, - double ReturnBandwidthToDCN) -{ - double CriticalCompression; - - if (DCCEnabledAnyPlane - && ReturnBandwidthToDCN - > mode_lib->vba.DCFCLK * mode_lib->vba.ReturnBusWidth / 4.0) - ReturnBW = - dml_min( - ReturnBW, - ReturnBandwidthToDCN * 4 - * (1.0 - - mode_lib->vba.UrgentLatency - / ((mode_lib->vba.ROBBufferSizeInKByte - - mode_lib->vba.PixelChunkSizeInKByte) - * 1024 - / ReturnBandwidthToDCN - - mode_lib->vba.DCFCLK - * mode_lib->vba.ReturnBusWidth - / 4) - + mode_lib->vba.UrgentLatency)); - - CriticalCompression = 2.0 * mode_lib->vba.ReturnBusWidth * mode_lib->vba.DCFCLK - * mode_lib->vba.UrgentLatency - / (ReturnBandwidthToDCN * mode_lib->vba.UrgentLatency - + (mode_lib->vba.ROBBufferSizeInKByte - - mode_lib->vba.PixelChunkSizeInKByte) - * 1024); - - if (DCCEnabledAnyPlane && CriticalCompression > 1.0 && CriticalCompression < 4.0) - ReturnBW = - dml_min( - ReturnBW, - 4.0 * ReturnBandwidthToDCN - * (mode_lib->vba.ROBBufferSizeInKByte - - mode_lib->vba.PixelChunkSizeInKByte) - * 1024 - * mode_lib->vba.ReturnBusWidth - * mode_lib->vba.DCFCLK - * mode_lib->vba.UrgentLatency - / dml_pow( - (ReturnBandwidthToDCN - * mode_lib->vba.UrgentLatency - + (mode_lib->vba.ROBBufferSizeInKByte - - mode_lib->vba.PixelChunkSizeInKByte) - * 1024), - 2)); - - return ReturnBW; -} - -static unsigned int dscceComputeDelay( - unsigned int bpc, - double bpp, - unsigned int sliceWidth, - unsigned int numSlices, - enum output_format_class pixelFormat) -{ - // valid bpc = source bits per component in the set of {8, 10, 12} - // valid bpp = increments of 1/16 of a bit - // min = 6/7/8 in N420/N422/444, respectively - // max = such that compression is 1:1 - //valid sliceWidth = number of pixels per slice line, must be less than or equal to 5184/numSlices (or 4096/numSlices in 420 mode) - //valid numSlices = number of slices in the horiziontal direction per DSC engine in the set of {1, 2, 3, 4} - //valid pixelFormat = pixel/color format in the set of {:N444_RGB, :S422, :N422, :N420} - - // fixed value - unsigned int rcModelSize = 8192; - - // N422/N420 operate at 2 pixels per clock - unsigned int pixelsPerClock, lstall, D, initalXmitDelay, w, s, ix, wx, p, l0, a, ax, l, - Delay, pixels; - - if (pixelFormat == dm_n422 || pixelFormat == dm_420) - pixelsPerClock = 2; - // #all other modes operate at 1 pixel per clock - else - pixelsPerClock = 1; - - //initial transmit delay as per PPS - initalXmitDelay = dml_round(rcModelSize / 2.0 / bpp / pixelsPerClock); - - //compute ssm delay - if (bpc == 8) - D = 81; - else if (bpc == 10) - D = 89; - else - D = 113; - - //divide by pixel per cycle to compute slice width as seen by DSC - w = sliceWidth / pixelsPerClock; - - //422 mode has an additional cycle of delay - if (pixelFormat == dm_s422) - s = 1; - else - s = 0; - - //main calculation for the dscce - ix = initalXmitDelay + 45; - wx = (w + 2) / 3; - p = 3 * wx - w; - l0 = ix / w; - a = ix + p * l0; - ax = (a + 2) / 3 + D + 6 + 1; - l = (ax + wx - 1) / wx; - if ((ix % w) == 0 && p != 0) - lstall = 1; - else - lstall = 0; - Delay = l * wx * (numSlices - 1) + ax + s + lstall + 22; - - //dsc processes 3 pixel containers per cycle and a container can contain 1 or 2 pixels - pixels = Delay * 3 * pixelsPerClock; - return pixels; -} - -static unsigned int dscComputeDelay(enum output_format_class pixelFormat) -{ - unsigned int Delay = 0; - - if (pixelFormat == dm_420) { - // sfr - Delay = Delay + 2; - // dsccif - Delay = Delay + 0; - // dscc - input deserializer - Delay = Delay + 3; - // dscc gets pixels every other cycle - Delay = Delay + 2; - // dscc - input cdc fifo - Delay = Delay + 12; - // dscc gets pixels every other cycle - Delay = Delay + 13; - // dscc - cdc uncertainty - Delay = Delay + 2; - // dscc - output cdc fifo - Delay = Delay + 7; - // dscc gets pixels every other cycle - Delay = Delay + 3; - // dscc - cdc uncertainty - Delay = Delay + 2; - // dscc - output serializer - Delay = Delay + 1; - // sft - Delay = Delay + 1; - } else if (pixelFormat == dm_n422) { - // sfr - Delay = Delay + 2; - // dsccif - Delay = Delay + 1; - // dscc - input deserializer - Delay = Delay + 5; - // dscc - input cdc fifo - Delay = Delay + 25; - // dscc - cdc uncertainty - Delay = Delay + 2; - // dscc - output cdc fifo - Delay = Delay + 10; - // dscc - cdc uncertainty - Delay = Delay + 2; - // dscc - output serializer - Delay = Delay + 1; - // sft - Delay = Delay + 1; - } else { - // sfr - Delay = Delay + 2; - // dsccif - Delay = Delay + 0; - // dscc - input deserializer - Delay = Delay + 3; - // dscc - input cdc fifo - Delay = Delay + 12; - // dscc - cdc uncertainty - Delay = Delay + 2; - // dscc - output cdc fifo - Delay = Delay + 7; - // dscc - output serializer - Delay = Delay + 1; - // dscc - cdc uncertainty - Delay = Delay + 2; - // sft - Delay = Delay + 1; - } - - return Delay; -} - -static bool CalculatePrefetchSchedule( - struct display_mode_lib *mode_lib, - double DPPCLK, - double DISPCLK, - double PixelClock, - double DCFClkDeepSleep, - unsigned int DSCDelay, - unsigned int DPPPerPlane, - bool ScalerEnabled, - unsigned int NumberOfCursors, - double DPPCLKDelaySubtotal, - double DPPCLKDelaySCL, - double DPPCLKDelaySCLLBOnly, - double DPPCLKDelayCNVCFormater, - double DPPCLKDelayCNVCCursor, - double DISPCLKDelaySubtotal, - unsigned int ScalerRecoutWidth, - enum output_format_class OutputFormat, - unsigned int VBlank, - unsigned int HTotal, - unsigned int MaxInterDCNTileRepeaters, - unsigned int VStartup, - unsigned int PageTableLevels, - bool VirtualMemoryEnable, - bool DynamicMetadataEnable, - unsigned int DynamicMetadataLinesBeforeActiveRequired, - unsigned int DynamicMetadataTransmittedBytes, - bool DCCEnable, - double UrgentLatency, - double UrgentExtraLatency, - double TCalc, - unsigned int PDEAndMetaPTEBytesFrame, - unsigned int MetaRowByte, - unsigned int PixelPTEBytesPerRow, - double PrefetchSourceLinesY, - unsigned int SwathWidthY, - double BytePerPixelDETY, - double VInitPreFillY, - unsigned int MaxNumSwathY, - double PrefetchSourceLinesC, - double BytePerPixelDETC, - double VInitPreFillC, - unsigned int MaxNumSwathC, - unsigned int SwathHeightY, - unsigned int SwathHeightC, - double TWait, - bool XFCEnabled, - double XFCRemoteSurfaceFlipDelay, - bool InterlaceEnable, - bool ProgressiveToInterlaceUnitInOPP, - double *DSTXAfterScaler, - double *DSTYAfterScaler, - double *DestinationLinesForPrefetch, - double *PrefetchBandwidth, - double *DestinationLinesToRequestVMInVBlank, - double *DestinationLinesToRequestRowInVBlank, - double *VRatioPrefetchY, - double *VRatioPrefetchC, - double *RequiredPrefetchPixDataBW, - unsigned int *VStartupRequiredWhenNotEnoughTimeForDynamicMetadata, - double *Tno_bw, - unsigned int *VUpdateOffsetPix, - unsigned int *VUpdateWidthPix, - unsigned int *VReadyOffsetPix) -{ - bool MyError = false; - unsigned int DPPCycles, DISPCLKCycles; - double DSTTotalPixelsAfterScaler, TotalRepeaterDelayTime; - double Tdm, LineTime, Tsetup; - double dst_y_prefetch_equ; - double Tsw_oto; - double prefetch_bw_oto; - double Tvm_oto; - double Tr0_oto; - double Tpre_oto; - double dst_y_prefetch_oto; - double TimeForFetchingMetaPTE = 0; - double TimeForFetchingRowInVBlank = 0; - double LinesToRequestPrefetchPixelData = 0; - - if (ScalerEnabled) - DPPCycles = DPPCLKDelaySubtotal + DPPCLKDelaySCL; - else - DPPCycles = DPPCLKDelaySubtotal + DPPCLKDelaySCLLBOnly; - - DPPCycles = DPPCycles + DPPCLKDelayCNVCFormater + NumberOfCursors * DPPCLKDelayCNVCCursor; - - DISPCLKCycles = DISPCLKDelaySubtotal; - - if (DPPCLK == 0.0 || DISPCLK == 0.0) - return true; - - *DSTXAfterScaler = DPPCycles * PixelClock / DPPCLK + DISPCLKCycles * PixelClock / DISPCLK - + DSCDelay; - - if (DPPPerPlane > 1) - *DSTXAfterScaler = *DSTXAfterScaler + ScalerRecoutWidth; - - if (OutputFormat == dm_420 || (InterlaceEnable && ProgressiveToInterlaceUnitInOPP)) - *DSTYAfterScaler = 1; - else - *DSTYAfterScaler = 0; - - DSTTotalPixelsAfterScaler = ((double) (*DSTYAfterScaler * HTotal)) + *DSTXAfterScaler; - *DSTYAfterScaler = dml_floor(DSTTotalPixelsAfterScaler / HTotal, 1); - *DSTXAfterScaler = DSTTotalPixelsAfterScaler - ((double) (*DSTYAfterScaler * HTotal)); - - *VUpdateOffsetPix = dml_ceil(HTotal / 4.0, 1); - TotalRepeaterDelayTime = MaxInterDCNTileRepeaters * (2.0 / DPPCLK + 3.0 / DISPCLK); - *VUpdateWidthPix = (14.0 / DCFClkDeepSleep + 12.0 / DPPCLK + TotalRepeaterDelayTime) - * PixelClock; - - *VReadyOffsetPix = dml_max( - 150.0 / DPPCLK, - TotalRepeaterDelayTime + 20.0 / DCFClkDeepSleep + 10.0 / DPPCLK) - * PixelClock; - - Tsetup = (double) (*VUpdateOffsetPix + *VUpdateWidthPix + *VReadyOffsetPix) / PixelClock; - - LineTime = (double) HTotal / PixelClock; - - if (DynamicMetadataEnable) { - double Tdmbf, Tdmec, Tdmsks; - - Tdm = dml_max(0.0, UrgentExtraLatency - TCalc); - Tdmbf = DynamicMetadataTransmittedBytes / 4.0 / DISPCLK; - Tdmec = LineTime; - if (DynamicMetadataLinesBeforeActiveRequired == 0) - Tdmsks = VBlank * LineTime / 2.0; - else - Tdmsks = DynamicMetadataLinesBeforeActiveRequired * LineTime; - if (InterlaceEnable && !ProgressiveToInterlaceUnitInOPP) - Tdmsks = Tdmsks / 2; - if (VStartup * LineTime - < Tsetup + TWait + UrgentExtraLatency + Tdmbf + Tdmec + Tdmsks) { - MyError = true; - *VStartupRequiredWhenNotEnoughTimeForDynamicMetadata = (Tsetup + TWait - + UrgentExtraLatency + Tdmbf + Tdmec + Tdmsks) / LineTime; - } else - *VStartupRequiredWhenNotEnoughTimeForDynamicMetadata = 0.0; - } else - Tdm = 0; - - if (VirtualMemoryEnable) { - if (PageTableLevels == 4) - *Tno_bw = UrgentExtraLatency + UrgentLatency; - else if (PageTableLevels == 3) - *Tno_bw = UrgentExtraLatency; - else - *Tno_bw = 0; - } else if (DCCEnable) - *Tno_bw = LineTime; - else - *Tno_bw = LineTime / 4; - - dst_y_prefetch_equ = VStartup - dml_max(TCalc + TWait, XFCRemoteSurfaceFlipDelay) / LineTime - - (Tsetup + Tdm) / LineTime - - (*DSTYAfterScaler + *DSTXAfterScaler / HTotal); - - Tsw_oto = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime; - - prefetch_bw_oto = (MetaRowByte + PixelPTEBytesPerRow - + PrefetchSourceLinesY * SwathWidthY * dml_ceil(BytePerPixelDETY, 1) - + PrefetchSourceLinesC * SwathWidthY / 2 * dml_ceil(BytePerPixelDETC, 2)) - / Tsw_oto; - - if (VirtualMemoryEnable == true) { - Tvm_oto = - dml_max( - *Tno_bw + PDEAndMetaPTEBytesFrame / prefetch_bw_oto, - dml_max( - UrgentExtraLatency - + UrgentLatency - * (PageTableLevels - - 1), - LineTime / 4.0)); - } else - Tvm_oto = LineTime / 4.0; - - if ((VirtualMemoryEnable == true || DCCEnable == true)) { - Tr0_oto = dml_max( - (MetaRowByte + PixelPTEBytesPerRow) / prefetch_bw_oto, - dml_max(UrgentLatency, dml_max(LineTime - Tvm_oto, LineTime / 4))); - } else - Tr0_oto = LineTime - Tvm_oto; - - Tpre_oto = Tvm_oto + Tr0_oto + Tsw_oto; - - dst_y_prefetch_oto = Tpre_oto / LineTime; - - if (dst_y_prefetch_oto < dst_y_prefetch_equ) - *DestinationLinesForPrefetch = dst_y_prefetch_oto; - else - *DestinationLinesForPrefetch = dst_y_prefetch_equ; - - *DestinationLinesForPrefetch = dml_floor(4.0 * (*DestinationLinesForPrefetch + 0.125), 1) - / 4; - - dml_print("DML: VStartup: %d\n", VStartup); - dml_print("DML: TCalc: %f\n", TCalc); - dml_print("DML: TWait: %f\n", TWait); - dml_print("DML: XFCRemoteSurfaceFlipDelay: %f\n", XFCRemoteSurfaceFlipDelay); - dml_print("DML: LineTime: %f\n", LineTime); - dml_print("DML: Tsetup: %f\n", Tsetup); - dml_print("DML: Tdm: %f\n", Tdm); - dml_print("DML: DSTYAfterScaler: %f\n", *DSTYAfterScaler); - dml_print("DML: DSTXAfterScaler: %f\n", *DSTXAfterScaler); - dml_print("DML: HTotal: %d\n", HTotal); - - *PrefetchBandwidth = 0; - *DestinationLinesToRequestVMInVBlank = 0; - *DestinationLinesToRequestRowInVBlank = 0; - *VRatioPrefetchY = 0; - *VRatioPrefetchC = 0; - *RequiredPrefetchPixDataBW = 0; - if (*DestinationLinesForPrefetch > 1) { - *PrefetchBandwidth = (PDEAndMetaPTEBytesFrame + 2 * MetaRowByte - + 2 * PixelPTEBytesPerRow - + PrefetchSourceLinesY * SwathWidthY * dml_ceil(BytePerPixelDETY, 1) - + PrefetchSourceLinesC * SwathWidthY / 2 - * dml_ceil(BytePerPixelDETC, 2)) - / (*DestinationLinesForPrefetch * LineTime - *Tno_bw); - if (VirtualMemoryEnable) { - TimeForFetchingMetaPTE = - dml_max( - *Tno_bw - + (double) PDEAndMetaPTEBytesFrame - / *PrefetchBandwidth, - dml_max( - UrgentExtraLatency - + UrgentLatency - * (PageTableLevels - - 1), - LineTime / 4)); - } else { - if (NumberOfCursors > 0 || XFCEnabled) - TimeForFetchingMetaPTE = LineTime / 4; - else - TimeForFetchingMetaPTE = 0.0; - } - - if ((VirtualMemoryEnable == true || DCCEnable == true)) { - TimeForFetchingRowInVBlank = - dml_max( - (MetaRowByte + PixelPTEBytesPerRow) - / *PrefetchBandwidth, - dml_max( - UrgentLatency, - dml_max( - LineTime - - TimeForFetchingMetaPTE, - LineTime - / 4.0))); - } else { - if (NumberOfCursors > 0 || XFCEnabled) - TimeForFetchingRowInVBlank = LineTime - TimeForFetchingMetaPTE; - else - TimeForFetchingRowInVBlank = 0.0; - } - - *DestinationLinesToRequestVMInVBlank = dml_floor( - 4.0 * (TimeForFetchingMetaPTE / LineTime + 0.125), - 1) / 4.0; - - *DestinationLinesToRequestRowInVBlank = dml_floor( - 4.0 * (TimeForFetchingRowInVBlank / LineTime + 0.125), - 1) / 4.0; - - LinesToRequestPrefetchPixelData = - *DestinationLinesForPrefetch - - ((NumberOfCursors > 0 || VirtualMemoryEnable - || DCCEnable) ? - (*DestinationLinesToRequestVMInVBlank - + *DestinationLinesToRequestRowInVBlank) : - 0.0); - - if (LinesToRequestPrefetchPixelData > 0) { - - *VRatioPrefetchY = (double) PrefetchSourceLinesY - / LinesToRequestPrefetchPixelData; - *VRatioPrefetchY = dml_max(*VRatioPrefetchY, 1.0); - if ((SwathHeightY > 4) && (VInitPreFillY > 3)) { - if (LinesToRequestPrefetchPixelData > (VInitPreFillY - 3.0) / 2.0) { - *VRatioPrefetchY = - dml_max( - (double) PrefetchSourceLinesY - / LinesToRequestPrefetchPixelData, - (double) MaxNumSwathY - * SwathHeightY - / (LinesToRequestPrefetchPixelData - - (VInitPreFillY - - 3.0) - / 2.0)); - *VRatioPrefetchY = dml_max(*VRatioPrefetchY, 1.0); - } else { - MyError = true; - *VRatioPrefetchY = 0; - } - } - - *VRatioPrefetchC = (double) PrefetchSourceLinesC - / LinesToRequestPrefetchPixelData; - *VRatioPrefetchC = dml_max(*VRatioPrefetchC, 1.0); - - if ((SwathHeightC > 4)) { - if (LinesToRequestPrefetchPixelData > (VInitPreFillC - 3.0) / 2.0) { - *VRatioPrefetchC = - dml_max( - *VRatioPrefetchC, - (double) MaxNumSwathC - * SwathHeightC - / (LinesToRequestPrefetchPixelData - - (VInitPreFillC - - 3.0) - / 2.0)); - *VRatioPrefetchC = dml_max(*VRatioPrefetchC, 1.0); - } else { - MyError = true; - *VRatioPrefetchC = 0; - } - } - - *RequiredPrefetchPixDataBW = - DPPPerPlane - * ((double) PrefetchSourceLinesY - / LinesToRequestPrefetchPixelData - * dml_ceil( - BytePerPixelDETY, - 1) - + (double) PrefetchSourceLinesC - / LinesToRequestPrefetchPixelData - * dml_ceil( - BytePerPixelDETC, - 2) - / 2) - * SwathWidthY / LineTime; - } else { - MyError = true; - *VRatioPrefetchY = 0; - *VRatioPrefetchC = 0; - *RequiredPrefetchPixDataBW = 0; - } - - } else { - MyError = true; - } - - if (MyError) { - *PrefetchBandwidth = 0; - TimeForFetchingMetaPTE = 0; - TimeForFetchingRowInVBlank = 0; - *DestinationLinesToRequestVMInVBlank = 0; - *DestinationLinesToRequestRowInVBlank = 0; - *DestinationLinesForPrefetch = 0; - LinesToRequestPrefetchPixelData = 0; - *VRatioPrefetchY = 0; - *VRatioPrefetchC = 0; - *RequiredPrefetchPixDataBW = 0; - } - - return MyError; -} - -static double RoundToDFSGranularityUp(double Clock, double VCOSpeed) -{ - return VCOSpeed * 4 / dml_floor(VCOSpeed * 4 / Clock, 1); -} - -static double RoundToDFSGranularityDown(double Clock, double VCOSpeed) -{ - return VCOSpeed * 4 / dml_ceil(VCOSpeed * 4 / Clock, 1); -} - -static double CalculatePrefetchSourceLines( - struct display_mode_lib *mode_lib, - double VRatio, - double vtaps, - bool Interlace, - bool ProgressiveToInterlaceUnitInOPP, - unsigned int SwathHeight, - unsigned int ViewportYStart, - double *VInitPreFill, - unsigned int *MaxNumSwath) -{ - unsigned int MaxPartialSwath; - - if (ProgressiveToInterlaceUnitInOPP) - *VInitPreFill = dml_floor((VRatio + vtaps + 1) / 2.0, 1); - else - *VInitPreFill = dml_floor((VRatio + vtaps + 1 + Interlace * 0.5 * VRatio) / 2.0, 1); - - if (!mode_lib->vba.IgnoreViewportPositioning) { - - *MaxNumSwath = dml_ceil((*VInitPreFill - 1.0) / SwathHeight, 1) + 1.0; - - if (*VInitPreFill > 1.0) - MaxPartialSwath = (unsigned int) (*VInitPreFill - 2) % SwathHeight; - else - MaxPartialSwath = (unsigned int) (*VInitPreFill + SwathHeight - 2) - % SwathHeight; - MaxPartialSwath = dml_max(1U, MaxPartialSwath); - - } else { - - if (ViewportYStart != 0) - dml_print( - "WARNING DML: using viewport y position of 0 even though actual viewport y position is non-zero in prefetch source lines calculation\n"); - - *MaxNumSwath = dml_ceil(*VInitPreFill / SwathHeight, 1); - - if (*VInitPreFill > 1.0) - MaxPartialSwath = (unsigned int) (*VInitPreFill - 1) % SwathHeight; - else - MaxPartialSwath = (unsigned int) (*VInitPreFill + SwathHeight - 1) - % SwathHeight; - } - - return *MaxNumSwath * SwathHeight + MaxPartialSwath; -} - -static unsigned int CalculateVMAndRowBytes( - struct display_mode_lib *mode_lib, - bool DCCEnable, - unsigned int BlockHeight256Bytes, - unsigned int BlockWidth256Bytes, - enum source_format_class SourcePixelFormat, - unsigned int SurfaceTiling, - unsigned int BytePerPixel, - enum scan_direction_class ScanDirection, - unsigned int ViewportWidth, - unsigned int ViewportHeight, - unsigned int SwathWidth, - bool VirtualMemoryEnable, - unsigned int VMMPageSize, - unsigned int PTEBufferSizeInRequests, - unsigned int PDEProcessingBufIn64KBReqs, - unsigned int Pitch, - unsigned int DCCMetaPitch, - unsigned int *MacroTileWidth, - unsigned int *MetaRowByte, - unsigned int *PixelPTEBytesPerRow, - bool *PTEBufferSizeNotExceeded, - unsigned int *dpte_row_height, - unsigned int *meta_row_height) -{ - unsigned int MetaRequestHeight; - unsigned int MetaRequestWidth; - unsigned int MetaSurfWidth; - unsigned int MetaSurfHeight; - unsigned int MPDEBytesFrame; - unsigned int MetaPTEBytesFrame; - unsigned int DCCMetaSurfaceBytes; - - unsigned int MacroTileSizeBytes; - unsigned int MacroTileHeight; - unsigned int DPDE0BytesFrame; - unsigned int ExtraDPDEBytesFrame; - unsigned int PDEAndMetaPTEBytesFrame; - - if (DCCEnable == true) { - MetaRequestHeight = 8 * BlockHeight256Bytes; - MetaRequestWidth = 8 * BlockWidth256Bytes; - if (ScanDirection == dm_horz) { - *meta_row_height = MetaRequestHeight; - MetaSurfWidth = dml_ceil((double) SwathWidth - 1, MetaRequestWidth) - + MetaRequestWidth; - *MetaRowByte = MetaSurfWidth * MetaRequestHeight * BytePerPixel / 256.0; - } else { - *meta_row_height = MetaRequestWidth; - MetaSurfHeight = dml_ceil((double) SwathWidth - 1, MetaRequestHeight) - + MetaRequestHeight; - *MetaRowByte = MetaSurfHeight * MetaRequestWidth * BytePerPixel / 256.0; - } - if (ScanDirection == dm_horz) { - DCCMetaSurfaceBytes = DCCMetaPitch - * (dml_ceil(ViewportHeight - 1, 64 * BlockHeight256Bytes) - + 64 * BlockHeight256Bytes) * BytePerPixel - / 256; - } else { - DCCMetaSurfaceBytes = DCCMetaPitch - * (dml_ceil( - (double) ViewportHeight - 1, - 64 * BlockHeight256Bytes) - + 64 * BlockHeight256Bytes) * BytePerPixel - / 256; - } - if (VirtualMemoryEnable == true) { - MetaPTEBytesFrame = (dml_ceil( - (double) (DCCMetaSurfaceBytes - VMMPageSize) - / (8 * VMMPageSize), - 1) + 1) * 64; - MPDEBytesFrame = 128 * (mode_lib->vba.MaxPageTableLevels - 1); - } else { - MetaPTEBytesFrame = 0; - MPDEBytesFrame = 0; - } - } else { - MetaPTEBytesFrame = 0; - MPDEBytesFrame = 0; - *MetaRowByte = 0; - } - - if (SurfaceTiling == dm_sw_linear) { - MacroTileSizeBytes = 256; - MacroTileHeight = 1; - } else if (SurfaceTiling == dm_sw_4kb_s || SurfaceTiling == dm_sw_4kb_s_x - || SurfaceTiling == dm_sw_4kb_d || SurfaceTiling == dm_sw_4kb_d_x) { - MacroTileSizeBytes = 4096; - MacroTileHeight = 4 * BlockHeight256Bytes; - } else if (SurfaceTiling == dm_sw_64kb_s || SurfaceTiling == dm_sw_64kb_s_t - || SurfaceTiling == dm_sw_64kb_s_x || SurfaceTiling == dm_sw_64kb_d - || SurfaceTiling == dm_sw_64kb_d_t || SurfaceTiling == dm_sw_64kb_d_x - || SurfaceTiling == dm_sw_64kb_r_x) { - MacroTileSizeBytes = 65536; - MacroTileHeight = 16 * BlockHeight256Bytes; - } else { - MacroTileSizeBytes = 262144; - MacroTileHeight = 32 * BlockHeight256Bytes; - } - *MacroTileWidth = MacroTileSizeBytes / BytePerPixel / MacroTileHeight; - - if (VirtualMemoryEnable == true && mode_lib->vba.MaxPageTableLevels > 1) { - if (ScanDirection == dm_horz) { - DPDE0BytesFrame = - 64 - * (dml_ceil( - ((Pitch - * (dml_ceil( - ViewportHeight - - 1, - MacroTileHeight) - + MacroTileHeight) - * BytePerPixel) - - MacroTileSizeBytes) - / (8 - * 2097152), - 1) + 1); - } else { - DPDE0BytesFrame = - 64 - * (dml_ceil( - ((Pitch - * (dml_ceil( - (double) SwathWidth - - 1, - MacroTileHeight) - + MacroTileHeight) - * BytePerPixel) - - MacroTileSizeBytes) - / (8 - * 2097152), - 1) + 1); - } - ExtraDPDEBytesFrame = 128 * (mode_lib->vba.MaxPageTableLevels - 2); - } else { - DPDE0BytesFrame = 0; - ExtraDPDEBytesFrame = 0; - } - - PDEAndMetaPTEBytesFrame = MetaPTEBytesFrame + MPDEBytesFrame + DPDE0BytesFrame - + ExtraDPDEBytesFrame; - - if (VirtualMemoryEnable == true) { - unsigned int PTERequestSize; - unsigned int PixelPTEReqHeight; - unsigned int PixelPTEReqWidth; - double FractionOfPTEReturnDrop; - unsigned int EffectivePDEProcessingBufIn64KBReqs; - - if (SurfaceTiling == dm_sw_linear) { - PixelPTEReqHeight = 1; - PixelPTEReqWidth = 8.0 * VMMPageSize / BytePerPixel; - PTERequestSize = 64; - FractionOfPTEReturnDrop = 0; - } else if (MacroTileSizeBytes == 4096) { - PixelPTEReqHeight = MacroTileHeight; - PixelPTEReqWidth = 8 * *MacroTileWidth; - PTERequestSize = 64; - if (ScanDirection == dm_horz) - FractionOfPTEReturnDrop = 0; - else - FractionOfPTEReturnDrop = 7 / 8; - } else if (VMMPageSize == 4096 && MacroTileSizeBytes > 4096) { - PixelPTEReqHeight = 16 * BlockHeight256Bytes; - PixelPTEReqWidth = 16 * BlockWidth256Bytes; - PTERequestSize = 128; - FractionOfPTEReturnDrop = 0; - } else { - PixelPTEReqHeight = MacroTileHeight; - PixelPTEReqWidth = 8 * *MacroTileWidth; - PTERequestSize = 64; - FractionOfPTEReturnDrop = 0; - } - - if (SourcePixelFormat == dm_420_8 || SourcePixelFormat == dm_420_10) - EffectivePDEProcessingBufIn64KBReqs = PDEProcessingBufIn64KBReqs / 2; - else - EffectivePDEProcessingBufIn64KBReqs = PDEProcessingBufIn64KBReqs; - - if (SurfaceTiling == dm_sw_linear) { - *dpte_row_height = - dml_min( - 128, - 1 - << (unsigned int) dml_floor( - dml_log2( - dml_min( - (double) PTEBufferSizeInRequests - * PixelPTEReqWidth, - EffectivePDEProcessingBufIn64KBReqs - * 65536.0 - / BytePerPixel) - / Pitch), - 1)); - *PixelPTEBytesPerRow = PTERequestSize - * (dml_ceil( - (double) (Pitch * *dpte_row_height - 1) - / PixelPTEReqWidth, - 1) + 1); - } else if (ScanDirection == dm_horz) { - *dpte_row_height = PixelPTEReqHeight; - *PixelPTEBytesPerRow = PTERequestSize - * (dml_ceil(((double) SwathWidth - 1) / PixelPTEReqWidth, 1) - + 1); - } else { - *dpte_row_height = dml_min(PixelPTEReqWidth, *MacroTileWidth); - *PixelPTEBytesPerRow = PTERequestSize - * (dml_ceil( - ((double) SwathWidth - 1) - / PixelPTEReqHeight, - 1) + 1); - } - if (*PixelPTEBytesPerRow * (1 - FractionOfPTEReturnDrop) - <= 64 * PTEBufferSizeInRequests) { - *PTEBufferSizeNotExceeded = true; - } else { - *PTEBufferSizeNotExceeded = false; - } - } else { - *PixelPTEBytesPerRow = 0; - *PTEBufferSizeNotExceeded = true; - } - - return PDEAndMetaPTEBytesFrame; -} - -static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation( - struct display_mode_lib *mode_lib) -{ - unsigned int j, k; - - mode_lib->vba.WritebackDISPCLK = 0.0; - mode_lib->vba.DISPCLKWithRamping = 0; - mode_lib->vba.DISPCLKWithoutRamping = 0; - mode_lib->vba.GlobalDPPCLK = 0.0; - - // dml_ml->vba.DISPCLK and dml_ml->vba.DPPCLK Calculation - // - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (mode_lib->vba.WritebackEnable[k]) { - mode_lib->vba.WritebackDISPCLK = - dml_max( - mode_lib->vba.WritebackDISPCLK, - CalculateWriteBackDISPCLK( - mode_lib->vba.WritebackPixelFormat[k], - mode_lib->vba.PixelClock[k], - mode_lib->vba.WritebackHRatio[k], - mode_lib->vba.WritebackVRatio[k], - mode_lib->vba.WritebackLumaHTaps[k], - mode_lib->vba.WritebackLumaVTaps[k], - mode_lib->vba.WritebackChromaHTaps[k], - mode_lib->vba.WritebackChromaVTaps[k], - mode_lib->vba.WritebackDestinationWidth[k], - mode_lib->vba.HTotal[k], - mode_lib->vba.WritebackChromaLineBufferWidth)); - } - } - - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (mode_lib->vba.HRatio[k] > 1) { - mode_lib->vba.PSCL_THROUGHPUT_LUMA[k] = dml_min( - mode_lib->vba.MaxDCHUBToPSCLThroughput, - mode_lib->vba.MaxPSCLToLBThroughput - * mode_lib->vba.HRatio[k] - / dml_ceil( - mode_lib->vba.htaps[k] - / 6.0, - 1)); - } else { - mode_lib->vba.PSCL_THROUGHPUT_LUMA[k] = dml_min( - mode_lib->vba.MaxDCHUBToPSCLThroughput, - mode_lib->vba.MaxPSCLToLBThroughput); - } - - mode_lib->vba.DPPCLKUsingSingleDPPLuma = - mode_lib->vba.PixelClock[k] - * dml_max( - mode_lib->vba.vtaps[k] / 6.0 - * dml_min( - 1.0, - mode_lib->vba.HRatio[k]), - dml_max( - mode_lib->vba.HRatio[k] - * mode_lib->vba.VRatio[k] - / mode_lib->vba.PSCL_THROUGHPUT_LUMA[k], - 1.0)); - - if ((mode_lib->vba.htaps[k] > 6 || mode_lib->vba.vtaps[k] > 6) - && mode_lib->vba.DPPCLKUsingSingleDPPLuma - < 2 * mode_lib->vba.PixelClock[k]) { - mode_lib->vba.DPPCLKUsingSingleDPPLuma = 2 * mode_lib->vba.PixelClock[k]; - } - - if ((mode_lib->vba.SourcePixelFormat[k] != dm_420_8 - && mode_lib->vba.SourcePixelFormat[k] != dm_420_10)) { - mode_lib->vba.PSCL_THROUGHPUT_CHROMA[k] = 0.0; - mode_lib->vba.DPPCLKUsingSingleDPP[k] = - mode_lib->vba.DPPCLKUsingSingleDPPLuma; - } else { - if (mode_lib->vba.HRatio[k] > 1) { - mode_lib->vba.PSCL_THROUGHPUT_CHROMA[k] = - dml_min( - mode_lib->vba.MaxDCHUBToPSCLThroughput, - mode_lib->vba.MaxPSCLToLBThroughput - * mode_lib->vba.HRatio[k] - / 2 - / dml_ceil( - mode_lib->vba.HTAPsChroma[k] - / 6.0, - 1.0)); - } else { - mode_lib->vba.PSCL_THROUGHPUT_CHROMA[k] = dml_min( - mode_lib->vba.MaxDCHUBToPSCLThroughput, - mode_lib->vba.MaxPSCLToLBThroughput); - } - mode_lib->vba.DPPCLKUsingSingleDPPChroma = - mode_lib->vba.PixelClock[k] - * dml_max( - mode_lib->vba.VTAPsChroma[k] - / 6.0 - * dml_min( - 1.0, - mode_lib->vba.HRatio[k] - / 2), - dml_max( - mode_lib->vba.HRatio[k] - * mode_lib->vba.VRatio[k] - / 4 - / mode_lib->vba.PSCL_THROUGHPUT_CHROMA[k], - 1.0)); - - if ((mode_lib->vba.HTAPsChroma[k] > 6 || mode_lib->vba.VTAPsChroma[k] > 6) - && mode_lib->vba.DPPCLKUsingSingleDPPChroma - < 2 * mode_lib->vba.PixelClock[k]) { - mode_lib->vba.DPPCLKUsingSingleDPPChroma = 2 - * mode_lib->vba.PixelClock[k]; - } - - mode_lib->vba.DPPCLKUsingSingleDPP[k] = dml_max( - mode_lib->vba.DPPCLKUsingSingleDPPLuma, - mode_lib->vba.DPPCLKUsingSingleDPPChroma); - } - } - - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (mode_lib->vba.BlendingAndTiming[k] != k) - continue; - if (mode_lib->vba.ODMCombineEnabled[k]) { - mode_lib->vba.DISPCLKWithRamping = - dml_max( - mode_lib->vba.DISPCLKWithRamping, - mode_lib->vba.PixelClock[k] / 2 - * (1 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100) - * (1 - + mode_lib->vba.DISPCLKRampingMargin - / 100)); - mode_lib->vba.DISPCLKWithoutRamping = - dml_max( - mode_lib->vba.DISPCLKWithoutRamping, - mode_lib->vba.PixelClock[k] / 2 - * (1 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100)); - } else if (!mode_lib->vba.ODMCombineEnabled[k]) { - mode_lib->vba.DISPCLKWithRamping = - dml_max( - mode_lib->vba.DISPCLKWithRamping, - mode_lib->vba.PixelClock[k] - * (1 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100) - * (1 - + mode_lib->vba.DISPCLKRampingMargin - / 100)); - mode_lib->vba.DISPCLKWithoutRamping = - dml_max( - mode_lib->vba.DISPCLKWithoutRamping, - mode_lib->vba.PixelClock[k] - * (1 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100)); - } - } - - mode_lib->vba.DISPCLKWithRamping = dml_max( - mode_lib->vba.DISPCLKWithRamping, - mode_lib->vba.WritebackDISPCLK); - mode_lib->vba.DISPCLKWithoutRamping = dml_max( - mode_lib->vba.DISPCLKWithoutRamping, - mode_lib->vba.WritebackDISPCLK); - - ASSERT(mode_lib->vba.DISPCLKDPPCLKVCOSpeed != 0); - mode_lib->vba.DISPCLKWithRampingRoundedToDFSGranularity = RoundToDFSGranularityUp( - mode_lib->vba.DISPCLKWithRamping, - mode_lib->vba.DISPCLKDPPCLKVCOSpeed); - mode_lib->vba.DISPCLKWithoutRampingRoundedToDFSGranularity = RoundToDFSGranularityUp( - mode_lib->vba.DISPCLKWithoutRamping, - mode_lib->vba.DISPCLKDPPCLKVCOSpeed); - mode_lib->vba.MaxDispclkRoundedToDFSGranularity = RoundToDFSGranularityDown( - mode_lib->vba.soc.clock_limits[NumberOfStates - 1].dispclk_mhz, - mode_lib->vba.DISPCLKDPPCLKVCOSpeed); - if (mode_lib->vba.DISPCLKWithoutRampingRoundedToDFSGranularity - > mode_lib->vba.MaxDispclkRoundedToDFSGranularity) { - mode_lib->vba.DISPCLK_calculated = - mode_lib->vba.DISPCLKWithoutRampingRoundedToDFSGranularity; - } else if (mode_lib->vba.DISPCLKWithRampingRoundedToDFSGranularity - > mode_lib->vba.MaxDispclkRoundedToDFSGranularity) { - mode_lib->vba.DISPCLK_calculated = mode_lib->vba.MaxDispclkRoundedToDFSGranularity; - } else { - mode_lib->vba.DISPCLK_calculated = - mode_lib->vba.DISPCLKWithRampingRoundedToDFSGranularity; - } - DTRACE(" dispclk_mhz (calculated) = %f", mode_lib->vba.DISPCLK_calculated); - - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - mode_lib->vba.DPPCLK_calculated[k] = mode_lib->vba.DPPCLKUsingSingleDPP[k] - / mode_lib->vba.DPPPerPlane[k] - * (1 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100); - mode_lib->vba.GlobalDPPCLK = dml_max( - mode_lib->vba.GlobalDPPCLK, - mode_lib->vba.DPPCLK_calculated[k]); - } - mode_lib->vba.GlobalDPPCLK = RoundToDFSGranularityUp( - mode_lib->vba.GlobalDPPCLK, - mode_lib->vba.DISPCLKDPPCLKVCOSpeed); - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - mode_lib->vba.DPPCLK_calculated[k] = mode_lib->vba.GlobalDPPCLK / 255 - * dml_ceil( - mode_lib->vba.DPPCLK_calculated[k] * 255 - / mode_lib->vba.GlobalDPPCLK, - 1); - DTRACE(" dppclk_mhz[%i] (calculated) = %f", k, mode_lib->vba.DPPCLK_calculated[k]); - } - - // Urgent Watermark - mode_lib->vba.DCCEnabledAnyPlane = false; - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) - if (mode_lib->vba.DCCEnable[k]) - mode_lib->vba.DCCEnabledAnyPlane = true; - - mode_lib->vba.ReturnBandwidthToDCN = dml_min( - mode_lib->vba.ReturnBusWidth * mode_lib->vba.DCFCLK, - mode_lib->vba.FabricAndDRAMBandwidth * 1000) - * mode_lib->vba.PercentOfIdealDRAMAndFabricBWReceivedAfterUrgLatency / 100; - - mode_lib->vba.ReturnBW = mode_lib->vba.ReturnBandwidthToDCN; - mode_lib->vba.ReturnBW = adjust_ReturnBW( - mode_lib, - mode_lib->vba.ReturnBW, - mode_lib->vba.DCCEnabledAnyPlane, - mode_lib->vba.ReturnBandwidthToDCN); - - // Let's do this calculation again?? - mode_lib->vba.ReturnBandwidthToDCN = dml_min( - mode_lib->vba.ReturnBusWidth * mode_lib->vba.DCFCLK, - mode_lib->vba.FabricAndDRAMBandwidth * 1000); - mode_lib->vba.ReturnBW = adjust_ReturnBW( - mode_lib, - mode_lib->vba.ReturnBW, - mode_lib->vba.DCCEnabledAnyPlane, - mode_lib->vba.ReturnBandwidthToDCN); - - DTRACE(" dcfclk_mhz = %f", mode_lib->vba.DCFCLK); - DTRACE(" return_bw_to_dcn = %f", mode_lib->vba.ReturnBandwidthToDCN); - DTRACE(" return_bus_bw = %f", mode_lib->vba.ReturnBW); - - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - bool MainPlaneDoesODMCombine = false; - - if (mode_lib->vba.SourceScan[k] == dm_horz) - mode_lib->vba.SwathWidthSingleDPPY[k] = mode_lib->vba.ViewportWidth[k]; - else - mode_lib->vba.SwathWidthSingleDPPY[k] = mode_lib->vba.ViewportHeight[k]; - - if (mode_lib->vba.ODMCombineEnabled[k] == true) - MainPlaneDoesODMCombine = true; - for (j = 0; j < mode_lib->vba.NumberOfActivePlanes; ++j) - if (mode_lib->vba.BlendingAndTiming[k] == j - && mode_lib->vba.ODMCombineEnabled[j] == true) - MainPlaneDoesODMCombine = true; - - if (MainPlaneDoesODMCombine == true) - mode_lib->vba.SwathWidthY[k] = dml_min( - (double) mode_lib->vba.SwathWidthSingleDPPY[k], - dml_round( - mode_lib->vba.HActive[k] / 2.0 - * mode_lib->vba.HRatio[k])); - else - mode_lib->vba.SwathWidthY[k] = mode_lib->vba.SwathWidthSingleDPPY[k] - / mode_lib->vba.DPPPerPlane[k]; - } - - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (mode_lib->vba.SourcePixelFormat[k] == dm_444_64) { - mode_lib->vba.BytePerPixelDETY[k] = 8; - mode_lib->vba.BytePerPixelDETC[k] = 0; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_32) { - mode_lib->vba.BytePerPixelDETY[k] = 4; - mode_lib->vba.BytePerPixelDETC[k] = 0; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_16) { - mode_lib->vba.BytePerPixelDETY[k] = 2; - mode_lib->vba.BytePerPixelDETC[k] = 0; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_8) { - mode_lib->vba.BytePerPixelDETY[k] = 1; - mode_lib->vba.BytePerPixelDETC[k] = 0; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_420_8) { - mode_lib->vba.BytePerPixelDETY[k] = 1; - mode_lib->vba.BytePerPixelDETC[k] = 2; - } else { // dm_420_10 - mode_lib->vba.BytePerPixelDETY[k] = 4.0 / 3.0; - mode_lib->vba.BytePerPixelDETC[k] = 8.0 / 3.0; - } - } - - mode_lib->vba.TotalDataReadBandwidth = 0.0; - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - mode_lib->vba.ReadBandwidthPlaneLuma[k] = mode_lib->vba.SwathWidthSingleDPPY[k] - * dml_ceil(mode_lib->vba.BytePerPixelDETY[k], 1) - / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) - * mode_lib->vba.VRatio[k]; - mode_lib->vba.ReadBandwidthPlaneChroma[k] = mode_lib->vba.SwathWidthSingleDPPY[k] - / 2 * dml_ceil(mode_lib->vba.BytePerPixelDETC[k], 2) - / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) - * mode_lib->vba.VRatio[k] / 2; - DTRACE( - " read_bw[%i] = %fBps", - k, - mode_lib->vba.ReadBandwidthPlaneLuma[k] - + mode_lib->vba.ReadBandwidthPlaneChroma[k]); - mode_lib->vba.TotalDataReadBandwidth += mode_lib->vba.ReadBandwidthPlaneLuma[k] - + mode_lib->vba.ReadBandwidthPlaneChroma[k]; - } - - mode_lib->vba.TotalDCCActiveDPP = 0; - mode_lib->vba.TotalActiveDPP = 0; - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - mode_lib->vba.TotalActiveDPP = mode_lib->vba.TotalActiveDPP - + mode_lib->vba.DPPPerPlane[k]; - if (mode_lib->vba.DCCEnable[k]) - mode_lib->vba.TotalDCCActiveDPP = mode_lib->vba.TotalDCCActiveDPP - + mode_lib->vba.DPPPerPlane[k]; - } - - mode_lib->vba.UrgentRoundTripAndOutOfOrderLatency = - (mode_lib->vba.RoundTripPingLatencyCycles + 32) / mode_lib->vba.DCFCLK - + mode_lib->vba.UrgentOutOfOrderReturnPerChannel - * mode_lib->vba.NumberOfChannels - / mode_lib->vba.ReturnBW; - - mode_lib->vba.LastPixelOfLineExtraWatermark = 0; - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - double DataFabricLineDeliveryTimeLuma, DataFabricLineDeliveryTimeChroma; - - if (mode_lib->vba.VRatio[k] <= 1.0) - mode_lib->vba.DisplayPipeLineDeliveryTimeLuma[k] = - (double) mode_lib->vba.SwathWidthY[k] - * mode_lib->vba.DPPPerPlane[k] - / mode_lib->vba.HRatio[k] - / mode_lib->vba.PixelClock[k]; - else - mode_lib->vba.DisplayPipeLineDeliveryTimeLuma[k] = - (double) mode_lib->vba.SwathWidthY[k] - / mode_lib->vba.PSCL_THROUGHPUT_LUMA[k] - / mode_lib->vba.DPPCLK[k]; - - DataFabricLineDeliveryTimeLuma = mode_lib->vba.SwathWidthSingleDPPY[k] - * mode_lib->vba.SwathHeightY[k] - * dml_ceil(mode_lib->vba.BytePerPixelDETY[k], 1) - / (mode_lib->vba.ReturnBW * mode_lib->vba.ReadBandwidthPlaneLuma[k] - / mode_lib->vba.TotalDataReadBandwidth); - mode_lib->vba.LastPixelOfLineExtraWatermark = dml_max( - mode_lib->vba.LastPixelOfLineExtraWatermark, - DataFabricLineDeliveryTimeLuma - - mode_lib->vba.DisplayPipeLineDeliveryTimeLuma[k]); - - if (mode_lib->vba.BytePerPixelDETC[k] == 0) - mode_lib->vba.DisplayPipeLineDeliveryTimeChroma[k] = 0.0; - else if (mode_lib->vba.VRatio[k] / 2.0 <= 1.0) - mode_lib->vba.DisplayPipeLineDeliveryTimeChroma[k] = - mode_lib->vba.SwathWidthY[k] / 2.0 - * mode_lib->vba.DPPPerPlane[k] - / (mode_lib->vba.HRatio[k] / 2.0) - / mode_lib->vba.PixelClock[k]; - else - mode_lib->vba.DisplayPipeLineDeliveryTimeChroma[k] = - mode_lib->vba.SwathWidthY[k] / 2.0 - / mode_lib->vba.PSCL_THROUGHPUT_CHROMA[k] - / mode_lib->vba.DPPCLK[k]; - - DataFabricLineDeliveryTimeChroma = mode_lib->vba.SwathWidthSingleDPPY[k] / 2.0 - * mode_lib->vba.SwathHeightC[k] - * dml_ceil(mode_lib->vba.BytePerPixelDETC[k], 2) - / (mode_lib->vba.ReturnBW - * mode_lib->vba.ReadBandwidthPlaneChroma[k] - / mode_lib->vba.TotalDataReadBandwidth); - mode_lib->vba.LastPixelOfLineExtraWatermark = - dml_max( - mode_lib->vba.LastPixelOfLineExtraWatermark, - DataFabricLineDeliveryTimeChroma - - mode_lib->vba.DisplayPipeLineDeliveryTimeChroma[k]); - } - - mode_lib->vba.UrgentExtraLatency = mode_lib->vba.UrgentRoundTripAndOutOfOrderLatency - + (mode_lib->vba.TotalActiveDPP * mode_lib->vba.PixelChunkSizeInKByte - + mode_lib->vba.TotalDCCActiveDPP - * mode_lib->vba.MetaChunkSize) * 1024.0 - / mode_lib->vba.ReturnBW; - - if (mode_lib->vba.VirtualMemoryEnable) - mode_lib->vba.UrgentExtraLatency += mode_lib->vba.TotalActiveDPP - * mode_lib->vba.PTEChunkSize * 1024.0 / mode_lib->vba.ReturnBW; - - mode_lib->vba.UrgentWatermark = mode_lib->vba.UrgentLatency - + mode_lib->vba.LastPixelOfLineExtraWatermark - + mode_lib->vba.UrgentExtraLatency; - - DTRACE(" urgent_extra_latency = %fus", mode_lib->vba.UrgentExtraLatency); - DTRACE(" wm_urgent = %fus", mode_lib->vba.UrgentWatermark); - - mode_lib->vba.MemoryTripWatermark = mode_lib->vba.UrgentLatency; - - mode_lib->vba.TotalActiveWriteback = 0; - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (mode_lib->vba.WritebackEnable[k]) - mode_lib->vba.TotalActiveWriteback = mode_lib->vba.TotalActiveWriteback + 1; - } - - if (mode_lib->vba.TotalActiveWriteback <= 1) - mode_lib->vba.WritebackUrgentWatermark = mode_lib->vba.WritebackLatency; - else - mode_lib->vba.WritebackUrgentWatermark = mode_lib->vba.WritebackLatency - + mode_lib->vba.WritebackChunkSize * 1024.0 / 32 - / mode_lib->vba.SOCCLK; - - DTRACE(" wm_wb_urgent = %fus", mode_lib->vba.WritebackUrgentWatermark); - - // NB P-State/DRAM Clock Change Watermark - mode_lib->vba.DRAMClockChangeWatermark = mode_lib->vba.DRAMClockChangeLatency - + mode_lib->vba.UrgentWatermark; - - DTRACE(" wm_pstate_change = %fus", mode_lib->vba.DRAMClockChangeWatermark); - - DTRACE(" calculating wb pstate watermark"); - DTRACE(" total wb outputs %d", mode_lib->vba.TotalActiveWriteback); - DTRACE(" socclk frequency %f Mhz", mode_lib->vba.SOCCLK); - - if (mode_lib->vba.TotalActiveWriteback <= 1) - mode_lib->vba.WritebackDRAMClockChangeWatermark = - mode_lib->vba.DRAMClockChangeLatency - + mode_lib->vba.WritebackLatency; - else - mode_lib->vba.WritebackDRAMClockChangeWatermark = - mode_lib->vba.DRAMClockChangeLatency - + mode_lib->vba.WritebackLatency - + mode_lib->vba.WritebackChunkSize * 1024.0 / 32 - / mode_lib->vba.SOCCLK; - - DTRACE(" wm_wb_pstate %fus", mode_lib->vba.WritebackDRAMClockChangeWatermark); - - // Stutter Efficiency - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - mode_lib->vba.LinesInDETY[k] = mode_lib->vba.DETBufferSizeY[k] - / mode_lib->vba.BytePerPixelDETY[k] / mode_lib->vba.SwathWidthY[k]; - mode_lib->vba.LinesInDETYRoundedDownToSwath[k] = dml_floor( - mode_lib->vba.LinesInDETY[k], - mode_lib->vba.SwathHeightY[k]); - mode_lib->vba.FullDETBufferingTimeY[k] = - mode_lib->vba.LinesInDETYRoundedDownToSwath[k] - * (mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]) - / mode_lib->vba.VRatio[k]; - if (mode_lib->vba.BytePerPixelDETC[k] > 0) { - mode_lib->vba.LinesInDETC[k] = mode_lib->vba.DETBufferSizeC[k] - / mode_lib->vba.BytePerPixelDETC[k] - / (mode_lib->vba.SwathWidthY[k] / 2); - mode_lib->vba.LinesInDETCRoundedDownToSwath[k] = dml_floor( - mode_lib->vba.LinesInDETC[k], - mode_lib->vba.SwathHeightC[k]); - mode_lib->vba.FullDETBufferingTimeC[k] = - mode_lib->vba.LinesInDETCRoundedDownToSwath[k] - * (mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]) - / (mode_lib->vba.VRatio[k] / 2); - } else { - mode_lib->vba.LinesInDETC[k] = 0; - mode_lib->vba.LinesInDETCRoundedDownToSwath[k] = 0; - mode_lib->vba.FullDETBufferingTimeC[k] = 999999; - } - } - - mode_lib->vba.MinFullDETBufferingTime = 999999.0; - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (mode_lib->vba.FullDETBufferingTimeY[k] - < mode_lib->vba.MinFullDETBufferingTime) { - mode_lib->vba.MinFullDETBufferingTime = - mode_lib->vba.FullDETBufferingTimeY[k]; - mode_lib->vba.FrameTimeForMinFullDETBufferingTime = - (double) mode_lib->vba.VTotal[k] * mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]; - } - if (mode_lib->vba.FullDETBufferingTimeC[k] - < mode_lib->vba.MinFullDETBufferingTime) { - mode_lib->vba.MinFullDETBufferingTime = - mode_lib->vba.FullDETBufferingTimeC[k]; - mode_lib->vba.FrameTimeForMinFullDETBufferingTime = - (double) mode_lib->vba.VTotal[k] * mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]; - } - } - - mode_lib->vba.AverageReadBandwidthGBytePerSecond = 0.0; - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (mode_lib->vba.DCCEnable[k]) { - mode_lib->vba.AverageReadBandwidthGBytePerSecond = - mode_lib->vba.AverageReadBandwidthGBytePerSecond - + mode_lib->vba.ReadBandwidthPlaneLuma[k] - / mode_lib->vba.DCCRate[k] - / 1000 - + mode_lib->vba.ReadBandwidthPlaneChroma[k] - / mode_lib->vba.DCCRate[k] - / 1000; - } else { - mode_lib->vba.AverageReadBandwidthGBytePerSecond = - mode_lib->vba.AverageReadBandwidthGBytePerSecond - + mode_lib->vba.ReadBandwidthPlaneLuma[k] - / 1000 - + mode_lib->vba.ReadBandwidthPlaneChroma[k] - / 1000; - } - if (mode_lib->vba.DCCEnable[k]) { - mode_lib->vba.AverageReadBandwidthGBytePerSecond = - mode_lib->vba.AverageReadBandwidthGBytePerSecond - + mode_lib->vba.ReadBandwidthPlaneLuma[k] - / 1000 / 256 - + mode_lib->vba.ReadBandwidthPlaneChroma[k] - / 1000 / 256; - } - if (mode_lib->vba.VirtualMemoryEnable) { - mode_lib->vba.AverageReadBandwidthGBytePerSecond = - mode_lib->vba.AverageReadBandwidthGBytePerSecond - + mode_lib->vba.ReadBandwidthPlaneLuma[k] - / 1000 / 512 - + mode_lib->vba.ReadBandwidthPlaneChroma[k] - / 1000 / 512; - } - } - - mode_lib->vba.PartOfBurstThatFitsInROB = - dml_min( - mode_lib->vba.MinFullDETBufferingTime - * mode_lib->vba.TotalDataReadBandwidth, - mode_lib->vba.ROBBufferSizeInKByte * 1024 - * mode_lib->vba.TotalDataReadBandwidth - / (mode_lib->vba.AverageReadBandwidthGBytePerSecond - * 1000)); - mode_lib->vba.StutterBurstTime = mode_lib->vba.PartOfBurstThatFitsInROB - * (mode_lib->vba.AverageReadBandwidthGBytePerSecond * 1000) - / mode_lib->vba.TotalDataReadBandwidth / mode_lib->vba.ReturnBW - + (mode_lib->vba.MinFullDETBufferingTime - * mode_lib->vba.TotalDataReadBandwidth - - mode_lib->vba.PartOfBurstThatFitsInROB) - / (mode_lib->vba.DCFCLK * 64); - if (mode_lib->vba.TotalActiveWriteback == 0) { - mode_lib->vba.StutterEfficiencyNotIncludingVBlank = (1 - - (mode_lib->vba.SRExitTime + mode_lib->vba.StutterBurstTime) - / mode_lib->vba.MinFullDETBufferingTime) * 100; - } else { - mode_lib->vba.StutterEfficiencyNotIncludingVBlank = 0; - } - - mode_lib->vba.SmallestVBlank = 999999; - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (mode_lib->vba.SynchronizedVBlank || mode_lib->vba.NumberOfActivePlanes == 1) { - mode_lib->vba.VBlankTime = (double) (mode_lib->vba.VTotal[k] - - mode_lib->vba.VActive[k]) * mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]; - } else { - mode_lib->vba.VBlankTime = 0; - } - mode_lib->vba.SmallestVBlank = dml_min( - mode_lib->vba.SmallestVBlank, - mode_lib->vba.VBlankTime); - } - - mode_lib->vba.StutterEfficiency = (mode_lib->vba.StutterEfficiencyNotIncludingVBlank / 100 - * (mode_lib->vba.FrameTimeForMinFullDETBufferingTime - - mode_lib->vba.SmallestVBlank) - + mode_lib->vba.SmallestVBlank) - / mode_lib->vba.FrameTimeForMinFullDETBufferingTime * 100; - - // dml_ml->vba.DCFCLK Deep Sleep - mode_lib->vba.DCFClkDeepSleep = 8.0; - - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; k++) { - if (mode_lib->vba.BytePerPixelDETC[k] > 0) { - mode_lib->vba.DCFCLKDeepSleepPerPlane = - dml_max( - 1.1 * mode_lib->vba.SwathWidthY[k] - * dml_ceil( - mode_lib->vba.BytePerPixelDETY[k], - 1) / 32 - / mode_lib->vba.DisplayPipeLineDeliveryTimeLuma[k], - 1.1 * mode_lib->vba.SwathWidthY[k] / 2.0 - * dml_ceil( - mode_lib->vba.BytePerPixelDETC[k], - 2) / 32 - / mode_lib->vba.DisplayPipeLineDeliveryTimeChroma[k]); - } else - mode_lib->vba.DCFCLKDeepSleepPerPlane = 1.1 * mode_lib->vba.SwathWidthY[k] - * dml_ceil(mode_lib->vba.BytePerPixelDETY[k], 1) / 64.0 - / mode_lib->vba.DisplayPipeLineDeliveryTimeLuma[k]; - mode_lib->vba.DCFCLKDeepSleepPerPlane = dml_max( - mode_lib->vba.DCFCLKDeepSleepPerPlane, - mode_lib->vba.PixelClock[k] / 16.0); - mode_lib->vba.DCFClkDeepSleep = dml_max( - mode_lib->vba.DCFClkDeepSleep, - mode_lib->vba.DCFCLKDeepSleepPerPlane); - - DTRACE( - " dcfclk_deepsleep_per_plane[%i] = %fMHz", - k, - mode_lib->vba.DCFCLKDeepSleepPerPlane); - } - - DTRACE(" dcfclk_deepsleep_mhz = %fMHz", mode_lib->vba.DCFClkDeepSleep); - - // Stutter Watermark - mode_lib->vba.StutterExitWatermark = mode_lib->vba.SRExitTime - + mode_lib->vba.LastPixelOfLineExtraWatermark - + mode_lib->vba.UrgentExtraLatency + 10 / mode_lib->vba.DCFClkDeepSleep; - mode_lib->vba.StutterEnterPlusExitWatermark = mode_lib->vba.SREnterPlusExitTime - + mode_lib->vba.LastPixelOfLineExtraWatermark - + mode_lib->vba.UrgentExtraLatency; - - DTRACE(" wm_cstate_exit = %fus", mode_lib->vba.StutterExitWatermark); - DTRACE(" wm_cstate_enter_exit = %fus", mode_lib->vba.StutterEnterPlusExitWatermark); - - // Urgent Latency Supported - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - mode_lib->vba.EffectiveDETPlusLBLinesLuma = - dml_floor( - mode_lib->vba.LinesInDETY[k] - + dml_min( - mode_lib->vba.LinesInDETY[k] - * mode_lib->vba.DPPCLK[k] - * mode_lib->vba.BytePerPixelDETY[k] - * mode_lib->vba.PSCL_THROUGHPUT_LUMA[k] - / (mode_lib->vba.ReturnBW - / mode_lib->vba.DPPPerPlane[k]), - (double) mode_lib->vba.EffectiveLBLatencyHidingSourceLinesLuma), - mode_lib->vba.SwathHeightY[k]); - - mode_lib->vba.UrgentLatencySupportUsLuma = mode_lib->vba.EffectiveDETPlusLBLinesLuma - * (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) - / mode_lib->vba.VRatio[k] - - mode_lib->vba.EffectiveDETPlusLBLinesLuma - * mode_lib->vba.SwathWidthY[k] - * mode_lib->vba.BytePerPixelDETY[k] - / (mode_lib->vba.ReturnBW - / mode_lib->vba.DPPPerPlane[k]); - - if (mode_lib->vba.BytePerPixelDETC[k] > 0) { - mode_lib->vba.EffectiveDETPlusLBLinesChroma = - dml_floor( - mode_lib->vba.LinesInDETC[k] - + dml_min( - mode_lib->vba.LinesInDETC[k] - * mode_lib->vba.DPPCLK[k] - * mode_lib->vba.BytePerPixelDETC[k] - * mode_lib->vba.PSCL_THROUGHPUT_CHROMA[k] - / (mode_lib->vba.ReturnBW - / mode_lib->vba.DPPPerPlane[k]), - (double) mode_lib->vba.EffectiveLBLatencyHidingSourceLinesChroma), - mode_lib->vba.SwathHeightC[k]); - mode_lib->vba.UrgentLatencySupportUsChroma = - mode_lib->vba.EffectiveDETPlusLBLinesChroma - * (mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]) - / (mode_lib->vba.VRatio[k] / 2) - - mode_lib->vba.EffectiveDETPlusLBLinesChroma - * (mode_lib->vba.SwathWidthY[k] - / 2) - * mode_lib->vba.BytePerPixelDETC[k] - / (mode_lib->vba.ReturnBW - / mode_lib->vba.DPPPerPlane[k]); - mode_lib->vba.UrgentLatencySupportUs[k] = dml_min( - mode_lib->vba.UrgentLatencySupportUsLuma, - mode_lib->vba.UrgentLatencySupportUsChroma); - } else { - mode_lib->vba.UrgentLatencySupportUs[k] = - mode_lib->vba.UrgentLatencySupportUsLuma; - } - } - - mode_lib->vba.MinUrgentLatencySupportUs = 999999; - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - mode_lib->vba.MinUrgentLatencySupportUs = dml_min( - mode_lib->vba.MinUrgentLatencySupportUs, - mode_lib->vba.UrgentLatencySupportUs[k]); - } - - // Non-Urgent Latency Tolerance - mode_lib->vba.NonUrgentLatencyTolerance = mode_lib->vba.MinUrgentLatencySupportUs - - mode_lib->vba.UrgentWatermark; - - // DSCCLK - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if ((mode_lib->vba.BlendingAndTiming[k] != k) || !mode_lib->vba.DSCEnabled[k]) { - mode_lib->vba.DSCCLK_calculated[k] = 0.0; - } else { - if (mode_lib->vba.OutputFormat[k] == dm_420 - || mode_lib->vba.OutputFormat[k] == dm_n422) - mode_lib->vba.DSCFormatFactor = 2; - else - mode_lib->vba.DSCFormatFactor = 1; - if (mode_lib->vba.ODMCombineEnabled[k]) - mode_lib->vba.DSCCLK_calculated[k] = - mode_lib->vba.PixelClockBackEnd[k] / 6 - / mode_lib->vba.DSCFormatFactor - / (1 - - mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100); - else - mode_lib->vba.DSCCLK_calculated[k] = - mode_lib->vba.PixelClockBackEnd[k] / 3 - / mode_lib->vba.DSCFormatFactor - / (1 - - mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100); - } - } - - // DSC Delay - // TODO - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - double bpp = mode_lib->vba.OutputBpp[k]; - unsigned int slices = mode_lib->vba.NumberOfDSCSlices[k]; - - if (mode_lib->vba.DSCEnabled[k] && bpp != 0) { - if (!mode_lib->vba.ODMCombineEnabled[k]) { - mode_lib->vba.DSCDelay[k] = - dscceComputeDelay( - mode_lib->vba.DSCInputBitPerComponent[k], - bpp, - dml_ceil( - (double) mode_lib->vba.HActive[k] - / mode_lib->vba.NumberOfDSCSlices[k], - 1), - slices, - mode_lib->vba.OutputFormat[k]) - + dscComputeDelay( - mode_lib->vba.OutputFormat[k]); - } else { - mode_lib->vba.DSCDelay[k] = - 2 - * (dscceComputeDelay( - mode_lib->vba.DSCInputBitPerComponent[k], - bpp, - dml_ceil( - (double) mode_lib->vba.HActive[k] - / mode_lib->vba.NumberOfDSCSlices[k], - 1), - slices / 2.0, - mode_lib->vba.OutputFormat[k]) - + dscComputeDelay( - mode_lib->vba.OutputFormat[k])); - } - mode_lib->vba.DSCDelay[k] = mode_lib->vba.DSCDelay[k] - * mode_lib->vba.PixelClock[k] - / mode_lib->vba.PixelClockBackEnd[k]; - } else { - mode_lib->vba.DSCDelay[k] = 0; - } - } - - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) - for (j = 0; j < mode_lib->vba.NumberOfActivePlanes; ++j) // NumberOfPlanes - if (j != k && mode_lib->vba.BlendingAndTiming[k] == j - && mode_lib->vba.DSCEnabled[j]) - mode_lib->vba.DSCDelay[k] = mode_lib->vba.DSCDelay[j]; - - // Prefetch - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - unsigned int PDEAndMetaPTEBytesFrameY; - unsigned int PixelPTEBytesPerRowY; - unsigned int MetaRowByteY; - unsigned int MetaRowByteC; - unsigned int PDEAndMetaPTEBytesFrameC; - unsigned int PixelPTEBytesPerRowC; - - Calculate256BBlockSizes( - mode_lib->vba.SourcePixelFormat[k], - mode_lib->vba.SurfaceTiling[k], - dml_ceil(mode_lib->vba.BytePerPixelDETY[k], 1), - dml_ceil(mode_lib->vba.BytePerPixelDETC[k], 2), - &mode_lib->vba.BlockHeight256BytesY[k], - &mode_lib->vba.BlockHeight256BytesC[k], - &mode_lib->vba.BlockWidth256BytesY[k], - &mode_lib->vba.BlockWidth256BytesC[k]); - PDEAndMetaPTEBytesFrameY = CalculateVMAndRowBytes( - mode_lib, - mode_lib->vba.DCCEnable[k], - mode_lib->vba.BlockHeight256BytesY[k], - mode_lib->vba.BlockWidth256BytesY[k], - mode_lib->vba.SourcePixelFormat[k], - mode_lib->vba.SurfaceTiling[k], - dml_ceil(mode_lib->vba.BytePerPixelDETY[k], 1), - mode_lib->vba.SourceScan[k], - mode_lib->vba.ViewportWidth[k], - mode_lib->vba.ViewportHeight[k], - mode_lib->vba.SwathWidthY[k], - mode_lib->vba.VirtualMemoryEnable, - mode_lib->vba.VMMPageSize, - mode_lib->vba.PTEBufferSizeInRequests, - mode_lib->vba.PDEProcessingBufIn64KBReqs, - mode_lib->vba.PitchY[k], - mode_lib->vba.DCCMetaPitchY[k], - &mode_lib->vba.MacroTileWidthY[k], - &MetaRowByteY, - &PixelPTEBytesPerRowY, - &mode_lib->vba.PTEBufferSizeNotExceeded[mode_lib->vba.VoltageLevel], - &mode_lib->vba.dpte_row_height[k], - &mode_lib->vba.meta_row_height[k]); - mode_lib->vba.PrefetchSourceLinesY[k] = CalculatePrefetchSourceLines( - mode_lib, - mode_lib->vba.VRatio[k], - mode_lib->vba.vtaps[k], - mode_lib->vba.Interlace[k], - mode_lib->vba.ProgressiveToInterlaceUnitInOPP, - mode_lib->vba.SwathHeightY[k], - mode_lib->vba.ViewportYStartY[k], - &mode_lib->vba.VInitPreFillY[k], - &mode_lib->vba.MaxNumSwathY[k]); - - if ((mode_lib->vba.SourcePixelFormat[k] != dm_444_64 - && mode_lib->vba.SourcePixelFormat[k] != dm_444_32 - && mode_lib->vba.SourcePixelFormat[k] != dm_444_16 - && mode_lib->vba.SourcePixelFormat[k] != dm_444_8)) { - PDEAndMetaPTEBytesFrameC = - CalculateVMAndRowBytes( - mode_lib, - mode_lib->vba.DCCEnable[k], - mode_lib->vba.BlockHeight256BytesC[k], - mode_lib->vba.BlockWidth256BytesC[k], - mode_lib->vba.SourcePixelFormat[k], - mode_lib->vba.SurfaceTiling[k], - dml_ceil( - mode_lib->vba.BytePerPixelDETC[k], - 2), - mode_lib->vba.SourceScan[k], - mode_lib->vba.ViewportWidth[k] / 2, - mode_lib->vba.ViewportHeight[k] / 2, - mode_lib->vba.SwathWidthY[k] / 2, - mode_lib->vba.VirtualMemoryEnable, - mode_lib->vba.VMMPageSize, - mode_lib->vba.PTEBufferSizeInRequests, - mode_lib->vba.PDEProcessingBufIn64KBReqs, - mode_lib->vba.PitchC[k], - 0, - &mode_lib->vba.MacroTileWidthC[k], - &MetaRowByteC, - &PixelPTEBytesPerRowC, - &mode_lib->vba.PTEBufferSizeNotExceeded[mode_lib->vba.VoltageLevel], - &mode_lib->vba.dpte_row_height_chroma[k], - &mode_lib->vba.meta_row_height_chroma[k]); - mode_lib->vba.PrefetchSourceLinesC[k] = CalculatePrefetchSourceLines( - mode_lib, - mode_lib->vba.VRatio[k] / 2, - mode_lib->vba.VTAPsChroma[k], - mode_lib->vba.Interlace[k], - mode_lib->vba.ProgressiveToInterlaceUnitInOPP, - mode_lib->vba.SwathHeightC[k], - mode_lib->vba.ViewportYStartC[k], - &mode_lib->vba.VInitPreFillC[k], - &mode_lib->vba.MaxNumSwathC[k]); - } else { - PixelPTEBytesPerRowC = 0; - PDEAndMetaPTEBytesFrameC = 0; - MetaRowByteC = 0; - mode_lib->vba.MaxNumSwathC[k] = 0; - mode_lib->vba.PrefetchSourceLinesC[k] = 0; - } - - mode_lib->vba.PixelPTEBytesPerRow[k] = PixelPTEBytesPerRowY + PixelPTEBytesPerRowC; - mode_lib->vba.PDEAndMetaPTEBytesFrame[k] = PDEAndMetaPTEBytesFrameY - + PDEAndMetaPTEBytesFrameC; - mode_lib->vba.MetaRowByte[k] = MetaRowByteY + MetaRowByteC; - - CalculateActiveRowBandwidth( - mode_lib->vba.VirtualMemoryEnable, - mode_lib->vba.SourcePixelFormat[k], - mode_lib->vba.VRatio[k], - mode_lib->vba.DCCEnable[k], - mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k], - MetaRowByteY, - MetaRowByteC, - mode_lib->vba.meta_row_height[k], - mode_lib->vba.meta_row_height_chroma[k], - PixelPTEBytesPerRowY, - PixelPTEBytesPerRowC, - mode_lib->vba.dpte_row_height[k], - mode_lib->vba.dpte_row_height_chroma[k], - &mode_lib->vba.meta_row_bw[k], - &mode_lib->vba.dpte_row_bw[k], - &mode_lib->vba.qual_row_bw[k]); - } - - mode_lib->vba.TCalc = 24.0 / mode_lib->vba.DCFClkDeepSleep; - - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (mode_lib->vba.BlendingAndTiming[k] == k) { - if (mode_lib->vba.WritebackEnable[k] == true) { - mode_lib->vba.WritebackDelay[mode_lib->vba.VoltageLevel][k] = - mode_lib->vba.WritebackLatency - + CalculateWriteBackDelay( - mode_lib->vba.WritebackPixelFormat[k], - mode_lib->vba.WritebackHRatio[k], - mode_lib->vba.WritebackVRatio[k], - mode_lib->vba.WritebackLumaHTaps[k], - mode_lib->vba.WritebackLumaVTaps[k], - mode_lib->vba.WritebackChromaHTaps[k], - mode_lib->vba.WritebackChromaVTaps[k], - mode_lib->vba.WritebackDestinationWidth[k]) - / mode_lib->vba.DISPCLK; - } else - mode_lib->vba.WritebackDelay[mode_lib->vba.VoltageLevel][k] = 0; - for (j = 0; j < mode_lib->vba.NumberOfActivePlanes; ++j) { - if (mode_lib->vba.BlendingAndTiming[j] == k - && mode_lib->vba.WritebackEnable[j] == true) { - mode_lib->vba.WritebackDelay[mode_lib->vba.VoltageLevel][k] = - dml_max( - mode_lib->vba.WritebackDelay[mode_lib->vba.VoltageLevel][k], - mode_lib->vba.WritebackLatency - + CalculateWriteBackDelay( - mode_lib->vba.WritebackPixelFormat[j], - mode_lib->vba.WritebackHRatio[j], - mode_lib->vba.WritebackVRatio[j], - mode_lib->vba.WritebackLumaHTaps[j], - mode_lib->vba.WritebackLumaVTaps[j], - mode_lib->vba.WritebackChromaHTaps[j], - mode_lib->vba.WritebackChromaVTaps[j], - mode_lib->vba.WritebackDestinationWidth[j]) - / mode_lib->vba.DISPCLK); - } - } - } - } - - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) - for (j = 0; j < mode_lib->vba.NumberOfActivePlanes; ++j) - if (mode_lib->vba.BlendingAndTiming[k] == j) - mode_lib->vba.WritebackDelay[mode_lib->vba.VoltageLevel][k] = - mode_lib->vba.WritebackDelay[mode_lib->vba.VoltageLevel][j]; - - mode_lib->vba.VStartupLines = 13; - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - mode_lib->vba.MaxVStartupLines[k] = - mode_lib->vba.VTotal[k] - mode_lib->vba.VActive[k] - - dml_max( - 1.0, - dml_ceil( - mode_lib->vba.WritebackDelay[mode_lib->vba.VoltageLevel][k] - / (mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]), - 1)); - } - - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) - mode_lib->vba.MaximumMaxVStartupLines = dml_max( - mode_lib->vba.MaximumMaxVStartupLines, - mode_lib->vba.MaxVStartupLines[k]); - - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - mode_lib->vba.cursor_bw[k] = 0.0; - for (j = 0; j < mode_lib->vba.NumberOfCursors[k]; ++j) - mode_lib->vba.cursor_bw[k] += mode_lib->vba.CursorWidth[k][j] - * mode_lib->vba.CursorBPP[k][j] / 8.0 - / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) - * mode_lib->vba.VRatio[k]; - } - - do { - double MaxTotalRDBandwidth = 0; - bool DestinationLineTimesForPrefetchLessThan2 = false; - bool VRatioPrefetchMoreThan4 = false; - bool prefetch_vm_bw_valid = true; - bool prefetch_row_bw_valid = true; - double TWait = CalculateTWait( - mode_lib->vba.PrefetchMode, - mode_lib->vba.DRAMClockChangeLatency, - mode_lib->vba.UrgentLatency, - mode_lib->vba.SREnterPlusExitTime); - - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (mode_lib->vba.XFCEnabled[k] == true) { - mode_lib->vba.XFCRemoteSurfaceFlipDelay = - CalculateRemoteSurfaceFlipDelay( - mode_lib, - mode_lib->vba.VRatio[k], - mode_lib->vba.SwathWidthY[k], - dml_ceil( - mode_lib->vba.BytePerPixelDETY[k], - 1), - mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k], - mode_lib->vba.XFCTSlvVupdateOffset, - mode_lib->vba.XFCTSlvVupdateWidth, - mode_lib->vba.XFCTSlvVreadyOffset, - mode_lib->vba.XFCXBUFLatencyTolerance, - mode_lib->vba.XFCFillBWOverhead, - mode_lib->vba.XFCSlvChunkSize, - mode_lib->vba.XFCBusTransportTime, - mode_lib->vba.TCalc, - TWait, - &mode_lib->vba.SrcActiveDrainRate, - &mode_lib->vba.TInitXFill, - &mode_lib->vba.TslvChk); - } else { - mode_lib->vba.XFCRemoteSurfaceFlipDelay = 0; - } - mode_lib->vba.ErrorResult[k] = - CalculatePrefetchSchedule( - mode_lib, - mode_lib->vba.DPPCLK[k], - mode_lib->vba.DISPCLK, - mode_lib->vba.PixelClock[k], - mode_lib->vba.DCFClkDeepSleep, - mode_lib->vba.DSCDelay[k], - mode_lib->vba.DPPPerPlane[k], - mode_lib->vba.ScalerEnabled[k], - mode_lib->vba.NumberOfCursors[k], - mode_lib->vba.DPPCLKDelaySubtotal, - mode_lib->vba.DPPCLKDelaySCL, - mode_lib->vba.DPPCLKDelaySCLLBOnly, - mode_lib->vba.DPPCLKDelayCNVCFormater, - mode_lib->vba.DPPCLKDelayCNVCCursor, - mode_lib->vba.DISPCLKDelaySubtotal, - (unsigned int) (mode_lib->vba.SwathWidthY[k] - / mode_lib->vba.HRatio[k]), - mode_lib->vba.OutputFormat[k], - mode_lib->vba.VTotal[k] - - mode_lib->vba.VActive[k], - mode_lib->vba.HTotal[k], - mode_lib->vba.MaxInterDCNTileRepeaters, - dml_min( - mode_lib->vba.VStartupLines, - mode_lib->vba.MaxVStartupLines[k]), - mode_lib->vba.MaxPageTableLevels, - mode_lib->vba.VirtualMemoryEnable, - mode_lib->vba.DynamicMetadataEnable[k], - mode_lib->vba.DynamicMetadataLinesBeforeActiveRequired[k], - mode_lib->vba.DynamicMetadataTransmittedBytes[k], - mode_lib->vba.DCCEnable[k], - mode_lib->vba.UrgentLatency, - mode_lib->vba.UrgentExtraLatency, - mode_lib->vba.TCalc, - mode_lib->vba.PDEAndMetaPTEBytesFrame[k], - mode_lib->vba.MetaRowByte[k], - mode_lib->vba.PixelPTEBytesPerRow[k], - mode_lib->vba.PrefetchSourceLinesY[k], - mode_lib->vba.SwathWidthY[k], - mode_lib->vba.BytePerPixelDETY[k], - mode_lib->vba.VInitPreFillY[k], - mode_lib->vba.MaxNumSwathY[k], - mode_lib->vba.PrefetchSourceLinesC[k], - mode_lib->vba.BytePerPixelDETC[k], - mode_lib->vba.VInitPreFillC[k], - mode_lib->vba.MaxNumSwathC[k], - mode_lib->vba.SwathHeightY[k], - mode_lib->vba.SwathHeightC[k], - TWait, - mode_lib->vba.XFCEnabled[k], - mode_lib->vba.XFCRemoteSurfaceFlipDelay, - mode_lib->vba.Interlace[k], - mode_lib->vba.ProgressiveToInterlaceUnitInOPP, - &mode_lib->vba.DSTXAfterScaler[k], - &mode_lib->vba.DSTYAfterScaler[k], - &mode_lib->vba.DestinationLinesForPrefetch[k], - &mode_lib->vba.PrefetchBandwidth[k], - &mode_lib->vba.DestinationLinesToRequestVMInVBlank[k], - &mode_lib->vba.DestinationLinesToRequestRowInVBlank[k], - &mode_lib->vba.VRatioPrefetchY[k], - &mode_lib->vba.VRatioPrefetchC[k], - &mode_lib->vba.RequiredPrefetchPixDataBW[k], - &mode_lib->vba.VStartupRequiredWhenNotEnoughTimeForDynamicMetadata, - &mode_lib->vba.Tno_bw[k], - &mode_lib->vba.VUpdateOffsetPix[k], - &mode_lib->vba.VUpdateWidthPix[k], - &mode_lib->vba.VReadyOffsetPix[k]); - if (mode_lib->vba.BlendingAndTiming[k] == k) { - mode_lib->vba.VStartup[k] = dml_min( - mode_lib->vba.VStartupLines, - mode_lib->vba.MaxVStartupLines[k]); - if (mode_lib->vba.VStartupRequiredWhenNotEnoughTimeForDynamicMetadata - != 0) { - mode_lib->vba.VStartup[k] = - mode_lib->vba.VStartupRequiredWhenNotEnoughTimeForDynamicMetadata; - } - } else { - mode_lib->vba.VStartup[k] = - dml_min( - mode_lib->vba.VStartupLines, - mode_lib->vba.MaxVStartupLines[mode_lib->vba.BlendingAndTiming[k]]); - } - } - - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - - if (mode_lib->vba.PDEAndMetaPTEBytesFrame[k] == 0) - mode_lib->vba.prefetch_vm_bw[k] = 0; - else if (mode_lib->vba.DestinationLinesToRequestVMInVBlank[k] > 0) { - mode_lib->vba.prefetch_vm_bw[k] = - (double) mode_lib->vba.PDEAndMetaPTEBytesFrame[k] - / (mode_lib->vba.DestinationLinesToRequestVMInVBlank[k] - * mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]); - } else { - mode_lib->vba.prefetch_vm_bw[k] = 0; - prefetch_vm_bw_valid = false; - } - if (mode_lib->vba.MetaRowByte[k] + mode_lib->vba.PixelPTEBytesPerRow[k] - == 0) - mode_lib->vba.prefetch_row_bw[k] = 0; - else if (mode_lib->vba.DestinationLinesToRequestRowInVBlank[k] > 0) { - mode_lib->vba.prefetch_row_bw[k] = - (double) (mode_lib->vba.MetaRowByte[k] - + mode_lib->vba.PixelPTEBytesPerRow[k]) - / (mode_lib->vba.DestinationLinesToRequestRowInVBlank[k] - * mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]); - } else { - mode_lib->vba.prefetch_row_bw[k] = 0; - prefetch_row_bw_valid = false; - } - - MaxTotalRDBandwidth = - MaxTotalRDBandwidth + mode_lib->vba.cursor_bw[k] - + dml_max( - mode_lib->vba.prefetch_vm_bw[k], - dml_max( - mode_lib->vba.prefetch_row_bw[k], - dml_max( - mode_lib->vba.ReadBandwidthPlaneLuma[k] - + mode_lib->vba.ReadBandwidthPlaneChroma[k], - mode_lib->vba.RequiredPrefetchPixDataBW[k]) - + mode_lib->vba.meta_row_bw[k] - + mode_lib->vba.dpte_row_bw[k])); - - if (mode_lib->vba.DestinationLinesForPrefetch[k] < 2) - DestinationLineTimesForPrefetchLessThan2 = true; - if (mode_lib->vba.VRatioPrefetchY[k] > 4 - || mode_lib->vba.VRatioPrefetchC[k] > 4) - VRatioPrefetchMoreThan4 = true; - } - - if (MaxTotalRDBandwidth <= mode_lib->vba.ReturnBW && prefetch_vm_bw_valid - && prefetch_row_bw_valid && !VRatioPrefetchMoreThan4 - && !DestinationLineTimesForPrefetchLessThan2) - mode_lib->vba.PrefetchModeSupported = true; - else { - mode_lib->vba.PrefetchModeSupported = false; - dml_print( - "DML: CalculatePrefetchSchedule ***failed***. Bandwidth violation. Results are NOT valid\n"); - } - - if (mode_lib->vba.PrefetchModeSupported == true) { - double final_flip_bw[DC__NUM_DPP__MAX]; - unsigned int ImmediateFlipBytes[DC__NUM_DPP__MAX]; - double total_dcn_read_bw_with_flip = 0; - - mode_lib->vba.BandwidthAvailableForImmediateFlip = mode_lib->vba.ReturnBW; - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - mode_lib->vba.BandwidthAvailableForImmediateFlip = - mode_lib->vba.BandwidthAvailableForImmediateFlip - - mode_lib->vba.cursor_bw[k] - - dml_max( - mode_lib->vba.ReadBandwidthPlaneLuma[k] - + mode_lib->vba.ReadBandwidthPlaneChroma[k] - + mode_lib->vba.qual_row_bw[k], - mode_lib->vba.PrefetchBandwidth[k]); - } - - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - ImmediateFlipBytes[k] = 0; - if ((mode_lib->vba.SourcePixelFormat[k] != dm_420_8 - && mode_lib->vba.SourcePixelFormat[k] != dm_420_10)) { - ImmediateFlipBytes[k] = - mode_lib->vba.PDEAndMetaPTEBytesFrame[k] - + mode_lib->vba.MetaRowByte[k] - + mode_lib->vba.PixelPTEBytesPerRow[k]; - } - } - mode_lib->vba.TotImmediateFlipBytes = 0; - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if ((mode_lib->vba.SourcePixelFormat[k] != dm_420_8 - && mode_lib->vba.SourcePixelFormat[k] != dm_420_10)) { - mode_lib->vba.TotImmediateFlipBytes = - mode_lib->vba.TotImmediateFlipBytes - + ImmediateFlipBytes[k]; - } - } - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - CalculateFlipSchedule( - mode_lib, - mode_lib->vba.UrgentExtraLatency, - mode_lib->vba.UrgentLatency, - mode_lib->vba.MaxPageTableLevels, - mode_lib->vba.VirtualMemoryEnable, - mode_lib->vba.BandwidthAvailableForImmediateFlip, - mode_lib->vba.TotImmediateFlipBytes, - mode_lib->vba.SourcePixelFormat[k], - ImmediateFlipBytes[k], - mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k], - mode_lib->vba.VRatio[k], - mode_lib->vba.Tno_bw[k], - mode_lib->vba.PDEAndMetaPTEBytesFrame[k], - mode_lib->vba.MetaRowByte[k], - mode_lib->vba.PixelPTEBytesPerRow[k], - mode_lib->vba.DCCEnable[k], - mode_lib->vba.dpte_row_height[k], - mode_lib->vba.meta_row_height[k], - mode_lib->vba.qual_row_bw[k], - &mode_lib->vba.DestinationLinesToRequestVMInImmediateFlip[k], - &mode_lib->vba.DestinationLinesToRequestRowInImmediateFlip[k], - &final_flip_bw[k], - &mode_lib->vba.ImmediateFlipSupportedForPipe[k]); - } - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - total_dcn_read_bw_with_flip = - total_dcn_read_bw_with_flip - + mode_lib->vba.cursor_bw[k] - + dml_max( - mode_lib->vba.prefetch_vm_bw[k], - dml_max( - mode_lib->vba.prefetch_row_bw[k], - final_flip_bw[k] - + dml_max( - mode_lib->vba.ReadBandwidthPlaneLuma[k] - + mode_lib->vba.ReadBandwidthPlaneChroma[k], - mode_lib->vba.RequiredPrefetchPixDataBW[k]))); - } - mode_lib->vba.ImmediateFlipSupported = true; - if (total_dcn_read_bw_with_flip > mode_lib->vba.ReturnBW) { - mode_lib->vba.ImmediateFlipSupported = false; - } - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (mode_lib->vba.ImmediateFlipSupportedForPipe[k] == false) { - mode_lib->vba.ImmediateFlipSupported = false; - } - } - } else { - mode_lib->vba.ImmediateFlipSupported = false; - } - - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (mode_lib->vba.ErrorResult[k]) { - mode_lib->vba.PrefetchModeSupported = false; - dml_print( - "DML: CalculatePrefetchSchedule ***failed***. Prefetch schedule violation. Results are NOT valid\n"); - } - } - - mode_lib->vba.VStartupLines = mode_lib->vba.VStartupLines + 1; - } while (!((mode_lib->vba.PrefetchModeSupported - && (!mode_lib->vba.ImmediateFlipSupport - || mode_lib->vba.ImmediateFlipSupported)) - || mode_lib->vba.MaximumMaxVStartupLines < mode_lib->vba.VStartupLines)); - - //Display Pipeline Delivery Time in Prefetch - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (mode_lib->vba.VRatioPrefetchY[k] <= 1) { - mode_lib->vba.DisplayPipeLineDeliveryTimeLumaPrefetch[k] = - mode_lib->vba.SwathWidthY[k] * mode_lib->vba.DPPPerPlane[k] - / mode_lib->vba.HRatio[k] - / mode_lib->vba.PixelClock[k]; - } else { - mode_lib->vba.DisplayPipeLineDeliveryTimeLumaPrefetch[k] = - mode_lib->vba.SwathWidthY[k] - / mode_lib->vba.PSCL_THROUGHPUT_LUMA[k] - / mode_lib->vba.DPPCLK[k]; - } - if (mode_lib->vba.BytePerPixelDETC[k] == 0) { - mode_lib->vba.DisplayPipeLineDeliveryTimeChromaPrefetch[k] = 0; - } else { - if (mode_lib->vba.VRatioPrefetchC[k] <= 1) { - mode_lib->vba.DisplayPipeLineDeliveryTimeChromaPrefetch[k] = - mode_lib->vba.SwathWidthY[k] - * mode_lib->vba.DPPPerPlane[k] - / mode_lib->vba.HRatio[k] - / mode_lib->vba.PixelClock[k]; - } else { - mode_lib->vba.DisplayPipeLineDeliveryTimeChromaPrefetch[k] = - mode_lib->vba.SwathWidthY[k] - / mode_lib->vba.PSCL_THROUGHPUT_LUMA[k] - / mode_lib->vba.DPPCLK[k]; - } - } - } - - // Min TTUVBlank - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (mode_lib->vba.PrefetchMode == 0) { - mode_lib->vba.AllowDRAMClockChangeDuringVBlank[k] = true; - mode_lib->vba.AllowDRAMSelfRefreshDuringVBlank[k] = true; - mode_lib->vba.MinTTUVBlank[k] = dml_max( - mode_lib->vba.DRAMClockChangeWatermark, - dml_max( - mode_lib->vba.StutterEnterPlusExitWatermark, - mode_lib->vba.UrgentWatermark)); - } else if (mode_lib->vba.PrefetchMode == 1) { - mode_lib->vba.AllowDRAMClockChangeDuringVBlank[k] = false; - mode_lib->vba.AllowDRAMSelfRefreshDuringVBlank[k] = true; - mode_lib->vba.MinTTUVBlank[k] = dml_max( - mode_lib->vba.StutterEnterPlusExitWatermark, - mode_lib->vba.UrgentWatermark); - } else { - mode_lib->vba.AllowDRAMClockChangeDuringVBlank[k] = false; - mode_lib->vba.AllowDRAMSelfRefreshDuringVBlank[k] = false; - mode_lib->vba.MinTTUVBlank[k] = mode_lib->vba.UrgentWatermark; - } - if (!mode_lib->vba.DynamicMetadataEnable[k]) - mode_lib->vba.MinTTUVBlank[k] = mode_lib->vba.TCalc - + mode_lib->vba.MinTTUVBlank[k]; - } - - // DCC Configuration - mode_lib->vba.ActiveDPPs = 0; - // NB P-State/DRAM Clock Change Support - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - mode_lib->vba.ActiveDPPs = mode_lib->vba.ActiveDPPs + mode_lib->vba.DPPPerPlane[k]; - } - - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - double EffectiveLBLatencyHidingY; - double EffectiveLBLatencyHidingC; - double DPPOutputBufferLinesY; - double DPPOutputBufferLinesC; - double DPPOPPBufferingY; - double MaxDETBufferingTimeY; - double ActiveDRAMClockChangeLatencyMarginY; - - mode_lib->vba.LBLatencyHidingSourceLinesY = - dml_min( - mode_lib->vba.MaxLineBufferLines, - (unsigned int) dml_floor( - (double) mode_lib->vba.LineBufferSize - / mode_lib->vba.LBBitPerPixel[k] - / (mode_lib->vba.SwathWidthY[k] - / dml_max( - mode_lib->vba.HRatio[k], - 1.0)), - 1)) - (mode_lib->vba.vtaps[k] - 1); - - mode_lib->vba.LBLatencyHidingSourceLinesC = - dml_min( - mode_lib->vba.MaxLineBufferLines, - (unsigned int) dml_floor( - (double) mode_lib->vba.LineBufferSize - / mode_lib->vba.LBBitPerPixel[k] - / (mode_lib->vba.SwathWidthY[k] - / 2.0 - / dml_max( - mode_lib->vba.HRatio[k] - / 2, - 1.0)), - 1)) - - (mode_lib->vba.VTAPsChroma[k] - 1); - - EffectiveLBLatencyHidingY = mode_lib->vba.LBLatencyHidingSourceLinesY - / mode_lib->vba.VRatio[k] - * (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]); - - EffectiveLBLatencyHidingC = mode_lib->vba.LBLatencyHidingSourceLinesC - / (mode_lib->vba.VRatio[k] / 2) - * (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]); - - if (mode_lib->vba.SwathWidthY[k] > 2 * mode_lib->vba.DPPOutputBufferPixels) { - DPPOutputBufferLinesY = mode_lib->vba.DPPOutputBufferPixels - / mode_lib->vba.SwathWidthY[k]; - } else if (mode_lib->vba.SwathWidthY[k] > mode_lib->vba.DPPOutputBufferPixels) { - DPPOutputBufferLinesY = 0.5; - } else { - DPPOutputBufferLinesY = 1; - } - - if (mode_lib->vba.SwathWidthY[k] / 2 > 2 * mode_lib->vba.DPPOutputBufferPixels) { - DPPOutputBufferLinesC = mode_lib->vba.DPPOutputBufferPixels - / (mode_lib->vba.SwathWidthY[k] / 2); - } else if (mode_lib->vba.SwathWidthY[k] / 2 > mode_lib->vba.DPPOutputBufferPixels) { - DPPOutputBufferLinesC = 0.5; - } else { - DPPOutputBufferLinesC = 1; - } - - DPPOPPBufferingY = (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) - * (DPPOutputBufferLinesY + mode_lib->vba.OPPOutputBufferLines); - MaxDETBufferingTimeY = mode_lib->vba.FullDETBufferingTimeY[k] - + (mode_lib->vba.LinesInDETY[k] - - mode_lib->vba.LinesInDETYRoundedDownToSwath[k]) - / mode_lib->vba.SwathHeightY[k] - * (mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]); - - ActiveDRAMClockChangeLatencyMarginY = DPPOPPBufferingY + EffectiveLBLatencyHidingY - + MaxDETBufferingTimeY - mode_lib->vba.DRAMClockChangeWatermark; - - if (mode_lib->vba.ActiveDPPs > 1) { - ActiveDRAMClockChangeLatencyMarginY = - ActiveDRAMClockChangeLatencyMarginY - - (1 - 1 / (mode_lib->vba.ActiveDPPs - 1)) - * mode_lib->vba.SwathHeightY[k] - * (mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]); - } - - if (mode_lib->vba.BytePerPixelDETC[k] > 0) { - double DPPOPPBufferingC = (mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]) - * (DPPOutputBufferLinesC - + mode_lib->vba.OPPOutputBufferLines); - double MaxDETBufferingTimeC = - mode_lib->vba.FullDETBufferingTimeC[k] - + (mode_lib->vba.LinesInDETC[k] - - mode_lib->vba.LinesInDETCRoundedDownToSwath[k]) - / mode_lib->vba.SwathHeightC[k] - * (mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]); - double ActiveDRAMClockChangeLatencyMarginC = DPPOPPBufferingC - + EffectiveLBLatencyHidingC + MaxDETBufferingTimeC - - mode_lib->vba.DRAMClockChangeWatermark; - - if (mode_lib->vba.ActiveDPPs > 1) { - ActiveDRAMClockChangeLatencyMarginC = - ActiveDRAMClockChangeLatencyMarginC - - (1 - - 1 - / (mode_lib->vba.ActiveDPPs - - 1)) - * mode_lib->vba.SwathHeightC[k] - * (mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]); - } - mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = dml_min( - ActiveDRAMClockChangeLatencyMarginY, - ActiveDRAMClockChangeLatencyMarginC); - } else { - mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = - ActiveDRAMClockChangeLatencyMarginY; - } - - if (mode_lib->vba.WritebackEnable[k]) { - double WritebackDRAMClockChangeLatencyMargin; - - if (mode_lib->vba.WritebackPixelFormat[k] == dm_444_32) { - WritebackDRAMClockChangeLatencyMargin = - (double) (mode_lib->vba.WritebackInterfaceLumaBufferSize - + mode_lib->vba.WritebackInterfaceChromaBufferSize) - / (mode_lib->vba.WritebackDestinationWidth[k] - * mode_lib->vba.WritebackDestinationHeight[k] - / (mode_lib->vba.WritebackSourceHeight[k] - * mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]) - * 4) - - mode_lib->vba.WritebackDRAMClockChangeWatermark; - } else if (mode_lib->vba.WritebackPixelFormat[k] == dm_420_10) { - WritebackDRAMClockChangeLatencyMargin = - dml_min( - (double) mode_lib->vba.WritebackInterfaceLumaBufferSize - * 8.0 / 10, - 2.0 - * mode_lib->vba.WritebackInterfaceChromaBufferSize - * 8 / 10) - / (mode_lib->vba.WritebackDestinationWidth[k] - * mode_lib->vba.WritebackDestinationHeight[k] - / (mode_lib->vba.WritebackSourceHeight[k] - * mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k])) - - mode_lib->vba.WritebackDRAMClockChangeWatermark; - } else { - WritebackDRAMClockChangeLatencyMargin = - dml_min( - (double) mode_lib->vba.WritebackInterfaceLumaBufferSize, - 2.0 - * mode_lib->vba.WritebackInterfaceChromaBufferSize) - / (mode_lib->vba.WritebackDestinationWidth[k] - * mode_lib->vba.WritebackDestinationHeight[k] - / (mode_lib->vba.WritebackSourceHeight[k] - * mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k])) - - mode_lib->vba.WritebackDRAMClockChangeWatermark; - } - mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = dml_min( - mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k], - WritebackDRAMClockChangeLatencyMargin); - } - } - - mode_lib->vba.MinActiveDRAMClockChangeMargin = 999999; - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] - < mode_lib->vba.MinActiveDRAMClockChangeMargin) { - mode_lib->vba.MinActiveDRAMClockChangeMargin = - mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k]; - } - } - - mode_lib->vba.MinActiveDRAMClockChangeLatencySupported = - mode_lib->vba.MinActiveDRAMClockChangeMargin - + mode_lib->vba.DRAMClockChangeLatency; - - if (mode_lib->vba.MinActiveDRAMClockChangeMargin > 0) { - mode_lib->vba.DRAMClockChangeSupport = dm_dram_clock_change_vactive; - } else { - if (mode_lib->vba.SynchronizedVBlank || mode_lib->vba.NumberOfActivePlanes == 1) { - mode_lib->vba.DRAMClockChangeSupport = dm_dram_clock_change_vblank; - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (!mode_lib->vba.AllowDRAMClockChangeDuringVBlank[k]) { - mode_lib->vba.DRAMClockChangeSupport = - dm_dram_clock_change_unsupported; - } - } - } else { - mode_lib->vba.DRAMClockChangeSupport = dm_dram_clock_change_unsupported; - } - } - - //XFC Parameters: - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - if (mode_lib->vba.XFCEnabled[k] == true) { - double TWait; - - mode_lib->vba.XFCSlaveVUpdateOffset[k] = mode_lib->vba.XFCTSlvVupdateOffset; - mode_lib->vba.XFCSlaveVupdateWidth[k] = mode_lib->vba.XFCTSlvVupdateWidth; - mode_lib->vba.XFCSlaveVReadyOffset[k] = mode_lib->vba.XFCTSlvVreadyOffset; - TWait = CalculateTWait( - mode_lib->vba.PrefetchMode, - mode_lib->vba.DRAMClockChangeLatency, - mode_lib->vba.UrgentLatency, - mode_lib->vba.SREnterPlusExitTime); - mode_lib->vba.XFCRemoteSurfaceFlipDelay = CalculateRemoteSurfaceFlipDelay( - mode_lib, - mode_lib->vba.VRatio[k], - mode_lib->vba.SwathWidthY[k], - dml_ceil(mode_lib->vba.BytePerPixelDETY[k], 1), - mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k], - mode_lib->vba.XFCTSlvVupdateOffset, - mode_lib->vba.XFCTSlvVupdateWidth, - mode_lib->vba.XFCTSlvVreadyOffset, - mode_lib->vba.XFCXBUFLatencyTolerance, - mode_lib->vba.XFCFillBWOverhead, - mode_lib->vba.XFCSlvChunkSize, - mode_lib->vba.XFCBusTransportTime, - mode_lib->vba.TCalc, - TWait, - &mode_lib->vba.SrcActiveDrainRate, - &mode_lib->vba.TInitXFill, - &mode_lib->vba.TslvChk); - mode_lib->vba.XFCRemoteSurfaceFlipLatency[k] = - dml_floor( - mode_lib->vba.XFCRemoteSurfaceFlipDelay - / (mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]), - 1); - mode_lib->vba.XFCTransferDelay[k] = - dml_ceil( - mode_lib->vba.XFCBusTransportTime - / (mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]), - 1); - mode_lib->vba.XFCPrechargeDelay[k] = - dml_ceil( - (mode_lib->vba.XFCBusTransportTime - + mode_lib->vba.TInitXFill - + mode_lib->vba.TslvChk) - / (mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]), - 1); - mode_lib->vba.InitFillLevel = mode_lib->vba.XFCXBUFLatencyTolerance - * mode_lib->vba.SrcActiveDrainRate; - mode_lib->vba.FinalFillMargin = - (mode_lib->vba.DestinationLinesToRequestVMInVBlank[k] - + mode_lib->vba.DestinationLinesToRequestRowInVBlank[k]) - * mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k] - * mode_lib->vba.SrcActiveDrainRate - + mode_lib->vba.XFCFillConstant; - mode_lib->vba.FinalFillLevel = mode_lib->vba.XFCRemoteSurfaceFlipDelay - * mode_lib->vba.SrcActiveDrainRate - + mode_lib->vba.FinalFillMargin; - mode_lib->vba.RemainingFillLevel = dml_max( - 0.0, - mode_lib->vba.FinalFillLevel - mode_lib->vba.InitFillLevel); - mode_lib->vba.TFinalxFill = mode_lib->vba.RemainingFillLevel - / (mode_lib->vba.SrcActiveDrainRate - * mode_lib->vba.XFCFillBWOverhead / 100); - mode_lib->vba.XFCPrefetchMargin[k] = - mode_lib->vba.XFCRemoteSurfaceFlipDelay - + mode_lib->vba.TFinalxFill - + (mode_lib->vba.DestinationLinesToRequestVMInVBlank[k] - + mode_lib->vba.DestinationLinesToRequestRowInVBlank[k]) - * mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]; - } else { - mode_lib->vba.XFCSlaveVUpdateOffset[k] = 0; - mode_lib->vba.XFCSlaveVupdateWidth[k] = 0; - mode_lib->vba.XFCSlaveVReadyOffset[k] = 0; - mode_lib->vba.XFCRemoteSurfaceFlipLatency[k] = 0; - mode_lib->vba.XFCPrechargeDelay[k] = 0; - mode_lib->vba.XFCTransferDelay[k] = 0; - mode_lib->vba.XFCPrefetchMargin[k] = 0; - } - } -} - -static void DisplayPipeConfiguration(struct display_mode_lib *mode_lib) -{ - double BytePerPixDETY; - double BytePerPixDETC; - double Read256BytesBlockHeightY; - double Read256BytesBlockHeightC; - double Read256BytesBlockWidthY; - double Read256BytesBlockWidthC; - double MaximumSwathHeightY; - double MaximumSwathHeightC; - double MinimumSwathHeightY; - double MinimumSwathHeightC; - double SwathWidth; - double SwathWidthGranularityY; - double SwathWidthGranularityC; - double RoundedUpMaxSwathSizeBytesY; - double RoundedUpMaxSwathSizeBytesC; - unsigned int j, k; - - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - bool MainPlaneDoesODMCombine = false; - - if (mode_lib->vba.SourcePixelFormat[k] == dm_444_64) { - BytePerPixDETY = 8; - BytePerPixDETC = 0; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_32) { - BytePerPixDETY = 4; - BytePerPixDETC = 0; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_16) { - BytePerPixDETY = 2; - BytePerPixDETC = 0; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_8) { - BytePerPixDETY = 1; - BytePerPixDETC = 0; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_420_8) { - BytePerPixDETY = 1; - BytePerPixDETC = 2; - } else { - BytePerPixDETY = 4.0 / 3.0; - BytePerPixDETC = 8.0 / 3.0; - } - - if ((mode_lib->vba.SourcePixelFormat[k] == dm_444_64 - || mode_lib->vba.SourcePixelFormat[k] == dm_444_32 - || mode_lib->vba.SourcePixelFormat[k] == dm_444_16 - || mode_lib->vba.SourcePixelFormat[k] == dm_444_8)) { - if (mode_lib->vba.SurfaceTiling[k] == dm_sw_linear) { - Read256BytesBlockHeightY = 1; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_64) { - Read256BytesBlockHeightY = 4; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_32 - || mode_lib->vba.SourcePixelFormat[k] == dm_444_16) { - Read256BytesBlockHeightY = 8; - } else { - Read256BytesBlockHeightY = 16; - } - Read256BytesBlockWidthY = 256 / dml_ceil(BytePerPixDETY, 1) - / Read256BytesBlockHeightY; - Read256BytesBlockHeightC = 0; - Read256BytesBlockWidthC = 0; - } else { - if (mode_lib->vba.SurfaceTiling[k] == dm_sw_linear) { - Read256BytesBlockHeightY = 1; - Read256BytesBlockHeightC = 1; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_420_8) { - Read256BytesBlockHeightY = 16; - Read256BytesBlockHeightC = 8; - } else { - Read256BytesBlockHeightY = 8; - Read256BytesBlockHeightC = 8; - } - Read256BytesBlockWidthY = 256 / dml_ceil(BytePerPixDETY, 1) - / Read256BytesBlockHeightY; - Read256BytesBlockWidthC = 256 / dml_ceil(BytePerPixDETC, 2) - / Read256BytesBlockHeightC; - } - - if (mode_lib->vba.SourceScan[k] == dm_horz) { - MaximumSwathHeightY = Read256BytesBlockHeightY; - MaximumSwathHeightC = Read256BytesBlockHeightC; - } else { - MaximumSwathHeightY = Read256BytesBlockWidthY; - MaximumSwathHeightC = Read256BytesBlockWidthC; - } - - if ((mode_lib->vba.SourcePixelFormat[k] == dm_444_64 - || mode_lib->vba.SourcePixelFormat[k] == dm_444_32 - || mode_lib->vba.SourcePixelFormat[k] == dm_444_16 - || mode_lib->vba.SourcePixelFormat[k] == dm_444_8)) { - if (mode_lib->vba.SurfaceTiling[k] == dm_sw_linear - || (mode_lib->vba.SourcePixelFormat[k] == dm_444_64 - && (mode_lib->vba.SurfaceTiling[k] - == dm_sw_4kb_s - || mode_lib->vba.SurfaceTiling[k] - == dm_sw_4kb_s_x - || mode_lib->vba.SurfaceTiling[k] - == dm_sw_64kb_s - || mode_lib->vba.SurfaceTiling[k] - == dm_sw_64kb_s_t - || mode_lib->vba.SurfaceTiling[k] - == dm_sw_64kb_s_x - || mode_lib->vba.SurfaceTiling[k] - == dm_sw_var_s - || mode_lib->vba.SurfaceTiling[k] - == dm_sw_var_s_x) - && mode_lib->vba.SourceScan[k] == dm_horz)) { - MinimumSwathHeightY = MaximumSwathHeightY; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_8 - && mode_lib->vba.SourceScan[k] != dm_horz) { - MinimumSwathHeightY = MaximumSwathHeightY; - } else { - MinimumSwathHeightY = MaximumSwathHeightY / 2.0; - } - MinimumSwathHeightC = MaximumSwathHeightC; - } else { - if (mode_lib->vba.SurfaceTiling[k] == dm_sw_linear) { - MinimumSwathHeightY = MaximumSwathHeightY; - MinimumSwathHeightC = MaximumSwathHeightC; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_420_8 - && mode_lib->vba.SourceScan[k] == dm_horz) { - MinimumSwathHeightY = MaximumSwathHeightY / 2.0; - MinimumSwathHeightC = MaximumSwathHeightC; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_420_10 - && mode_lib->vba.SourceScan[k] == dm_horz) { - MinimumSwathHeightC = MaximumSwathHeightC / 2.0; - MinimumSwathHeightY = MaximumSwathHeightY; - } else { - MinimumSwathHeightY = MaximumSwathHeightY; - MinimumSwathHeightC = MaximumSwathHeightC; - } - } - - if (mode_lib->vba.SourceScan[k] == dm_horz) { - SwathWidth = mode_lib->vba.ViewportWidth[k]; - } else { - SwathWidth = mode_lib->vba.ViewportHeight[k]; - } - - if (mode_lib->vba.ODMCombineEnabled[k] == true) { - MainPlaneDoesODMCombine = true; - } - for (j = 0; j < mode_lib->vba.NumberOfActivePlanes; ++j) { - if (mode_lib->vba.BlendingAndTiming[k] == j - && mode_lib->vba.ODMCombineEnabled[j] == true) { - MainPlaneDoesODMCombine = true; - } - } - - if (MainPlaneDoesODMCombine == true) { - SwathWidth = dml_min( - SwathWidth, - mode_lib->vba.HActive[k] / 2.0 * mode_lib->vba.HRatio[k]); - } else { - SwathWidth = SwathWidth / mode_lib->vba.DPPPerPlane[k]; - } - - SwathWidthGranularityY = 256 / dml_ceil(BytePerPixDETY, 1) / MaximumSwathHeightY; - RoundedUpMaxSwathSizeBytesY = (dml_ceil( - (double) (SwathWidth - 1), - SwathWidthGranularityY) + SwathWidthGranularityY) * BytePerPixDETY - * MaximumSwathHeightY; - if (mode_lib->vba.SourcePixelFormat[k] == dm_420_10) { - RoundedUpMaxSwathSizeBytesY = dml_ceil(RoundedUpMaxSwathSizeBytesY, 256) - + 256; - } - if (MaximumSwathHeightC > 0) { - SwathWidthGranularityC = 256.0 / dml_ceil(BytePerPixDETC, 2) - / MaximumSwathHeightC; - RoundedUpMaxSwathSizeBytesC = (dml_ceil( - (double) (SwathWidth / 2.0 - 1), - SwathWidthGranularityC) + SwathWidthGranularityC) - * BytePerPixDETC * MaximumSwathHeightC; - if (mode_lib->vba.SourcePixelFormat[k] == dm_420_10) { - RoundedUpMaxSwathSizeBytesC = dml_ceil( - RoundedUpMaxSwathSizeBytesC, - 256) + 256; - } - } else - RoundedUpMaxSwathSizeBytesC = 0.0; - - if (RoundedUpMaxSwathSizeBytesY + RoundedUpMaxSwathSizeBytesC - <= mode_lib->vba.DETBufferSizeInKByte * 1024.0 / 2.0) { - mode_lib->vba.SwathHeightY[k] = MaximumSwathHeightY; - mode_lib->vba.SwathHeightC[k] = MaximumSwathHeightC; - } else { - mode_lib->vba.SwathHeightY[k] = MinimumSwathHeightY; - mode_lib->vba.SwathHeightC[k] = MinimumSwathHeightC; - } - - if (mode_lib->vba.SwathHeightC[k] == 0) { - mode_lib->vba.DETBufferSizeY[k] = mode_lib->vba.DETBufferSizeInKByte * 1024; - mode_lib->vba.DETBufferSizeC[k] = 0; - } else if (mode_lib->vba.SwathHeightY[k] <= mode_lib->vba.SwathHeightC[k]) { - mode_lib->vba.DETBufferSizeY[k] = mode_lib->vba.DETBufferSizeInKByte - * 1024.0 / 2; - mode_lib->vba.DETBufferSizeC[k] = mode_lib->vba.DETBufferSizeInKByte - * 1024.0 / 2; - } else { - mode_lib->vba.DETBufferSizeY[k] = mode_lib->vba.DETBufferSizeInKByte - * 1024.0 * 2 / 3; - mode_lib->vba.DETBufferSizeC[k] = mode_lib->vba.DETBufferSizeInKByte - * 1024.0 / 3; - } - } -} - -bool Calculate256BBlockSizes( - enum source_format_class SourcePixelFormat, - enum dm_swizzle_mode SurfaceTiling, - unsigned int BytePerPixelY, - unsigned int BytePerPixelC, - unsigned int *BlockHeight256BytesY, - unsigned int *BlockHeight256BytesC, - unsigned int *BlockWidth256BytesY, - unsigned int *BlockWidth256BytesC) -{ - if ((SourcePixelFormat == dm_444_64 || SourcePixelFormat == dm_444_32 - || SourcePixelFormat == dm_444_16 - || SourcePixelFormat == dm_444_8)) { - if (SurfaceTiling == dm_sw_linear) { - *BlockHeight256BytesY = 1; - } else if (SourcePixelFormat == dm_444_64) { - *BlockHeight256BytesY = 4; - } else if (SourcePixelFormat == dm_444_8) { - *BlockHeight256BytesY = 16; - } else { - *BlockHeight256BytesY = 8; - } - *BlockWidth256BytesY = 256 / BytePerPixelY / *BlockHeight256BytesY; - *BlockHeight256BytesC = 0; - *BlockWidth256BytesC = 0; - } else { - if (SurfaceTiling == dm_sw_linear) { - *BlockHeight256BytesY = 1; - *BlockHeight256BytesC = 1; - } else if (SourcePixelFormat == dm_420_8) { - *BlockHeight256BytesY = 16; - *BlockHeight256BytesC = 8; - } else { - *BlockHeight256BytesY = 8; - *BlockHeight256BytesC = 8; - } - *BlockWidth256BytesY = 256 / BytePerPixelY / *BlockHeight256BytesY; - *BlockWidth256BytesC = 256 / BytePerPixelC / *BlockHeight256BytesC; - } - return true; -} - -static double CalculateTWait( - unsigned int PrefetchMode, - double DRAMClockChangeLatency, - double UrgentLatency, - double SREnterPlusExitTime) -{ - if (PrefetchMode == 0) { - return dml_max( - DRAMClockChangeLatency + UrgentLatency, - dml_max(SREnterPlusExitTime, UrgentLatency)); - } else if (PrefetchMode == 1) { - return dml_max(SREnterPlusExitTime, UrgentLatency); - } else { - return UrgentLatency; - } -} - -static double CalculateRemoteSurfaceFlipDelay( - struct display_mode_lib *mode_lib, - double VRatio, - double SwathWidth, - double Bpp, - double LineTime, - double XFCTSlvVupdateOffset, - double XFCTSlvVupdateWidth, - double XFCTSlvVreadyOffset, - double XFCXBUFLatencyTolerance, - double XFCFillBWOverhead, - double XFCSlvChunkSize, - double XFCBusTransportTime, - double TCalc, - double TWait, - double *SrcActiveDrainRate, - double *TInitXFill, - double *TslvChk) -{ - double TSlvSetup, AvgfillRate, result; - - *SrcActiveDrainRate = VRatio * SwathWidth * Bpp / LineTime; - TSlvSetup = XFCTSlvVupdateOffset + XFCTSlvVupdateWidth + XFCTSlvVreadyOffset; - *TInitXFill = XFCXBUFLatencyTolerance / (1 + XFCFillBWOverhead / 100); - AvgfillRate = *SrcActiveDrainRate * (1 + XFCFillBWOverhead / 100); - *TslvChk = XFCSlvChunkSize / AvgfillRate; - dml_print( - "DML::CalculateRemoteSurfaceFlipDelay: SrcActiveDrainRate: %f\n", - *SrcActiveDrainRate); - dml_print("DML::CalculateRemoteSurfaceFlipDelay: TSlvSetup: %f\n", TSlvSetup); - dml_print("DML::CalculateRemoteSurfaceFlipDelay: TInitXFill: %f\n", *TInitXFill); - dml_print("DML::CalculateRemoteSurfaceFlipDelay: AvgfillRate: %f\n", AvgfillRate); - dml_print("DML::CalculateRemoteSurfaceFlipDelay: TslvChk: %f\n", *TslvChk); - result = 2 * XFCBusTransportTime + TSlvSetup + TCalc + TWait + *TslvChk + *TInitXFill; // TODO: This doesn't seem to match programming guide - dml_print("DML::CalculateRemoteSurfaceFlipDelay: RemoteSurfaceFlipDelay: %f\n", result); - return result; -} - -static double CalculateWriteBackDISPCLK( - enum source_format_class WritebackPixelFormat, - double PixelClock, - double WritebackHRatio, - double WritebackVRatio, - unsigned int WritebackLumaHTaps, - unsigned int WritebackLumaVTaps, - unsigned int WritebackChromaHTaps, - unsigned int WritebackChromaVTaps, - double WritebackDestinationWidth, - unsigned int HTotal, - unsigned int WritebackChromaLineBufferWidth) -{ - double CalculateWriteBackDISPCLK = - 1.01 * PixelClock - * dml_max( - dml_ceil(WritebackLumaHTaps / 4.0, 1) - / WritebackHRatio, - dml_max( - (WritebackLumaVTaps - * dml_ceil( - 1.0 - / WritebackVRatio, - 1) - * dml_ceil( - WritebackDestinationWidth - / 4.0, - 1) - + dml_ceil( - WritebackDestinationWidth - / 4.0, - 1)) - / (double) HTotal - + dml_ceil( - 1.0 - / WritebackVRatio, - 1) - * (dml_ceil( - WritebackLumaVTaps - / 4.0, - 1) - + 4.0) - / (double) HTotal, - dml_ceil( - 1.0 - / WritebackVRatio, - 1) - * WritebackDestinationWidth - / (double) HTotal)); - if (WritebackPixelFormat != dm_444_32) { - CalculateWriteBackDISPCLK = - dml_max( - CalculateWriteBackDISPCLK, - 1.01 * PixelClock - * dml_max( - dml_ceil( - WritebackChromaHTaps - / 2.0, - 1) - / (2 - * WritebackHRatio), - dml_max( - (WritebackChromaVTaps - * dml_ceil( - 1 - / (2 - * WritebackVRatio), - 1) - * dml_ceil( - WritebackDestinationWidth - / 2.0 - / 2.0, - 1) - + dml_ceil( - WritebackDestinationWidth - / 2.0 - / WritebackChromaLineBufferWidth, - 1)) - / HTotal - + dml_ceil( - 1 - / (2 - * WritebackVRatio), - 1) - * (dml_ceil( - WritebackChromaVTaps - / 4.0, - 1) - + 4) - / HTotal, - dml_ceil( - 1.0 - / (2 - * WritebackVRatio), - 1) - * WritebackDestinationWidth - / 2.0 - / HTotal))); - } - return CalculateWriteBackDISPCLK; -} - -static double CalculateWriteBackDelay( - enum source_format_class WritebackPixelFormat, - double WritebackHRatio, - double WritebackVRatio, - unsigned int WritebackLumaHTaps, - unsigned int WritebackLumaVTaps, - unsigned int WritebackChromaHTaps, - unsigned int WritebackChromaVTaps, - unsigned int WritebackDestinationWidth) -{ - double CalculateWriteBackDelay = - dml_max( - dml_ceil(WritebackLumaHTaps / 4.0, 1) / WritebackHRatio, - WritebackLumaVTaps * dml_ceil(1.0 / WritebackVRatio, 1) - * dml_ceil( - WritebackDestinationWidth - / 4.0, - 1) - + dml_ceil(1.0 / WritebackVRatio, 1) - * (dml_ceil( - WritebackLumaVTaps - / 4.0, - 1) + 4)); - - if (WritebackPixelFormat != dm_444_32) { - CalculateWriteBackDelay = - dml_max( - CalculateWriteBackDelay, - dml_max( - dml_ceil( - WritebackChromaHTaps - / 2.0, - 1) - / (2 - * WritebackHRatio), - WritebackChromaVTaps - * dml_ceil( - 1 - / (2 - * WritebackVRatio), - 1) - * dml_ceil( - WritebackDestinationWidth - / 2.0 - / 2.0, - 1) - + dml_ceil( - 1 - / (2 - * WritebackVRatio), - 1) - * (dml_ceil( - WritebackChromaVTaps - / 4.0, - 1) - + 4))); - } - return CalculateWriteBackDelay; -} - -static void CalculateActiveRowBandwidth( - bool VirtualMemoryEnable, - enum source_format_class SourcePixelFormat, - double VRatio, - bool DCCEnable, - double LineTime, - unsigned int MetaRowByteLuma, - unsigned int MetaRowByteChroma, - unsigned int meta_row_height_luma, - unsigned int meta_row_height_chroma, - unsigned int PixelPTEBytesPerRowLuma, - unsigned int PixelPTEBytesPerRowChroma, - unsigned int dpte_row_height_luma, - unsigned int dpte_row_height_chroma, - double *meta_row_bw, - double *dpte_row_bw, - double *qual_row_bw) -{ - if (DCCEnable != true) { - *meta_row_bw = 0; - } else if (SourcePixelFormat == dm_420_8 || SourcePixelFormat == dm_420_10) { - *meta_row_bw = VRatio * MetaRowByteLuma / (meta_row_height_luma * LineTime) - + VRatio / 2 * MetaRowByteChroma - / (meta_row_height_chroma * LineTime); - } else { - *meta_row_bw = VRatio * MetaRowByteLuma / (meta_row_height_luma * LineTime); - } - - if (VirtualMemoryEnable != true) { - *dpte_row_bw = 0; - } else if (SourcePixelFormat == dm_420_8 || SourcePixelFormat == dm_420_10) { - *dpte_row_bw = VRatio * PixelPTEBytesPerRowLuma / (dpte_row_height_luma * LineTime) - + VRatio / 2 * PixelPTEBytesPerRowChroma - / (dpte_row_height_chroma * LineTime); - } else { - *dpte_row_bw = VRatio * PixelPTEBytesPerRowLuma / (dpte_row_height_luma * LineTime); - } - - if ((SourcePixelFormat == dm_420_8 || SourcePixelFormat == dm_420_10)) { - *qual_row_bw = *meta_row_bw + *dpte_row_bw; - } else { - *qual_row_bw = 0; - } -} - -static void CalculateFlipSchedule( - struct display_mode_lib *mode_lib, - double UrgentExtraLatency, - double UrgentLatency, - unsigned int MaxPageTableLevels, - bool VirtualMemoryEnable, - double BandwidthAvailableForImmediateFlip, - unsigned int TotImmediateFlipBytes, - enum source_format_class SourcePixelFormat, - unsigned int ImmediateFlipBytes, - double LineTime, - double Tno_bw, - double VRatio, - double PDEAndMetaPTEBytesFrame, - unsigned int MetaRowByte, - unsigned int PixelPTEBytesPerRow, - bool DCCEnable, - unsigned int dpte_row_height, - unsigned int meta_row_height, - double qual_row_bw, - double *DestinationLinesToRequestVMInImmediateFlip, - double *DestinationLinesToRequestRowInImmediateFlip, - double *final_flip_bw, - bool *ImmediateFlipSupportedForPipe) -{ - double min_row_time = 0.0; - - if (SourcePixelFormat == dm_420_8 || SourcePixelFormat == dm_420_10) { - *DestinationLinesToRequestVMInImmediateFlip = 0.0; - *DestinationLinesToRequestRowInImmediateFlip = 0.0; - *final_flip_bw = qual_row_bw; - *ImmediateFlipSupportedForPipe = true; - } else { - double TimeForFetchingMetaPTEImmediateFlip; - double TimeForFetchingRowInVBlankImmediateFlip; - - if (VirtualMemoryEnable == true) { - mode_lib->vba.ImmediateFlipBW = BandwidthAvailableForImmediateFlip - * ImmediateFlipBytes / TotImmediateFlipBytes; - TimeForFetchingMetaPTEImmediateFlip = - dml_max( - Tno_bw - + PDEAndMetaPTEBytesFrame - / mode_lib->vba.ImmediateFlipBW, - dml_max( - UrgentExtraLatency - + UrgentLatency - * (MaxPageTableLevels - - 1), - LineTime / 4.0)); - } else { - TimeForFetchingMetaPTEImmediateFlip = 0; - } - - *DestinationLinesToRequestVMInImmediateFlip = dml_floor( - 4.0 * (TimeForFetchingMetaPTEImmediateFlip / LineTime + 0.125), - 1) / 4.0; - - if ((VirtualMemoryEnable == true || DCCEnable == true)) { - mode_lib->vba.ImmediateFlipBW = BandwidthAvailableForImmediateFlip - * ImmediateFlipBytes / TotImmediateFlipBytes; - TimeForFetchingRowInVBlankImmediateFlip = dml_max( - (MetaRowByte + PixelPTEBytesPerRow) - / mode_lib->vba.ImmediateFlipBW, - dml_max(UrgentLatency, LineTime / 4.0)); - } else { - TimeForFetchingRowInVBlankImmediateFlip = 0; - } - - *DestinationLinesToRequestRowInImmediateFlip = dml_floor( - 4.0 * (TimeForFetchingRowInVBlankImmediateFlip / LineTime + 0.125), - 1) / 4.0; - - if (VirtualMemoryEnable == true) { - *final_flip_bw = - dml_max( - PDEAndMetaPTEBytesFrame - / (*DestinationLinesToRequestVMInImmediateFlip - * LineTime), - (MetaRowByte + PixelPTEBytesPerRow) - / (TimeForFetchingRowInVBlankImmediateFlip - * LineTime)); - } else if (MetaRowByte + PixelPTEBytesPerRow > 0) { - *final_flip_bw = (MetaRowByte + PixelPTEBytesPerRow) - / (TimeForFetchingRowInVBlankImmediateFlip * LineTime); - } else { - *final_flip_bw = 0; - } - - if (VirtualMemoryEnable && !DCCEnable) - min_row_time = dpte_row_height * LineTime / VRatio; - else if (!VirtualMemoryEnable && DCCEnable) - min_row_time = meta_row_height * LineTime / VRatio; - else - min_row_time = dml_min(dpte_row_height, meta_row_height) * LineTime - / VRatio; - - if (*DestinationLinesToRequestVMInImmediateFlip >= 8 - || *DestinationLinesToRequestRowInImmediateFlip >= 16 - || TimeForFetchingMetaPTEImmediateFlip - + 2 * TimeForFetchingRowInVBlankImmediateFlip - > min_row_time) - *ImmediateFlipSupportedForPipe = false; - else - *ImmediateFlipSupportedForPipe = true; - } -} - -static void PixelClockAdjustmentForProgressiveToInterlaceUnit(struct display_mode_lib *mode_lib) -{ - unsigned int k; - - //Progressive To dml_ml->vba.Interlace Unit Effect - for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { - mode_lib->vba.PixelClockBackEnd[k] = mode_lib->vba.PixelClock[k]; - if (mode_lib->vba.Interlace[k] == 1 - && mode_lib->vba.ProgressiveToInterlaceUnitInOPP == true) { - mode_lib->vba.PixelClock[k] = 2 * mode_lib->vba.PixelClock[k]; - } - } -} - -static unsigned int CursorBppEnumToBits(enum cursor_bpp ebpp) -{ - switch (ebpp) { - case dm_cur_2bit: - return 2; - case dm_cur_32bit: - return 32; - case dm_cur_64bit: - return 64; - default: - return 0; - } -} - -static unsigned int TruncToValidBPP( - double DecimalBPP, - bool DSCEnabled, - enum output_encoder_class Output, - enum output_format_class Format, - unsigned int DSCInputBitPerComponent) -{ - if (Output == dm_hdmi) { - if (Format == dm_420) { - if (DecimalBPP >= 18) - return 18; - else if (DecimalBPP >= 15) - return 15; - else if (DecimalBPP >= 12) - return 12; - else - return BPP_INVALID; - } else if (Format == dm_444) { - if (DecimalBPP >= 36) - return 36; - else if (DecimalBPP >= 30) - return 30; - else if (DecimalBPP >= 24) - return 24; - else - return BPP_INVALID; - } else { - if (DecimalBPP / 1.5 >= 24) - return 24; - else if (DecimalBPP / 1.5 >= 20) - return 20; - else if (DecimalBPP / 1.5 >= 16) - return 16; - else - return BPP_INVALID; - } - } else { - if (DSCEnabled) { - if (Format == dm_420) { - if (DecimalBPP < 6) - return BPP_INVALID; - else if (DecimalBPP >= 1.5 * DSCInputBitPerComponent - 1 / 16) - return 1.5 * DSCInputBitPerComponent - 1 / 16; - else - return dml_floor(16 * DecimalBPP, 1) / 16; - } else if (Format == dm_n422) { - if (DecimalBPP < 7) - return BPP_INVALID; - else if (DecimalBPP >= 2 * DSCInputBitPerComponent - 1 / 16) - return 2 * DSCInputBitPerComponent - 1 / 16; - else - return dml_floor(16 * DecimalBPP, 1) / 16; - } else { - if (DecimalBPP < 8) - return BPP_INVALID; - else if (DecimalBPP >= 3 * DSCInputBitPerComponent - 1 / 16) - return 3 * DSCInputBitPerComponent - 1 / 16; - else - return dml_floor(16 * DecimalBPP, 1) / 16; - } - } else if (Format == dm_420) { - if (DecimalBPP >= 18) - return 18; - else if (DecimalBPP >= 15) - return 15; - else if (DecimalBPP >= 12) - return 12; - else - return BPP_INVALID; - } else if (Format == dm_s422 || Format == dm_n422) { - if (DecimalBPP >= 24) - return 24; - else if (DecimalBPP >= 20) - return 20; - else if (DecimalBPP >= 16) - return 16; - else - return BPP_INVALID; - } else { - if (DecimalBPP >= 36) - return 36; - else if (DecimalBPP >= 30) - return 30; - else if (DecimalBPP >= 24) - return 24; - else - return BPP_INVALID; - } - } -} - -static void ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib) -{ - int i; - unsigned int j, k; - /*MODE SUPPORT, VOLTAGE STATE AND SOC CONFIGURATION*/ - - /*Scale Ratio, taps Support Check*/ - - mode_lib->vba.ScaleRatioAndTapsSupport = true; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.ScalerEnabled[k] == false - && ((mode_lib->vba.SourcePixelFormat[k] != dm_444_64 - && mode_lib->vba.SourcePixelFormat[k] != dm_444_32 - && mode_lib->vba.SourcePixelFormat[k] != dm_444_16 - && mode_lib->vba.SourcePixelFormat[k] != dm_mono_16 - && mode_lib->vba.SourcePixelFormat[k] != dm_mono_8) - || mode_lib->vba.HRatio[k] != 1.0 - || mode_lib->vba.htaps[k] != 1.0 - || mode_lib->vba.VRatio[k] != 1.0 - || mode_lib->vba.vtaps[k] != 1.0)) { - mode_lib->vba.ScaleRatioAndTapsSupport = false; - } else if (mode_lib->vba.vtaps[k] < 1.0 || mode_lib->vba.vtaps[k] > 8.0 - || mode_lib->vba.htaps[k] < 1.0 || mode_lib->vba.htaps[k] > 8.0 - || (mode_lib->vba.htaps[k] > 1.0 - && (mode_lib->vba.htaps[k] % 2) == 1) - || mode_lib->vba.HRatio[k] > mode_lib->vba.MaxHSCLRatio - || mode_lib->vba.VRatio[k] > mode_lib->vba.MaxVSCLRatio - || mode_lib->vba.HRatio[k] > mode_lib->vba.htaps[k] - || mode_lib->vba.VRatio[k] > mode_lib->vba.vtaps[k] - || (mode_lib->vba.SourcePixelFormat[k] != dm_444_64 - && mode_lib->vba.SourcePixelFormat[k] != dm_444_32 - && mode_lib->vba.SourcePixelFormat[k] != dm_444_16 - && mode_lib->vba.SourcePixelFormat[k] != dm_mono_16 - && mode_lib->vba.SourcePixelFormat[k] != dm_mono_8 - && (mode_lib->vba.HRatio[k] / 2.0 - > mode_lib->vba.HTAPsChroma[k] - || mode_lib->vba.VRatio[k] / 2.0 - > mode_lib->vba.VTAPsChroma[k]))) { - mode_lib->vba.ScaleRatioAndTapsSupport = false; - } - } - /*Source Format, Pixel Format and Scan Support Check*/ - - mode_lib->vba.SourceFormatPixelAndScanSupport = true; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if ((mode_lib->vba.SurfaceTiling[k] == dm_sw_linear - && mode_lib->vba.SourceScan[k] != dm_horz) - || ((mode_lib->vba.SurfaceTiling[k] == dm_sw_4kb_d - || mode_lib->vba.SurfaceTiling[k] == dm_sw_4kb_d_x - || mode_lib->vba.SurfaceTiling[k] == dm_sw_64kb_d - || mode_lib->vba.SurfaceTiling[k] == dm_sw_64kb_d_t - || mode_lib->vba.SurfaceTiling[k] == dm_sw_64kb_d_x - || mode_lib->vba.SurfaceTiling[k] == dm_sw_var_d - || mode_lib->vba.SurfaceTiling[k] == dm_sw_var_d_x) - && mode_lib->vba.SourcePixelFormat[k] != dm_444_64) - || (mode_lib->vba.SurfaceTiling[k] == dm_sw_64kb_r_x - && (mode_lib->vba.SourcePixelFormat[k] == dm_mono_8 - || mode_lib->vba.SourcePixelFormat[k] - == dm_420_8 - || mode_lib->vba.SourcePixelFormat[k] - == dm_420_10)) - || (((mode_lib->vba.SurfaceTiling[k] - == dm_sw_gfx7_2d_thin_gl - || mode_lib->vba.SurfaceTiling[k] - == dm_sw_gfx7_2d_thin_lvp) - && !((mode_lib->vba.SourcePixelFormat[k] - == dm_444_64 - || mode_lib->vba.SourcePixelFormat[k] - == dm_444_32) - && mode_lib->vba.SourceScan[k] - == dm_horz - && mode_lib->vba.SupportGFX7CompatibleTilingIn32bppAnd64bpp - == true - && mode_lib->vba.DCCEnable[k] - == false)) - || (mode_lib->vba.DCCEnable[k] == true - && (mode_lib->vba.SurfaceTiling[k] - == dm_sw_linear - || mode_lib->vba.SourcePixelFormat[k] - == dm_420_8 - || mode_lib->vba.SourcePixelFormat[k] - == dm_420_10)))) { - mode_lib->vba.SourceFormatPixelAndScanSupport = false; - } - } - /*Bandwidth Support Check*/ - - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.SourceScan[k] == dm_horz) { - mode_lib->vba.SwathWidthYSingleDPP[k] = mode_lib->vba.ViewportWidth[k]; - } else { - mode_lib->vba.SwathWidthYSingleDPP[k] = mode_lib->vba.ViewportHeight[k]; - } - if (mode_lib->vba.SourcePixelFormat[k] == dm_444_64) { - mode_lib->vba.BytePerPixelInDETY[k] = 8.0; - mode_lib->vba.BytePerPixelInDETC[k] = 0.0; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_32) { - mode_lib->vba.BytePerPixelInDETY[k] = 4.0; - mode_lib->vba.BytePerPixelInDETC[k] = 0.0; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_16 - || mode_lib->vba.SourcePixelFormat[k] == dm_mono_16) { - mode_lib->vba.BytePerPixelInDETY[k] = 2.0; - mode_lib->vba.BytePerPixelInDETC[k] = 0.0; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_mono_8) { - mode_lib->vba.BytePerPixelInDETY[k] = 1.0; - mode_lib->vba.BytePerPixelInDETC[k] = 0.0; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_420_8) { - mode_lib->vba.BytePerPixelInDETY[k] = 1.0; - mode_lib->vba.BytePerPixelInDETC[k] = 2.0; - } else { - mode_lib->vba.BytePerPixelInDETY[k] = 4.0 / 3; - mode_lib->vba.BytePerPixelInDETC[k] = 8.0 / 3; - } - } - mode_lib->vba.TotalReadBandwidthConsumedGBytePerSecond = 0.0; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.ReadBandwidth[k] = mode_lib->vba.SwathWidthYSingleDPP[k] - * (dml_ceil(mode_lib->vba.BytePerPixelInDETY[k], 1.0) - * mode_lib->vba.VRatio[k] - + dml_ceil(mode_lib->vba.BytePerPixelInDETC[k], 2.0) - / 2.0 * mode_lib->vba.VRatio[k] / 2) - / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]); - if (mode_lib->vba.DCCEnable[k] == true) { - mode_lib->vba.ReadBandwidth[k] = mode_lib->vba.ReadBandwidth[k] - * (1 + 1 / 256); - } - if (mode_lib->vba.VirtualMemoryEnable == true - && mode_lib->vba.SourceScan[k] != dm_horz - && (mode_lib->vba.SurfaceTiling[k] == dm_sw_4kb_s - || mode_lib->vba.SurfaceTiling[k] == dm_sw_4kb_s_x - || mode_lib->vba.SurfaceTiling[k] == dm_sw_4kb_d - || mode_lib->vba.SurfaceTiling[k] == dm_sw_4kb_d_x)) { - mode_lib->vba.ReadBandwidth[k] = mode_lib->vba.ReadBandwidth[k] - * (1 + 1 / 64); - } else if (mode_lib->vba.VirtualMemoryEnable == true - && mode_lib->vba.SourceScan[k] == dm_horz - && (mode_lib->vba.SourcePixelFormat[k] == dm_444_64 - || mode_lib->vba.SourcePixelFormat[k] == dm_444_32) - && (mode_lib->vba.SurfaceTiling[k] == dm_sw_64kb_s - || mode_lib->vba.SurfaceTiling[k] == dm_sw_64kb_s_t - || mode_lib->vba.SurfaceTiling[k] == dm_sw_64kb_s_x - || mode_lib->vba.SurfaceTiling[k] == dm_sw_64kb_d - || mode_lib->vba.SurfaceTiling[k] == dm_sw_64kb_d_t - || mode_lib->vba.SurfaceTiling[k] == dm_sw_64kb_d_x - || mode_lib->vba.SurfaceTiling[k] == dm_sw_64kb_r_x)) { - mode_lib->vba.ReadBandwidth[k] = mode_lib->vba.ReadBandwidth[k] - * (1 + 1 / 256); - } else if (mode_lib->vba.VirtualMemoryEnable == true) { - mode_lib->vba.ReadBandwidth[k] = mode_lib->vba.ReadBandwidth[k] - * (1 + 1 / 512); - } - mode_lib->vba.TotalReadBandwidthConsumedGBytePerSecond = - mode_lib->vba.TotalReadBandwidthConsumedGBytePerSecond - + mode_lib->vba.ReadBandwidth[k] / 1000.0; - } - mode_lib->vba.TotalWriteBandwidthConsumedGBytePerSecond = 0.0; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.WritebackEnable[k] == true - && mode_lib->vba.WritebackPixelFormat[k] == dm_444_32) { - mode_lib->vba.WriteBandwidth[k] = mode_lib->vba.WritebackDestinationWidth[k] - * mode_lib->vba.WritebackDestinationHeight[k] - / (mode_lib->vba.WritebackSourceHeight[k] - * mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]) * 4.0; - } else if (mode_lib->vba.WritebackEnable[k] == true - && mode_lib->vba.WritebackPixelFormat[k] == dm_420_10) { - mode_lib->vba.WriteBandwidth[k] = mode_lib->vba.WritebackDestinationWidth[k] - * mode_lib->vba.WritebackDestinationHeight[k] - / (mode_lib->vba.WritebackSourceHeight[k] - * mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]) * 3.0; - } else if (mode_lib->vba.WritebackEnable[k] == true) { - mode_lib->vba.WriteBandwidth[k] = mode_lib->vba.WritebackDestinationWidth[k] - * mode_lib->vba.WritebackDestinationHeight[k] - / (mode_lib->vba.WritebackSourceHeight[k] - * mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]) * 1.5; - } else { - mode_lib->vba.WriteBandwidth[k] = 0.0; - } - mode_lib->vba.TotalWriteBandwidthConsumedGBytePerSecond = - mode_lib->vba.TotalWriteBandwidthConsumedGBytePerSecond - + mode_lib->vba.WriteBandwidth[k] / 1000.0; - } - mode_lib->vba.TotalBandwidthConsumedGBytePerSecond = - mode_lib->vba.TotalReadBandwidthConsumedGBytePerSecond - + mode_lib->vba.TotalWriteBandwidthConsumedGBytePerSecond; - mode_lib->vba.DCCEnabledInAnyPlane = false; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.DCCEnable[k] == true) { - mode_lib->vba.DCCEnabledInAnyPlane = true; - } - } - for (i = 0; i <= DC__VOLTAGE_STATES; i++) { - mode_lib->vba.FabricAndDRAMBandwidthPerState[i] = dml_min( - mode_lib->vba.DRAMSpeedPerState[i] * mode_lib->vba.NumberOfChannels - * mode_lib->vba.DRAMChannelWidth, - mode_lib->vba.FabricClockPerState[i] - * mode_lib->vba.FabricDatapathToDCNDataReturn) - / 1000; - mode_lib->vba.ReturnBWToDCNPerState = dml_min( - mode_lib->vba.ReturnBusWidth * mode_lib->vba.DCFCLKPerState[i], - mode_lib->vba.FabricAndDRAMBandwidthPerState[i] * 1000.0) - * mode_lib->vba.PercentOfIdealDRAMAndFabricBWReceivedAfterUrgLatency - / 100; - mode_lib->vba.ReturnBWPerState[i] = mode_lib->vba.ReturnBWToDCNPerState; - if (mode_lib->vba.DCCEnabledInAnyPlane == true - && mode_lib->vba.ReturnBWToDCNPerState - > mode_lib->vba.DCFCLKPerState[i] - * mode_lib->vba.ReturnBusWidth - / 4.0) { - mode_lib->vba.ReturnBWPerState[i] = - dml_min( - mode_lib->vba.ReturnBWPerState[i], - mode_lib->vba.ReturnBWToDCNPerState * 4.0 - * (1.0 - - mode_lib->vba.UrgentLatency - / ((mode_lib->vba.ROBBufferSizeInKByte - - mode_lib->vba.PixelChunkSizeInKByte) - * 1024.0 - / (mode_lib->vba.ReturnBWToDCNPerState - - mode_lib->vba.DCFCLKPerState[i] - * mode_lib->vba.ReturnBusWidth - / 4.0) - + mode_lib->vba.UrgentLatency))); - } - mode_lib->vba.CriticalPoint = - 2.0 * mode_lib->vba.ReturnBusWidth * mode_lib->vba.DCFCLKPerState[i] - * mode_lib->vba.UrgentLatency - / (mode_lib->vba.ReturnBWToDCNPerState - * mode_lib->vba.UrgentLatency - + (mode_lib->vba.ROBBufferSizeInKByte - - mode_lib->vba.PixelChunkSizeInKByte) - * 1024.0); - if (mode_lib->vba.DCCEnabledInAnyPlane == true && mode_lib->vba.CriticalPoint > 1.0 - && mode_lib->vba.CriticalPoint < 4.0) { - mode_lib->vba.ReturnBWPerState[i] = - dml_min( - mode_lib->vba.ReturnBWPerState[i], - dml_pow( - 4.0 - * mode_lib->vba.ReturnBWToDCNPerState - * (mode_lib->vba.ROBBufferSizeInKByte - - mode_lib->vba.PixelChunkSizeInKByte) - * 1024.0 - * mode_lib->vba.ReturnBusWidth - * mode_lib->vba.DCFCLKPerState[i] - * mode_lib->vba.UrgentLatency - / (mode_lib->vba.ReturnBWToDCNPerState - * mode_lib->vba.UrgentLatency - + (mode_lib->vba.ROBBufferSizeInKByte - - mode_lib->vba.PixelChunkSizeInKByte) - * 1024.0), - 2)); - } - mode_lib->vba.ReturnBWToDCNPerState = dml_min( - mode_lib->vba.ReturnBusWidth * mode_lib->vba.DCFCLKPerState[i], - mode_lib->vba.FabricAndDRAMBandwidthPerState[i] * 1000.0); - if (mode_lib->vba.DCCEnabledInAnyPlane == true - && mode_lib->vba.ReturnBWToDCNPerState - > mode_lib->vba.DCFCLKPerState[i] - * mode_lib->vba.ReturnBusWidth - / 4.0) { - mode_lib->vba.ReturnBWPerState[i] = - dml_min( - mode_lib->vba.ReturnBWPerState[i], - mode_lib->vba.ReturnBWToDCNPerState * 4.0 - * (1.0 - - mode_lib->vba.UrgentLatency - / ((mode_lib->vba.ROBBufferSizeInKByte - - mode_lib->vba.PixelChunkSizeInKByte) - * 1024.0 - / (mode_lib->vba.ReturnBWToDCNPerState - - mode_lib->vba.DCFCLKPerState[i] - * mode_lib->vba.ReturnBusWidth - / 4.0) - + mode_lib->vba.UrgentLatency))); - } - mode_lib->vba.CriticalPoint = - 2.0 * mode_lib->vba.ReturnBusWidth * mode_lib->vba.DCFCLKPerState[i] - * mode_lib->vba.UrgentLatency - / (mode_lib->vba.ReturnBWToDCNPerState - * mode_lib->vba.UrgentLatency - + (mode_lib->vba.ROBBufferSizeInKByte - - mode_lib->vba.PixelChunkSizeInKByte) - * 1024.0); - if (mode_lib->vba.DCCEnabledInAnyPlane == true && mode_lib->vba.CriticalPoint > 1.0 - && mode_lib->vba.CriticalPoint < 4.0) { - mode_lib->vba.ReturnBWPerState[i] = - dml_min( - mode_lib->vba.ReturnBWPerState[i], - dml_pow( - 4.0 - * mode_lib->vba.ReturnBWToDCNPerState - * (mode_lib->vba.ROBBufferSizeInKByte - - mode_lib->vba.PixelChunkSizeInKByte) - * 1024.0 - * mode_lib->vba.ReturnBusWidth - * mode_lib->vba.DCFCLKPerState[i] - * mode_lib->vba.UrgentLatency - / (mode_lib->vba.ReturnBWToDCNPerState - * mode_lib->vba.UrgentLatency - + (mode_lib->vba.ROBBufferSizeInKByte - - mode_lib->vba.PixelChunkSizeInKByte) - * 1024.0), - 2)); - } - } - for (i = 0; i <= DC__VOLTAGE_STATES; i++) { - if ((mode_lib->vba.TotalReadBandwidthConsumedGBytePerSecond * 1000.0 - <= mode_lib->vba.ReturnBWPerState[i]) - && (mode_lib->vba.TotalBandwidthConsumedGBytePerSecond * 1000.0 - <= mode_lib->vba.FabricAndDRAMBandwidthPerState[i] - * 1000.0 - * mode_lib->vba.PercentOfIdealDRAMAndFabricBWReceivedAfterUrgLatency - / 100.0)) { - mode_lib->vba.BandwidthSupport[i] = true; - } else { - mode_lib->vba.BandwidthSupport[i] = false; - } - } - /*Writeback Latency support check*/ - - mode_lib->vba.WritebackLatencySupport = true; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.WritebackEnable[k] == true) { - if (mode_lib->vba.WritebackPixelFormat[k] == dm_444_32) { - if (mode_lib->vba.WriteBandwidth[k] - > (mode_lib->vba.WritebackInterfaceLumaBufferSize - + mode_lib->vba.WritebackInterfaceChromaBufferSize) - / mode_lib->vba.WritebackLatency) { - mode_lib->vba.WritebackLatencySupport = false; - } - } else { - if (mode_lib->vba.WriteBandwidth[k] - > 1.5 - * dml_min( - mode_lib->vba.WritebackInterfaceLumaBufferSize, - 2.0 - * mode_lib->vba.WritebackInterfaceChromaBufferSize) - / mode_lib->vba.WritebackLatency) { - mode_lib->vba.WritebackLatencySupport = false; - } - } - } - } - /*Re-ordering Buffer Support Check*/ - - for (i = 0; i <= DC__VOLTAGE_STATES; i++) { - mode_lib->vba.UrgentRoundTripAndOutOfOrderLatencyPerState[i] = - (mode_lib->vba.RoundTripPingLatencyCycles + 32.0) - / mode_lib->vba.DCFCLKPerState[i] - + mode_lib->vba.UrgentOutOfOrderReturnPerChannel - * mode_lib->vba.NumberOfChannels - / mode_lib->vba.ReturnBWPerState[i]; - if ((mode_lib->vba.ROBBufferSizeInKByte - mode_lib->vba.PixelChunkSizeInKByte) - * 1024.0 / mode_lib->vba.ReturnBWPerState[i] - > mode_lib->vba.UrgentRoundTripAndOutOfOrderLatencyPerState[i]) { - mode_lib->vba.ROBSupport[i] = true; - } else { - mode_lib->vba.ROBSupport[i] = false; - } - } - /*Writeback Mode Support Check*/ - - mode_lib->vba.TotalNumberOfActiveWriteback = 0; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.WritebackEnable[k] == true) { - mode_lib->vba.TotalNumberOfActiveWriteback = - mode_lib->vba.TotalNumberOfActiveWriteback + 1; - } - } - mode_lib->vba.WritebackModeSupport = true; - if (mode_lib->vba.TotalNumberOfActiveWriteback > mode_lib->vba.MaxNumWriteback) { - mode_lib->vba.WritebackModeSupport = false; - } - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.WritebackEnable[k] == true - && mode_lib->vba.Writeback10bpc420Supported != true - && mode_lib->vba.WritebackPixelFormat[k] == dm_420_10) { - mode_lib->vba.WritebackModeSupport = false; - } - } - /*Writeback Scale Ratio and Taps Support Check*/ - - mode_lib->vba.WritebackScaleRatioAndTapsSupport = true; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.WritebackEnable[k] == true) { - if (mode_lib->vba.WritebackLumaAndChromaScalingSupported == false - && (mode_lib->vba.WritebackHRatio[k] != 1.0 - || mode_lib->vba.WritebackVRatio[k] != 1.0)) { - mode_lib->vba.WritebackScaleRatioAndTapsSupport = false; - } - if (mode_lib->vba.WritebackHRatio[k] > mode_lib->vba.WritebackMaxHSCLRatio - || mode_lib->vba.WritebackVRatio[k] - > mode_lib->vba.WritebackMaxVSCLRatio - || mode_lib->vba.WritebackHRatio[k] - < mode_lib->vba.WritebackMinHSCLRatio - || mode_lib->vba.WritebackVRatio[k] - < mode_lib->vba.WritebackMinVSCLRatio - || mode_lib->vba.WritebackLumaHTaps[k] - > mode_lib->vba.WritebackMaxHSCLTaps - || mode_lib->vba.WritebackLumaVTaps[k] - > mode_lib->vba.WritebackMaxVSCLTaps - || mode_lib->vba.WritebackHRatio[k] - > mode_lib->vba.WritebackLumaHTaps[k] - || mode_lib->vba.WritebackVRatio[k] - > mode_lib->vba.WritebackLumaVTaps[k] - || (mode_lib->vba.WritebackLumaHTaps[k] > 2.0 - && ((mode_lib->vba.WritebackLumaHTaps[k] % 2) - == 1)) - || (mode_lib->vba.WritebackPixelFormat[k] != dm_444_32 - && (mode_lib->vba.WritebackChromaHTaps[k] - > mode_lib->vba.WritebackMaxHSCLTaps - || mode_lib->vba.WritebackChromaVTaps[k] - > mode_lib->vba.WritebackMaxVSCLTaps - || 2.0 - * mode_lib->vba.WritebackHRatio[k] - > mode_lib->vba.WritebackChromaHTaps[k] - || 2.0 - * mode_lib->vba.WritebackVRatio[k] - > mode_lib->vba.WritebackChromaVTaps[k] - || (mode_lib->vba.WritebackChromaHTaps[k] > 2.0 - && ((mode_lib->vba.WritebackChromaHTaps[k] % 2) == 1))))) { - mode_lib->vba.WritebackScaleRatioAndTapsSupport = false; - } - if (mode_lib->vba.WritebackVRatio[k] < 1.0) { - mode_lib->vba.WritebackLumaVExtra = - dml_max(1.0 - 2.0 / dml_ceil(1.0 / mode_lib->vba.WritebackVRatio[k], 1.0), 0.0); - } else { - mode_lib->vba.WritebackLumaVExtra = -1; - } - if ((mode_lib->vba.WritebackPixelFormat[k] == dm_444_32 - && mode_lib->vba.WritebackLumaVTaps[k] - > (mode_lib->vba.WritebackLineBufferLumaBufferSize - + mode_lib->vba.WritebackLineBufferChromaBufferSize) - / 3.0 - / mode_lib->vba.WritebackDestinationWidth[k] - - mode_lib->vba.WritebackLumaVExtra) - || (mode_lib->vba.WritebackPixelFormat[k] == dm_420_8 - && mode_lib->vba.WritebackLumaVTaps[k] - > mode_lib->vba.WritebackLineBufferLumaBufferSize - / mode_lib->vba.WritebackDestinationWidth[k] - - mode_lib->vba.WritebackLumaVExtra) - || (mode_lib->vba.WritebackPixelFormat[k] == dm_420_10 - && mode_lib->vba.WritebackLumaVTaps[k] - > mode_lib->vba.WritebackLineBufferLumaBufferSize - * 8.0 / 10.0 - / mode_lib->vba.WritebackDestinationWidth[k] - - mode_lib->vba.WritebackLumaVExtra)) { - mode_lib->vba.WritebackScaleRatioAndTapsSupport = false; - } - if (2.0 * mode_lib->vba.WritebackVRatio[k] < 1) { - mode_lib->vba.WritebackChromaVExtra = 0.0; - } else { - mode_lib->vba.WritebackChromaVExtra = -1; - } - if ((mode_lib->vba.WritebackPixelFormat[k] == dm_420_8 - && mode_lib->vba.WritebackChromaVTaps[k] - > mode_lib->vba.WritebackLineBufferChromaBufferSize - / mode_lib->vba.WritebackDestinationWidth[k] - - mode_lib->vba.WritebackChromaVExtra) - || (mode_lib->vba.WritebackPixelFormat[k] == dm_420_10 - && mode_lib->vba.WritebackChromaVTaps[k] - > mode_lib->vba.WritebackLineBufferChromaBufferSize - * 8.0 / 10.0 - / mode_lib->vba.WritebackDestinationWidth[k] - - mode_lib->vba.WritebackChromaVExtra)) { - mode_lib->vba.WritebackScaleRatioAndTapsSupport = false; - } - } - } - /*Maximum DISPCLK/DPPCLK Support check*/ - - mode_lib->vba.WritebackRequiredDISPCLK = 0.0; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.WritebackEnable[k] == true) { - mode_lib->vba.WritebackRequiredDISPCLK = - dml_max( - mode_lib->vba.WritebackRequiredDISPCLK, - CalculateWriteBackDISPCLK( - mode_lib->vba.WritebackPixelFormat[k], - mode_lib->vba.PixelClock[k], - mode_lib->vba.WritebackHRatio[k], - mode_lib->vba.WritebackVRatio[k], - mode_lib->vba.WritebackLumaHTaps[k], - mode_lib->vba.WritebackLumaVTaps[k], - mode_lib->vba.WritebackChromaHTaps[k], - mode_lib->vba.WritebackChromaVTaps[k], - mode_lib->vba.WritebackDestinationWidth[k], - mode_lib->vba.HTotal[k], - mode_lib->vba.WritebackChromaLineBufferWidth)); - } - } - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.HRatio[k] > 1.0) { - mode_lib->vba.PSCL_FACTOR[k] = dml_min( - mode_lib->vba.MaxDCHUBToPSCLThroughput, - mode_lib->vba.MaxPSCLToLBThroughput - * mode_lib->vba.HRatio[k] - / dml_ceil( - mode_lib->vba.htaps[k] - / 6.0, - 1.0)); - } else { - mode_lib->vba.PSCL_FACTOR[k] = dml_min( - mode_lib->vba.MaxDCHUBToPSCLThroughput, - mode_lib->vba.MaxPSCLToLBThroughput); - } - if (mode_lib->vba.BytePerPixelInDETC[k] == 0.0) { - mode_lib->vba.PSCL_FACTOR_CHROMA[k] = 0.0; - mode_lib->vba.MinDPPCLKUsingSingleDPP[k] = - mode_lib->vba.PixelClock[k] - * dml_max3( - mode_lib->vba.vtaps[k] / 6.0 - * dml_min( - 1.0, - mode_lib->vba.HRatio[k]), - mode_lib->vba.HRatio[k] - * mode_lib->vba.VRatio[k] - / mode_lib->vba.PSCL_FACTOR[k], - 1.0); - if ((mode_lib->vba.htaps[k] > 6.0 || mode_lib->vba.vtaps[k] > 6.0) - && mode_lib->vba.MinDPPCLKUsingSingleDPP[k] - < 2.0 * mode_lib->vba.PixelClock[k]) { - mode_lib->vba.MinDPPCLKUsingSingleDPP[k] = 2.0 - * mode_lib->vba.PixelClock[k]; - } - } else { - if (mode_lib->vba.HRatio[k] / 2.0 > 1.0) { - mode_lib->vba.PSCL_FACTOR_CHROMA[k] = - dml_min( - mode_lib->vba.MaxDCHUBToPSCLThroughput, - mode_lib->vba.MaxPSCLToLBThroughput - * mode_lib->vba.HRatio[k] - / 2.0 - / dml_ceil( - mode_lib->vba.HTAPsChroma[k] - / 6.0, - 1.0)); - } else { - mode_lib->vba.PSCL_FACTOR_CHROMA[k] = dml_min( - mode_lib->vba.MaxDCHUBToPSCLThroughput, - mode_lib->vba.MaxPSCLToLBThroughput); - } - mode_lib->vba.MinDPPCLKUsingSingleDPP[k] = - mode_lib->vba.PixelClock[k] - * dml_max5( - mode_lib->vba.vtaps[k] / 6.0 - * dml_min( - 1.0, - mode_lib->vba.HRatio[k]), - mode_lib->vba.HRatio[k] - * mode_lib->vba.VRatio[k] - / mode_lib->vba.PSCL_FACTOR[k], - mode_lib->vba.VTAPsChroma[k] - / 6.0 - * dml_min( - 1.0, - mode_lib->vba.HRatio[k] - / 2.0), - mode_lib->vba.HRatio[k] - * mode_lib->vba.VRatio[k] - / 4.0 - / mode_lib->vba.PSCL_FACTOR_CHROMA[k], - 1.0); - if ((mode_lib->vba.htaps[k] > 6.0 || mode_lib->vba.vtaps[k] > 6.0 - || mode_lib->vba.HTAPsChroma[k] > 6.0 - || mode_lib->vba.VTAPsChroma[k] > 6.0) - && mode_lib->vba.MinDPPCLKUsingSingleDPP[k] - < 2.0 * mode_lib->vba.PixelClock[k]) { - mode_lib->vba.MinDPPCLKUsingSingleDPP[k] = 2.0 - * mode_lib->vba.PixelClock[k]; - } - } - } - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - Calculate256BBlockSizes( - mode_lib->vba.SourcePixelFormat[k], - mode_lib->vba.SurfaceTiling[k], - dml_ceil(mode_lib->vba.BytePerPixelInDETY[k], 1.0), - dml_ceil(mode_lib->vba.BytePerPixelInDETC[k], 2.0), - &mode_lib->vba.Read256BlockHeightY[k], - &mode_lib->vba.Read256BlockHeightC[k], - &mode_lib->vba.Read256BlockWidthY[k], - &mode_lib->vba.Read256BlockWidthC[k]); - if (mode_lib->vba.SourceScan[k] == dm_horz) { - mode_lib->vba.MaxSwathHeightY[k] = mode_lib->vba.Read256BlockHeightY[k]; - mode_lib->vba.MaxSwathHeightC[k] = mode_lib->vba.Read256BlockHeightC[k]; - } else { - mode_lib->vba.MaxSwathHeightY[k] = mode_lib->vba.Read256BlockWidthY[k]; - mode_lib->vba.MaxSwathHeightC[k] = mode_lib->vba.Read256BlockWidthC[k]; - } - if ((mode_lib->vba.SourcePixelFormat[k] == dm_444_64 - || mode_lib->vba.SourcePixelFormat[k] == dm_444_32 - || mode_lib->vba.SourcePixelFormat[k] == dm_444_16 - || mode_lib->vba.SourcePixelFormat[k] == dm_mono_16 - || mode_lib->vba.SourcePixelFormat[k] == dm_mono_8)) { - if (mode_lib->vba.SurfaceTiling[k] == dm_sw_linear - || (mode_lib->vba.SourcePixelFormat[k] == dm_444_64 - && (mode_lib->vba.SurfaceTiling[k] - == dm_sw_4kb_s - || mode_lib->vba.SurfaceTiling[k] - == dm_sw_4kb_s_x - || mode_lib->vba.SurfaceTiling[k] - == dm_sw_64kb_s - || mode_lib->vba.SurfaceTiling[k] - == dm_sw_64kb_s_t - || mode_lib->vba.SurfaceTiling[k] - == dm_sw_64kb_s_x - || mode_lib->vba.SurfaceTiling[k] - == dm_sw_var_s - || mode_lib->vba.SurfaceTiling[k] - == dm_sw_var_s_x) - && mode_lib->vba.SourceScan[k] == dm_horz)) { - mode_lib->vba.MinSwathHeightY[k] = mode_lib->vba.MaxSwathHeightY[k]; - } else { - mode_lib->vba.MinSwathHeightY[k] = mode_lib->vba.MaxSwathHeightY[k] - / 2.0; - } - mode_lib->vba.MinSwathHeightC[k] = mode_lib->vba.MaxSwathHeightC[k]; - } else { - if (mode_lib->vba.SurfaceTiling[k] == dm_sw_linear) { - mode_lib->vba.MinSwathHeightY[k] = mode_lib->vba.MaxSwathHeightY[k]; - mode_lib->vba.MinSwathHeightC[k] = mode_lib->vba.MaxSwathHeightC[k]; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_420_8 - && mode_lib->vba.SourceScan[k] == dm_horz) { - mode_lib->vba.MinSwathHeightY[k] = mode_lib->vba.MaxSwathHeightY[k] - / 2.0; - mode_lib->vba.MinSwathHeightC[k] = mode_lib->vba.MaxSwathHeightC[k]; - } else if (mode_lib->vba.SourcePixelFormat[k] == dm_420_10 - && mode_lib->vba.SourceScan[k] == dm_horz) { - mode_lib->vba.MinSwathHeightC[k] = mode_lib->vba.MaxSwathHeightC[k] - / 2.0; - mode_lib->vba.MinSwathHeightY[k] = mode_lib->vba.MaxSwathHeightY[k]; - } else { - mode_lib->vba.MinSwathHeightY[k] = mode_lib->vba.MaxSwathHeightY[k]; - mode_lib->vba.MinSwathHeightC[k] = mode_lib->vba.MaxSwathHeightC[k]; - } - } - if (mode_lib->vba.SurfaceTiling[k] == dm_sw_linear) { - mode_lib->vba.MaximumSwathWidthSupport = 8192.0; - } else { - mode_lib->vba.MaximumSwathWidthSupport = 5120.0; - } - mode_lib->vba.MaximumSwathWidthInDETBuffer = - dml_min( - mode_lib->vba.MaximumSwathWidthSupport, - mode_lib->vba.DETBufferSizeInKByte * 1024.0 / 2.0 - / (mode_lib->vba.BytePerPixelInDETY[k] - * mode_lib->vba.MinSwathHeightY[k] - + mode_lib->vba.BytePerPixelInDETC[k] - / 2.0 - * mode_lib->vba.MinSwathHeightC[k])); - if (mode_lib->vba.BytePerPixelInDETC[k] == 0.0) { - mode_lib->vba.MaximumSwathWidthInLineBuffer = - mode_lib->vba.LineBufferSize - * dml_max(mode_lib->vba.HRatio[k], 1.0) - / mode_lib->vba.LBBitPerPixel[k] - / (mode_lib->vba.vtaps[k] - + dml_max( - dml_ceil( - mode_lib->vba.VRatio[k], - 1.0) - - 2, - 0.0)); - } else { - mode_lib->vba.MaximumSwathWidthInLineBuffer = - dml_min( - mode_lib->vba.LineBufferSize - * dml_max( - mode_lib->vba.HRatio[k], - 1.0) - / mode_lib->vba.LBBitPerPixel[k] - / (mode_lib->vba.vtaps[k] - + dml_max( - dml_ceil( - mode_lib->vba.VRatio[k], - 1.0) - - 2, - 0.0)), - 2.0 * mode_lib->vba.LineBufferSize - * dml_max( - mode_lib->vba.HRatio[k] - / 2.0, - 1.0) - / mode_lib->vba.LBBitPerPixel[k] - / (mode_lib->vba.VTAPsChroma[k] - + dml_max( - dml_ceil( - mode_lib->vba.VRatio[k] - / 2.0, - 1.0) - - 2, - 0.0))); - } - mode_lib->vba.MaximumSwathWidth[k] = dml_min( - mode_lib->vba.MaximumSwathWidthInDETBuffer, - mode_lib->vba.MaximumSwathWidthInLineBuffer); - } - for (i = 0; i <= DC__VOLTAGE_STATES; i++) { - mode_lib->vba.MaxDispclkRoundedDownToDFSGranularity = RoundToDFSGranularityDown( - mode_lib->vba.MaxDispclk[i], - mode_lib->vba.DISPCLKDPPCLKVCOSpeed); - mode_lib->vba.MaxDppclkRoundedDownToDFSGranularity = RoundToDFSGranularityDown( - mode_lib->vba.MaxDppclk[i], - mode_lib->vba.DISPCLKDPPCLKVCOSpeed); - mode_lib->vba.RequiredDISPCLK[i] = 0.0; - mode_lib->vba.DISPCLK_DPPCLK_Support[i] = true; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.PlaneRequiredDISPCLKWithoutODMCombine = - mode_lib->vba.PixelClock[k] - * (1.0 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100.0) - * (1.0 - + mode_lib->vba.DISPCLKRampingMargin - / 100.0); - if (mode_lib->vba.ODMCapability == true - && mode_lib->vba.PlaneRequiredDISPCLKWithoutODMCombine - > mode_lib->vba.MaxDispclkRoundedDownToDFSGranularity) { - mode_lib->vba.ODMCombineEnablePerState[i][k] = true; - mode_lib->vba.PlaneRequiredDISPCLK = - mode_lib->vba.PlaneRequiredDISPCLKWithoutODMCombine - / 2.0; - } else { - mode_lib->vba.ODMCombineEnablePerState[i][k] = false; - mode_lib->vba.PlaneRequiredDISPCLK = - mode_lib->vba.PlaneRequiredDISPCLKWithoutODMCombine; - } - if (mode_lib->vba.MinDPPCLKUsingSingleDPP[k] - * (1.0 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100.0) - <= mode_lib->vba.MaxDppclkRoundedDownToDFSGranularity - && mode_lib->vba.SwathWidthYSingleDPP[k] - <= mode_lib->vba.MaximumSwathWidth[k] - && mode_lib->vba.ODMCombineEnablePerState[i][k] == false) { - mode_lib->vba.NoOfDPP[i][k] = 1; - mode_lib->vba.RequiredDPPCLK[i][k] = - mode_lib->vba.MinDPPCLKUsingSingleDPP[k] - * (1.0 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100.0); - } else { - mode_lib->vba.NoOfDPP[i][k] = 2; - mode_lib->vba.RequiredDPPCLK[i][k] = - mode_lib->vba.MinDPPCLKUsingSingleDPP[k] - * (1.0 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100.0) - / 2.0; - } - mode_lib->vba.RequiredDISPCLK[i] = dml_max( - mode_lib->vba.RequiredDISPCLK[i], - mode_lib->vba.PlaneRequiredDISPCLK); - if ((mode_lib->vba.MinDPPCLKUsingSingleDPP[k] / mode_lib->vba.NoOfDPP[i][k] - * (1.0 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100.0) - > mode_lib->vba.MaxDppclkRoundedDownToDFSGranularity) - || (mode_lib->vba.PlaneRequiredDISPCLK - > mode_lib->vba.MaxDispclkRoundedDownToDFSGranularity)) { - mode_lib->vba.DISPCLK_DPPCLK_Support[i] = false; - } - } - mode_lib->vba.TotalNumberOfActiveDPP[i] = 0.0; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.TotalNumberOfActiveDPP[i] = - mode_lib->vba.TotalNumberOfActiveDPP[i] - + mode_lib->vba.NoOfDPP[i][k]; - } - if ((mode_lib->vba.MaxDispclk[i] == mode_lib->vba.MaxDispclk[DC__VOLTAGE_STATES] - && mode_lib->vba.MaxDppclk[i] - == mode_lib->vba.MaxDppclk[DC__VOLTAGE_STATES]) - && (mode_lib->vba.TotalNumberOfActiveDPP[i] - > mode_lib->vba.MaxNumDPP - || mode_lib->vba.DISPCLK_DPPCLK_Support[i] == false)) { - mode_lib->vba.RequiredDISPCLK[i] = 0.0; - mode_lib->vba.DISPCLK_DPPCLK_Support[i] = true; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.PlaneRequiredDISPCLKWithoutODMCombine = - mode_lib->vba.PixelClock[k] - * (1.0 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100.0); - if (mode_lib->vba.ODMCapability == true - && mode_lib->vba.PlaneRequiredDISPCLKWithoutODMCombine - > mode_lib->vba.MaxDispclkRoundedDownToDFSGranularity) { - mode_lib->vba.ODMCombineEnablePerState[i][k] = true; - mode_lib->vba.PlaneRequiredDISPCLK = - mode_lib->vba.PlaneRequiredDISPCLKWithoutODMCombine - / 2.0; - } else { - mode_lib->vba.ODMCombineEnablePerState[i][k] = false; - mode_lib->vba.PlaneRequiredDISPCLK = - mode_lib->vba.PlaneRequiredDISPCLKWithoutODMCombine; - } - if (mode_lib->vba.MinDPPCLKUsingSingleDPP[k] - * (1.0 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100.0) - <= mode_lib->vba.MaxDppclkRoundedDownToDFSGranularity - && mode_lib->vba.SwathWidthYSingleDPP[k] - <= mode_lib->vba.MaximumSwathWidth[k] - && mode_lib->vba.ODMCombineEnablePerState[i][k] - == false) { - mode_lib->vba.NoOfDPP[i][k] = 1; - mode_lib->vba.RequiredDPPCLK[i][k] = - mode_lib->vba.MinDPPCLKUsingSingleDPP[k] - * (1.0 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100.0); - } else { - mode_lib->vba.NoOfDPP[i][k] = 2; - mode_lib->vba.RequiredDPPCLK[i][k] = - mode_lib->vba.MinDPPCLKUsingSingleDPP[k] - * (1.0 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100.0) - / 2.0; - } - mode_lib->vba.RequiredDISPCLK[i] = dml_max( - mode_lib->vba.RequiredDISPCLK[i], - mode_lib->vba.PlaneRequiredDISPCLK); - if ((mode_lib->vba.MinDPPCLKUsingSingleDPP[k] - / mode_lib->vba.NoOfDPP[i][k] - * (1.0 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100.0) - > mode_lib->vba.MaxDppclkRoundedDownToDFSGranularity) - || (mode_lib->vba.PlaneRequiredDISPCLK - > mode_lib->vba.MaxDispclkRoundedDownToDFSGranularity)) { - mode_lib->vba.DISPCLK_DPPCLK_Support[i] = false; - } - } - mode_lib->vba.TotalNumberOfActiveDPP[i] = 0.0; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.TotalNumberOfActiveDPP[i] = - mode_lib->vba.TotalNumberOfActiveDPP[i] - + mode_lib->vba.NoOfDPP[i][k]; - } - } - if (mode_lib->vba.TotalNumberOfActiveDPP[i] > mode_lib->vba.MaxNumDPP) { - mode_lib->vba.RequiredDISPCLK[i] = 0.0; - mode_lib->vba.DISPCLK_DPPCLK_Support[i] = true; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.ODMCombineEnablePerState[i][k] = false; - if (mode_lib->vba.SwathWidthYSingleDPP[k] - <= mode_lib->vba.MaximumSwathWidth[k]) { - mode_lib->vba.NoOfDPP[i][k] = 1; - mode_lib->vba.RequiredDPPCLK[i][k] = - mode_lib->vba.MinDPPCLKUsingSingleDPP[k] - * (1.0 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100.0); - } else { - mode_lib->vba.NoOfDPP[i][k] = 2; - mode_lib->vba.RequiredDPPCLK[i][k] = - mode_lib->vba.MinDPPCLKUsingSingleDPP[k] - * (1.0 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100.0) - / 2.0; - } - if (!(mode_lib->vba.MaxDispclk[i] - == mode_lib->vba.MaxDispclk[DC__VOLTAGE_STATES] - && mode_lib->vba.MaxDppclk[i] - == mode_lib->vba.MaxDppclk[DC__VOLTAGE_STATES])) { - mode_lib->vba.PlaneRequiredDISPCLK = - mode_lib->vba.PixelClock[k] - * (1.0 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100.0) - * (1.0 - + mode_lib->vba.DISPCLKRampingMargin - / 100.0); - } else { - mode_lib->vba.PlaneRequiredDISPCLK = - mode_lib->vba.PixelClock[k] - * (1.0 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100.0); - } - mode_lib->vba.RequiredDISPCLK[i] = dml_max( - mode_lib->vba.RequiredDISPCLK[i], - mode_lib->vba.PlaneRequiredDISPCLK); - if ((mode_lib->vba.MinDPPCLKUsingSingleDPP[k] - / mode_lib->vba.NoOfDPP[i][k] - * (1.0 - + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100.0) - > mode_lib->vba.MaxDppclkRoundedDownToDFSGranularity) - || (mode_lib->vba.PlaneRequiredDISPCLK - > mode_lib->vba.MaxDispclkRoundedDownToDFSGranularity)) { - mode_lib->vba.DISPCLK_DPPCLK_Support[i] = false; - } - } - mode_lib->vba.TotalNumberOfActiveDPP[i] = 0.0; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.TotalNumberOfActiveDPP[i] = - mode_lib->vba.TotalNumberOfActiveDPP[i] - + mode_lib->vba.NoOfDPP[i][k]; - } - } - mode_lib->vba.RequiredDISPCLK[i] = dml_max( - mode_lib->vba.RequiredDISPCLK[i], - mode_lib->vba.WritebackRequiredDISPCLK); - if (mode_lib->vba.MaxDispclkRoundedDownToDFSGranularity - < mode_lib->vba.WritebackRequiredDISPCLK) { - mode_lib->vba.DISPCLK_DPPCLK_Support[i] = false; - } - } - /*Viewport Size Check*/ - - for (i = 0; i <= DC__VOLTAGE_STATES; i++) { - mode_lib->vba.ViewportSizeSupport[i] = true; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.ODMCombineEnablePerState[i][k] == true) { - if (dml_min(mode_lib->vba.SwathWidthYSingleDPP[k], dml_round(mode_lib->vba.HActive[k] / 2.0 * mode_lib->vba.HRatio[k])) - > mode_lib->vba.MaximumSwathWidth[k]) { - mode_lib->vba.ViewportSizeSupport[i] = false; - } - } else { - if (mode_lib->vba.SwathWidthYSingleDPP[k] / 2.0 - > mode_lib->vba.MaximumSwathWidth[k]) { - mode_lib->vba.ViewportSizeSupport[i] = false; - } - } - } - } - /*Total Available Pipes Support Check*/ - - for (i = 0; i <= DC__VOLTAGE_STATES; i++) { - if (mode_lib->vba.TotalNumberOfActiveDPP[i] <= mode_lib->vba.MaxNumDPP) { - mode_lib->vba.TotalAvailablePipesSupport[i] = true; - } else { - mode_lib->vba.TotalAvailablePipesSupport[i] = false; - } - } - /*Total Available OTG Support Check*/ - - mode_lib->vba.TotalNumberOfActiveOTG = 0.0; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.BlendingAndTiming[k] == k) { - mode_lib->vba.TotalNumberOfActiveOTG = mode_lib->vba.TotalNumberOfActiveOTG - + 1.0; - } - } - if (mode_lib->vba.TotalNumberOfActiveOTG <= mode_lib->vba.MaxNumOTG) { - mode_lib->vba.NumberOfOTGSupport = true; - } else { - mode_lib->vba.NumberOfOTGSupport = false; - } - /*Display IO and DSC Support Check*/ - - mode_lib->vba.NonsupportedDSCInputBPC = false; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (!(mode_lib->vba.DSCInputBitPerComponent[k] == 12.0 - || mode_lib->vba.DSCInputBitPerComponent[k] == 10.0 - || mode_lib->vba.DSCInputBitPerComponent[k] == 8.0)) { - mode_lib->vba.NonsupportedDSCInputBPC = true; - } - } - for (i = 0; i <= DC__VOLTAGE_STATES; i++) { - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.RequiresDSC[i][k] = 0; - mode_lib->vba.RequiresFEC[i][k] = 0; - if (mode_lib->vba.BlendingAndTiming[k] == k) { - if (mode_lib->vba.Output[k] == dm_hdmi) { - mode_lib->vba.RequiresDSC[i][k] = 0; - mode_lib->vba.RequiresFEC[i][k] = 0; - mode_lib->vba.OutputBppPerState[i][k] = - TruncToValidBPP(dml_min(600.0, mode_lib->vba.PHYCLKPerState[i]) - / mode_lib->vba.PixelClockBackEnd[k] * 24, - false, - mode_lib->vba.Output[k], - mode_lib->vba.OutputFormat[k], - mode_lib->vba.DSCInputBitPerComponent[k]); - } else if (mode_lib->vba.Output[k] == dm_dp - || mode_lib->vba.Output[k] == dm_edp) { - if (mode_lib->vba.Output[k] == dm_edp) { - mode_lib->vba.EffectiveFECOverhead = 0.0; - } else { - mode_lib->vba.EffectiveFECOverhead = - mode_lib->vba.FECOverhead; - } - if (mode_lib->vba.PHYCLKPerState[i] >= 270.0) { - mode_lib->vba.Outbpp = - TruncToValidBPP((1.0 - mode_lib->vba.Downspreading / 100.0) * 270.0 - * mode_lib->vba.OutputLinkDPLanes[k] / mode_lib->vba.PixelClockBackEnd[k] * 8.0, - false, - mode_lib->vba.Output[k], - mode_lib->vba.OutputFormat[k], - mode_lib->vba.DSCInputBitPerComponent[k]); - mode_lib->vba.OutbppDSC = - TruncToValidBPP((1.0 - mode_lib->vba.Downspreading / 100.0) - * (1.0 - mode_lib->vba.EffectiveFECOverhead / 100.0) * 270.0 - * mode_lib->vba.OutputLinkDPLanes[k] / mode_lib->vba.PixelClockBackEnd[k] * 8.0, - true, - mode_lib->vba.Output[k], - mode_lib->vba.OutputFormat[k], - mode_lib->vba.DSCInputBitPerComponent[k]); - if (mode_lib->vba.DSCEnabled[k] == true) { - mode_lib->vba.RequiresDSC[i][k] = true; - if (mode_lib->vba.Output[k] == dm_dp) { - mode_lib->vba.RequiresFEC[i][k] = - true; - } else { - mode_lib->vba.RequiresFEC[i][k] = - false; - } - mode_lib->vba.Outbpp = - mode_lib->vba.OutbppDSC; - } else { - mode_lib->vba.RequiresDSC[i][k] = false; - mode_lib->vba.RequiresFEC[i][k] = false; - } - mode_lib->vba.OutputBppPerState[i][k] = - mode_lib->vba.Outbpp; - } - if (mode_lib->vba.Outbpp == BPP_INVALID) { - mode_lib->vba.Outbpp = - TruncToValidBPP((1.0 - mode_lib->vba.Downspreading / 100.0) * 540.0 - * mode_lib->vba.OutputLinkDPLanes[k] / mode_lib->vba.PixelClockBackEnd[k] * 8.0, - false, - mode_lib->vba.Output[k], - mode_lib->vba.OutputFormat[k], - mode_lib->vba.DSCInputBitPerComponent[k]); - mode_lib->vba.OutbppDSC = - TruncToValidBPP((1.0 - mode_lib->vba.Downspreading / 100.0) - * (1.0 - mode_lib->vba.EffectiveFECOverhead / 100.0) * 540.0 - * mode_lib->vba.OutputLinkDPLanes[k] / mode_lib->vba.PixelClockBackEnd[k] * 8.0, - true, - mode_lib->vba.Output[k], - mode_lib->vba.OutputFormat[k], - mode_lib->vba.DSCInputBitPerComponent[k]); - if (mode_lib->vba.DSCEnabled[k] == true) { - mode_lib->vba.RequiresDSC[i][k] = true; - if (mode_lib->vba.Output[k] == dm_dp) { - mode_lib->vba.RequiresFEC[i][k] = - true; - } else { - mode_lib->vba.RequiresFEC[i][k] = - false; - } - mode_lib->vba.Outbpp = - mode_lib->vba.OutbppDSC; - } else { - mode_lib->vba.RequiresDSC[i][k] = false; - mode_lib->vba.RequiresFEC[i][k] = false; - } - mode_lib->vba.OutputBppPerState[i][k] = - mode_lib->vba.Outbpp; - } - if (mode_lib->vba.Outbpp == BPP_INVALID - && mode_lib->vba.PHYCLKPerState[i] - >= 810.0) { - mode_lib->vba.Outbpp = - TruncToValidBPP((1.0 - mode_lib->vba.Downspreading / 100.0) * 810.0 - * mode_lib->vba.OutputLinkDPLanes[k] / mode_lib->vba.PixelClockBackEnd[k] * 8.0, - false, - mode_lib->vba.Output[k], - mode_lib->vba.OutputFormat[k], - mode_lib->vba.DSCInputBitPerComponent[k]); - mode_lib->vba.OutbppDSC = - TruncToValidBPP((1.0 - mode_lib->vba.Downspreading / 100.0) - * (1.0 - mode_lib->vba.EffectiveFECOverhead / 100.0) * 810.0 - * mode_lib->vba.OutputLinkDPLanes[k] / mode_lib->vba.PixelClockBackEnd[k] * 8.0, - true, - mode_lib->vba.Output[k], - mode_lib->vba.OutputFormat[k], - mode_lib->vba.DSCInputBitPerComponent[k]); - if (mode_lib->vba.DSCEnabled[k] == true - || mode_lib->vba.Outbpp == BPP_INVALID) { - mode_lib->vba.RequiresDSC[i][k] = true; - if (mode_lib->vba.Output[k] == dm_dp) { - mode_lib->vba.RequiresFEC[i][k] = - true; - } else { - mode_lib->vba.RequiresFEC[i][k] = - false; - } - mode_lib->vba.Outbpp = - mode_lib->vba.OutbppDSC; - } else { - mode_lib->vba.RequiresDSC[i][k] = false; - mode_lib->vba.RequiresFEC[i][k] = false; - } - mode_lib->vba.OutputBppPerState[i][k] = - mode_lib->vba.Outbpp; - } - } - } else { - mode_lib->vba.OutputBppPerState[i][k] = BPP_BLENDED_PIPE; - } - } - } - for (i = 0; i <= DC__VOLTAGE_STATES; i++) { - mode_lib->vba.DIOSupport[i] = true; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.OutputBppPerState[i][k] == BPP_INVALID - || (mode_lib->vba.OutputFormat[k] == dm_420 - && mode_lib->vba.ProgressiveToInterlaceUnitInOPP - == true)) { - mode_lib->vba.DIOSupport[i] = false; - } - } - } - for (i = 0; i <= DC__VOLTAGE_STATES; i++) { - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.DSCCLKRequiredMoreThanSupported[i] = false; - if (mode_lib->vba.BlendingAndTiming[k] == k) { - if ((mode_lib->vba.Output[k] == dm_dp - || mode_lib->vba.Output[k] == dm_edp)) { - if (mode_lib->vba.OutputFormat[k] == dm_420 - || mode_lib->vba.OutputFormat[k] - == dm_n422) { - mode_lib->vba.DSCFormatFactor = 2; - } else { - mode_lib->vba.DSCFormatFactor = 1; - } - if (mode_lib->vba.RequiresDSC[i][k] == true) { - if (mode_lib->vba.ODMCombineEnablePerState[i][k] - == true) { - if (mode_lib->vba.PixelClockBackEnd[k] / 6.0 - / mode_lib->vba.DSCFormatFactor - > (1.0 - - mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100.0) - * mode_lib->vba.MaxDSCCLK[i]) { - mode_lib->vba.DSCCLKRequiredMoreThanSupported[i] = - true; - } - } else { - if (mode_lib->vba.PixelClockBackEnd[k] / 3.0 - / mode_lib->vba.DSCFormatFactor - > (1.0 - - mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading - / 100.0) - * mode_lib->vba.MaxDSCCLK[i]) { - mode_lib->vba.DSCCLKRequiredMoreThanSupported[i] = - true; - } - } - } - } - } - } - } - for (i = 0; i <= DC__VOLTAGE_STATES; i++) { - mode_lib->vba.NotEnoughDSCUnits[i] = false; - mode_lib->vba.TotalDSCUnitsRequired = 0.0; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.RequiresDSC[i][k] == true) { - if (mode_lib->vba.ODMCombineEnablePerState[i][k] == true) { - mode_lib->vba.TotalDSCUnitsRequired = - mode_lib->vba.TotalDSCUnitsRequired + 2.0; - } else { - mode_lib->vba.TotalDSCUnitsRequired = - mode_lib->vba.TotalDSCUnitsRequired + 1.0; - } - } - } - if (mode_lib->vba.TotalDSCUnitsRequired > mode_lib->vba.NumberOfDSC) { - mode_lib->vba.NotEnoughDSCUnits[i] = true; - } - } - /*DSC Delay per state*/ - - for (i = 0; i <= DC__VOLTAGE_STATES; i++) { - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.BlendingAndTiming[k] != k) { - mode_lib->vba.slices = 0; - } else if (mode_lib->vba.RequiresDSC[i][k] == 0 - || mode_lib->vba.RequiresDSC[i][k] == false) { - mode_lib->vba.slices = 0; - } else if (mode_lib->vba.PixelClockBackEnd[k] > 3200.0) { - mode_lib->vba.slices = dml_ceil( - mode_lib->vba.PixelClockBackEnd[k] / 400.0, - 4.0); - } else if (mode_lib->vba.PixelClockBackEnd[k] > 1360.0) { - mode_lib->vba.slices = 8.0; - } else if (mode_lib->vba.PixelClockBackEnd[k] > 680.0) { - mode_lib->vba.slices = 4.0; - } else if (mode_lib->vba.PixelClockBackEnd[k] > 340.0) { - mode_lib->vba.slices = 2.0; - } else { - mode_lib->vba.slices = 1.0; - } - if (mode_lib->vba.OutputBppPerState[i][k] == BPP_BLENDED_PIPE - || mode_lib->vba.OutputBppPerState[i][k] == BPP_INVALID) { - mode_lib->vba.bpp = 0.0; - } else { - mode_lib->vba.bpp = mode_lib->vba.OutputBppPerState[i][k]; - } - if (mode_lib->vba.RequiresDSC[i][k] == true && mode_lib->vba.bpp != 0.0) { - if (mode_lib->vba.ODMCombineEnablePerState[i][k] == false) { - mode_lib->vba.DSCDelayPerState[i][k] = - dscceComputeDelay( - mode_lib->vba.DSCInputBitPerComponent[k], - mode_lib->vba.bpp, - dml_ceil( - mode_lib->vba.HActive[k] - / mode_lib->vba.slices, - 1.0), - mode_lib->vba.slices, - mode_lib->vba.OutputFormat[k]) - + dscComputeDelay( - mode_lib->vba.OutputFormat[k]); - } else { - mode_lib->vba.DSCDelayPerState[i][k] = - 2.0 - * (dscceComputeDelay( - mode_lib->vba.DSCInputBitPerComponent[k], - mode_lib->vba.bpp, - dml_ceil( - mode_lib->vba.HActive[k] - / mode_lib->vba.slices, - 1.0), - mode_lib->vba.slices - / 2, - mode_lib->vba.OutputFormat[k]) - + dscComputeDelay( - mode_lib->vba.OutputFormat[k])); - } - mode_lib->vba.DSCDelayPerState[i][k] = - mode_lib->vba.DSCDelayPerState[i][k] - * mode_lib->vba.PixelClock[k] - / mode_lib->vba.PixelClockBackEnd[k]; - } else { - mode_lib->vba.DSCDelayPerState[i][k] = 0.0; - } - } - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - for (j = 0; j <= mode_lib->vba.NumberOfActivePlanes - 1; j++) { - if (mode_lib->vba.BlendingAndTiming[k] == j - && mode_lib->vba.RequiresDSC[i][j] == true) { - mode_lib->vba.DSCDelayPerState[i][k] = - mode_lib->vba.DSCDelayPerState[i][j]; - } - } - } - } - /*Urgent Latency Support Check*/ - - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - for (i = 0; i <= DC__VOLTAGE_STATES; i++) { - if (mode_lib->vba.ODMCombineEnablePerState[i][k] == true) { - mode_lib->vba.SwathWidthYPerState[i][k] = - dml_min( - mode_lib->vba.SwathWidthYSingleDPP[k], - dml_round( - mode_lib->vba.HActive[k] - / 2.0 - * mode_lib->vba.HRatio[k])); - } else { - mode_lib->vba.SwathWidthYPerState[i][k] = - mode_lib->vba.SwathWidthYSingleDPP[k] - / mode_lib->vba.NoOfDPP[i][k]; - } - mode_lib->vba.SwathWidthGranularityY = 256.0 - / dml_ceil(mode_lib->vba.BytePerPixelInDETY[k], 1.0) - / mode_lib->vba.MaxSwathHeightY[k]; - mode_lib->vba.RoundedUpMaxSwathSizeBytesY = (dml_ceil( - mode_lib->vba.SwathWidthYPerState[i][k] - 1.0, - mode_lib->vba.SwathWidthGranularityY) - + mode_lib->vba.SwathWidthGranularityY) - * mode_lib->vba.BytePerPixelInDETY[k] - * mode_lib->vba.MaxSwathHeightY[k]; - if (mode_lib->vba.SourcePixelFormat[k] == dm_420_10) { - mode_lib->vba.RoundedUpMaxSwathSizeBytesY = dml_ceil( - mode_lib->vba.RoundedUpMaxSwathSizeBytesY, - 256.0) + 256; - } - if (mode_lib->vba.MaxSwathHeightC[k] > 0.0) { - mode_lib->vba.SwathWidthGranularityC = 256.0 - / dml_ceil(mode_lib->vba.BytePerPixelInDETC[k], 2.0) - / mode_lib->vba.MaxSwathHeightC[k]; - mode_lib->vba.RoundedUpMaxSwathSizeBytesC = (dml_ceil( - mode_lib->vba.SwathWidthYPerState[i][k] / 2.0 - 1.0, - mode_lib->vba.SwathWidthGranularityC) - + mode_lib->vba.SwathWidthGranularityC) - * mode_lib->vba.BytePerPixelInDETC[k] - * mode_lib->vba.MaxSwathHeightC[k]; - if (mode_lib->vba.SourcePixelFormat[k] == dm_420_10) { - mode_lib->vba.RoundedUpMaxSwathSizeBytesC = dml_ceil( - mode_lib->vba.RoundedUpMaxSwathSizeBytesC, - 256.0) + 256; - } - } else { - mode_lib->vba.RoundedUpMaxSwathSizeBytesC = 0.0; - } - if (mode_lib->vba.RoundedUpMaxSwathSizeBytesY - + mode_lib->vba.RoundedUpMaxSwathSizeBytesC - <= mode_lib->vba.DETBufferSizeInKByte * 1024.0 / 2.0) { - mode_lib->vba.SwathHeightYPerState[i][k] = - mode_lib->vba.MaxSwathHeightY[k]; - mode_lib->vba.SwathHeightCPerState[i][k] = - mode_lib->vba.MaxSwathHeightC[k]; - } else { - mode_lib->vba.SwathHeightYPerState[i][k] = - mode_lib->vba.MinSwathHeightY[k]; - mode_lib->vba.SwathHeightCPerState[i][k] = - mode_lib->vba.MinSwathHeightC[k]; - } - if (mode_lib->vba.BytePerPixelInDETC[k] == 0.0) { - mode_lib->vba.LinesInDETLuma = mode_lib->vba.DETBufferSizeInKByte - * 1024.0 / mode_lib->vba.BytePerPixelInDETY[k] - / mode_lib->vba.SwathWidthYPerState[i][k]; - mode_lib->vba.LinesInDETChroma = 0.0; - } else if (mode_lib->vba.SwathHeightYPerState[i][k] - <= mode_lib->vba.SwathHeightCPerState[i][k]) { - mode_lib->vba.LinesInDETLuma = mode_lib->vba.DETBufferSizeInKByte - * 1024.0 / 2.0 / mode_lib->vba.BytePerPixelInDETY[k] - / mode_lib->vba.SwathWidthYPerState[i][k]; - mode_lib->vba.LinesInDETChroma = mode_lib->vba.DETBufferSizeInKByte - * 1024.0 / 2.0 / mode_lib->vba.BytePerPixelInDETC[k] - / (mode_lib->vba.SwathWidthYPerState[i][k] / 2.0); - } else { - mode_lib->vba.LinesInDETLuma = mode_lib->vba.DETBufferSizeInKByte - * 1024.0 * 2.0 / 3.0 - / mode_lib->vba.BytePerPixelInDETY[k] - / mode_lib->vba.SwathWidthYPerState[i][k]; - mode_lib->vba.LinesInDETChroma = mode_lib->vba.DETBufferSizeInKByte - * 1024.0 / 3.0 / mode_lib->vba.BytePerPixelInDETY[k] - / (mode_lib->vba.SwathWidthYPerState[i][k] / 2.0); - } - mode_lib->vba.EffectiveLBLatencyHidingSourceLinesLuma = - dml_min( - mode_lib->vba.MaxLineBufferLines, - dml_floor( - mode_lib->vba.LineBufferSize - / mode_lib->vba.LBBitPerPixel[k] - / (mode_lib->vba.SwathWidthYPerState[i][k] - / dml_max( - mode_lib->vba.HRatio[k], - 1.0)), - 1.0)) - - (mode_lib->vba.vtaps[k] - 1.0); - mode_lib->vba.EffectiveLBLatencyHidingSourceLinesChroma = - dml_min( - mode_lib->vba.MaxLineBufferLines, - dml_floor( - mode_lib->vba.LineBufferSize - / mode_lib->vba.LBBitPerPixel[k] - / (mode_lib->vba.SwathWidthYPerState[i][k] - / 2.0 - / dml_max( - mode_lib->vba.HRatio[k] - / 2.0, - 1.0)), - 1.0)) - - (mode_lib->vba.VTAPsChroma[k] - 1.0); - mode_lib->vba.EffectiveDETLBLinesLuma = - dml_floor( - mode_lib->vba.LinesInDETLuma - + dml_min( - mode_lib->vba.LinesInDETLuma - * mode_lib->vba.RequiredDISPCLK[i] - * mode_lib->vba.BytePerPixelInDETY[k] - * mode_lib->vba.PSCL_FACTOR[k] - / mode_lib->vba.ReturnBWPerState[i], - mode_lib->vba.EffectiveLBLatencyHidingSourceLinesLuma), - mode_lib->vba.SwathHeightYPerState[i][k]); - mode_lib->vba.EffectiveDETLBLinesChroma = - dml_floor( - mode_lib->vba.LinesInDETChroma - + dml_min( - mode_lib->vba.LinesInDETChroma - * mode_lib->vba.RequiredDISPCLK[i] - * mode_lib->vba.BytePerPixelInDETC[k] - * mode_lib->vba.PSCL_FACTOR_CHROMA[k] - / mode_lib->vba.ReturnBWPerState[i], - mode_lib->vba.EffectiveLBLatencyHidingSourceLinesChroma), - mode_lib->vba.SwathHeightCPerState[i][k]); - if (mode_lib->vba.BytePerPixelInDETC[k] == 0.0) { - mode_lib->vba.UrgentLatencySupportUsPerState[i][k] = - mode_lib->vba.EffectiveDETLBLinesLuma - * (mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]) - / mode_lib->vba.VRatio[k] - - mode_lib->vba.EffectiveDETLBLinesLuma - * mode_lib->vba.SwathWidthYPerState[i][k] - * dml_ceil( - mode_lib->vba.BytePerPixelInDETY[k], - 1.0) - / (mode_lib->vba.ReturnBWPerState[i] - / mode_lib->vba.NoOfDPP[i][k]); - } else { - mode_lib->vba.UrgentLatencySupportUsPerState[i][k] = - dml_min( - mode_lib->vba.EffectiveDETLBLinesLuma - * (mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]) - / mode_lib->vba.VRatio[k] - - mode_lib->vba.EffectiveDETLBLinesLuma - * mode_lib->vba.SwathWidthYPerState[i][k] - * dml_ceil( - mode_lib->vba.BytePerPixelInDETY[k], - 1.0) - / (mode_lib->vba.ReturnBWPerState[i] - / mode_lib->vba.NoOfDPP[i][k]), - mode_lib->vba.EffectiveDETLBLinesChroma - * (mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]) - / (mode_lib->vba.VRatio[k] - / 2.0) - - mode_lib->vba.EffectiveDETLBLinesChroma - * mode_lib->vba.SwathWidthYPerState[i][k] - / 2.0 - * dml_ceil( - mode_lib->vba.BytePerPixelInDETC[k], - 2.0) - / (mode_lib->vba.ReturnBWPerState[i] - / mode_lib->vba.NoOfDPP[i][k])); - } - } - } - for (i = 0; i <= DC__VOLTAGE_STATES; i++) { - mode_lib->vba.UrgentLatencySupport[i] = true; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.UrgentLatencySupportUsPerState[i][k] - < mode_lib->vba.UrgentLatency / 1.0) { - mode_lib->vba.UrgentLatencySupport[i] = false; - } - } - } - /*Prefetch Check*/ - - for (i = 0; i <= DC__VOLTAGE_STATES; i++) { - mode_lib->vba.TotalNumberOfDCCActiveDPP[i] = 0.0; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.DCCEnable[k] == true) { - mode_lib->vba.TotalNumberOfDCCActiveDPP[i] = - mode_lib->vba.TotalNumberOfDCCActiveDPP[i] - + mode_lib->vba.NoOfDPP[i][k]; - } - } - } - for (i = 0; i <= DC__VOLTAGE_STATES; i++) { - mode_lib->vba.ProjectedDCFCLKDeepSleep = 8.0; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.ProjectedDCFCLKDeepSleep = dml_max( - mode_lib->vba.ProjectedDCFCLKDeepSleep, - mode_lib->vba.PixelClock[k] / 16.0); - if (mode_lib->vba.BytePerPixelInDETC[k] == 0.0) { - if (mode_lib->vba.VRatio[k] <= 1.0) { - mode_lib->vba.ProjectedDCFCLKDeepSleep = - dml_max( - mode_lib->vba.ProjectedDCFCLKDeepSleep, - 1.1 - * dml_ceil( - mode_lib->vba.BytePerPixelInDETY[k], - 1.0) - / 64.0 - * mode_lib->vba.HRatio[k] - * mode_lib->vba.PixelClock[k] - / mode_lib->vba.NoOfDPP[i][k]); - } else { - mode_lib->vba.ProjectedDCFCLKDeepSleep = - dml_max( - mode_lib->vba.ProjectedDCFCLKDeepSleep, - 1.1 - * dml_ceil( - mode_lib->vba.BytePerPixelInDETY[k], - 1.0) - / 64.0 - * mode_lib->vba.PSCL_FACTOR[k] - * mode_lib->vba.RequiredDPPCLK[i][k]); - } - } else { - if (mode_lib->vba.VRatio[k] <= 1.0) { - mode_lib->vba.ProjectedDCFCLKDeepSleep = - dml_max( - mode_lib->vba.ProjectedDCFCLKDeepSleep, - 1.1 - * dml_ceil( - mode_lib->vba.BytePerPixelInDETY[k], - 1.0) - / 32.0 - * mode_lib->vba.HRatio[k] - * mode_lib->vba.PixelClock[k] - / mode_lib->vba.NoOfDPP[i][k]); - } else { - mode_lib->vba.ProjectedDCFCLKDeepSleep = - dml_max( - mode_lib->vba.ProjectedDCFCLKDeepSleep, - 1.1 - * dml_ceil( - mode_lib->vba.BytePerPixelInDETY[k], - 1.0) - / 32.0 - * mode_lib->vba.PSCL_FACTOR[k] - * mode_lib->vba.RequiredDPPCLK[i][k]); - } - if (mode_lib->vba.VRatio[k] / 2.0 <= 1.0) { - mode_lib->vba.ProjectedDCFCLKDeepSleep = - dml_max( - mode_lib->vba.ProjectedDCFCLKDeepSleep, - 1.1 - * dml_ceil( - mode_lib->vba.BytePerPixelInDETC[k], - 2.0) - / 32.0 - * mode_lib->vba.HRatio[k] - / 2.0 - * mode_lib->vba.PixelClock[k] - / mode_lib->vba.NoOfDPP[i][k]); - } else { - mode_lib->vba.ProjectedDCFCLKDeepSleep = - dml_max( - mode_lib->vba.ProjectedDCFCLKDeepSleep, - 1.1 - * dml_ceil( - mode_lib->vba.BytePerPixelInDETC[k], - 2.0) - / 32.0 - * mode_lib->vba.PSCL_FACTOR_CHROMA[k] - * mode_lib->vba.RequiredDPPCLK[i][k]); - } - } - } - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.PDEAndMetaPTEBytesPerFrameY = CalculateVMAndRowBytes( - mode_lib, - mode_lib->vba.DCCEnable[k], - mode_lib->vba.Read256BlockHeightY[k], - mode_lib->vba.Read256BlockWidthY[k], - mode_lib->vba.SourcePixelFormat[k], - mode_lib->vba.SurfaceTiling[k], - dml_ceil(mode_lib->vba.BytePerPixelInDETY[k], 1.0), - mode_lib->vba.SourceScan[k], - mode_lib->vba.ViewportWidth[k], - mode_lib->vba.ViewportHeight[k], - mode_lib->vba.SwathWidthYPerState[i][k], - mode_lib->vba.VirtualMemoryEnable, - mode_lib->vba.VMMPageSize, - mode_lib->vba.PTEBufferSizeInRequests, - mode_lib->vba.PDEProcessingBufIn64KBReqs, - mode_lib->vba.PitchY[k], - mode_lib->vba.DCCMetaPitchY[k], - &mode_lib->vba.MacroTileWidthY[k], - &mode_lib->vba.MetaRowBytesY, - &mode_lib->vba.DPTEBytesPerRowY, - &mode_lib->vba.PTEBufferSizeNotExceededY[i][k], - &mode_lib->vba.dpte_row_height[k], - &mode_lib->vba.meta_row_height[k]); - mode_lib->vba.PrefetchLinesY[k] = CalculatePrefetchSourceLines( - mode_lib, - mode_lib->vba.VRatio[k], - mode_lib->vba.vtaps[k], - mode_lib->vba.Interlace[k], - mode_lib->vba.ProgressiveToInterlaceUnitInOPP, - mode_lib->vba.SwathHeightYPerState[i][k], - mode_lib->vba.ViewportYStartY[k], - &mode_lib->vba.PrefillY[k], - &mode_lib->vba.MaxNumSwY[k]); - if ((mode_lib->vba.SourcePixelFormat[k] != dm_444_64 - && mode_lib->vba.SourcePixelFormat[k] != dm_444_32 - && mode_lib->vba.SourcePixelFormat[k] != dm_444_16 - && mode_lib->vba.SourcePixelFormat[k] != dm_mono_16 - && mode_lib->vba.SourcePixelFormat[k] != dm_mono_8)) { - mode_lib->vba.PDEAndMetaPTEBytesPerFrameC = CalculateVMAndRowBytes( - mode_lib, - mode_lib->vba.DCCEnable[k], - mode_lib->vba.Read256BlockHeightY[k], - mode_lib->vba.Read256BlockWidthY[k], - mode_lib->vba.SourcePixelFormat[k], - mode_lib->vba.SurfaceTiling[k], - dml_ceil(mode_lib->vba.BytePerPixelInDETC[k], 2.0), - mode_lib->vba.SourceScan[k], - mode_lib->vba.ViewportWidth[k] / 2.0, - mode_lib->vba.ViewportHeight[k] / 2.0, - mode_lib->vba.SwathWidthYPerState[i][k] / 2.0, - mode_lib->vba.VirtualMemoryEnable, - mode_lib->vba.VMMPageSize, - mode_lib->vba.PTEBufferSizeInRequests, - mode_lib->vba.PDEProcessingBufIn64KBReqs, - mode_lib->vba.PitchC[k], - 0.0, - &mode_lib->vba.MacroTileWidthC[k], - &mode_lib->vba.MetaRowBytesC, - &mode_lib->vba.DPTEBytesPerRowC, - &mode_lib->vba.PTEBufferSizeNotExceededC[i][k], - &mode_lib->vba.dpte_row_height_chroma[k], - &mode_lib->vba.meta_row_height_chroma[k]); - mode_lib->vba.PrefetchLinesC[k] = CalculatePrefetchSourceLines( - mode_lib, - mode_lib->vba.VRatio[k] / 2.0, - mode_lib->vba.VTAPsChroma[k], - mode_lib->vba.Interlace[k], - mode_lib->vba.ProgressiveToInterlaceUnitInOPP, - mode_lib->vba.SwathHeightCPerState[i][k], - mode_lib->vba.ViewportYStartC[k], - &mode_lib->vba.PrefillC[k], - &mode_lib->vba.MaxNumSwC[k]); - } else { - mode_lib->vba.PDEAndMetaPTEBytesPerFrameC = 0.0; - mode_lib->vba.MetaRowBytesC = 0.0; - mode_lib->vba.DPTEBytesPerRowC = 0.0; - mode_lib->vba.PrefetchLinesC[k] = 0.0; - mode_lib->vba.PTEBufferSizeNotExceededC[i][k] = true; - } - mode_lib->vba.PDEAndMetaPTEBytesPerFrame[k] = - mode_lib->vba.PDEAndMetaPTEBytesPerFrameY - + mode_lib->vba.PDEAndMetaPTEBytesPerFrameC; - mode_lib->vba.MetaRowBytes[k] = mode_lib->vba.MetaRowBytesY - + mode_lib->vba.MetaRowBytesC; - mode_lib->vba.DPTEBytesPerRow[k] = mode_lib->vba.DPTEBytesPerRowY - + mode_lib->vba.DPTEBytesPerRowC; - } - mode_lib->vba.ExtraLatency = - mode_lib->vba.UrgentRoundTripAndOutOfOrderLatencyPerState[i] - + (mode_lib->vba.TotalNumberOfActiveDPP[i] - * mode_lib->vba.PixelChunkSizeInKByte - + mode_lib->vba.TotalNumberOfDCCActiveDPP[i] - * mode_lib->vba.MetaChunkSize) - * 1024.0 - / mode_lib->vba.ReturnBWPerState[i]; - if (mode_lib->vba.VirtualMemoryEnable == true) { - mode_lib->vba.ExtraLatency = mode_lib->vba.ExtraLatency - + mode_lib->vba.TotalNumberOfActiveDPP[i] - * mode_lib->vba.PTEChunkSize * 1024.0 - / mode_lib->vba.ReturnBWPerState[i]; - } - mode_lib->vba.TimeCalc = 24.0 / mode_lib->vba.ProjectedDCFCLKDeepSleep; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.BlendingAndTiming[k] == k) { - if (mode_lib->vba.WritebackEnable[k] == true) { - mode_lib->vba.WritebackDelay[i][k] = - mode_lib->vba.WritebackLatency - + CalculateWriteBackDelay( - mode_lib->vba.WritebackPixelFormat[k], - mode_lib->vba.WritebackHRatio[k], - mode_lib->vba.WritebackVRatio[k], - mode_lib->vba.WritebackLumaHTaps[k], - mode_lib->vba.WritebackLumaVTaps[k], - mode_lib->vba.WritebackChromaHTaps[k], - mode_lib->vba.WritebackChromaVTaps[k], - mode_lib->vba.WritebackDestinationWidth[k]) - / mode_lib->vba.RequiredDISPCLK[i]; - } else { - mode_lib->vba.WritebackDelay[i][k] = 0.0; - } - for (j = 0; j <= mode_lib->vba.NumberOfActivePlanes - 1; j++) { - if (mode_lib->vba.BlendingAndTiming[j] == k - && mode_lib->vba.WritebackEnable[j] - == true) { - mode_lib->vba.WritebackDelay[i][k] = - dml_max( - mode_lib->vba.WritebackDelay[i][k], - mode_lib->vba.WritebackLatency - + CalculateWriteBackDelay( - mode_lib->vba.WritebackPixelFormat[j], - mode_lib->vba.WritebackHRatio[j], - mode_lib->vba.WritebackVRatio[j], - mode_lib->vba.WritebackLumaHTaps[j], - mode_lib->vba.WritebackLumaVTaps[j], - mode_lib->vba.WritebackChromaHTaps[j], - mode_lib->vba.WritebackChromaVTaps[j], - mode_lib->vba.WritebackDestinationWidth[j]) - / mode_lib->vba.RequiredDISPCLK[i]); - } - } - } - } - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - for (j = 0; j <= mode_lib->vba.NumberOfActivePlanes - 1; j++) { - if (mode_lib->vba.BlendingAndTiming[k] == j) { - mode_lib->vba.WritebackDelay[i][k] = - mode_lib->vba.WritebackDelay[i][j]; - } - } - } - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.MaximumVStartup[k] = - mode_lib->vba.VTotal[k] - mode_lib->vba.VActive[k] - - dml_max( - 1.0, - dml_ceil( - mode_lib->vba.WritebackDelay[i][k] - / (mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]), - 1.0)); - } - mode_lib->vba.TWait = CalculateTWait( - mode_lib->vba.PrefetchMode, - mode_lib->vba.DRAMClockChangeLatency, - mode_lib->vba.UrgentLatency, - mode_lib->vba.SREnterPlusExitTime); - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.XFCEnabled[k] == true) { - mode_lib->vba.XFCRemoteSurfaceFlipDelay = - CalculateRemoteSurfaceFlipDelay( - mode_lib, - mode_lib->vba.VRatio[k], - mode_lib->vba.SwathWidthYPerState[i][k], - dml_ceil( - mode_lib->vba.BytePerPixelInDETY[k], - 1.0), - mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k], - mode_lib->vba.XFCTSlvVupdateOffset, - mode_lib->vba.XFCTSlvVupdateWidth, - mode_lib->vba.XFCTSlvVreadyOffset, - mode_lib->vba.XFCXBUFLatencyTolerance, - mode_lib->vba.XFCFillBWOverhead, - mode_lib->vba.XFCSlvChunkSize, - mode_lib->vba.XFCBusTransportTime, - mode_lib->vba.TimeCalc, - mode_lib->vba.TWait, - &mode_lib->vba.SrcActiveDrainRate, - &mode_lib->vba.TInitXFill, - &mode_lib->vba.TslvChk); - } else { - mode_lib->vba.XFCRemoteSurfaceFlipDelay = 0.0; - } - mode_lib->vba.IsErrorResult[i][k] = - CalculatePrefetchSchedule( - mode_lib, - mode_lib->vba.RequiredDPPCLK[i][k], - mode_lib->vba.RequiredDISPCLK[i], - mode_lib->vba.PixelClock[k], - mode_lib->vba.ProjectedDCFCLKDeepSleep, - mode_lib->vba.DSCDelayPerState[i][k], - mode_lib->vba.NoOfDPP[i][k], - mode_lib->vba.ScalerEnabled[k], - mode_lib->vba.NumberOfCursors[k], - mode_lib->vba.DPPCLKDelaySubtotal, - mode_lib->vba.DPPCLKDelaySCL, - mode_lib->vba.DPPCLKDelaySCLLBOnly, - mode_lib->vba.DPPCLKDelayCNVCFormater, - mode_lib->vba.DPPCLKDelayCNVCCursor, - mode_lib->vba.DISPCLKDelaySubtotal, - mode_lib->vba.SwathWidthYPerState[i][k] - / mode_lib->vba.HRatio[k], - mode_lib->vba.OutputFormat[k], - mode_lib->vba.VTotal[k] - - mode_lib->vba.VActive[k], - mode_lib->vba.HTotal[k], - mode_lib->vba.MaxInterDCNTileRepeaters, - mode_lib->vba.MaximumVStartup[k], - mode_lib->vba.MaxPageTableLevels, - mode_lib->vba.VirtualMemoryEnable, - mode_lib->vba.DynamicMetadataEnable[k], - mode_lib->vba.DynamicMetadataLinesBeforeActiveRequired[k], - mode_lib->vba.DynamicMetadataTransmittedBytes[k], - mode_lib->vba.DCCEnable[k], - mode_lib->vba.UrgentLatency, - mode_lib->vba.ExtraLatency, - mode_lib->vba.TimeCalc, - mode_lib->vba.PDEAndMetaPTEBytesPerFrame[k], - mode_lib->vba.MetaRowBytes[k], - mode_lib->vba.DPTEBytesPerRow[k], - mode_lib->vba.PrefetchLinesY[k], - mode_lib->vba.SwathWidthYPerState[i][k], - mode_lib->vba.BytePerPixelInDETY[k], - mode_lib->vba.PrefillY[k], - mode_lib->vba.MaxNumSwY[k], - mode_lib->vba.PrefetchLinesC[k], - mode_lib->vba.BytePerPixelInDETC[k], - mode_lib->vba.PrefillC[k], - mode_lib->vba.MaxNumSwC[k], - mode_lib->vba.SwathHeightYPerState[i][k], - mode_lib->vba.SwathHeightCPerState[i][k], - mode_lib->vba.TWait, - mode_lib->vba.XFCEnabled[k], - mode_lib->vba.XFCRemoteSurfaceFlipDelay, - mode_lib->vba.Interlace[k], - mode_lib->vba.ProgressiveToInterlaceUnitInOPP, - mode_lib->vba.DSTXAfterScaler, - mode_lib->vba.DSTYAfterScaler, - &mode_lib->vba.LineTimesForPrefetch[k], - &mode_lib->vba.PrefetchBW[k], - &mode_lib->vba.LinesForMetaPTE[k], - &mode_lib->vba.LinesForMetaAndDPTERow[k], - &mode_lib->vba.VRatioPreY[i][k], - &mode_lib->vba.VRatioPreC[i][k], - &mode_lib->vba.RequiredPrefetchPixelDataBW[i][k], - &mode_lib->vba.VStartupRequiredWhenNotEnoughTimeForDynamicMetadata, - &mode_lib->vba.Tno_bw[k], - &mode_lib->vba.VUpdateOffsetPix[k], - &mode_lib->vba.VUpdateWidthPix[k], - &mode_lib->vba.VReadyOffsetPix[k]); - } - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.cursor_bw[k] = mode_lib->vba.NumberOfCursors[k] - * mode_lib->vba.CursorWidth[k][0] - * mode_lib->vba.CursorBPP[k][0] / 8.0 - / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) - * mode_lib->vba.VRatio[k]; - } - mode_lib->vba.MaximumReadBandwidthWithPrefetch = 0.0; - mode_lib->vba.prefetch_vm_bw_valid = true; - mode_lib->vba.prefetch_row_bw_valid = true; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.PDEAndMetaPTEBytesPerFrame[k] == 0.0) { - mode_lib->vba.prefetch_vm_bw[k] = 0.0; - } else if (mode_lib->vba.LinesForMetaPTE[k] > 0.0) { - mode_lib->vba.prefetch_vm_bw[k] = - mode_lib->vba.PDEAndMetaPTEBytesPerFrame[k] - / (mode_lib->vba.LinesForMetaPTE[k] - * mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]); - } else { - mode_lib->vba.prefetch_vm_bw[k] = 0.0; - mode_lib->vba.prefetch_vm_bw_valid = false; - } - if (mode_lib->vba.MetaRowBytes[k] + mode_lib->vba.DPTEBytesPerRow[k] - == 0.0) { - mode_lib->vba.prefetch_row_bw[k] = 0.0; - } else if (mode_lib->vba.LinesForMetaAndDPTERow[k] > 0.0) { - mode_lib->vba.prefetch_row_bw[k] = (mode_lib->vba.MetaRowBytes[k] - + mode_lib->vba.DPTEBytesPerRow[k]) - / (mode_lib->vba.LinesForMetaAndDPTERow[k] - * mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k]); - } else { - mode_lib->vba.prefetch_row_bw[k] = 0.0; - mode_lib->vba.prefetch_row_bw_valid = false; - } - mode_lib->vba.MaximumReadBandwidthWithPrefetch = - mode_lib->vba.MaximumReadBandwidthWithPrefetch - + mode_lib->vba.cursor_bw[k] - + dml_max4( - mode_lib->vba.prefetch_vm_bw[k], - mode_lib->vba.prefetch_row_bw[k], - mode_lib->vba.ReadBandwidth[k], - mode_lib->vba.RequiredPrefetchPixelDataBW[i][k]); - } - mode_lib->vba.PrefetchSupported[i] = true; - if (mode_lib->vba.MaximumReadBandwidthWithPrefetch - > mode_lib->vba.ReturnBWPerState[i] - || mode_lib->vba.prefetch_vm_bw_valid == false - || mode_lib->vba.prefetch_row_bw_valid == false) { - mode_lib->vba.PrefetchSupported[i] = false; - } - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.LineTimesForPrefetch[k] < 2.0 - || mode_lib->vba.LinesForMetaPTE[k] >= 8.0 - || mode_lib->vba.LinesForMetaAndDPTERow[k] >= 16.0 - || mode_lib->vba.IsErrorResult[i][k] == true) { - mode_lib->vba.PrefetchSupported[i] = false; - } - } - mode_lib->vba.VRatioInPrefetchSupported[i] = true; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.VRatioPreY[i][k] > 4.0 - || mode_lib->vba.VRatioPreC[i][k] > 4.0 - || mode_lib->vba.IsErrorResult[i][k] == true) { - mode_lib->vba.VRatioInPrefetchSupported[i] = false; - } - } - if (mode_lib->vba.PrefetchSupported[i] == true - && mode_lib->vba.VRatioInPrefetchSupported[i] == true) { - mode_lib->vba.BandwidthAvailableForImmediateFlip = - mode_lib->vba.ReturnBWPerState[i]; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.BandwidthAvailableForImmediateFlip = - mode_lib->vba.BandwidthAvailableForImmediateFlip - - mode_lib->vba.cursor_bw[k] - - dml_max( - mode_lib->vba.ReadBandwidth[k], - mode_lib->vba.PrefetchBW[k]); - } - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.ImmediateFlipBytes[k] = 0.0; - if ((mode_lib->vba.SourcePixelFormat[k] != dm_420_8 - && mode_lib->vba.SourcePixelFormat[k] != dm_420_10)) { - mode_lib->vba.ImmediateFlipBytes[k] = - mode_lib->vba.PDEAndMetaPTEBytesPerFrame[k] - + mode_lib->vba.MetaRowBytes[k] - + mode_lib->vba.DPTEBytesPerRow[k]; - } - } - mode_lib->vba.TotImmediateFlipBytes = 0.0; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if ((mode_lib->vba.SourcePixelFormat[k] != dm_420_8 - && mode_lib->vba.SourcePixelFormat[k] != dm_420_10)) { - mode_lib->vba.TotImmediateFlipBytes = - mode_lib->vba.TotImmediateFlipBytes - + mode_lib->vba.ImmediateFlipBytes[k]; - } - } - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - CalculateFlipSchedule( - mode_lib, - mode_lib->vba.ExtraLatency, - mode_lib->vba.UrgentLatency, - mode_lib->vba.MaxPageTableLevels, - mode_lib->vba.VirtualMemoryEnable, - mode_lib->vba.BandwidthAvailableForImmediateFlip, - mode_lib->vba.TotImmediateFlipBytes, - mode_lib->vba.SourcePixelFormat[k], - mode_lib->vba.ImmediateFlipBytes[k], - mode_lib->vba.HTotal[k] - / mode_lib->vba.PixelClock[k], - mode_lib->vba.VRatio[k], - mode_lib->vba.Tno_bw[k], - mode_lib->vba.PDEAndMetaPTEBytesPerFrame[k], - mode_lib->vba.MetaRowBytes[k], - mode_lib->vba.DPTEBytesPerRow[k], - mode_lib->vba.DCCEnable[k], - mode_lib->vba.dpte_row_height[k], - mode_lib->vba.meta_row_height[k], - mode_lib->vba.qual_row_bw[k], - &mode_lib->vba.DestinationLinesToRequestVMInImmediateFlip[k], - &mode_lib->vba.DestinationLinesToRequestRowInImmediateFlip[k], - &mode_lib->vba.final_flip_bw[k], - &mode_lib->vba.ImmediateFlipSupportedForPipe[k]); - } - mode_lib->vba.total_dcn_read_bw_with_flip = 0.0; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.total_dcn_read_bw_with_flip = - mode_lib->vba.total_dcn_read_bw_with_flip - + mode_lib->vba.cursor_bw[k] - + dml_max3( - mode_lib->vba.prefetch_vm_bw[k], - mode_lib->vba.prefetch_row_bw[k], - mode_lib->vba.final_flip_bw[k] - + dml_max( - mode_lib->vba.ReadBandwidth[k], - mode_lib->vba.RequiredPrefetchPixelDataBW[i][k])); - } - mode_lib->vba.ImmediateFlipSupportedForState[i] = true; - if (mode_lib->vba.total_dcn_read_bw_with_flip - > mode_lib->vba.ReturnBWPerState[i]) { - mode_lib->vba.ImmediateFlipSupportedForState[i] = false; - } - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.ImmediateFlipSupportedForPipe[k] == false) { - mode_lib->vba.ImmediateFlipSupportedForState[i] = false; - } - } - } else { - mode_lib->vba.ImmediateFlipSupportedForState[i] = false; - } - } - /*PTE Buffer Size Check*/ - - for (i = 0; i <= DC__VOLTAGE_STATES; i++) { - mode_lib->vba.PTEBufferSizeNotExceeded[i] = true; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.PTEBufferSizeNotExceededY[i][k] == false - || mode_lib->vba.PTEBufferSizeNotExceededC[i][k] == false) { - mode_lib->vba.PTEBufferSizeNotExceeded[i] = false; - } - } - } - /*Cursor Support Check*/ - - mode_lib->vba.CursorSupport = true; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.CursorWidth[k][0] > 0.0) { - if (dml_floor( - dml_floor( - mode_lib->vba.CursorBufferSize - - mode_lib->vba.CursorChunkSize, - mode_lib->vba.CursorChunkSize) * 1024.0 - / (mode_lib->vba.CursorWidth[k][0] - * mode_lib->vba.CursorBPP[k][0] - / 8.0), - 1.0) - * (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) - / mode_lib->vba.VRatio[k] < mode_lib->vba.UrgentLatency - || (mode_lib->vba.CursorBPP[k][0] == 64.0 - && mode_lib->vba.Cursor64BppSupport == false)) { - mode_lib->vba.CursorSupport = false; - } - } - } - /*Valid Pitch Check*/ - - mode_lib->vba.PitchSupport = true; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.AlignedYPitch[k] = dml_ceil( - dml_max(mode_lib->vba.PitchY[k], mode_lib->vba.ViewportWidth[k]), - mode_lib->vba.MacroTileWidthY[k]); - if (mode_lib->vba.AlignedYPitch[k] > mode_lib->vba.PitchY[k]) { - mode_lib->vba.PitchSupport = false; - } - if (mode_lib->vba.DCCEnable[k] == true) { - mode_lib->vba.AlignedDCCMetaPitch[k] = dml_ceil( - dml_max( - mode_lib->vba.DCCMetaPitchY[k], - mode_lib->vba.ViewportWidth[k]), - 64.0 * mode_lib->vba.Read256BlockWidthY[k]); - } else { - mode_lib->vba.AlignedDCCMetaPitch[k] = mode_lib->vba.DCCMetaPitchY[k]; - } - if (mode_lib->vba.AlignedDCCMetaPitch[k] > mode_lib->vba.DCCMetaPitchY[k]) { - mode_lib->vba.PitchSupport = false; - } - if (mode_lib->vba.SourcePixelFormat[k] != dm_444_64 - && mode_lib->vba.SourcePixelFormat[k] != dm_444_32 - && mode_lib->vba.SourcePixelFormat[k] != dm_444_16 - && mode_lib->vba.SourcePixelFormat[k] != dm_mono_16 - && mode_lib->vba.SourcePixelFormat[k] != dm_mono_8) { - mode_lib->vba.AlignedCPitch[k] = dml_ceil( - dml_max( - mode_lib->vba.PitchC[k], - mode_lib->vba.ViewportWidth[k] / 2.0), - mode_lib->vba.MacroTileWidthC[k]); - } else { - mode_lib->vba.AlignedCPitch[k] = mode_lib->vba.PitchC[k]; - } - if (mode_lib->vba.AlignedCPitch[k] > mode_lib->vba.PitchC[k]) { - mode_lib->vba.PitchSupport = false; - } - } - /*Mode Support, Voltage State and SOC Configuration*/ - - for (i = DC__VOLTAGE_STATES; i >= 0; i--) { - if (mode_lib->vba.ScaleRatioAndTapsSupport == true - && mode_lib->vba.SourceFormatPixelAndScanSupport == true - && mode_lib->vba.ViewportSizeSupport[i] == true - && mode_lib->vba.BandwidthSupport[i] == true - && mode_lib->vba.DIOSupport[i] == true - && mode_lib->vba.NotEnoughDSCUnits[i] == false - && mode_lib->vba.DSCCLKRequiredMoreThanSupported[i] == false - && mode_lib->vba.UrgentLatencySupport[i] == true - && mode_lib->vba.ROBSupport[i] == true - && mode_lib->vba.DISPCLK_DPPCLK_Support[i] == true - && mode_lib->vba.TotalAvailablePipesSupport[i] == true - && mode_lib->vba.NumberOfOTGSupport == true - && mode_lib->vba.WritebackModeSupport == true - && mode_lib->vba.WritebackLatencySupport == true - && mode_lib->vba.WritebackScaleRatioAndTapsSupport == true - && mode_lib->vba.CursorSupport == true - && mode_lib->vba.PitchSupport == true - && mode_lib->vba.PrefetchSupported[i] == true - && mode_lib->vba.VRatioInPrefetchSupported[i] == true - && mode_lib->vba.PTEBufferSizeNotExceeded[i] == true - && mode_lib->vba.NonsupportedDSCInputBPC == false) { - mode_lib->vba.ModeSupport[i] = true; - } else { - mode_lib->vba.ModeSupport[i] = false; - } - } - for (i = DC__VOLTAGE_STATES; i >= 0; i--) { - if (i == DC__VOLTAGE_STATES || mode_lib->vba.ModeSupport[i] == true) { - mode_lib->vba.VoltageLevel = i; - } - } - mode_lib->vba.DCFCLK = mode_lib->vba.DCFCLKPerState[mode_lib->vba.VoltageLevel]; - mode_lib->vba.DRAMSpeed = mode_lib->vba.DRAMSpeedPerState[mode_lib->vba.VoltageLevel]; - mode_lib->vba.FabricClock = mode_lib->vba.FabricClockPerState[mode_lib->vba.VoltageLevel]; - mode_lib->vba.SOCCLK = mode_lib->vba.SOCCLKPerState[mode_lib->vba.VoltageLevel]; - mode_lib->vba.FabricAndDRAMBandwidth = - mode_lib->vba.FabricAndDRAMBandwidthPerState[mode_lib->vba.VoltageLevel]; - mode_lib->vba.ImmediateFlipSupport = - mode_lib->vba.ImmediateFlipSupportedForState[mode_lib->vba.VoltageLevel]; - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - mode_lib->vba.DPPPerPlane[k] = mode_lib->vba.NoOfDPP[mode_lib->vba.VoltageLevel][k]; - } - for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { - if (mode_lib->vba.BlendingAndTiming[k] == k) { - mode_lib->vba.ODMCombineEnabled[k] = - mode_lib->vba.ODMCombineEnablePerState[mode_lib->vba.VoltageLevel][k]; - } else { - mode_lib->vba.ODMCombineEnabled[k] = 0; - } - mode_lib->vba.DSCEnabled[k] = - mode_lib->vba.RequiresDSC[mode_lib->vba.VoltageLevel][k]; - mode_lib->vba.OutputBpp[k] = - mode_lib->vba.OutputBppPerState[mode_lib->vba.VoltageLevel][k]; - } -} diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h deleted file mode 100644 index 4112409cd974..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h +++ /dev/null @@ -1,598 +0,0 @@ -/* - * Copyright 2017 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DML2_DISPLAY_MODE_VBA_H__ -#define __DML2_DISPLAY_MODE_VBA_H__ - -#include "dml_common_defs.h" - -struct display_mode_lib; - -void set_prefetch_mode(struct display_mode_lib *mode_lib, - bool cstate_en, - bool pstate_en, - bool ignore_viewport_pos, - bool immediate_flip_support); - -#define dml_get_attr_decl(attr) double get_##attr(struct display_mode_lib *mode_lib, const display_e2e_pipe_params_st *pipes, unsigned int num_pipes) - -dml_get_attr_decl(clk_dcf_deepsleep); -dml_get_attr_decl(wm_urgent); -dml_get_attr_decl(wm_memory_trip); -dml_get_attr_decl(wm_writeback_urgent); -dml_get_attr_decl(wm_stutter_exit); -dml_get_attr_decl(wm_stutter_enter_exit); -dml_get_attr_decl(wm_dram_clock_change); -dml_get_attr_decl(wm_writeback_dram_clock_change); -dml_get_attr_decl(wm_xfc_underflow); -dml_get_attr_decl(stutter_efficiency_no_vblank); -dml_get_attr_decl(stutter_efficiency); -dml_get_attr_decl(urgent_latency); -dml_get_attr_decl(urgent_extra_latency); -dml_get_attr_decl(nonurgent_latency); -dml_get_attr_decl(dram_clock_change_latency); -dml_get_attr_decl(dispclk_calculated); -dml_get_attr_decl(total_data_read_bw); -dml_get_attr_decl(return_bw); -dml_get_attr_decl(tcalc); - -#define dml_get_pipe_attr_decl(attr) double get_##attr(struct display_mode_lib *mode_lib, const display_e2e_pipe_params_st *pipes, unsigned int num_pipes, unsigned int which_pipe) - -dml_get_pipe_attr_decl(dsc_delay); -dml_get_pipe_attr_decl(dppclk_calculated); -dml_get_pipe_attr_decl(dscclk_calculated); -dml_get_pipe_attr_decl(min_ttu_vblank); -dml_get_pipe_attr_decl(vratio_prefetch_l); -dml_get_pipe_attr_decl(vratio_prefetch_c); -dml_get_pipe_attr_decl(dst_x_after_scaler); -dml_get_pipe_attr_decl(dst_y_after_scaler); -dml_get_pipe_attr_decl(dst_y_per_vm_vblank); -dml_get_pipe_attr_decl(dst_y_per_row_vblank); -dml_get_pipe_attr_decl(dst_y_prefetch); -dml_get_pipe_attr_decl(dst_y_per_vm_flip); -dml_get_pipe_attr_decl(dst_y_per_row_flip); -dml_get_pipe_attr_decl(xfc_transfer_delay); -dml_get_pipe_attr_decl(xfc_precharge_delay); -dml_get_pipe_attr_decl(xfc_remote_surface_flip_latency); -dml_get_pipe_attr_decl(xfc_prefetch_margin); - -unsigned int get_vstartup_calculated( - struct display_mode_lib *mode_lib, - const display_e2e_pipe_params_st *pipes, - unsigned int num_pipes, - unsigned int which_pipe); - -double get_total_immediate_flip_bytes( - struct display_mode_lib *mode_lib, - const display_e2e_pipe_params_st *pipes, - unsigned int num_pipes); -double get_total_immediate_flip_bw( - struct display_mode_lib *mode_lib, - const display_e2e_pipe_params_st *pipes, - unsigned int num_pipes); -double get_total_prefetch_bw( - struct display_mode_lib *mode_lib, - const display_e2e_pipe_params_st *pipes, - unsigned int num_pipes); - -unsigned int dml_get_voltage_level( - struct display_mode_lib *mode_lib, - const display_e2e_pipe_params_st *pipes, - unsigned int num_pipes); - -bool Calculate256BBlockSizes( - enum source_format_class SourcePixelFormat, - enum dm_swizzle_mode SurfaceTiling, - unsigned int BytePerPixelY, - unsigned int BytePerPixelC, - unsigned int *BlockHeight256BytesY, - unsigned int *BlockHeight256BytesC, - unsigned int *BlockWidth256BytesY, - unsigned int *BlockWidth256BytesC); - - -struct vba_vars_st { - ip_params_st ip; - soc_bounding_box_st soc; - - unsigned int MaximumMaxVStartupLines; - double cursor_bw[DC__NUM_DPP__MAX]; - double meta_row_bw[DC__NUM_DPP__MAX]; - double dpte_row_bw[DC__NUM_DPP__MAX]; - double qual_row_bw[DC__NUM_DPP__MAX]; - double WritebackDISPCLK; - double PSCL_THROUGHPUT_LUMA[DC__NUM_DPP__MAX]; - double PSCL_THROUGHPUT_CHROMA[DC__NUM_DPP__MAX]; - double DPPCLKUsingSingleDPPLuma; - double DPPCLKUsingSingleDPPChroma; - double DPPCLKUsingSingleDPP[DC__NUM_DPP__MAX]; - double DISPCLKWithRamping; - double DISPCLKWithoutRamping; - double GlobalDPPCLK; - double DISPCLKWithRampingRoundedToDFSGranularity; - double DISPCLKWithoutRampingRoundedToDFSGranularity; - double MaxDispclkRoundedToDFSGranularity; - bool DCCEnabledAnyPlane; - double ReturnBandwidthToDCN; - unsigned int SwathWidthY[DC__NUM_DPP__MAX]; - unsigned int SwathWidthSingleDPPY[DC__NUM_DPP__MAX]; - double BytePerPixelDETY[DC__NUM_DPP__MAX]; - double BytePerPixelDETC[DC__NUM_DPP__MAX]; - double ReadBandwidthPlaneLuma[DC__NUM_DPP__MAX]; - double ReadBandwidthPlaneChroma[DC__NUM_DPP__MAX]; - unsigned int TotalActiveDPP; - unsigned int TotalDCCActiveDPP; - double UrgentRoundTripAndOutOfOrderLatency; - double DisplayPipeLineDeliveryTimeLuma[DC__NUM_DPP__MAX]; // WM - double DisplayPipeLineDeliveryTimeChroma[DC__NUM_DPP__MAX]; // WM - double LinesInDETY[DC__NUM_DPP__MAX]; // WM - double LinesInDETC[DC__NUM_DPP__MAX]; // WM - unsigned int LinesInDETYRoundedDownToSwath[DC__NUM_DPP__MAX]; // WM - unsigned int LinesInDETCRoundedDownToSwath[DC__NUM_DPP__MAX]; // WM - double FullDETBufferingTimeY[DC__NUM_DPP__MAX]; // WM - double FullDETBufferingTimeC[DC__NUM_DPP__MAX]; // WM - double MinFullDETBufferingTime; - double FrameTimeForMinFullDETBufferingTime; - double AverageReadBandwidthGBytePerSecond; - double PartOfBurstThatFitsInROB; - double StutterBurstTime; - //unsigned int NextPrefetchMode; - double VBlankTime; - double SmallestVBlank; - double DCFCLKDeepSleepPerPlane; - double EffectiveDETPlusLBLinesLuma; - double EffectiveDETPlusLBLinesChroma; - double UrgentLatencySupportUsLuma; - double UrgentLatencySupportUsChroma; - double UrgentLatencySupportUs[DC__NUM_DPP__MAX]; - unsigned int DSCFormatFactor; - unsigned int BlockHeight256BytesY[DC__NUM_DPP__MAX]; - unsigned int BlockHeight256BytesC[DC__NUM_DPP__MAX]; - unsigned int BlockWidth256BytesY[DC__NUM_DPP__MAX]; - unsigned int BlockWidth256BytesC[DC__NUM_DPP__MAX]; - double VInitPreFillY[DC__NUM_DPP__MAX]; - double VInitPreFillC[DC__NUM_DPP__MAX]; - unsigned int MaxNumSwathY[DC__NUM_DPP__MAX]; - unsigned int MaxNumSwathC[DC__NUM_DPP__MAX]; - double PrefetchSourceLinesY[DC__NUM_DPP__MAX]; - double PrefetchSourceLinesC[DC__NUM_DPP__MAX]; - double PixelPTEBytesPerRow[DC__NUM_DPP__MAX]; - double MetaRowByte[DC__NUM_DPP__MAX]; - unsigned int dpte_row_height[DC__NUM_DPP__MAX]; - unsigned int dpte_row_height_chroma[DC__NUM_DPP__MAX]; - unsigned int meta_row_height[DC__NUM_DPP__MAX]; - unsigned int meta_row_height_chroma[DC__NUM_DPP__MAX]; - - unsigned int MacroTileWidthY[DC__NUM_DPP__MAX]; - unsigned int MacroTileWidthC[DC__NUM_DPP__MAX]; - unsigned int MaxVStartupLines[DC__NUM_DPP__MAX]; - double WritebackDelay[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - bool PrefetchModeSupported; - bool AllowDRAMClockChangeDuringVBlank[DC__NUM_DPP__MAX]; - bool AllowDRAMSelfRefreshDuringVBlank[DC__NUM_DPP__MAX]; - double RequiredPrefetchPixDataBW[DC__NUM_DPP__MAX]; - double XFCRemoteSurfaceFlipDelay; - double TInitXFill; - double TslvChk; - double SrcActiveDrainRate; - double Tno_bw[DC__NUM_DPP__MAX]; - bool ImmediateFlipSupported; - - double prefetch_vm_bw[DC__NUM_DPP__MAX]; - double prefetch_row_bw[DC__NUM_DPP__MAX]; - bool ImmediateFlipSupportedForPipe[DC__NUM_DPP__MAX]; - unsigned int VStartupLines; - double DisplayPipeLineDeliveryTimeLumaPrefetch[DC__NUM_DPP__MAX]; - double DisplayPipeLineDeliveryTimeChromaPrefetch[DC__NUM_DPP__MAX]; - unsigned int ActiveDPPs; - unsigned int LBLatencyHidingSourceLinesY; - unsigned int LBLatencyHidingSourceLinesC; - double ActiveDRAMClockChangeLatencyMargin[DC__NUM_DPP__MAX]; - double MinActiveDRAMClockChangeMargin; - double XFCSlaveVUpdateOffset[DC__NUM_DPP__MAX]; - double XFCSlaveVupdateWidth[DC__NUM_DPP__MAX]; - double XFCSlaveVReadyOffset[DC__NUM_DPP__MAX]; - double InitFillLevel; - double FinalFillMargin; - double FinalFillLevel; - double RemainingFillLevel; - double TFinalxFill; - - - // - // SOC Bounding Box Parameters - // - double SRExitTime; - double SREnterPlusExitTime; - double UrgentLatency; - double WritebackLatency; - double PercentOfIdealDRAMAndFabricBWReceivedAfterUrgLatency; - double NumberOfChannels; - double DRAMChannelWidth; - double FabricDatapathToDCNDataReturn; - double ReturnBusWidth; - double Downspreading; - double DISPCLKDPPCLKDSCCLKDownSpreading; - double DISPCLKDPPCLKVCOSpeed; - double RoundTripPingLatencyCycles; - double UrgentOutOfOrderReturnPerChannel; - unsigned int VMMPageSize; - double DRAMClockChangeLatency; - double XFCBusTransportTime; - double XFCXBUFLatencyTolerance; - - // - // IP Parameters - // - unsigned int ROBBufferSizeInKByte; - double DETBufferSizeInKByte; - unsigned int DPPOutputBufferPixels; - unsigned int OPPOutputBufferLines; - unsigned int PixelChunkSizeInKByte; - double ReturnBW; - bool VirtualMemoryEnable; - unsigned int MaxPageTableLevels; - unsigned int OverridePageTableLevels; - unsigned int PTEChunkSize; - unsigned int MetaChunkSize; - unsigned int WritebackChunkSize; - bool ODMCapability; - unsigned int NumberOfDSC; - unsigned int LineBufferSize; - unsigned int MaxLineBufferLines; - unsigned int WritebackInterfaceLumaBufferSize; - unsigned int WritebackInterfaceChromaBufferSize; - unsigned int WritebackChromaLineBufferWidth; - double MaxDCHUBToPSCLThroughput; - double MaxPSCLToLBThroughput; - unsigned int PTEBufferSizeInRequests; - double DISPCLKRampingMargin; - unsigned int MaxInterDCNTileRepeaters; - bool XFCSupported; - double XFCSlvChunkSize; - double XFCFillBWOverhead; - double XFCFillConstant; - double XFCTSlvVupdateOffset; - double XFCTSlvVupdateWidth; - double XFCTSlvVreadyOffset; - double DPPCLKDelaySubtotal; - double DPPCLKDelaySCL; - double DPPCLKDelaySCLLBOnly; - double DPPCLKDelayCNVCFormater; - double DPPCLKDelayCNVCCursor; - double DISPCLKDelaySubtotal; - bool ProgressiveToInterlaceUnitInOPP; - unsigned int PDEProcessingBufIn64KBReqs; - - // Pipe/Plane Parameters - int VoltageLevel; - double FabricAndDRAMBandwidth; - double FabricClock; - double DRAMSpeed; - double DISPCLK; - double SOCCLK; - double DCFCLK; - - unsigned int NumberOfActivePlanes; - unsigned int ViewportWidth[DC__NUM_DPP__MAX]; - unsigned int ViewportHeight[DC__NUM_DPP__MAX]; - unsigned int ViewportYStartY[DC__NUM_DPP__MAX]; - unsigned int ViewportYStartC[DC__NUM_DPP__MAX]; - unsigned int PitchY[DC__NUM_DPP__MAX]; - unsigned int PitchC[DC__NUM_DPP__MAX]; - double HRatio[DC__NUM_DPP__MAX]; - double VRatio[DC__NUM_DPP__MAX]; - unsigned int htaps[DC__NUM_DPP__MAX]; - unsigned int vtaps[DC__NUM_DPP__MAX]; - unsigned int HTAPsChroma[DC__NUM_DPP__MAX]; - unsigned int VTAPsChroma[DC__NUM_DPP__MAX]; - unsigned int HTotal[DC__NUM_DPP__MAX]; - unsigned int VTotal[DC__NUM_DPP__MAX]; - unsigned int DPPPerPlane[DC__NUM_DPP__MAX]; - double PixelClock[DC__NUM_DPP__MAX]; - double PixelClockBackEnd[DC__NUM_DPP__MAX]; - double DPPCLK[DC__NUM_DPP__MAX]; - bool DCCEnable[DC__NUM_DPP__MAX]; - unsigned int DCCMetaPitchY[DC__NUM_DPP__MAX]; - enum scan_direction_class SourceScan[DC__NUM_DPP__MAX]; - enum source_format_class SourcePixelFormat[DC__NUM_DPP__MAX]; - bool WritebackEnable[DC__NUM_DPP__MAX]; - double WritebackDestinationWidth[DC__NUM_DPP__MAX]; - double WritebackDestinationHeight[DC__NUM_DPP__MAX]; - double WritebackSourceHeight[DC__NUM_DPP__MAX]; - enum source_format_class WritebackPixelFormat[DC__NUM_DPP__MAX]; - unsigned int WritebackLumaHTaps[DC__NUM_DPP__MAX]; - unsigned int WritebackLumaVTaps[DC__NUM_DPP__MAX]; - unsigned int WritebackChromaHTaps[DC__NUM_DPP__MAX]; - unsigned int WritebackChromaVTaps[DC__NUM_DPP__MAX]; - double WritebackHRatio[DC__NUM_DPP__MAX]; - double WritebackVRatio[DC__NUM_DPP__MAX]; - unsigned int HActive[DC__NUM_DPP__MAX]; - unsigned int VActive[DC__NUM_DPP__MAX]; - bool Interlace[DC__NUM_DPP__MAX]; - enum dm_swizzle_mode SurfaceTiling[DC__NUM_DPP__MAX]; - unsigned int ScalerRecoutWidth[DC__NUM_DPP__MAX]; - bool DynamicMetadataEnable[DC__NUM_DPP__MAX]; - unsigned int DynamicMetadataLinesBeforeActiveRequired[DC__NUM_DPP__MAX]; - unsigned int DynamicMetadataTransmittedBytes[DC__NUM_DPP__MAX]; - double DCCRate[DC__NUM_DPP__MAX]; - bool ODMCombineEnabled[DC__NUM_DPP__MAX]; - double OutputBpp[DC__NUM_DPP__MAX]; - unsigned int NumberOfDSCSlices[DC__NUM_DPP__MAX]; - bool DSCEnabled[DC__NUM_DPP__MAX]; - unsigned int DSCDelay[DC__NUM_DPP__MAX]; - unsigned int DSCInputBitPerComponent[DC__NUM_DPP__MAX]; - enum output_format_class OutputFormat[DC__NUM_DPP__MAX]; - enum output_encoder_class Output[DC__NUM_DPP__MAX]; - unsigned int BlendingAndTiming[DC__NUM_DPP__MAX]; - bool SynchronizedVBlank; - unsigned int NumberOfCursors[DC__NUM_DPP__MAX]; - unsigned int CursorWidth[DC__NUM_DPP__MAX][DC__NUM_CURSOR__MAX]; - unsigned int CursorBPP[DC__NUM_DPP__MAX][DC__NUM_CURSOR__MAX]; - bool XFCEnabled[DC__NUM_DPP__MAX]; - bool ScalerEnabled[DC__NUM_DPP__MAX]; - - // Intermediates/Informational - bool ImmediateFlipSupport; - unsigned int SwathHeightY[DC__NUM_DPP__MAX]; - unsigned int SwathHeightC[DC__NUM_DPP__MAX]; - unsigned int DETBufferSizeY[DC__NUM_DPP__MAX]; - unsigned int DETBufferSizeC[DC__NUM_DPP__MAX]; - unsigned int LBBitPerPixel[DC__NUM_DPP__MAX]; - double LastPixelOfLineExtraWatermark; - double TotalDataReadBandwidth; - unsigned int TotalActiveWriteback; - unsigned int EffectiveLBLatencyHidingSourceLinesLuma; - unsigned int EffectiveLBLatencyHidingSourceLinesChroma; - double BandwidthAvailableForImmediateFlip; - unsigned int PrefetchMode; - bool IgnoreViewportPositioning; - double PrefetchBandwidth[DC__NUM_DPP__MAX]; - bool ErrorResult[DC__NUM_DPP__MAX]; - double PDEAndMetaPTEBytesFrame[DC__NUM_DPP__MAX]; - - // - // Calculated dml_ml->vba.Outputs - // - double DCFClkDeepSleep; - double UrgentWatermark; - double UrgentExtraLatency; - double MemoryTripWatermark; - double WritebackUrgentWatermark; - double StutterExitWatermark; - double StutterEnterPlusExitWatermark; - double DRAMClockChangeWatermark; - double WritebackDRAMClockChangeWatermark; - double StutterEfficiency; - double StutterEfficiencyNotIncludingVBlank; - double MinUrgentLatencySupportUs; - double NonUrgentLatencyTolerance; - double MinActiveDRAMClockChangeLatencySupported; - enum clock_change_support DRAMClockChangeSupport; - - // These are the clocks calcuated by the library but they are not actually - // used explicitly. They are fetched by tests and then possibly used. The - // ultimate values to use are the ones specified by the parameters to DML - double DISPCLK_calculated; - double DSCCLK_calculated[DC__NUM_DPP__MAX]; - double DPPCLK_calculated[DC__NUM_DPP__MAX]; - - unsigned int VStartup[DC__NUM_DPP__MAX]; - unsigned int VUpdateOffsetPix[DC__NUM_DPP__MAX]; - unsigned int VUpdateWidthPix[DC__NUM_DPP__MAX]; - unsigned int VReadyOffsetPix[DC__NUM_DPP__MAX]; - unsigned int VStartupRequiredWhenNotEnoughTimeForDynamicMetadata; - - double ImmediateFlipBW; - unsigned int TotImmediateFlipBytes; - double TCalc; - double MinTTUVBlank[DC__NUM_DPP__MAX]; - double VRatioPrefetchY[DC__NUM_DPP__MAX]; - double VRatioPrefetchC[DC__NUM_DPP__MAX]; - double DSTXAfterScaler[DC__NUM_DPP__MAX]; - double DSTYAfterScaler[DC__NUM_DPP__MAX]; - - double DestinationLinesToRequestVMInVBlank[DC__NUM_DPP__MAX]; - double DestinationLinesToRequestRowInVBlank[DC__NUM_DPP__MAX]; - double DestinationLinesForPrefetch[DC__NUM_DPP__MAX]; - double DestinationLinesToRequestRowInImmediateFlip[DC__NUM_DPP__MAX]; - double DestinationLinesToRequestVMInImmediateFlip[DC__NUM_DPP__MAX]; - - double XFCTransferDelay[DC__NUM_DPP__MAX]; - double XFCPrechargeDelay[DC__NUM_DPP__MAX]; - double XFCRemoteSurfaceFlipLatency[DC__NUM_DPP__MAX]; - double XFCPrefetchMargin[DC__NUM_DPP__MAX]; - - display_e2e_pipe_params_st cache_pipes[DC__NUM_DPP__MAX]; - unsigned int cache_num_pipes; - unsigned int pipe_plane[DC__NUM_DPP__MAX]; - - /* vba mode support */ - /*inputs*/ - bool SupportGFX7CompatibleTilingIn32bppAnd64bpp; - double MaxHSCLRatio; - double MaxVSCLRatio; - unsigned int MaxNumWriteback; - bool WritebackLumaAndChromaScalingSupported; - bool Cursor64BppSupport; - double DCFCLKPerState[DC__VOLTAGE_STATES + 1]; - double FabricClockPerState[DC__VOLTAGE_STATES + 1]; - double SOCCLKPerState[DC__VOLTAGE_STATES + 1]; - double PHYCLKPerState[DC__VOLTAGE_STATES + 1]; - double MaxDppclk[DC__VOLTAGE_STATES + 1]; - double MaxDSCCLK[DC__VOLTAGE_STATES + 1]; - double DRAMSpeedPerState[DC__VOLTAGE_STATES + 1]; - double MaxDispclk[DC__VOLTAGE_STATES + 1]; - - /*outputs*/ - bool ScaleRatioAndTapsSupport; - bool SourceFormatPixelAndScanSupport; - unsigned int SwathWidthYSingleDPP[DC__NUM_DPP__MAX]; - double BytePerPixelInDETY[DC__NUM_DPP__MAX]; - double BytePerPixelInDETC[DC__NUM_DPP__MAX]; - double TotalReadBandwidthConsumedGBytePerSecond; - double ReadBandwidth[DC__NUM_DPP__MAX]; - double TotalWriteBandwidthConsumedGBytePerSecond; - double WriteBandwidth[DC__NUM_DPP__MAX]; - double TotalBandwidthConsumedGBytePerSecond; - bool DCCEnabledInAnyPlane; - bool WritebackLatencySupport; - bool WritebackModeSupport; - bool Writeback10bpc420Supported; - bool BandwidthSupport[DC__VOLTAGE_STATES + 1]; - unsigned int TotalNumberOfActiveWriteback; - double CriticalPoint; - double ReturnBWToDCNPerState; - double FabricAndDRAMBandwidthPerState[DC__VOLTAGE_STATES + 1]; - double ReturnBWPerState[DC__VOLTAGE_STATES + 1]; - double UrgentRoundTripAndOutOfOrderLatencyPerState[DC__VOLTAGE_STATES + 1]; - bool ODMCombineEnablePerState[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - bool PTEBufferSizeNotExceededY[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - bool PTEBufferSizeNotExceededC[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - bool PrefetchSupported[DC__VOLTAGE_STATES + 1]; - bool VRatioInPrefetchSupported[DC__VOLTAGE_STATES + 1]; - bool DISPCLK_DPPCLK_Support[DC__VOLTAGE_STATES + 1]; - bool TotalAvailablePipesSupport[DC__VOLTAGE_STATES + 1]; - bool UrgentLatencySupport[DC__VOLTAGE_STATES + 1]; - bool ModeSupport[DC__VOLTAGE_STATES + 1]; - bool DIOSupport[DC__VOLTAGE_STATES + 1]; - bool NotEnoughDSCUnits[DC__VOLTAGE_STATES + 1]; - bool DSCCLKRequiredMoreThanSupported[DC__VOLTAGE_STATES + 1]; - bool ROBSupport[DC__VOLTAGE_STATES + 1]; - bool PTEBufferSizeNotExceeded[DC__VOLTAGE_STATES + 1]; - bool RequiresDSC[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - bool IsErrorResult[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - bool ViewportSizeSupport[DC__VOLTAGE_STATES + 1]; - bool prefetch_vm_bw_valid; - bool prefetch_row_bw_valid; - bool NumberOfOTGSupport; - bool NonsupportedDSCInputBPC; - bool WritebackScaleRatioAndTapsSupport; - bool CursorSupport; - bool PitchSupport; - - double WritebackLineBufferLumaBufferSize; - double WritebackLineBufferChromaBufferSize; - double WritebackMinHSCLRatio; - double WritebackMinVSCLRatio; - double WritebackMaxHSCLRatio; - double WritebackMaxVSCLRatio; - double WritebackMaxHSCLTaps; - double WritebackMaxVSCLTaps; - unsigned int MaxNumDPP; - unsigned int MaxNumOTG; - double CursorBufferSize; - double CursorChunkSize; - unsigned int Mode; - unsigned int NoOfDPP[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - double OutputLinkDPLanes[DC__NUM_DPP__MAX]; - double SwathWidthYPerState[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - double SwathHeightYPerState[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - double SwathHeightCPerState[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - double UrgentLatencySupportUsPerState[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - double VRatioPreY[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - double VRatioPreC[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - double RequiredPrefetchPixelDataBW[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - double RequiredDPPCLK[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - double RequiredDISPCLK[DC__VOLTAGE_STATES + 1]; - double TotalNumberOfActiveDPP[DC__VOLTAGE_STATES + 1]; - double TotalNumberOfDCCActiveDPP[DC__VOLTAGE_STATES + 1]; - double PrefetchBW[DC__NUM_DPP__MAX]; - double PDEAndMetaPTEBytesPerFrame[DC__NUM_DPP__MAX]; - double MetaRowBytes[DC__NUM_DPP__MAX]; - double DPTEBytesPerRow[DC__NUM_DPP__MAX]; - double PrefetchLinesY[DC__NUM_DPP__MAX]; - double PrefetchLinesC[DC__NUM_DPP__MAX]; - unsigned int MaxNumSwY[DC__NUM_DPP__MAX]; - unsigned int MaxNumSwC[DC__NUM_DPP__MAX]; - double PrefillY[DC__NUM_DPP__MAX]; - double PrefillC[DC__NUM_DPP__MAX]; - double LineTimesForPrefetch[DC__NUM_DPP__MAX]; - double LinesForMetaPTE[DC__NUM_DPP__MAX]; - double LinesForMetaAndDPTERow[DC__NUM_DPP__MAX]; - double MinDPPCLKUsingSingleDPP[DC__NUM_DPP__MAX]; - double RequiresFEC[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - unsigned int OutputBppPerState[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - double DSCDelayPerState[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; - unsigned int Read256BlockHeightY[DC__NUM_DPP__MAX]; - unsigned int Read256BlockWidthY[DC__NUM_DPP__MAX]; - unsigned int Read256BlockHeightC[DC__NUM_DPP__MAX]; - unsigned int Read256BlockWidthC[DC__NUM_DPP__MAX]; - unsigned int ImmediateFlipBytes[DC__NUM_DPP__MAX]; - double MaxSwathHeightY[DC__NUM_DPP__MAX]; - double MaxSwathHeightC[DC__NUM_DPP__MAX]; - double MinSwathHeightY[DC__NUM_DPP__MAX]; - double MinSwathHeightC[DC__NUM_DPP__MAX]; - double PSCL_FACTOR[DC__NUM_DPP__MAX]; - double PSCL_FACTOR_CHROMA[DC__NUM_DPP__MAX]; - double MaximumVStartup[DC__NUM_DPP__MAX]; - double AlignedDCCMetaPitch[DC__NUM_DPP__MAX]; - double AlignedYPitch[DC__NUM_DPP__MAX]; - double AlignedCPitch[DC__NUM_DPP__MAX]; - double MaximumSwathWidth[DC__NUM_DPP__MAX]; - double final_flip_bw[DC__NUM_DPP__MAX]; - double ImmediateFlipSupportedForState[DC__VOLTAGE_STATES + 1]; - - double WritebackLumaVExtra; - double WritebackChromaVExtra; - double WritebackRequiredDISPCLK; - double MaximumSwathWidthSupport; - double MaximumSwathWidthInDETBuffer; - double MaximumSwathWidthInLineBuffer; - double MaxDispclkRoundedDownToDFSGranularity; - double MaxDppclkRoundedDownToDFSGranularity; - double PlaneRequiredDISPCLKWithoutODMCombine; - double PlaneRequiredDISPCLK; - double TotalNumberOfActiveOTG; - double FECOverhead; - double EffectiveFECOverhead; - unsigned int Outbpp; - unsigned int OutbppDSC; - double TotalDSCUnitsRequired; - double bpp; - unsigned int slices; - double SwathWidthGranularityY; - double RoundedUpMaxSwathSizeBytesY; - double SwathWidthGranularityC; - double RoundedUpMaxSwathSizeBytesC; - double LinesInDETLuma; - double LinesInDETChroma; - double EffectiveDETLBLinesLuma; - double EffectiveDETLBLinesChroma; - double ProjectedDCFCLKDeepSleep; - double PDEAndMetaPTEBytesPerFrameY; - double PDEAndMetaPTEBytesPerFrameC; - unsigned int MetaRowBytesY; - unsigned int MetaRowBytesC; - unsigned int DPTEBytesPerRowC; - unsigned int DPTEBytesPerRowY; - double ExtraLatency; - double TimeCalc; - double TWait; - double MaximumReadBandwidthWithPrefetch; - double total_dcn_read_bw_with_flip; -}; - -#endif /* _DML2_DISPLAY_MODE_VBA_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_calc.c b/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_calc.c deleted file mode 100644 index 325dd2b757d6..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_calc.c +++ /dev/null @@ -1,1772 +0,0 @@ -/* - * Copyright 2017 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "display_mode_lib.h" -#include "display_mode_vba.h" -#include "display_rq_dlg_calc.h" - -/* - * NOTE: - * This file is gcc-parseable HW gospel, coming straight from HW engineers. - * - * It doesn't adhere to Linux kernel style and sometimes will do things in odd - * ways. Unless there is something clearly wrong with it the code should - * remain as-is as it provides us with a guarantee from HW that it is correct. - */ - -static void calculate_ttu_cursor(struct display_mode_lib *mode_lib, - double *refcyc_per_req_delivery_pre_cur, - double *refcyc_per_req_delivery_cur, - double refclk_freq_in_mhz, - double ref_freq_to_pix_freq, - double hscale_pixel_rate_l, - double hscl_ratio, - double vratio_pre_l, - double vratio_l, - unsigned int cur_width, - enum cursor_bpp cur_bpp); - -#include "dml_inline_defs.h" - -static unsigned int get_bytes_per_element(enum source_format_class source_format, bool is_chroma) -{ - unsigned int ret_val = 0; - - if (source_format == dm_444_16) { - if (!is_chroma) - ret_val = 2; - } else if (source_format == dm_444_32) { - if (!is_chroma) - ret_val = 4; - } else if (source_format == dm_444_64) { - if (!is_chroma) - ret_val = 8; - } else if (source_format == dm_420_8) { - if (is_chroma) - ret_val = 2; - else - ret_val = 1; - } else if (source_format == dm_420_10) { - if (is_chroma) - ret_val = 4; - else - ret_val = 2; - } else if (source_format == dm_444_8) { - ret_val = 1; - } - return ret_val; -} - -static bool is_dual_plane(enum source_format_class source_format) -{ - bool ret_val = 0; - - if ((source_format == dm_420_8) || (source_format == dm_420_10)) - ret_val = 1; - - return ret_val; -} - -static double get_refcyc_per_delivery(struct display_mode_lib *mode_lib, - double refclk_freq_in_mhz, - double pclk_freq_in_mhz, - bool odm_combine, - unsigned int recout_width, - unsigned int hactive, - double vratio, - double hscale_pixel_rate, - unsigned int delivery_width, - unsigned int req_per_swath_ub) -{ - double refcyc_per_delivery = 0.0; - - if (vratio <= 1.0) { - if (odm_combine) - refcyc_per_delivery = (double) refclk_freq_in_mhz - * dml_min((double) recout_width, (double) hactive / 2.0) - / pclk_freq_in_mhz / (double) req_per_swath_ub; - else - refcyc_per_delivery = (double) refclk_freq_in_mhz * (double) recout_width - / pclk_freq_in_mhz / (double) req_per_swath_ub; - } else { - refcyc_per_delivery = (double) refclk_freq_in_mhz * (double) delivery_width - / (double) hscale_pixel_rate / (double) req_per_swath_ub; - } - - dml_print("DML_DLG: %s: refclk_freq_in_mhz = %3.2f\n", __func__, refclk_freq_in_mhz); - dml_print("DML_DLG: %s: pclk_freq_in_mhz = %3.2f\n", __func__, pclk_freq_in_mhz); - dml_print("DML_DLG: %s: recout_width = %d\n", __func__, recout_width); - dml_print("DML_DLG: %s: vratio = %3.2f\n", __func__, vratio); - dml_print("DML_DLG: %s: req_per_swath_ub = %d\n", __func__, req_per_swath_ub); - dml_print("DML_DLG: %s: refcyc_per_delivery= %3.2f\n", __func__, refcyc_per_delivery); - - return refcyc_per_delivery; - -} - -static unsigned int get_blk_size_bytes(const enum source_macro_tile_size tile_size) -{ - if (tile_size == dm_256k_tile) - return (256 * 1024); - else if (tile_size == dm_64k_tile) - return (64 * 1024); - else - return (4 * 1024); -} - -static void extract_rq_sizing_regs(struct display_mode_lib *mode_lib, - display_data_rq_regs_st *rq_regs, - const display_data_rq_sizing_params_st rq_sizing) -{ - dml_print("DML_DLG: %s: rq_sizing param\n", __func__); - print__data_rq_sizing_params_st(mode_lib, rq_sizing); - - rq_regs->chunk_size = dml_log2(rq_sizing.chunk_bytes) - 10; - - if (rq_sizing.min_chunk_bytes == 0) - rq_regs->min_chunk_size = 0; - else - rq_regs->min_chunk_size = dml_log2(rq_sizing.min_chunk_bytes) - 8 + 1; - - rq_regs->meta_chunk_size = dml_log2(rq_sizing.meta_chunk_bytes) - 10; - if (rq_sizing.min_meta_chunk_bytes == 0) - rq_regs->min_meta_chunk_size = 0; - else - rq_regs->min_meta_chunk_size = dml_log2(rq_sizing.min_meta_chunk_bytes) - 6 + 1; - - rq_regs->dpte_group_size = dml_log2(rq_sizing.dpte_group_bytes) - 6; - rq_regs->mpte_group_size = dml_log2(rq_sizing.mpte_group_bytes) - 6; -} - -static void extract_rq_regs(struct display_mode_lib *mode_lib, - display_rq_regs_st *rq_regs, - const display_rq_params_st rq_param) -{ - unsigned int detile_buf_size_in_bytes = mode_lib->ip.det_buffer_size_kbytes * 1024; - unsigned int detile_buf_plane1_addr = 0; - - extract_rq_sizing_regs(mode_lib, &(rq_regs->rq_regs_l), rq_param.sizing.rq_l); - - rq_regs->rq_regs_l.pte_row_height_linear = dml_floor(dml_log2(rq_param.dlg.rq_l.dpte_row_height), - 1) - 3; - - if (rq_param.yuv420) { - extract_rq_sizing_regs(mode_lib, &(rq_regs->rq_regs_c), rq_param.sizing.rq_c); - rq_regs->rq_regs_c.pte_row_height_linear = dml_floor(dml_log2(rq_param.dlg.rq_c.dpte_row_height), - 1) - 3; - } - - rq_regs->rq_regs_l.swath_height = dml_log2(rq_param.dlg.rq_l.swath_height); - rq_regs->rq_regs_c.swath_height = dml_log2(rq_param.dlg.rq_c.swath_height); - - // FIXME: take the max between luma, chroma chunk size? - // okay for now, as we are setting chunk_bytes to 8kb anyways - if (rq_param.sizing.rq_l.chunk_bytes >= 32 * 1024) { //32kb - rq_regs->drq_expansion_mode = 0; - } else { - rq_regs->drq_expansion_mode = 2; - } - rq_regs->prq_expansion_mode = 1; - rq_regs->mrq_expansion_mode = 1; - rq_regs->crq_expansion_mode = 1; - - if (rq_param.yuv420) { - if ((double) rq_param.misc.rq_l.stored_swath_bytes - / (double) rq_param.misc.rq_c.stored_swath_bytes <= 1.5) { - detile_buf_plane1_addr = (detile_buf_size_in_bytes / 2.0 / 64.0); // half to chroma - } else { - detile_buf_plane1_addr = dml_round_to_multiple((unsigned int) ((2.0 * detile_buf_size_in_bytes) / 3.0), - 256, - 0) / 64.0; // 2/3 to chroma - } - } - rq_regs->plane1_base_address = detile_buf_plane1_addr; -} - -static void handle_det_buf_split(struct display_mode_lib *mode_lib, - display_rq_params_st *rq_param, - const display_pipe_source_params_st pipe_src_param) -{ - unsigned int total_swath_bytes = 0; - unsigned int swath_bytes_l = 0; - unsigned int swath_bytes_c = 0; - unsigned int full_swath_bytes_packed_l = 0; - unsigned int full_swath_bytes_packed_c = 0; - bool req128_l = 0; - bool req128_c = 0; - bool surf_linear = (pipe_src_param.sw_mode == dm_sw_linear); - bool surf_vert = (pipe_src_param.source_scan == dm_vert); - unsigned int log2_swath_height_l = 0; - unsigned int log2_swath_height_c = 0; - unsigned int detile_buf_size_in_bytes = mode_lib->ip.det_buffer_size_kbytes * 1024; - - full_swath_bytes_packed_l = rq_param->misc.rq_l.full_swath_bytes; - full_swath_bytes_packed_c = rq_param->misc.rq_c.full_swath_bytes; - - if (rq_param->yuv420_10bpc) { - full_swath_bytes_packed_l = dml_round_to_multiple(rq_param->misc.rq_l.full_swath_bytes * 2 / 3, - 256, - 1) + 256; - full_swath_bytes_packed_c = dml_round_to_multiple(rq_param->misc.rq_c.full_swath_bytes * 2 / 3, - 256, - 1) + 256; - } - - if (rq_param->yuv420) { - total_swath_bytes = 2 * full_swath_bytes_packed_l + 2 * full_swath_bytes_packed_c; - - if (total_swath_bytes <= detile_buf_size_in_bytes) { //full 256b request - req128_l = 0; - req128_c = 0; - swath_bytes_l = full_swath_bytes_packed_l; - swath_bytes_c = full_swath_bytes_packed_c; - } else { //128b request (for luma only for yuv420 8bpc) - req128_l = 1; - req128_c = 0; - swath_bytes_l = full_swath_bytes_packed_l / 2; - swath_bytes_c = full_swath_bytes_packed_c; - } - // Note: assumption, the config that pass in will fit into - // the detiled buffer. - } else { - total_swath_bytes = 2 * full_swath_bytes_packed_l; - - if (total_swath_bytes <= detile_buf_size_in_bytes) - req128_l = 0; - else - req128_l = 1; - - swath_bytes_l = total_swath_bytes; - swath_bytes_c = 0; - } - rq_param->misc.rq_l.stored_swath_bytes = swath_bytes_l; - rq_param->misc.rq_c.stored_swath_bytes = swath_bytes_c; - - if (surf_linear) { - log2_swath_height_l = 0; - log2_swath_height_c = 0; - } else if (!surf_vert) { - log2_swath_height_l = dml_log2(rq_param->misc.rq_l.blk256_height) - req128_l; - log2_swath_height_c = dml_log2(rq_param->misc.rq_c.blk256_height) - req128_c; - } else { - log2_swath_height_l = dml_log2(rq_param->misc.rq_l.blk256_width) - req128_l; - log2_swath_height_c = dml_log2(rq_param->misc.rq_c.blk256_width) - req128_c; - } - rq_param->dlg.rq_l.swath_height = 1 << log2_swath_height_l; - rq_param->dlg.rq_c.swath_height = 1 << log2_swath_height_c; - - dml_print("DML_DLG: %s: req128_l = %0d\n", __func__, req128_l); - dml_print("DML_DLG: %s: req128_c = %0d\n", __func__, req128_c); - dml_print("DML_DLG: %s: full_swath_bytes_packed_l = %0d\n", - __func__, - full_swath_bytes_packed_l); - dml_print("DML_DLG: %s: full_swath_bytes_packed_c = %0d\n", - __func__, - full_swath_bytes_packed_c); -} - -static void get_meta_and_pte_attr(struct display_mode_lib *mode_lib, - display_data_rq_dlg_params_st *rq_dlg_param, - display_data_rq_misc_params_st *rq_misc_param, - display_data_rq_sizing_params_st *rq_sizing_param, - unsigned int vp_width, - unsigned int vp_height, - unsigned int data_pitch, - unsigned int meta_pitch, - unsigned int source_format, - unsigned int tiling, - unsigned int macro_tile_size, - unsigned int source_scan, - unsigned int is_chroma) -{ - bool surf_linear = (tiling == dm_sw_linear); - bool surf_vert = (source_scan == dm_vert); - - unsigned int bytes_per_element; - unsigned int bytes_per_element_y = get_bytes_per_element((enum source_format_class)(source_format), - false); - unsigned int bytes_per_element_c = get_bytes_per_element((enum source_format_class)(source_format), - true); - - unsigned int blk256_width = 0; - unsigned int blk256_height = 0; - - unsigned int blk256_width_y = 0; - unsigned int blk256_height_y = 0; - unsigned int blk256_width_c = 0; - unsigned int blk256_height_c = 0; - unsigned int log2_bytes_per_element; - unsigned int log2_blk256_width; - unsigned int log2_blk256_height; - unsigned int blk_bytes; - unsigned int log2_blk_bytes; - unsigned int log2_blk_height; - unsigned int log2_blk_width; - unsigned int log2_meta_req_bytes; - unsigned int log2_meta_req_height; - unsigned int log2_meta_req_width; - unsigned int meta_req_width; - unsigned int meta_req_height; - unsigned int log2_meta_row_height; - unsigned int meta_row_width_ub; - unsigned int log2_meta_chunk_bytes; - unsigned int log2_meta_chunk_height; - - //full sized meta chunk width in unit of data elements - unsigned int log2_meta_chunk_width; - unsigned int log2_min_meta_chunk_bytes; - unsigned int min_meta_chunk_width; - unsigned int meta_chunk_width; - unsigned int meta_chunk_per_row_int; - unsigned int meta_row_remainder; - unsigned int meta_chunk_threshold; - unsigned int meta_blk_bytes; - unsigned int meta_blk_height; - unsigned int meta_blk_width; - unsigned int meta_surface_bytes; - unsigned int vmpg_bytes; - unsigned int meta_pte_req_per_frame_ub; - unsigned int meta_pte_bytes_per_frame_ub; - const unsigned int log2_vmpg_bytes = dml_log2(mode_lib->soc.vmm_page_size_bytes); - const unsigned int dpte_buf_in_pte_reqs = mode_lib->ip.dpte_buffer_size_in_pte_reqs; - const unsigned int pde_proc_buffer_size_64k_reqs = - mode_lib->ip.pde_proc_buffer_size_64k_reqs; - - unsigned int log2_vmpg_height = 0; - unsigned int log2_vmpg_width = 0; - unsigned int log2_dpte_req_height_ptes = 0; - unsigned int log2_dpte_req_height = 0; - unsigned int log2_dpte_req_width = 0; - unsigned int log2_dpte_row_height_linear = 0; - unsigned int log2_dpte_row_height = 0; - unsigned int log2_dpte_group_width = 0; - unsigned int dpte_row_width_ub = 0; - unsigned int dpte_req_height = 0; - unsigned int dpte_req_width = 0; - unsigned int dpte_group_width = 0; - unsigned int log2_dpte_group_bytes = 0; - unsigned int log2_dpte_group_length = 0; - unsigned int pde_buf_entries; - bool yuv420 = (source_format == dm_420_8 || source_format == dm_420_10); - - Calculate256BBlockSizes((enum source_format_class)(source_format), - (enum dm_swizzle_mode)(tiling), - bytes_per_element_y, - bytes_per_element_c, - &blk256_height_y, - &blk256_height_c, - &blk256_width_y, - &blk256_width_c); - - if (!is_chroma) { - blk256_width = blk256_width_y; - blk256_height = blk256_height_y; - bytes_per_element = bytes_per_element_y; - } else { - blk256_width = blk256_width_c; - blk256_height = blk256_height_c; - bytes_per_element = bytes_per_element_c; - } - - log2_bytes_per_element = dml_log2(bytes_per_element); - - dml_print("DML_DLG: %s: surf_linear = %d\n", __func__, surf_linear); - dml_print("DML_DLG: %s: surf_vert = %d\n", __func__, surf_vert); - dml_print("DML_DLG: %s: blk256_width = %d\n", __func__, blk256_width); - dml_print("DML_DLG: %s: blk256_height = %d\n", __func__, blk256_height); - - log2_blk256_width = dml_log2((double) blk256_width); - log2_blk256_height = dml_log2((double) blk256_height); - blk_bytes = surf_linear ? - 256 : get_blk_size_bytes((enum source_macro_tile_size) macro_tile_size); - log2_blk_bytes = dml_log2((double) blk_bytes); - log2_blk_height = 0; - log2_blk_width = 0; - - // remember log rule - // "+" in log is multiply - // "-" in log is divide - // "/2" is like square root - // blk is vertical biased - if (tiling != dm_sw_linear) - log2_blk_height = log2_blk256_height - + dml_ceil((double) (log2_blk_bytes - 8) / 2.0, 1); - else - log2_blk_height = 0; // blk height of 1 - - log2_blk_width = log2_blk_bytes - log2_bytes_per_element - log2_blk_height; - - if (!surf_vert) { - rq_dlg_param->swath_width_ub = dml_round_to_multiple(vp_width - 1, blk256_width, 1) - + blk256_width; - rq_dlg_param->req_per_swath_ub = rq_dlg_param->swath_width_ub >> log2_blk256_width; - } else { - rq_dlg_param->swath_width_ub = dml_round_to_multiple(vp_height - 1, blk256_height, 1) - + blk256_height; - rq_dlg_param->req_per_swath_ub = rq_dlg_param->swath_width_ub >> log2_blk256_height; - } - - if (!surf_vert) - rq_misc_param->full_swath_bytes = rq_dlg_param->swath_width_ub * blk256_height - * bytes_per_element; - else - rq_misc_param->full_swath_bytes = rq_dlg_param->swath_width_ub * blk256_width - * bytes_per_element; - - rq_misc_param->blk256_height = blk256_height; - rq_misc_param->blk256_width = blk256_width; - - // ------- - // meta - // ------- - log2_meta_req_bytes = 6; // meta request is 64b and is 8x8byte meta element - - // each 64b meta request for dcn is 8x8 meta elements and - // a meta element covers one 256b block of the the data surface. - log2_meta_req_height = log2_blk256_height + 3; // meta req is 8x8 byte, each byte represent 1 blk256 - log2_meta_req_width = log2_meta_req_bytes + 8 - log2_bytes_per_element - - log2_meta_req_height; - meta_req_width = 1 << log2_meta_req_width; - meta_req_height = 1 << log2_meta_req_height; - log2_meta_row_height = 0; - meta_row_width_ub = 0; - - // the dimensions of a meta row are meta_row_width x meta_row_height in elements. - // calculate upper bound of the meta_row_width - if (!surf_vert) { - log2_meta_row_height = log2_meta_req_height; - meta_row_width_ub = dml_round_to_multiple(vp_width - 1, meta_req_width, 1) - + meta_req_width; - rq_dlg_param->meta_req_per_row_ub = meta_row_width_ub / meta_req_width; - } else { - log2_meta_row_height = log2_meta_req_width; - meta_row_width_ub = dml_round_to_multiple(vp_height - 1, meta_req_height, 1) - + meta_req_height; - rq_dlg_param->meta_req_per_row_ub = meta_row_width_ub / meta_req_height; - } - rq_dlg_param->meta_bytes_per_row_ub = rq_dlg_param->meta_req_per_row_ub * 64; - - rq_dlg_param->meta_row_height = 1 << log2_meta_row_height; - - log2_meta_chunk_bytes = dml_log2(rq_sizing_param->meta_chunk_bytes); - log2_meta_chunk_height = log2_meta_row_height; - - //full sized meta chunk width in unit of data elements - log2_meta_chunk_width = log2_meta_chunk_bytes + 8 - log2_bytes_per_element - - log2_meta_chunk_height; - log2_min_meta_chunk_bytes = dml_log2(rq_sizing_param->min_meta_chunk_bytes); - min_meta_chunk_width = 1 - << (log2_min_meta_chunk_bytes + 8 - log2_bytes_per_element - - log2_meta_chunk_height); - meta_chunk_width = 1 << log2_meta_chunk_width; - meta_chunk_per_row_int = (unsigned int) (meta_row_width_ub / meta_chunk_width); - meta_row_remainder = meta_row_width_ub % meta_chunk_width; - meta_chunk_threshold = 0; - meta_blk_bytes = 4096; - meta_blk_height = blk256_height * 64; - meta_blk_width = meta_blk_bytes * 256 / bytes_per_element / meta_blk_height; - meta_surface_bytes = meta_pitch - * (dml_round_to_multiple(vp_height - 1, meta_blk_height, 1) + meta_blk_height) - * bytes_per_element / 256; - vmpg_bytes = mode_lib->soc.vmm_page_size_bytes; - meta_pte_req_per_frame_ub = (dml_round_to_multiple(meta_surface_bytes - vmpg_bytes, - 8 * vmpg_bytes, - 1) + 8 * vmpg_bytes) / (8 * vmpg_bytes); - meta_pte_bytes_per_frame_ub = meta_pte_req_per_frame_ub * 64; //64B mpte request - rq_dlg_param->meta_pte_bytes_per_frame_ub = meta_pte_bytes_per_frame_ub; - - dml_print("DML_DLG: %s: meta_blk_height = %d\n", __func__, meta_blk_height); - dml_print("DML_DLG: %s: meta_blk_width = %d\n", __func__, meta_blk_width); - dml_print("DML_DLG: %s: meta_surface_bytes = %d\n", __func__, meta_surface_bytes); - dml_print("DML_DLG: %s: meta_pte_req_per_frame_ub = %d\n", - __func__, - meta_pte_req_per_frame_ub); - dml_print("DML_DLG: %s: meta_pte_bytes_per_frame_ub = %d\n", - __func__, - meta_pte_bytes_per_frame_ub); - - if (!surf_vert) - meta_chunk_threshold = 2 * min_meta_chunk_width - meta_req_width; - else - meta_chunk_threshold = 2 * min_meta_chunk_width - meta_req_height; - - if (meta_row_remainder <= meta_chunk_threshold) - rq_dlg_param->meta_chunks_per_row_ub = meta_chunk_per_row_int + 1; - else - rq_dlg_param->meta_chunks_per_row_ub = meta_chunk_per_row_int + 2; - - // ------ - // dpte - // ------ - if (surf_linear) { - log2_vmpg_height = 0; // one line high - } else { - log2_vmpg_height = (log2_vmpg_bytes - 8) / 2 + log2_blk256_height; - } - log2_vmpg_width = log2_vmpg_bytes - log2_bytes_per_element - log2_vmpg_height; - - // only 3 possible shapes for dpte request in dimensions of ptes: 8x1, 4x2, 2x4. - if (surf_linear) { //one 64B PTE request returns 8 PTEs - log2_dpte_req_height_ptes = 0; - log2_dpte_req_width = log2_vmpg_width + 3; - log2_dpte_req_height = 0; - } else if (log2_blk_bytes == 12) { //4KB tile means 4kB page size - //one 64B req gives 8x1 PTEs for 4KB tile - log2_dpte_req_height_ptes = 0; - log2_dpte_req_width = log2_blk_width + 3; - log2_dpte_req_height = log2_blk_height + 0; - } else if ((log2_blk_bytes >= 16) && (log2_vmpg_bytes == 12)) { // tile block >= 64KB - //two 64B reqs of 2x4 PTEs give 16 PTEs to cover 64KB - log2_dpte_req_height_ptes = 4; - log2_dpte_req_width = log2_blk256_width + 4; // log2_64KB_width - log2_dpte_req_height = log2_blk256_height + 4; // log2_64KB_height - } else { //64KB page size and must 64KB tile block - //one 64B req gives 8x1 PTEs for 64KB tile - log2_dpte_req_height_ptes = 0; - log2_dpte_req_width = log2_blk_width + 3; - log2_dpte_req_height = log2_blk_height + 0; - } - - // The dpte request dimensions in data elements is dpte_req_width x dpte_req_height - // log2_vmpg_width is how much 1 pte represent, now calculating how much a 64b pte req represent - // That depends on the pte shape (i.e. 8x1, 4x2, 2x4) - //log2_dpte_req_height = log2_vmpg_height + log2_dpte_req_height_ptes; - //log2_dpte_req_width = log2_vmpg_width + log2_dpte_req_width_ptes; - dpte_req_height = 1 << log2_dpte_req_height; - dpte_req_width = 1 << log2_dpte_req_width; - - // calculate pitch dpte row buffer can hold - // round the result down to a power of two. - pde_buf_entries = yuv420 ? (pde_proc_buffer_size_64k_reqs >> 1) : pde_proc_buffer_size_64k_reqs; - if (surf_linear) { - unsigned int dpte_row_height; - - log2_dpte_row_height_linear = dml_floor(dml_log2(dml_min(64 * 1024 * pde_buf_entries - / bytes_per_element, - dpte_buf_in_pte_reqs - * dpte_req_width) - / data_pitch), - 1); - - ASSERT(log2_dpte_row_height_linear >= 3); - - if (log2_dpte_row_height_linear > 7) - log2_dpte_row_height_linear = 7; - - log2_dpte_row_height = log2_dpte_row_height_linear; - // For linear, the dpte row is pitch dependent and the pte requests wrap at the pitch boundary. - // the dpte_row_width_ub is the upper bound of data_pitch*dpte_row_height in elements with this unique buffering. - dpte_row_height = 1 << log2_dpte_row_height; - dpte_row_width_ub = dml_round_to_multiple(data_pitch * dpte_row_height - 1, - dpte_req_width, - 1) + dpte_req_width; - rq_dlg_param->dpte_req_per_row_ub = dpte_row_width_ub / dpte_req_width; - } else { - // the upper bound of the dpte_row_width without dependency on viewport position follows. - // for tiled mode, row height is the same as req height and row store up to vp size upper bound - if (!surf_vert) { - log2_dpte_row_height = log2_dpte_req_height; - dpte_row_width_ub = dml_round_to_multiple(vp_width - 1, dpte_req_width, 1) - + dpte_req_width; - rq_dlg_param->dpte_req_per_row_ub = dpte_row_width_ub / dpte_req_width; - } else { - log2_dpte_row_height = - (log2_blk_width < log2_dpte_req_width) ? - log2_blk_width : log2_dpte_req_width; - dpte_row_width_ub = dml_round_to_multiple(vp_height - 1, dpte_req_height, 1) - + dpte_req_height; - rq_dlg_param->dpte_req_per_row_ub = dpte_row_width_ub / dpte_req_height; - } - } - if (log2_blk_bytes >= 16 && log2_vmpg_bytes == 12) // tile block >= 64KB - rq_dlg_param->dpte_bytes_per_row_ub = rq_dlg_param->dpte_req_per_row_ub * 128; //2*64B dpte request - else - rq_dlg_param->dpte_bytes_per_row_ub = rq_dlg_param->dpte_req_per_row_ub * 64; //64B dpte request - - rq_dlg_param->dpte_row_height = 1 << log2_dpte_row_height; - - // the dpte_group_bytes is reduced for the specific case of vertical - // access of a tile surface that has dpte request of 8x1 ptes. - if (!surf_linear & (log2_dpte_req_height_ptes == 0) & surf_vert) //reduced, in this case, will have page fault within a group - rq_sizing_param->dpte_group_bytes = 512; - else - //full size - rq_sizing_param->dpte_group_bytes = 2048; - - //since pte request size is 64byte, the number of data pte requests per full sized group is as follows. - log2_dpte_group_bytes = dml_log2(rq_sizing_param->dpte_group_bytes); - log2_dpte_group_length = log2_dpte_group_bytes - 6; //length in 64b requests - - // full sized data pte group width in elements - if (!surf_vert) - log2_dpte_group_width = log2_dpte_group_length + log2_dpte_req_width; - else - log2_dpte_group_width = log2_dpte_group_length + log2_dpte_req_height; - - //But if the tile block >=64KB and the page size is 4KB, then each dPTE request is 2*64B - if ((log2_blk_bytes >= 16) && (log2_vmpg_bytes == 12)) // tile block >= 64KB - log2_dpte_group_width = log2_dpte_group_width - 1; - - dpte_group_width = 1 << log2_dpte_group_width; - - // since dpte groups are only aligned to dpte_req_width and not dpte_group_width, - // the upper bound for the dpte groups per row is as follows. - rq_dlg_param->dpte_groups_per_row_ub = dml_ceil((double) dpte_row_width_ub / dpte_group_width, - 1); -} - -static void get_surf_rq_param(struct display_mode_lib *mode_lib, - display_data_rq_sizing_params_st *rq_sizing_param, - display_data_rq_dlg_params_st *rq_dlg_param, - display_data_rq_misc_params_st *rq_misc_param, - const display_pipe_source_params_st pipe_src_param, - bool is_chroma) -{ - bool mode_422 = 0; - unsigned int vp_width = 0; - unsigned int vp_height = 0; - unsigned int data_pitch = 0; - unsigned int meta_pitch = 0; - unsigned int ppe = mode_422 ? 2 : 1; - - // FIXME check if ppe apply for both luma and chroma in 422 case - if (is_chroma) { - vp_width = pipe_src_param.viewport_width_c / ppe; - vp_height = pipe_src_param.viewport_height_c; - data_pitch = pipe_src_param.data_pitch_c; - meta_pitch = pipe_src_param.meta_pitch_c; - } else { - vp_width = pipe_src_param.viewport_width / ppe; - vp_height = pipe_src_param.viewport_height; - data_pitch = pipe_src_param.data_pitch; - meta_pitch = pipe_src_param.meta_pitch; - } - - rq_sizing_param->chunk_bytes = 8192; - - if (rq_sizing_param->chunk_bytes == 64 * 1024) - rq_sizing_param->min_chunk_bytes = 0; - else - rq_sizing_param->min_chunk_bytes = 1024; - - rq_sizing_param->meta_chunk_bytes = 2048; - rq_sizing_param->min_meta_chunk_bytes = 256; - - rq_sizing_param->mpte_group_bytes = 2048; - - get_meta_and_pte_attr(mode_lib, - rq_dlg_param, - rq_misc_param, - rq_sizing_param, - vp_width, - vp_height, - data_pitch, - meta_pitch, - pipe_src_param.source_format, - pipe_src_param.sw_mode, - pipe_src_param.macro_tile_size, - pipe_src_param.source_scan, - is_chroma); -} - -void dml_rq_dlg_get_rq_params(struct display_mode_lib *mode_lib, - display_rq_params_st *rq_param, - const display_pipe_source_params_st pipe_src_param) -{ - // get param for luma surface - rq_param->yuv420 = pipe_src_param.source_format == dm_420_8 - || pipe_src_param.source_format == dm_420_10; - rq_param->yuv420_10bpc = pipe_src_param.source_format == dm_420_10; - - get_surf_rq_param(mode_lib, - &(rq_param->sizing.rq_l), - &(rq_param->dlg.rq_l), - &(rq_param->misc.rq_l), - pipe_src_param, - 0); - - if (is_dual_plane((enum source_format_class)(pipe_src_param.source_format))) { - // get param for chroma surface - get_surf_rq_param(mode_lib, - &(rq_param->sizing.rq_c), - &(rq_param->dlg.rq_c), - &(rq_param->misc.rq_c), - pipe_src_param, - 1); - } - - // calculate how to split the det buffer space between luma and chroma - handle_det_buf_split(mode_lib, rq_param, pipe_src_param); - print__rq_params_st(mode_lib, *rq_param); -} - -void dml_rq_dlg_get_rq_reg(struct display_mode_lib *mode_lib, - display_rq_regs_st *rq_regs, - const display_pipe_source_params_st pipe_src_param) -{ - display_rq_params_st rq_param = {0}; - - memset(rq_regs, 0, sizeof(*rq_regs)); - dml_rq_dlg_get_rq_params(mode_lib, &rq_param, pipe_src_param); - extract_rq_regs(mode_lib, rq_regs, rq_param); - - print__rq_regs_st(mode_lib, *rq_regs); -} - -// Note: currently taken in as is. -// Nice to decouple code from hw register implement and extract code that are repeated for luma and chroma. -void dml_rq_dlg_get_dlg_params(struct display_mode_lib *mode_lib, - const display_e2e_pipe_params_st *e2e_pipe_param, - const unsigned int num_pipes, - const unsigned int pipe_idx, - display_dlg_regs_st *disp_dlg_regs, - display_ttu_regs_st *disp_ttu_regs, - const display_rq_dlg_params_st rq_dlg_param, - const display_dlg_sys_params_st dlg_sys_param, - const bool cstate_en, - const bool pstate_en, - const bool vm_en, - const bool ignore_viewport_pos, - const bool immediate_flip_support) -{ - const display_pipe_source_params_st *src = &e2e_pipe_param[pipe_idx].pipe.src; - const display_pipe_dest_params_st *dst = &e2e_pipe_param[pipe_idx].pipe.dest; - const display_output_params_st *dout = &e2e_pipe_param[pipe_idx].dout; - const display_clocks_and_cfg_st *clks = &e2e_pipe_param[pipe_idx].clks_cfg; - const scaler_ratio_depth_st *scl = &e2e_pipe_param[pipe_idx].pipe.scale_ratio_depth; - const scaler_taps_st *taps = &e2e_pipe_param[pipe_idx].pipe.scale_taps; - - // ------------------------- - // Section 1.15.2.1: OTG dependent Params - // ------------------------- - // Timing - unsigned int htotal = dst->htotal; -// unsigned int hblank_start = dst.hblank_start; // TODO: Remove - unsigned int hblank_end = dst->hblank_end; - unsigned int vblank_start = dst->vblank_start; - unsigned int vblank_end = dst->vblank_end; - unsigned int min_vblank = mode_lib->ip.min_vblank_lines; - - double dppclk_freq_in_mhz = clks->dppclk_mhz; - double dispclk_freq_in_mhz = clks->dispclk_mhz; - double refclk_freq_in_mhz = clks->refclk_mhz; - double pclk_freq_in_mhz = dst->pixel_rate_mhz; - bool interlaced = dst->interlaced; - - double ref_freq_to_pix_freq = refclk_freq_in_mhz / pclk_freq_in_mhz; - - double min_dcfclk_mhz; - double t_calc_us; - double min_ttu_vblank; - - double min_dst_y_ttu_vblank; - unsigned int dlg_vblank_start; - bool dual_plane; - bool mode_422; - unsigned int access_dir; - unsigned int vp_height_l; - unsigned int vp_width_l; - unsigned int vp_height_c; - unsigned int vp_width_c; - - // Scaling - unsigned int htaps_l; - unsigned int htaps_c; - double hratio_l; - double hratio_c; - double vratio_l; - double vratio_c; - bool scl_enable; - - double line_time_in_us; - // double vinit_l; - // double vinit_c; - // double vinit_bot_l; - // double vinit_bot_c; - - // unsigned int swath_height_l; - unsigned int swath_width_ub_l; - // unsigned int dpte_bytes_per_row_ub_l; - unsigned int dpte_groups_per_row_ub_l; - // unsigned int meta_pte_bytes_per_frame_ub_l; - // unsigned int meta_bytes_per_row_ub_l; - - // unsigned int swath_height_c; - unsigned int swath_width_ub_c; - // unsigned int dpte_bytes_per_row_ub_c; - unsigned int dpte_groups_per_row_ub_c; - - unsigned int meta_chunks_per_row_ub_l; - unsigned int meta_chunks_per_row_ub_c; - unsigned int vupdate_offset; - unsigned int vupdate_width; - unsigned int vready_offset; - - unsigned int dppclk_delay_subtotal; - unsigned int dispclk_delay_subtotal; - unsigned int pixel_rate_delay_subtotal; - - unsigned int vstartup_start; - unsigned int dst_x_after_scaler; - unsigned int dst_y_after_scaler; - double line_wait; - double dst_y_prefetch; - double dst_y_per_vm_vblank; - double dst_y_per_row_vblank; - double dst_y_per_vm_flip; - double dst_y_per_row_flip; - double min_dst_y_per_vm_vblank; - double min_dst_y_per_row_vblank; - double lsw; - double vratio_pre_l; - double vratio_pre_c; - unsigned int req_per_swath_ub_l; - unsigned int req_per_swath_ub_c; - unsigned int meta_row_height_l; - unsigned int meta_row_height_c; - unsigned int swath_width_pixels_ub_l; - unsigned int swath_width_pixels_ub_c; - unsigned int scaler_rec_in_width_l; - unsigned int scaler_rec_in_width_c; - unsigned int dpte_row_height_l; - unsigned int dpte_row_height_c; - double hscale_pixel_rate_l; - double hscale_pixel_rate_c; - double min_hratio_fact_l; - double min_hratio_fact_c; - double refcyc_per_line_delivery_pre_l; - double refcyc_per_line_delivery_pre_c; - double refcyc_per_line_delivery_l; - double refcyc_per_line_delivery_c; - - double refcyc_per_req_delivery_pre_l; - double refcyc_per_req_delivery_pre_c; - double refcyc_per_req_delivery_l; - double refcyc_per_req_delivery_c; - - unsigned int full_recout_width; - double xfc_transfer_delay; - double xfc_precharge_delay; - double xfc_remote_surface_flip_latency; - double xfc_dst_y_delta_drq_limit; - double xfc_prefetch_margin; - double refcyc_per_req_delivery_pre_cur0; - double refcyc_per_req_delivery_cur0; - double refcyc_per_req_delivery_pre_cur1; - double refcyc_per_req_delivery_cur1; - - memset(disp_dlg_regs, 0, sizeof(*disp_dlg_regs)); - memset(disp_ttu_regs, 0, sizeof(*disp_ttu_regs)); - - dml_print("DML_DLG: %s: cstate_en = %d\n", __func__, cstate_en); - dml_print("DML_DLG: %s: pstate_en = %d\n", __func__, pstate_en); - dml_print("DML_DLG: %s: vm_en = %d\n", __func__, vm_en); - dml_print("DML_DLG: %s: ignore_viewport_pos = %d\n", __func__, ignore_viewport_pos); - dml_print("DML_DLG: %s: immediate_flip_support = %d\n", __func__, immediate_flip_support); - - dml_print("DML_DLG: %s: dppclk_freq_in_mhz = %3.2f\n", __func__, dppclk_freq_in_mhz); - dml_print("DML_DLG: %s: dispclk_freq_in_mhz = %3.2f\n", __func__, dispclk_freq_in_mhz); - dml_print("DML_DLG: %s: refclk_freq_in_mhz = %3.2f\n", __func__, refclk_freq_in_mhz); - dml_print("DML_DLG: %s: pclk_freq_in_mhz = %3.2f\n", __func__, pclk_freq_in_mhz); - dml_print("DML_DLG: %s: interlaced = %d\n", __func__, interlaced); - ASSERT(ref_freq_to_pix_freq < 4.0); - - disp_dlg_regs->ref_freq_to_pix_freq = - (unsigned int) (ref_freq_to_pix_freq * dml_pow(2, 19)); - disp_dlg_regs->refcyc_per_htotal = (unsigned int) (ref_freq_to_pix_freq * (double) htotal - * dml_pow(2, 8)); - disp_dlg_regs->dlg_vblank_end = interlaced ? (vblank_end / 2) : vblank_end; // 15 bits - disp_dlg_regs->refcyc_h_blank_end = (unsigned int) ((double) hblank_end - * (double) ref_freq_to_pix_freq); - ASSERT(disp_dlg_regs->refcyc_h_blank_end < (unsigned int) dml_pow(2, 13)); - - min_dcfclk_mhz = dlg_sys_param.deepsleep_dcfclk_mhz; - set_prefetch_mode(mode_lib, cstate_en, pstate_en, ignore_viewport_pos, immediate_flip_support); - t_calc_us = get_tcalc(mode_lib, e2e_pipe_param, num_pipes); - min_ttu_vblank = get_min_ttu_vblank(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); - - min_dst_y_ttu_vblank = min_ttu_vblank * pclk_freq_in_mhz / (double) htotal; - dlg_vblank_start = interlaced ? (vblank_start / 2) : vblank_start; - - disp_dlg_regs->min_dst_y_next_start = (unsigned int) (((double) dlg_vblank_start - + min_dst_y_ttu_vblank) * dml_pow(2, 2)); - ASSERT(disp_dlg_regs->min_dst_y_next_start < (unsigned int) dml_pow(2, 18)); - - dml_print("DML_DLG: %s: min_dcfclk_mhz = %3.2f\n", - __func__, - min_dcfclk_mhz); - dml_print("DML_DLG: %s: min_ttu_vblank = %3.2f\n", - __func__, - min_ttu_vblank); - dml_print("DML_DLG: %s: min_dst_y_ttu_vblank = %3.2f\n", - __func__, - min_dst_y_ttu_vblank); - dml_print("DML_DLG: %s: t_calc_us = %3.2f\n", - __func__, - t_calc_us); - dml_print("DML_DLG: %s: disp_dlg_regs->min_dst_y_next_start = 0x%0x\n", - __func__, - disp_dlg_regs->min_dst_y_next_start); - dml_print("DML_DLG: %s: ref_freq_to_pix_freq = %3.2f\n", - __func__, - ref_freq_to_pix_freq); - - // ------------------------- - // Section 1.15.2.2: Prefetch, Active and TTU - // ------------------------- - // Prefetch Calc - // Source -// dcc_en = src.dcc; - dual_plane = is_dual_plane((enum source_format_class)(src->source_format)); - mode_422 = 0; // FIXME - access_dir = (src->source_scan == dm_vert); // vp access direction: horizontal or vertical accessed -// bytes_per_element_l = get_bytes_per_element(source_format_class(src.source_format), 0); -// bytes_per_element_c = get_bytes_per_element(source_format_class(src.source_format), 1); - vp_height_l = src->viewport_height; - vp_width_l = src->viewport_width; - vp_height_c = src->viewport_height_c; - vp_width_c = src->viewport_width_c; - - // Scaling - htaps_l = taps->htaps; - htaps_c = taps->htaps_c; - hratio_l = scl->hscl_ratio; - hratio_c = scl->hscl_ratio_c; - vratio_l = scl->vscl_ratio; - vratio_c = scl->vscl_ratio_c; - scl_enable = scl->scl_enable; - - line_time_in_us = (htotal / pclk_freq_in_mhz); -// vinit_l = scl.vinit; -// vinit_c = scl.vinit_c; -// vinit_bot_l = scl.vinit_bot; -// vinit_bot_c = scl.vinit_bot_c; - -// unsigned int swath_height_l = rq_dlg_param.rq_l.swath_height; - swath_width_ub_l = rq_dlg_param.rq_l.swath_width_ub; -// unsigned int dpte_bytes_per_row_ub_l = rq_dlg_param.rq_l.dpte_bytes_per_row_ub; - dpte_groups_per_row_ub_l = rq_dlg_param.rq_l.dpte_groups_per_row_ub; -// unsigned int meta_pte_bytes_per_frame_ub_l = rq_dlg_param.rq_l.meta_pte_bytes_per_frame_ub; -// unsigned int meta_bytes_per_row_ub_l = rq_dlg_param.rq_l.meta_bytes_per_row_ub; - -// unsigned int swath_height_c = rq_dlg_param.rq_c.swath_height; - swath_width_ub_c = rq_dlg_param.rq_c.swath_width_ub; - // dpte_bytes_per_row_ub_c = rq_dlg_param.rq_c.dpte_bytes_per_row_ub; - dpte_groups_per_row_ub_c = rq_dlg_param.rq_c.dpte_groups_per_row_ub; - - meta_chunks_per_row_ub_l = rq_dlg_param.rq_l.meta_chunks_per_row_ub; - meta_chunks_per_row_ub_c = rq_dlg_param.rq_c.meta_chunks_per_row_ub; - vupdate_offset = dst->vupdate_offset; - vupdate_width = dst->vupdate_width; - vready_offset = dst->vready_offset; - - dppclk_delay_subtotal = mode_lib->ip.dppclk_delay_subtotal; - dispclk_delay_subtotal = mode_lib->ip.dispclk_delay_subtotal; - - if (scl_enable) - dppclk_delay_subtotal += mode_lib->ip.dppclk_delay_scl; - else - dppclk_delay_subtotal += mode_lib->ip.dppclk_delay_scl_lb_only; - - dppclk_delay_subtotal += mode_lib->ip.dppclk_delay_cnvc_formatter - + src->num_cursors * mode_lib->ip.dppclk_delay_cnvc_cursor; - - if (dout->dsc_enable) { - double dsc_delay = get_dsc_delay(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); - - dispclk_delay_subtotal += dsc_delay; - } - - pixel_rate_delay_subtotal = dppclk_delay_subtotal * pclk_freq_in_mhz / dppclk_freq_in_mhz - + dispclk_delay_subtotal * pclk_freq_in_mhz / dispclk_freq_in_mhz; - - vstartup_start = dst->vstartup_start; - if (interlaced) { - if (vstartup_start / 2.0 - - (double) (vready_offset + vupdate_width + vupdate_offset) / htotal - <= vblank_end / 2.0) - disp_dlg_regs->vready_after_vcount0 = 1; - else - disp_dlg_regs->vready_after_vcount0 = 0; - } else { - if (vstartup_start - - (double) (vready_offset + vupdate_width + vupdate_offset) / htotal - <= vblank_end) - disp_dlg_regs->vready_after_vcount0 = 1; - else - disp_dlg_regs->vready_after_vcount0 = 0; - } - - // TODO: Where is this coming from? - if (interlaced) - vstartup_start = vstartup_start / 2; - - // TODO: What if this min_vblank doesn't match the value in the dml_config_settings.cpp? - if (vstartup_start >= min_vblank) { - dml_print("WARNING: DML_DLG: %s: vblank_start=%d vblank_end=%d\n", - __func__, - vblank_start, - vblank_end); - dml_print("WARNING: DML_DLG: %s: vstartup_start=%d should be less than min_vblank=%d\n", - __func__, - vstartup_start, - min_vblank); - min_vblank = vstartup_start + 1; - dml_print("WARNING: DML_DLG: %s: vstartup_start=%d should be less than min_vblank=%d\n", - __func__, - vstartup_start, - min_vblank); - } - - dst_x_after_scaler = get_dst_x_after_scaler(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); - dst_y_after_scaler = get_dst_y_after_scaler(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); - - dml_print("DML_DLG: %s: htotal = %d\n", __func__, htotal); - dml_print("DML_DLG: %s: pixel_rate_delay_subtotal = %d\n", - __func__, - pixel_rate_delay_subtotal); - dml_print("DML_DLG: %s: dst_x_after_scaler = %d\n", - __func__, - dst_x_after_scaler); - dml_print("DML_DLG: %s: dst_y_after_scaler = %d\n", - __func__, - dst_y_after_scaler); - - // Lwait - line_wait = mode_lib->soc.urgent_latency_us; - if (cstate_en) - line_wait = dml_max(mode_lib->soc.sr_enter_plus_exit_time_us, line_wait); - if (pstate_en) - line_wait = dml_max(mode_lib->soc.dram_clock_change_latency_us - + mode_lib->soc.urgent_latency_us, - line_wait); - line_wait = line_wait / line_time_in_us; - - dst_y_prefetch = get_dst_y_prefetch(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); - dml_print("DML_DLG: %s: dst_y_prefetch (after rnd) = %3.2f\n", __func__, dst_y_prefetch); - - dst_y_per_vm_vblank = get_dst_y_per_vm_vblank(mode_lib, - e2e_pipe_param, - num_pipes, - pipe_idx); - dst_y_per_row_vblank = get_dst_y_per_row_vblank(mode_lib, - e2e_pipe_param, - num_pipes, - pipe_idx); - dst_y_per_vm_flip = get_dst_y_per_vm_flip(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); - dst_y_per_row_flip = get_dst_y_per_row_flip(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); - - min_dst_y_per_vm_vblank = 8.0; - min_dst_y_per_row_vblank = 16.0; - - // magic! - if (htotal <= 75) { - min_vblank = 300; - min_dst_y_per_vm_vblank = 100.0; - min_dst_y_per_row_vblank = 100.0; - } - - dml_print("DML_DLG: %s: dst_y_per_vm_vblank = %3.2f\n", __func__, dst_y_per_vm_vblank); - dml_print("DML_DLG: %s: dst_y_per_row_vblank = %3.2f\n", __func__, dst_y_per_row_vblank); - - ASSERT(dst_y_per_vm_vblank < min_dst_y_per_vm_vblank); - ASSERT(dst_y_per_row_vblank < min_dst_y_per_row_vblank); - - ASSERT(dst_y_prefetch > (dst_y_per_vm_vblank + dst_y_per_row_vblank)); - lsw = dst_y_prefetch - (dst_y_per_vm_vblank + dst_y_per_row_vblank); - - dml_print("DML_DLG: %s: lsw = %3.2f\n", __func__, lsw); - - vratio_pre_l = get_vratio_prefetch_l(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); - vratio_pre_c = get_vratio_prefetch_c(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); - - dml_print("DML_DLG: %s: vratio_pre_l=%3.2f\n", __func__, vratio_pre_l); - dml_print("DML_DLG: %s: vratio_pre_c=%3.2f\n", __func__, vratio_pre_c); - - // Active - req_per_swath_ub_l = rq_dlg_param.rq_l.req_per_swath_ub; - req_per_swath_ub_c = rq_dlg_param.rq_c.req_per_swath_ub; - meta_row_height_l = rq_dlg_param.rq_l.meta_row_height; - meta_row_height_c = rq_dlg_param.rq_c.meta_row_height; - swath_width_pixels_ub_l = 0; - swath_width_pixels_ub_c = 0; - scaler_rec_in_width_l = 0; - scaler_rec_in_width_c = 0; - dpte_row_height_l = rq_dlg_param.rq_l.dpte_row_height; - dpte_row_height_c = rq_dlg_param.rq_c.dpte_row_height; - - if (mode_422) { - swath_width_pixels_ub_l = swath_width_ub_l * 2; // *2 for 2 pixel per element - swath_width_pixels_ub_c = swath_width_ub_c * 2; - } else { - swath_width_pixels_ub_l = swath_width_ub_l * 1; - swath_width_pixels_ub_c = swath_width_ub_c * 1; - } - - hscale_pixel_rate_l = 0.; - hscale_pixel_rate_c = 0.; - min_hratio_fact_l = 1.0; - min_hratio_fact_c = 1.0; - - if (htaps_l <= 1) - min_hratio_fact_l = 2.0; - else if (htaps_l <= 6) { - if ((hratio_l * 2.0) > 4.0) - min_hratio_fact_l = 4.0; - else - min_hratio_fact_l = hratio_l * 2.0; - } else { - if (hratio_l > 4.0) - min_hratio_fact_l = 4.0; - else - min_hratio_fact_l = hratio_l; - } - - hscale_pixel_rate_l = min_hratio_fact_l * dppclk_freq_in_mhz; - - if (htaps_c <= 1) - min_hratio_fact_c = 2.0; - else if (htaps_c <= 6) { - if ((hratio_c * 2.0) > 4.0) - min_hratio_fact_c = 4.0; - else - min_hratio_fact_c = hratio_c * 2.0; - } else { - if (hratio_c > 4.0) - min_hratio_fact_c = 4.0; - else - min_hratio_fact_c = hratio_c; - } - - hscale_pixel_rate_c = min_hratio_fact_c * dppclk_freq_in_mhz; - - refcyc_per_line_delivery_pre_l = 0.; - refcyc_per_line_delivery_pre_c = 0.; - refcyc_per_line_delivery_l = 0.; - refcyc_per_line_delivery_c = 0.; - - refcyc_per_req_delivery_pre_l = 0.; - refcyc_per_req_delivery_pre_c = 0.; - refcyc_per_req_delivery_l = 0.; - refcyc_per_req_delivery_c = 0.; - - full_recout_width = 0; - // In ODM - if (src->is_hsplit) { - // This "hack" is only allowed (and valid) for MPC combine. In ODM - // combine, you MUST specify the full_recout_width...according to Oswin - if (dst->full_recout_width == 0 && !dst->odm_combine) { - dml_print("DML_DLG: %s: Warning: full_recout_width not set in hsplit mode\n", - __func__); - full_recout_width = dst->recout_width * 2; // assume half split for dcn1 - } else - full_recout_width = dst->full_recout_width; - } else - full_recout_width = dst->recout_width; - - // mpc_combine and odm_combine are mutually exclusive - refcyc_per_line_delivery_pre_l = get_refcyc_per_delivery(mode_lib, - refclk_freq_in_mhz, - pclk_freq_in_mhz, - dst->odm_combine, - full_recout_width, - dst->hactive, - vratio_pre_l, - hscale_pixel_rate_l, - swath_width_pixels_ub_l, - 1); // per line - - refcyc_per_line_delivery_l = get_refcyc_per_delivery(mode_lib, - refclk_freq_in_mhz, - pclk_freq_in_mhz, - dst->odm_combine, - full_recout_width, - dst->hactive, - vratio_l, - hscale_pixel_rate_l, - swath_width_pixels_ub_l, - 1); // per line - - dml_print("DML_DLG: %s: full_recout_width = %d\n", - __func__, - full_recout_width); - dml_print("DML_DLG: %s: hscale_pixel_rate_l = %3.2f\n", - __func__, - hscale_pixel_rate_l); - dml_print("DML_DLG: %s: refcyc_per_line_delivery_pre_l = %3.2f\n", - __func__, - refcyc_per_line_delivery_pre_l); - dml_print("DML_DLG: %s: refcyc_per_line_delivery_l = %3.2f\n", - __func__, - refcyc_per_line_delivery_l); - - if (dual_plane) { - refcyc_per_line_delivery_pre_c = get_refcyc_per_delivery(mode_lib, - refclk_freq_in_mhz, - pclk_freq_in_mhz, - dst->odm_combine, - full_recout_width, - dst->hactive, - vratio_pre_c, - hscale_pixel_rate_c, - swath_width_pixels_ub_c, - 1); // per line - - refcyc_per_line_delivery_c = get_refcyc_per_delivery(mode_lib, - refclk_freq_in_mhz, - pclk_freq_in_mhz, - dst->odm_combine, - full_recout_width, - dst->hactive, - vratio_c, - hscale_pixel_rate_c, - swath_width_pixels_ub_c, - 1); // per line - - dml_print("DML_DLG: %s: refcyc_per_line_delivery_pre_c = %3.2f\n", - __func__, - refcyc_per_line_delivery_pre_c); - dml_print("DML_DLG: %s: refcyc_per_line_delivery_c = %3.2f\n", - __func__, - refcyc_per_line_delivery_c); - } - - // TTU - Luma / Chroma - if (access_dir) { // vertical access - scaler_rec_in_width_l = vp_height_l; - scaler_rec_in_width_c = vp_height_c; - } else { - scaler_rec_in_width_l = vp_width_l; - scaler_rec_in_width_c = vp_width_c; - } - - refcyc_per_req_delivery_pre_l = get_refcyc_per_delivery(mode_lib, - refclk_freq_in_mhz, - pclk_freq_in_mhz, - dst->odm_combine, - full_recout_width, - dst->hactive, - vratio_pre_l, - hscale_pixel_rate_l, - scaler_rec_in_width_l, - req_per_swath_ub_l); // per req - refcyc_per_req_delivery_l = get_refcyc_per_delivery(mode_lib, - refclk_freq_in_mhz, - pclk_freq_in_mhz, - dst->odm_combine, - full_recout_width, - dst->hactive, - vratio_l, - hscale_pixel_rate_l, - scaler_rec_in_width_l, - req_per_swath_ub_l); // per req - - dml_print("DML_DLG: %s: refcyc_per_req_delivery_pre_l = %3.2f\n", - __func__, - refcyc_per_req_delivery_pre_l); - dml_print("DML_DLG: %s: refcyc_per_req_delivery_l = %3.2f\n", - __func__, - refcyc_per_req_delivery_l); - - ASSERT(refcyc_per_req_delivery_pre_l < dml_pow(2, 13)); - ASSERT(refcyc_per_req_delivery_l < dml_pow(2, 13)); - - if (dual_plane) { - refcyc_per_req_delivery_pre_c = get_refcyc_per_delivery(mode_lib, - refclk_freq_in_mhz, - pclk_freq_in_mhz, - dst->odm_combine, - full_recout_width, - dst->hactive, - vratio_pre_c, - hscale_pixel_rate_c, - scaler_rec_in_width_c, - req_per_swath_ub_c); // per req - refcyc_per_req_delivery_c = get_refcyc_per_delivery(mode_lib, - refclk_freq_in_mhz, - pclk_freq_in_mhz, - dst->odm_combine, - full_recout_width, - dst->hactive, - vratio_c, - hscale_pixel_rate_c, - scaler_rec_in_width_c, - req_per_swath_ub_c); // per req - - dml_print("DML_DLG: %s: refcyc_per_req_delivery_pre_c = %3.2f\n", - __func__, - refcyc_per_req_delivery_pre_c); - dml_print("DML_DLG: %s: refcyc_per_req_delivery_c = %3.2f\n", - __func__, - refcyc_per_req_delivery_c); - - ASSERT(refcyc_per_req_delivery_pre_c < dml_pow(2, 13)); - ASSERT(refcyc_per_req_delivery_c < dml_pow(2, 13)); - } - - // XFC - xfc_transfer_delay = get_xfc_transfer_delay(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); - xfc_precharge_delay = get_xfc_precharge_delay(mode_lib, - e2e_pipe_param, - num_pipes, - pipe_idx); - xfc_remote_surface_flip_latency = get_xfc_remote_surface_flip_latency(mode_lib, - e2e_pipe_param, - num_pipes, - pipe_idx); - xfc_dst_y_delta_drq_limit = xfc_remote_surface_flip_latency; - xfc_prefetch_margin = get_xfc_prefetch_margin(mode_lib, - e2e_pipe_param, - num_pipes, - pipe_idx); - - // TTU - Cursor - refcyc_per_req_delivery_pre_cur0 = 0.0; - refcyc_per_req_delivery_cur0 = 0.0; - if (src->num_cursors > 0) { - calculate_ttu_cursor(mode_lib, - &refcyc_per_req_delivery_pre_cur0, - &refcyc_per_req_delivery_cur0, - refclk_freq_in_mhz, - ref_freq_to_pix_freq, - hscale_pixel_rate_l, - scl->hscl_ratio, - vratio_pre_l, - vratio_l, - src->cur0_src_width, - (enum cursor_bpp)(src->cur0_bpp)); - } - - refcyc_per_req_delivery_pre_cur1 = 0.0; - refcyc_per_req_delivery_cur1 = 0.0; - if (src->num_cursors > 1) { - calculate_ttu_cursor(mode_lib, - &refcyc_per_req_delivery_pre_cur1, - &refcyc_per_req_delivery_cur1, - refclk_freq_in_mhz, - ref_freq_to_pix_freq, - hscale_pixel_rate_l, - scl->hscl_ratio, - vratio_pre_l, - vratio_l, - src->cur1_src_width, - (enum cursor_bpp)(src->cur1_bpp)); - } - - // TTU - Misc - // all hard-coded - - // Assignment to register structures - disp_dlg_regs->dst_y_after_scaler = dst_y_after_scaler; // in terms of line - disp_dlg_regs->refcyc_x_after_scaler = dst_x_after_scaler * ref_freq_to_pix_freq; // in terms of refclk - ASSERT(disp_dlg_regs->refcyc_x_after_scaler < (unsigned int) dml_pow(2, 13)); - disp_dlg_regs->dst_y_prefetch = (unsigned int) (dst_y_prefetch * dml_pow(2, 2)); - disp_dlg_regs->dst_y_per_vm_vblank = (unsigned int) (dst_y_per_vm_vblank * dml_pow(2, 2)); - disp_dlg_regs->dst_y_per_row_vblank = (unsigned int) (dst_y_per_row_vblank * dml_pow(2, 2)); - disp_dlg_regs->dst_y_per_vm_flip = (unsigned int) (dst_y_per_vm_flip * dml_pow(2, 2)); - disp_dlg_regs->dst_y_per_row_flip = (unsigned int) (dst_y_per_row_flip * dml_pow(2, 2)); - - disp_dlg_regs->vratio_prefetch = (unsigned int) (vratio_pre_l * dml_pow(2, 19)); - disp_dlg_regs->vratio_prefetch_c = (unsigned int) (vratio_pre_c * dml_pow(2, 19)); - - disp_dlg_regs->refcyc_per_pte_group_vblank_l = - (unsigned int) (dst_y_per_row_vblank * (double) htotal - * ref_freq_to_pix_freq / (double) dpte_groups_per_row_ub_l); - ASSERT(disp_dlg_regs->refcyc_per_pte_group_vblank_l < (unsigned int) dml_pow(2, 13)); - - if (dual_plane) { - disp_dlg_regs->refcyc_per_pte_group_vblank_c = (unsigned int) (dst_y_per_row_vblank - * (double) htotal * ref_freq_to_pix_freq - / (double) dpte_groups_per_row_ub_c); - ASSERT(disp_dlg_regs->refcyc_per_pte_group_vblank_c - < (unsigned int) dml_pow(2, 13)); - } - - disp_dlg_regs->refcyc_per_meta_chunk_vblank_l = - (unsigned int) (dst_y_per_row_vblank * (double) htotal - * ref_freq_to_pix_freq / (double) meta_chunks_per_row_ub_l); - ASSERT(disp_dlg_regs->refcyc_per_meta_chunk_vblank_l < (unsigned int) dml_pow(2, 13)); - - disp_dlg_regs->refcyc_per_meta_chunk_vblank_c = - disp_dlg_regs->refcyc_per_meta_chunk_vblank_l; // dcc for 4:2:0 is not supported in dcn1.0. assigned to be the same as _l for now - - disp_dlg_regs->refcyc_per_pte_group_flip_l = (unsigned int) (dst_y_per_row_flip * htotal - * ref_freq_to_pix_freq) / dpte_groups_per_row_ub_l; - disp_dlg_regs->refcyc_per_meta_chunk_flip_l = (unsigned int) (dst_y_per_row_flip * htotal - * ref_freq_to_pix_freq) / meta_chunks_per_row_ub_l; - - if (dual_plane) { - disp_dlg_regs->refcyc_per_pte_group_flip_c = (unsigned int) (dst_y_per_row_flip - * htotal * ref_freq_to_pix_freq) / dpte_groups_per_row_ub_c; - disp_dlg_regs->refcyc_per_meta_chunk_flip_c = (unsigned int) (dst_y_per_row_flip - * htotal * ref_freq_to_pix_freq) / meta_chunks_per_row_ub_c; - } - - disp_dlg_regs->dst_y_per_pte_row_nom_l = (unsigned int) ((double) dpte_row_height_l - / (double) vratio_l * dml_pow(2, 2)); - ASSERT(disp_dlg_regs->dst_y_per_pte_row_nom_l < (unsigned int) dml_pow(2, 17)); - - if (dual_plane) { - disp_dlg_regs->dst_y_per_pte_row_nom_c = (unsigned int) ((double) dpte_row_height_c - / (double) vratio_c * dml_pow(2, 2)); - if (disp_dlg_regs->dst_y_per_pte_row_nom_c >= (unsigned int) dml_pow(2, 17)) { - dml_print("DML_DLG: %s: Warning dst_y_per_pte_row_nom_c %u larger than supported by register format U15.2 %u\n", - __func__, - disp_dlg_regs->dst_y_per_pte_row_nom_c, - (unsigned int) dml_pow(2, 17) - 1); - } - } - - disp_dlg_regs->dst_y_per_meta_row_nom_l = (unsigned int) ((double) meta_row_height_l - / (double) vratio_l * dml_pow(2, 2)); - ASSERT(disp_dlg_regs->dst_y_per_meta_row_nom_l < (unsigned int) dml_pow(2, 17)); - - disp_dlg_regs->dst_y_per_meta_row_nom_c = disp_dlg_regs->dst_y_per_meta_row_nom_l; // TODO: dcc for 4:2:0 is not supported in dcn1.0. assigned to be the same as _l for now - - disp_dlg_regs->refcyc_per_pte_group_nom_l = (unsigned int) ((double) dpte_row_height_l - / (double) vratio_l * (double) htotal * ref_freq_to_pix_freq - / (double) dpte_groups_per_row_ub_l); - if (disp_dlg_regs->refcyc_per_pte_group_nom_l >= (unsigned int) dml_pow(2, 23)) - disp_dlg_regs->refcyc_per_pte_group_nom_l = dml_pow(2, 23) - 1; - disp_dlg_regs->refcyc_per_meta_chunk_nom_l = (unsigned int) ((double) meta_row_height_l - / (double) vratio_l * (double) htotal * ref_freq_to_pix_freq - / (double) meta_chunks_per_row_ub_l); - if (disp_dlg_regs->refcyc_per_meta_chunk_nom_l >= (unsigned int) dml_pow(2, 23)) - disp_dlg_regs->refcyc_per_meta_chunk_nom_l = dml_pow(2, 23) - 1; - - if (dual_plane) { - disp_dlg_regs->refcyc_per_pte_group_nom_c = - (unsigned int) ((double) dpte_row_height_c / (double) vratio_c - * (double) htotal * ref_freq_to_pix_freq - / (double) dpte_groups_per_row_ub_c); - if (disp_dlg_regs->refcyc_per_pte_group_nom_c >= (unsigned int) dml_pow(2, 23)) - disp_dlg_regs->refcyc_per_pte_group_nom_c = dml_pow(2, 23) - 1; - - // TODO: Is this the right calculation? Does htotal need to be halved? - disp_dlg_regs->refcyc_per_meta_chunk_nom_c = - (unsigned int) ((double) meta_row_height_c / (double) vratio_c - * (double) htotal * ref_freq_to_pix_freq - / (double) meta_chunks_per_row_ub_c); - if (disp_dlg_regs->refcyc_per_meta_chunk_nom_c >= (unsigned int) dml_pow(2, 23)) - disp_dlg_regs->refcyc_per_meta_chunk_nom_c = dml_pow(2, 23) - 1; - } - - disp_dlg_regs->refcyc_per_line_delivery_pre_l = (unsigned int) dml_floor(refcyc_per_line_delivery_pre_l, - 1); - disp_dlg_regs->refcyc_per_line_delivery_l = (unsigned int) dml_floor(refcyc_per_line_delivery_l, - 1); - ASSERT(disp_dlg_regs->refcyc_per_line_delivery_pre_l < (unsigned int) dml_pow(2, 13)); - ASSERT(disp_dlg_regs->refcyc_per_line_delivery_l < (unsigned int) dml_pow(2, 13)); - - disp_dlg_regs->refcyc_per_line_delivery_pre_c = (unsigned int) dml_floor(refcyc_per_line_delivery_pre_c, - 1); - disp_dlg_regs->refcyc_per_line_delivery_c = (unsigned int) dml_floor(refcyc_per_line_delivery_c, - 1); - ASSERT(disp_dlg_regs->refcyc_per_line_delivery_pre_c < (unsigned int) dml_pow(2, 13)); - ASSERT(disp_dlg_regs->refcyc_per_line_delivery_c < (unsigned int) dml_pow(2, 13)); - - disp_dlg_regs->chunk_hdl_adjust_cur0 = 3; - disp_dlg_regs->dst_y_offset_cur0 = 0; - disp_dlg_regs->chunk_hdl_adjust_cur1 = 3; - disp_dlg_regs->dst_y_offset_cur1 = 0; - - disp_dlg_regs->xfc_reg_transfer_delay = xfc_transfer_delay; - disp_dlg_regs->xfc_reg_precharge_delay = xfc_precharge_delay; - disp_dlg_regs->xfc_reg_remote_surface_flip_latency = xfc_remote_surface_flip_latency; - disp_dlg_regs->xfc_reg_prefetch_margin = dml_ceil(xfc_prefetch_margin * refclk_freq_in_mhz, - 1); - - // slave has to have this value also set to off - if (src->xfc_enable && !src->xfc_slave) - disp_dlg_regs->dst_y_delta_drq_limit = dml_ceil(xfc_dst_y_delta_drq_limit, 1); - else - disp_dlg_regs->dst_y_delta_drq_limit = 0x7fff; // off - - disp_ttu_regs->refcyc_per_req_delivery_pre_l = (unsigned int) (refcyc_per_req_delivery_pre_l - * dml_pow(2, 10)); - disp_ttu_regs->refcyc_per_req_delivery_l = (unsigned int) (refcyc_per_req_delivery_l - * dml_pow(2, 10)); - disp_ttu_regs->refcyc_per_req_delivery_pre_c = (unsigned int) (refcyc_per_req_delivery_pre_c - * dml_pow(2, 10)); - disp_ttu_regs->refcyc_per_req_delivery_c = (unsigned int) (refcyc_per_req_delivery_c - * dml_pow(2, 10)); - disp_ttu_regs->refcyc_per_req_delivery_pre_cur0 = - (unsigned int) (refcyc_per_req_delivery_pre_cur0 * dml_pow(2, 10)); - disp_ttu_regs->refcyc_per_req_delivery_cur0 = (unsigned int) (refcyc_per_req_delivery_cur0 - * dml_pow(2, 10)); - disp_ttu_regs->refcyc_per_req_delivery_pre_cur1 = - (unsigned int) (refcyc_per_req_delivery_pre_cur1 * dml_pow(2, 10)); - disp_ttu_regs->refcyc_per_req_delivery_cur1 = (unsigned int) (refcyc_per_req_delivery_cur1 - * dml_pow(2, 10)); - disp_ttu_regs->qos_level_low_wm = 0; - ASSERT(disp_ttu_regs->qos_level_low_wm < dml_pow(2, 14)); - disp_ttu_regs->qos_level_high_wm = (unsigned int) (4.0 * (double) htotal - * ref_freq_to_pix_freq); - ASSERT(disp_ttu_regs->qos_level_high_wm < dml_pow(2, 14)); - - disp_ttu_regs->qos_level_flip = 14; - disp_ttu_regs->qos_level_fixed_l = 8; - disp_ttu_regs->qos_level_fixed_c = 8; - disp_ttu_regs->qos_level_fixed_cur0 = 8; - disp_ttu_regs->qos_ramp_disable_l = 0; - disp_ttu_regs->qos_ramp_disable_c = 0; - disp_ttu_regs->qos_ramp_disable_cur0 = 0; - - disp_ttu_regs->min_ttu_vblank = min_ttu_vblank * refclk_freq_in_mhz; - ASSERT(disp_ttu_regs->min_ttu_vblank < dml_pow(2, 24)); - - print__ttu_regs_st(mode_lib, *disp_ttu_regs); - print__dlg_regs_st(mode_lib, *disp_dlg_regs); -} - -void dml_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib, - display_dlg_regs_st *dlg_regs, - display_ttu_regs_st *ttu_regs, - display_e2e_pipe_params_st *e2e_pipe_param, - const unsigned int num_pipes, - const unsigned int pipe_idx, - const bool cstate_en, - const bool pstate_en, - const bool vm_en, - const bool ignore_viewport_pos, - const bool immediate_flip_support) -{ - display_rq_params_st rq_param = {0}; - display_dlg_sys_params_st dlg_sys_param = {0}; - - // Get watermark and Tex. - dlg_sys_param.t_urg_wm_us = get_wm_urgent(mode_lib, e2e_pipe_param, num_pipes); - dlg_sys_param.deepsleep_dcfclk_mhz = get_clk_dcf_deepsleep(mode_lib, - e2e_pipe_param, - num_pipes); - dlg_sys_param.t_extra_us = get_urgent_extra_latency(mode_lib, e2e_pipe_param, num_pipes); - dlg_sys_param.mem_trip_us = get_wm_memory_trip(mode_lib, e2e_pipe_param, num_pipes); - dlg_sys_param.t_mclk_wm_us = get_wm_dram_clock_change(mode_lib, e2e_pipe_param, num_pipes); - dlg_sys_param.t_sr_wm_us = get_wm_stutter_enter_exit(mode_lib, e2e_pipe_param, num_pipes); - dlg_sys_param.total_flip_bw = get_total_immediate_flip_bw(mode_lib, - e2e_pipe_param, - num_pipes); - dlg_sys_param.total_flip_bytes = get_total_immediate_flip_bytes(mode_lib, - e2e_pipe_param, - num_pipes); - dlg_sys_param.t_srx_delay_us = mode_lib->ip.dcfclk_cstate_latency - / dlg_sys_param.deepsleep_dcfclk_mhz; // TODO: Deprecated - - print__dlg_sys_params_st(mode_lib, dlg_sys_param); - - // system parameter calculation done - - dml_print("DML_DLG: Calculation for pipe[%d] start\n\n", pipe_idx); - dml_rq_dlg_get_rq_params(mode_lib, &rq_param, e2e_pipe_param[pipe_idx].pipe.src); - dml_rq_dlg_get_dlg_params(mode_lib, - e2e_pipe_param, - num_pipes, - pipe_idx, - dlg_regs, - ttu_regs, - rq_param.dlg, - dlg_sys_param, - cstate_en, - pstate_en, - vm_en, - ignore_viewport_pos, - immediate_flip_support); - dml_print("DML_DLG: Calculation for pipe[%d] end\n", pipe_idx); -} - -void dml_rq_dlg_get_arb_params(struct display_mode_lib *mode_lib, display_arb_params_st *arb_param) -{ - memset(arb_param, 0, sizeof(*arb_param)); - arb_param->max_req_outstanding = 256; - arb_param->min_req_outstanding = 68; - arb_param->sat_level_us = 60; -} - -void calculate_ttu_cursor(struct display_mode_lib *mode_lib, - double *refcyc_per_req_delivery_pre_cur, - double *refcyc_per_req_delivery_cur, - double refclk_freq_in_mhz, - double ref_freq_to_pix_freq, - double hscale_pixel_rate_l, - double hscl_ratio, - double vratio_pre_l, - double vratio_l, - unsigned int cur_width, - enum cursor_bpp cur_bpp) -{ - unsigned int cur_src_width = cur_width; - unsigned int cur_req_size = 0; - unsigned int cur_req_width = 0; - double cur_width_ub = 0.0; - double cur_req_per_width = 0.0; - double hactive_cur = 0.0; - - ASSERT(cur_src_width <= 256); - - *refcyc_per_req_delivery_pre_cur = 0.0; - *refcyc_per_req_delivery_cur = 0.0; - if (cur_src_width > 0) { - unsigned int cur_bit_per_pixel = 0; - - if (cur_bpp == dm_cur_2bit) { - cur_req_size = 64; // byte - cur_bit_per_pixel = 2; - } else { // 32bit - cur_bit_per_pixel = 32; - if (cur_src_width >= 1 && cur_src_width <= 16) - cur_req_size = 64; - else if (cur_src_width >= 17 && cur_src_width <= 31) - cur_req_size = 128; - else - cur_req_size = 256; - } - - cur_req_width = (double) cur_req_size / ((double) cur_bit_per_pixel / 8.0); - cur_width_ub = dml_ceil((double) cur_src_width / (double) cur_req_width, 1) - * (double) cur_req_width; - cur_req_per_width = cur_width_ub / (double) cur_req_width; - hactive_cur = (double) cur_src_width / hscl_ratio; // FIXME: oswin to think about what to do for cursor - - if (vratio_pre_l <= 1.0) { - *refcyc_per_req_delivery_pre_cur = hactive_cur * ref_freq_to_pix_freq - / (double) cur_req_per_width; - } else { - *refcyc_per_req_delivery_pre_cur = (double) refclk_freq_in_mhz - * (double) cur_src_width / hscale_pixel_rate_l - / (double) cur_req_per_width; - } - - ASSERT(*refcyc_per_req_delivery_pre_cur < dml_pow(2, 13)); - - if (vratio_l <= 1.0) { - *refcyc_per_req_delivery_cur = hactive_cur * ref_freq_to_pix_freq - / (double) cur_req_per_width; - } else { - *refcyc_per_req_delivery_cur = (double) refclk_freq_in_mhz - * (double) cur_src_width / hscale_pixel_rate_l - / (double) cur_req_per_width; - } - - dml_print("DML_DLG: %s: cur_req_width = %d\n", - __func__, - cur_req_width); - dml_print("DML_DLG: %s: cur_width_ub = %3.2f\n", - __func__, - cur_width_ub); - dml_print("DML_DLG: %s: cur_req_per_width = %3.2f\n", - __func__, - cur_req_per_width); - dml_print("DML_DLG: %s: hactive_cur = %3.2f\n", - __func__, - hactive_cur); - dml_print("DML_DLG: %s: refcyc_per_req_delivery_pre_cur = %3.2f\n", - __func__, - *refcyc_per_req_delivery_pre_cur); - dml_print("DML_DLG: %s: refcyc_per_req_delivery_cur = %3.2f\n", - __func__, - *refcyc_per_req_delivery_cur); - - ASSERT(*refcyc_per_req_delivery_cur < dml_pow(2, 13)); - } -} - -unsigned int dml_rq_dlg_get_calculated_vstartup(struct display_mode_lib *mode_lib, - display_e2e_pipe_params_st *e2e_pipe_param, - const unsigned int num_pipes, - const unsigned int pipe_idx) -{ - unsigned int vstartup_pipe[DC__NUM_PIPES__MAX]; - bool visited[DC__NUM_PIPES__MAX]; - unsigned int pipe_inst = 0; - unsigned int i, j, k; - - for (k = 0; k < num_pipes; ++k) - visited[k] = false; - - for (i = 0; i < num_pipes; i++) { - if (e2e_pipe_param[i].pipe.src.is_hsplit && !visited[i]) { - unsigned int grp = e2e_pipe_param[i].pipe.src.hsplit_grp; - - for (j = i; j < num_pipes; j++) { - if (e2e_pipe_param[j].pipe.src.hsplit_grp == grp - && e2e_pipe_param[j].pipe.src.is_hsplit - && !visited[j]) { - vstartup_pipe[j] = get_vstartup_calculated(mode_lib, - e2e_pipe_param, - num_pipes, - pipe_inst); - visited[j] = true; - } - } - - pipe_inst++; - } - - if (!visited[i]) { - vstartup_pipe[i] = get_vstartup_calculated(mode_lib, - e2e_pipe_param, - num_pipes, - pipe_inst); - visited[i] = true; - pipe_inst++; - } - } - - return vstartup_pipe[pipe_idx]; - -} - -void dml_rq_dlg_get_row_heights(struct display_mode_lib *mode_lib, - unsigned int *o_dpte_row_height, - unsigned int *o_meta_row_height, - unsigned int vp_width, - unsigned int data_pitch, - int source_format, - int tiling, - int macro_tile_size, - int source_scan, - int is_chroma) -{ - display_data_rq_dlg_params_st rq_dlg_param; - display_data_rq_misc_params_st rq_misc_param; - display_data_rq_sizing_params_st rq_sizing_param; - - get_meta_and_pte_attr(mode_lib, - &rq_dlg_param, - &rq_misc_param, - &rq_sizing_param, - vp_width, - 0, // dummy - data_pitch, - 0, // dummy - source_format, - tiling, - macro_tile_size, - source_scan, - is_chroma); - - *o_dpte_row_height = rq_dlg_param.dpte_row_height; - *o_meta_row_height = rq_dlg_param.meta_row_height; -} diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_calc.h b/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_calc.h deleted file mode 100644 index efdd4c73d8f3..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_calc.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2017 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DML2_DISPLAY_RQ_DLG_CALC_H__ -#define __DML2_DISPLAY_RQ_DLG_CALC_H__ - -#include "dml_common_defs.h" -#include "display_rq_dlg_helpers.h" - -struct display_mode_lib; - -// Function: dml_rq_dlg_get_rq_params -// Calculate requestor related parameters that register definition agnostic -// (i.e. this layer does try to separate real values from register definition) -// Input: -// pipe_src_param - pipe source configuration (e.g. vp, pitch, etc.) -// Output: -// rq_param - values that can be used to setup RQ (e.g. swath_height, plane1_addr, etc.) -// -void dml_rq_dlg_get_rq_params( - struct display_mode_lib *mode_lib, - display_rq_params_st *rq_param, - const display_pipe_source_params_st pipe_src_param); - -// Function: dml_rq_dlg_get_rq_reg -// Main entry point for test to get the register values out of this DML class. -// This function calls and fucntions to calculate -// and then populate the rq_regs struct -// Input: -// pipe_src_param - pipe source configuration (e.g. vp, pitch, etc.) -// Output: -// rq_regs - struct that holds all the RQ registers field value. -// See also: -void dml_rq_dlg_get_rq_reg( - struct display_mode_lib *mode_lib, - display_rq_regs_st *rq_regs, - const display_pipe_source_params_st pipe_src_param); - -// Function: dml_rq_dlg_get_dlg_params -// Calculate deadline related parameters -// -void dml_rq_dlg_get_dlg_params(struct display_mode_lib *mode_lib, - const display_e2e_pipe_params_st *e2e_pipe_param, - const unsigned int num_pipes, - const unsigned int pipe_idx, - display_dlg_regs_st *disp_dlg_regs, - display_ttu_regs_st *disp_ttu_regs, - const display_rq_dlg_params_st rq_dlg_param, - const display_dlg_sys_params_st dlg_sys_param, - const bool cstate_en, - const bool pstate_en, - const bool vm_en, - const bool ignore_viewport_pos, - const bool immediate_flip_support); - -// Function: dml_rq_dlg_get_dlg_param_prefetch -// For flip_bw programming guide change, now dml needs to calculate the flip_bytes and prefetch_bw -// for ALL pipes and use this info to calculate the prefetch programming. -// Output: prefetch_param.prefetch_bw and flip_bytes -void dml_rq_dlg_get_dlg_params_prefetch( - struct display_mode_lib *mode_lib, - display_dlg_prefetch_param_st *prefetch_param, - display_rq_dlg_params_st rq_dlg_param, - display_dlg_sys_params_st dlg_sys_param, - display_e2e_pipe_params_st e2e_pipe_param, - const bool cstate_en, - const bool pstate_en, - const bool vm_en); - -// Function: dml_rq_dlg_get_dlg_reg -// Calculate and return DLG and TTU register struct given the system setting -// Output: -// dlg_regs - output DLG register struct -// ttu_regs - output DLG TTU register struct -// Input: -// e2e_pipe_param - "compacted" array of e2e pipe param struct -// num_pipes - num of active "pipe" or "route" -// pipe_idx - index that identifies the e2e_pipe_param that corresponding to this dlg -// cstate - 0: when calculate min_ttu_vblank it is assumed cstate is not required. 1: Normal mode, cstate is considered. -// Added for legacy or unrealistic timing tests. -void dml_rq_dlg_get_dlg_reg( - struct display_mode_lib *mode_lib, - display_dlg_regs_st *dlg_regs, - display_ttu_regs_st *ttu_regs, - display_e2e_pipe_params_st *e2e_pipe_param, - const unsigned int num_pipes, - const unsigned int pipe_idx, - const bool cstate_en, - const bool pstate_en, - const bool vm_en, - const bool ignore_viewport_pos, - const bool immediate_flip_support); - -// Function: dml_rq_dlg_get_calculated_vstartup -// Calculate and return vstartup -// Output: -// unsigned int vstartup -// Input: -// e2e_pipe_param - "compacted" array of e2e pipe param struct -// num_pipes - num of active "pipe" or "route" -// pipe_idx - index that identifies the e2e_pipe_param that corresponding to this dlg -// NOTE: this MUST be called after setting the prefetch mode! -unsigned int dml_rq_dlg_get_calculated_vstartup( - struct display_mode_lib *mode_lib, - display_e2e_pipe_params_st *e2e_pipe_param, - const unsigned int num_pipes, - const unsigned int pipe_idx); - -// Function: dml_rq_dlg_get_row_heights -// Calculate dpte and meta row heights -void dml_rq_dlg_get_row_heights( - struct display_mode_lib *mode_lib, - unsigned int *o_dpte_row_height, - unsigned int *o_meta_row_height, - unsigned int vp_width, - unsigned int data_pitch, - int source_format, - int tiling, - int macro_tile_size, - int source_scan, - int is_chroma); - -// Function: dml_rq_dlg_get_arb_params -void dml_rq_dlg_get_arb_params(struct display_mode_lib *mode_lib, display_arb_params_st *arb_param); - -#endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.h b/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.h index 987d7671cd0f..304164986bd8 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.h @@ -27,10 +27,11 @@ #define __DISPLAY_RQ_DLG_CALC_H__ #include "dml_common_defs.h" -#include "display_rq_dlg_helpers.h" struct display_mode_lib; +#include "display_rq_dlg_helpers.h" + void dml1_extract_rq_regs( struct display_mode_lib *mode_lib, struct _vcs_dpi_display_rq_regs_st *rq_regs, diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_factory_dce120.c b/drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_factory_dce120.c index 0c2314efb47e..ea3f888e5c65 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_factory_dce120.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_factory_dce120.c @@ -36,7 +36,8 @@ #include "dce/dce_12_0_offset.h" #include "dce/dce_12_0_sh_mask.h" -#include "soc15ip.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" #define block HPD #define reg_num 0 diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_translate_dce120.c b/drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_translate_dce120.c index a225b02cc779..39ef5c7dad97 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_translate_dce120.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_translate_dce120.c @@ -35,7 +35,8 @@ #include "dce/dce_12_0_offset.h" #include "dce/dce_12_0_sh_mask.h" -#include "soc15ip.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" /* begin ********************* * macros to expend register list macro defined in HW object header file */ diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_factory_dcn10.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_factory_dcn10.c index 5235f69f0602..32aa47a04a0d 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_factory_dcn10.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_factory_dcn10.c @@ -36,7 +36,8 @@ #include "dcn/dcn_1_0_offset.h" #include "dcn/dcn_1_0_sh_mask.h" -#include "soc15ip.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" #define block HPD #define reg_num 0 diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_translate_dcn10.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_translate_dcn10.c index 347864810d01..fecc8688048d 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_translate_dcn10.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_translate_dcn10.c @@ -35,7 +35,8 @@ #include "dcn/dcn_1_0_offset.h" #include "dcn/dcn_1_0_sh_mask.h" -#include "soc15ip.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" /* begin ********************* * macros to expend register list macro defined in HW object header file */ diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c index fc7a7d4ebca5..0b1db48fef36 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c @@ -284,6 +284,14 @@ static bool read_command( msleep(engine->delay); } while (ctx.operation_succeeded && !ctx.transaction_complete); + if (request->payload.address_space == + I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { + dm_logger_write(engine->base.ctx->logger, LOG_I2C_AUX, "READ: addr:0x%x value:0x%x Result:%d", + request->payload.address, + request->payload.data[0], + ctx.operation_succeeded); + } + return ctx.operation_succeeded; } @@ -484,6 +492,14 @@ static bool write_command( msleep(engine->delay); } while (ctx.operation_succeeded && !ctx.transaction_complete); + if (request->payload.address_space == + I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { + dm_logger_write(engine->base.ctx->logger, LOG_I2C_AUX, "WRITE: addr:0x%x value:0x%x Result:%d", + request->payload.address, + request->payload.data[0], + ctx.operation_succeeded); + } + return ctx.operation_succeeded; } diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c index 81f9f3e34c10..5f47f6c007ac 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c @@ -441,10 +441,6 @@ static void construct( static void destruct( struct aux_engine_dce110 *engine) { - struct aux_engine_dce110 *aux110 = engine; -/*temp w/a, to do*/ - REG_UPDATE(AUX_ARB_CONTROL, AUX_DMCU_DONE_USING_AUX_REG, 1); - REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1); dal_aux_engine_destruct(&engine->base); } diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.c index a401636bf3f8..0e7b18260027 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.c @@ -38,7 +38,8 @@ #include "dce/dce_12_0_offset.h" #include "dce/dce_12_0_sh_mask.h" -#include "soc15ip.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" /* begin ********************* * macros to expend register list macro defined in HW object header file */ diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.c b/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.c index bed7cc3e77de..e44a8901f38b 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.c @@ -38,7 +38,8 @@ #include "dcn/dcn_1_0_offset.h" #include "dcn/dcn_1_0_sh_mask.h" -#include "soc15ip.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" /* begin ********************* * macros to expend register list macro defined in HW object header file */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index d6971054ec07..5509e13e7edf 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -119,6 +119,11 @@ struct resource_funcs { struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream); + + enum dc_status (*remove_stream_from_ctx)( + struct dc *dc, + struct dc_state *new_ctx, + struct dc_stream_state *stream); }; struct audio_support{ @@ -148,6 +153,7 @@ struct resource_pool { unsigned int underlay_pipe_index; unsigned int stream_enc_count; unsigned int ref_clock_inKhz; + unsigned int timing_generator_count; /* * reserved clock source for DP @@ -188,6 +194,7 @@ struct plane_resource { struct input_pixel_processor *ipp; struct transform *xfm; struct dpp *dpp; + uint8_t mpcc_inst; }; struct pipe_ctx { diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h index 616c73e2b0bd..2f783c650084 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h @@ -53,7 +53,7 @@ bool perform_link_training_with_retries( bool is_mst_supported(struct dc_link *link); -void detect_dp_sink_caps(struct dc_link *link); +bool detect_dp_sink_caps(struct dc_link *link); void detect_edp_sink_caps(struct dc_link *link); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h index ce206355461b..de60f940030d 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h @@ -32,13 +32,6 @@ enum dmcu_state { DMCU_RUNNING = 1 }; -struct dmcu_version { - unsigned int day; - unsigned int month; - unsigned int year; - unsigned int interface_version; -}; - struct dmcu { struct dc_context *ctx; const struct dmcu_funcs *funcs; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h index 25edbde6163e..78abc16ec4dc 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h @@ -131,6 +131,11 @@ struct dpp_funcs { uint32_t width ); + void (*dpp_dppclk_control)( + struct dpp *dpp_base, + bool dppclk_div, + bool enable); + }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h index b7c7e70022e4..9ced254e652c 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h @@ -119,6 +119,9 @@ struct hubp_funcs { void (*hubp_disconnect)(struct hubp *hubp); + void (*hubp_clk_cntl)(struct hubp *hubp, bool enable); + void (*hubp_vtg_sel)(struct hubp *hubp, uint32_t otg_inst); + }; #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h index e3f0b4056318..b22158190262 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h @@ -136,7 +136,7 @@ struct out_csc_color_matrix { enum opp_regamma { OPP_REGAMMA_BYPASS = 0, OPP_REGAMMA_SRGB, - OPP_REGAMMA_3_6, + OPP_REGAMMA_XVYCC, OPP_REGAMMA_USER }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h index 0fd329deacd8..54d8a1386142 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h @@ -123,8 +123,7 @@ struct link_encoder_funcs { void (*enable_tmds_output)(struct link_encoder *enc, enum clock_source_id clock_source, enum dc_color_depth color_depth, - bool hdmi, - bool dual_link, + enum signal_type signal, uint32_t pixel_clock); void (*enable_dp_output)(struct link_encoder *enc, const struct dc_link_settings *link_settings, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h index ab8fb77f1ae5..d974d9e18612 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h @@ -297,6 +297,10 @@ struct opp_funcs { bool enable, const struct dc_crtc_timing *timing); + void (*opp_pipe_clock_control)( + struct output_pixel_processor *opp, + bool enable); + }; #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h index ec312f1a3e55..3217b5bf6c7a 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h @@ -92,6 +92,36 @@ struct crtc_stereo_flags { uint8_t DISABLE_STEREO_DP_SYNC : 1; }; +enum crc_selection { + /* Order must match values expected by hardware */ + UNION_WINDOW_A_B = 0, + UNION_WINDOW_A_NOT_B, + UNION_WINDOW_NOT_A_B, + UNION_WINDOW_NOT_A_NOT_B, + INTERSECT_WINDOW_A_B, + INTERSECT_WINDOW_A_NOT_B, + INTERSECT_WINDOW_NOT_A_B, + INTERSECT_WINDOW_NOT_A_NOT_B, +}; + +struct crc_params { + /* Regions used to calculate CRC*/ + uint16_t windowa_x_start; + uint16_t windowa_x_end; + uint16_t windowa_y_start; + uint16_t windowa_y_end; + + uint16_t windowb_x_start; + uint16_t windowb_x_end; + uint16_t windowb_y_start; + uint16_t windowb_y_end; + + enum crc_selection selection; + + bool continuous_mode; + bool enable; +}; + struct timing_generator { const struct timing_generator_funcs *funcs; struct dc_bios *bp; @@ -173,6 +203,21 @@ struct timing_generator_funcs { bool (*is_tg_enabled)(struct timing_generator *tg); bool (*is_optc_underflow_occurred)(struct timing_generator *tg); void (*clear_optc_underflow)(struct timing_generator *tg); + + /** + * Configure CRCs for the given timing generator. Return false if TG is + * not on. + */ + bool (*configure_crc)(struct timing_generator *tg, + const struct crc_params *params); + + /** + * Get CRCs for the given timing generator. Return false if CRCs are + * not enabled (via configure_crc). + */ + bool (*get_crc)(struct timing_generator *tg, + uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb); + }; #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h b/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h index 6f6c02b89f90..c5b3623bcbd9 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h @@ -30,7 +30,7 @@ #include "dc_hw_types.h" #include "fixed31_32.h" -#define CSC_TEMPERATURE_MATRIX_SIZE 9 +#define CSC_TEMPERATURE_MATRIX_SIZE 12 struct bit_depth_reduction_params; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h index 4c0aa56f7bae..e764cbad881b 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -114,7 +114,7 @@ struct hw_sequencer_funcs { void (*power_down)(struct dc *dc); - void (*enable_accelerated_mode)(struct dc *dc); + void (*enable_accelerated_mode)(struct dc *dc, struct dc_state *context); void (*enable_timing_synchronization)( struct dc *dc, @@ -149,6 +149,7 @@ struct hw_sequencer_funcs { void (*unblank_stream)(struct pipe_ctx *pipe_ctx, struct dc_link_settings *link_settings); + void (*blank_stream)(struct pipe_ctx *pipe_ctx); void (*pipe_control_lock)( struct dc *dc, struct pipe_ctx *pipe, @@ -198,6 +199,8 @@ struct hw_sequencer_funcs { bool enable); void (*edp_wait_for_hpd_ready)(struct dc_link *link, bool power_up); + void (*set_cursor_position)(struct pipe_ctx *pipe); + void (*set_cursor_attribute)(struct pipe_ctx *pipe); }; void color_space_to_black_color( diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h index f2b8c9a376d5..30be7bb4a01a 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h @@ -51,6 +51,8 @@ void dp_enable_link_phy( const struct dc_link_settings *link_settings); void dp_receiver_power_ctrl(struct dc_link *link, bool on); +bool edp_receiver_ready_T9(struct dc_link *link); +bool edp_receiver_ready_T7(struct dc_link *link); void dp_disable_link_phy(struct dc_link *link, enum signal_type signal); diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.c b/drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.c index 66d52580e29f..1ea7256ec89b 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.c @@ -32,7 +32,8 @@ #include "dce/dce_12_0_offset.h" #include "dce/dce_12_0_sh_mask.h" -#include "soc15ip.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" #include "ivsrcid/ivsrcid_vislands30.h" diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c b/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c index 7f7db66c48b0..e04ae49243f6 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c @@ -31,7 +31,8 @@ #include "dcn/dcn_1_0_offset.h" #include "dcn/dcn_1_0_sh_mask.h" -#include "soc15ip.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" #include "irq_service_dcn10.h" diff --git a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c index 57a54a7b89e5..1c079ba37c30 100644 --- a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c @@ -42,8 +42,7 @@ static void virtual_link_encoder_enable_tmds_output( struct link_encoder *enc, enum clock_source_id clock_source, enum dc_color_depth color_depth, - bool hdmi, - bool dual_link, + enum signal_type signal, uint32_t pixel_clock) {} static void virtual_link_encoder_enable_dp_output( diff --git a/drivers/gpu/drm/amd/display/include/dal_asic_id.h b/drivers/gpu/drm/amd/display/include/dal_asic_id.h index 7abe663ecc6e..9831cb5eaa7c 100644 --- a/drivers/gpu/drm/amd/display/include/dal_asic_id.h +++ b/drivers/gpu/drm/amd/display/include/dal_asic_id.h @@ -109,6 +109,14 @@ #define ASIC_REV_IS_STONEY(rev) \ ((rev >= STONEY_A0) && (rev < CZ_UNKNOWN)) +/* DCE12 */ + +#define AI_GREENLAND_P_A0 1 +#define AI_GREENLAND_P_A1 2 + +#define ASICREV_IS_GREENLAND_M(eChipRev) (eChipRev < AI_UNKNOWN) +#define ASICREV_IS_GREENLAND_P(eChipRev) (eChipRev < AI_UNKNOWN) + /* DCN1_0 */ #define INTERNAL_REV_RAVEN_A0 0x00 /* First spin of Raven */ #define RAVEN_A0 0x01 diff --git a/drivers/gpu/drm/amd/display/include/fixed31_32.h b/drivers/gpu/drm/amd/display/include/fixed31_32.h index 4badaedbaadd..0de258622c12 100644 --- a/drivers/gpu/drm/amd/display/include/fixed31_32.h +++ b/drivers/gpu/drm/amd/display/include/fixed31_32.h @@ -470,4 +470,7 @@ uint32_t dal_fixed31_32_clamp_u0d14( uint32_t dal_fixed31_32_clamp_u0d10( struct fixed31_32 arg); +int32_t dal_fixed31_32_s4d19( + struct fixed31_32 arg); + #endif diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h index 7a9b43f84a31..36bbad594267 100644 --- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h @@ -419,11 +419,6 @@ struct bios_event_info { bool backlight_changed; }; -enum { - HDMI_PIXEL_CLOCK_IN_KHZ_297 = 297000, - TMDS_PIXEL_CLOCK_IN_KHZ_165 = 165000 -}; - /* * DFS-bypass flag */ diff --git a/drivers/gpu/drm/amd/display/include/signal_types.h b/drivers/gpu/drm/amd/display/include/signal_types.h index b5ebde642207..199c5db67cbc 100644 --- a/drivers/gpu/drm/amd/display/include/signal_types.h +++ b/drivers/gpu/drm/amd/display/include/signal_types.h @@ -26,6 +26,11 @@ #ifndef __DC_SIGNAL_TYPES_H__ #define __DC_SIGNAL_TYPES_H__ +/* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */ +#define TMDS_MIN_PIXEL_CLOCK 25000 +/* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */ +#define TMDS_MAX_PIXEL_CLOCK 165000 + enum signal_type { SIGNAL_TYPE_NONE = 0L, /* no signal */ SIGNAL_TYPE_DVI_SINGLE_LINK = (1 << 0), diff --git a/drivers/gpu/drm/amd/display/modules/color/Makefile b/drivers/gpu/drm/amd/display/modules/color/Makefile new file mode 100644 index 000000000000..65c33a76951a --- /dev/null +++ b/drivers/gpu/drm/amd/display/modules/color/Makefile @@ -0,0 +1,31 @@ +# +# Copyright 2018 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# +# Makefile for the color sub-module of DAL. +# + +MOD_COLOR = color_gamma.o + +AMD_DAL_MOD_COLOR = $(addprefix $(AMDDALPATH)/modules/color/,$(MOD_COLOR)) +#$(info ************ DAL COLOR MODULE MAKEFILE ************) + +AMD_DISPLAY_FILES += $(AMD_DAL_MOD_COLOR) diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c new file mode 100644 index 000000000000..a5fd14a4016f --- /dev/null +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -0,0 +1,1403 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dc.h" +#include "opp.h" +#include "color_gamma.h" + + +#define NUM_PTS_IN_REGION 16 +#define NUM_REGIONS 32 +#define NUM_DEGAMMA_REGIONS 12 +#define MAX_HW_POINTS (NUM_PTS_IN_REGION*NUM_REGIONS) +#define MAX_HW_DEGAMMA_POINTS (NUM_PTS_IN_REGION*NUM_DEGAMMA_REGIONS) + +static struct hw_x_point coordinates_x[MAX_HW_POINTS + 2]; +static struct hw_x_point degamma_coordinates_x[MAX_HW_DEGAMMA_POINTS + 2]; + +static struct fixed31_32 pq_table[MAX_HW_POINTS + 2]; +static struct fixed31_32 de_pq_table[MAX_HW_DEGAMMA_POINTS + 2]; + +static bool pq_initialized; /* = false; */ +static bool de_pq_initialized; /* = false; */ + +/* one-time setup of X points */ +void setup_x_points_distribution(void) +{ + struct fixed31_32 region_size = dal_fixed31_32_from_int(128); + int32_t segment; + uint32_t seg_offset; + uint32_t index; + struct fixed31_32 increment; + + coordinates_x[MAX_HW_POINTS].x = region_size; + coordinates_x[MAX_HW_POINTS + 1].x = region_size; + + for (segment = 6; segment > (6 - NUM_REGIONS); segment--) { + region_size = dal_fixed31_32_div_int(region_size, 2); + increment = dal_fixed31_32_div_int(region_size, + NUM_PTS_IN_REGION); + seg_offset = (segment + (NUM_REGIONS - 7)) * NUM_PTS_IN_REGION; + coordinates_x[seg_offset].x = region_size; + + for (index = seg_offset + 1; + index < seg_offset + NUM_PTS_IN_REGION; + index++) { + coordinates_x[index].x = dal_fixed31_32_add + (coordinates_x[index-1].x, increment); + } + } + + region_size = dal_fixed31_32_from_int(1); + degamma_coordinates_x[MAX_HW_DEGAMMA_POINTS].x = region_size; + degamma_coordinates_x[MAX_HW_DEGAMMA_POINTS + 1].x = region_size; + + for (segment = -1; segment > -(NUM_DEGAMMA_REGIONS + 1); segment--) { + region_size = dal_fixed31_32_div_int(region_size, 2); + increment = dal_fixed31_32_div_int(region_size, + NUM_PTS_IN_REGION); + seg_offset = (segment + NUM_DEGAMMA_REGIONS) * NUM_PTS_IN_REGION; + degamma_coordinates_x[seg_offset].x = region_size; + + for (index = seg_offset + 1; + index < seg_offset + NUM_PTS_IN_REGION; + index++) { + degamma_coordinates_x[index].x = dal_fixed31_32_add + (degamma_coordinates_x[index-1].x, increment); + } + } + +} + +static void compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) +{ + /* consts for PQ gamma formula. */ + const struct fixed31_32 m1 = + dal_fixed31_32_from_fraction(159301758, 1000000000); + const struct fixed31_32 m2 = + dal_fixed31_32_from_fraction(7884375, 100000); + const struct fixed31_32 c1 = + dal_fixed31_32_from_fraction(8359375, 10000000); + const struct fixed31_32 c2 = + dal_fixed31_32_from_fraction(188515625, 10000000); + const struct fixed31_32 c3 = + dal_fixed31_32_from_fraction(186875, 10000); + + struct fixed31_32 l_pow_m1; + struct fixed31_32 base; + + if (dal_fixed31_32_lt(in_x, dal_fixed31_32_zero)) + in_x = dal_fixed31_32_zero; + + l_pow_m1 = dal_fixed31_32_pow(in_x, m1); + base = dal_fixed31_32_div( + dal_fixed31_32_add(c1, + (dal_fixed31_32_mul(c2, l_pow_m1))), + dal_fixed31_32_add(dal_fixed31_32_one, + (dal_fixed31_32_mul(c3, l_pow_m1)))); + *out_y = dal_fixed31_32_pow(base, m2); +} + +static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) +{ + /* consts for dePQ gamma formula. */ + const struct fixed31_32 m1 = + dal_fixed31_32_from_fraction(159301758, 1000000000); + const struct fixed31_32 m2 = + dal_fixed31_32_from_fraction(7884375, 100000); + const struct fixed31_32 c1 = + dal_fixed31_32_from_fraction(8359375, 10000000); + const struct fixed31_32 c2 = + dal_fixed31_32_from_fraction(188515625, 10000000); + const struct fixed31_32 c3 = + dal_fixed31_32_from_fraction(186875, 10000); + + struct fixed31_32 l_pow_m1; + struct fixed31_32 base, div; + + + if (dal_fixed31_32_lt(in_x, dal_fixed31_32_zero)) + in_x = dal_fixed31_32_zero; + + l_pow_m1 = dal_fixed31_32_pow(in_x, + dal_fixed31_32_div(dal_fixed31_32_one, m2)); + base = dal_fixed31_32_sub(l_pow_m1, c1); + + if (dal_fixed31_32_lt(base, dal_fixed31_32_zero)) + base = dal_fixed31_32_zero; + + div = dal_fixed31_32_sub(c2, dal_fixed31_32_mul(c3, l_pow_m1)); + + *out_y = dal_fixed31_32_pow(dal_fixed31_32_div(base, div), + dal_fixed31_32_div(dal_fixed31_32_one, m1)); + +} +/* one-time pre-compute PQ values - only for sdr_white_level 80 */ +void precompute_pq(void) +{ + int i; + struct fixed31_32 x; + const struct hw_x_point *coord_x = coordinates_x + 32; + struct fixed31_32 scaling_factor = + dal_fixed31_32_from_fraction(80, 10000); + + /* pow function has problems with arguments too small */ + for (i = 0; i < 32; i++) + pq_table[i] = dal_fixed31_32_zero; + + for (i = 32; i <= MAX_HW_POINTS; i++) { + x = dal_fixed31_32_mul(coord_x->x, scaling_factor); + compute_pq(x, &pq_table[i]); + ++coord_x; + } +} + +/* one-time pre-compute dePQ values - only for max pixel value 125 FP16 */ +void precompute_de_pq(void) +{ + int i; + struct fixed31_32 y; + const struct hw_x_point *coord_x = degamma_coordinates_x; + struct fixed31_32 scaling_factor = dal_fixed31_32_from_int(125); + + + for (i = 0; i <= MAX_HW_DEGAMMA_POINTS; i++) { + compute_de_pq(coord_x->x, &y); + de_pq_table[i] = dal_fixed31_32_mul(y, scaling_factor); + ++coord_x; + } +} +struct dividers { + struct fixed31_32 divider1; + struct fixed31_32 divider2; + struct fixed31_32 divider3; +}; + +static void build_coefficients(struct gamma_coefficients *coefficients, bool is_2_4) +{ + static const int32_t numerator01[] = { 31308, 180000}; + static const int32_t numerator02[] = { 12920, 4500}; + static const int32_t numerator03[] = { 55, 99}; + static const int32_t numerator04[] = { 55, 99}; + static const int32_t numerator05[] = { 2400, 2200}; + + uint32_t i = 0; + uint32_t index = is_2_4 == true ? 0:1; + + do { + coefficients->a0[i] = dal_fixed31_32_from_fraction( + numerator01[index], 10000000); + coefficients->a1[i] = dal_fixed31_32_from_fraction( + numerator02[index], 1000); + coefficients->a2[i] = dal_fixed31_32_from_fraction( + numerator03[index], 1000); + coefficients->a3[i] = dal_fixed31_32_from_fraction( + numerator04[index], 1000); + coefficients->user_gamma[i] = dal_fixed31_32_from_fraction( + numerator05[index], 1000); + + ++i; + } while (i != ARRAY_SIZE(coefficients->a0)); +} + +static struct fixed31_32 translate_from_linear_space( + struct fixed31_32 arg, + struct fixed31_32 a0, + struct fixed31_32 a1, + struct fixed31_32 a2, + struct fixed31_32 a3, + struct fixed31_32 gamma) +{ + const struct fixed31_32 one = dal_fixed31_32_from_int(1); + + if (dal_fixed31_32_lt(one, arg)) + return one; + + if (dal_fixed31_32_le(arg, dal_fixed31_32_neg(a0))) + return dal_fixed31_32_sub( + a2, + dal_fixed31_32_mul( + dal_fixed31_32_add( + one, + a3), + dal_fixed31_32_pow( + dal_fixed31_32_neg(arg), + dal_fixed31_32_recip(gamma)))); + else if (dal_fixed31_32_le(a0, arg)) + return dal_fixed31_32_sub( + dal_fixed31_32_mul( + dal_fixed31_32_add( + one, + a3), + dal_fixed31_32_pow( + arg, + dal_fixed31_32_recip(gamma))), + a2); + else + return dal_fixed31_32_mul( + arg, + a1); +} + +static struct fixed31_32 translate_to_linear_space( + struct fixed31_32 arg, + struct fixed31_32 a0, + struct fixed31_32 a1, + struct fixed31_32 a2, + struct fixed31_32 a3, + struct fixed31_32 gamma) +{ + struct fixed31_32 linear; + + a0 = dal_fixed31_32_mul(a0, a1); + if (dal_fixed31_32_le(arg, dal_fixed31_32_neg(a0))) + + linear = dal_fixed31_32_neg( + dal_fixed31_32_pow( + dal_fixed31_32_div( + dal_fixed31_32_sub(a2, arg), + dal_fixed31_32_add( + dal_fixed31_32_one, a3)), gamma)); + + else if (dal_fixed31_32_le(dal_fixed31_32_neg(a0), arg) && + dal_fixed31_32_le(arg, a0)) + linear = dal_fixed31_32_div(arg, a1); + else + linear = dal_fixed31_32_pow( + dal_fixed31_32_div( + dal_fixed31_32_add(a2, arg), + dal_fixed31_32_add( + dal_fixed31_32_one, a3)), gamma); + + return linear; +} + +static inline struct fixed31_32 translate_from_linear_space_ex( + struct fixed31_32 arg, + struct gamma_coefficients *coeff, + uint32_t color_index) +{ + return translate_from_linear_space( + arg, + coeff->a0[color_index], + coeff->a1[color_index], + coeff->a2[color_index], + coeff->a3[color_index], + coeff->user_gamma[color_index]); +} + + +static inline struct fixed31_32 translate_to_linear_space_ex( + struct fixed31_32 arg, + struct gamma_coefficients *coeff, + uint32_t color_index) +{ + return translate_to_linear_space( + arg, + coeff->a0[color_index], + coeff->a1[color_index], + coeff->a2[color_index], + coeff->a3[color_index], + coeff->user_gamma[color_index]); +} + + +static bool find_software_points( + const struct dc_gamma *ramp, + const struct gamma_pixel *axis_x, + struct fixed31_32 hw_point, + enum channel_name channel, + uint32_t *index_to_start, + uint32_t *index_left, + uint32_t *index_right, + enum hw_point_position *pos) +{ + const uint32_t max_number = ramp->num_entries + 3; + + struct fixed31_32 left, right; + + uint32_t i = *index_to_start; + + while (i < max_number) { + if (channel == CHANNEL_NAME_RED) { + left = axis_x[i].r; + + if (i < max_number - 1) + right = axis_x[i + 1].r; + else + right = axis_x[max_number - 1].r; + } else if (channel == CHANNEL_NAME_GREEN) { + left = axis_x[i].g; + + if (i < max_number - 1) + right = axis_x[i + 1].g; + else + right = axis_x[max_number - 1].g; + } else { + left = axis_x[i].b; + + if (i < max_number - 1) + right = axis_x[i + 1].b; + else + right = axis_x[max_number - 1].b; + } + + if (dal_fixed31_32_le(left, hw_point) && + dal_fixed31_32_le(hw_point, right)) { + *index_to_start = i; + *index_left = i; + + if (i < max_number - 1) + *index_right = i + 1; + else + *index_right = max_number - 1; + + *pos = HW_POINT_POSITION_MIDDLE; + + return true; + } else if ((i == *index_to_start) && + dal_fixed31_32_le(hw_point, left)) { + *index_to_start = i; + *index_left = i; + *index_right = i; + + *pos = HW_POINT_POSITION_LEFT; + + return true; + } else if ((i == max_number - 1) && + dal_fixed31_32_le(right, hw_point)) { + *index_to_start = i; + *index_left = i; + *index_right = i; + + *pos = HW_POINT_POSITION_RIGHT; + + return true; + } + + ++i; + } + + return false; +} + +static bool build_custom_gamma_mapping_coefficients_worker( + const struct dc_gamma *ramp, + struct pixel_gamma_point *coeff, + const struct hw_x_point *coordinates_x, + const struct gamma_pixel *axis_x, + enum channel_name channel, + uint32_t number_of_points) +{ + uint32_t i = 0; + + while (i <= number_of_points) { + struct fixed31_32 coord_x; + + uint32_t index_to_start = 0; + uint32_t index_left = 0; + uint32_t index_right = 0; + + enum hw_point_position hw_pos; + + struct gamma_point *point; + + struct fixed31_32 left_pos; + struct fixed31_32 right_pos; + + if (channel == CHANNEL_NAME_RED) + coord_x = coordinates_x[i].regamma_y_red; + else if (channel == CHANNEL_NAME_GREEN) + coord_x = coordinates_x[i].regamma_y_green; + else + coord_x = coordinates_x[i].regamma_y_blue; + + if (!find_software_points( + ramp, axis_x, coord_x, channel, + &index_to_start, &index_left, &index_right, &hw_pos)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (index_left >= ramp->num_entries + 3) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (index_right >= ramp->num_entries + 3) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (channel == CHANNEL_NAME_RED) { + point = &coeff[i].r; + + left_pos = axis_x[index_left].r; + right_pos = axis_x[index_right].r; + } else if (channel == CHANNEL_NAME_GREEN) { + point = &coeff[i].g; + + left_pos = axis_x[index_left].g; + right_pos = axis_x[index_right].g; + } else { + point = &coeff[i].b; + + left_pos = axis_x[index_left].b; + right_pos = axis_x[index_right].b; + } + + if (hw_pos == HW_POINT_POSITION_MIDDLE) + point->coeff = dal_fixed31_32_div( + dal_fixed31_32_sub( + coord_x, + left_pos), + dal_fixed31_32_sub( + right_pos, + left_pos)); + else if (hw_pos == HW_POINT_POSITION_LEFT) + point->coeff = dal_fixed31_32_zero; + else if (hw_pos == HW_POINT_POSITION_RIGHT) + point->coeff = dal_fixed31_32_from_int(2); + else { + BREAK_TO_DEBUGGER(); + return false; + } + + point->left_index = index_left; + point->right_index = index_right; + point->pos = hw_pos; + + ++i; + } + + return true; +} + +static struct fixed31_32 calculate_mapped_value( + struct pwl_float_data *rgb, + const struct pixel_gamma_point *coeff, + enum channel_name channel, + uint32_t max_index) +{ + const struct gamma_point *point; + + struct fixed31_32 result; + + if (channel == CHANNEL_NAME_RED) + point = &coeff->r; + else if (channel == CHANNEL_NAME_GREEN) + point = &coeff->g; + else + point = &coeff->b; + + if ((point->left_index < 0) || (point->left_index > max_index)) { + BREAK_TO_DEBUGGER(); + return dal_fixed31_32_zero; + } + + if ((point->right_index < 0) || (point->right_index > max_index)) { + BREAK_TO_DEBUGGER(); + return dal_fixed31_32_zero; + } + + if (point->pos == HW_POINT_POSITION_MIDDLE) + if (channel == CHANNEL_NAME_RED) + result = dal_fixed31_32_add( + dal_fixed31_32_mul( + point->coeff, + dal_fixed31_32_sub( + rgb[point->right_index].r, + rgb[point->left_index].r)), + rgb[point->left_index].r); + else if (channel == CHANNEL_NAME_GREEN) + result = dal_fixed31_32_add( + dal_fixed31_32_mul( + point->coeff, + dal_fixed31_32_sub( + rgb[point->right_index].g, + rgb[point->left_index].g)), + rgb[point->left_index].g); + else + result = dal_fixed31_32_add( + dal_fixed31_32_mul( + point->coeff, + dal_fixed31_32_sub( + rgb[point->right_index].b, + rgb[point->left_index].b)), + rgb[point->left_index].b); + else if (point->pos == HW_POINT_POSITION_LEFT) { + BREAK_TO_DEBUGGER(); + result = dal_fixed31_32_zero; + } else { + BREAK_TO_DEBUGGER(); + result = dal_fixed31_32_one; + } + + return result; +} + +static void build_pq(struct pwl_float_data_ex *rgb_regamma, + uint32_t hw_points_num, + const struct hw_x_point *coordinate_x, + uint32_t sdr_white_level) +{ + uint32_t i, start_index; + + struct pwl_float_data_ex *rgb = rgb_regamma; + const struct hw_x_point *coord_x = coordinate_x; + struct fixed31_32 x; + struct fixed31_32 output; + struct fixed31_32 scaling_factor = + dal_fixed31_32_from_fraction(sdr_white_level, 10000); + + if (!pq_initialized && sdr_white_level == 80) { + precompute_pq(); + pq_initialized = true; + } + + /* TODO: start index is from segment 2^-24, skipping first segment + * due to x values too small for power calculations + */ + start_index = 32; + rgb += start_index; + coord_x += start_index; + + for (i = start_index; i <= hw_points_num; i++) { + /* Multiply 0.008 as regamma is 0-1 and FP16 input is 0-125. + * FP 1.0 = 80nits + */ + if (sdr_white_level == 80) { + output = pq_table[i]; + } else { + x = dal_fixed31_32_mul(coord_x->x, scaling_factor); + compute_pq(x, &output); + } + + /* should really not happen? */ + if (dal_fixed31_32_lt(output, dal_fixed31_32_zero)) + output = dal_fixed31_32_zero; + else if (dal_fixed31_32_lt(dal_fixed31_32_one, output)) + output = dal_fixed31_32_one; + + rgb->r = output; + rgb->g = output; + rgb->b = output; + + ++coord_x; + ++rgb; + } +} + +static void build_de_pq(struct pwl_float_data_ex *de_pq, + uint32_t hw_points_num, + const struct hw_x_point *coordinate_x) +{ + uint32_t i; + struct fixed31_32 output; + + struct pwl_float_data_ex *rgb = de_pq; + const struct hw_x_point *coord_x = degamma_coordinates_x; + struct fixed31_32 scaling_factor = dal_fixed31_32_from_int(125); + + if (!de_pq_initialized) { + precompute_de_pq(); + de_pq_initialized = true; + } + + + for (i = 0; i <= hw_points_num; i++) { + output = de_pq_table[i]; + /* should really not happen? */ + if (dal_fixed31_32_lt(output, dal_fixed31_32_zero)) + output = dal_fixed31_32_zero; + else if (dal_fixed31_32_lt(scaling_factor, output)) + output = scaling_factor; + + rgb->r = output; + rgb->g = output; + rgb->b = output; + + ++coord_x; + ++rgb; + } +} + +static void build_regamma(struct pwl_float_data_ex *rgb_regamma, + uint32_t hw_points_num, + const struct hw_x_point *coordinate_x, bool is_2_4) +{ + uint32_t i; + + struct gamma_coefficients coeff; + struct pwl_float_data_ex *rgb = rgb_regamma; + const struct hw_x_point *coord_x = coordinate_x; + + build_coefficients(&coeff, is_2_4); + + i = 0; + + while (i != hw_points_num + 1) { + /*TODO use y vs r,g,b*/ + rgb->r = translate_from_linear_space_ex( + coord_x->x, &coeff, 0); + rgb->g = rgb->r; + rgb->b = rgb->r; + ++coord_x; + ++rgb; + ++i; + } +} + +static void build_degamma(struct pwl_float_data_ex *curve, + uint32_t hw_points_num, + const struct hw_x_point *coordinate_x, bool is_2_4) +{ + uint32_t i; + + struct gamma_coefficients coeff; + struct pwl_float_data_ex *rgb = curve; + const struct hw_x_point *coord_x = degamma_coordinates_x; + + build_coefficients(&coeff, is_2_4); + + i = 0; + + while (i != hw_points_num + 1) { + /*TODO use y vs r,g,b*/ + rgb->r = translate_to_linear_space_ex( + coord_x->x, &coeff, 0); + rgb->g = rgb->r; + rgb->b = rgb->r; + ++coord_x; + ++rgb; + ++i; + } +} + +static bool scale_gamma(struct pwl_float_data *pwl_rgb, + const struct dc_gamma *ramp, + struct dividers dividers) +{ + const struct fixed31_32 max_driver = dal_fixed31_32_from_int(0xFFFF); + const struct fixed31_32 max_os = dal_fixed31_32_from_int(0xFF00); + struct fixed31_32 scaler = max_os; + uint32_t i; + struct pwl_float_data *rgb = pwl_rgb; + struct pwl_float_data *rgb_last = rgb + ramp->num_entries - 1; + + i = 0; + + do { + if (dal_fixed31_32_lt(max_os, ramp->entries.red[i]) || + dal_fixed31_32_lt(max_os, ramp->entries.green[i]) || + dal_fixed31_32_lt(max_os, ramp->entries.blue[i])) { + scaler = max_driver; + break; + } + ++i; + } while (i != ramp->num_entries); + + i = 0; + + do { + rgb->r = dal_fixed31_32_div( + ramp->entries.red[i], scaler); + rgb->g = dal_fixed31_32_div( + ramp->entries.green[i], scaler); + rgb->b = dal_fixed31_32_div( + ramp->entries.blue[i], scaler); + + ++rgb; + ++i; + } while (i != ramp->num_entries); + + rgb->r = dal_fixed31_32_mul(rgb_last->r, + dividers.divider1); + rgb->g = dal_fixed31_32_mul(rgb_last->g, + dividers.divider1); + rgb->b = dal_fixed31_32_mul(rgb_last->b, + dividers.divider1); + + ++rgb; + + rgb->r = dal_fixed31_32_mul(rgb_last->r, + dividers.divider2); + rgb->g = dal_fixed31_32_mul(rgb_last->g, + dividers.divider2); + rgb->b = dal_fixed31_32_mul(rgb_last->b, + dividers.divider2); + + ++rgb; + + rgb->r = dal_fixed31_32_mul(rgb_last->r, + dividers.divider3); + rgb->g = dal_fixed31_32_mul(rgb_last->g, + dividers.divider3); + rgb->b = dal_fixed31_32_mul(rgb_last->b, + dividers.divider3); + + return true; +} + +static bool scale_gamma_dx(struct pwl_float_data *pwl_rgb, + const struct dc_gamma *ramp, + struct dividers dividers) +{ + uint32_t i; + struct fixed31_32 min = dal_fixed31_32_zero; + struct fixed31_32 max = dal_fixed31_32_one; + + struct fixed31_32 delta = dal_fixed31_32_zero; + struct fixed31_32 offset = dal_fixed31_32_zero; + + for (i = 0 ; i < ramp->num_entries; i++) { + if (dal_fixed31_32_lt(ramp->entries.red[i], min)) + min = ramp->entries.red[i]; + + if (dal_fixed31_32_lt(ramp->entries.green[i], min)) + min = ramp->entries.green[i]; + + if (dal_fixed31_32_lt(ramp->entries.blue[i], min)) + min = ramp->entries.blue[i]; + + if (dal_fixed31_32_lt(max, ramp->entries.red[i])) + max = ramp->entries.red[i]; + + if (dal_fixed31_32_lt(max, ramp->entries.green[i])) + max = ramp->entries.green[i]; + + if (dal_fixed31_32_lt(max, ramp->entries.blue[i])) + max = ramp->entries.blue[i]; + } + + if (dal_fixed31_32_lt(min, dal_fixed31_32_zero)) + delta = dal_fixed31_32_neg(min); + + offset = dal_fixed31_32_add(min, max); + + for (i = 0 ; i < ramp->num_entries; i++) { + pwl_rgb[i].r = dal_fixed31_32_div( + dal_fixed31_32_add( + ramp->entries.red[i], delta), offset); + pwl_rgb[i].g = dal_fixed31_32_div( + dal_fixed31_32_add( + ramp->entries.green[i], delta), offset); + pwl_rgb[i].b = dal_fixed31_32_div( + dal_fixed31_32_add( + ramp->entries.blue[i], delta), offset); + + } + + pwl_rgb[i].r = dal_fixed31_32_sub(dal_fixed31_32_mul_int( + pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r); + pwl_rgb[i].g = dal_fixed31_32_sub(dal_fixed31_32_mul_int( + pwl_rgb[i-1].g, 2), pwl_rgb[i-2].g); + pwl_rgb[i].b = dal_fixed31_32_sub(dal_fixed31_32_mul_int( + pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b); + ++i; + pwl_rgb[i].r = dal_fixed31_32_sub(dal_fixed31_32_mul_int( + pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r); + pwl_rgb[i].g = dal_fixed31_32_sub(dal_fixed31_32_mul_int( + pwl_rgb[i-1].g, 2), pwl_rgb[i-2].g); + pwl_rgb[i].b = dal_fixed31_32_sub(dal_fixed31_32_mul_int( + pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b); + + return true; +} + +/* + * RS3+ color transform DDI - 1D LUT adjustment is composed with regamma here + * Input is evenly distributed in the output color space as specified in + * SetTimings + * + * Interpolation details: + * 1D LUT has 4096 values which give curve correction in 0-1 float range + * for evenly spaced points in 0-1 range. lut1D[index] gives correction + * for index/4095. + * First we find index for which: + * index/4095 < regamma_y < (index+1)/4095 => + * index < 4095*regamma_y < index + 1 + * norm_y = 4095*regamma_y, and index is just truncating to nearest integer + * lut1 = lut1D[index], lut2 = lut1D[index+1] + * + *adjustedY is then linearly interpolating regamma Y between lut1 and lut2 + */ +static void apply_lut_1d( + const struct dc_gamma *ramp, + uint32_t num_hw_points, + struct dc_transfer_func_distributed_points *tf_pts) +{ + int i = 0; + int color = 0; + struct fixed31_32 *regamma_y; + struct fixed31_32 norm_y; + struct fixed31_32 lut1; + struct fixed31_32 lut2; + const int max_lut_index = 4095; + const struct fixed31_32 max_lut_index_f = + dal_fixed31_32_from_int_nonconst(max_lut_index); + int32_t index = 0, index_next = 0; + struct fixed31_32 index_f; + struct fixed31_32 delta_lut; + struct fixed31_32 delta_index; + + if (ramp->type != GAMMA_CS_TFM_1D) + return; // this is not expected + + for (i = 0; i < num_hw_points; i++) { + for (color = 0; color < 3; color++) { + if (color == 0) + regamma_y = &tf_pts->red[i]; + else if (color == 1) + regamma_y = &tf_pts->green[i]; + else + regamma_y = &tf_pts->blue[i]; + + norm_y = dal_fixed31_32_mul(max_lut_index_f, + *regamma_y); + index = dal_fixed31_32_floor(norm_y); + index_f = dal_fixed31_32_from_int_nonconst(index); + + if (index < 0 || index > max_lut_index) + continue; + + index_next = (index == max_lut_index) ? index : index+1; + + if (color == 0) { + lut1 = ramp->entries.red[index]; + lut2 = ramp->entries.red[index_next]; + } else if (color == 1) { + lut1 = ramp->entries.green[index]; + lut2 = ramp->entries.green[index_next]; + } else { + lut1 = ramp->entries.blue[index]; + lut2 = ramp->entries.blue[index_next]; + } + + // we have everything now, so interpolate + delta_lut = dal_fixed31_32_sub(lut2, lut1); + delta_index = dal_fixed31_32_sub(norm_y, index_f); + + *regamma_y = dal_fixed31_32_add(lut1, + dal_fixed31_32_mul(delta_index, delta_lut)); + } + } +} + +static void build_evenly_distributed_points( + struct gamma_pixel *points, + uint32_t numberof_points, + struct dividers dividers) +{ + struct gamma_pixel *p = points; + struct gamma_pixel *p_last = p + numberof_points - 1; + + uint32_t i = 0; + + do { + struct fixed31_32 value = dal_fixed31_32_from_fraction(i, + numberof_points - 1); + + p->r = value; + p->g = value; + p->b = value; + + ++p; + ++i; + } while (i != numberof_points); + + p->r = dal_fixed31_32_div(p_last->r, dividers.divider1); + p->g = dal_fixed31_32_div(p_last->g, dividers.divider1); + p->b = dal_fixed31_32_div(p_last->b, dividers.divider1); + + ++p; + + p->r = dal_fixed31_32_div(p_last->r, dividers.divider2); + p->g = dal_fixed31_32_div(p_last->g, dividers.divider2); + p->b = dal_fixed31_32_div(p_last->b, dividers.divider2); + + ++p; + + p->r = dal_fixed31_32_div(p_last->r, dividers.divider3); + p->g = dal_fixed31_32_div(p_last->g, dividers.divider3); + p->b = dal_fixed31_32_div(p_last->b, dividers.divider3); +} + +static inline void copy_rgb_regamma_to_coordinates_x( + struct hw_x_point *coordinates_x, + uint32_t hw_points_num, + const struct pwl_float_data_ex *rgb_ex) +{ + struct hw_x_point *coords = coordinates_x; + uint32_t i = 0; + const struct pwl_float_data_ex *rgb_regamma = rgb_ex; + + while (i <= hw_points_num) { + coords->regamma_y_red = rgb_regamma->r; + coords->regamma_y_green = rgb_regamma->g; + coords->regamma_y_blue = rgb_regamma->b; + + ++coords; + ++rgb_regamma; + ++i; + } +} + +static bool calculate_interpolated_hardware_curve( + const struct dc_gamma *ramp, + struct pixel_gamma_point *coeff128, + struct pwl_float_data *rgb_user, + const struct hw_x_point *coordinates_x, + const struct gamma_pixel *axis_x, + uint32_t number_of_points, + struct dc_transfer_func_distributed_points *tf_pts) +{ + + const struct pixel_gamma_point *coeff = coeff128; + uint32_t max_entries = 3 - 1; + + uint32_t i = 0; + + for (i = 0; i < 3; i++) { + if (!build_custom_gamma_mapping_coefficients_worker( + ramp, coeff128, coordinates_x, axis_x, i, + number_of_points)) + return false; + } + + i = 0; + max_entries += ramp->num_entries; + + /* TODO: float point case */ + + while (i <= number_of_points) { + tf_pts->red[i] = calculate_mapped_value( + rgb_user, coeff, CHANNEL_NAME_RED, max_entries); + tf_pts->green[i] = calculate_mapped_value( + rgb_user, coeff, CHANNEL_NAME_GREEN, max_entries); + tf_pts->blue[i] = calculate_mapped_value( + rgb_user, coeff, CHANNEL_NAME_BLUE, max_entries); + + ++coeff; + ++i; + } + + return true; +} + +static void build_new_custom_resulted_curve( + uint32_t hw_points_num, + struct dc_transfer_func_distributed_points *tf_pts) +{ + uint32_t i; + + i = 0; + + while (i != hw_points_num + 1) { + tf_pts->red[i] = dal_fixed31_32_clamp( + tf_pts->red[i], dal_fixed31_32_zero, + dal_fixed31_32_one); + tf_pts->green[i] = dal_fixed31_32_clamp( + tf_pts->green[i], dal_fixed31_32_zero, + dal_fixed31_32_one); + tf_pts->blue[i] = dal_fixed31_32_clamp( + tf_pts->blue[i], dal_fixed31_32_zero, + dal_fixed31_32_one); + + ++i; + } +} + +static bool map_regamma_hw_to_x_user( + const struct dc_gamma *ramp, + struct pixel_gamma_point *coeff128, + struct pwl_float_data *rgb_user, + struct hw_x_point *coords_x, + const struct gamma_pixel *axis_x, + const struct pwl_float_data_ex *rgb_regamma, + uint32_t hw_points_num, + struct dc_transfer_func_distributed_points *tf_pts, + bool mapUserRamp) +{ + /* setup to spare calculated ideal regamma values */ + + int i = 0; + struct hw_x_point *coords = coords_x; + const struct pwl_float_data_ex *regamma = rgb_regamma; + + if (mapUserRamp) { + copy_rgb_regamma_to_coordinates_x(coords, + hw_points_num, + rgb_regamma); + + calculate_interpolated_hardware_curve( + ramp, coeff128, rgb_user, coords, axis_x, + hw_points_num, tf_pts); + } else { + /* just copy current rgb_regamma into tf_pts */ + while (i <= hw_points_num) { + tf_pts->red[i] = regamma->r; + tf_pts->green[i] = regamma->g; + tf_pts->blue[i] = regamma->b; + + ++regamma; + ++i; + } + } + + build_new_custom_resulted_curve(hw_points_num, tf_pts); + + return true; +} + +#define _EXTRA_POINTS 3 + +bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, + const struct dc_gamma *ramp, bool mapUserRamp) +{ + struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts; + struct dividers dividers; + + struct pwl_float_data *rgb_user = NULL; + struct pwl_float_data_ex *rgb_regamma = NULL; + struct gamma_pixel *axix_x = NULL; + struct pixel_gamma_point *coeff = NULL; + enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; + bool ret = false; + + if (output_tf->type == TF_TYPE_BYPASS) + return false; + + /* we can use hardcoded curve for plain SRGB TF */ + if (output_tf->type == TF_TYPE_PREDEFINED && + output_tf->tf == TRANSFER_FUNCTION_SRGB && + (!mapUserRamp && ramp->type == GAMMA_RGB_256)) + return true; + + output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; + + rgb_user = kzalloc(sizeof(*rgb_user) * (ramp->num_entries + _EXTRA_POINTS), + GFP_KERNEL); + if (!rgb_user) + goto rgb_user_alloc_fail; + rgb_regamma = kzalloc(sizeof(*rgb_regamma) * (MAX_HW_POINTS + _EXTRA_POINTS), + GFP_KERNEL); + if (!rgb_regamma) + goto rgb_regamma_alloc_fail; + axix_x = kzalloc(sizeof(*axix_x) * (ramp->num_entries + 3), + GFP_KERNEL); + if (!axix_x) + goto axix_x_alloc_fail; + coeff = kzalloc(sizeof(*coeff) * (MAX_HW_POINTS + _EXTRA_POINTS), GFP_KERNEL); + if (!coeff) + goto coeff_alloc_fail; + + dividers.divider1 = dal_fixed31_32_from_fraction(3, 2); + dividers.divider2 = dal_fixed31_32_from_int(2); + dividers.divider3 = dal_fixed31_32_from_fraction(5, 2); + + tf = output_tf->tf; + + build_evenly_distributed_points( + axix_x, + ramp->num_entries, + dividers); + + if (ramp->type == GAMMA_RGB_256 && mapUserRamp) + scale_gamma(rgb_user, ramp, dividers); + else if (ramp->type == GAMMA_RGB_FLOAT_1024) + scale_gamma_dx(rgb_user, ramp, dividers); + + if (tf == TRANSFER_FUNCTION_PQ) { + tf_pts->end_exponent = 7; + tf_pts->x_point_at_y1_red = 125; + tf_pts->x_point_at_y1_green = 125; + tf_pts->x_point_at_y1_blue = 125; + + build_pq(rgb_regamma, + MAX_HW_POINTS, + coordinates_x, + output_tf->sdr_ref_white_level); + } else { + tf_pts->end_exponent = 0; + tf_pts->x_point_at_y1_red = 1; + tf_pts->x_point_at_y1_green = 1; + tf_pts->x_point_at_y1_blue = 1; + + build_regamma(rgb_regamma, + MAX_HW_POINTS, + coordinates_x, tf == TRANSFER_FUNCTION_SRGB ? true:false); + } + + map_regamma_hw_to_x_user(ramp, coeff, rgb_user, + coordinates_x, axix_x, rgb_regamma, + MAX_HW_POINTS, tf_pts, + (mapUserRamp || ramp->type != GAMMA_RGB_256) && + ramp->type != GAMMA_CS_TFM_1D); + + if (ramp->type == GAMMA_CS_TFM_1D) + apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts); + + ret = true; + + kfree(coeff); +coeff_alloc_fail: + kfree(axix_x); +axix_x_alloc_fail: + kfree(rgb_regamma); +rgb_regamma_alloc_fail: + kfree(rgb_user); +rgb_user_alloc_fail: + return ret; +} + + +/*TODO fix me should be 2*/ +#define _EXTRA_POINTS 3 + +bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, + const struct dc_gamma *ramp, bool mapUserRamp) +{ + struct dc_transfer_func_distributed_points *tf_pts = &input_tf->tf_pts; + struct dividers dividers; + + struct pwl_float_data *rgb_user = NULL; + struct pwl_float_data_ex *curve = NULL; + struct gamma_pixel *axix_x = NULL; + struct pixel_gamma_point *coeff = NULL; + enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; + bool ret = false; + + if (input_tf->type == TF_TYPE_BYPASS) + return false; + + /* we can use hardcoded curve for plain SRGB TF */ + if (input_tf->type == TF_TYPE_PREDEFINED && + input_tf->tf == TRANSFER_FUNCTION_SRGB && + (!mapUserRamp && ramp->type == GAMMA_RGB_256)) + return true; + + input_tf->type = TF_TYPE_DISTRIBUTED_POINTS; + + rgb_user = kzalloc(sizeof(*rgb_user) * (ramp->num_entries + _EXTRA_POINTS), + GFP_KERNEL); + if (!rgb_user) + goto rgb_user_alloc_fail; + curve = kzalloc(sizeof(*curve) * (MAX_HW_DEGAMMA_POINTS + _EXTRA_POINTS), + GFP_KERNEL); + if (!curve) + goto curve_alloc_fail; + axix_x = kzalloc(sizeof(*axix_x) * (ramp->num_entries + _EXTRA_POINTS), + GFP_KERNEL); + if (!axix_x) + goto axix_x_alloc_fail; + coeff = kzalloc(sizeof(*coeff) * (MAX_HW_DEGAMMA_POINTS + _EXTRA_POINTS), GFP_KERNEL); + if (!coeff) + goto coeff_alloc_fail; + + dividers.divider1 = dal_fixed31_32_from_fraction(3, 2); + dividers.divider2 = dal_fixed31_32_from_int(2); + dividers.divider3 = dal_fixed31_32_from_fraction(5, 2); + + tf = input_tf->tf; + + build_evenly_distributed_points( + axix_x, + ramp->num_entries, + dividers); + + if (ramp->type == GAMMA_RGB_256 && mapUserRamp) + scale_gamma(rgb_user, ramp, dividers); + else if (ramp->type == GAMMA_RGB_FLOAT_1024) + scale_gamma_dx(rgb_user, ramp, dividers); + + if (tf == TRANSFER_FUNCTION_PQ) + build_de_pq(curve, + MAX_HW_DEGAMMA_POINTS, + degamma_coordinates_x); + else + build_degamma(curve, + MAX_HW_DEGAMMA_POINTS, + degamma_coordinates_x, + tf == TRANSFER_FUNCTION_SRGB ? true:false); + + tf_pts->end_exponent = 0; + tf_pts->x_point_at_y1_red = 1; + tf_pts->x_point_at_y1_green = 1; + tf_pts->x_point_at_y1_blue = 1; + + map_regamma_hw_to_x_user(ramp, coeff, rgb_user, + degamma_coordinates_x, axix_x, curve, + MAX_HW_DEGAMMA_POINTS, tf_pts, + mapUserRamp); + + ret = true; + + kfree(coeff); +coeff_alloc_fail: + kfree(axix_x); +axix_x_alloc_fail: + kfree(curve); +curve_alloc_fail: + kfree(rgb_user); +rgb_user_alloc_fail: + + return ret; + +} + + +bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, + struct dc_transfer_func_distributed_points *points) +{ + uint32_t i; + bool ret = false; + struct pwl_float_data_ex *rgb_regamma = NULL; + + if (trans == TRANSFER_FUNCTION_UNITY) { + points->end_exponent = 0; + points->x_point_at_y1_red = 1; + points->x_point_at_y1_green = 1; + points->x_point_at_y1_blue = 1; + + for (i = 0; i < MAX_HW_POINTS ; i++) { + points->red[i] = coordinates_x[i].x; + points->green[i] = coordinates_x[i].x; + points->blue[i] = coordinates_x[i].x; + } + ret = true; + } else if (trans == TRANSFER_FUNCTION_PQ) { + rgb_regamma = kzalloc(sizeof(*rgb_regamma) * (MAX_HW_POINTS + + _EXTRA_POINTS), GFP_KERNEL); + if (!rgb_regamma) + goto rgb_regamma_alloc_fail; + points->end_exponent = 7; + points->x_point_at_y1_red = 125; + points->x_point_at_y1_green = 125; + points->x_point_at_y1_blue = 125; + + + build_pq(rgb_regamma, + MAX_HW_POINTS, + coordinates_x, + 80); + for (i = 0; i < MAX_HW_POINTS ; i++) { + points->red[i] = rgb_regamma[i].r; + points->green[i] = rgb_regamma[i].g; + points->blue[i] = rgb_regamma[i].b; + } + ret = true; + + kfree(rgb_regamma); + } else if (trans == TRANSFER_FUNCTION_SRGB || + trans == TRANSFER_FUNCTION_BT709) { + rgb_regamma = kzalloc(sizeof(*rgb_regamma) * (MAX_HW_POINTS + + _EXTRA_POINTS), GFP_KERNEL); + if (!rgb_regamma) + goto rgb_regamma_alloc_fail; + points->end_exponent = 0; + points->x_point_at_y1_red = 1; + points->x_point_at_y1_green = 1; + points->x_point_at_y1_blue = 1; + + build_regamma(rgb_regamma, + MAX_HW_POINTS, + coordinates_x, trans == TRANSFER_FUNCTION_SRGB ? true:false); + for (i = 0; i < MAX_HW_POINTS ; i++) { + points->red[i] = rgb_regamma[i].r; + points->green[i] = rgb_regamma[i].g; + points->blue[i] = rgb_regamma[i].b; + } + ret = true; + + kfree(rgb_regamma); + } +rgb_regamma_alloc_fail: + return ret; +} + + +bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, + struct dc_transfer_func_distributed_points *points) +{ + uint32_t i; + bool ret = false; + struct pwl_float_data_ex *rgb_degamma = NULL; + + if (trans == TRANSFER_FUNCTION_UNITY) { + + for (i = 0; i < MAX_HW_DEGAMMA_POINTS ; i++) { + points->red[i] = degamma_coordinates_x[i].x; + points->green[i] = degamma_coordinates_x[i].x; + points->blue[i] = degamma_coordinates_x[i].x; + } + ret = true; + } else if (trans == TRANSFER_FUNCTION_PQ) { + rgb_degamma = kzalloc(sizeof(*rgb_degamma) * (MAX_HW_DEGAMMA_POINTS + + _EXTRA_POINTS), GFP_KERNEL); + if (!rgb_degamma) + goto rgb_degamma_alloc_fail; + + + build_de_pq(rgb_degamma, + MAX_HW_DEGAMMA_POINTS, + degamma_coordinates_x); + for (i = 0; i < MAX_HW_DEGAMMA_POINTS ; i++) { + points->red[i] = rgb_degamma[i].r; + points->green[i] = rgb_degamma[i].g; + points->blue[i] = rgb_degamma[i].b; + } + ret = true; + + kfree(rgb_degamma); + } else if (trans == TRANSFER_FUNCTION_SRGB || + trans == TRANSFER_FUNCTION_BT709) { + rgb_degamma = kzalloc(sizeof(*rgb_degamma) * (MAX_HW_DEGAMMA_POINTS + + _EXTRA_POINTS), GFP_KERNEL); + if (!rgb_degamma) + goto rgb_degamma_alloc_fail; + + build_degamma(rgb_degamma, + MAX_HW_DEGAMMA_POINTS, + degamma_coordinates_x, trans == TRANSFER_FUNCTION_SRGB ? true:false); + for (i = 0; i < MAX_HW_DEGAMMA_POINTS ; i++) { + points->red[i] = rgb_degamma[i].r; + points->green[i] = rgb_degamma[i].g; + points->blue[i] = rgb_degamma[i].b; + } + ret = true; + + kfree(rgb_degamma); + } + points->end_exponent = 0; + points->x_point_at_y1_red = 1; + points->x_point_at_y1_green = 1; + points->x_point_at_y1_blue = 1; + +rgb_degamma_alloc_fail: + return ret; +} + + diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h new file mode 100644 index 000000000000..b7f9bc27d101 --- /dev/null +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h @@ -0,0 +1,53 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef COLOR_MOD_COLOR_GAMMA_H_ +#define COLOR_MOD_COLOR_GAMMA_H_ + +struct dc_transfer_func; +struct dc_gamma; +struct dc_transfer_func_distributed_points; +struct dc_rgb_fixed; +enum dc_transfer_func_predefined; + +void setup_x_points_distribution(void); +void precompute_pq(void); +void precompute_de_pq(void); + +bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, + const struct dc_gamma *ramp, bool mapUserRamp); + +bool mod_color_calculate_degamma_params(struct dc_transfer_func *output_tf, + const struct dc_gamma *ramp, bool mapUserRamp); + +bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, + struct dc_transfer_func_distributed_points *points); + +bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, + struct dc_transfer_func_distributed_points *points); + + + +#endif /* COLOR_MOD_COLOR_GAMMA_H_ */ diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_1_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_1_0_sh_mask.h index b28d4b64c05d..e2a2f114bd8e 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_1_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_1_0_sh_mask.h @@ -9364,17 +9364,31 @@ #define HUBPREQ0_DCSURF_SURFACE_CONTROL__PRIMARY_SURFACE_TMZ__SHIFT 0x0 #define HUBPREQ0_DCSURF_SURFACE_CONTROL__PRIMARY_SURFACE_DCC_EN__SHIFT 0x1 #define HUBPREQ0_DCSURF_SURFACE_CONTROL__PRIMARY_SURFACE_DCC_IND_64B_BLK__SHIFT 0x2 +#define HUBPREQ0_DCSURF_SURFACE_CONTROL__PRIMARY_SURFACE_TMZ_C__SHIFT 0x4 #define HUBPREQ0_DCSURF_SURFACE_CONTROL__PRIMARY_SURFACE_DCC_IND_64B_BLK_C__SHIFT 0x5 +#define HUBPREQ0_DCSURF_SURFACE_CONTROL__SECONDARY_SURFACE_TMZ__SHIFT 0x8 #define HUBPREQ0_DCSURF_SURFACE_CONTROL__SECONDARY_SURFACE_DCC_EN__SHIFT 0x9 #define HUBPREQ0_DCSURF_SURFACE_CONTROL__SECONDARY_SURFACE_DCC_IND_64B_BLK__SHIFT 0xa +#define HUBPREQ0_DCSURF_SURFACE_CONTROL__SECONDARY_SURFACE_TMZ_C__SHIFT 0xc #define HUBPREQ0_DCSURF_SURFACE_CONTROL__SECONDARY_SURFACE_DCC_IND_64B_BLK_C__SHIFT 0xd +#define HUBPREQ0_DCSURF_SURFACE_CONTROL__PRIMARY_META_SURFACE_TMZ__SHIFT 0x10 +#define HUBPREQ0_DCSURF_SURFACE_CONTROL__PRIMARY_META_SURFACE_TMZ_C__SHIFT 0x14 +#define HUBPREQ0_DCSURF_SURFACE_CONTROL__SECONDARY_META_SURFACE_TMZ__SHIFT 0x18 +#define HUBPREQ0_DCSURF_SURFACE_CONTROL__SECONDARY_META_SURFACE_TMZ_C__SHIFT 0x1c #define HUBPREQ0_DCSURF_SURFACE_CONTROL__PRIMARY_SURFACE_TMZ_MASK 0x00000001L #define HUBPREQ0_DCSURF_SURFACE_CONTROL__PRIMARY_SURFACE_DCC_EN_MASK 0x00000002L #define HUBPREQ0_DCSURF_SURFACE_CONTROL__PRIMARY_SURFACE_DCC_IND_64B_BLK_MASK 0x00000004L +#define HUBPREQ0_DCSURF_SURFACE_CONTROL__PRIMARY_SURFACE_TMZ_C_MASK 0x00000010L #define HUBPREQ0_DCSURF_SURFACE_CONTROL__PRIMARY_SURFACE_DCC_IND_64B_BLK_C_MASK 0x00000020L +#define HUBPREQ0_DCSURF_SURFACE_CONTROL__SECONDARY_SURFACE_TMZ_MASK 0x00000100L #define HUBPREQ0_DCSURF_SURFACE_CONTROL__SECONDARY_SURFACE_DCC_EN_MASK 0x00000200L #define HUBPREQ0_DCSURF_SURFACE_CONTROL__SECONDARY_SURFACE_DCC_IND_64B_BLK_MASK 0x00000400L +#define HUBPREQ0_DCSURF_SURFACE_CONTROL__SECONDARY_SURFACE_TMZ_C_MASK 0x00001000L #define HUBPREQ0_DCSURF_SURFACE_CONTROL__SECONDARY_SURFACE_DCC_IND_64B_BLK_C_MASK 0x00002000L +#define HUBPREQ0_DCSURF_SURFACE_CONTROL__PRIMARY_META_SURFACE_TMZ_MASK 0x00010000L +#define HUBPREQ0_DCSURF_SURFACE_CONTROL__PRIMARY_META_SURFACE_TMZ_C_MASK 0x00100000L +#define HUBPREQ0_DCSURF_SURFACE_CONTROL__SECONDARY_META_SURFACE_TMZ_MASK 0x01000000L +#define HUBPREQ0_DCSURF_SURFACE_CONTROL__SECONDARY_META_SURFACE_TMZ_C_MASK 0x10000000L //HUBPREQ0_DCSURF_FLIP_CONTROL #define HUBPREQ0_DCSURF_FLIP_CONTROL__SURFACE_UPDATE_LOCK__SHIFT 0x0 #define HUBPREQ0_DCSURF_FLIP_CONTROL__SURFACE_FLIP_TYPE__SHIFT 0x1 diff --git a/drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_1_3_d.h b/drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_1_3_d.h index b89347ed1a40..f35aba72e640 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_1_3_d.h +++ b/drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_1_3_d.h @@ -1246,5 +1246,6 @@ #define ixGC_CAC_OVRD_CU 0xe7 #define ixCURRENT_PG_STATUS 0xc020029c #define ixCURRENT_PG_STATUS_APU 0xd020029c +#define ixPWR_SVI2_STATUS 0xC0200294 #endif /* SMU_7_1_3_D_H */ diff --git a/drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_1_3_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_1_3_sh_mask.h index 654c1093d362..481ee6560aa9 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_1_3_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_1_3_sh_mask.h @@ -6078,6 +6078,8 @@ #define GC_CAC_OVRD_CU__OVRRD_VALUE__SHIFT 0x10 #define CURRENT_PG_STATUS__VCE_PG_STATUS_MASK 0x00000002 #define CURRENT_PG_STATUS__UVD_PG_STATUS_MASK 0x00000004 - - +#define PWR_SVI2_STATUS__PLANE1_VID_MASK 0x000000ff +#define PWR_SVI2_STATUS__PLANE1_VID__SHIFT 0x00000000 +#define PWR_SVI2_STATUS__PLANE2_VID_MASK 0x0000ff00 +#define PWR_SVI2_STATUS__PLANE2_VID__SHIFT 0x00000008 #endif /* SMU_7_1_3_SH_MASK_H */ diff --git a/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_9_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_9_0_offset.h index c1006fe58daa..efd2704d0f8f 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_9_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_9_0_offset.h @@ -172,4 +172,7 @@ #define mmROM_SW_DATA_64 0x006d #define mmROM_SW_DATA_64_BASE_IDX 0 +#define mmSMUSVI0_PLANE0_CURRENTVID_BASE_IDX 0 +#define mmSMUSVI0_PLANE0_CURRENTVID 0x0013 + #endif diff --git a/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_9_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_9_0_sh_mask.h index a0be5c9bfc10..2487ab9621e9 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_9_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_9_0_sh_mask.h @@ -254,5 +254,8 @@ //ROM_SW_DATA_64 #define ROM_SW_DATA_64__ROM_SW_DATA__SHIFT 0x0 #define ROM_SW_DATA_64__ROM_SW_DATA_MASK 0xFFFFFFFFL +/* SMUSVI0_PLANE0_CURRENTVID */ +#define SMUSVI0_PLANE0_CURRENTVID__CURRENT_SVI0_PLANE0_VID__SHIFT 0x18 +#define SMUSVI0_PLANE0_CURRENTVID__CURRENT_SVI0_PLANE0_VID_MASK 0xFF000000L #endif diff --git a/drivers/gpu/drm/amd/include/cgs_common.h b/drivers/gpu/drm/amd/include/cgs_common.h index 675988d56392..f5c73970ab88 100644 --- a/drivers/gpu/drm/amd/include/cgs_common.h +++ b/drivers/gpu/drm/amd/include/cgs_common.h @@ -427,6 +427,9 @@ struct amd_pp_init; typedef void* (*cgs_register_pp_handle)(struct cgs_device *cgs_device, int (*call_back_func)(struct amd_pp_init *, void **)); +typedef int (*cgs_set_temperature_range)(struct cgs_device *cgs_device, + int min_temperature, + int max_temperature); struct cgs_ops { /* memory management calls (similar to KFD interface) */ cgs_alloc_gpu_mem_t alloc_gpu_mem; @@ -464,6 +467,7 @@ struct cgs_ops { cgs_enter_safe_mode enter_safe_mode; cgs_lock_grbm_idx lock_grbm_idx; cgs_register_pp_handle register_pp_handle; + cgs_set_temperature_range set_temperature_range; }; struct cgs_os_ops; /* To be define in OS-specific CGS header */ @@ -545,4 +549,7 @@ struct cgs_device #define cgs_register_pp_handle(cgs_device, call_back_func) \ CGS_CALL(register_pp_handle, cgs_device, call_back_func) +#define cgs_set_temperature_range(dev, min_temp, max_temp) \ + CGS_CALL(set_temperature_range, dev, min_temp, max_temp) + #endif /* _CGS_COMMON_H */ diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index ed27626dff14..22c2fa30731f 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -107,6 +107,8 @@ enum pp_clock_type { PP_SCLK, PP_MCLK, PP_PCIE, + OD_SCLK, + OD_MCLK, }; enum amd_pp_sensors { @@ -122,6 +124,8 @@ enum amd_pp_sensors { AMDGPU_PP_SENSOR_VCE_POWER, AMDGPU_PP_SENSOR_UVD_POWER, AMDGPU_PP_SENSOR_GPU_POWER, + AMDGPU_PP_SENSOR_STABLE_PSTATE_SCLK, + AMDGPU_PP_SENSOR_STABLE_PSTATE_MCLK, }; enum amd_pp_task { @@ -140,7 +144,15 @@ struct amd_pp_init { uint32_t feature_mask; }; - +enum PP_SMC_POWER_PROFILE { + PP_SMC_POWER_PROFILE_FULLSCREEN3D = 0x0, + PP_SMC_POWER_PROFILE_POWERSAVING = 0x1, + PP_SMC_POWER_PROFILE_VIDEO = 0x2, + PP_SMC_POWER_PROFILE_VR = 0x3, + PP_SMC_POWER_PROFILE_COMPUTE = 0x4, + PP_SMC_POWER_PROFILE_CUSTOM = 0x5, + PP_SMC_POWER_PROFILE_AUTO = 0x6, +}; enum { PP_GROUP_UNKNOWN = 0, @@ -149,6 +161,13 @@ enum { PP_GROUP_MAX }; +enum PP_OD_DPM_TABLE_COMMAND { + PP_OD_EDIT_SCLK_VDDC_TABLE, + PP_OD_EDIT_MCLK_VDDC_TABLE, + PP_OD_RESTORE_DEFAULT_TABLE, + PP_OD_COMMIT_DPM_TABLE +}; + struct pp_states_info { uint32_t nums; uint32_t states[16]; @@ -222,7 +241,6 @@ struct amd_pm_funcs { void *rps, bool *equal); /* export for sysfs */ - int (*get_temperature)(void *handle); void (*set_fan_control_mode)(void *handle, u32 mode); u32 (*get_fan_control_mode)(void *handle); int (*set_fan_speed_percent)(void *handle, u32 speed); @@ -256,7 +274,7 @@ struct amd_pm_funcs { void (*powergate_vce)(void *handle, bool gate); struct amd_vce_state *(*get_vce_clock_state)(void *handle, u32 idx); int (*dispatch_tasks)(void *handle, enum amd_pp_task task_id, - void *input, void *output); + enum amd_pm_state_type *user_state); int (*load_firmware)(void *handle); int (*wait_for_fw_loading_complete)(void *handle); int (*set_clockgating_by_smu)(void *handle, uint32_t msg_id); @@ -265,6 +283,8 @@ struct amd_pm_funcs { uint32_t mc_addr_low, uint32_t mc_addr_hi, uint32_t size); + int (*set_power_limit)(void *handle, uint32_t n); + int (*get_power_limit)(void *handle, uint32_t *limit, bool default_limit); /* export to DC */ u32 (*get_sclk)(void *handle, bool low); u32 (*get_mclk)(void *handle, bool low); @@ -289,6 +309,10 @@ struct amd_pm_funcs { struct pp_display_clock_request *clock); int (*get_display_mode_validation_clocks)(void *handle, struct amd_pp_simple_clock_info *clocks); + int (*get_power_profile_mode)(void *handle, char *buf); + int (*set_power_profile_mode)(void *handle, long *input, uint32_t size); + int (*odn_edit_dpm_table)(void *handle, uint32_t type, long *input, uint32_t size); + int (*set_mmhub_powergating_by_smu)(void *handle); }; #endif diff --git a/drivers/gpu/drm/amd/include/soc15_hw_ip.h b/drivers/gpu/drm/amd/include/soc15_hw_ip.h new file mode 100644 index 000000000000..f17e30cb4eae --- /dev/null +++ b/drivers/gpu/drm/amd/include/soc15_hw_ip.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef _soc15_hw_ip_HEADER +#define _soc15_hw_ip_HEADER + +// HW ID +#define MP1_HWID 1 +#define MP2_HWID 2 +#define THM_HWID 3 +#define SMUIO_HWID 4 +#define FUSE_HWID 5 +#define CLKA_HWID 6 +#define PWR_HWID 10 +#define GC_HWID 11 +#define UVD_HWID 12 +#define VCN_HWID UVD_HWID +#define AUDIO_AZ_HWID 13 +#define ACP_HWID 14 +#define DCI_HWID 15 +#define DMU_HWID 271 +#define DCO_HWID 16 +#define DIO_HWID 272 +#define XDMA_HWID 17 +#define DCEAZ_HWID 18 +#define DAZ_HWID 274 +#define SDPMUX_HWID 19 +#define NTB_HWID 20 +#define IOHC_HWID 24 +#define L2IMU_HWID 28 +#define VCE_HWID 32 +#define MMHUB_HWID 34 +#define ATHUB_HWID 35 +#define DBGU_NBIO_HWID 36 +#define DFX_HWID 37 +#define DBGU0_HWID 38 +#define DBGU1_HWID 39 +#define OSSSYS_HWID 40 +#define HDP_HWID 41 +#define SDMA0_HWID 42 +#define SDMA1_HWID 43 +#define ISP_HWID 44 +#define DBGU_IO_HWID 45 +#define DF_HWID 46 +#define CLKB_HWID 47 +#define FCH_HWID 48 +#define DFX_DAP_HWID 49 +#define L1IMU_PCIE_HWID 50 +#define L1IMU_NBIF_HWID 51 +#define L1IMU_IOAGR_HWID 52 +#define L1IMU3_HWID 53 +#define L1IMU4_HWID 54 +#define L1IMU5_HWID 55 +#define L1IMU6_HWID 56 +#define L1IMU7_HWID 57 +#define L1IMU8_HWID 58 +#define L1IMU9_HWID 59 +#define L1IMU10_HWID 60 +#define L1IMU11_HWID 61 +#define L1IMU12_HWID 62 +#define L1IMU13_HWID 63 +#define L1IMU14_HWID 64 +#define L1IMU15_HWID 65 +#define WAFLC_HWID 66 +#define FCH_USB_PD_HWID 67 +#define PCIE_HWID 70 +#define PCS_HWID 80 +#define DDCL_HWID 89 +#define SST_HWID 90 +#define IOAGR_HWID 100 +#define NBIF_HWID 108 +#define IOAPIC_HWID 124 +#define SYSTEMHUB_HWID 128 +#define NTBCCP_HWID 144 +#define UMC_HWID 150 +#define SATA_HWID 168 +#define USB_HWID 170 +#define CCXSEC_HWID 176 +#define XGBE_HWID 216 +#define MP0_HWID 254 +#endif diff --git a/drivers/gpu/drm/amd/include/soc15ip.h b/drivers/gpu/drm/amd/include/vega10_ip_offset.h similarity index 92% rename from drivers/gpu/drm/amd/include/soc15ip.h rename to drivers/gpu/drm/amd/include/vega10_ip_offset.h index 1767db69df7a..4c78dba5cf25 100644 --- a/drivers/gpu/drm/amd/include/soc15ip.h +++ b/drivers/gpu/drm/amd/include/vega10_ip_offset.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Advanced Micro Devices, Inc. + * Copyright (C) 2018 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -18,88 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef _soc15ip_new_HEADER -#define _soc15ip_new_HEADER - -// HW ID -#define MP1_HWID 1 -#define MP2_HWID 2 -#define THM_HWID 3 -#define SMUIO_HWID 4 -#define FUSE_HWID 5 -#define CLKA_HWID 6 -#define PWR_HWID 10 -#define GC_HWID 11 -#define UVD_HWID 12 -#define VCN_HWID UVD_HWID -#define AUDIO_AZ_HWID 13 -#define ACP_HWID 14 -#define DCI_HWID 15 -#define DMU_HWID 271 -#define DCO_HWID 16 -#define DIO_HWID 272 -#define XDMA_HWID 17 -#define DCEAZ_HWID 18 -#define DAZ_HWID 274 -#define SDPMUX_HWID 19 -#define NTB_HWID 20 -#define IOHC_HWID 24 -#define L2IMU_HWID 28 -#define VCE_HWID 32 -#define MMHUB_HWID 34 -#define ATHUB_HWID 35 -#define DBGU_NBIO_HWID 36 -#define DFX_HWID 37 -#define DBGU0_HWID 38 -#define DBGU1_HWID 39 -#define OSSSYS_HWID 40 -#define HDP_HWID 41 -#define SDMA0_HWID 42 -#define SDMA1_HWID 43 -#define ISP_HWID 44 -#define DBGU_IO_HWID 45 -#define DF_HWID 46 -#define CLKB_HWID 47 -#define FCH_HWID 48 -#define DFX_DAP_HWID 49 -#define L1IMU_PCIE_HWID 50 -#define L1IMU_NBIF_HWID 51 -#define L1IMU_IOAGR_HWID 52 -#define L1IMU3_HWID 53 -#define L1IMU4_HWID 54 -#define L1IMU5_HWID 55 -#define L1IMU6_HWID 56 -#define L1IMU7_HWID 57 -#define L1IMU8_HWID 58 -#define L1IMU9_HWID 59 -#define L1IMU10_HWID 60 -#define L1IMU11_HWID 61 -#define L1IMU12_HWID 62 -#define L1IMU13_HWID 63 -#define L1IMU14_HWID 64 -#define L1IMU15_HWID 65 -#define WAFLC_HWID 66 -#define FCH_USB_PD_HWID 67 -#define PCIE_HWID 70 -#define PCS_HWID 80 -#define DDCL_HWID 89 -#define SST_HWID 90 -#define IOAGR_HWID 100 -#define NBIF_HWID 108 -#define IOAPIC_HWID 124 -#define SYSTEMHUB_HWID 128 -#define NTBCCP_HWID 144 -#define UMC_HWID 150 -#define SATA_HWID 168 -#define USB_HWID 170 -#define CCXSEC_HWID 176 -#define XGBE_HWID 216 -#define MP0_HWID 254 +#ifndef _vega10_ip_offset_HEADER +#define _vega10_ip_offset_HEADER #define MAX_INSTANCE 5 #define MAX_SEGMENT 5 - struct IP_BASE_INSTANCE { unsigned int segment[MAX_SEGMENT]; @@ -1337,7 +1261,5 @@ static const struct IP_BASE FUSE_BASE = { { { { 0x00017400, 0, 0, 0, 0 } }, #define FUSE_BASE__INST4_SEG2 0 #define FUSE_BASE__INST4_SEG3 0 #define FUSE_BASE__INST4_SEG4 0 - - #endif diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index 4c3223a4d62b..376ed2dd52c7 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -33,7 +33,7 @@ #define PP_DPM_DISABLED 0xCCCC static int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_task task_id, - void *input, void *output); + enum amd_pm_state_type *user_state); static inline int pp_check(struct pp_instance *handle) { @@ -162,7 +162,7 @@ static int pp_hw_init(void *handle) if(hwmgr->smumgr_funcs->start_smu(pp_handle->hwmgr)) { pr_err("smc start failed\n"); hwmgr->smumgr_funcs->smu_fini(pp_handle->hwmgr); - return -EINVAL;; + return -EINVAL; } if (ret == PP_DPM_DISABLED) goto exit; @@ -198,7 +198,7 @@ static int pp_late_init(void *handle) ret = pp_check(pp_handle); if (ret == 0) pp_dpm_dispatch_tasks(pp_handle, - AMD_PP_TASK_COMPLETE_INIT, NULL, NULL); + AMD_PP_TASK_COMPLETE_INIT, NULL); return 0; } @@ -392,7 +392,7 @@ static int pp_dpm_force_performance_level(void *handle, mutex_lock(&pp_handle->pp_lock); pp_dpm_en_umd_pstate(hwmgr, &level); hwmgr->request_dpm_level = level; - hwmgr_handle_task(pp_handle, AMD_PP_TASK_READJUST_POWER_STATE, NULL, NULL); + hwmgr_handle_task(pp_handle, AMD_PP_TASK_READJUST_POWER_STATE, NULL); mutex_unlock(&pp_handle->pp_lock); return 0; @@ -511,7 +511,7 @@ static void pp_dpm_powergate_uvd(void *handle, bool gate) } static int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_task task_id, - void *input, void *output) + enum amd_pm_state_type *user_state) { int ret = 0; struct pp_instance *pp_handle = (struct pp_instance *)handle; @@ -522,7 +522,7 @@ static int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_task task_id, return ret; mutex_lock(&pp_handle->pp_lock); - ret = hwmgr_handle_task(pp_handle, task_id, input, output); + ret = hwmgr_handle_task(pp_handle, task_id, user_state); mutex_unlock(&pp_handle->pp_lock); return ret; @@ -687,29 +687,6 @@ static int pp_dpm_get_fan_speed_rpm(void *handle, uint32_t *rpm) return ret; } -static int pp_dpm_get_temperature(void *handle) -{ - struct pp_hwmgr *hwmgr; - struct pp_instance *pp_handle = (struct pp_instance *)handle; - int ret = 0; - - ret = pp_check(pp_handle); - - if (ret) - return ret; - - hwmgr = pp_handle->hwmgr; - - if (hwmgr->hwmgr_func->get_temperature == NULL) { - pr_info("%s was not implemented.\n", __func__); - return 0; - } - mutex_lock(&pp_handle->pp_lock); - ret = hwmgr->hwmgr_func->get_temperature(hwmgr); - mutex_unlock(&pp_handle->pp_lock); - return ret; -} - static int pp_dpm_get_pp_num_states(void *handle, struct pp_states_info *data) { @@ -799,7 +776,7 @@ static int amd_powerplay_reset(void *handle) if (ret) return ret; - return hwmgr_handle_task(instance, AMD_PP_TASK_COMPLETE_INIT, NULL, NULL); + return hwmgr_handle_task(instance, AMD_PP_TASK_COMPLETE_INIT, NULL); } static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size) @@ -862,7 +839,10 @@ static int pp_dpm_force_clock_level(void *handle, return 0; } mutex_lock(&pp_handle->pp_lock); - hwmgr->hwmgr_func->force_clock_level(hwmgr, type, mask); + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) + ret = hwmgr->hwmgr_func->force_clock_level(hwmgr, type, mask); + else + ret = -EINVAL; mutex_unlock(&pp_handle->pp_lock); return ret; } @@ -992,22 +972,27 @@ static int pp_dpm_read_sensor(void *handle, int idx, int ret = 0; ret = pp_check(pp_handle); - if (ret) return ret; + if (value == NULL) + return -EINVAL; + hwmgr = pp_handle->hwmgr; - if (hwmgr->hwmgr_func->read_sensor == NULL) { - pr_info("%s was not implemented.\n", __func__); + switch (idx) { + case AMDGPU_PP_SENSOR_STABLE_PSTATE_SCLK: + *((uint32_t *)value) = hwmgr->pstate_sclk; return 0; + case AMDGPU_PP_SENSOR_STABLE_PSTATE_MCLK: + *((uint32_t *)value) = hwmgr->pstate_mclk; + return 0; + default: + mutex_lock(&pp_handle->pp_lock); + ret = hwmgr->hwmgr_func->read_sensor(hwmgr, idx, value, size); + mutex_unlock(&pp_handle->pp_lock); + return ret; } - - mutex_lock(&pp_handle->pp_lock); - ret = hwmgr->hwmgr_func->read_sensor(hwmgr, idx, value, size); - mutex_unlock(&pp_handle->pp_lock); - - return ret; } static struct amd_vce_state* @@ -1081,6 +1066,64 @@ static int pp_dpm_get_power_profile_state(void *handle, return 0; } +static int pp_get_power_profile_mode(void *handle, char *buf) +{ + struct pp_hwmgr *hwmgr; + struct pp_instance *pp_handle = (struct pp_instance *)handle; + + if (!buf || pp_check(pp_handle)) + return -EINVAL; + + hwmgr = pp_handle->hwmgr; + + if (hwmgr->hwmgr_func->get_power_profile_mode == NULL) { + pr_info("%s was not implemented.\n", __func__); + return snprintf(buf, PAGE_SIZE, "\n"); + } + + return hwmgr->hwmgr_func->get_power_profile_mode(hwmgr, buf); +} + +static int pp_set_power_profile_mode(void *handle, long *input, uint32_t size) +{ + struct pp_hwmgr *hwmgr; + struct pp_instance *pp_handle = (struct pp_instance *)handle; + int ret = -EINVAL; + + if (pp_check(pp_handle)) + return -EINVAL; + + hwmgr = pp_handle->hwmgr; + + if (hwmgr->hwmgr_func->set_power_profile_mode == NULL) { + pr_info("%s was not implemented.\n", __func__); + return -EINVAL; + } + mutex_lock(&pp_handle->pp_lock); + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) + ret = hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, input, size); + mutex_unlock(&pp_handle->pp_lock); + return ret; +} + +static int pp_odn_edit_dpm_table(void *handle, uint32_t type, long *input, uint32_t size) +{ + struct pp_hwmgr *hwmgr; + struct pp_instance *pp_handle = (struct pp_instance *)handle; + + if (pp_check(pp_handle)) + return -EINVAL; + + hwmgr = pp_handle->hwmgr; + + if (hwmgr->hwmgr_func->odn_edit_dpm_table == NULL) { + pr_info("%s was not implemented.\n", __func__); + return -EINVAL; + } + + return hwmgr->hwmgr_func->odn_edit_dpm_table(hwmgr, type, input, size); +} + static int pp_dpm_set_power_profile_state(void *handle, struct amd_pp_profile *request) { @@ -1194,6 +1237,65 @@ static int pp_dpm_notify_smu_memory_info(void *handle, return ret; } +static int pp_set_power_limit(void *handle, uint32_t limit) +{ + struct pp_hwmgr *hwmgr; + struct pp_instance *pp_handle = (struct pp_instance *)handle; + int ret = 0; + + ret = pp_check(pp_handle); + + if (ret) + return ret; + + hwmgr = pp_handle->hwmgr; + + if (hwmgr->hwmgr_func->set_power_limit == NULL) { + pr_info("%s was not implemented.\n", __func__); + return -EINVAL; + } + + if (limit == 0) + limit = hwmgr->default_power_limit; + + if (limit > hwmgr->default_power_limit) + return -EINVAL; + + mutex_lock(&pp_handle->pp_lock); + hwmgr->hwmgr_func->set_power_limit(hwmgr, limit); + hwmgr->power_limit = limit; + mutex_unlock(&pp_handle->pp_lock); + return ret; +} + +static int pp_get_power_limit(void *handle, uint32_t *limit, bool default_limit) +{ + struct pp_hwmgr *hwmgr; + struct pp_instance *pp_handle = (struct pp_instance *)handle; + int ret = 0; + + ret = pp_check(pp_handle); + + if (ret) + return ret; + + if (limit == NULL) + return -EINVAL; + + hwmgr = pp_handle->hwmgr; + + mutex_lock(&pp_handle->pp_lock); + + if (default_limit) + *limit = hwmgr->default_power_limit; + else + *limit = hwmgr->power_limit; + + mutex_unlock(&pp_handle->pp_lock); + + return ret; +} + static int pp_display_configuration_change(void *handle, const struct amd_pp_display_configuration *display_config) { @@ -1432,8 +1534,28 @@ static int pp_get_display_mode_validation_clocks(void *handle, return ret; } +static int pp_set_mmhub_powergating_by_smu(void *handle) +{ + struct pp_hwmgr *hwmgr; + struct pp_instance *pp_handle = (struct pp_instance *)handle; + int ret = 0; + + ret = pp_check(pp_handle); + + if (ret) + return ret; + + hwmgr = pp_handle->hwmgr; + + if (hwmgr->hwmgr_func->set_mmhub_powergating_by_smu == NULL) { + pr_info("%s was not implemented.\n", __func__); + return 0; + } + + return hwmgr->hwmgr_func->set_mmhub_powergating_by_smu(hwmgr); +} + const struct amd_pm_funcs pp_dpm_funcs = { - .get_temperature = pp_dpm_get_temperature, .load_firmware = pp_dpm_load_fw, .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete, .force_performance_level = pp_dpm_force_performance_level, @@ -1464,6 +1586,11 @@ const struct amd_pm_funcs pp_dpm_funcs = { .switch_power_profile = pp_dpm_switch_power_profile, .set_clockgating_by_smu = pp_set_clockgating_by_smu, .notify_smu_memory_info = pp_dpm_notify_smu_memory_info, + .get_power_profile_mode = pp_get_power_profile_mode, + .set_power_profile_mode = pp_set_power_profile_mode, + .odn_edit_dpm_table = pp_odn_edit_dpm_table, + .set_power_limit = pp_set_power_limit, + .get_power_limit = pp_get_power_limit, /* export to DC */ .get_sclk = pp_dpm_get_sclk, .get_mclk = pp_dpm_get_mclk, @@ -1476,4 +1603,5 @@ const struct amd_pm_funcs pp_dpm_funcs = { .set_watermarks_for_clocks_ranges = pp_set_watermarks_for_clocks_ranges, .display_clock_voltage_request = pp_display_clock_voltage_request, .get_display_mode_validation_clocks = pp_get_display_mode_validation_clocks, + .set_mmhub_powergating_by_smu = pp_set_mmhub_powergating_by_smu, }; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c index 44de0874629f..416abebb8b86 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c @@ -166,10 +166,10 @@ void cz_dpm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate) cz_dpm_powerup_uvd(hwmgr); cgs_set_clockgating_state(hwmgr->device, AMD_IP_BLOCK_TYPE_UVD, - AMD_PG_STATE_UNGATE); + AMD_CG_STATE_UNGATE); cgs_set_powergating_state(hwmgr->device, AMD_IP_BLOCK_TYPE_UVD, - AMD_CG_STATE_UNGATE); + AMD_PG_STATE_UNGATE); cz_dpm_update_uvd_dpm(hwmgr, false); } @@ -197,11 +197,11 @@ void cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate) cgs_set_clockgating_state( hwmgr->device, AMD_IP_BLOCK_TYPE_VCE, - AMD_PG_STATE_UNGATE); + AMD_CG_STATE_UNGATE); cgs_set_powergating_state( hwmgr->device, AMD_IP_BLOCK_TYPE_VCE, - AMD_CG_STATE_UNGATE); + AMD_PG_STATE_UNGATE); cz_dpm_update_vce_dpm(hwmgr); cz_enable_disable_vce_dpm(hwmgr, true); } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c index b314d09d41af..5a7b99f45d36 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c @@ -38,6 +38,7 @@ #include "cz_hwmgr.h" #include "power_state.h" #include "cz_clockpowergating.h" +#include "pp_thermal.h" #define ixSMUSVI_NB_CURRENTVID 0xD8230044 #define CURRENT_NB_VID_MASK 0xff000000 @@ -172,16 +173,12 @@ static uint32_t cz_get_max_sclk_level(struct pp_hwmgr *hwmgr) static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) { struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); - uint32_t i; struct cgs_system_info sys_info = {0}; int result; cz_hwmgr->gfx_ramp_step = 256*25/100; cz_hwmgr->gfx_ramp_delay = 1; /* by default, we delay 1us */ - for (i = 0; i < CZ_MAX_HARDWARE_POWERLEVELS; i++) - cz_hwmgr->activity_target[i] = CZ_AT_DFLT; - cz_hwmgr->mgcg_cgtt_local0 = 0x00000000; cz_hwmgr->mgcg_cgtt_local1 = 0x00000000; cz_hwmgr->clock_slow_down_freq = 25000; @@ -1188,6 +1185,8 @@ static int cz_phm_unforce_dpm_levels(struct pp_hwmgr *hwmgr) cz_hwmgr->sclk_dpm.soft_min_clk = table->entries[0].clk; cz_hwmgr->sclk_dpm.hard_min_clk = table->entries[0].clk; + hwmgr->pstate_sclk = table->entries[0].clk; + hwmgr->pstate_mclk = 0; level = cz_get_max_sclk_level(hwmgr) - 1; @@ -1559,9 +1558,6 @@ static int cz_get_dal_power_level(struct pp_hwmgr *hwmgr, static int cz_force_clock_level(struct pp_hwmgr *hwmgr, enum pp_clock_type type, uint32_t mask) { - if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) - return -EINVAL; - switch (type) { case PP_SCLK: smum_send_msg_to_smc_with_parameter(hwmgr, @@ -1581,6 +1577,7 @@ static int cz_force_clock_level(struct pp_hwmgr *hwmgr, static int cz_print_clock_levels(struct pp_hwmgr *hwmgr, enum pp_clock_type type, char *buf) { + struct cz_hwmgr *data = (struct cz_hwmgr *)(hwmgr->backend); struct phm_clock_voltage_dependency_table *sclk_table = hwmgr->dyn_state.vddc_dependency_on_sclk; int i, now, size = 0; @@ -1598,6 +1595,18 @@ static int cz_print_clock_levels(struct pp_hwmgr *hwmgr, i, sclk_table->entries[i].clk / 100, (i == now) ? "*" : ""); break; + case PP_MCLK: + now = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, + CGS_IND_REG__SMC, + ixTARGET_AND_CURRENT_PROFILE_INDEX), + TARGET_AND_CURRENT_PROFILE_INDEX, + CURR_MCLK_INDEX); + + for (i = CZ_NUM_NBPMEMORYCLOCK; i > 0; i--) + size += sprintf(buf + size, "%d: %uMhz %s\n", + CZ_NUM_NBPMEMORYCLOCK-i, data->sys_info.nbp_memory_clock[i-1] / 100, + (CZ_NUM_NBPMEMORYCLOCK-i == now) ? "*" : ""); + break; default: break; } @@ -1858,6 +1867,19 @@ static int cz_notify_cac_buffer_info(struct pp_hwmgr *hwmgr, return 0; } +static int cz_get_thermal_temperature_range(struct pp_hwmgr *hwmgr, + struct PP_TemperatureRange *thermal_data) +{ + struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); + + memcpy(thermal_data, &SMU7ThermalPolicy[0], sizeof(struct PP_TemperatureRange)); + + thermal_data->max = (cz_hwmgr->thermal_auto_throttling_treshold + + cz_hwmgr->sys_info.htc_hyst_lmt) * + PP_TEMPERATURE_UNITS_PER_CENTIGRADES; + + return 0; +} static const struct pp_hwmgr_func cz_hwmgr_funcs = { .backend_init = cz_hwmgr_backend_init, @@ -1882,7 +1904,6 @@ static const struct pp_hwmgr_func cz_hwmgr_funcs = { .get_current_shallow_sleep_clocks = cz_get_current_shallow_sleep_clocks, .get_clock_by_type = cz_get_clock_by_type, .get_max_high_clocks = cz_get_max_high_clocks, - .get_temperature = cz_thermal_get_temperature, .read_sensor = cz_read_sensor, .power_off_asic = cz_power_off_asic, .asic_setup = cz_setup_asic_task, @@ -1890,6 +1911,7 @@ static const struct pp_hwmgr_func cz_hwmgr_funcs = { .power_state_set = cz_set_power_state_tasks, .dynamic_state_management_disable = cz_disable_dpm_tasks, .notify_cac_buffer_info = cz_notify_cac_buffer_info, + .get_thermal_temperature_range = cz_get_thermal_temperature_range, }; int cz_init_function_pointers(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h index 508b422d6159..468c739a4299 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.h @@ -30,7 +30,6 @@ #define CZ_NUM_NBPSTATES 4 #define CZ_NUM_NBPMEMORYCLOCK 2 #define MAX_DISPLAY_CLOCK_LEVEL 8 -#define CZ_AT_DFLT 30 #define CZ_MAX_HARDWARE_POWERLEVELS 8 #define PPCZ_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102 #define CZ_MIN_DEEP_SLEEP_SCLK 800 @@ -185,7 +184,6 @@ struct cc6_settings { }; struct cz_hwmgr { - uint32_t activity_target[CZ_MAX_HARDWARE_POWERLEVELS]; uint32_t dpm_interval; uint32_t voltage_drop_threshold; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c index 2b0c53fe4c8d..fdd2c05d25d5 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c @@ -223,26 +223,25 @@ int phm_register_thermal_interrupt(struct pp_hwmgr *hwmgr, const void *info) * Initializes the thermal controller subsystem. * * @param pHwMgr the address of the powerplay hardware manager. -* @param pTemperatureRange the address of the structure holding the temperature range. * @exception PP_Result_Failed if any of the paramters is NULL, otherwise the return value from the dispatcher. */ -int phm_start_thermal_controller(struct pp_hwmgr *hwmgr, struct PP_TemperatureRange *temperature_range) +int phm_start_thermal_controller(struct pp_hwmgr *hwmgr) { - struct PP_TemperatureRange range; + int ret = 0; + struct PP_TemperatureRange range = {TEMP_RANGE_MIN, TEMP_RANGE_MAX}; + + if (hwmgr->hwmgr_func->get_thermal_temperature_range) + hwmgr->hwmgr_func->get_thermal_temperature_range( + hwmgr, &range); - if (temperature_range == NULL) { - range.max = TEMP_RANGE_MAX; - range.min = TEMP_RANGE_MIN; - } else { - range.max = temperature_range->max; - range.min = temperature_range->min; - } if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ThermalController) && hwmgr->hwmgr_func->start_thermal_controller != NULL) - return hwmgr->hwmgr_func->start_thermal_controller(hwmgr, &range); + ret = hwmgr->hwmgr_func->start_thermal_controller(hwmgr, &range); - return 0; + cgs_set_temperature_range(hwmgr->device, range.min, range.max); + + return ret; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index 0229f774f7a9..33eabc18211d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c @@ -60,6 +60,11 @@ uint8_t convert_to_vid(uint16_t vddc) return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25); } +uint16_t convert_to_vddc(uint8_t vid) +{ + return (uint16_t) ((6200 - (vid * 25)) / VOLTAGE_SCALE); +} + static int phm_get_pci_bus_devfn(struct pp_hwmgr *hwmgr, struct cgs_system_info *sys_info) { @@ -162,9 +167,11 @@ int hwmgr_early_init(struct pp_instance *handle) hwmgr->feature_mask &= ~(PP_VBI_TIME_SUPPORT_MASK | PP_ENABLE_GFX_CG_THRU_SMU); hwmgr->pp_table_version = PP_TABLE_V0; + hwmgr->od_enabled = false; smu7_init_function_pointers(hwmgr); break; case AMDGPU_FAMILY_CZ: + hwmgr->od_enabled = false; hwmgr->smumgr_funcs = &cz_smu_funcs; cz_init_function_pointers(hwmgr); break; @@ -176,6 +183,7 @@ int hwmgr_early_init(struct pp_instance *handle) hwmgr->feature_mask &= ~ (PP_VBI_TIME_SUPPORT_MASK | PP_ENABLE_GFX_CG_THRU_SMU); hwmgr->pp_table_version = PP_TABLE_V0; + hwmgr->od_enabled = false; break; case CHIP_TONGA: hwmgr->smumgr_funcs = &tonga_smu_funcs; @@ -213,6 +221,7 @@ int hwmgr_early_init(struct pp_instance *handle) case AMDGPU_FAMILY_RV: switch (hwmgr->chip_id) { case CHIP_RAVEN: + hwmgr->od_enabled = false; hwmgr->smumgr_funcs = &rv_smu_funcs; rv_init_function_pointers(hwmgr); break; @@ -261,7 +270,7 @@ int hwmgr_hw_init(struct pp_instance *handle) ret = phm_enable_dynamic_state_management(hwmgr); if (ret) goto err2; - ret = phm_start_thermal_controller(hwmgr, NULL); + ret = phm_start_thermal_controller(hwmgr); ret |= psm_set_performance_states(hwmgr); if (ret) goto err2; @@ -341,7 +350,7 @@ int hwmgr_hw_resume(struct pp_instance *handle) ret = phm_enable_dynamic_state_management(hwmgr); if (ret) return ret; - ret = phm_start_thermal_controller(hwmgr, NULL); + ret = phm_start_thermal_controller(hwmgr); if (ret) return ret; @@ -369,7 +378,7 @@ static enum PP_StateUILabel power_state_convert(enum amd_pm_state_type state) } int hwmgr_handle_task(struct pp_instance *handle, enum amd_pp_task task_id, - void *input, void *output) + enum amd_pm_state_type *user_state) { int ret = 0; struct pp_hwmgr *hwmgr; @@ -391,17 +400,15 @@ int hwmgr_handle_task(struct pp_instance *handle, enum amd_pp_task task_id, break; case AMD_PP_TASK_ENABLE_USER_STATE: { - enum amd_pm_state_type ps; enum PP_StateUILabel requested_ui_label; struct pp_power_state *requested_ps = NULL; - if (input == NULL) { + if (user_state == NULL) { ret = -EINVAL; break; } - ps = *(unsigned long *)input; - requested_ui_label = power_state_convert(ps); + requested_ui_label = power_state_convert(*user_state); ret = psm_set_user_performance_state(hwmgr, requested_ui_label, &requested_ps); if (ret) return ret; @@ -932,6 +939,9 @@ int hwmgr_set_user_specify_caps(struct pp_hwmgr *hwmgr) PHM_PlatformCaps_CAC); } + if (hwmgr->feature_mask & PP_OVERDRIVE_MASK) + hwmgr->od_enabled = true; + return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c b/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c index b49d65c3e984..c9eecce5683f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c @@ -836,10 +836,10 @@ static int init_over_drive_limits( hwmgr->platform_descriptor.maxOverdriveVDDC = 0; hwmgr->platform_descriptor.overdriveVDDCStep = 0; - if (hwmgr->platform_descriptor.overdriveLimit.engineClock > 0 \ - && hwmgr->platform_descriptor.overdriveLimit.memoryClock > 0) { - phm_cap_set(hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_ACOverdriveSupport); + if (hwmgr->platform_descriptor.overdriveLimit.engineClock == 0 \ + || hwmgr->platform_descriptor.overdriveLimit.memoryClock == 0) { + hwmgr->od_enabled = false; + pr_debug("OverDrive feature not support by VBIOS\n"); } return 0; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c index c3e7e34535e8..36ca7c419c90 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c @@ -1074,12 +1074,11 @@ static int init_overdrive_limits(struct pp_hwmgr *hwmgr, powerplay_table, (const ATOM_FIRMWARE_INFO_V2_1 *)fw_info); - if (hwmgr->platform_descriptor.overdriveLimit.engineClock > 0 - && hwmgr->platform_descriptor.overdriveLimit.memoryClock > 0 - && !phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_OverdriveDisabledByPowerBudget)) - phm_cap_set(hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_ACOverdriveSupport); + if (hwmgr->platform_descriptor.overdriveLimit.engineClock == 0 + && hwmgr->platform_descriptor.overdriveLimit.memoryClock == 0) { + hwmgr->od_enabled = false; + pr_debug("OverDrive feature not support by VBIOS\n"); + } return result; } @@ -1697,9 +1696,6 @@ static int pp_tables_uninitialize(struct pp_hwmgr *hwmgr) kfree(hwmgr->dyn_state.vdd_gfx_dependency_on_sclk); hwmgr->dyn_state.vdd_gfx_dependency_on_sclk = NULL; - kfree(hwmgr->dyn_state.vq_budgeting_table); - hwmgr->dyn_state.vq_budgeting_table = NULL; - return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.c index 569073e3a5a1..8ddfb78f28cc 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.c @@ -451,6 +451,9 @@ static int rv_hwmgr_backend_init(struct pp_hwmgr *hwmgr) hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50; + hwmgr->pstate_sclk = RAVEN_UMD_PSTATE_GFXCLK; + hwmgr->pstate_mclk = RAVEN_UMD_PSTATE_FCLK; + return result; } @@ -1023,6 +1026,11 @@ static int rv_read_sensor(struct pp_hwmgr *hwmgr, int idx, return ret; } +static int rv_set_mmhub_powergating_by_smu(struct pp_hwmgr *hwmgr) +{ + return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_PowerGateMmHub); +} + static const struct pp_hwmgr_func rv_hwmgr_funcs = { .backend_init = rv_hwmgr_backend_init, .backend_fini = rv_hwmgr_backend_fini, @@ -1056,6 +1064,7 @@ static const struct pp_hwmgr_func rv_hwmgr_funcs = { .asic_setup = rv_setup_asic_task, .power_state_set = rv_set_power_state_tasks, .dynamic_state_management_disable = rv_disable_dpm_tasks, + .set_mmhub_powergating_by_smu = rv_set_mmhub_powergating_by_smu, }; int rv_init_function_pointers(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c index 69a0678ace98..402aa9cb1f78 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c @@ -162,7 +162,7 @@ void smu7_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate) AMD_CG_STATE_UNGATE); cgs_set_powergating_state(hwmgr->device, AMD_IP_BLOCK_TYPE_UVD, - AMD_CG_STATE_UNGATE); + AMD_PG_STATE_UNGATE); smu7_update_uvd_dpm(hwmgr, false); } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_dyn_defaults.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_dyn_defaults.h index f967613191cf..3477d4dfff70 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_dyn_defaults.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_dyn_defaults.h @@ -50,6 +50,6 @@ #define SMU7_CGULVCONTROL_DFLT 0x00007450 #define SMU7_TARGETACTIVITY_DFLT 50 #define SMU7_MCLK_TARGETACTIVITY_DFLT 10 - +#define SMU7_SCLK_TARGETACTIVITY_DFLT 30 #endif diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 41e42beff213..0202841ae639 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -48,6 +48,7 @@ #include "smu7_thermal.h" #include "smu7_clockpowergating.h" #include "processpptables.h" +#include "pp_thermal.h" #define MC_CG_ARB_FREQ_F0 0x0a #define MC_CG_ARB_FREQ_F1 0x0b @@ -90,7 +91,6 @@ enum DPM_EVENT_SRC { DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL = 4 }; -static int smu7_avfs_control(struct pp_hwmgr *hwmgr, bool enable); static const unsigned long PhwVIslands_Magic = (unsigned long)(PHM_VIslands_Magic); static int smu7_force_clock_level(struct pp_hwmgr *hwmgr, enum pp_clock_type type, uint32_t mask); @@ -792,6 +792,76 @@ static int smu7_setup_dpm_tables_v1(struct pp_hwmgr *hwmgr) return 0; } +static int smu7_get_voltage_dependency_table( + const struct phm_ppt_v1_clock_voltage_dependency_table *allowed_dep_table, + struct phm_ppt_v1_clock_voltage_dependency_table *dep_table) +{ + uint8_t i = 0; + PP_ASSERT_WITH_CODE((0 != allowed_dep_table->count), + "Voltage Lookup Table empty", + return -EINVAL); + + dep_table->count = allowed_dep_table->count; + for (i=0; icount; i++) { + dep_table->entries[i].clk = allowed_dep_table->entries[i].clk; + dep_table->entries[i].vddInd = allowed_dep_table->entries[i].vddInd; + dep_table->entries[i].vdd_offset = allowed_dep_table->entries[i].vdd_offset; + dep_table->entries[i].vddc = allowed_dep_table->entries[i].vddc; + dep_table->entries[i].vddgfx = allowed_dep_table->entries[i].vddgfx; + dep_table->entries[i].vddci = allowed_dep_table->entries[i].vddci; + dep_table->entries[i].mvdd = allowed_dep_table->entries[i].mvdd; + dep_table->entries[i].phases = allowed_dep_table->entries[i].phases; + dep_table->entries[i].cks_enable = allowed_dep_table->entries[i].cks_enable; + dep_table->entries[i].cks_voffset = allowed_dep_table->entries[i].cks_voffset; + } + + return 0; +} + +static int smu7_odn_initial_default_setting(struct pp_hwmgr *hwmgr) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + struct smu7_odn_dpm_table *odn_table = &(data->odn_dpm_table); + struct phm_ppt_v1_information *table_info = + (struct phm_ppt_v1_information *)(hwmgr->pptable); + uint32_t i; + + struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table; + struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table; + + if (table_info == NULL) + return -EINVAL; + + dep_sclk_table = table_info->vdd_dep_on_sclk; + dep_mclk_table = table_info->vdd_dep_on_mclk; + + odn_table->odn_core_clock_dpm_levels.num_of_pl = + data->golden_dpm_table.sclk_table.count; + for (i=0; igolden_dpm_table.sclk_table.count; i++) { + odn_table->odn_core_clock_dpm_levels.entries[i].clock = + data->golden_dpm_table.sclk_table.dpm_levels[i].value; + odn_table->odn_core_clock_dpm_levels.entries[i].enabled = true; + odn_table->odn_core_clock_dpm_levels.entries[i].vddc = dep_sclk_table->entries[i].vddc; + } + + smu7_get_voltage_dependency_table(dep_sclk_table, + (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dependency_on_sclk)); + + odn_table->odn_memory_clock_dpm_levels.num_of_pl = + data->golden_dpm_table.mclk_table.count; + for (i=0; igolden_dpm_table.sclk_table.count; i++) { + odn_table->odn_memory_clock_dpm_levels.entries[i].clock = + data->golden_dpm_table.mclk_table.dpm_levels[i].value; + odn_table->odn_memory_clock_dpm_levels.entries[i].enabled = true; + odn_table->odn_memory_clock_dpm_levels.entries[i].vddc = dep_mclk_table->entries[i].vddc; + } + + smu7_get_voltage_dependency_table(dep_mclk_table, + (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dependency_on_mclk)); + + return 0; +} + static int smu7_setup_default_dpm_tables(struct pp_hwmgr *hwmgr) { struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); @@ -808,6 +878,11 @@ static int smu7_setup_default_dpm_tables(struct pp_hwmgr *hwmgr) /* save a copy of the default DPM table */ memcpy(&(data->golden_dpm_table), &(data->dpm_table), sizeof(struct smu7_dpm_table)); + + /* initialize ODN table */ + if (hwmgr->od_enabled) + smu7_odn_initial_default_setting(hwmgr); + return 0; } @@ -1275,6 +1350,58 @@ static int smu7_enable_dpm_tasks(struct pp_hwmgr *hwmgr) return 0; } +static int smu7_avfs_control(struct pp_hwmgr *hwmgr, bool enable) +{ + struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); + + if (smu_data == NULL) + return -EINVAL; + + if (smu_data->avfs.avfs_btc_status == AVFS_BTC_NOTSUPPORTED) + return 0; + + if (enable) { + if (!PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, + CGS_IND_REG__SMC, FEATURE_STATUS, AVS_ON)) { + PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc( + hwmgr, PPSMC_MSG_EnableAvfs), + "Failed to enable AVFS!", + return -EINVAL); + } + } else if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, + CGS_IND_REG__SMC, FEATURE_STATUS, AVS_ON)) { + PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc( + hwmgr, PPSMC_MSG_DisableAvfs), + "Failed to disable AVFS!", + return -EINVAL); + } + + return 0; +} + +static int smu7_update_avfs(struct pp_hwmgr *hwmgr) +{ + struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + + if (smu_data == NULL) + return -EINVAL; + + if (smu_data->avfs.avfs_btc_status == AVFS_BTC_NOTSUPPORTED) + return 0; + + if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_VDDC) { + smu7_avfs_control(hwmgr, false); + } else if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) { + smu7_avfs_control(hwmgr, false); + smu7_avfs_control(hwmgr, true); + } else { + smu7_avfs_control(hwmgr, true); + } + + return 0; +} + int smu7_disable_dpm_tasks(struct pp_hwmgr *hwmgr) { int tmp_result, result = 0; @@ -1357,7 +1484,6 @@ static void smu7_init_dpm_defaults(struct pp_hwmgr *hwmgr) data->dll_default_on = false; data->mclk_dpm0_activity_target = 0xa; - data->mclk_activity_target = SMU7_MCLK_TARGETACTIVITY_DFLT; data->vddc_vddgfx_delta = 300; data->static_screen_threshold = SMU7_STATICSCREENTHRESHOLD_DFLT; data->static_screen_threshold_unit = SMU7_STATICSCREENTHRESHOLDUNIT_DFLT; @@ -1381,6 +1507,14 @@ static void smu7_init_dpm_defaults(struct pp_hwmgr *hwmgr) data->enable_pkg_pwr_tracking_feature = true; data->force_pcie_gen = PP_PCIEGenInvalid; data->ulv_supported = hwmgr->feature_mask & PP_ULV_MASK ? true : false; + data->current_profile_setting.bupdate_sclk = 1; + data->current_profile_setting.sclk_up_hyst = 0; + data->current_profile_setting.sclk_down_hyst = 100; + data->current_profile_setting.sclk_activity = SMU7_SCLK_TARGETACTIVITY_DFLT; + data->current_profile_setting.bupdate_sclk = 1; + data->current_profile_setting.mclk_up_hyst = 0; + data->current_profile_setting.mclk_down_hyst = 100; + data->current_profile_setting.mclk_activity = SMU7_MCLK_TARGETACTIVITY_DFLT; if (hwmgr->chip_id == CHIP_POLARIS12 || hwmgr->is_kicker) { uint8_t tmp1, tmp2; @@ -2266,14 +2400,18 @@ static int smu7_set_private_data_based_on_pptable_v0(struct pp_hwmgr *hwmgr) struct phm_clock_voltage_dependency_table *allowed_mclk_vddci_table = hwmgr->dyn_state.vddci_dependency_on_mclk; PP_ASSERT_WITH_CODE(allowed_sclk_vddc_table != NULL, - "VDDC dependency on SCLK table is missing. This table is mandatory\n", return -EINVAL); + "VDDC dependency on SCLK table is missing. This table is mandatory", + return -EINVAL); PP_ASSERT_WITH_CODE(allowed_sclk_vddc_table->count >= 1, - "VDDC dependency on SCLK table has to have is missing. This table is mandatory\n", return -EINVAL); + "VDDC dependency on SCLK table has to have is missing. This table is mandatory", + return -EINVAL); PP_ASSERT_WITH_CODE(allowed_mclk_vddc_table != NULL, - "VDDC dependency on MCLK table is missing. This table is mandatory\n", return -EINVAL); + "VDDC dependency on MCLK table is missing. This table is mandatory", + return -EINVAL); PP_ASSERT_WITH_CODE(allowed_mclk_vddc_table->count >= 1, - "VDD dependency on MCLK table has to have is missing. This table is mandatory\n", return -EINVAL); + "VDD dependency on MCLK table has to have is missing. This table is mandatory", + return -EINVAL); data->min_vddc_in_pptable = (uint16_t)allowed_sclk_vddc_table->entries[0].v; data->max_vddc_in_pptable = (uint16_t)allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].v; @@ -2574,8 +2712,10 @@ static int smu7_get_profiling_clk(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_le break; } } - if (count < 0 || level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) + if (count < 0 || level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { *sclk_mask = 0; + tmp_sclk = hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].clk; + } if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) *sclk_mask = hwmgr->dyn_state.vddc_dependency_on_sclk->count-1; @@ -2590,8 +2730,10 @@ static int smu7_get_profiling_clk(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_le break; } } - if (count < 0 || level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) + if (count < 0 || level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { *sclk_mask = 0; + tmp_sclk = table_info->vdd_dep_on_sclk->entries[0].clk; + } if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) *sclk_mask = table_info->vdd_dep_on_sclk->count - 1; @@ -2603,6 +2745,9 @@ static int smu7_get_profiling_clk(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_le *mclk_mask = golden_dpm_table->mclk_table.count - 1; *pcie_mask = data->dpm_table.pcie_speed_table.count - 1; + hwmgr->pstate_sclk = tmp_sclk; + hwmgr->pstate_mclk = tmp_mclk; + return 0; } @@ -2614,6 +2759,9 @@ static int smu7_force_dpm_level(struct pp_hwmgr *hwmgr, uint32_t mclk_mask = 0; uint32_t pcie_mask = 0; + if (hwmgr->pstate_sclk == 0) + smu7_get_profiling_clk(hwmgr, level, &sclk_mask, &mclk_mask, &pcie_mask); + switch (level) { case AMD_DPM_FORCED_LEVEL_HIGH: ret = smu7_force_dpm_highest(hwmgr); @@ -2756,10 +2904,12 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, PHM_PlatformCaps_DisableMclkSwitchingForFrameLock); - disable_mclk_switching = ((1 < info.display_count) || - disable_mclk_switching_for_frame_lock || - smu7_vblank_too_short(hwmgr, mode_info.vblank_time_us) || - (mode_info.refresh_rate > 120)); + if (info.display_count == 0) + disable_mclk_switching = false; + else + disable_mclk_switching = ((1 < info.display_count) || + disable_mclk_switching_for_frame_lock || + smu7_vblank_too_short(hwmgr, mode_info.vblank_time_us)); sclk = smu7_ps->performance_levels[0].engine_clock; mclk = smu7_ps->performance_levels[0].memory_clock; @@ -3312,7 +3462,7 @@ static int smu7_read_sensor(struct pp_hwmgr *hwmgr, int idx, void *value, int *size) { uint32_t sclk, mclk, activity_percent; - uint32_t offset; + uint32_t offset, val_vid; struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); /* size must be at least 4 bytes for all sensors */ @@ -3360,6 +3510,16 @@ static int smu7_read_sensor(struct pp_hwmgr *hwmgr, int idx, return -EINVAL; *size = sizeof(struct pp_gpu_power); return smu7_get_gpu_power(hwmgr, (struct pp_gpu_power *)value); + case AMDGPU_PP_SENSOR_VDDGFX: + if ((data->vr_config & 0xff) == 0x2) + val_vid = PHM_READ_INDIRECT_FIELD(hwmgr->device, + CGS_IND_REG__SMC, PWR_SVI2_STATUS, PLANE2_VID); + else + val_vid = PHM_READ_INDIRECT_FIELD(hwmgr->device, + CGS_IND_REG__SMC, PWR_SVI2_STATUS, PLANE1_VID); + + *((uint32_t *)value) = (uint32_t)convert_to_vddc(val_vid); + return 0; default: return -EINVAL; } @@ -3382,8 +3542,6 @@ static int smu7_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, cons uint32_t i; struct cgs_display_info info = {0}; - data->need_update_smu7_dpm_table = 0; - for (i = 0; i < sclk_table->count; i++) { if (sclk == sclk_table->dpm_levels[i].value) break; @@ -3525,108 +3683,27 @@ static int smu7_populate_and_upload_sclk_mclk_dpm_levels( struct pp_hwmgr *hwmgr, const void *input) { int result = 0; - const struct phm_set_power_state_input *states = - (const struct phm_set_power_state_input *)input; - const struct smu7_power_state *smu7_ps = - cast_const_phw_smu7_power_state(states->pnew_state); struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - uint32_t sclk = smu7_ps->performance_levels - [smu7_ps->performance_level_count - 1].engine_clock; - uint32_t mclk = smu7_ps->performance_levels - [smu7_ps->performance_level_count - 1].memory_clock; struct smu7_dpm_table *dpm_table = &data->dpm_table; - - struct smu7_dpm_table *golden_dpm_table = &data->golden_dpm_table; - uint32_t dpm_count, clock_percent; - uint32_t i; + uint32_t count; + struct smu7_odn_dpm_table *odn_table = &(data->odn_dpm_table); + struct phm_odn_clock_levels *odn_sclk_table = &(odn_table->odn_core_clock_dpm_levels); + struct phm_odn_clock_levels *odn_mclk_table = &(odn_table->odn_memory_clock_dpm_levels); if (0 == data->need_update_smu7_dpm_table) return 0; - if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) { - dpm_table->sclk_table.dpm_levels - [dpm_table->sclk_table.count - 1].value = sclk; - - if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinACSupport) || - phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinDCSupport)) { - /* Need to do calculation based on the golden DPM table - * as the Heatmap GPU Clock axis is also based on the default values - */ - PP_ASSERT_WITH_CODE( - (golden_dpm_table->sclk_table.dpm_levels - [golden_dpm_table->sclk_table.count - 1].value != 0), - "Divide by 0!", - return -EINVAL); - dpm_count = dpm_table->sclk_table.count < 2 ? 0 : dpm_table->sclk_table.count - 2; - - for (i = dpm_count; i > 1; i--) { - if (sclk > golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count-1].value) { - clock_percent = - ((sclk - - golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count-1].value - ) * 100) - / golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count-1].value; - - dpm_table->sclk_table.dpm_levels[i].value = - golden_dpm_table->sclk_table.dpm_levels[i].value + - (golden_dpm_table->sclk_table.dpm_levels[i].value * - clock_percent)/100; - - } else if (golden_dpm_table->sclk_table.dpm_levels[dpm_table->sclk_table.count-1].value > sclk) { - clock_percent = - ((golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count - 1].value - - sclk) * 100) - / golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count-1].value; - - dpm_table->sclk_table.dpm_levels[i].value = - golden_dpm_table->sclk_table.dpm_levels[i].value - - (golden_dpm_table->sclk_table.dpm_levels[i].value * - clock_percent) / 100; - } else - dpm_table->sclk_table.dpm_levels[i].value = - golden_dpm_table->sclk_table.dpm_levels[i].value; - } + if (hwmgr->od_enabled && data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK) { + for (count = 0; count < dpm_table->sclk_table.count; count++) { + dpm_table->sclk_table.dpm_levels[count].enabled = odn_sclk_table->entries[count].enabled; + dpm_table->sclk_table.dpm_levels[count].value = odn_sclk_table->entries[count].clock; } } - if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK) { - dpm_table->mclk_table.dpm_levels - [dpm_table->mclk_table.count - 1].value = mclk; - - if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinACSupport) || - phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinDCSupport)) { - - PP_ASSERT_WITH_CODE( - (golden_dpm_table->mclk_table.dpm_levels - [golden_dpm_table->mclk_table.count-1].value != 0), - "Divide by 0!", - return -EINVAL); - dpm_count = dpm_table->mclk_table.count < 2 ? 0 : dpm_table->mclk_table.count - 2; - for (i = dpm_count; i > 1; i--) { - if (golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count-1].value < mclk) { - clock_percent = ((mclk - - golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count-1].value) * 100) - / golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count-1].value; - - dpm_table->mclk_table.dpm_levels[i].value = - golden_dpm_table->mclk_table.dpm_levels[i].value + - (golden_dpm_table->mclk_table.dpm_levels[i].value * - clock_percent) / 100; - - } else if (golden_dpm_table->mclk_table.dpm_levels[dpm_table->mclk_table.count-1].value > mclk) { - clock_percent = ( - (golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count-1].value - mclk) - * 100) - / golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count-1].value; - - dpm_table->mclk_table.dpm_levels[i].value = - golden_dpm_table->mclk_table.dpm_levels[i].value - - (golden_dpm_table->mclk_table.dpm_levels[i].value * - clock_percent) / 100; - } else - dpm_table->mclk_table.dpm_levels[i].value = - golden_dpm_table->mclk_table.dpm_levels[i].value; - } + if (hwmgr->od_enabled && data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK) { + for (count = 0; count < dpm_table->mclk_table.count; count++) { + dpm_table->mclk_table.dpm_levels[count].enabled = odn_mclk_table->entries[count].enabled; + dpm_table->mclk_table.dpm_levels[count].value = odn_mclk_table->entries[count].clock; } } @@ -3748,7 +3825,7 @@ static int smu7_unfreeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr) return -EINVAL); } - data->need_update_smu7_dpm_table = 0; + data->need_update_smu7_dpm_table &= DPMTABLE_OD_UPDATE_VDDC; return 0; } @@ -3825,6 +3902,11 @@ static int smu7_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input) "Failed to populate and upload SCLK MCLK DPM levels!", result = tmp_result); + tmp_result = smu7_update_avfs(hwmgr); + PP_ASSERT_WITH_CODE((0 == tmp_result), + "Failed to update avfs voltages!", + result = tmp_result); + tmp_result = smu7_generate_dpm_level_enable_mask(hwmgr, input); PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to generate DPM level enabled mask!", @@ -4016,6 +4098,7 @@ static int smu7_check_states_equal(struct pp_hwmgr *hwmgr, const struct smu7_power_state *psa; const struct smu7_power_state *psb; int i; + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); if (pstate1 == NULL || pstate2 == NULL || equal == NULL) return -EINVAL; @@ -4040,6 +4123,10 @@ static int smu7_check_states_equal(struct pp_hwmgr *hwmgr, *equal = ((psa->uvd_clks.vclk == psb->uvd_clks.vclk) && (psa->uvd_clks.dclk == psb->uvd_clks.dclk)); *equal &= ((psa->vce_clks.evclk == psb->vce_clks.evclk) && (psa->vce_clks.ecclk == psb->vce_clks.ecclk)); *equal &= (psa->sclk_threshold == psb->sclk_threshold); + /* For OD call, set value based on flag */ + *equal &= !(data->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK | + DPMTABLE_OD_UPDATE_MCLK | + DPMTABLE_OD_UPDATE_VDDC)); return 0; } @@ -4211,9 +4298,7 @@ static int smu7_force_clock_level(struct pp_hwmgr *hwmgr, { struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - if (hwmgr->request_dpm_level & (AMD_DPM_FORCED_LEVEL_AUTO | - AMD_DPM_FORCED_LEVEL_LOW | - AMD_DPM_FORCED_LEVEL_HIGH)) + if (mask == 0) return -EINVAL; switch (type) { @@ -4232,15 +4317,15 @@ static int smu7_force_clock_level(struct pp_hwmgr *hwmgr, case PP_PCIE: { uint32_t tmp = mask & data->dpm_level_enable_mask.pcie_dpm_enable_mask; - uint32_t level = 0; - while (tmp >>= 1) - level++; - - if (!data->pcie_dpm_key_disabled) - smum_send_msg_to_smc_with_parameter(hwmgr, + if (!data->pcie_dpm_key_disabled) { + if (fls(tmp) != ffs(tmp)) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_PCIeDPM_UnForceLevel); + else + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_PCIeDPM_ForceLevel, - level); + fls(tmp) - 1); + } break; } default: @@ -4257,6 +4342,9 @@ static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr, struct smu7_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table); struct smu7_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table); struct smu7_single_dpm_table *pcie_table = &(data->dpm_table.pcie_speed_table); + struct smu7_odn_dpm_table *odn_table = &(data->odn_dpm_table); + struct phm_odn_clock_levels *odn_sclk_table = &(odn_table->odn_core_clock_dpm_levels); + struct phm_odn_clock_levels *odn_mclk_table = &(odn_table->odn_memory_clock_dpm_levels); int i, now, size = 0; uint32_t clock, pcie_speed; @@ -4309,6 +4397,24 @@ static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr, (pcie_table->dpm_levels[i].value == 2) ? "8.0GT/s, x16" : "", (i == now) ? "*" : ""); break; + case OD_SCLK: + if (hwmgr->od_enabled) { + size = sprintf(buf, "%s: \n", "OD_SCLK"); + for (i = 0; i < odn_sclk_table->num_of_pl; i++) + size += sprintf(buf + size, "%d: %10uMhz %10u mV\n", + i, odn_sclk_table->entries[i].clock / 100, + odn_sclk_table->entries[i].vddc); + } + break; + case OD_MCLK: + if (hwmgr->od_enabled) { + size = sprintf(buf, "%s: \n", "OD_MCLK"); + for (i = 0; i < odn_mclk_table->num_of_pl; i++) + size += sprintf(buf + size, "%d: %10uMhz %10u mV\n", + i, odn_mclk_table->entries[i].clock / 100, + odn_mclk_table->entries[i].vddc); + } + break; default: break; } @@ -4583,33 +4689,6 @@ static int smu7_set_power_profile_state(struct pp_hwmgr *hwmgr, return result; } -static int smu7_avfs_control(struct pp_hwmgr *hwmgr, bool enable) -{ - struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); - - if (smu_data == NULL) - return -EINVAL; - - if (smu_data->avfs.avfs_btc_status == AVFS_BTC_NOTSUPPORTED) - return 0; - - if (enable) { - if (!PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, - CGS_IND_REG__SMC, FEATURE_STATUS, AVS_ON)) - PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc( - hwmgr, PPSMC_MSG_EnableAvfs), - "Failed to enable AVFS!", - return -EINVAL); - } else if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, - CGS_IND_REG__SMC, FEATURE_STATUS, AVS_ON)) - PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc( - hwmgr, PPSMC_MSG_DisableAvfs), - "Failed to disable AVFS!", - return -EINVAL); - - return 0; -} - static int smu7_notify_cac_buffer_info(struct pp_hwmgr *hwmgr, uint32_t virtual_addr_low, uint32_t virtual_addr_hi, @@ -4670,6 +4749,192 @@ static int smu7_get_max_high_clocks(struct pp_hwmgr *hwmgr, return 0; } +static int smu7_get_thermal_temperature_range(struct pp_hwmgr *hwmgr, + struct PP_TemperatureRange *thermal_data) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + struct phm_ppt_v1_information *table_info = + (struct phm_ppt_v1_information *)hwmgr->pptable; + + memcpy(thermal_data, &SMU7ThermalPolicy[0], sizeof(struct PP_TemperatureRange)); + + if (hwmgr->pp_table_version == PP_TABLE_V1) + thermal_data->max = table_info->cac_dtp_table->usSoftwareShutdownTemp * + PP_TEMPERATURE_UNITS_PER_CENTIGRADES; + else if (hwmgr->pp_table_version == PP_TABLE_V0) + thermal_data->max = data->thermal_temp_setting.temperature_shutdown * + PP_TEMPERATURE_UNITS_PER_CENTIGRADES; + + return 0; +} + +static bool smu7_check_clk_voltage_valid(struct pp_hwmgr *hwmgr, + enum PP_OD_DPM_TABLE_COMMAND type, + uint32_t clk, + uint32_t voltage) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + + struct phm_ppt_v1_information *table_info = + (struct phm_ppt_v1_information *)(hwmgr->pptable); + uint32_t min_vddc; + struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table; + + if (table_info == NULL) + return -EINVAL; + + dep_sclk_table = table_info->vdd_dep_on_sclk; + min_vddc = dep_sclk_table->entries[0].vddc; + + if (voltage < min_vddc || voltage > 2000) { + pr_info("OD voltage is out of range [%d - 2000] mV\n", min_vddc); + return false; + } + + if (type == PP_OD_EDIT_SCLK_VDDC_TABLE) { + if (data->vbios_boot_state.sclk_bootup_value > clk || + hwmgr->platform_descriptor.overdriveLimit.engineClock < clk) { + pr_info("OD engine clock is out of range [%d - %d] MHz\n", + data->vbios_boot_state.sclk_bootup_value, + hwmgr->platform_descriptor.overdriveLimit.engineClock / 100); + return false; + } + } else if (type == PP_OD_EDIT_MCLK_VDDC_TABLE) { + if (data->vbios_boot_state.mclk_bootup_value > clk || + hwmgr->platform_descriptor.overdriveLimit.memoryClock < clk) { + pr_info("OD memory clock is out of range [%d - %d] MHz\n", + data->vbios_boot_state.mclk_bootup_value/100, + hwmgr->platform_descriptor.overdriveLimit.memoryClock / 100); + return false; + } + } else { + return false; + } + + return true; +} + +static void smu7_check_dpm_table_updated(struct pp_hwmgr *hwmgr) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + struct smu7_odn_dpm_table *odn_table = &(data->odn_dpm_table); + struct phm_ppt_v1_information *table_info = + (struct phm_ppt_v1_information *)(hwmgr->pptable); + uint32_t i; + + struct phm_ppt_v1_clock_voltage_dependency_table *dep_table; + struct phm_ppt_v1_clock_voltage_dependency_table *odn_dep_table; + + if (table_info == NULL) + return; + + for (i=0; idpm_table.sclk_table.count; i++) { + if (odn_table->odn_core_clock_dpm_levels.entries[i].clock != + data->dpm_table.sclk_table.dpm_levels[i].value) { + data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK; + break; + } + } + + for (i=0; idpm_table.sclk_table.count; i++) { + if (odn_table->odn_memory_clock_dpm_levels.entries[i].clock != + data->dpm_table.mclk_table.dpm_levels[i].value) { + data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK; + break; + } + } + + dep_table = table_info->vdd_dep_on_mclk; + odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dependency_on_mclk); + + for (i=0; i < dep_table->count; i++) { + if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) { + data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_VDDC; + break; + } + } + if (i == dep_table->count) + data->need_update_smu7_dpm_table &= ~DPMTABLE_OD_UPDATE_VDDC; + + dep_table = table_info->vdd_dep_on_sclk; + odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dependency_on_sclk); + for (i=0; i < dep_table->count; i++) { + if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) { + data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_VDDC; + break; + } + } + if (i == dep_table->count) + data->need_update_smu7_dpm_table &= ~DPMTABLE_OD_UPDATE_VDDC; +} + +static int smu7_odn_edit_dpm_table(struct pp_hwmgr *hwmgr, + enum PP_OD_DPM_TABLE_COMMAND type, + long *input, uint32_t size) +{ + uint32_t i; + struct phm_odn_clock_levels *podn_dpm_table_in_backend = NULL; + struct smu7_odn_clock_voltage_dependency_table *podn_vdd_dep_in_backend = NULL; + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + + uint32_t input_clk; + uint32_t input_vol; + uint32_t input_level; + + PP_ASSERT_WITH_CODE(input, "NULL user input for clock and voltage", + return -EINVAL); + + if (!hwmgr->od_enabled) { + pr_info("OverDrive feature not enabled\n"); + return -EINVAL; + } + + if (PP_OD_EDIT_SCLK_VDDC_TABLE == type) { + podn_dpm_table_in_backend = &data->odn_dpm_table.odn_core_clock_dpm_levels; + podn_vdd_dep_in_backend = &data->odn_dpm_table.vdd_dependency_on_sclk; + PP_ASSERT_WITH_CODE((podn_dpm_table_in_backend && podn_vdd_dep_in_backend), + "Failed to get ODN SCLK and Voltage tables", + return -EINVAL); + } else if (PP_OD_EDIT_MCLK_VDDC_TABLE == type) { + podn_dpm_table_in_backend = &data->odn_dpm_table.odn_memory_clock_dpm_levels; + podn_vdd_dep_in_backend = &data->odn_dpm_table.vdd_dependency_on_mclk; + + PP_ASSERT_WITH_CODE((podn_dpm_table_in_backend && podn_vdd_dep_in_backend), + "Failed to get ODN MCLK and Voltage tables", + return -EINVAL); + } else if (PP_OD_RESTORE_DEFAULT_TABLE == type) { + smu7_odn_initial_default_setting(hwmgr); + return 0; + } else if (PP_OD_COMMIT_DPM_TABLE == type) { + smu7_check_dpm_table_updated(hwmgr); + return 0; + } else { + return -EINVAL; + } + + for (i = 0; i < size; i += 3) { + if (i + 3 > size || input[i] >= podn_dpm_table_in_backend->num_of_pl) { + pr_info("invalid clock voltage input \n"); + return 0; + } + input_level = input[i]; + input_clk = input[i+1] * 100; + input_vol = input[i+2]; + + if (smu7_check_clk_voltage_valid(hwmgr, type, input_clk, input_vol)) { + podn_dpm_table_in_backend->entries[input_level].clock = input_clk; + podn_vdd_dep_in_backend->entries[input_level].clk = input_clk; + podn_dpm_table_in_backend->entries[input_level].vddc = input_vol; + podn_vdd_dep_in_backend->entries[input_level].vddc = input_vol; + } else { + return -EINVAL; + } + } + + return 0; +} + + static const struct pp_hwmgr_func smu7_hwmgr_funcs = { .backend_init = &smu7_hwmgr_backend_init, .backend_fini = &smu7_hwmgr_backend_fini, @@ -4693,7 +4958,6 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = { .display_config_changed = smu7_display_configuration_changed_task, .set_max_fan_pwm_output = smu7_set_max_fan_pwm_output, .set_max_fan_rpm_output = smu7_set_max_fan_rpm_output, - .get_temperature = smu7_thermal_get_temperature, .stop_thermal_controller = smu7_thermal_stop_thermal_controller, .get_fan_speed_info = smu7_fan_ctrl_get_fan_speed_info, .get_fan_speed_percent = smu7_fan_ctrl_get_fan_speed_percent, @@ -4723,6 +4987,9 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = { .start_thermal_controller = smu7_start_thermal_controller, .notify_cac_buffer_info = smu7_notify_cac_buffer_info, .get_max_high_clocks = smu7_get_max_high_clocks, + .get_thermal_temperature_range = smu7_get_thermal_temperature_range, + .odn_edit_dpm_table = smu7_odn_edit_dpm_table, + .set_power_limit = smu7_set_power_limit, }; uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock, @@ -4754,4 +5021,3 @@ int smu7_init_function_pointers(struct pp_hwmgr *hwmgr) return ret; } - diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h index e021154aedbd..3bcfc61cd5a2 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h @@ -34,11 +34,6 @@ #define SMU7_VOLTAGE_CONTROL_BY_SVID2 0x2 #define SMU7_VOLTAGE_CONTROL_MERGED 0x3 -#define DPMTABLE_OD_UPDATE_SCLK 0x00000001 -#define DPMTABLE_OD_UPDATE_MCLK 0x00000002 -#define DPMTABLE_UPDATE_SCLK 0x00000004 -#define DPMTABLE_UPDATE_MCLK 0x00000008 - enum gpu_pt_config_reg_type { GPU_CONFIGREG_MMR = 0, GPU_CONFIGREG_SMC_IND, @@ -178,9 +173,34 @@ struct smu7_pcie_perf_range { uint16_t min; }; +struct smu7_odn_clock_voltage_dependency_table { + uint32_t count; + phm_ppt_v1_clock_voltage_dependency_record entries[MAX_REGULAR_DPM_NUMBER]; +}; + +struct smu7_odn_dpm_table { + struct phm_odn_clock_levels odn_core_clock_dpm_levels; + struct phm_odn_clock_levels odn_memory_clock_dpm_levels; + struct smu7_odn_clock_voltage_dependency_table vdd_dependency_on_sclk; + struct smu7_odn_clock_voltage_dependency_table vdd_dependency_on_mclk; + uint32_t odn_mclk_min_limit; +}; + +struct profile_mode_setting { + uint8_t bupdate_sclk; + uint8_t sclk_up_hyst; + uint8_t sclk_down_hyst; + uint16_t sclk_activity; + uint8_t bupdate_mclk; + uint8_t mclk_up_hyst; + uint8_t mclk_down_hyst; + uint16_t mclk_activity; +}; + struct smu7_hwmgr { struct smu7_dpm_table dpm_table; struct smu7_dpm_table golden_dpm_table; + struct smu7_odn_dpm_table odn_dpm_table; uint32_t voting_rights_clients[8]; uint32_t static_screen_threshold_unit; @@ -280,7 +300,6 @@ struct smu7_hwmgr { struct smu7_pcie_perf_range pcie_lane_power_saving; bool use_pcie_performance_levels; bool use_pcie_power_saving_levels; - uint32_t mclk_activity_target; uint32_t mclk_dpm0_activity_target; uint32_t low_sclk_interrupt_threshold; uint32_t last_mclk_dpm_enable_mask; @@ -305,6 +324,9 @@ struct smu7_hwmgr { uint32_t frame_time_x2; uint16_t mem_latency_high; uint16_t mem_latency_low; + uint32_t vr_config; + struct profile_mode_setting custom_profile_setting; + struct profile_mode_setting current_profile_setting; }; /* To convert to Q8.8 format for firmware */ diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c index 85ca16abb626..a93829dfd730 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c @@ -857,6 +857,8 @@ int smu7_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n) { struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + n = (n & 0xff) << 8; + if (data->power_containment_features & POWERCONTAINMENT_FEATURE_PkgPwrLimit) return smum_send_msg_to_smc_with_parameter(hwmgr, @@ -903,12 +905,12 @@ int smu7_enable_power_containment(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE((0 == smc_result), "Failed to enable PkgPwrTracking in SMC.", result = -1;); if (0 == smc_result) { - uint32_t default_limit = - (uint32_t)(cac_table->usMaximumPowerDeliveryLimit * 256); + hwmgr->default_power_limit = hwmgr->power_limit = + cac_table->usMaximumPowerDeliveryLimit; data->power_containment_features |= POWERCONTAINMENT_FEATURE_PkgPwrLimit; - if (smu7_set_power_limit(hwmgr, default_limit)) + if (smu7_set_power_limit(hwmgr, hwmgr->power_limit)) pr_err("Failed to set Default Power Limit in SMC!"); } } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.c index d7aa643cdb51..f6573ed0357d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.c @@ -310,9 +310,9 @@ int smu7_thermal_get_temperature(struct pp_hwmgr *hwmgr) static int smu7_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, uint32_t low_temp, uint32_t high_temp) { - uint32_t low = SMU7_THERMAL_MINIMUM_ALERT_TEMP * + int low = SMU7_THERMAL_MINIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; - uint32_t high = SMU7_THERMAL_MAXIMUM_ALERT_TEMP * + int high = SMU7_THERMAL_MAXIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; if (low < low_temp) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 2d55dabc77d4..1d442a498bf6 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -49,6 +49,10 @@ #include "cgs_linux.h" #include "ppinterrupt.h" #include "pp_overdriver.h" +#include "pp_thermal.h" + +#include "smuio/smuio_9_0_offset.h" +#include "smuio/smuio_9_0_sh_mask.h" #define VOLTAGE_SCALE 4 #define VOLTAGE_VID_OFFSET_SCALE1 625 @@ -756,6 +760,9 @@ static int vega10_hwmgr_backend_init(struct pp_hwmgr *hwmgr) hwmgr->backend = data; + hwmgr->power_profile_mode = PP_SMC_POWER_PROFILE_VIDEO; + hwmgr->default_power_profile_mode = PP_SMC_POWER_PROFILE_VIDEO; + vega10_set_default_registry_data(hwmgr); data->disable_dpm_mask = 0xff; @@ -1380,14 +1387,12 @@ static int vega10_setup_default_dpm_tables(struct pp_hwmgr *hwmgr) if (PP_CAP(PHM_PlatformCaps_ODNinACSupport) || PP_CAP(PHM_PlatformCaps_ODNinDCSupport)) { - data->odn_dpm_table.odn_core_clock_dpm_levels. - number_of_performance_levels = data->dpm_table.gfx_table.count; + data->odn_dpm_table.odn_core_clock_dpm_levels.num_of_pl = + data->dpm_table.gfx_table.count; for (i = 0; i < data->dpm_table.gfx_table.count; i++) { - data->odn_dpm_table.odn_core_clock_dpm_levels. - performance_level_entries[i].clock = + data->odn_dpm_table.odn_core_clock_dpm_levels.entries[i].clock = data->dpm_table.gfx_table.dpm_levels[i].value; - data->odn_dpm_table.odn_core_clock_dpm_levels. - performance_level_entries[i].enabled = true; + data->odn_dpm_table.odn_core_clock_dpm_levels.entries[i].enabled = true; } data->odn_dpm_table.vdd_dependency_on_sclk.count = @@ -1403,14 +1408,12 @@ static int vega10_setup_default_dpm_tables(struct pp_hwmgr *hwmgr) dep_gfx_table->entries[i].cks_voffset; } - data->odn_dpm_table.odn_memory_clock_dpm_levels. - number_of_performance_levels = data->dpm_table.mem_table.count; + data->odn_dpm_table.odn_memory_clock_dpm_levels.num_of_pl = + data->dpm_table.mem_table.count; for (i = 0; i < data->dpm_table.mem_table.count; i++) { - data->odn_dpm_table.odn_memory_clock_dpm_levels. - performance_level_entries[i].clock = + data->odn_dpm_table.odn_memory_clock_dpm_levels.entries[i].clock = data->dpm_table.mem_table.dpm_levels[i].value; - data->odn_dpm_table.odn_memory_clock_dpm_levels. - performance_level_entries[i].enabled = true; + data->odn_dpm_table.odn_memory_clock_dpm_levels.entries[i].enabled = true; } data->odn_dpm_table.vdd_dependency_on_mclk.count = dep_mclk_table->count; @@ -3162,16 +3165,19 @@ static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, minimum_clocks.memoryClock = stable_pstate_mclk; } - disable_mclk_switching_for_frame_lock = phm_cap_enabled( - hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_DisableMclkSwitchingForFrameLock); - disable_mclk_switching_for_vr = PP_CAP(PHM_PlatformCaps_DisableMclkSwitchForVR); + disable_mclk_switching_for_frame_lock = + PP_CAP(PHM_PlatformCaps_DisableMclkSwitchingForFrameLock); + disable_mclk_switching_for_vr = + PP_CAP(PHM_PlatformCaps_DisableMclkSwitchForVR); force_mclk_high = PP_CAP(PHM_PlatformCaps_ForceMclkHigh); - disable_mclk_switching = (info.display_count > 1) || - disable_mclk_switching_for_frame_lock || - disable_mclk_switching_for_vr || - force_mclk_high; + if (info.display_count == 0) + disable_mclk_switching = false; + else + disable_mclk_switching = (info.display_count > 1) || + disable_mclk_switching_for_frame_lock || + disable_mclk_switching_for_vr || + force_mclk_high; sclk = vega10_ps->performance_levels[0].gfx_clock; mclk = vega10_ps->performance_levels[0].mem_clock; @@ -3348,11 +3354,9 @@ static int vega10_populate_and_upload_sclk_mclk_dpm_levels( dpm_count < dpm_table->gfx_table.count; dpm_count++) { dpm_table->gfx_table.dpm_levels[dpm_count].enabled = - data->odn_dpm_table.odn_core_clock_dpm_levels. - performance_level_entries[dpm_count].enabled; + data->odn_dpm_table.odn_core_clock_dpm_levels.entries[dpm_count].enabled; dpm_table->gfx_table.dpm_levels[dpm_count].value = - data->odn_dpm_table.odn_core_clock_dpm_levels. - performance_level_entries[dpm_count].clock; + data->odn_dpm_table.odn_core_clock_dpm_levels.entries[dpm_count].clock; } } @@ -3362,11 +3366,9 @@ static int vega10_populate_and_upload_sclk_mclk_dpm_levels( dpm_count < dpm_table->mem_table.count; dpm_count++) { dpm_table->mem_table.dpm_levels[dpm_count].enabled = - data->odn_dpm_table.odn_memory_clock_dpm_levels. - performance_level_entries[dpm_count].enabled; + data->odn_dpm_table.odn_memory_clock_dpm_levels.entries[dpm_count].enabled; dpm_table->mem_table.dpm_levels[dpm_count].value = - data->odn_dpm_table.odn_memory_clock_dpm_levels. - performance_level_entries[dpm_count].clock; + data->odn_dpm_table.odn_memory_clock_dpm_levels.entries[dpm_count].clock; } } @@ -3398,8 +3400,7 @@ static int vega10_populate_and_upload_sclk_mclk_dpm_levels( dpm_table-> gfx_table.dpm_levels[dpm_table->gfx_table.count - 1]. value = sclk; - if (PP_CAP(PHM_PlatformCaps_OD6PlusinACSupport) || - PP_CAP(PHM_PlatformCaps_OD6PlusinDCSupport)) { + if (hwmgr->od_enabled) { /* Need to do calculation based on the golden DPM table * as the Heatmap GPU Clock axis is also based on * the default values @@ -3453,9 +3454,7 @@ static int vega10_populate_and_upload_sclk_mclk_dpm_levels( mem_table.dpm_levels[dpm_table->mem_table.count - 1]. value = mclk; - if (PP_CAP(PHM_PlatformCaps_OD6PlusinACSupport) || - PP_CAP(PHM_PlatformCaps_OD6PlusinDCSupport)) { - + if (hwmgr->od_enabled) { PP_ASSERT_WITH_CODE( golden_dpm_table->mem_table.dpm_levels [golden_dpm_table->mem_table.count - 1].value, @@ -3894,7 +3893,9 @@ static int vega10_get_gpu_power(struct pp_hwmgr *hwmgr, return -EINVAL); vega10_read_arg_from_smc(hwmgr, &value); + /* power value is an integer */ + memset(query, 0, sizeof *query); query->average_gpu_power = value << 8; return 0; @@ -3907,6 +3908,7 @@ static int vega10_read_sensor(struct pp_hwmgr *hwmgr, int idx, struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); struct vega10_dpm_table *dpm_table = &data->dpm_table; int ret = 0; + uint32_t reg, val_vid; switch (idx) { case AMDGPU_PP_SENSOR_GFX_SCLK: @@ -3953,10 +3955,20 @@ static int vega10_read_sensor(struct pp_hwmgr *hwmgr, int idx, ret = vega10_get_gpu_power(hwmgr, (struct pp_gpu_power *)value); } break; + case AMDGPU_PP_SENSOR_VDDGFX: + reg = soc15_get_register_offset(SMUIO_HWID, 0, + mmSMUSVI0_PLANE0_CURRENTVID_BASE_IDX, + mmSMUSVI0_PLANE0_CURRENTVID); + val_vid = (cgs_read_register(hwmgr->device, reg) & + SMUSVI0_PLANE0_CURRENTVID__CURRENT_SVI0_PLANE0_VID_MASK) >> + SMUSVI0_PLANE0_CURRENTVID__CURRENT_SVI0_PLANE0_VID__SHIFT; + *((uint32_t *)value) = (uint32_t)convert_to_vddc((uint8_t)val_vid); + return 0; default: ret = -EINVAL; break; } + return ret; } @@ -4169,6 +4181,8 @@ static int vega10_get_profiling_clk_mask(struct pp_hwmgr *hwmgr, enum amd_dpm_fo *sclk_mask = VEGA10_UMD_PSTATE_GFXCLK_LEVEL; *soc_mask = VEGA10_UMD_PSTATE_SOCCLK_LEVEL; *mclk_mask = VEGA10_UMD_PSTATE_MCLK_LEVEL; + hwmgr->pstate_sclk = table_info->vdd_dep_on_sclk->entries[VEGA10_UMD_PSTATE_GFXCLK_LEVEL].clk; + hwmgr->pstate_mclk = table_info->vdd_dep_on_mclk->entries[VEGA10_UMD_PSTATE_MCLK_LEVEL].clk; } if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { @@ -4210,6 +4224,9 @@ static int vega10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, uint32_t mclk_mask = 0; uint32_t soc_mask = 0; + if (hwmgr->pstate_sclk == 0) + vega10_get_profiling_clk_mask(hwmgr, level, &sclk_mask, &mclk_mask, &soc_mask); + switch (level) { case AMD_DPM_FORCED_LEVEL_HIGH: ret = vega10_force_dpm_highest(hwmgr); @@ -4219,6 +4236,11 @@ static int vega10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, break; case AMD_DPM_FORCED_LEVEL_AUTO: ret = vega10_unforce_dpm_levels(hwmgr); + if (hwmgr->default_power_profile_mode != hwmgr->power_profile_mode) { + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetWorkloadMask, + 1 << hwmgr->default_power_profile_mode); + hwmgr->power_profile_mode = hwmgr->default_power_profile_mode; + } break; case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: @@ -4242,6 +4264,7 @@ static int vega10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, else if (level != AMD_DPM_FORCED_LEVEL_PROFILE_PEAK && hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) vega10_set_fan_control_mode(hwmgr, AMD_FAN_CTRL_AUTO); } + return ret; } @@ -4488,26 +4511,11 @@ static int vega10_force_clock_level(struct pp_hwmgr *hwmgr, enum pp_clock_type type, uint32_t mask) { struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); - int i; - - if (hwmgr->request_dpm_level & (AMD_DPM_FORCED_LEVEL_AUTO | - AMD_DPM_FORCED_LEVEL_LOW | - AMD_DPM_FORCED_LEVEL_HIGH)) - return -EINVAL; switch (type) { case PP_SCLK: - for (i = 0; i < 32; i++) { - if (mask & (1 << i)) - break; - } - data->smc_state_table.gfx_boot_level = i; - - for (i = 31; i >= 0; i--) { - if (mask & (1 << i)) - break; - } - data->smc_state_table.gfx_max_level = i; + data->smc_state_table.gfx_boot_level = mask ? (ffs(mask) - 1) : 0; + data->smc_state_table.gfx_max_level = mask ? (fls(mask) - 1) : 0; PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr), "Failed to upload boot level to lowest!", @@ -4519,17 +4527,8 @@ static int vega10_force_clock_level(struct pp_hwmgr *hwmgr, break; case PP_MCLK: - for (i = 0; i < 32; i++) { - if (mask & (1 << i)) - break; - } - data->smc_state_table.mem_boot_level = i; - - for (i = 31; i >= 0; i--) { - if (mask & (1 << i)) - break; - } - data->smc_state_table.mem_max_level = i; + data->smc_state_table.mem_boot_level = mask ? (ffs(mask) - 1) : 0; + data->smc_state_table.mem_max_level = mask ? (fls(mask) - 1) : 0; PP_ASSERT_WITH_CODE(!vega10_upload_dpm_bootup_level(hwmgr), "Failed to upload boot level to lowest!", @@ -4988,6 +4987,20 @@ static int vega10_notify_cac_buffer_info(struct pp_hwmgr *hwmgr, return 0; } +static int vega10_get_thermal_temperature_range(struct pp_hwmgr *hwmgr, + struct PP_TemperatureRange *thermal_data) +{ + struct phm_ppt_v2_information *table_info = + (struct phm_ppt_v2_information *)hwmgr->pptable; + + memcpy(thermal_data, &SMU7ThermalWithDelayPolicy[0], sizeof(struct PP_TemperatureRange)); + + thermal_data->max = table_info->tdp_table->usSoftwareShutdownTemp * + PP_TEMPERATURE_UNITS_PER_CENTIGRADES; + + return 0; +} + static int vega10_register_thermal_interrupt(struct pp_hwmgr *hwmgr, const void *info) { @@ -5020,6 +5033,77 @@ static int vega10_register_thermal_interrupt(struct pp_hwmgr *hwmgr, return 0; } +static int vega10_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf) +{ + struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); + uint32_t i, size = 0; + static const uint8_t profile_mode_setting[5][4] = {{70, 60, 1, 3,}, + {90, 60, 0, 0,}, + {70, 60, 0, 0,}, + {70, 90, 0, 0,}, + {30, 60, 0, 6,}, + }; + static const char *profile_name[6] = {"3D_FULL_SCREEN", + "POWER_SAVING", + "VIDEO", + "VR", + "COMPUTE", + "CUSTOM"}; + static const char *title[6] = {"NUM", + "MODE_NAME", + "BUSY_SET_POINT", + "FPS", + "USE_RLC_BUSY", + "MIN_ACTIVE_LEVEL"}; + + if (!buf) + return -EINVAL; + + size += sprintf(buf + size, "%s %16s %s %s %s %s\n",title[0], + title[1], title[2], title[3], title[4], title[5]); + + for (i = 0; i < PP_SMC_POWER_PROFILE_CUSTOM; i++) + size += sprintf(buf + size, "%3d %14s%s: %14d %3d %10d %14d\n", + i, profile_name[i], (i == hwmgr->power_profile_mode) ? "*" : " ", + profile_mode_setting[i][0], profile_mode_setting[i][1], + profile_mode_setting[i][2], profile_mode_setting[i][3]); + size += sprintf(buf + size, "%3d %14s%s: %14d %3d %10d %14d\n", i, + profile_name[i], (i == hwmgr->power_profile_mode) ? "*" : " ", + data->custom_profile_mode[0], data->custom_profile_mode[1], + data->custom_profile_mode[2], data->custom_profile_mode[3]); + return size; +} + +static int vega10_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, uint32_t size) +{ + struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend); + uint8_t busy_set_point; + uint8_t FPS; + uint8_t use_rlc_busy; + uint8_t min_active_level; + + hwmgr->power_profile_mode = input[size]; + + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetWorkloadMask, + 1<power_profile_mode); + + if (hwmgr->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { + if (size == 0 || size > 4) + return -EINVAL; + + data->custom_profile_mode[0] = busy_set_point = input[0]; + data->custom_profile_mode[1] = FPS = input[1]; + data->custom_profile_mode[2] = use_rlc_busy = input[2]; + data->custom_profile_mode[3] = min_active_level = input[3]; + smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetCustomGfxDpmParameters, + busy_set_point | FPS<<8 | + use_rlc_busy << 16 | min_active_level<<24); + } + + return 0; +} + static const struct pp_hwmgr_func vega10_hwmgr_funcs = { .backend_init = vega10_hwmgr_backend_init, .backend_fini = vega10_hwmgr_backend_fini, @@ -5038,7 +5122,6 @@ static const struct pp_hwmgr_func vega10_hwmgr_funcs = { .notify_smc_display_config_after_ps_adjustment = vega10_notify_smc_display_config_after_ps_adjustment, .force_dpm_level = vega10_dpm_force_dpm_level, - .get_temperature = vega10_thermal_get_temperature, .stop_thermal_controller = vega10_thermal_stop_thermal_controller, .get_fan_speed_info = vega10_fan_ctrl_get_fan_speed_info, .get_fan_speed_percent = vega10_fan_ctrl_get_fan_speed_percent, @@ -5074,8 +5157,12 @@ static const struct pp_hwmgr_func vega10_hwmgr_funcs = { .set_mclk_od = vega10_set_mclk_od, .avfs_control = vega10_avfs_enable, .notify_cac_buffer_info = vega10_notify_cac_buffer_info, + .get_thermal_temperature_range = vega10_get_thermal_temperature_range, .register_internal_thermal_interrupt = vega10_register_thermal_interrupt, .start_thermal_controller = vega10_start_thermal_controller, + .get_power_profile_mode = vega10_get_power_profile_mode, + .set_power_profile_mode = vega10_set_power_profile_mode, + .set_power_limit = vega10_set_power_limit, }; int vega10_hwmgr_init(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h index e8507ff8dbb3..ab3e8798bee8 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h @@ -189,12 +189,6 @@ struct vega10_vbios_boot_state { uint32_t dcef_clock; }; -#define DPMTABLE_OD_UPDATE_SCLK 0x00000001 -#define DPMTABLE_OD_UPDATE_MCLK 0x00000002 -#define DPMTABLE_UPDATE_SCLK 0x00000004 -#define DPMTABLE_UPDATE_MCLK 0x00000008 -#define DPMTABLE_OD_UPDATE_VDDC 0x00000010 - struct vega10_smc_state_table { uint32_t soc_boot_level; uint32_t gfx_boot_level; @@ -389,6 +383,7 @@ struct vega10_hwmgr { uint32_t config_telemetry; uint32_t acg_loop_state; uint32_t mem_channels; + uint8_t custom_profile_mode[4]; }; #define VEGA10_DPM2_NEAR_TDP_DEC 10 diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c index 598a194737a9..981c9e5431da 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c @@ -1357,10 +1357,11 @@ int vega10_enable_power_containment(struct pp_hwmgr *hwmgr) struct phm_ppt_v2_information *table_info = (struct phm_ppt_v2_information *)(hwmgr->pptable); struct phm_tdp_table *tdp_table = table_info->tdp_table; - uint32_t default_pwr_limit = - (uint32_t)(tdp_table->usMaximumPowerDeliveryLimit); int result = 0; + hwmgr->default_power_limit = hwmgr->power_limit = + (uint32_t)(tdp_table->usMaximumPowerDeliveryLimit); + if (PP_CAP(PHM_PlatformCaps_PowerContainment)) { if (data->smu_features[GNLD_PPT].supported) PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr, @@ -1374,7 +1375,7 @@ int vega10_enable_power_containment(struct pp_hwmgr *hwmgr) "Attempt to enable PPT feature Failed!", data->smu_features[GNLD_TDC].supported = false); - result = vega10_set_power_limit(hwmgr, default_pwr_limit); + result = vega10_set_power_limit(hwmgr, hwmgr->power_limit); PP_ASSERT_WITH_CODE(!result, "Failed to set Default Power Limit in SMC!", return result); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c index f14c7611fad3..6d44cf043618 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c @@ -267,10 +267,10 @@ static int init_over_drive_limits( hwmgr->platform_descriptor.maxOverdriveVDDC = 0; hwmgr->platform_descriptor.overdriveVDDCStep = 0; - if (hwmgr->platform_descriptor.overdriveLimit.engineClock > 0 && - hwmgr->platform_descriptor.overdriveLimit.memoryClock > 0) { - phm_cap_set(hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_ACOverdriveSupport); + if (hwmgr->platform_descriptor.overdriveLimit.engineClock == 0 || + hwmgr->platform_descriptor.overdriveLimit.memoryClock == 0) { + hwmgr->od_enabled = false; + pr_debug("OverDrive feature not support by VBIOS\n"); } return 0; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c index dc3761bcb9b6..749116329c36 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c @@ -386,9 +386,9 @@ int vega10_thermal_get_temperature(struct pp_hwmgr *hwmgr) static int vega10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, struct PP_TemperatureRange *range) { - uint32_t low = VEGA10_THERMAL_MINIMUM_ALERT_TEMP * + int low = VEGA10_THERMAL_MINIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; - uint32_t high = VEGA10_THERMAL_MAXIMUM_ALERT_TEMP * + int high = VEGA10_THERMAL_MAXIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; uint32_t val, reg; diff --git a/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h b/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h index 5716b937a6ad..6f528e662a6f 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h @@ -358,6 +358,17 @@ struct phm_clocks { uint32_t clock[MAX_NUM_CLOCKS]; }; +#define DPMTABLE_OD_UPDATE_SCLK 0x00000001 +#define DPMTABLE_OD_UPDATE_MCLK 0x00000002 +#define DPMTABLE_UPDATE_SCLK 0x00000004 +#define DPMTABLE_UPDATE_MCLK 0x00000008 +#define DPMTABLE_OD_UPDATE_VDDC 0x00000010 + +/* To determine if sclk and mclk are in overdrive state */ +#define SCLK_OVERDRIVE_ENABLED 0x00000001 +#define MCLK_OVERDRIVE_ENABLED 0x00000002 +#define VDDC_OVERDRIVE_ENABLED 0x00000010 + struct phm_odn_performance_level { uint32_t clock; uint32_t vddc; @@ -368,9 +379,9 @@ struct phm_odn_clock_levels { uint32_t size; uint32_t options; uint32_t flags; - uint32_t number_of_performance_levels; - /* variable-sized array, specify by ulNumberOfPerformanceLevels. */ - struct phm_odn_performance_level performance_level_entries[8]; + uint32_t num_of_pl; + /* variable-sized array, specify by num_of_pl. */ + struct phm_odn_performance_level entries[8]; }; extern int phm_disable_clock_power_gatings(struct pp_hwmgr *hwmgr); @@ -393,7 +404,7 @@ extern int phm_force_dpm_levels(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_leve extern int phm_display_configuration_changed(struct pp_hwmgr *hwmgr); extern int phm_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr); extern int phm_register_thermal_interrupt(struct pp_hwmgr *hwmgr, const void *info); -extern int phm_start_thermal_controller(struct pp_hwmgr *hwmgr, struct PP_TemperatureRange *temperature_range); +extern int phm_start_thermal_controller(struct pp_hwmgr *hwmgr); extern int phm_stop_thermal_controller(struct pp_hwmgr *hwmgr); extern bool phm_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr); diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index 565fe0832f41..2a59ee8f4acb 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -42,6 +42,7 @@ struct pp_atomctrl_voltage_table; #define VOLTAGE_SCALE 4 uint8_t convert_to_vid(uint16_t vddc); +uint16_t convert_to_vddc(uint8_t vid); enum DISPLAY_GAP { DISPLAY_GAP_VBLANK_OR_WM = 0, /* Wait for vblank or MCHG watermark. */ @@ -83,6 +84,7 @@ enum PP_FEATURE_MASK { PP_OD_FUZZY_FAN_CONTROL_MASK = 0x800, PP_SOCCLK_DPM_MASK = 0x1000, PP_DCEFCLK_DPM_MASK = 0x2000, + PP_OVERDRIVE_MASK = 0x4000, }; enum PHM_BackEnd_Magic { @@ -277,7 +279,6 @@ struct pp_hwmgr_func { const uint32_t *msg_id); int (*set_max_fan_rpm_output)(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm); int (*set_max_fan_pwm_output)(struct pp_hwmgr *hwmgr, uint16_t us_max_fan_pwm); - int (*get_temperature)(struct pp_hwmgr *hwmgr); int (*stop_thermal_controller)(struct pp_hwmgr *hwmgr); int (*get_fan_speed_info)(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info); void (*set_fan_control_mode)(struct pp_hwmgr *hwmgr, uint32_t mode); @@ -339,6 +340,15 @@ struct pp_hwmgr_func { uint32_t mc_addr_low, uint32_t mc_addr_hi, uint32_t size); + int (*get_thermal_temperature_range)(struct pp_hwmgr *hwmgr, + struct PP_TemperatureRange *range); + int (*get_power_profile_mode)(struct pp_hwmgr *hwmgr, char *buf); + int (*set_power_profile_mode)(struct pp_hwmgr *hwmgr, long *input, uint32_t size); + int (*odn_edit_dpm_table)(struct pp_hwmgr *hwmgr, + enum PP_OD_DPM_TABLE_COMMAND type, + long *input, uint32_t size); + int (*set_power_limit)(struct pp_hwmgr *hwmgr, uint32_t n); + int (*set_mmhub_powergating_by_smu)(struct pp_hwmgr *hwmgr); }; struct pp_table_func { @@ -608,7 +618,6 @@ struct phm_dynamic_state_info { struct phm_ppm_table *ppm_parameter_table; struct phm_cac_tdp_table *cac_dtp_table; struct phm_clock_voltage_dependency_table *vdd_gfx_dependency_on_sclk; - struct phm_vq_budgeting_table *vq_budgeting_table; }; struct pp_fan_info { @@ -747,6 +756,13 @@ struct pp_hwmgr { struct amd_pp_profile default_compute_power_profile; enum amd_pp_profile_type current_power_profile; bool en_umd_pstate; + uint32_t power_profile_mode; + uint32_t default_power_profile_mode; + uint32_t pstate_sclk; + uint32_t pstate_mclk; + bool od_enabled; + uint32_t power_limit; + uint32_t default_power_limit; }; struct cgs_irq_src_funcs { @@ -761,7 +777,7 @@ extern int hwmgr_hw_suspend(struct pp_instance *handle); extern int hwmgr_hw_resume(struct pp_instance *handle); extern int hwmgr_handle_task(struct pp_instance *handle, enum amd_pp_task task_id, - void *input, void *output); + enum amd_pm_state_type *user_state); extern int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index, uint32_t value, uint32_t mask); diff --git a/drivers/gpu/drm/amd/powerplay/inc/polaris10_ppsmc.h b/drivers/gpu/drm/amd/powerplay/inc/polaris10_ppsmc.h deleted file mode 100644 index b8f4b73c322e..000000000000 --- a/drivers/gpu/drm/amd/powerplay/inc/polaris10_ppsmc.h +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef POLARIS10_PP_SMC_H -#define POLARIS10_PP_SMC_H - - -#pragma pack(push, 1) - -#define PPSMC_MSG_SetGBDroopSettings ((uint16_t) 0x305) - -#define PPSMC_SWSTATE_FLAG_DC 0x01 -#define PPSMC_SWSTATE_FLAG_UVD 0x02 -#define PPSMC_SWSTATE_FLAG_VCE 0x04 - -#define PPSMC_THERMAL_PROTECT_TYPE_INTERNAL 0x00 -#define PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL 0x01 -#define PPSMC_THERMAL_PROTECT_TYPE_NONE 0xff - -#define PPSMC_SYSTEMFLAG_GPIO_DC 0x01 -#define PPSMC_SYSTEMFLAG_STEPVDDC 0x02 -#define PPSMC_SYSTEMFLAG_GDDR5 0x04 - -#define PPSMC_SYSTEMFLAG_DISABLE_BABYSTEP 0x08 - -#define PPSMC_SYSTEMFLAG_REGULATOR_HOT 0x10 -#define PPSMC_SYSTEMFLAG_REGULATOR_HOT_ANALOG 0x20 - -#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_MASK 0x07 -#define PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK 0x08 - -#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTODPMLOWSTATE 0x00 -#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE 0x01 - - -#define PPSMC_DPM2FLAGS_TDPCLMP 0x01 -#define PPSMC_DPM2FLAGS_PWRSHFT 0x02 -#define PPSMC_DPM2FLAGS_OCP 0x04 - - -#define PPSMC_DISPLAY_WATERMARK_LOW 0 -#define PPSMC_DISPLAY_WATERMARK_HIGH 1 - - -#define PPSMC_STATEFLAG_AUTO_PULSE_SKIP 0x01 -#define PPSMC_STATEFLAG_POWERBOOST 0x02 -#define PPSMC_STATEFLAG_PSKIP_ON_TDP_FAULT 0x04 -#define PPSMC_STATEFLAG_POWERSHIFT 0x08 -#define PPSMC_STATEFLAG_SLOW_READ_MARGIN 0x10 -#define PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE 0x20 -#define PPSMC_STATEFLAG_DEEPSLEEP_BYPASS 0x40 - - -#define FDO_MODE_HARDWARE 0 -#define FDO_MODE_PIECE_WISE_LINEAR 1 - -enum FAN_CONTROL { - FAN_CONTROL_FUZZY, - FAN_CONTROL_TABLE -}; - - -#define PPSMC_Result_OK ((uint16_t)0x01) -#define PPSMC_Result_NoMore ((uint16_t)0x02) - -#define PPSMC_Result_NotNow ((uint16_t)0x03) -#define PPSMC_Result_Failed ((uint16_t)0xFF) -#define PPSMC_Result_UnknownCmd ((uint16_t)0xFE) -#define PPSMC_Result_UnknownVT ((uint16_t)0xFD) - -typedef uint16_t PPSMC_Result; - -#define PPSMC_isERROR(x) ((uint16_t)0x80 & (x)) - - -#define PPSMC_MSG_Halt ((uint16_t)0x10) -#define PPSMC_MSG_Resume ((uint16_t)0x11) -#define PPSMC_MSG_EnableDPMLevel ((uint16_t)0x12) -#define PPSMC_MSG_ZeroLevelsDisabled ((uint16_t)0x13) -#define PPSMC_MSG_OneLevelsDisabled ((uint16_t)0x14) -#define PPSMC_MSG_TwoLevelsDisabled ((uint16_t)0x15) -#define PPSMC_MSG_EnableThermalInterrupt ((uint16_t)0x16) -#define PPSMC_MSG_RunningOnAC ((uint16_t)0x17) -#define PPSMC_MSG_LevelUp ((uint16_t)0x18) -#define PPSMC_MSG_LevelDown ((uint16_t)0x19) -#define PPSMC_MSG_ResetDPMCounters ((uint16_t)0x1a) -#define PPSMC_MSG_SwitchToSwState ((uint16_t)0x20) -#define PPSMC_MSG_SwitchToSwStateLast ((uint16_t)0x3f) -#define PPSMC_MSG_SwitchToInitialState ((uint16_t)0x40) -#define PPSMC_MSG_NoForcedLevel ((uint16_t)0x41) -#define PPSMC_MSG_ForceHigh ((uint16_t)0x42) -#define PPSMC_MSG_ForceMediumOrHigh ((uint16_t)0x43) -#define PPSMC_MSG_SwitchToMinimumPower ((uint16_t)0x51) -#define PPSMC_MSG_ResumeFromMinimumPower ((uint16_t)0x52) -#define PPSMC_MSG_EnableCac ((uint16_t)0x53) -#define PPSMC_MSG_DisableCac ((uint16_t)0x54) -#define PPSMC_DPMStateHistoryStart ((uint16_t)0x55) -#define PPSMC_DPMStateHistoryStop ((uint16_t)0x56) -#define PPSMC_CACHistoryStart ((uint16_t)0x57) -#define PPSMC_CACHistoryStop ((uint16_t)0x58) -#define PPSMC_TDPClampingActive ((uint16_t)0x59) -#define PPSMC_TDPClampingInactive ((uint16_t)0x5A) -#define PPSMC_StartFanControl ((uint16_t)0x5B) -#define PPSMC_StopFanControl ((uint16_t)0x5C) -#define PPSMC_NoDisplay ((uint16_t)0x5D) -#define PPSMC_HasDisplay ((uint16_t)0x5E) -#define PPSMC_MSG_UVDPowerOFF ((uint16_t)0x60) -#define PPSMC_MSG_UVDPowerON ((uint16_t)0x61) -#define PPSMC_MSG_EnableULV ((uint16_t)0x62) -#define PPSMC_MSG_DisableULV ((uint16_t)0x63) -#define PPSMC_MSG_EnterULV ((uint16_t)0x64) -#define PPSMC_MSG_ExitULV ((uint16_t)0x65) -#define PPSMC_PowerShiftActive ((uint16_t)0x6A) -#define PPSMC_PowerShiftInactive ((uint16_t)0x6B) -#define PPSMC_OCPActive ((uint16_t)0x6C) -#define PPSMC_OCPInactive ((uint16_t)0x6D) -#define PPSMC_CACLongTermAvgEnable ((uint16_t)0x6E) -#define PPSMC_CACLongTermAvgDisable ((uint16_t)0x6F) -#define PPSMC_MSG_InferredStateSweep_Start ((uint16_t)0x70) -#define PPSMC_MSG_InferredStateSweep_Stop ((uint16_t)0x71) -#define PPSMC_MSG_SwitchToLowestInfState ((uint16_t)0x72) -#define PPSMC_MSG_SwitchToNonInfState ((uint16_t)0x73) -#define PPSMC_MSG_AllStateSweep_Start ((uint16_t)0x74) -#define PPSMC_MSG_AllStateSweep_Stop ((uint16_t)0x75) -#define PPSMC_MSG_SwitchNextLowerInfState ((uint16_t)0x76) -#define PPSMC_MSG_SwitchNextHigherInfState ((uint16_t)0x77) -#define PPSMC_MSG_MclkRetrainingTest ((uint16_t)0x78) -#define PPSMC_MSG_ForceTDPClamping ((uint16_t)0x79) -#define PPSMC_MSG_CollectCAC_PowerCorreln ((uint16_t)0x7A) -#define PPSMC_MSG_CollectCAC_WeightCalib ((uint16_t)0x7B) -#define PPSMC_MSG_CollectCAC_SQonly ((uint16_t)0x7C) -#define PPSMC_MSG_CollectCAC_TemperaturePwr ((uint16_t)0x7D) - -#define PPSMC_MSG_ExtremitiesTest_Start ((uint16_t)0x7E) -#define PPSMC_MSG_ExtremitiesTest_Stop ((uint16_t)0x7F) -#define PPSMC_FlushDataCache ((uint16_t)0x80) -#define PPSMC_FlushInstrCache ((uint16_t)0x81) - -#define PPSMC_MSG_SetEnabledLevels ((uint16_t)0x82) -#define PPSMC_MSG_SetForcedLevels ((uint16_t)0x83) - -#define PPSMC_MSG_ResetToDefaults ((uint16_t)0x84) - -#define PPSMC_MSG_SetForcedLevelsAndJump ((uint16_t)0x85) -#define PPSMC_MSG_SetCACHistoryMode ((uint16_t)0x86) -#define PPSMC_MSG_EnableDTE ((uint16_t)0x87) -#define PPSMC_MSG_DisableDTE ((uint16_t)0x88) - -#define PPSMC_MSG_SmcSpaceSetAddress ((uint16_t)0x89) -#define PPSM_MSG_SmcSpaceWriteDWordInc ((uint16_t)0x8A) -#define PPSM_MSG_SmcSpaceWriteWordInc ((uint16_t)0x8B) -#define PPSM_MSG_SmcSpaceWriteByteInc ((uint16_t)0x8C) - -#define PPSMC_MSG_BREAK ((uint16_t)0xF8) - -#define PPSMC_MSG_Test ((uint16_t) 0x100) -#define PPSMC_MSG_DPM_Voltage_Pwrmgt ((uint16_t) 0x101) -#define PPSMC_MSG_DPM_Config ((uint16_t) 0x102) -#define PPSMC_MSG_PM_Controller_Start ((uint16_t) 0x103) -#define PPSMC_MSG_DPM_ForceState ((uint16_t) 0x104) -#define PPSMC_MSG_PG_PowerDownSIMD ((uint16_t) 0x105) -#define PPSMC_MSG_PG_PowerUpSIMD ((uint16_t) 0x106) -#define PPSMC_MSG_PM_Controller_Stop ((uint16_t) 0x107) -#define PPSMC_MSG_PG_SIMD_Config ((uint16_t) 0x108) -#define PPSMC_MSG_Voltage_Cntl_Enable ((uint16_t) 0x109) -#define PPSMC_MSG_Thermal_Cntl_Enable ((uint16_t) 0x10a) -#define PPSMC_MSG_Reset_Service ((uint16_t) 0x10b) -#define PPSMC_MSG_VCEPowerOFF ((uint16_t) 0x10e) -#define PPSMC_MSG_VCEPowerON ((uint16_t) 0x10f) -#define PPSMC_MSG_DPM_Disable_VCE_HS ((uint16_t) 0x110) -#define PPSMC_MSG_DPM_Enable_VCE_HS ((uint16_t) 0x111) -#define PPSMC_MSG_DPM_N_LevelsDisabled ((uint16_t) 0x112) -#define PPSMC_MSG_DCEPowerOFF ((uint16_t) 0x113) -#define PPSMC_MSG_DCEPowerON ((uint16_t) 0x114) -#define PPSMC_MSG_PCIE_DDIPowerDown ((uint16_t) 0x117) -#define PPSMC_MSG_PCIE_DDIPowerUp ((uint16_t) 0x118) -#define PPSMC_MSG_PCIE_CascadePLLPowerDown ((uint16_t) 0x119) -#define PPSMC_MSG_PCIE_CascadePLLPowerUp ((uint16_t) 0x11a) -#define PPSMC_MSG_SYSPLLPowerOff ((uint16_t) 0x11b) -#define PPSMC_MSG_SYSPLLPowerOn ((uint16_t) 0x11c) -#define PPSMC_MSG_DCE_RemoveVoltageAdjustment ((uint16_t) 0x11d) -#define PPSMC_MSG_DCE_AllowVoltageAdjustment ((uint16_t) 0x11e) -#define PPSMC_MSG_DISPLAYPHYStatusNotify ((uint16_t) 0x11f) -#define PPSMC_MSG_EnableBAPM ((uint16_t) 0x120) -#define PPSMC_MSG_DisableBAPM ((uint16_t) 0x121) -#define PPSMC_MSG_Spmi_Enable ((uint16_t) 0x122) -#define PPSMC_MSG_Spmi_Timer ((uint16_t) 0x123) -#define PPSMC_MSG_LCLK_DPM_Config ((uint16_t) 0x124) -#define PPSMC_MSG_VddNB_Request ((uint16_t) 0x125) -#define PPSMC_MSG_PCIE_DDIPhyPowerDown ((uint32_t) 0x126) -#define PPSMC_MSG_PCIE_DDIPhyPowerUp ((uint32_t) 0x127) -#define PPSMC_MSG_MCLKDPM_Config ((uint16_t) 0x128) - -#define PPSMC_MSG_UVDDPM_Config ((uint16_t) 0x129) -#define PPSMC_MSG_VCEDPM_Config ((uint16_t) 0x12A) -#define PPSMC_MSG_ACPDPM_Config ((uint16_t) 0x12B) -#define PPSMC_MSG_SAMUDPM_Config ((uint16_t) 0x12C) -#define PPSMC_MSG_UVDDPM_SetEnabledMask ((uint16_t) 0x12D) -#define PPSMC_MSG_VCEDPM_SetEnabledMask ((uint16_t) 0x12E) -#define PPSMC_MSG_ACPDPM_SetEnabledMask ((uint16_t) 0x12F) -#define PPSMC_MSG_SAMUDPM_SetEnabledMask ((uint16_t) 0x130) -#define PPSMC_MSG_MCLKDPM_ForceState ((uint16_t) 0x131) -#define PPSMC_MSG_MCLKDPM_NoForcedLevel ((uint16_t) 0x132) -#define PPSMC_MSG_Thermal_Cntl_Disable ((uint16_t) 0x133) -#define PPSMC_MSG_SetTDPLimit ((uint16_t) 0x134) -#define PPSMC_MSG_Voltage_Cntl_Disable ((uint16_t) 0x135) -#define PPSMC_MSG_PCIeDPM_Enable ((uint16_t) 0x136) -#define PPSMC_MSG_ACPPowerOFF ((uint16_t) 0x137) -#define PPSMC_MSG_ACPPowerON ((uint16_t) 0x138) -#define PPSMC_MSG_SAMPowerOFF ((uint16_t) 0x139) -#define PPSMC_MSG_SAMPowerON ((uint16_t) 0x13a) -#define PPSMC_MSG_SDMAPowerOFF ((uint16_t) 0x13b) -#define PPSMC_MSG_SDMAPowerON ((uint16_t) 0x13c) -#define PPSMC_MSG_PCIeDPM_Disable ((uint16_t) 0x13d) -#define PPSMC_MSG_IOMMUPowerOFF ((uint16_t) 0x13e) -#define PPSMC_MSG_IOMMUPowerON ((uint16_t) 0x13f) -#define PPSMC_MSG_NBDPM_Enable ((uint16_t) 0x140) -#define PPSMC_MSG_NBDPM_Disable ((uint16_t) 0x141) -#define PPSMC_MSG_NBDPM_ForceNominal ((uint16_t) 0x142) -#define PPSMC_MSG_NBDPM_ForcePerformance ((uint16_t) 0x143) -#define PPSMC_MSG_NBDPM_UnForce ((uint16_t) 0x144) -#define PPSMC_MSG_SCLKDPM_SetEnabledMask ((uint16_t) 0x145) -#define PPSMC_MSG_MCLKDPM_SetEnabledMask ((uint16_t) 0x146) -#define PPSMC_MSG_PCIeDPM_ForceLevel ((uint16_t) 0x147) -#define PPSMC_MSG_PCIeDPM_UnForceLevel ((uint16_t) 0x148) -#define PPSMC_MSG_EnableACDCGPIOInterrupt ((uint16_t) 0x149) -#define PPSMC_MSG_EnableVRHotGPIOInterrupt ((uint16_t) 0x14a) -#define PPSMC_MSG_SwitchToAC ((uint16_t) 0x14b) -#define PPSMC_MSG_XDMAPowerOFF ((uint16_t) 0x14c) -#define PPSMC_MSG_XDMAPowerON ((uint16_t) 0x14d) - -#define PPSMC_MSG_DPM_Enable ((uint16_t) 0x14e) -#define PPSMC_MSG_DPM_Disable ((uint16_t) 0x14f) -#define PPSMC_MSG_MCLKDPM_Enable ((uint16_t) 0x150) -#define PPSMC_MSG_MCLKDPM_Disable ((uint16_t) 0x151) -#define PPSMC_MSG_LCLKDPM_Enable ((uint16_t) 0x152) -#define PPSMC_MSG_LCLKDPM_Disable ((uint16_t) 0x153) -#define PPSMC_MSG_UVDDPM_Enable ((uint16_t) 0x154) -#define PPSMC_MSG_UVDDPM_Disable ((uint16_t) 0x155) -#define PPSMC_MSG_SAMUDPM_Enable ((uint16_t) 0x156) -#define PPSMC_MSG_SAMUDPM_Disable ((uint16_t) 0x157) -#define PPSMC_MSG_ACPDPM_Enable ((uint16_t) 0x158) -#define PPSMC_MSG_ACPDPM_Disable ((uint16_t) 0x159) -#define PPSMC_MSG_VCEDPM_Enable ((uint16_t) 0x15a) -#define PPSMC_MSG_VCEDPM_Disable ((uint16_t) 0x15b) -#define PPSMC_MSG_LCLKDPM_SetEnabledMask ((uint16_t) 0x15c) -#define PPSMC_MSG_DPM_FPS_Mode ((uint16_t) 0x15d) -#define PPSMC_MSG_DPM_Activity_Mode ((uint16_t) 0x15e) -#define PPSMC_MSG_VddC_Request ((uint16_t) 0x15f) -#define PPSMC_MSG_MCLKDPM_GetEnabledMask ((uint16_t) 0x160) -#define PPSMC_MSG_LCLKDPM_GetEnabledMask ((uint16_t) 0x161) -#define PPSMC_MSG_SCLKDPM_GetEnabledMask ((uint16_t) 0x162) -#define PPSMC_MSG_UVDDPM_GetEnabledMask ((uint16_t) 0x163) -#define PPSMC_MSG_SAMUDPM_GetEnabledMask ((uint16_t) 0x164) -#define PPSMC_MSG_ACPDPM_GetEnabledMask ((uint16_t) 0x165) -#define PPSMC_MSG_VCEDPM_GetEnabledMask ((uint16_t) 0x166) -#define PPSMC_MSG_PCIeDPM_SetEnabledMask ((uint16_t) 0x167) -#define PPSMC_MSG_PCIeDPM_GetEnabledMask ((uint16_t) 0x168) -#define PPSMC_MSG_TDCLimitEnable ((uint16_t) 0x169) -#define PPSMC_MSG_TDCLimitDisable ((uint16_t) 0x16a) -#define PPSMC_MSG_DPM_AutoRotate_Mode ((uint16_t) 0x16b) -#define PPSMC_MSG_DISPCLK_FROM_FCH ((uint16_t) 0x16c) -#define PPSMC_MSG_DISPCLK_FROM_DFS ((uint16_t) 0x16d) -#define PPSMC_MSG_DPREFCLK_FROM_FCH ((uint16_t) 0x16e) -#define PPSMC_MSG_DPREFCLK_FROM_DFS ((uint16_t) 0x16f) -#define PPSMC_MSG_PmStatusLogStart ((uint16_t) 0x170) -#define PPSMC_MSG_PmStatusLogSample ((uint16_t) 0x171) -#define PPSMC_MSG_SCLK_AutoDPM_ON ((uint16_t) 0x172) -#define PPSMC_MSG_MCLK_AutoDPM_ON ((uint16_t) 0x173) -#define PPSMC_MSG_LCLK_AutoDPM_ON ((uint16_t) 0x174) -#define PPSMC_MSG_UVD_AutoDPM_ON ((uint16_t) 0x175) -#define PPSMC_MSG_SAMU_AutoDPM_ON ((uint16_t) 0x176) -#define PPSMC_MSG_ACP_AutoDPM_ON ((uint16_t) 0x177) -#define PPSMC_MSG_VCE_AutoDPM_ON ((uint16_t) 0x178) -#define PPSMC_MSG_PCIe_AutoDPM_ON ((uint16_t) 0x179) -#define PPSMC_MSG_MASTER_AutoDPM_ON ((uint16_t) 0x17a) -#define PPSMC_MSG_MASTER_AutoDPM_OFF ((uint16_t) 0x17b) -#define PPSMC_MSG_DYNAMICDISPPHYPOWER ((uint16_t) 0x17c) -#define PPSMC_MSG_CAC_COLLECTION_ON ((uint16_t) 0x17d) -#define PPSMC_MSG_CAC_COLLECTION_OFF ((uint16_t) 0x17e) -#define PPSMC_MSG_CAC_CORRELATION_ON ((uint16_t) 0x17f) -#define PPSMC_MSG_CAC_CORRELATION_OFF ((uint16_t) 0x180) -#define PPSMC_MSG_PM_STATUS_TO_DRAM_ON ((uint16_t) 0x181) -#define PPSMC_MSG_PM_STATUS_TO_DRAM_OFF ((uint16_t) 0x182) -#define PPSMC_MSG_ALLOW_LOWSCLK_INTERRUPT ((uint16_t) 0x184) -#define PPSMC_MSG_PkgPwrLimitEnable ((uint16_t) 0x185) -#define PPSMC_MSG_PkgPwrLimitDisable ((uint16_t) 0x186) -#define PPSMC_MSG_PkgPwrSetLimit ((uint16_t) 0x187) -#define PPSMC_MSG_OverDriveSetTargetTdp ((uint16_t) 0x188) -#define PPSMC_MSG_SCLKDPM_FreezeLevel ((uint16_t) 0x189) -#define PPSMC_MSG_SCLKDPM_UnfreezeLevel ((uint16_t) 0x18A) -#define PPSMC_MSG_MCLKDPM_FreezeLevel ((uint16_t) 0x18B) -#define PPSMC_MSG_MCLKDPM_UnfreezeLevel ((uint16_t) 0x18C) -#define PPSMC_MSG_START_DRAM_LOGGING ((uint16_t) 0x18D) -#define PPSMC_MSG_STOP_DRAM_LOGGING ((uint16_t) 0x18E) -#define PPSMC_MSG_MASTER_DeepSleep_ON ((uint16_t) 0x18F) -#define PPSMC_MSG_MASTER_DeepSleep_OFF ((uint16_t) 0x190) -#define PPSMC_MSG_Remove_DC_Clamp ((uint16_t) 0x191) -#define PPSMC_MSG_DisableACDCGPIOInterrupt ((uint16_t) 0x192) -#define PPSMC_MSG_OverrideVoltageControl_SetVddc ((uint16_t) 0x193) -#define PPSMC_MSG_OverrideVoltageControl_SetVddci ((uint16_t) 0x194) -#define PPSMC_MSG_SetVidOffset_1 ((uint16_t) 0x195) -#define PPSMC_MSG_SetVidOffset_2 ((uint16_t) 0x207) -#define PPSMC_MSG_GetVidOffset_1 ((uint16_t) 0x196) -#define PPSMC_MSG_GetVidOffset_2 ((uint16_t) 0x208) -#define PPSMC_MSG_THERMAL_OVERDRIVE_Enable ((uint16_t) 0x197) -#define PPSMC_MSG_THERMAL_OVERDRIVE_Disable ((uint16_t) 0x198) -#define PPSMC_MSG_SetTjMax ((uint16_t) 0x199) -#define PPSMC_MSG_SetFanPwmMax ((uint16_t) 0x19A) -#define PPSMC_MSG_WaitForMclkSwitchFinish ((uint16_t) 0x19B) -#define PPSMC_MSG_ENABLE_THERMAL_DPM ((uint16_t) 0x19C) -#define PPSMC_MSG_DISABLE_THERMAL_DPM ((uint16_t) 0x19D) - -#define PPSMC_MSG_API_GetSclkFrequency ((uint16_t) 0x200) -#define PPSMC_MSG_API_GetMclkFrequency ((uint16_t) 0x201) -#define PPSMC_MSG_API_GetSclkBusy ((uint16_t) 0x202) -#define PPSMC_MSG_API_GetMclkBusy ((uint16_t) 0x203) -#define PPSMC_MSG_API_GetAsicPower ((uint16_t) 0x204) -#define PPSMC_MSG_SetFanRpmMax ((uint16_t) 0x205) -#define PPSMC_MSG_SetFanSclkTarget ((uint16_t) 0x206) -#define PPSMC_MSG_SetFanMinPwm ((uint16_t) 0x209) -#define PPSMC_MSG_SetFanTemperatureTarget ((uint16_t) 0x20A) - -#define PPSMC_MSG_BACO_StartMonitor ((uint16_t) 0x240) -#define PPSMC_MSG_BACO_Cancel ((uint16_t) 0x241) -#define PPSMC_MSG_EnableVddGfx ((uint16_t) 0x242) -#define PPSMC_MSG_DisableVddGfx ((uint16_t) 0x243) -#define PPSMC_MSG_UcodeAddressLow ((uint16_t) 0x244) -#define PPSMC_MSG_UcodeAddressHigh ((uint16_t) 0x245) -#define PPSMC_MSG_UcodeLoadStatus ((uint16_t) 0x246) - -#define PPSMC_MSG_DRV_DRAM_ADDR_HI ((uint16_t) 0x250) -#define PPSMC_MSG_DRV_DRAM_ADDR_LO ((uint16_t) 0x251) -#define PPSMC_MSG_SMU_DRAM_ADDR_HI ((uint16_t) 0x252) -#define PPSMC_MSG_SMU_DRAM_ADDR_LO ((uint16_t) 0x253) -#define PPSMC_MSG_LoadUcodes ((uint16_t) 0x254) -#define PPSMC_MSG_PowerStateNotify ((uint16_t) 0x255) -#define PPSMC_MSG_COND_EXEC_DRAM_ADDR_HI ((uint16_t) 0x256) -#define PPSMC_MSG_COND_EXEC_DRAM_ADDR_LO ((uint16_t) 0x257) -#define PPSMC_MSG_VBIOS_DRAM_ADDR_HI ((uint16_t) 0x258) -#define PPSMC_MSG_VBIOS_DRAM_ADDR_LO ((uint16_t) 0x259) -#define PPSMC_MSG_LoadVBios ((uint16_t) 0x25A) -#define PPSMC_MSG_GetUcodeVersion ((uint16_t) 0x25B) -#define DMCUSMC_MSG_PSREntry ((uint16_t) 0x25C) -#define DMCUSMC_MSG_PSRExit ((uint16_t) 0x25D) -#define PPSMC_MSG_EnableClockGatingFeature ((uint16_t) 0x260) -#define PPSMC_MSG_DisableClockGatingFeature ((uint16_t) 0x261) -#define PPSMC_MSG_IsDeviceRunning ((uint16_t) 0x262) -#define PPSMC_MSG_LoadMetaData ((uint16_t) 0x263) -#define PPSMC_MSG_TMON_AutoCaliberate_Enable ((uint16_t) 0x264) -#define PPSMC_MSG_TMON_AutoCaliberate_Disable ((uint16_t) 0x265) -#define PPSMC_MSG_GetTelemetry1Slope ((uint16_t) 0x266) -#define PPSMC_MSG_GetTelemetry1Offset ((uint16_t) 0x267) -#define PPSMC_MSG_GetTelemetry2Slope ((uint16_t) 0x268) -#define PPSMC_MSG_GetTelemetry2Offset ((uint16_t) 0x269) -#define PPSMC_MSG_EnableAvfs ((uint16_t) 0x26A) -#define PPSMC_MSG_DisableAvfs ((uint16_t) 0x26B) - -#define PPSMC_MSG_PerformBtc ((uint16_t) 0x26C) -#define PPSMC_MSG_VftTableIsValid ((uint16_t) 0x275) -#define PPSMC_MSG_UseNewGPIOScheme ((uint16_t) 0x277) -#define PPSMC_MSG_GetEnabledPsm ((uint16_t) 0x400) -#define PPSMC_MSG_AgmStartPsm ((uint16_t) 0x401) -#define PPSMC_MSG_AgmReadPsm ((uint16_t) 0x402) -#define PPSMC_MSG_AgmResetPsm ((uint16_t) 0x403) -#define PPSMC_MSG_ReadVftCell ((uint16_t) 0x404) - -#define PPSMC_MSG_GFX_CU_PG_ENABLE ((uint16_t) 0x280) -#define PPSMC_MSG_GFX_CU_PG_DISABLE ((uint16_t) 0x281) -#define PPSMC_MSG_GetCurrPkgPwr ((uint16_t) 0x282) - -#define PPSMC_MSG_SetGpuPllDfsForSclk ((uint16_t) 0x300) -#define PPSMC_MSG_Didt_Block_Function ((uint16_t) 0x301) - -#define PPSMC_MSG_SetVBITimeout ((uint16_t) 0x306) - -#define PPSMC_MSG_SecureSRBMWrite ((uint16_t) 0x600) -#define PPSMC_MSG_SecureSRBMRead ((uint16_t) 0x601) -#define PPSMC_MSG_SetAddress ((uint16_t) 0x800) -#define PPSMC_MSG_GetData ((uint16_t) 0x801) -#define PPSMC_MSG_SetData ((uint16_t) 0x802) - -typedef uint16_t PPSMC_Msg; - -#define PPSMC_EVENT_STATUS_THERMAL 0x00000001 -#define PPSMC_EVENT_STATUS_REGULATORHOT 0x00000002 -#define PPSMC_EVENT_STATUS_DC 0x00000004 - -#pragma pack(pop) - -#endif - diff --git a/drivers/gpu/drm/amd/powerplay/inc/power_state.h b/drivers/gpu/drm/amd/powerplay/inc/power_state.h index 827860fffe78..a99b5cbb113e 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/power_state.h +++ b/drivers/gpu/drm/amd/powerplay/inc/power_state.h @@ -122,8 +122,8 @@ struct PP_StateSoftwareAlgorithmBlock { * Type to hold a temperature range. */ struct PP_TemperatureRange { - uint32_t min; - uint32_t max; + int min; + int max; }; struct PP_StateValidationBlock { diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_feature.h b/drivers/gpu/drm/amd/powerplay/inc/pp_feature.h deleted file mode 100644 index 0faf6a25c18b..000000000000 --- a/drivers/gpu/drm/amd/powerplay/inc/pp_feature.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef _PP_FEATURE_H_ -#define _PP_FEATURE_H_ - -/** - * PowerPlay feature ids. - */ -enum pp_feature { - PP_Feature_PowerPlay = 0, - PP_Feature_User2DPerformance, - PP_Feature_User3DPerformance, - PP_Feature_VariBright, - PP_Feature_VariBrightOnPowerXpress, - PP_Feature_ReducedRefreshRate, - PP_Feature_GFXClockGating, - PP_Feature_OverdriveTest, - PP_Feature_OverDrive, - PP_Feature_PowerBudgetWaiver, - PP_Feature_PowerControl, - PP_Feature_PowerControl_2, - PP_Feature_MultiUVDState, - PP_Feature_Force3DClock, - PP_Feature_BACO, - PP_Feature_PowerDown, - PP_Feature_DynamicUVDState, - PP_Feature_VCEDPM, - PP_Feature_PPM, - PP_Feature_ACP_POWERGATING, - PP_Feature_FFC, - PP_Feature_FPS, - PP_Feature_ViPG, - PP_Feature_Max -}; - -/** - * Struct for PowerPlay feature info. - */ -struct pp_feature_info { - bool supported; /* feature supported by PowerPlay */ - bool enabled; /* feature enabled in PowerPlay */ - bool enabled_default; /* default enable status of the feature */ - uint32_t version; /* feature version */ -}; - -#endif /* _PP_FEATURE_H_ */ diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_soc15.h b/drivers/gpu/drm/amd/powerplay/inc/pp_soc15.h index b7ab69e4c254..214f370c5efd 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/pp_soc15.h +++ b/drivers/gpu/drm/amd/powerplay/inc/pp_soc15.h @@ -23,7 +23,8 @@ #ifndef PP_SOC15_H #define PP_SOC15_H -#include "soc15ip.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" inline static uint32_t soc15_get_register_offset( uint32_t hw_id, @@ -43,7 +44,8 @@ inline static uint32_t soc15_get_register_offset( reg = DF_BASE.instance[inst].segment[segment] + offset; else if (hw_id == GC_HWID) reg = GC_BASE.instance[inst].segment[segment] + offset; - + else if (hw_id == SMUIO_HWID) + reg = SMUIO_BASE.instance[inst].segment[segment] + offset; return reg; } diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_thermal.h b/drivers/gpu/drm/amd/powerplay/inc/pp_thermal.h new file mode 100644 index 000000000000..201d2b6329ab --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/inc/pp_thermal.h @@ -0,0 +1,40 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +#ifndef PP_THERMAL_H +#define PP_THERMAL_H + +#include "power_state.h" + +static const struct PP_TemperatureRange SMU7ThermalWithDelayPolicy[] = +{ + {-273150, 99000}, + { 120000, 120000}, +}; + +static const struct PP_TemperatureRange SMU7ThermalPolicy[] = +{ + {-273150, 99000}, + { 120000, 120000}, +}; + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/rv_ppsmc.h b/drivers/gpu/drm/amd/powerplay/inc/rv_ppsmc.h index f15f4df9d0a9..426bff2aad2b 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/rv_ppsmc.h +++ b/drivers/gpu/drm/amd/powerplay/inc/rv_ppsmc.h @@ -80,7 +80,8 @@ #define PPSMC_MSG_SetSoftMaxSocclkByFreq 0x32 #define PPSMC_MSG_SetSoftMaxFclkByFreq 0x33 #define PPSMC_MSG_SetSoftMaxVcn 0x34 -#define PPSMC_Message_Count 0x35 +#define PPSMC_MSG_PowerGateMmHub 0x35 +#define PPSMC_Message_Count 0x36 typedef uint16_t PPSMC_Result; diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu7.h b/drivers/gpu/drm/amd/powerplay/inc/smu7.h index 75a380a15292..e14072d45918 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu7.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smu7.h @@ -82,6 +82,25 @@ #define SCRATCH_B_CURR_SAMU_INDEX_MASK (0x7<backend); @@ -438,14 +437,14 @@ static int ci_populate_single_graphic_level(struct pp_hwmgr *hwmgr, clock, &level->MinVddcPhases); - level->ActivityLevel = sclk_al_threshold; + level->ActivityLevel = data->current_profile_setting.sclk_activity; level->CcPwrDynRm = 0; level->CcPwrDynRm1 = 0; level->EnabledForActivity = 0; /* this level can be used for throttling.*/ level->EnabledForThrottle = 1; - level->UpH = 0; - level->DownH = 0; + level->UpH = data->current_profile_setting.sclk_up_hyst; + level->DownH = data->current_profile_setting.sclk_down_hyst; level->VoltageDownH = 0; level->PowerThrottle = 0; @@ -492,7 +491,6 @@ static int ci_populate_all_graphic_levels(struct pp_hwmgr *hwmgr) for (i = 0; i < dpm_table->sclk_table.count; i++) { result = ci_populate_single_graphic_level(hwmgr, dpm_table->sclk_table.dpm_levels[i].value, - (uint16_t)smu_data->activity_target[i], &levels[i]); if (result) return result; @@ -860,10 +858,13 @@ static int ci_populate_smc_vddc_table(struct pp_hwmgr *hwmgr, PP_ASSERT_WITH_CODE(0 == result, "do not populate SMC VDDC voltage table", return -EINVAL); /* GPIO voltage control */ - if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->voltage_control) - table->VddcLevel[count].Smio |= data->vddc_voltage_table.entries[count].smio_low; - else + if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->voltage_control) { + table->VddcLevel[count].Smio = (uint8_t) count; + table->Smio[count] |= data->vddc_voltage_table.entries[count].smio_low; + table->SmioMaskVddcVid |= data->vddc_voltage_table.entries[count].smio_low; + } else { table->VddcLevel[count].Smio = 0; + } } CONVERT_FROM_HOST_TO_SMC_UL(table->VddcLevelCount); @@ -885,10 +886,13 @@ static int ci_populate_smc_vdd_ci_table(struct pp_hwmgr *hwmgr, &(data->vddci_voltage_table.entries[count]), &(table->VddciLevel[count])); PP_ASSERT_WITH_CODE(result == 0, "do not populate SMC VDDCI voltage table", return -EINVAL); - if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) - table->VddciLevel[count].Smio |= data->vddci_voltage_table.entries[count].smio_low; - else - table->VddciLevel[count].Smio |= 0; + if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) { + table->VddciLevel[count].Smio = (uint8_t) count; + table->Smio[count] |= data->vddci_voltage_table.entries[count].smio_low; + table->SmioMaskVddciVid |= data->vddci_voltage_table.entries[count].smio_low; + } else { + table->VddciLevel[count].Smio = 0; + } } CONVERT_FROM_HOST_TO_SMC_UL(table->VddciLevelCount); @@ -910,10 +914,13 @@ static int ci_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr, &(data->mvdd_voltage_table.entries[count]), &table->MvddLevel[count]); PP_ASSERT_WITH_CODE(result == 0, "do not populate SMC mvdd voltage table", return -EINVAL); - if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) - table->MvddLevel[count].Smio |= data->mvdd_voltage_table.entries[count].smio_low; - else - table->MvddLevel[count].Smio |= 0; + if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) { + table->MvddLevel[count].Smio = (uint8_t) count; + table->Smio[count] |= data->mvdd_voltage_table.entries[count].smio_low; + table->SmioMaskMvddVid |= data->mvdd_voltage_table.entries[count].smio_low; + } else { + table->MvddLevel[count].Smio = 0; + } } CONVERT_FROM_HOST_TO_SMC_UL(table->MvddLevelCount); @@ -1217,12 +1224,12 @@ static int ci_populate_single_memory_level( memory_level->EnabledForThrottle = 1; memory_level->EnabledForActivity = 1; - memory_level->UpH = 0; - memory_level->DownH = 100; + memory_level->UpH = data->current_profile_setting.mclk_up_hyst; + memory_level->DownH = data->current_profile_setting.mclk_down_hyst; memory_level->VoltageDownH = 0; /* Indicates maximum activity level for this performance level.*/ - memory_level->ActivityLevel = (uint16_t)data->mclk_activity_target; + memory_level->ActivityLevel = data->current_profile_setting.mclk_activity; memory_level->StutterEnable = 0; memory_level->StrobeEnable = 0; memory_level->EdcReadEnable = 0; @@ -1506,7 +1513,7 @@ static int ci_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, table->MemoryACPILevel.DownH = 100; table->MemoryACPILevel.VoltageDownH = 0; /* Indicates maximum activity level for this performance level.*/ - table->MemoryACPILevel.ActivityLevel = PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target); + table->MemoryACPILevel.ActivityLevel = PP_HOST_TO_SMC_US(data->current_profile_setting.mclk_activity); table->MemoryACPILevel.StutterEnable = 0; table->MemoryACPILevel.StrobeEnable = 0; @@ -1941,6 +1948,37 @@ static int ci_start_smc(struct pp_hwmgr *hwmgr) return 0; } +static int ci_populate_vr_config(struct pp_hwmgr *hwmgr, SMU7_Discrete_DpmTable *table) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + uint16_t config; + + config = VR_SVI2_PLANE_1; + table->VRConfig |= (config<voltage_control) { + config = VR_SVI2_PLANE_2; + table->VRConfig |= config; + } else { + pr_info("VDDCshould be on SVI2 controller!"); + } + + if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) { + config = VR_SVI2_PLANE_2; + table->VRConfig |= (config<vddci_control) { + config = VR_SMIO_PATTERN_1; + table->VRConfig |= (config<mvdd_control) { + config = VR_SMIO_PATTERN_2; + table->VRConfig |= (config<PCIeBootLinkLevel = (uint8_t)data->dpm_table.pcie_speed_table.count; table->PCIeGenInterval = 1; + result = ci_populate_vr_config(hwmgr, table); + PP_ASSERT_WITH_CODE(0 == result, + "Failed to populate VRConfig setting!", return result); + data->vr_config = table->VRConfig; + ci_populate_smc_svi2_config(hwmgr, table); for (i = 0; i < SMU7_MAX_ENTRIES_SMIO; i++) @@ -2084,6 +2127,7 @@ static int ci_init_smc_table(struct pp_hwmgr *hwmgr) table->AcDcGpio = SMU7_UNUSED_GPIO_PIN; CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags); + CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig); CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddcVid); CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddcPhase); CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddciVid); @@ -2756,7 +2800,6 @@ static int ci_populate_requested_graphic_levels(struct pp_hwmgr *hwmgr, static int ci_smu_init(struct pp_hwmgr *hwmgr) { - int i; struct ci_smumgr *ci_priv = NULL; ci_priv = kzalloc(sizeof(struct ci_smumgr), GFP_KERNEL); @@ -2764,9 +2807,6 @@ static int ci_smu_init(struct pp_hwmgr *hwmgr) if (ci_priv == NULL) return -ENOMEM; - for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) - ci_priv->activity_target[i] = 30; - hwmgr->smu_backend = ci_priv; return 0; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.h index 8189cfa17c46..a8282705c569 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.h @@ -70,8 +70,6 @@ struct ci_smumgr { const struct ci_pt_defaults *power_tune_defaults; SMU7_Discrete_MCRegisters mc_regs; struct ci_mc_reg_table mc_reg_table; - uint32_t activity_target[SMU7_MAX_LEVELS_GRAPHICS]; - }; #endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c index 085d81c8b332..9d5ccdbc391d 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c @@ -368,7 +368,6 @@ static bool fiji_is_hw_avfs_present(struct pp_hwmgr *hwmgr) static int fiji_smu_init(struct pp_hwmgr *hwmgr) { - int i; struct fiji_smumgr *fiji_priv = NULL; fiji_priv = kzalloc(sizeof(struct fiji_smumgr), GFP_KERNEL); @@ -381,9 +380,6 @@ static int fiji_smu_init(struct pp_hwmgr *hwmgr) if (smu7_init(hwmgr)) return -EINVAL; - for (i = 0; i < SMU73_MAX_LEVELS_GRAPHICS; i++) - fiji_priv->activity_target[i] = 30; - return 0; } @@ -972,8 +968,7 @@ static int fiji_calculate_sclk_params(struct pp_hwmgr *hwmgr, } static int fiji_populate_single_graphic_level(struct pp_hwmgr *hwmgr, - uint32_t clock, uint16_t sclk_al_threshold, - struct SMU73_Discrete_GraphicsLevel *level) + uint32_t clock, struct SMU73_Discrete_GraphicsLevel *level) { int result; /* PP_Clocks minClocks; */ @@ -981,12 +976,18 @@ static int fiji_populate_single_graphic_level(struct pp_hwmgr *hwmgr, struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); struct phm_ppt_v1_information *table_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); + phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL; result = fiji_calculate_sclk_params(hwmgr, clock, level); + if (hwmgr->od_enabled) + vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_sclk; + else + vdd_dep_table = table_info->vdd_dep_on_sclk; + /* populate graphics levels */ result = fiji_get_dependency_volt_by_clk(hwmgr, - table_info->vdd_dep_on_sclk, clock, + vdd_dep_table, clock, (uint32_t *)(&level->MinVoltage), &mvdd); PP_ASSERT_WITH_CODE((0 == result), "can not find VDDC voltage value for " @@ -994,13 +995,13 @@ static int fiji_populate_single_graphic_level(struct pp_hwmgr *hwmgr, return result); level->SclkFrequency = clock; - level->ActivityLevel = sclk_al_threshold; + level->ActivityLevel = data->current_profile_setting.sclk_activity; level->CcPwrDynRm = 0; level->CcPwrDynRm1 = 0; level->EnabledForActivity = 0; level->EnabledForThrottle = 1; - level->UpHyst = 10; - level->DownHyst = 0; + level->UpHyst = data->current_profile_setting.sclk_up_hyst; + level->DownHyst = data->current_profile_setting.sclk_down_hyst; level->VoltageDownHyst = 0; level->PowerThrottle = 0; @@ -1057,7 +1058,6 @@ static int fiji_populate_all_graphic_levels(struct pp_hwmgr *hwmgr) for (i = 0; i < dpm_table->sclk_table.count; i++) { result = fiji_populate_single_graphic_level(hwmgr, dpm_table->sclk_table.dpm_levels[i].value, - (uint16_t)smu_data->activity_target[i], &levels[i]); if (result) return result; @@ -1202,10 +1202,16 @@ static int fiji_populate_single_memory_level(struct pp_hwmgr *hwmgr, (struct phm_ppt_v1_information *)(hwmgr->pptable); int result = 0; uint32_t mclk_stutter_mode_threshold = 60000; + phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL; - if (table_info->vdd_dep_on_mclk) { + if (hwmgr->od_enabled) + vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_sclk; + else + vdd_dep_table = table_info->vdd_dep_on_mclk; + + if (vdd_dep_table) { result = fiji_get_dependency_volt_by_clk(hwmgr, - table_info->vdd_dep_on_mclk, clock, + vdd_dep_table, clock, (uint32_t *)(&mem_level->MinVoltage), &mem_level->MinMvdd); PP_ASSERT_WITH_CODE((0 == result), "can not find MinVddc voltage value from memory " @@ -1214,10 +1220,10 @@ static int fiji_populate_single_memory_level(struct pp_hwmgr *hwmgr, mem_level->EnabledForThrottle = 1; mem_level->EnabledForActivity = 0; - mem_level->UpHyst = 0; - mem_level->DownHyst = 100; + mem_level->UpHyst = data->current_profile_setting.mclk_up_hyst; + mem_level->DownHyst = data->current_profile_setting.mclk_down_hyst; mem_level->VoltageDownHyst = 0; - mem_level->ActivityLevel = (uint16_t)data->mclk_activity_target; + mem_level->ActivityLevel = data->current_profile_setting.mclk_activity; mem_level->StutterEnable = false; mem_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW; @@ -1435,7 +1441,7 @@ static int fiji_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, table->MemoryACPILevel.DownHyst = 100; table->MemoryACPILevel.VoltageDownHyst = 0; table->MemoryACPILevel.ActivityLevel = - PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target); + PP_HOST_TO_SMC_US(data->current_profile_setting.mclk_activity); table->MemoryACPILevel.StutterEnable = false; CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MclkFrequency); @@ -1799,7 +1805,7 @@ static int fiji_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr) phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ClockStretcher); PP_ASSERT_WITH_CODE(false, - "Stretch Amount in PPTable not supported\n", + "Stretch Amount in PPTable not supported", return -EINVAL); } @@ -2141,7 +2147,7 @@ static int fiji_init_smc_table(struct pp_hwmgr *hwmgr) result = fiji_populate_vr_config(hwmgr, table); PP_ASSERT_WITH_CODE(0 == result, "Failed to populate VRConfig setting!", return result); - + data->vr_config = table->VRConfig; table->ThermGpio = 17; table->SclkStepSize = 0x4000; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h index 279647772578..6d3746268ccf 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h @@ -43,8 +43,6 @@ struct fiji_smumgr { struct SMU73_Discrete_Ulv ulv_setting; struct SMU73_Discrete_PmFuses power_tune_table; const struct fiji_pt_defaults *power_tune_defaults; - uint32_t activity_target[SMU73_MAX_LEVELS_GRAPHICS]; - }; #endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c index 125312691f75..11aeb150a97f 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c @@ -262,7 +262,6 @@ static int iceland_start_smu(struct pp_hwmgr *hwmgr) static int iceland_smu_init(struct pp_hwmgr *hwmgr) { - int i; struct iceland_smumgr *iceland_priv = NULL; iceland_priv = kzalloc(sizeof(struct iceland_smumgr), GFP_KERNEL); @@ -275,9 +274,6 @@ static int iceland_smu_init(struct pp_hwmgr *hwmgr) if (smu7_init(hwmgr)) return -EINVAL; - for (i = 0; i < SMU71_MAX_LEVELS_GRAPHICS; i++) - iceland_priv->activity_target[i] = 30; - return 0; } @@ -546,7 +542,7 @@ static int iceland_get_std_voltage_value_sidd(struct pp_hwmgr *hwmgr, /* SCLK/VDDC Dependency Table has to exist. */ PP_ASSERT_WITH_CODE(NULL != hwmgr->dyn_state.vddc_dependency_on_sclk, - "The SCLK/VDDC Dependency Table does not exist.\n", + "The SCLK/VDDC Dependency Table does not exist.", return -EINVAL); if (NULL == hwmgr->dyn_state.cac_leakage_table) { @@ -898,7 +894,6 @@ static int iceland_populate_phase_value_based_on_sclk(struct pp_hwmgr *hwmgr, static int iceland_populate_single_graphic_level(struct pp_hwmgr *hwmgr, uint32_t engine_clock, - uint16_t sclk_activity_level_threshold, SMU71_Discrete_GraphicsLevel *graphic_level) { int result; @@ -924,7 +919,7 @@ static int iceland_populate_single_graphic_level(struct pp_hwmgr *hwmgr, &graphic_level->MinVddcPhases); /* Indicates maximum activity level for this performance level. 50% for now*/ - graphic_level->ActivityLevel = sclk_activity_level_threshold; + graphic_level->ActivityLevel = data->current_profile_setting.sclk_activity; graphic_level->CcPwrDynRm = 0; graphic_level->CcPwrDynRm1 = 0; @@ -932,8 +927,8 @@ static int iceland_populate_single_graphic_level(struct pp_hwmgr *hwmgr, graphic_level->EnabledForActivity = 0; /* this level can be used for throttling.*/ graphic_level->EnabledForThrottle = 1; - graphic_level->UpHyst = 0; - graphic_level->DownHyst = 100; + graphic_level->UpHyst = data->current_profile_setting.sclk_up_hyst; + graphic_level->DownHyst = data->current_profile_setting.sclk_down_hyst; graphic_level->VoltageDownHyst = 0; graphic_level->PowerThrottle = 0; @@ -989,7 +984,6 @@ static int iceland_populate_all_graphic_levels(struct pp_hwmgr *hwmgr) for (i = 0; i < dpm_table->sclk_table.count; i++) { result = iceland_populate_single_graphic_level(hwmgr, dpm_table->sclk_table.dpm_levels[i].value, - (uint16_t)smu_data->activity_target[i], &(smu_data->smc_state_table.GraphicsLevel[i])); if (result != 0) return result; @@ -1275,12 +1269,12 @@ static int iceland_populate_single_memory_level( memory_level->EnabledForThrottle = 1; memory_level->EnabledForActivity = 0; - memory_level->UpHyst = 0; - memory_level->DownHyst = 100; + memory_level->UpHyst = data->current_profile_setting.mclk_up_hyst; + memory_level->DownHyst = data->current_profile_setting.mclk_down_hyst; memory_level->VoltageDownHyst = 0; /* Indicates maximum activity level for this performance level.*/ - memory_level->ActivityLevel = (uint16_t)data->mclk_activity_target; + memory_level->ActivityLevel = data->current_profile_setting.mclk_activity; memory_level->StutterEnable = 0; memory_level->StrobeEnable = 0; memory_level->EdcReadEnable = 0; @@ -1561,7 +1555,7 @@ static int iceland_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, table->MemoryACPILevel.DownHyst = 100; table->MemoryACPILevel.VoltageDownHyst = 0; /* Indicates maximum activity level for this performance level.*/ - table->MemoryACPILevel.ActivityLevel = PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target); + table->MemoryACPILevel.ActivityLevel = PP_HOST_TO_SMC_US(data->current_profile_setting.mclk_activity); table->MemoryACPILevel.StutterEnable = 0; table->MemoryACPILevel.StrobeEnable = 0; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.h index 802472530d34..f32c506779c9 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.h @@ -65,7 +65,6 @@ struct iceland_smumgr { const struct iceland_pt_defaults *power_tune_defaults; SMU71_Discrete_MCRegisters mc_regs; struct iceland_mc_reg_table mc_reg_table; - uint32_t activity_target[SMU71_MAX_LEVELS_GRAPHICS]; }; #endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c index cdb47657b567..bfb2c85d3c60 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c @@ -366,7 +366,6 @@ static bool polaris10_is_hw_avfs_present(struct pp_hwmgr *hwmgr) static int polaris10_smu_init(struct pp_hwmgr *hwmgr) { struct polaris10_smumgr *smu_data; - int i; smu_data = kzalloc(sizeof(struct polaris10_smumgr), GFP_KERNEL); if (smu_data == NULL) @@ -377,9 +376,6 @@ static int polaris10_smu_init(struct pp_hwmgr *hwmgr) if (smu7_init(hwmgr)) return -EINVAL; - for (i = 0; i < SMU74_MAX_LEVELS_GRAPHICS; i++) - smu_data->activity_target[i] = PPPOLARIS10_TARGETACTIVITY_DFLT; - return 0; } @@ -938,8 +934,7 @@ static int polaris10_calculate_sclk_params(struct pp_hwmgr *hwmgr, } static int polaris10_populate_single_graphic_level(struct pp_hwmgr *hwmgr, - uint32_t clock, uint16_t sclk_al_threshold, - struct SMU74_Discrete_GraphicsLevel *level) + uint32_t clock, struct SMU74_Discrete_GraphicsLevel *level) { int result; /* PP_Clocks minClocks; */ @@ -948,26 +943,32 @@ static int polaris10_populate_single_graphic_level(struct pp_hwmgr *hwmgr, struct phm_ppt_v1_information *table_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); SMU_SclkSetting curr_sclk_setting = { 0 }; + phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL; result = polaris10_calculate_sclk_params(hwmgr, clock, &curr_sclk_setting); + if (hwmgr->od_enabled) + vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_sclk; + else + vdd_dep_table = table_info->vdd_dep_on_sclk; + /* populate graphics levels */ result = polaris10_get_dependency_volt_by_clk(hwmgr, - table_info->vdd_dep_on_sclk, clock, + vdd_dep_table, clock, &level->MinVoltage, &mvdd); PP_ASSERT_WITH_CODE((0 == result), "can not find VDDC voltage value for " "VDDC engine clock dependency table", return result); - level->ActivityLevel = sclk_al_threshold; + level->ActivityLevel = data->current_profile_setting.sclk_activity; level->CcPwrDynRm = 0; level->CcPwrDynRm1 = 0; level->EnabledForActivity = 0; level->EnabledForThrottle = 1; - level->UpHyst = 10; - level->DownHyst = 0; + level->UpHyst = data->current_profile_setting.sclk_up_hyst; + level->DownHyst = data->current_profile_setting.sclk_down_hyst; level->VoltageDownHyst = 0; level->PowerThrottle = 0; data->display_timing.min_clock_in_sr = hwmgr->display_config.min_core_set_clock_in_sr; @@ -1031,7 +1032,6 @@ static int polaris10_populate_all_graphic_levels(struct pp_hwmgr *hwmgr) result = polaris10_populate_single_graphic_level(hwmgr, dpm_table->sclk_table.dpm_levels[i].value, - (uint16_t)smu_data->activity_target[i], &(smu_data->smc_state_table.GraphicsLevel[i])); if (result) return result; @@ -1107,12 +1107,18 @@ static int polaris10_populate_single_memory_level(struct pp_hwmgr *hwmgr, int result = 0; struct cgs_display_info info = {0, 0, NULL}; uint32_t mclk_stutter_mode_threshold = 40000; + phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL; cgs_get_active_displays_info(hwmgr->device, &info); - if (table_info->vdd_dep_on_mclk) { + if (hwmgr->od_enabled) + vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_sclk; + else + vdd_dep_table = table_info->vdd_dep_on_mclk; + + if (vdd_dep_table) { result = polaris10_get_dependency_volt_by_clk(hwmgr, - table_info->vdd_dep_on_mclk, clock, + vdd_dep_table, clock, &mem_level->MinVoltage, &mem_level->MinMvdd); PP_ASSERT_WITH_CODE((0 == result), "can not find MinVddc voltage value from memory " @@ -1122,10 +1128,10 @@ static int polaris10_populate_single_memory_level(struct pp_hwmgr *hwmgr, mem_level->MclkFrequency = clock; mem_level->EnabledForThrottle = 1; mem_level->EnabledForActivity = 0; - mem_level->UpHyst = 0; - mem_level->DownHyst = 100; + mem_level->UpHyst = data->current_profile_setting.mclk_up_hyst; + mem_level->DownHyst = data->current_profile_setting.mclk_down_hyst; mem_level->VoltageDownHyst = 0; - mem_level->ActivityLevel = (uint16_t)data->mclk_activity_target; + mem_level->ActivityLevel = data->current_profile_setting.mclk_activity; mem_level->StutterEnable = false; mem_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW; @@ -1306,7 +1312,7 @@ static int polaris10_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, table->MemoryACPILevel.DownHyst = 100; table->MemoryACPILevel.VoltageDownHyst = 0; table->MemoryACPILevel.ActivityLevel = - PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target); + PP_HOST_TO_SMC_US(data->current_profile_setting.mclk_activity); CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MclkFrequency); CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage); @@ -1652,7 +1658,7 @@ static int polaris10_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr) phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ClockStretcher); PP_ASSERT_WITH_CODE(false, - "Stretch Amount in PPTable not supported\n", + "Stretch Amount in PPTable not supported", return -EINVAL); } @@ -1991,7 +1997,7 @@ static int polaris10_init_smc_table(struct pp_hwmgr *hwmgr) result = polaris10_populate_vr_config(hwmgr, table); PP_ASSERT_WITH_CODE(0 == result, "Failed to populate VRConfig setting!", return result); - + hw_data->vr_config = table->VRConfig; table->ThermGpio = 17; table->SclkStepSize = 0x4000; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.h index 5e19c24b0561..1ec425df9eda 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.h @@ -59,7 +59,6 @@ struct polaris10_smumgr { struct SMU74_Discrete_PmFuses power_tune_table; struct polaris10_range_table range_table[NUM_SCLK_RANGE]; const struct polaris10_pt_defaults *power_tune_defaults; - uint32_t activity_target[SMU74_MAX_LEVELS_GRAPHICS]; uint32_t bif_sclk_table[SMU74_MAX_LEVELS_LINK]; }; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c index 79e5c05571bc..97404a578542 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c @@ -222,7 +222,6 @@ static int tonga_start_smu(struct pp_hwmgr *hwmgr) static int tonga_smu_init(struct pp_hwmgr *hwmgr) { struct tonga_smumgr *tonga_priv = NULL; - int i; tonga_priv = kzalloc(sizeof(struct tonga_smumgr), GFP_KERNEL); if (tonga_priv == NULL) @@ -233,9 +232,6 @@ static int tonga_smu_init(struct pp_hwmgr *hwmgr) if (smu7_init(hwmgr)) return -EINVAL; - for (i = 0; i < SMU72_MAX_LEVELS_GRAPHICS; i++) - tonga_priv->activity_target[i] = 30; - return 0; } @@ -416,7 +412,7 @@ static int tonga_populate_cac_tables(struct pp_hwmgr *hwmgr, convert_to_vid(vddc_lookup_table->entries[index].us_cac_high); } - if ((data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2)) { + if (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) { /* We are populating vddgfx CAC data to BapmVddgfx table in split mode */ for (count = 0; count < vddgfx_level_count; count++) { index = phm_get_voltage_index(vddgfx_lookup_table, @@ -612,7 +608,6 @@ static int tonga_calculate_sclk_params(struct pp_hwmgr *hwmgr, static int tonga_populate_single_graphic_level(struct pp_hwmgr *hwmgr, uint32_t engine_clock, - uint16_t sclk_activity_level_threshold, SMU72_Discrete_GraphicsLevel *graphic_level) { int result; @@ -620,12 +615,18 @@ static int tonga_populate_single_graphic_level(struct pp_hwmgr *hwmgr, struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); + phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL; result = tonga_calculate_sclk_params(hwmgr, engine_clock, graphic_level); + if (hwmgr->od_enabled) + vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_sclk; + else + vdd_dep_table = pptable_info->vdd_dep_on_sclk; + /* populate graphics levels*/ result = tonga_get_dependency_volt_by_clk(hwmgr, - pptable_info->vdd_dep_on_sclk, engine_clock, + vdd_dep_table, engine_clock, &graphic_level->MinVoltage, &mvdd); PP_ASSERT_WITH_CODE((!result), "can not find VDDC voltage value for VDDC " @@ -634,7 +635,7 @@ static int tonga_populate_single_graphic_level(struct pp_hwmgr *hwmgr, /* SCLK frequency in units of 10KHz*/ graphic_level->SclkFrequency = engine_clock; /* Indicates maximum activity level for this performance level. 50% for now*/ - graphic_level->ActivityLevel = sclk_activity_level_threshold; + graphic_level->ActivityLevel = data->current_profile_setting.sclk_activity; graphic_level->CcPwrDynRm = 0; graphic_level->CcPwrDynRm1 = 0; @@ -642,8 +643,8 @@ static int tonga_populate_single_graphic_level(struct pp_hwmgr *hwmgr, graphic_level->EnabledForActivity = 0; /* this level can be used for throttling.*/ graphic_level->EnabledForThrottle = 1; - graphic_level->UpHyst = 0; - graphic_level->DownHyst = 0; + graphic_level->UpHyst = data->current_profile_setting.sclk_up_hyst; + graphic_level->DownHyst = data->current_profile_setting.sclk_down_hyst; graphic_level->VoltageDownHyst = 0; graphic_level->PowerThrottle = 0; @@ -702,7 +703,6 @@ static int tonga_populate_all_graphic_levels(struct pp_hwmgr *hwmgr) for (i = 0; i < dpm_table->sclk_table.count; i++) { result = tonga_populate_single_graphic_level(hwmgr, dpm_table->sclk_table.dpm_levels[i].value, - (uint16_t)smu_data->activity_target[i], &(smu_data->smc_state_table.GraphicsLevel[i])); if (result != 0) return result; @@ -966,10 +966,16 @@ static int tonga_populate_single_memory_level( uint32_t mclk_stutter_mode_threshold = 30000; uint32_t mclk_edc_enable_threshold = 40000; uint32_t mclk_strobe_mode_threshold = 40000; + phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL; - if (NULL != pptable_info->vdd_dep_on_mclk) { + if (hwmgr->od_enabled) + vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_sclk; + else + vdd_dep_table = pptable_info->vdd_dep_on_mclk; + + if (NULL != vdd_dep_table) { result = tonga_get_dependency_volt_by_clk(hwmgr, - pptable_info->vdd_dep_on_mclk, + vdd_dep_table, memory_clock, &memory_level->MinVoltage, &mvdd); PP_ASSERT_WITH_CODE( @@ -986,12 +992,12 @@ static int tonga_populate_single_memory_level( memory_level->EnabledForThrottle = 1; memory_level->EnabledForActivity = 0; - memory_level->UpHyst = 0; - memory_level->DownHyst = 100; + memory_level->UpHyst = data->current_profile_setting.mclk_up_hyst; + memory_level->DownHyst = data->current_profile_setting.mclk_down_hyst; memory_level->VoltageDownHyst = 0; /* Indicates maximum activity level for this performance level.*/ - memory_level->ActivityLevel = (uint16_t)data->mclk_activity_target; + memory_level->ActivityLevel = data->current_profile_setting.mclk_activity; memory_level->StutterEnable = 0; memory_level->StrobeEnable = 0; memory_level->EdcReadEnable = 0; @@ -1281,7 +1287,7 @@ static int tonga_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, table->MemoryACPILevel.VoltageDownHyst = 0; /* Indicates maximum activity level for this performance level.*/ table->MemoryACPILevel.ActivityLevel = - PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target); + PP_HOST_TO_SMC_US(data->current_profile_setting.mclk_activity); table->MemoryACPILevel.StutterEnable = 0; table->MemoryACPILevel.StrobeEnable = 0; @@ -1699,7 +1705,7 @@ static int tonga_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr) phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ClockStretcher); PP_ASSERT_WITH_CODE(false, - "Stretch Amount in PPTable not supported\n", + "Stretch Amount in PPTable not supported", return -EINVAL); } @@ -2434,7 +2440,7 @@ static int tonga_init_smc_table(struct pp_hwmgr *hwmgr) result = tonga_populate_vr_config(hwmgr, table); PP_ASSERT_WITH_CODE(!result, "Failed to populate VRConfig setting !", return result); - + data->vr_config = table->VRConfig; table->ThermGpio = 17; table->SclkStepSize = 0x4000; @@ -2501,7 +2507,6 @@ static int tonga_init_smc_table(struct pp_hwmgr *hwmgr) for (i = 0; i < SMU72_MAX_ENTRIES_SMIO; i++) table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]); - CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags); CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig); CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.h index 5d70a00348e2..d664fedd3d85 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.h @@ -69,9 +69,6 @@ struct tonga_smumgr { const struct tonga_pt_defaults *power_tune_defaults; SMU72_Discrete_MCRegisters mc_regs; struct tonga_mc_reg_table mc_reg_table; - - uint32_t activity_target[SMU72_MAX_LEVELS_GRAPHICS]; - }; #endif diff --git a/drivers/gpu/drm/arc/arcpgu_hdmi.c b/drivers/gpu/drm/arc/arcpgu_hdmi.c index 0ce7f398bcff..977dfa55162f 100644 --- a/drivers/gpu/drm/arc/arcpgu_hdmi.c +++ b/drivers/gpu/drm/arc/arcpgu_hdmi.c @@ -15,7 +15,8 @@ */ #include -#include +#include +#include #include "arcpgu.h" diff --git a/drivers/gpu/drm/arc/arcpgu_sim.c b/drivers/gpu/drm/arc/arcpgu_sim.c index bca3a678c955..b8f6f9a5dfbe 100644 --- a/drivers/gpu/drm/arc/arcpgu_sim.c +++ b/drivers/gpu/drm/arc/arcpgu_sim.c @@ -15,7 +15,6 @@ */ #include -#include #include #include "arcpgu.h" @@ -29,7 +28,6 @@ struct arcpgu_drm_connector { struct drm_connector connector; - struct drm_encoder_slave *encoder_slave; }; static int arcpgu_drm_connector_get_modes(struct drm_connector *connector) @@ -68,7 +66,7 @@ static struct drm_encoder_funcs arcpgu_drm_encoder_funcs = { int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np) { struct arcpgu_drm_connector *arcpgu_connector; - struct drm_encoder_slave *encoder; + struct drm_encoder *encoder; struct drm_connector *connector; int ret; @@ -76,10 +74,10 @@ int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np) if (encoder == NULL) return -ENOMEM; - encoder->base.possible_crtcs = 1; - encoder->base.possible_clones = 0; + encoder->possible_crtcs = 1; + encoder->possible_clones = 0; - ret = drm_encoder_init(drm, &encoder->base, &arcpgu_drm_encoder_funcs, + ret = drm_encoder_init(drm, encoder, &arcpgu_drm_encoder_funcs, DRM_MODE_ENCODER_VIRTUAL, NULL); if (ret) return ret; @@ -101,21 +99,19 @@ int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np) goto error_encoder_cleanup; } - ret = drm_mode_connector_attach_encoder(connector, &encoder->base); + ret = drm_mode_connector_attach_encoder(connector, encoder); if (ret < 0) { dev_err(drm->dev, "could not attach connector to encoder\n"); drm_connector_unregister(connector); goto error_connector_cleanup; } - arcpgu_connector->encoder_slave = encoder; - return 0; error_connector_cleanup: drm_connector_cleanup(connector); error_encoder_cleanup: - drm_encoder_cleanup(&encoder->base); + drm_encoder_cleanup(encoder); return ret; } diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c index 630721f429f7..877647ef35a9 100644 --- a/drivers/gpu/drm/arm/hdlcd_crtc.c +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c @@ -249,8 +249,9 @@ static int hdlcd_plane_atomic_check(struct drm_plane *plane, return -EINVAL; } - clip.x2 = crtc_state->adjusted_mode.hdisplay; - clip.y2 = crtc_state->adjusted_mode.vdisplay; + if (crtc_state->enable) + drm_mode_get_hv_timing(&crtc_state->mode, + &clip.x2, &clip.y2); return drm_atomic_helper_check_plane_state(state, crtc_state, &clip, DRM_PLANE_HELPER_NO_SCALING, diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 33c5ef96ced0..2885d69af456 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -148,8 +148,10 @@ static int malidp_se_check_scaling(struct malidp_plane *mp, if (!crtc_state) return -EINVAL; - clip.x2 = crtc_state->adjusted_mode.hdisplay; - clip.y2 = crtc_state->adjusted_mode.vdisplay; + if (crtc_state->enable) + drm_mode_get_hv_timing(&crtc_state->mode, + &clip.x2, &clip.y2); + ret = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, 0, INT_MAX, true, true); if (ret) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index 703c2d13603f..e18800ed7cd1 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c @@ -194,20 +194,6 @@ static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode) return 0; } -static bool atmel_hlcdc_format_embeds_alpha(u32 format) -{ - int i; - - for (i = 0; i < sizeof(format); i++) { - char tmp = (format >> (8 * i)) & 0xff; - - if (tmp == 'A') - return true; - } - - return false; -} - static u32 heo_downscaling_xcoef[] = { 0x11343311, 0x000000f7, @@ -377,13 +363,13 @@ atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane, { unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id; const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc; - u32 format = state->base.fb->format->format; + const struct drm_format_info *format = state->base.fb->format; /* * Rotation optimization is not working on RGB888 (rotation is still * working but without any optimization). */ - if (format == DRM_FORMAT_RGB888) + if (format->format == DRM_FORMAT_RGB888) cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS; atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG, @@ -395,7 +381,7 @@ atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane, cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL | ATMEL_HLCDC_LAYER_ITER; - if (atmel_hlcdc_format_embeds_alpha(format)) + if (format->has_alpha) cfg |= ATMEL_HLCDC_LAYER_LAEN; else cfg |= ATMEL_HLCDC_LAYER_GAEN | @@ -566,7 +552,7 @@ atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state) ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s); if (!ovl_s->fb || - atmel_hlcdc_format_embeds_alpha(ovl_s->fb->format->format) || + ovl_s->fb->format->has_alpha || ovl_state->alpha != 255) continue; @@ -769,7 +755,7 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p, if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) && (!desc->layout.memsize || - atmel_hlcdc_format_embeds_alpha(state->base.fb->format->format))) + state->base.fb->format->has_alpha)) return -EINVAL; if (state->crtc_x < 0 || state->crtc_y < 0) diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index 704e879711e4..b1d5aee46316 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -194,7 +194,7 @@ static struct ttm_tt *bochs_ttm_tt_create(struct ttm_bo_device *bdev, return tt; } -struct ttm_bo_driver bochs_bo_driver = { +static struct ttm_bo_driver bochs_bo_driver = { .ttm_tt_create = bochs_ttm_tt_create, .ttm_tt_populate = ttm_pool_populate, .ttm_tt_unpopulate = ttm_pool_unpopulate, diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c index ed12a7ddd64a..b49043866be6 100644 --- a/drivers/gpu/drm/bridge/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c @@ -1301,8 +1301,7 @@ static void unregister_i2c_dummy_clients(struct anx78xx *anx78xx) unsigned int i; for (i = 0; i < ARRAY_SIZE(anx78xx->i2c_dummy); i++) - if (anx78xx->i2c_dummy[i]) - i2c_unregister_device(anx78xx->i2c_dummy[i]); + i2c_unregister_device(anx78xx->i2c_dummy[i]); } static const struct regmap_config anx78xx_regmap_config = { diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index a8905049b9da..b2756bc4225a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -727,7 +727,6 @@ static int analogix_dp_set_link_train(struct analogix_dp_device *dp, static int analogix_dp_config_video(struct analogix_dp_device *dp) { - int retval = 0; int timeout_loop = 0; int done_count = 0; @@ -783,10 +782,7 @@ static int analogix_dp_config_video(struct analogix_dp_device *dp) usleep_range(1000, 1001); } - if (retval != 0) - dev_err(dp->dev, "Video stream is not detected!\n"); - - return retval; + return 0; } static void analogix_dp_enable_scramble(struct analogix_dp_device *dp, diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c index de5e7dee7ad6..498d5948d1a8 100644 --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c @@ -11,6 +11,7 @@ */ #include +#include #include #include @@ -204,6 +205,7 @@ static int dumb_vga_probe(struct platform_device *pdev) vga->bridge.funcs = &dumb_vga_bridge_funcs; vga->bridge.of_node = pdev->dev.of_node; + vga->bridge.timings = of_device_get_match_data(&pdev->dev); drm_bridge_add(&vga->bridge); @@ -222,10 +224,61 @@ static int dumb_vga_remove(struct platform_device *pdev) return 0; } +/* + * We assume the ADV7123 DAC is the "default" for historical reasons + * Information taken from the ADV7123 datasheet, revision D. + * NOTE: the ADV7123EP seems to have other timings and need a new timings + * set if used. + */ +static const struct drm_bridge_timings default_dac_timings = { + /* Timing specifications, datasheet page 7 */ + .sampling_edge = DRM_BUS_FLAG_PIXDATA_POSEDGE, + .setup_time_ps = 500, + .hold_time_ps = 1500, +}; + +/* + * Information taken from the THS8134, THS8134A, THS8134B datasheet named + * "SLVS205D", dated May 1990, revised March 2000. + */ +static const struct drm_bridge_timings ti_ths8134_dac_timings = { + /* From timing diagram, datasheet page 9 */ + .sampling_edge = DRM_BUS_FLAG_PIXDATA_POSEDGE, + /* From datasheet, page 12 */ + .setup_time_ps = 3000, + /* I guess this means latched input */ + .hold_time_ps = 0, +}; + +/* + * Information taken from the THS8135 datasheet named "SLAS343B", dated + * May 2001, revised April 2013. + */ +static const struct drm_bridge_timings ti_ths8135_dac_timings = { + /* From timing diagram, datasheet page 14 */ + .sampling_edge = DRM_BUS_FLAG_PIXDATA_POSEDGE, + /* From datasheet, page 16 */ + .setup_time_ps = 2000, + .hold_time_ps = 500, +}; + static const struct of_device_id dumb_vga_match[] = { - { .compatible = "dumb-vga-dac" }, - { .compatible = "adi,adv7123" }, - { .compatible = "ti,ths8135" }, + { + .compatible = "dumb-vga-dac", + .data = NULL, + }, + { + .compatible = "adi,adv7123", + .data = &default_dac_timings, + }, + { + .compatible = "ti,ths8135", + .data = &ti_ths8135_dac_timings, + }, + { + .compatible = "ti,ths8134", + .data = &ti_ths8134_dac_timings, + }, {}, }; MODULE_DEVICE_TABLE(of, dumb_vga_match); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index a38db40ce990..f9802399cc0d 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1037,19 +1037,21 @@ static void dw_hdmi_phy_enable_svsret(struct dw_hdmi *hdmi, u8 enable) HDMI_PHY_CONF0_SVSRET_MASK); } -static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable) +void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable) { hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET, HDMI_PHY_CONF0_GEN2_PDDQ_MASK); } +EXPORT_SYMBOL_GPL(dw_hdmi_phy_gen2_pddq); -static void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable) +void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable) { hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET, HDMI_PHY_CONF0_GEN2_TXPWRON_MASK); } +EXPORT_SYMBOL_GPL(dw_hdmi_phy_gen2_txpwron); static void dw_hdmi_phy_sel_data_en_pol(struct dw_hdmi *hdmi, u8 enable) { @@ -1065,6 +1067,22 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable) HDMI_PHY_CONF0_SELDIPIF_MASK); } +void dw_hdmi_phy_reset(struct dw_hdmi *hdmi) +{ + /* PHY reset. The reset signal is active high on Gen2 PHYs. */ + hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ); + hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ); +} +EXPORT_SYMBOL_GPL(dw_hdmi_phy_reset); + +void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address) +{ + hdmi_phy_test_clear(hdmi, 1); + hdmi_writeb(hdmi, address, HDMI_PHY_I2CM_SLAVE_ADDR); + hdmi_phy_test_clear(hdmi, 0); +} +EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_set_addr); + static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi) { const struct dw_hdmi_phy_data *phy = hdmi->phy.data; @@ -1203,16 +1221,11 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi) if (phy->has_svsret) dw_hdmi_phy_enable_svsret(hdmi, 1); - /* PHY reset. The reset signal is active high on Gen2 PHYs. */ - hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ); - hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ); + dw_hdmi_phy_reset(hdmi); hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST); - hdmi_phy_test_clear(hdmi, 1); - hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2, - HDMI_PHY_I2CM_SLAVE_ADDR); - hdmi_phy_test_clear(hdmi, 0); + dw_hdmi_phy_i2c_set_addr(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2); /* Write to the PHY as configured by the platform */ if (pdata->configure_phy) @@ -1251,15 +1264,16 @@ static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data) dw_hdmi_phy_power_off(hdmi); } -static enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi, - void *data) +enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi, + void *data) { return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ? connector_status_connected : connector_status_disconnected; } +EXPORT_SYMBOL_GPL(dw_hdmi_phy_read_hpd); -static void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data, - bool force, bool disabled, bool rxsense) +void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data, + bool force, bool disabled, bool rxsense) { u8 old_mask = hdmi->phy_mask; @@ -1271,8 +1285,9 @@ static void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data, if (old_mask != hdmi->phy_mask) hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); } +EXPORT_SYMBOL_GPL(dw_hdmi_phy_update_hpd); -static void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data) +void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data) { /* * Configure the PHY RX SENSE and HPD interrupts polarities and clear @@ -1291,6 +1306,7 @@ static void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data) hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE), HDMI_IH_MUTE_PHY_STAT0); } +EXPORT_SYMBOL_GPL(dw_hdmi_phy_setup_hpd); static const struct dw_hdmi_phy_ops dw_hdmi_synopsys_phy_ops = { .init = dw_hdmi_phy_init, @@ -1634,9 +1650,10 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi) * then write one of the FC registers several times. * * The number of iterations matters and depends on the HDMI TX revision - * (and possibly on the platform). So far only i.MX6Q (v1.30a) and - * i.MX6DL (v1.31a) have been identified as needing the workaround, with - * 4 and 1 iterations respectively. + * (and possibly on the platform). So far i.MX6Q (v1.30a), i.MX6DL + * (v1.31a) and multiple Allwinner SoCs (v1.32a) have been identified + * as needing the workaround, with 4 iterations for v1.30a and 1 + * iteration for others. */ switch (hdmi->version) { @@ -1644,6 +1661,7 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi) count = 4; break; case 0x131a: + case 0x132a: count = 1; break; default: @@ -2525,8 +2543,6 @@ __dw_hdmi_probe(struct platform_device *pdev, if (hdmi->i2c) dw_hdmi_i2c_init(hdmi); - platform_set_drvdata(pdev, hdmi); - return hdmi; err_iahb: @@ -2576,25 +2592,23 @@ static void __dw_hdmi_remove(struct dw_hdmi *hdmi) /* ----------------------------------------------------------------------------- * Probe/remove API, used from platforms based on the DRM bridge API. */ -int dw_hdmi_probe(struct platform_device *pdev, - const struct dw_hdmi_plat_data *plat_data) +struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, + const struct dw_hdmi_plat_data *plat_data) { struct dw_hdmi *hdmi; hdmi = __dw_hdmi_probe(pdev, plat_data); if (IS_ERR(hdmi)) - return PTR_ERR(hdmi); + return hdmi; drm_bridge_add(&hdmi->bridge); - return 0; + return hdmi; } EXPORT_SYMBOL_GPL(dw_hdmi_probe); -void dw_hdmi_remove(struct platform_device *pdev) +void dw_hdmi_remove(struct dw_hdmi *hdmi) { - struct dw_hdmi *hdmi = platform_get_drvdata(pdev); - drm_bridge_remove(&hdmi->bridge); __dw_hdmi_remove(hdmi); @@ -2604,31 +2618,30 @@ EXPORT_SYMBOL_GPL(dw_hdmi_remove); /* ----------------------------------------------------------------------------- * Bind/unbind API, used from platforms based on the component framework. */ -int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, - const struct dw_hdmi_plat_data *plat_data) +struct dw_hdmi *dw_hdmi_bind(struct platform_device *pdev, + struct drm_encoder *encoder, + const struct dw_hdmi_plat_data *plat_data) { struct dw_hdmi *hdmi; int ret; hdmi = __dw_hdmi_probe(pdev, plat_data); if (IS_ERR(hdmi)) - return PTR_ERR(hdmi); + return hdmi; ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL); if (ret) { - dw_hdmi_remove(pdev); + dw_hdmi_remove(hdmi); DRM_ERROR("Failed to initialize bridge with drm\n"); - return ret; + return ERR_PTR(ret); } - return 0; + return hdmi; } EXPORT_SYMBOL_GPL(dw_hdmi_bind); -void dw_hdmi_unbind(struct device *dev) +void dw_hdmi_unbind(struct dw_hdmi *hdmi) { - struct dw_hdmi *hdmi = dev_get_drvdata(dev); - __dw_hdmi_remove(hdmi); } EXPORT_SYMBOL_GPL(dw_hdmi_unbind); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index d9cca4fd66ec..7bac101c285c 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -29,7 +29,10 @@ #include #include