diff --git a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl index 589b40cc5eb5..2a272275c81b 100644 --- a/Documentation/DocBook/kernel-hacking.tmpl +++ b/Documentation/DocBook/kernel-hacking.tmpl @@ -483,7 +483,7 @@ printk(KERN_INFO "my ip: %pI4\n", &ipaddress); get_user() / put_user() - include/asm/uaccess.h + include/linux/uaccess.h diff --git a/Documentation/devicetree/bindings/pwm/pwm-meson.txt b/Documentation/devicetree/bindings/pwm/pwm-meson.txt new file mode 100644 index 000000000000..5376a4468cb6 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm-meson.txt @@ -0,0 +1,23 @@ +Amlogic Meson PWM Controller +============================ + +Required properties: +- compatible: Shall contain "amlogic,meson8b-pwm" or "amlogic,meson-gxbb-pwm". +- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of + the cells format. + +Optional properties: +- clocks: Could contain one or two parents clocks phandle for each of the two + PWM channels. +- clock-names: Could contain at least the "clkin0" and/or "clkin1" names. + +Example: + + pwm_ab: pwm@8550 { + compatible = "amlogic,meson-gxbb-pwm"; + reg = <0x0 0x08550 0x0 0x10>; + #pwm-cells = <3>; + status = "disabled"; + clocks = <&xtal>, <&xtal>; + clock-names = "clkin0", "clkin1"; + } diff --git a/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt b/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt index f8f59baf6b67..6f8af2bcc7b7 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt @@ -2,8 +2,9 @@ MediaTek display PWM controller Required properties: - compatible: should be "mediatek,-disp-pwm": - - "mediatek,mt8173-disp-pwm": found on mt8173 SoC. + - "mediatek,mt2701-disp-pwm": found on mt2701 SoC. - "mediatek,mt6595-disp-pwm": found on mt6595 SoC. + - "mediatek,mt8173-disp-pwm": found on mt8173 SoC. - reg: physical base address and length of the controller's registers. - #pwm-cells: must be 2. See pwm.txt in this directory for a description of the cell format. diff --git a/Documentation/devicetree/bindings/pwm/pwm-st.txt b/Documentation/devicetree/bindings/pwm/pwm-st.txt index 84d2fb807d3c..19fce774cafa 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-st.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-st.txt @@ -13,13 +13,14 @@ Required parameters: - pinctrl-0: List of phandles pointing to pin configuration nodes for PWM module. For Pinctrl properties, please refer to [1]. -- clock-names: Set to "pwm". +- clock-names: Valid entries are "pwm" and/or "capture". - clocks: phandle of the clock used by the PWM module. For Clk properties, please refer to [2]. +- interrupts: IRQ for the Capture device Optional properties: -- st,pwm-num-chan: Number of available channels. If not passed, the driver - will consider single channel by default. +- st,pwm-num-chan: Number of available PWM channels. Default is 0. +- st,capture-num-chan: Number of available Capture channels. Default is 0. [1] Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt [2] Documentation/devicetree/bindings/clock/clock-bindings.txt @@ -38,4 +39,5 @@ pwm1: pwm@fe510000 { clocks = <&clk_sysin>; clock-names = "pwm"; st,pwm-num-chan = <4>; + st,capture-num-chan = <2>; }; diff --git a/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt b/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt index cf6068b8e974..f1cbeefb3087 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt @@ -6,6 +6,7 @@ Required properties: - "allwinner,sun5i-a10s-pwm" - "allwinner,sun5i-a13-pwm" - "allwinner,sun7i-a20-pwm" + - "allwinner,sun8i-h3-pwm" - reg: physical base address and length of the controller's registers - #pwm-cells: should be 3. See pwm.txt in this directory for a description of the cells format. diff --git a/Documentation/devicetree/bindings/thermal/max77620_thermal.txt b/Documentation/devicetree/bindings/thermal/max77620_thermal.txt new file mode 100644 index 000000000000..323a3b3822aa --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/max77620_thermal.txt @@ -0,0 +1,70 @@ +Thermal driver for MAX77620 Power management IC from Maxim Semiconductor. + +Maxim Semiconductor MAX77620 supports alarm interrupts when its +die temperature crosses 120C and 140C. These threshold temperatures +are not configurable. Device does not provide the real temperature +of die other than just indicating whether temperature is above or +below threshold level. + +Required properties: +------------------- +#thermal-sensor-cells: Please refer + for more details. + The value must be 0. + +For more details, please refer generic thermal DT binding document +. + +Please refer for mfd DT binding +document for the MAX77620. + +Example: +-------- +#include +#include +... + +i2c@7000d000 { + spmic: max77620@3c { + compatible = "maxim,max77620"; + ::::: + #thermal-sensor-cells = <0>; + ::: + }; +}; + +cool_dev: cool-dev { + compatible = "cooling-dev"; + #cooling-cells = <2>; +}; + +thermal-zones { + PMIC-Die { + polling-delay = <0>; + polling-delay-passive = <0>; + thermal-sensors = <&spmic>; + + trips { + pmic_die_warn_temp_thresh: hot-die { + temperature = <120000>; + type = "hot"; + hysteresis = <0>; + }; + + pmic_die_cirt_temp_thresh: cirtical-die { + temperature = <140000>; + type = "critical"; + hysteresis = <0>; + }; + }; + + cooling-maps { + map0 { + trip = <&pmic_die_warn_temp_thresh>; + cooling-device = <&cool_dev THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + contribution = <100>; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt b/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt index 81f9a512bc2a..e2f494d74d8a 100644 --- a/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt @@ -8,7 +8,9 @@ apmixedsys register space via AHB bus accesses, so a phandle to the APMIXEDSYS is also needed. Required properties: -- compatible: "mediatek,mt8173-thermal" +- compatible: + - "mediatek,mt8173-thermal" : For MT8173 family of SoCs + - "mediatek,mt2701-thermal" : For MT2701 family of SoCs - reg: Address range of the thermal controller - interrupts: IRQ for the thermal controller - clocks, clock-names: Clocks needed for the thermal controller. required diff --git a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt index edebfa0a985e..b6c0ae53d4dc 100644 --- a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt +++ b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt @@ -10,8 +10,14 @@ Required properties : - compatible : For Tegra124, must contain "nvidia,tegra124-soctherm". For Tegra132, must contain "nvidia,tegra132-soctherm". For Tegra210, must contain "nvidia,tegra210-soctherm". -- reg : Should contain 1 entry: +- reg : Should contain at least 2 entries for each entry in reg-names: - SOCTHERM register set + - Tegra CAR register set: Required for Tegra124 and Tegra210. + - CCROC register set: Required for Tegra132. +- reg-names : Should contain at least 2 entries: + - soctherm-reg + - car-reg + - ccroc-reg - interrupts : Defines the interrupt used by SOCTHERM - clocks : Must contain an entry for each entry in clock-names. See ../clocks/clock-bindings.txt for details. @@ -25,17 +31,45 @@ Required properties : - #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description of this property. See for a list of valid values when referring to thermal sensors. +- throttle-cfgs: A sub-node which is a container of configuration for each + hardware throttle events. These events can be set as cooling devices. + * throttle events: Sub-nodes must be named as "light" or "heavy". + Properties: + - nvidia,priority: Each throttles has its own throttle settings, so the + SW need to set priorities for various throttle, the HW arbiter can select + the final throttle settings. + Bigger value indicates higher priority, In general, higher priority + translates to lower target frequency. SW needs to ensure that critical + thermal alarms are given higher priority, and ensure that there is + no race if priority of two vectors is set to the same value. + The range of this value is 1~100. + - nvidia,cpu-throt-percent: This property is for Tegra124 and Tegra210. + It is the throttling depth of pulse skippers, it's the percentage + throttling. + - nvidia,cpu-throt-level: This property is only for Tegra132, it is the + level of pulse skippers, which used to throttle clock frequencies. It + indicates cpu clock throttling depth, and the depth can be programmed. + Must set as following values: + TEGRA_SOCTHERM_THROT_LEVEL_LOW, TEGRA_SOCTHERM_THROT_LEVEL_MED + TEGRA_SOCTHERM_THROT_LEVEL_HIGH, TEGRA_SOCTHERM_THROT_LEVEL_NONE + - #cooling-cells: Should be 1. This cooling device only support on/off state. + See ./thermal.txt for a description of this property. Note: - the "critical" type trip points will be set to SOC_THERM hardware as the shut down temperature. Once the temperature of this thermal zone is higher than it, the system will be shutdown or reset by hardware. +- the "hot" type trip points will be set to SOC_THERM hardware as the throttle +temperature. Once the the temperature of this thermal zone is higher +than it, it will trigger the HW throttle event. Example : soctherm@700e2000 { compatible = "nvidia,tegra124-soctherm"; - reg = <0x0 0x700e2000 0x0 0x1000>; + reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */ + 0x0 0x60006000 0x0 0x400 /* CAR reg_base */ + reg-names = "soctherm-reg", "car-reg"; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_TSENSOR>, <&tegra_car TEGRA124_CLK_SOC_THERM>; @@ -44,6 +78,76 @@ Example : reset-names = "soctherm"; #thermal-sensor-cells = <1>; + + throttle-cfgs { + /* + * When the "heavy" cooling device triggered, + * the HW will skip cpu clock's pulse in 85% depth + */ + throttle_heavy: heavy { + nvidia,priority = <100>; + nvidia,cpu-throt-percent = <85>; + + #cooling-cells = <1>; + }; + + /* + * When the "light" cooling device triggered, + * the HW will skip cpu clock's pulse in 50% depth + */ + throttle_light: light { + nvidia,priority = <80>; + nvidia,cpu-throt-percent = <50>; + + #cooling-cells = <1>; + }; + + /* + * If these two devices are triggered in same time, the HW throttle + * arbiter will select the highest priority as the final throttle + * settings to skip cpu pulse. + */ + }; + }; + +Example: referring to Tegra132's "reg", "reg-names" and "throttle-cfgs" : + + soctherm@700e2000 { + compatible = "nvidia,tegra132-soctherm"; + reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */ + 0x0 0x70040000 0x0 0x200>; /* CCROC reg_base */; + reg-names = "soctherm-reg", "ccroc-reg"; + + throttle-cfgs { + /* + * When the "heavy" cooling device triggered, + * the HW will skip cpu clock's pulse in HIGH level + */ + throttle_heavy: heavy { + nvidia,priority = <100>; + nvidia,cpu-throt-level = ; + + #cooling-cells = <1>; + }; + + /* + * When the "light" cooling device triggered, + * the HW will skip cpu clock's pulse in MED level + */ + throttle_light: light { + nvidia,priority = <80>; + nvidia,cpu-throt-level = ; + + #cooling-cells = <1>; + }; + + /* + * If these two devices are triggered in same time, the HW throttle + * arbiter will select the highest priority as the final throttle + * settings to skip cpu pulse. + */ + + }; }; Example: referring to thermal sensors : @@ -62,6 +166,19 @@ Example: referring to thermal sensors : hysteresis = <1000>; type = "critical"; }; + + cpu_throttle_trip: throttle-trip { + temperature = <100000>; + hysteresis = <1000>; + type = "hot"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_throttle_trip>; + cooling-device = <&throttle_heavy 1 1>; + }; }; }; }; diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt new file mode 100644 index 000000000000..292ed89d900b --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt @@ -0,0 +1,21 @@ +* QCOM SoC Temperature Sensor (TSENS) + +Required properties: +- compatible : + - "qcom,msm8916-tsens" : For 8916 Family of SoCs + - "qcom,msm8974-tsens" : For 8974 Family of SoCs + - "qcom,msm8996-tsens" : For 8996 Family of SoCs + +- reg: Address range of the thermal registers +- #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description. +- Refer to Documentation/devicetree/bindings/nvmem/nvmem.txt to know how to specify +nvmem cells + +Example: +tsens: thermal-sensor@900000 { + compatible = "qcom,msm8916-tsens"; + reg = <0x4a8000 0x2000>; + nvmem-cells = <&tsens_caldata>, <&tsens_calsel>; + nvmem-cell-names = "caldata", "calsel"; + #thermal-sensor-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt b/Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt index 6d63782a7378..c6ae9c9d5e3e 100644 --- a/Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt @@ -7,6 +7,8 @@ Required properties: - reg : Physical base address and size Optional properties: +- clocks : Input clock specifier. Refer to common clock + bindings. - clock-frequency : Frequency of clock in Hz - xlnx,wdt-enable-once : 0 - Watchdog can be restarted 1 - Watchdog can be enabled just once @@ -17,6 +19,7 @@ Example: axi-timebase-wdt@40100000 { clock-frequency = <50000000>; compatible = "xlnx,xps-timebase-wdt-1.00.a"; + clocks = <&clkc 15>; reg = <0x40100000 0x10000>; xlnx,wdt-enable-once = <0x0>; xlnx,wdt-interval = <0x1b>; diff --git a/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt b/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt index 039c5ca45577..b949039bc502 100644 --- a/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt @@ -9,8 +9,7 @@ functionality. Required properties -- compatible : Must be one of: "st,stih407-lpc" "st,stih416-lpc" - "st,stih415-lpc" "st,stid127-lpc" +- compatible : Should be: "st,stih407-lpc" - reg : LPC registers base address + size - interrupts : LPC interrupt line number and associated flags - clocks : Clock used by LPC device (See: ../clock/clock-bindings.txt) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a1489e14f8ee..58f3c1041759 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2470,6 +2470,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. nfsrootdebug [NFS] enable nfsroot debugging messages. See Documentation/filesystems/nfs/nfsroot.txt. + nfs.callback_nr_threads= + [NFSv4] set the total number of threads that the + NFS client will assign to service NFSv4 callback + requests. + nfs.callback_tcpport= [NFS] set the TCP port on which the NFSv4 callback channel should listen. @@ -2493,6 +2498,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. of returning the full 64-bit number. The default is to return 64-bit inode numbers. + nfs.max_session_cb_slots= + [NFSv4.1] Sets the maximum number of session + slots the client will assign to the callback + channel. This determines the maximum number of + callbacks the client will process in parallel for + a particular server. + nfs.max_session_slots= [NFSv4.1] Sets the maximum number of session slots the client will attempt to negotiate with the server. diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt index efc3f3d293c4..ef473dc7f55e 100644 --- a/Documentation/thermal/sysfs-api.txt +++ b/Documentation/thermal/sysfs-api.txt @@ -49,6 +49,9 @@ temperature) and throttle appropriate devices. .bind: bind the thermal zone device with a thermal cooling device. .unbind: unbind the thermal zone device with a thermal cooling device. .get_temp: get the current temperature of the thermal zone. + .set_trips: set the trip points window. Whenever the current temperature + is updated, the trip points immediately below and above the + current temperature are found. .get_mode: get the current mode (enabled/disabled) of the thermal zone. - "enabled" means the kernel thermal management is enabled. - "disabled" will prevent kernel thermal driver action upon trip points @@ -95,6 +98,10 @@ temperature) and throttle appropriate devices. get_temp: a pointer to a function that reads the sensor temperature. This is mandatory callback provided by sensor driver. + set_trips: a pointer to a function that sets a + temperature window. When this window is + left the driver must inform the thermal + core via thermal_zone_device_update. get_trend: a pointer to a function that reads the sensor temperature trend. set_emul_temp: a pointer to a function that sets @@ -140,6 +147,18 @@ temperature) and throttle appropriate devices. Normally this function will not need to be called and the resource management code will ensure that the resource is freed. +1.1.7 int thermal_zone_get_slope(struct thermal_zone_device *tz) + + This interface is used to read the slope attribute value + for the thermal zone device, which might be useful for platform + drivers for temperature calculations. + +1.1.8 int thermal_zone_get_offset(struct thermal_zone_device *tz) + + This interface is used to read the offset attribute value + for the thermal zone device, which might be useful for platform + drivers for temperature calculations. + 1.2 thermal cooling device interface 1.2.1 struct thermal_cooling_device *thermal_cooling_device_register(char *name, void *devdata, struct thermal_cooling_device_ops *) diff --git a/Documentation/watchdog/watchdog-kernel-api.txt b/Documentation/watchdog/watchdog-kernel-api.txt index 7f31125c123e..ea277478982f 100644 --- a/Documentation/watchdog/watchdog-kernel-api.txt +++ b/Documentation/watchdog/watchdog-kernel-api.txt @@ -48,8 +48,10 @@ struct watchdog_device { const struct attribute_group **groups; const struct watchdog_info *info; const struct watchdog_ops *ops; + const struct watchdog_governor *gov; unsigned int bootstatus; unsigned int timeout; + unsigned int pretimeout; unsigned int min_timeout; unsigned int max_timeout; unsigned int min_hw_heartbeat_ms; @@ -74,9 +76,11 @@ It contains following fields: * info: a pointer to a watchdog_info structure. This structure gives some additional information about the watchdog timer itself. (Like it's unique name) * ops: a pointer to the list of watchdog operations that the watchdog supports. +* gov: a pointer to the assigned watchdog device pretimeout governor or NULL. * timeout: the watchdog timer's timeout value (in seconds). This is the time after which the system will reboot if user space does not send a heartbeat request if WDOG_ACTIVE is set. +* pretimeout: the watchdog timer's pretimeout value (in seconds). * min_timeout: the watchdog timer's minimum timeout value (in seconds). If set, the minimum configurable value for 'timeout'. * max_timeout: the watchdog timer's maximum timeout value (in seconds), @@ -121,6 +125,7 @@ struct watchdog_ops { int (*ping)(struct watchdog_device *); unsigned int (*status)(struct watchdog_device *); int (*set_timeout)(struct watchdog_device *, unsigned int); + int (*set_pretimeout)(struct watchdog_device *, unsigned int); unsigned int (*get_timeleft)(struct watchdog_device *); int (*restart)(struct watchdog_device *); void (*ref)(struct watchdog_device *) __deprecated; @@ -188,6 +193,23 @@ they are supported. These optional routines/operations are: If set_timeout is not provided but, WDIOF_SETTIMEOUT is set, the watchdog infrastructure updates the timeout value of the watchdog_device internally to the requested value. + If the pretimeout feature is used (WDIOF_PRETIMEOUT), then set_timeout must + also take care of checking if pretimeout is still valid and set up the timer + accordingly. This can't be done in the core without races, so it is the + duty of the driver. +* set_pretimeout: this routine checks and changes the pretimeout value of + the watchdog. It is optional because not all watchdogs support pretimeout + notification. The timeout value is not an absolute time, but the number of + seconds before the actual timeout would happen. It returns 0 on success, + -EINVAL for "parameter out of range" and -EIO for "could not write value to + the watchdog". A value of 0 disables pretimeout notification. + (Note: the WDIOF_PRETIMEOUT needs to be set in the options field of the + watchdog's info structure). + If the watchdog driver does not have to perform any action but setting the + watchdog_device.pretimeout, this callback can be omitted. That means if + set_pretimeout is not provided but WDIOF_PRETIMEOUT is set, the watchdog + infrastructure updates the pretimeout value of the watchdog_device internally + to the requested value. * get_timeleft: this routines returns the time that's left before a reset. * restart: this routine restarts the machine. It returns 0 on success or a negative errno code for failure. @@ -268,3 +290,14 @@ User should follow the following guidelines for setting the priority: * 128: default restart handler, use if no other handler is expected to be available, and/or if restart is sufficient to restart the entire system * 255: highest priority, will preempt all other restart handlers + +To raise a pretimeout notification, the following function should be used: + +void watchdog_notify_pretimeout(struct watchdog_device *wdd) + +The function can be called in the interrupt context. If watchdog pretimeout +governor framework (kbuild CONFIG_WATCHDOG_PRETIMEOUT_GOV symbol) is enabled, +an action is taken by a preconfigured pretimeout governor preassigned to +the watchdog device. If watchdog pretimeout governor framework is not +enabled, watchdog_notify_pretimeout() prints a notification message to +the kernel log buffer. diff --git a/MAINTAINERS b/MAINTAINERS index 5e925a25e77d..1fc66f0aceb5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4775,15 +4775,6 @@ L: iommu@lists.linux-foundation.org S: Maintained F: drivers/iommu/exynos-iommu.c -EXYNOS MIPI DISPLAY DRIVERS -M: Inki Dae -M: Donghwa Lee -M: Kyungmin Park -L: linux-fbdev@vger.kernel.org -S: Maintained -F: drivers/video/fbdev/exynos/exynos_mipi* -F: include/video/exynos_mipi* - EZchip NPS platform support M: Noam Camus S: Supported @@ -4962,12 +4953,9 @@ F: drivers/net/wan/dlci.c F: drivers/net/wan/sdla.c FRAMEBUFFER LAYER -M: Jean-Christophe Plagniol-Villard M: Tomi Valkeinen L: linux-fbdev@vger.kernel.org -W: http://linux-fbdev.sourceforge.net/ Q: http://patchwork.kernel.org/project/linux-fbdev/list/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/plagnioj/linux-fbdev.git S: Maintained F: Documentation/fb/ F: drivers/video/ @@ -9201,6 +9189,14 @@ S: Maintained F: Documentation/devicetree/bindings/pci/versatile.txt F: drivers/pci/host/pci-versatile.c +PCI DRIVER FOR ARMADA 8K +M: Thomas Petazzoni +L: linux-pci@vger.kernel.org +L: linux-arm-kernel@lists.infradead.org +S: Maintained +F: Documentation/devicetree/bindings/pci/pci-armada8k.txt +F: drivers/pci/host/pcie-armada8k.c + PCI DRIVER FOR APPLIEDMICRO XGENE M: Tanmay Inamdar L: linux-pci@vger.kernel.org @@ -9247,6 +9243,7 @@ M: Thomas Petazzoni L: linux-pci@vger.kernel.org L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained +F: Documentation/devicetree/bindings/pci/aardvark-pci.txt F: drivers/pci/host/pci-aardvark.c PCI DRIVER FOR NVIDIA TEGRA diff --git a/Makefile b/Makefile index addb235b537c..27f97b53e6eb 100644 --- a/Makefile +++ b/Makefile @@ -621,6 +621,7 @@ include arch/$(SRCARCH)/Makefile KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,) KBUILD_CFLAGS += $(call cc-disable-warning,maybe-uninitialized,) +KBUILD_CFLAGS += $(call cc-disable-warning,frame-address,) ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE KBUILD_CFLAGS += -Os diff --git a/arch/arm/boot/dts/tegra124-jetson-tk1.dts b/arch/arm/boot/dts/tegra124-jetson-tk1.dts index e52b82449a79..53994f9fbbcc 100644 --- a/arch/arm/boot/dts/tegra124-jetson-tk1.dts +++ b/arch/arm/boot/dts/tegra124-jetson-tk1.dts @@ -2045,44 +2045,32 @@ thermal-zones { cpu { trips { - trip { + cpu-shutdown-trip { temperature = <101000>; hysteresis = <0>; type = "critical"; }; }; - - cooling-maps { - /* There are currently no cooling maps because there are no cooling devices */ - }; }; mem { trips { - trip { + mem-shutdown-trip { temperature = <101000>; hysteresis = <0>; type = "critical"; }; }; - - cooling-maps { - /* There are currently no cooling maps because there are no cooling devices */ - }; }; gpu { trips { - trip { + gpu-shutdown-trip { temperature = <101000>; hysteresis = <0>; type = "critical"; }; }; - - cooling-maps { - /* There are currently no cooling maps because there are no cooling devices */ - }; }; }; }; diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi index ea340f9de448..187a36c6d0fc 100644 --- a/arch/arm/boot/dts/tegra124.dtsi +++ b/arch/arm/boot/dts/tegra124.dtsi @@ -851,7 +851,9 @@ soctherm: thermal-sensor@700e2000 { compatible = "nvidia,tegra124-soctherm"; - reg = <0x0 0x700e2000 0x0 0x1000>; + reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */ + 0x0 0x60006000 0x0 0x400>; /* CAR reg_base */ + reg-names = "soctherm-reg", "car-reg"; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_TSENSOR>, <&tegra_car TEGRA124_CLK_SOC_THERM>; @@ -859,6 +861,15 @@ resets = <&tegra_car 78>; reset-names = "soctherm"; #thermal-sensor-cells = <1>; + + throttle-cfgs { + throttle_heavy: heavy { + nvidia,priority = <100>; + nvidia,cpu-throt-percent = <85>; + + #cooling-cells = <2>; + }; + }; }; dfll: clock@70110000 { @@ -1154,6 +1165,26 @@ thermal-sensors = <&soctherm TEGRA124_SOCTHERM_SENSOR_CPU>; + + trips { + cpu-shutdown-trip { + temperature = <103000>; + hysteresis = <0>; + type = "critical"; + }; + cpu_throttle_trip: throttle-trip { + temperature = <100000>; + hysteresis = <1000>; + type = "hot"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_throttle_trip>; + cooling-device = <&throttle_heavy 1 1>; + }; + }; }; mem { @@ -1162,6 +1193,21 @@ thermal-sensors = <&soctherm TEGRA124_SOCTHERM_SENSOR_MEM>; + + trips { + mem-shutdown-trip { + temperature = <103000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + /* + * There are currently no cooling maps, + * because there are no cooling devices. + */ + }; }; gpu { @@ -1170,6 +1216,26 @@ thermal-sensors = <&soctherm TEGRA124_SOCTHERM_SENSOR_GPU>; + + trips { + gpu-shutdown-trip { + temperature = <101000>; + hysteresis = <0>; + type = "critical"; + }; + gpu_throttle_trip: throttle-trip { + temperature = <99000>; + hysteresis = <1000>; + type = "hot"; + }; + }; + + cooling-maps { + map0 { + trip = <&gpu_throttle_trip>; + cooling-device = <&throttle_heavy 1 1>; + }; + }; }; pllx { @@ -1178,6 +1244,21 @@ thermal-sensors = <&soctherm TEGRA124_SOCTHERM_SENSOR_PLLX>; + + trips { + pllx-shutdown-trip { + temperature = <103000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + /* + * There are currently no cooling maps, + * because there are no cooling devices. + */ + }; }; }; diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig index 4e484f406419..c58f6841f8aa 100644 --- a/arch/arm/configs/exynos_defconfig +++ b/arch/arm/configs/exynos_defconfig @@ -168,8 +168,6 @@ CONFIG_DRM_PANEL_SAMSUNG_LD9040=y CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=y CONFIG_DRM_NXP_PTN3460=y CONFIG_DRM_PARADE_PS8622=y -CONFIG_EXYNOS_VIDEO=y -CONFIG_EXYNOS_MIPI_DSI=y CONFIG_LCD_CLASS_DEVICE=y CONFIG_LCD_PLATFORM=y CONFIG_BACKLIGHT_PWM=y diff --git a/arch/arm/mm/fault.h b/arch/arm/mm/fault.h index 05ec5e0df32d..67532f242271 100644 --- a/arch/arm/mm/fault.h +++ b/arch/arm/mm/fault.h @@ -23,7 +23,6 @@ static inline int fsr_fs(unsigned int fsr) #endif void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs); -unsigned long search_exception_table(unsigned long addr); void early_abt_enable(void); #endif /* __ARCH_ARM_FAULT_H */ diff --git a/arch/arm64/boot/dts/nvidia/tegra132.dtsi b/arch/arm64/boot/dts/nvidia/tegra132.dtsi index 2013f8916084..3f3a46a4bd01 100644 --- a/arch/arm64/boot/dts/nvidia/tegra132.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra132.dtsi @@ -4,6 +4,7 @@ #include #include #include +#include / { compatible = "nvidia,tegra132", "nvidia,tegra124"; @@ -727,8 +728,10 @@ }; soctherm: thermal-sensor@700e2000 { - compatible = "nvidia,tegra124-soctherm"; - reg = <0x0 0x700e2000 0x0 0x1000>; + compatible = "nvidia,tegra132-soctherm"; + reg = <0x0 0x700e2000 0x0 0x600 /* 0: SOC_THERM reg_base */ + 0x0 0x70040000 0x0 0x200>; /* 2: CCROC reg_base */ + reg-names = "soctherm-reg", "ccroc-reg"; interrupts = ; clocks = <&tegra_car TEGRA124_CLK_TSENSOR>, <&tegra_car TEGRA124_CLK_SOC_THERM>; @@ -736,6 +739,118 @@ resets = <&tegra_car 78>; reset-names = "soctherm"; #thermal-sensor-cells = <1>; + + throttle-cfgs { + throttle_heavy: heavy { + nvidia,priority = <100>; + nvidia,cpu-throt-level = ; + + #cooling-cells = <2>; + }; + }; + }; + + thermal-zones { + cpu { + polling-delay-passive = <1000>; + polling-delay = <0>; + + thermal-sensors = + <&soctherm TEGRA124_SOCTHERM_SENSOR_CPU>; + + trips { + cpu_shutdown_trip { + temperature = <105000>; + hysteresis = <1000>; + type = "critical"; + }; + + cpu_throttle_trip: throttle-trip { + temperature = <102000>; + hysteresis = <1000>; + type = "hot"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_throttle_trip>; + cooling-device = <&throttle_heavy 1 1>; + }; + }; + }; + mem { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = + <&soctherm TEGRA124_SOCTHERM_SENSOR_MEM>; + + trips { + mem_shutdown_trip { + temperature = <101000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + + cooling-maps { + /* + * There are currently no cooling maps, + * because there are no cooling devices. + */ + }; + }; + gpu { + polling-delay-passive = <1000>; + polling-delay = <0>; + + thermal-sensors = + <&soctherm TEGRA124_SOCTHERM_SENSOR_GPU>; + + trips { + gpu_shutdown_trip { + temperature = <101000>; + hysteresis = <1000>; + type = "critical"; + }; + + gpu_throttle_trip: throttle-trip { + temperature = <99000>; + hysteresis = <1000>; + type = "hot"; + }; + }; + + cooling-maps { + map0 { + trip = <&gpu_throttle_trip>; + cooling-device = <&throttle_heavy 1 1>; + }; + }; + }; + pllx { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = + <&soctherm TEGRA124_SOCTHERM_SENSOR_PLLX>; + + trips { + pllx_shutdown_trip { + temperature = <105000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + + cooling-maps { + /* + * There are currently no cooling maps, + * because there are no cooling devices. + */ + }; + }; }; ahub@70300000 { diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi index f6739797150a..46045fe719da 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi @@ -3,6 +3,7 @@ #include #include #include +#include / { compatible = "nvidia,tegra210"; @@ -1159,4 +1160,130 @@ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; interrupt-parent = <&gic>; }; + + soctherm: thermal-sensor@700e2000 { + compatible = "nvidia,tegra210-soctherm"; + reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */ + 0x0 0x60006000 0x0 0x400>; /* CAR reg_base */ + reg-names = "soctherm-reg", "car-reg"; + interrupts = ; + clocks = <&tegra_car TEGRA210_CLK_TSENSOR>, + <&tegra_car TEGRA210_CLK_SOC_THERM>; + clock-names = "tsensor", "soctherm"; + resets = <&tegra_car 78>; + reset-names = "soctherm"; + #thermal-sensor-cells = <1>; + + throttle-cfgs { + throttle_heavy: heavy { + nvidia,priority = <100>; + nvidia,cpu-throt-percent = <85>; + + #cooling-cells = <2>; + }; + }; + }; + + thermal-zones { + cpu { + polling-delay-passive = <1000>; + polling-delay = <0>; + + thermal-sensors = + <&soctherm TEGRA124_SOCTHERM_SENSOR_CPU>; + + trips { + cpu-shutdown-trip { + temperature = <102500>; + hysteresis = <0>; + type = "critical"; + }; + + cpu_throttle_trip: throttle-trip { + temperature = <98500>; + hysteresis = <1000>; + type = "hot"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_throttle_trip>; + cooling-device = <&throttle_heavy 1 1>; + }; + }; + }; + mem { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = + <&soctherm TEGRA124_SOCTHERM_SENSOR_MEM>; + + trips { + mem-shutdown-trip { + temperature = <103000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + /* + * There are currently no cooling maps, + * because there are no cooling devices. + */ + }; + }; + gpu { + polling-delay-passive = <1000>; + polling-delay = <0>; + + thermal-sensors = + <&soctherm TEGRA124_SOCTHERM_SENSOR_GPU>; + + trips { + gpu-shutdown-trip { + temperature = <103000>; + hysteresis = <0>; + type = "critical"; + }; + + gpu_throttle_trip: throttle-trip { + temperature = <100000>; + hysteresis = <1000>; + type = "hot"; + }; + }; + + cooling-maps { + map0 { + trip = <&gpu_throttle_trip>; + cooling-device = <&throttle_heavy 1 1>; + }; + }; + }; + pllx { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = + <&soctherm TEGRA124_SOCTHERM_SENSOR_PLLX>; + + trips { + pllx-shutdown-trip { + temperature = <103000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + /* + * There are currently no cooling maps, + * because there are no cooling devices. + */ + }; + }; + }; }; diff --git a/arch/frv/include/asm/pgtable.h b/arch/frv/include/asm/pgtable.h index 07d7a7ef8bd5..a0513d463a1f 100644 --- a/arch/frv/include/asm/pgtable.h +++ b/arch/frv/include/asm/pgtable.h @@ -522,5 +522,6 @@ extern void __init pgtable_cache_init(void); #ifndef __ASSEMBLY__ extern void __init paging_init(void); #endif /* !__ASSEMBLY__ */ +#define HAVE_ARCH_UNMAPPED_AREA #endif /* _ASM_PGTABLE_H */ diff --git a/arch/frv/include/asm/segment.h b/arch/frv/include/asm/segment.h index 4377c89a57f5..2305142d4cf8 100644 --- a/arch/frv/include/asm/segment.h +++ b/arch/frv/include/asm/segment.h @@ -32,7 +32,6 @@ typedef struct { #define get_ds() (KERNEL_DS) #define get_fs() (__current_thread_info->addr_limit) #define segment_eq(a, b) ((a).seg == (b).seg) -#define __kernel_ds_p() segment_eq(get_fs(), KERNEL_DS) #define get_addr_limit() (get_fs().seg) #define set_fs(_x) \ diff --git a/arch/frv/include/asm/uaccess.h b/arch/frv/include/asm/uaccess.h index 87d9e34c5df8..c0f4057eab60 100644 --- a/arch/frv/include/asm/uaccess.h +++ b/arch/frv/include/asm/uaccess.h @@ -20,8 +20,6 @@ #include #include -#define HAVE_ARCH_UNMAPPED_AREA /* we decide where to put mmaps */ - #define __ptr(x) ((unsigned long __force *)(x)) #define VERIFY_READ 0 diff --git a/arch/m68k/include/asm/uaccess_no.h b/arch/m68k/include/asm/uaccess_no.h index 1bdf15263754..36deeb36503b 100644 --- a/arch/m68k/include/asm/uaccess_no.h +++ b/arch/m68k/include/asm/uaccess_no.h @@ -44,9 +44,6 @@ struct exception_table_entry unsigned long insn, fixup; }; -/* Returns 0 if exception not found and fixup otherwise. */ -extern unsigned long search_exception_table(unsigned long); - /* * These are the main single-value transfer routines. They automatically diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index 826676778094..253a67e275ad 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -71,9 +71,6 @@ struct exception_table_entry { unsigned long insn, fixup; }; -/* Returns 0 if exception not found and fixup otherwise. */ -extern unsigned long search_exception_table(unsigned long); - #ifndef CONFIG_MMU /* Check against bounds of physical memory */ diff --git a/arch/mips/include/asm/extable.h b/arch/mips/include/asm/extable.h new file mode 100644 index 000000000000..dce7a627a925 --- /dev/null +++ b/arch/mips/include/asm/extable.h @@ -0,0 +1,13 @@ +#ifndef _ASM_EXTABLE_H +#define _ASM_EXTABLE_H + +struct exception_table_entry +{ + unsigned long insn; + unsigned long nextinsn; +}; + +struct pt_regs; +extern int fixup_exception(struct pt_regs *regs); + +#endif diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h index 0aaf9a01ea50..702c273e67a9 100644 --- a/arch/mips/include/asm/module.h +++ b/arch/mips/include/asm/module.h @@ -3,7 +3,7 @@ #include #include -#include +#include struct mod_arch_specific { /* Data Bus Error exception tables */ diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h index 21a2aaba20d5..4daf839cd8a8 100644 --- a/arch/mips/include/asm/uaccess.h +++ b/arch/mips/include/asm/uaccess.h @@ -16,6 +16,7 @@ #include #include #include +#include /* * The fs value determines whether argument validity checking should be @@ -1485,12 +1486,4 @@ static inline long strnlen_user(const char __user *s, long n) return res; } -struct exception_table_entry -{ - unsigned long insn; - unsigned long nextinsn; -}; - -extern int fixup_exception(struct pt_regs *regs); - #endif /* _ASM_UACCESS_H */ diff --git a/arch/mips/lasat/picvue_proc.c b/arch/mips/lasat/picvue_proc.c index 27533c109f92..dd292dcec684 100644 --- a/arch/mips/lasat/picvue_proc.c +++ b/arch/mips/lasat/picvue_proc.c @@ -16,6 +16,7 @@ #include #include +#include #include "picvue.h" diff --git a/arch/mn10300/include/asm/processor.h b/arch/mn10300/include/asm/processor.h index 769d5ed8e992..b10ba121c849 100644 --- a/arch/mn10300/include/asm/processor.h +++ b/arch/mn10300/include/asm/processor.h @@ -18,7 +18,6 @@ #include #include #include -#include #include /* Forward declaration, a strange C thing */ diff --git a/arch/mn10300/include/asm/uaccess.h b/arch/mn10300/include/asm/uaccess.h index d012e877a95a..2eedf6f46a57 100644 --- a/arch/mn10300/include/asm/uaccess.h +++ b/arch/mn10300/include/asm/uaccess.h @@ -38,7 +38,6 @@ #define get_ds() (KERNEL_DS) #define get_fs() (current_thread_info()->addr_limit) #define set_fs(x) (current_thread_info()->addr_limit = (x)) -#define __kernel_ds_p() (current_thread_info()->addr_limit.seg == 0x9FFFFFFF) #define segment_eq(a, b) ((a).seg == (b).seg) @@ -72,12 +71,6 @@ static inline int ___range_ok(unsigned long addr, unsigned int size) #define access_ok(type, addr, size) (__range_ok((addr), (size)) == 0) #define __access_ok(addr, size) (__range_ok((addr), (size)) == 0) -static inline int verify_area(int type, const void *addr, unsigned long size) -{ - return access_ok(type, addr, size) ? 0 : -EFAULT; -} - - /* * The exception table consists of pairs of addresses: the first is the * address of an instruction that is allowed to fault, and the second is diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c index dfd0301cf200..cd8cb1d1176b 100644 --- a/arch/mn10300/kernel/signal.c +++ b/arch/mn10300/kernel/signal.c @@ -75,7 +75,7 @@ static int restore_sigcontext(struct pt_regs *regs, struct fpucontext *buf; err |= __get_user(buf, &sc->fpucontext); if (buf) { - if (verify_area(VERIFY_READ, buf, sizeof(*buf))) + if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) goto badframe; err |= fpu_restore_sigcontext(buf); } @@ -98,7 +98,7 @@ asmlinkage long sys_sigreturn(void) long d0; frame = (struct sigframe __user *) current_frame()->sp; - if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; if (__get_user(set.sig[0], &frame->sc.oldmask)) goto badframe; @@ -130,7 +130,7 @@ asmlinkage long sys_rt_sigreturn(void) long d0; frame = (struct rt_sigframe __user *) current_frame()->sp; - if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; diff --git a/arch/openrisc/include/asm/uaccess.h b/arch/openrisc/include/asm/uaccess.h index 5cc6b4f1b795..140faa16685a 100644 --- a/arch/openrisc/include/asm/uaccess.h +++ b/arch/openrisc/include/asm/uaccess.h @@ -82,10 +82,6 @@ struct exception_table_entry { unsigned long insn, fixup; }; -/* Returns 0 if exception not found and fixup otherwise. */ -extern unsigned long search_exception_table(unsigned long); -extern void sort_exception_table(void); - /* * These are the main single-value transfer routines. They automatically * use the right size if we just have the right pointer type. diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h index e44bdb9078a5..c2c43f714684 100644 --- a/arch/parisc/include/asm/pgtable.h +++ b/arch/parisc/include/asm/pgtable.h @@ -83,10 +83,10 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr) printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, (unsigned long)pgd_val(e)) /* This is the size of the initially mapped kernel memory */ -#if defined(CONFIG_64BIT) || defined(CONFIG_SMP) -#define KERNEL_INITIAL_ORDER 25 /* 1<<25 = 32MB */ +#if defined(CONFIG_64BIT) +#define KERNEL_INITIAL_ORDER 26 /* 1<<26 = 64MB */ #else -#define KERNEL_INITIAL_ORDER 24 /* 1<<24 = 16MB */ +#define KERNEL_INITIAL_ORDER 25 /* 1<<25 = 32MB */ #endif #define KERNEL_INITIAL_SIZE (1 << KERNEL_INITIAL_ORDER) diff --git a/arch/parisc/include/asm/traps.h b/arch/parisc/include/asm/traps.h index 5e953ab4530d..63670231f48a 100644 --- a/arch/parisc/include/asm/traps.h +++ b/arch/parisc/include/asm/traps.h @@ -11,6 +11,7 @@ void parisc_terminate(char *msg, struct pt_regs *regs, void die_if_kernel(char *str, struct pt_regs *regs, long err); /* mm/fault.c */ +const char *trap_name(unsigned long code); void do_page_fault(struct pt_regs *regs, unsigned long code, unsigned long address); #endif diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index 97d6b208e129..378df9207406 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -458,8 +458,8 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o } printk("\n"); - printk(KERN_CRIT "%s: Code=%d regs=%p (Addr=" RFMT ")\n", - msg, code, regs, offset); + pr_crit("%s: Code=%d (%s) regs=%p (Addr=" RFMT ")\n", + msg, code, trap_name(code), regs, offset); show_regs(regs); spin_unlock(&terminate_lock); diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index b37787dbe775..3d6ef1b29c6a 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -90,8 +90,9 @@ SECTIONS /* Start of data section */ _sdata = .; - RO_DATA_SECTION(8) - + /* Architecturally we need to keep __gp below 0x1000000 and thus + * in front of RO_DATA_SECTION() which stores lots of tracepoint + * and ftrace symbols. */ #ifdef CONFIG_64BIT . = ALIGN(16); /* Linkage tables */ @@ -106,6 +107,12 @@ SECTIONS } #endif + RO_DATA_SECTION(8) + + /* RO because of BUILDTIME_EXTABLE_SORT */ + EXCEPTION_TABLE(8) + NOTES + /* unwind info */ .PARISC.unwind : { __start___unwind = .; @@ -121,9 +128,6 @@ SECTIONS . = ALIGN(HUGEPAGE_SIZE); data_start = .; - EXCEPTION_TABLE(8) - NOTES - /* Data */ RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, PAGE_SIZE) diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index 47a6ca4c9e40..8ff9253930af 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include @@ -204,6 +204,16 @@ static const char * const trap_description[] = { [28] "Unaligned data reference trap", }; +const char *trap_name(unsigned long code) +{ + const char *t = NULL; + + if (code < ARRAY_SIZE(trap_description)) + t = trap_description[code]; + + return t ? t : "Unknown trap"; +} + /* * Print out info about fatal segfaults, if the show_unhandled_signals * sysctl is set: @@ -213,8 +223,6 @@ show_signal_msg(struct pt_regs *regs, unsigned long code, unsigned long address, struct task_struct *tsk, struct vm_area_struct *vma) { - const char *trap_name = NULL; - if (!unhandled_signal(tsk, SIGSEGV)) return; @@ -226,10 +234,7 @@ show_signal_msg(struct pt_regs *regs, unsigned long code, tsk->comm, code, address); print_vma_addr(KERN_CONT " in ", regs->iaoq[0]); - if (code < ARRAY_SIZE(trap_description)) - trap_name = trap_description[code]; - pr_warn(KERN_CONT " trap #%lu: %s%c", code, - trap_name ? trap_name : "unknown", + pr_cont(" trap #%lu: %s%c", code, trap_name(code), vma ? ',':'\n'); if (vma) diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index 356f38473b5d..e02ada312be8 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c @@ -105,6 +105,8 @@ static void * __init get_memblock(unsigned long size) else panic("get_memblock() failed.\n"); + memset(__va(phys), 0, size); + return __va(phys); } diff --git a/arch/score/include/asm/extable.h b/arch/score/include/asm/extable.h new file mode 100644 index 000000000000..c4423ccf830d --- /dev/null +++ b/arch/score/include/asm/extable.h @@ -0,0 +1,11 @@ +#ifndef _ASM_SCORE_EXTABLE_H +#define _ASM_SCORE_EXTABLE_H + +struct exception_table_entry { + unsigned long insn; + unsigned long fixup; +}; + +struct pt_regs; +extern int fixup_exception(struct pt_regs *regs); +#endif diff --git a/arch/score/include/asm/module.h b/arch/score/include/asm/module.h index abf395bbfaba..6dc1f2935eef 100644 --- a/arch/score/include/asm/module.h +++ b/arch/score/include/asm/module.h @@ -2,7 +2,7 @@ #define _ASM_SCORE_MODULE_H #include -#include +#include #include struct mod_arch_specific { diff --git a/arch/score/include/asm/uaccess.h b/arch/score/include/asm/uaccess.h index 01aec8ccde83..db58ab98ec4b 100644 --- a/arch/score/include/asm/uaccess.h +++ b/arch/score/include/asm/uaccess.h @@ -4,6 +4,7 @@ #include #include #include +#include #define VERIFY_READ 0 #define VERIFY_WRITE 1 @@ -420,12 +421,5 @@ static inline long strnlen_user(const char __user *str, long len) return __strnlen_user(str, len); } -struct exception_table_entry { - unsigned long insn; - unsigned long fixup; -}; - -extern int fixup_exception(struct pt_regs *regs); - #endif /* __SCORE_UACCESS_H */ diff --git a/arch/sh/include/asm/uaccess.h b/arch/sh/include/asm/uaccess.h index 92ade79ac427..a38d0c7b818f 100644 --- a/arch/sh/include/asm/uaccess.h +++ b/arch/sh/include/asm/uaccess.h @@ -192,8 +192,6 @@ struct exception_table_entry { #endif int fixup_exception(struct pt_regs *regs); -/* Returns 0 if exception not found and fixup.unit otherwise. */ -unsigned long search_exception_table(unsigned long addr); const struct exception_table_entry *search_exception_tables(unsigned long addr); extern void *set_exception_table_vec(unsigned int vec, void *handler); diff --git a/arch/sparc/include/asm/elf_64.h b/arch/sparc/include/asm/elf_64.h index 93310837c2df..3f2d403873bd 100644 --- a/arch/sparc/include/asm/elf_64.h +++ b/arch/sparc/include/asm/elf_64.h @@ -7,7 +7,7 @@ #include #include -#include +#include #include /* diff --git a/arch/sparc/include/asm/extable_64.h b/arch/sparc/include/asm/extable_64.h new file mode 100644 index 000000000000..1121cb056ffb --- /dev/null +++ b/arch/sparc/include/asm/extable_64.h @@ -0,0 +1,20 @@ +#ifndef __ASM_EXTABLE64_H +#define __ASM_EXTABLE64_H +/* + * The exception table consists of pairs of addresses: the first is the + * address of an instruction that is allowed to fault, and the second is + * the address at which the program should continue. No registers are + * modified, so it is entirely up to the continuation code to figure out + * what to do. + * + * All the routines below use bits of fixup code that are out of line + * with the main instruction path. This means when everything is well, + * we don't even have to jump over them. Further, they do not intrude + * on our cache or tlb entries. + */ + +struct exception_table_entry { + unsigned int insn, fixup; +}; + +#endif diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h index 37a315d0ddd4..b68acc563235 100644 --- a/arch/sparc/include/asm/uaccess_64.h +++ b/arch/sparc/include/asm/uaccess_64.h @@ -13,6 +13,7 @@ #include #include #include +#include #endif #ifndef __ASSEMBLY__ @@ -81,23 +82,6 @@ static inline int access_ok(int type, const void __user * addr, unsigned long si return 1; } -/* - * The exception table consists of pairs of addresses: the first is the - * address of an instruction that is allowed to fault, and the second is - * the address at which the program should continue. No registers are - * modified, so it is entirely up to the continuation code to figure out - * what to do. - * - * All the routines below use bits of fixup code that are out of line - * with the main instruction path. This means when everything is well, - * we don't even have to jump over them. Further, they do not intrude - * on our cache or tlb entries. - */ - -struct exception_table_entry { - unsigned int insn, fixup; -}; - void __ret_efault(void); void __retl_efault(void); diff --git a/arch/x86/include/asm/cacheflush.h b/arch/x86/include/asm/cacheflush.h index 61518cf79437..872877d930de 100644 --- a/arch/x86/include/asm/cacheflush.h +++ b/arch/x86/include/asm/cacheflush.h @@ -4,7 +4,6 @@ /* Caches aren't brain-dead on the intel. */ #include #include -#include /* * The set_memory_* API can be used to change various attributes of a virtual diff --git a/arch/x86/include/asm/extable.h b/arch/x86/include/asm/extable.h new file mode 100644 index 000000000000..b8ad261d11dc --- /dev/null +++ b/arch/x86/include/asm/extable.h @@ -0,0 +1,35 @@ +#ifndef _ASM_X86_EXTABLE_H +#define _ASM_X86_EXTABLE_H +/* + * The exception table consists of triples of addresses relative to the + * exception table entry itself. The first address is of an instruction + * that is allowed to fault, the second is the target at which the program + * should continue. The third is a handler function to deal with the fault + * caused by the instruction in the first field. + * + * All the routines below use bits of fixup code that are out of line + * with the main instruction path. This means when everything is well, + * we don't even have to jump over them. Further, they do not intrude + * on our cache or tlb entries. + */ + +struct exception_table_entry { + int insn, fixup, handler; +}; +struct pt_regs; + +#define ARCH_HAS_RELATIVE_EXTABLE + +#define swap_ex_entry_fixup(a, b, tmp, delta) \ + do { \ + (a)->fixup = (b)->fixup + (delta); \ + (b)->fixup = (tmp).fixup - (delta); \ + (a)->handler = (b)->handler + (delta); \ + (b)->handler = (tmp).handler - (delta); \ + } while (0) + +extern int fixup_exception(struct pt_regs *regs, int trapnr); +extern bool ex_has_fault_handler(unsigned long ip); +extern void early_fixup_exception(struct pt_regs *regs, int trapnr); + +#endif diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h index 13b6cdd0af57..2f75f30cb2f6 100644 --- a/arch/x86/include/asm/sections.h +++ b/arch/x86/include/asm/sections.h @@ -2,7 +2,7 @@ #define _ASM_X86_SECTIONS_H #include -#include +#include extern char __brk_base[], __brk_limit[]; extern struct exception_table_entry __stop___ex_table[]; diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 2131c4ce7d8a..faf3687f1035 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -11,6 +11,7 @@ #include #include #include +#include #define VERIFY_READ 0 #define VERIFY_WRITE 1 @@ -90,37 +91,6 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un #define access_ok(type, addr, size) \ likely(!__range_not_ok(addr, size, user_addr_max())) -/* - * The exception table consists of triples of addresses relative to the - * exception table entry itself. The first address is of an instruction - * that is allowed to fault, the second is the target at which the program - * should continue. The third is a handler function to deal with the fault - * caused by the instruction in the first field. - * - * All the routines below use bits of fixup code that are out of line - * with the main instruction path. This means when everything is well, - * we don't even have to jump over them. Further, they do not intrude - * on our cache or tlb entries. - */ - -struct exception_table_entry { - int insn, fixup, handler; -}; - -#define ARCH_HAS_RELATIVE_EXTABLE - -#define swap_ex_entry_fixup(a, b, tmp, delta) \ - do { \ - (a)->fixup = (b)->fixup + (delta); \ - (b)->fixup = (tmp).fixup - (delta); \ - (a)->handler = (b)->handler + (delta); \ - (b)->handler = (tmp).handler - (delta); \ - } while (0) - -extern int fixup_exception(struct pt_regs *regs, int trapnr); -extern bool ex_has_fault_handler(unsigned long ip); -extern void early_fixup_exception(struct pt_regs *regs, int trapnr); - /* * These are the main single-value transfer routines. They automatically * use the right size if we just have the right pointer type. diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 4dc13340653e..9f72ca3b2669 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -5,7 +5,7 @@ */ #include /* test_thread_flag(), ... */ #include /* oops_begin/end, ... */ -#include /* search_exception_table */ +#include /* search_exception_tables */ #include /* max_low_pfn */ #include /* NOKPROBE_SYMBOL, ... */ #include /* kmmio_handler, ... */ diff --git a/arch/xtensa/include/asm/asm-uaccess.h b/arch/xtensa/include/asm/asm-uaccess.h new file mode 100644 index 000000000000..a7a110039786 --- /dev/null +++ b/arch/xtensa/include/asm/asm-uaccess.h @@ -0,0 +1,160 @@ +/* + * include/asm-xtensa/uaccess.h + * + * User space memory access functions + * + * These routines provide basic accessing functions to the user memory + * space for the kernel. This header file provides functions such as: + * + * 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. + * + * Copyright (C) 2001 - 2005 Tensilica Inc. + */ + +#ifndef _XTENSA_ASM_UACCESS_H +#define _XTENSA_ASM_UACCESS_H + +#include +#include + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +#include +#include +#include + +/* + * These assembly macros mirror the C macros in asm/uaccess.h. They + * should always have identical functionality. See + * arch/xtensa/kernel/sys.S for usage. + */ + +#define KERNEL_DS 0 +#define USER_DS 1 + +#define get_ds (KERNEL_DS) + +/* + * get_fs reads current->thread.current_ds into a register. + * On Entry: + * anything + * stack + * On Exit: + * contains current->thread.current_ds + */ + .macro get_fs ad, sp + GET_CURRENT(\ad,\sp) +#if THREAD_CURRENT_DS > 1020 + addi \ad, \ad, TASK_THREAD + l32i \ad, \ad, THREAD_CURRENT_DS - TASK_THREAD +#else + l32i \ad, \ad, THREAD_CURRENT_DS +#endif + .endm + +/* + * set_fs sets current->thread.current_ds to some value. + * On Entry: + * anything (temp register) + * value to write + * stack + * On Exit: + * destroyed (actually, current) + * preserved, value to write + */ + .macro set_fs at, av, sp + GET_CURRENT(\at,\sp) + s32i \av, \at, THREAD_CURRENT_DS + .endm + +/* + * kernel_ok determines whether we should bypass addr/size checking. + * See the equivalent C-macro version below for clarity. + * On success, kernel_ok branches to a label indicated by parameter + * . This implies that the macro falls through to the next + * insruction on an error. + * + * Note that while this macro can be used independently, we designed + * in for optimal use in the access_ok macro below (i.e., we fall + * through on error). + * + * On Entry: + * anything (temp register) + * label to branch to on success; implies + * fall-through macro on error + * stack pointer + * On Exit: + * destroyed (actually, current->thread.current_ds) + */ + +#if ((KERNEL_DS != 0) || (USER_DS == 0)) +# error Assembly macro kernel_ok fails +#endif + .macro kernel_ok at, sp, success + get_fs \at, \sp + beqz \at, \success + .endm + +/* + * user_ok determines whether the access to user-space memory is allowed. + * See the equivalent C-macro version below for clarity. + * + * On error, user_ok branches to a label indicated by parameter + * . This implies that the macro falls through to the next + * instruction on success. + * + * Note that while this macro can be used independently, we designed + * in for optimal use in the access_ok macro below (i.e., we fall + * through on success). + * + * On Entry: + * register containing memory address + * register containing memory size + * temp register + * label to branch to on error; implies fall-through + * macro on success + * On Exit: + * preserved + * preserved + * destroyed (actually, (TASK_SIZE + 1 - size)) + */ + .macro user_ok aa, as, at, error + movi \at, __XTENSA_UL_CONST(TASK_SIZE) + bgeu \as, \at, \error + sub \at, \at, \as + bgeu \aa, \at, \error + .endm + +/* + * access_ok determines whether a memory access is allowed. See the + * equivalent C-macro version below for clarity. + * + * On error, access_ok branches to a label indicated by parameter + * . This implies that the macro falls through to the next + * instruction on success. + * + * Note that we assume success is the common case, and we optimize the + * branch fall-through case on success. + * + * On Entry: + * register containing memory address + * register containing memory size + * temp register + * + * label to branch to on error; implies fall-through + * macro on success + * On Exit: + * preserved + * preserved + * destroyed + */ + .macro access_ok aa, as, at, sp, error + kernel_ok \at, \sp, .Laccess_ok_\@ + user_ok \aa, \as, \at, \error +.Laccess_ok_\@: + .endm + +#endif /* _XTENSA_ASM_UACCESS_H */ diff --git a/arch/xtensa/include/asm/uaccess.h b/arch/xtensa/include/asm/uaccess.h index 147b26ed9c91..848a3d736bcb 100644 --- a/arch/xtensa/include/asm/uaccess.h +++ b/arch/xtensa/include/asm/uaccess.h @@ -17,153 +17,12 @@ #define _XTENSA_UACCESS_H #include -#ifndef __ASSEMBLY__ #include -#endif #include #define VERIFY_READ 0 #define VERIFY_WRITE 1 -#ifdef __ASSEMBLY__ - -#include -#include -#include - -/* - * These assembly macros mirror the C macros that follow below. They - * should always have identical functionality. See - * arch/xtensa/kernel/sys.S for usage. - */ - -#define KERNEL_DS 0 -#define USER_DS 1 - -#define get_ds (KERNEL_DS) - -/* - * get_fs reads current->thread.current_ds into a register. - * On Entry: - * anything - * stack - * On Exit: - * contains current->thread.current_ds - */ - .macro get_fs ad, sp - GET_CURRENT(\ad,\sp) -#if THREAD_CURRENT_DS > 1020 - addi \ad, \ad, TASK_THREAD - l32i \ad, \ad, THREAD_CURRENT_DS - TASK_THREAD -#else - l32i \ad, \ad, THREAD_CURRENT_DS -#endif - .endm - -/* - * set_fs sets current->thread.current_ds to some value. - * On Entry: - * anything (temp register) - * value to write - * stack - * On Exit: - * destroyed (actually, current) - * preserved, value to write - */ - .macro set_fs at, av, sp - GET_CURRENT(\at,\sp) - s32i \av, \at, THREAD_CURRENT_DS - .endm - -/* - * kernel_ok determines whether we should bypass addr/size checking. - * See the equivalent C-macro version below for clarity. - * On success, kernel_ok branches to a label indicated by parameter - * . This implies that the macro falls through to the next - * insruction on an error. - * - * Note that while this macro can be used independently, we designed - * in for optimal use in the access_ok macro below (i.e., we fall - * through on error). - * - * On Entry: - * anything (temp register) - * label to branch to on success; implies - * fall-through macro on error - * stack pointer - * On Exit: - * destroyed (actually, current->thread.current_ds) - */ - -#if ((KERNEL_DS != 0) || (USER_DS == 0)) -# error Assembly macro kernel_ok fails -#endif - .macro kernel_ok at, sp, success - get_fs \at, \sp - beqz \at, \success - .endm - -/* - * user_ok determines whether the access to user-space memory is allowed. - * See the equivalent C-macro version below for clarity. - * - * On error, user_ok branches to a label indicated by parameter - * . This implies that the macro falls through to the next - * instruction on success. - * - * Note that while this macro can be used independently, we designed - * in for optimal use in the access_ok macro below (i.e., we fall - * through on success). - * - * On Entry: - * register containing memory address - * register containing memory size - * temp register - * label to branch to on error; implies fall-through - * macro on success - * On Exit: - * preserved - * preserved - * destroyed (actually, (TASK_SIZE + 1 - size)) - */ - .macro user_ok aa, as, at, error - movi \at, __XTENSA_UL_CONST(TASK_SIZE) - bgeu \as, \at, \error - sub \at, \at, \as - bgeu \aa, \at, \error - .endm - -/* - * access_ok determines whether a memory access is allowed. See the - * equivalent C-macro version below for clarity. - * - * On error, access_ok branches to a label indicated by parameter - * . This implies that the macro falls through to the next - * instruction on success. - * - * Note that we assume success is the common case, and we optimize the - * branch fall-through case on success. - * - * On Entry: - * register containing memory address - * register containing memory size - * temp register - * - * label to branch to on error; implies fall-through - * macro on success - * On Exit: - * preserved - * preserved - * destroyed - */ - .macro access_ok aa, as, at, sp, error - kernel_ok \at, \sp, .Laccess_ok_\@ - user_ok \aa, \as, \at, \error -.Laccess_ok_\@: - .endm - -#else /* __ASSEMBLY__ not defined */ - #include /* @@ -495,16 +354,4 @@ struct exception_table_entry unsigned long insn, fixup; }; -/* Returns 0 if exception not found and fixup.unit otherwise. */ - -extern unsigned long search_exception_table(unsigned long addr); -extern void sort_exception_table(void); - -/* Returns the new pc */ -#define fixup_exception(map_reg, fixup_unit, pc) \ -({ \ - fixup_unit; \ -}) - -#endif /* __ASSEMBLY__ */ #endif /* _XTENSA_UACCESS_H */ diff --git a/arch/xtensa/kernel/coprocessor.S b/arch/xtensa/kernel/coprocessor.S index a482df5df2b2..6911e384f608 100644 --- a/arch/xtensa/kernel/coprocessor.S +++ b/arch/xtensa/kernel/coprocessor.S @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index fa04d9d368a7..f5ef3cc0497c 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index f4ebe39539af..35e8fbca10ad 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -520,7 +520,8 @@ static void acpi_thermal_check(void *data) if (!tz->tz_enabled) return; - thermal_zone_device_update(tz->thermal_zone); + thermal_zone_device_update(tz->thermal_zone, + THERMAL_EVENT_UNSPECIFIED); } /* sys I/F for generic thermal sysfs support */ diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c index 480a777db577..7c19d9b22785 100644 --- a/drivers/char/tb0219.c +++ b/drivers/char/tb0219.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 3f31ca32f52b..5fa36ebc0640 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -471,9 +471,9 @@ static int bond_check_dev_link(struct bonding *bond, /* Yes, the mii is overlaid on the ifreq.ifr_ifru */ strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ); mii = if_mii(&ifr); - if (IOCTL(slave_dev, &ifr, SIOCGMIIPHY) == 0) { + if (ioctl(slave_dev, &ifr, SIOCGMIIPHY) == 0) { mii->reg_num = MII_BMSR; - if (IOCTL(slave_dev, &ifr, SIOCGMIIREG) == 0) + if (ioctl(slave_dev, &ifr, SIOCGMIIREG) == 0) return mii->val_out & BMSR_LSTATUS; } } diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c index bddb198c0b74..380a64115a98 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c @@ -693,7 +693,7 @@ static int cn23xx_enable_io_queues(struct octeon_device *oct) while ((reg_val & CN23XX_PKT_INPUT_CTL_RST) && !(reg_val & CN23XX_PKT_INPUT_CTL_QUIET) && - loop--) { + --loop) { reg_val = octeon_read_csr64( oct, CN23XX_SLI_IQ_PKT_CONTROL64(q_no)); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c index d4585154151d..cc4fd61914d3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c @@ -287,7 +287,7 @@ retry: goto retry; } - MLX5_SET64(manage_pages_in, in, pas[i], addr); + MLX5_ARRAY_SET64(manage_pages_in, in, pas, i, addr); } MLX5_SET(manage_pages_in, in, opcode, MLX5_CMD_OP_MANAGE_PAGES); @@ -344,7 +344,7 @@ static int reclaim_pages_cmd(struct mlx5_core_dev *dev, if (fwp->func_id != func_id) continue; - MLX5_SET64(manage_pages_out, out, pas[i], fwp->addr); + MLX5_ARRAY_SET64(manage_pages_out, out, pas, i, fwp->addr); i++; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index a6db10717d5c..02a8be2faed7 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -1517,7 +1517,7 @@ static void qed_ll2_register_cb_ops(struct qed_dev *cdev, static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params) { struct qed_ll2_info ll2_info; - struct qed_ll2_buffer *buffer; + struct qed_ll2_buffer *buffer, *tmp_buffer; enum qed_ll2_conn_type conn_type; struct qed_ptt *p_ptt; int rc, i; @@ -1587,7 +1587,7 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params) /* Post all Rx buffers to FW */ spin_lock_bh(&cdev->ll2->lock); - list_for_each_entry(buffer, &cdev->ll2->list, list) { + list_for_each_entry_safe(buffer, tmp_buffer, &cdev->ll2->list, list) { rc = qed_ll2_post_rx_buffer(QED_LEADING_HWFN(cdev), cdev->ll2->handle, buffer->phys_addr, 0, buffer, 1); diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index 23430059471c..76831a398bed 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -2947,7 +2947,7 @@ static const struct qed_rdma_ops qed_rdma_ops_pass = { .roce_ll2_stats = &qed_roce_ll2_stats, }; -const struct qed_rdma_ops *qed_get_rdma_ops() +const struct qed_rdma_ops *qed_get_rdma_ops(void) { return &qed_rdma_ops_pass; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 1a06c87e3935..da0b80a1917a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -652,20 +652,27 @@ static int stmmac_init_ptp(struct stmmac_priv *priv) if (IS_ERR(priv->clk_ptp_ref)) { priv->clk_ptp_rate = clk_get_rate(priv->stmmac_clk); priv->clk_ptp_ref = NULL; + netdev_dbg(priv->dev, "PTP uses main clock\n"); } else { clk_prepare_enable(priv->clk_ptp_ref); priv->clk_ptp_rate = clk_get_rate(priv->clk_ptp_ref); + netdev_dbg(priv->dev, "PTP rate %d\n", priv->clk_ptp_rate); } priv->adv_ts = 0; - if (priv->dma_cap.atime_stamp && priv->extend_desc) + /* Check if adv_ts can be enabled for dwmac 4.x core */ + if (priv->plat->has_gmac4 && priv->dma_cap.atime_stamp) + priv->adv_ts = 1; + /* Dwmac 3.x core with extend_desc can support adv_ts */ + else if (priv->extend_desc && priv->dma_cap.atime_stamp) priv->adv_ts = 1; - if (netif_msg_hw(priv) && priv->dma_cap.time_stamp) - pr_debug("IEEE 1588-2002 Time Stamp supported\n"); + if (priv->dma_cap.time_stamp) + netdev_info(priv->dev, "IEEE 1588-2002 Timestamp supported\n"); - if (netif_msg_hw(priv) && priv->adv_ts) - pr_debug("IEEE 1588-2008 Advanced Time Stamp supported\n"); + if (priv->adv_ts) + netdev_info(priv->dev, + "IEEE 1588-2008 Advanced Timestamp supported\n"); priv->hw->ptp = &stmmac_ptp; priv->hwts_tx_en = 0; @@ -1702,8 +1709,8 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) if (init_ptp) { ret = stmmac_init_ptp(priv); - if (ret && ret != -EOPNOTSUPP) - pr_warn("%s: failed PTP initialisation\n", __func__); + if (ret) + netdev_warn(priv->dev, "PTP support cannot init.\n"); } #ifdef CONFIG_DEBUG_FS diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c index 6e3b82972ce8..289d52725a6c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c @@ -186,10 +186,12 @@ int stmmac_ptp_register(struct stmmac_priv *priv) priv->device); if (IS_ERR(priv->ptp_clock)) { priv->ptp_clock = NULL; - pr_err("ptp_clock_register() failed on %s\n", priv->dev->name); - } else if (priv->ptp_clock) - pr_debug("Added PTP HW clock successfully on %s\n", - priv->dev->name); + return PTR_ERR(priv->ptp_clock); + } + + spin_lock_init(&priv->ptp_lock); + + netdev_dbg(priv->dev, "Added PTP HW clock successfully\n"); return 0; } diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index 4a3eeb10d45b..c8d53d8c83ee 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -610,8 +610,8 @@ err_out_regions: #ifdef CONFIG_PCI if (pdev) pci_release_regions(pdev); -#endif err_out: +#endif if (pdev) pci_disable_device(pdev); return rc; diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 35f9f9742a48..c688d68c39aa 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -431,8 +431,7 @@ static void axienet_setoptions(struct net_device *ndev, u32 options) lp->options |= options; } -static void __axienet_device_reset(struct axienet_local *lp, - struct device *dev, off_t offset) +static void __axienet_device_reset(struct axienet_local *lp, off_t offset) { u32 timeout; /* Reset Axi DMA. This would reset Axi Ethernet core as well. The reset @@ -468,8 +467,8 @@ static void axienet_device_reset(struct net_device *ndev) u32 axienet_status; struct axienet_local *lp = netdev_priv(ndev); - __axienet_device_reset(lp, &ndev->dev, XAXIDMA_TX_CR_OFFSET); - __axienet_device_reset(lp, &ndev->dev, XAXIDMA_RX_CR_OFFSET); + __axienet_device_reset(lp, XAXIDMA_TX_CR_OFFSET); + __axienet_device_reset(lp, XAXIDMA_RX_CR_OFFSET); lp->max_frm_size = XAE_MAX_VLAN_FRAME_SIZE; lp->options |= XAE_OPTION_VLAN; @@ -1338,8 +1337,8 @@ static void axienet_dma_err_handler(unsigned long data) axienet_iow(lp, XAE_MDIO_MC_OFFSET, (mdio_mcreg & ~XAE_MDIO_MC_MDIOEN_MASK)); - __axienet_device_reset(lp, &ndev->dev, XAXIDMA_TX_CR_OFFSET); - __axienet_device_reset(lp, &ndev->dev, XAXIDMA_RX_CR_OFFSET); + __axienet_device_reset(lp, XAXIDMA_TX_CR_OFFSET); + __axienet_device_reset(lp, XAXIDMA_RX_CR_OFFSET); axienet_iow(lp, XAE_MDIO_MC_OFFSET, mdio_mcreg); axienet_mdio_wait_until_ready(lp); diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 52eeb2f67276..f0919bd3a563 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -442,8 +442,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) } net_trans_info = get_net_transport_info(skb, &hdr_offset); - if (net_trans_info == TRANSPORT_INFO_NOT_IP) - goto do_send; /* * Setup the sendside checksum offload only if this is not a @@ -478,56 +476,29 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) } lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset; lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size; - goto do_send; + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + if (net_trans_info & INFO_TCP) { + rndis_msg_size += NDIS_CSUM_PPI_SIZE; + ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE, + TCPIP_CHKSUM_PKTINFO); + + csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi + + ppi->ppi_offset); + + if (net_trans_info & (INFO_IPV4 << 16)) + csum_info->transmit.is_ipv4 = 1; + else + csum_info->transmit.is_ipv6 = 1; + + csum_info->transmit.tcp_checksum = 1; + csum_info->transmit.tcp_header_offset = hdr_offset; + } else { + /* UDP checksum (and other) offload is not supported. */ + if (skb_checksum_help(skb)) + goto drop; + } } - if ((skb->ip_summed == CHECKSUM_NONE) || - (skb->ip_summed == CHECKSUM_UNNECESSARY)) - goto do_send; - - rndis_msg_size += NDIS_CSUM_PPI_SIZE; - ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE, - TCPIP_CHKSUM_PKTINFO); - - csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi + - ppi->ppi_offset); - - if (net_trans_info & (INFO_IPV4 << 16)) - csum_info->transmit.is_ipv4 = 1; - else - csum_info->transmit.is_ipv6 = 1; - - if (net_trans_info & INFO_TCP) { - csum_info->transmit.tcp_checksum = 1; - csum_info->transmit.tcp_header_offset = hdr_offset; - } else if (net_trans_info & INFO_UDP) { - /* UDP checksum offload is not supported on ws2008r2. - * Furthermore, on ws2012 and ws2012r2, there are some - * issues with udp checksum offload from Linux guests. - * (these are host issues). - * For now compute the checksum here. - */ - struct udphdr *uh; - u16 udp_len; - - ret = skb_cow_head(skb, 0); - if (ret) - goto no_memory; - - uh = udp_hdr(skb); - udp_len = ntohs(uh->len); - uh->check = 0; - uh->check = csum_tcpudp_magic(ip_hdr(skb)->saddr, - ip_hdr(skb)->daddr, - udp_len, IPPROTO_UDP, - csum_partial(uh, udp_len, 0)); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - - csum_info->transmit.udp_checksum = 0; - } - -do_send: /* Start filling in the page buffers with the rndis hdr */ rndis_msg->msg_len += rndis_msg_size; packet->total_data_buflen = rndis_msg->msg_len; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index c6f66832a1a6..f424b867f73e 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -607,6 +607,21 @@ void phy_start_machine(struct phy_device *phydev) queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, HZ); } +/** + * phy_trigger_machine - trigger the state machine to run + * + * @phydev: the phy_device struct + * + * Description: There has been a change in state which requires that the + * state machine runs. + */ + +static void phy_trigger_machine(struct phy_device *phydev) +{ + cancel_delayed_work_sync(&phydev->state_queue); + queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, 0); +} + /** * phy_stop_machine - stop the PHY state machine tracking * @phydev: target phy_device struct @@ -639,6 +654,8 @@ static void phy_error(struct phy_device *phydev) mutex_lock(&phydev->lock); phydev->state = PHY_HALTED; mutex_unlock(&phydev->lock); + + phy_trigger_machine(phydev); } /** @@ -800,8 +817,7 @@ void phy_change(struct work_struct *work) } /* reschedule state queue work to run as soon as possible */ - cancel_delayed_work_sync(&phydev->state_queue); - queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, 0); + phy_trigger_machine(phydev); return; ignore: @@ -890,6 +906,8 @@ void phy_start(struct phy_device *phydev) /* if phy was suspended, bring the physical link up again */ if (do_resume) phy_resume(phydev); + + phy_trigger_machine(phydev); } EXPORT_SYMBOL(phy_start); diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 9d1fce8a6e84..3ff76c6db4f6 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -59,6 +59,10 @@ enum qmi_wwan_flags { QMI_WWAN_FLAG_RAWIP = 1 << 0, }; +enum qmi_wwan_quirks { + QMI_WWAN_QUIRK_DTR = 1 << 0, /* needs "set DTR" request */ +}; + static void qmi_wwan_netdev_setup(struct net_device *net) { struct usbnet *dev = netdev_priv(net); @@ -411,9 +415,14 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) * clearing out state the clients might need. * * MDM9x30 is the first QMI chipset with USB3 support. Abuse - * this fact to enable the quirk. + * this fact to enable the quirk for all USB3 devices. + * + * There are also chipsets with the same "set DTR" requirement + * but without USB3 support. Devices based on these chips + * need a quirk flag in the device ID table. */ - if (le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) { + if (dev->driver_info->data & QMI_WWAN_QUIRK_DTR || + le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) { qmi_wwan_manage_power(dev, 1); qmi_wwan_change_dtr(dev, true); } @@ -526,6 +535,16 @@ static const struct driver_info qmi_wwan_info = { .rx_fixup = qmi_wwan_rx_fixup, }; +static const struct driver_info qmi_wwan_info_quirk_dtr = { + .description = "WWAN/QMI device", + .flags = FLAG_WWAN, + .bind = qmi_wwan_bind, + .unbind = qmi_wwan_unbind, + .manage_power = qmi_wwan_manage_power, + .rx_fixup = qmi_wwan_rx_fixup, + .data = QMI_WWAN_QUIRK_DTR, +}; + #define HUAWEI_VENDOR_ID 0x12D1 /* map QMI/wwan function by a fixed interface number */ @@ -533,6 +552,11 @@ static const struct driver_info qmi_wwan_info = { USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \ .driver_info = (unsigned long)&qmi_wwan_info +/* devices requiring "set DTR" quirk */ +#define QMI_QUIRK_SET_DTR(vend, prod, num) \ + USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \ + .driver_info = (unsigned long)&qmi_wwan_info_quirk_dtr + /* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */ #define QMI_GOBI1K_DEVICE(vend, prod) \ QMI_FIXED_INTF(vend, prod, 3) @@ -895,6 +919,8 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */ {QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */ {QMI_FIXED_INTF(0x1e0e, 0x9001, 5)}, /* SIMCom 7230E */ + {QMI_QUIRK_SET_DTR(0x2c7c, 0x0125, 4)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ + {QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)}, /* Quectel EC21 Mini PCIe */ /* 4. Gobi 1000 devices */ {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index cf68149cbb55..3ce1f7da8647 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -407,4 +407,8 @@ u32 xenvif_set_hash_mapping(struct xenvif *vif, u32 gref, u32 len, void xenvif_set_skb_hash(struct xenvif *vif, struct sk_buff *skb); +#ifdef CONFIG_DEBUG_FS +void xenvif_dump_hash_info(struct xenvif *vif, struct seq_file *m); +#endif + #endif /* __XEN_NETBACK__COMMON_H__ */ diff --git a/drivers/net/xen-netback/hash.c b/drivers/net/xen-netback/hash.c index 613bac057650..e8c5dddc54ba 100644 --- a/drivers/net/xen-netback/hash.c +++ b/drivers/net/xen-netback/hash.c @@ -360,6 +360,74 @@ u32 xenvif_set_hash_mapping(struct xenvif *vif, u32 gref, u32 len, return XEN_NETIF_CTRL_STATUS_SUCCESS; } +#ifdef CONFIG_DEBUG_FS +void xenvif_dump_hash_info(struct xenvif *vif, struct seq_file *m) +{ + unsigned int i; + + switch (vif->hash.alg) { + case XEN_NETIF_CTRL_HASH_ALGORITHM_TOEPLITZ: + seq_puts(m, "Hash Algorithm: TOEPLITZ\n"); + break; + + case XEN_NETIF_CTRL_HASH_ALGORITHM_NONE: + seq_puts(m, "Hash Algorithm: NONE\n"); + /* FALLTHRU */ + default: + return; + } + + if (vif->hash.flags) { + seq_puts(m, "\nHash Flags:\n"); + + if (vif->hash.flags & XEN_NETIF_CTRL_HASH_TYPE_IPV4) + seq_puts(m, "- IPv4\n"); + if (vif->hash.flags & XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP) + seq_puts(m, "- IPv4 + TCP\n"); + if (vif->hash.flags & XEN_NETIF_CTRL_HASH_TYPE_IPV6) + seq_puts(m, "- IPv6\n"); + if (vif->hash.flags & XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP) + seq_puts(m, "- IPv6 + TCP\n"); + } + + seq_puts(m, "\nHash Key:\n"); + + for (i = 0; i < XEN_NETBK_MAX_HASH_KEY_SIZE; ) { + unsigned int j, n; + + n = 8; + if (i + n >= XEN_NETBK_MAX_HASH_KEY_SIZE) + n = XEN_NETBK_MAX_HASH_KEY_SIZE - i; + + seq_printf(m, "[%2u - %2u]: ", i, i + n - 1); + + for (j = 0; j < n; j++, i++) + seq_printf(m, "%02x ", vif->hash.key[i]); + + seq_puts(m, "\n"); + } + + if (vif->hash.size != 0) { + seq_puts(m, "\nHash Mapping:\n"); + + for (i = 0; i < vif->hash.size; ) { + unsigned int j, n; + + n = 8; + if (i + n >= vif->hash.size) + n = vif->hash.size - i; + + seq_printf(m, "[%4u - %4u]: ", i, i + n - 1); + + for (j = 0; j < n; j++, i++) + seq_printf(m, "%4u ", vif->hash.mapping[i]); + + seq_puts(m, "\n"); + } + } +} +#endif /* CONFIG_DEBUG_FS */ + void xenvif_init_hash(struct xenvif *vif) { if (xenvif_hash_cache_size == 0) diff --git a/drivers/net/xen-netback/rx.c b/drivers/net/xen-netback/rx.c index 8e9ade6ccf18..b1cf7c6f407a 100644 --- a/drivers/net/xen-netback/rx.c +++ b/drivers/net/xen-netback/rx.c @@ -337,9 +337,9 @@ static void xenvif_rx_next_chunk(struct xenvif_queue *queue, frag_data += pkt->frag_offset; frag_len -= pkt->frag_offset; - chunk_len = min(frag_len, XEN_PAGE_SIZE - offset); - chunk_len = min(chunk_len, - XEN_PAGE_SIZE - xen_offset_in_page(frag_data)); + chunk_len = min_t(size_t, frag_len, XEN_PAGE_SIZE - offset); + chunk_len = min_t(size_t, chunk_len, XEN_PAGE_SIZE - + xen_offset_in_page(frag_data)); pkt->frag_offset += chunk_len; @@ -425,6 +425,8 @@ void xenvif_rx_skb(struct xenvif_queue *queue) xenvif_rx_next_skb(queue, &pkt); + queue->last_rx_time = jiffies; + do { struct xen_netif_rx_request *req; struct xen_netif_rx_response *rsp; diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 7056404e3cb8..8674e188b697 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -165,7 +165,7 @@ xenvif_write_io_ring(struct file *filp, const char __user *buf, size_t count, return count; } -static int xenvif_dump_open(struct inode *inode, struct file *filp) +static int xenvif_io_ring_open(struct inode *inode, struct file *filp) { int ret; void *queue = NULL; @@ -179,13 +179,35 @@ static int xenvif_dump_open(struct inode *inode, struct file *filp) static const struct file_operations xenvif_dbg_io_ring_ops_fops = { .owner = THIS_MODULE, - .open = xenvif_dump_open, + .open = xenvif_io_ring_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, .write = xenvif_write_io_ring, }; +static int xenvif_read_ctrl(struct seq_file *m, void *v) +{ + struct xenvif *vif = m->private; + + xenvif_dump_hash_info(vif, m); + + return 0; +} + +static int xenvif_ctrl_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, xenvif_read_ctrl, inode->i_private); +} + +static const struct file_operations xenvif_dbg_ctrl_ops_fops = { + .owner = THIS_MODULE, + .open = xenvif_ctrl_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static void xenvif_debugfs_addif(struct xenvif *vif) { struct dentry *pfile; @@ -210,6 +232,17 @@ static void xenvif_debugfs_addif(struct xenvif *vif) pr_warn("Creation of io_ring file returned %ld!\n", PTR_ERR(pfile)); } + + if (vif->ctrl_irq) { + pfile = debugfs_create_file("ctrl", + S_IRUSR, + vif->xenvif_dbg_root, + vif, + &xenvif_dbg_ctrl_ops_fops); + if (IS_ERR_OR_NULL(pfile)) + pr_warn("Creation of ctrl file returned %ld!\n", + PTR_ERR(pfile)); + } } else netdev_warn(vif->dev, "Creation of vif debugfs dir returned %ld!\n", diff --git a/drivers/pci/host/pci-aardvark.c b/drivers/pci/host/pci-aardvark.c index e4a5b7ee90cf..4fce494271cc 100644 --- a/drivers/pci/host/pci-aardvark.c +++ b/drivers/pci/host/pci-aardvark.c @@ -230,20 +230,20 @@ static int advk_pcie_link_up(struct advk_pcie *pcie) static int advk_pcie_wait_for_link(struct advk_pcie *pcie) { + struct device *dev = &pcie->pdev->dev; int retries; /* check if the link is up or not */ for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) { if (advk_pcie_link_up(pcie)) { - dev_info(&pcie->pdev->dev, "link up\n"); + dev_info(dev, "link up\n"); return 0; } usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX); } - dev_err(&pcie->pdev->dev, "link never came up\n"); - + dev_err(dev, "link never came up\n"); return -ETIMEDOUT; } @@ -376,6 +376,7 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie) static void advk_pcie_check_pio_status(struct advk_pcie *pcie) { + struct device *dev = &pcie->pdev->dev; u32 reg; unsigned int status; char *strcomp_status, *str_posted; @@ -407,12 +408,13 @@ static void advk_pcie_check_pio_status(struct advk_pcie *pcie) else str_posted = "Posted"; - dev_err(&pcie->pdev->dev, "%s PIO Response Status: %s, %#x @ %#x\n", + dev_err(dev, "%s PIO Response Status: %s, %#x @ %#x\n", str_posted, strcomp_status, reg, advk_readl(pcie, PIO_ADDR_LS)); } static int advk_pcie_wait_pio(struct advk_pcie *pcie) { + struct device *dev = &pcie->pdev->dev; unsigned long timeout; timeout = jiffies + msecs_to_jiffies(PIO_TIMEOUT_MS); @@ -426,7 +428,7 @@ static int advk_pcie_wait_pio(struct advk_pcie *pcie) return 0; } - dev_err(&pcie->pdev->dev, "config read/write timed out\n"); + dev_err(dev, "config read/write timed out\n"); return -ETIMEDOUT; } @@ -560,10 +562,11 @@ static int advk_pcie_alloc_msi(struct advk_pcie *pcie) static void advk_pcie_free_msi(struct advk_pcie *pcie, int hwirq) { + struct device *dev = &pcie->pdev->dev; + mutex_lock(&pcie->msi_used_lock); if (!test_bit(hwirq, pcie->msi_irq_in_use)) - dev_err(&pcie->pdev->dev, "trying to free unused MSI#%d\n", - hwirq); + dev_err(dev, "trying to free unused MSI#%d\n", hwirq); else clear_bit(hwirq, pcie->msi_irq_in_use); mutex_unlock(&pcie->msi_used_lock); @@ -910,6 +913,7 @@ out_release_res: static int advk_pcie_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct advk_pcie *pcie; struct resource *res; struct pci_bus *bus, *child; @@ -917,31 +921,29 @@ static int advk_pcie_probe(struct platform_device *pdev) struct device_node *msi_node; int ret, irq; - pcie = devm_kzalloc(&pdev->dev, sizeof(struct advk_pcie), - GFP_KERNEL); + pcie = devm_kzalloc(dev, sizeof(struct advk_pcie), GFP_KERNEL); if (!pcie) return -ENOMEM; pcie->pdev = pdev; - platform_set_drvdata(pdev, pcie); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pcie->base = devm_ioremap_resource(&pdev->dev, res); + pcie->base = devm_ioremap_resource(dev, res); if (IS_ERR(pcie->base)) return PTR_ERR(pcie->base); irq = platform_get_irq(pdev, 0); - ret = devm_request_irq(&pdev->dev, irq, advk_pcie_irq_handler, + ret = devm_request_irq(dev, irq, advk_pcie_irq_handler, IRQF_SHARED | IRQF_NO_THREAD, "advk-pcie", pcie); if (ret) { - dev_err(&pdev->dev, "Failed to register interrupt\n"); + dev_err(dev, "Failed to register interrupt\n"); return ret; } ret = advk_pcie_parse_request_of_pci_ranges(pcie); if (ret) { - dev_err(&pdev->dev, "Failed to parse resources\n"); + dev_err(dev, "Failed to parse resources\n"); return ret; } @@ -949,24 +951,24 @@ static int advk_pcie_probe(struct platform_device *pdev) ret = advk_pcie_init_irq_domain(pcie); if (ret) { - dev_err(&pdev->dev, "Failed to initialize irq\n"); + dev_err(dev, "Failed to initialize irq\n"); return ret; } ret = advk_pcie_init_msi_irq_domain(pcie); if (ret) { - dev_err(&pdev->dev, "Failed to initialize irq\n"); + dev_err(dev, "Failed to initialize irq\n"); advk_pcie_remove_irq_domain(pcie); return ret; } - msi_node = of_parse_phandle(pdev->dev.of_node, "msi-parent", 0); + msi_node = of_parse_phandle(dev->of_node, "msi-parent", 0); if (msi_node) msi = of_pci_find_msi_chip_by_node(msi_node); else msi = NULL; - bus = pci_scan_root_bus_msi(&pdev->dev, 0, &advk_pcie_ops, + bus = pci_scan_root_bus_msi(dev, 0, &advk_pcie_ops, pcie, &pcie->resources, &pcie->msi); if (!bus) { advk_pcie_remove_msi_irq_domain(pcie); @@ -980,7 +982,6 @@ static int advk_pcie_probe(struct platform_device *pdev) pcie_bus_configure_settings(child); pci_bus_add_devices(bus); - return 0; } diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/host/pci-dra7xx.c index 19223ed2e619..9595fad63f6f 100644 --- a/drivers/pci/host/pci-dra7xx.c +++ b/drivers/pci/host/pci-dra7xx.c @@ -64,11 +64,10 @@ #define DRA7XX_CPU_TO_BUS_ADDR 0x0FFFFFFF struct dra7xx_pcie { - void __iomem *base; - struct phy **phy; - int phy_count; - struct device *dev; struct pcie_port pp; + void __iomem *base; /* DT ti_conf */ + int phy_count; /* DT phy-names count */ + struct phy **phy; }; #define to_dra7xx_pcie(x) container_of((x), struct dra7xx_pcie, pp) @@ -84,17 +83,6 @@ static inline void dra7xx_pcie_writel(struct dra7xx_pcie *pcie, u32 offset, writel(value, pcie->base + offset); } -static inline u32 dra7xx_pcie_readl_rc(struct pcie_port *pp, u32 offset) -{ - return readl(pp->dbi_base + offset); -} - -static inline void dra7xx_pcie_writel_rc(struct pcie_port *pp, u32 offset, - u32 value) -{ - writel(value, pp->dbi_base + offset); -} - static int dra7xx_pcie_link_up(struct pcie_port *pp) { struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); @@ -103,13 +91,14 @@ static int dra7xx_pcie_link_up(struct pcie_port *pp) return !!(reg & LINK_UP); } -static int dra7xx_pcie_establish_link(struct pcie_port *pp) +static int dra7xx_pcie_establish_link(struct dra7xx_pcie *dra7xx) { - struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); + struct pcie_port *pp = &dra7xx->pp; + struct device *dev = pp->dev; u32 reg; if (dw_pcie_link_up(pp)) { - dev_err(pp->dev, "link is already up\n"); + dev_err(dev, "link is already up\n"); return 0; } @@ -120,10 +109,8 @@ static int dra7xx_pcie_establish_link(struct pcie_port *pp) return dw_pcie_wait_for_link(pp); } -static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp) +static void dra7xx_pcie_enable_interrupts(struct dra7xx_pcie *dra7xx) { - struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); - dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN, ~INTERRUPTS); dra7xx_pcie_writel(dra7xx, @@ -142,6 +129,8 @@ static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp) static void dra7xx_pcie_host_init(struct pcie_port *pp) { + struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); + pp->io_base &= DRA7XX_CPU_TO_BUS_ADDR; pp->mem_base &= DRA7XX_CPU_TO_BUS_ADDR; pp->cfg0_base &= DRA7XX_CPU_TO_BUS_ADDR; @@ -149,10 +138,10 @@ static void dra7xx_pcie_host_init(struct pcie_port *pp) dw_pcie_setup_rc(pp); - dra7xx_pcie_establish_link(pp); + dra7xx_pcie_establish_link(dra7xx); if (IS_ENABLED(CONFIG_PCI_MSI)) dw_pcie_msi_init(pp); - dra7xx_pcie_enable_interrupts(pp); + dra7xx_pcie_enable_interrupts(dra7xx); } static struct pcie_host_ops dra7xx_pcie_host_ops = { @@ -196,8 +185,8 @@ static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp) static irqreturn_t dra7xx_pcie_msi_irq_handler(int irq, void *arg) { - struct pcie_port *pp = arg; - struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); + struct dra7xx_pcie *dra7xx = arg; + struct pcie_port *pp = &dra7xx->pp; u32 reg; reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI); @@ -223,51 +212,51 @@ static irqreturn_t dra7xx_pcie_msi_irq_handler(int irq, void *arg) static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg) { struct dra7xx_pcie *dra7xx = arg; + struct device *dev = dra7xx->pp.dev; u32 reg; reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN); if (reg & ERR_SYS) - dev_dbg(dra7xx->dev, "System Error\n"); + dev_dbg(dev, "System Error\n"); if (reg & ERR_FATAL) - dev_dbg(dra7xx->dev, "Fatal Error\n"); + dev_dbg(dev, "Fatal Error\n"); if (reg & ERR_NONFATAL) - dev_dbg(dra7xx->dev, "Non Fatal Error\n"); + dev_dbg(dev, "Non Fatal Error\n"); if (reg & ERR_COR) - dev_dbg(dra7xx->dev, "Correctable Error\n"); + dev_dbg(dev, "Correctable Error\n"); if (reg & ERR_AXI) - dev_dbg(dra7xx->dev, "AXI tag lookup fatal Error\n"); + dev_dbg(dev, "AXI tag lookup fatal Error\n"); if (reg & ERR_ECRC) - dev_dbg(dra7xx->dev, "ECRC Error\n"); + dev_dbg(dev, "ECRC Error\n"); if (reg & PME_TURN_OFF) - dev_dbg(dra7xx->dev, + dev_dbg(dev, "Power Management Event Turn-Off message received\n"); if (reg & PME_TO_ACK) - dev_dbg(dra7xx->dev, + dev_dbg(dev, "Power Management Turn-Off Ack message received\n"); if (reg & PM_PME) - dev_dbg(dra7xx->dev, - "PM Power Management Event message received\n"); + dev_dbg(dev, "PM Power Management Event message received\n"); if (reg & LINK_REQ_RST) - dev_dbg(dra7xx->dev, "Link Request Reset\n"); + dev_dbg(dev, "Link Request Reset\n"); if (reg & LINK_UP_EVT) - dev_dbg(dra7xx->dev, "Link-up state change\n"); + dev_dbg(dev, "Link-up state change\n"); if (reg & CFG_BME_EVT) - dev_dbg(dra7xx->dev, "CFG 'Bus Master Enable' change\n"); + dev_dbg(dev, "CFG 'Bus Master Enable' change\n"); if (reg & CFG_MSE_EVT) - dev_dbg(dra7xx->dev, "CFG 'Memory Space Enable' change\n"); + dev_dbg(dev, "CFG 'Memory Space Enable' change\n"); dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN, reg); @@ -278,13 +267,9 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, struct platform_device *pdev) { int ret; - struct pcie_port *pp; + struct pcie_port *pp = &dra7xx->pp; + struct device *dev = pp->dev; struct resource *res; - struct device *dev = &pdev->dev; - - pp = &dra7xx->pp; - pp->dev = dev; - pp->ops = &dra7xx_pcie_host_ops; pp->irq = platform_get_irq(pdev, 1); if (pp->irq < 0) { @@ -292,12 +277,11 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, return -EINVAL; } - ret = devm_request_irq(&pdev->dev, pp->irq, - dra7xx_pcie_msi_irq_handler, + ret = devm_request_irq(dev, pp->irq, dra7xx_pcie_msi_irq_handler, IRQF_SHARED | IRQF_NO_THREAD, - "dra7-pcie-msi", pp); + "dra7-pcie-msi", dra7xx); if (ret) { - dev_err(&pdev->dev, "failed to request irq\n"); + dev_err(dev, "failed to request irq\n"); return ret; } @@ -314,7 +298,7 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, ret = dw_pcie_host_init(pp); if (ret) { - dev_err(dra7xx->dev, "failed to initialize host\n"); + dev_err(dev, "failed to initialize host\n"); return ret; } @@ -332,6 +316,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) void __iomem *base; struct resource *res; struct dra7xx_pcie *dra7xx; + struct pcie_port *pp; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; char name[10]; @@ -343,6 +328,10 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) if (!dra7xx) return -ENOMEM; + pp = &dra7xx->pp; + pp->dev = dev; + pp->ops = &dra7xx_pcie_host_ops; + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(dev, "missing IRQ resource\n"); @@ -390,7 +379,6 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) dra7xx->base = base; dra7xx->phy = phy; - dra7xx->dev = dev; dra7xx->phy_count = phy_count; pm_runtime_enable(dev); @@ -407,7 +395,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) ret = devm_gpio_request_one(dev, gpio_sel, gpio_flags, "pcie_reset"); if (ret) { - dev_err(&pdev->dev, "gpio%d request failed, ret %d\n", + dev_err(dev, "gpio%d request failed, ret %d\n", gpio_sel, ret); goto err_gpio; } @@ -420,12 +408,11 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) reg &= ~LTSSM_EN; dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); - platform_set_drvdata(pdev, dra7xx); - ret = dra7xx_add_pcie_port(dra7xx, pdev); if (ret < 0) goto err_gpio; + platform_set_drvdata(pdev, dra7xx); return 0; err_gpio: @@ -451,9 +438,9 @@ static int dra7xx_pcie_suspend(struct device *dev) u32 val; /* clear MSE */ - val = dra7xx_pcie_readl_rc(pp, PCI_COMMAND); + val = dw_pcie_readl_rc(pp, PCI_COMMAND); val &= ~PCI_COMMAND_MEMORY; - dra7xx_pcie_writel_rc(pp, PCI_COMMAND, val); + dw_pcie_writel_rc(pp, PCI_COMMAND, val); return 0; } @@ -465,9 +452,9 @@ static int dra7xx_pcie_resume(struct device *dev) u32 val; /* set MSE */ - val = dra7xx_pcie_readl_rc(pp, PCI_COMMAND); + val = dw_pcie_readl_rc(pp, PCI_COMMAND); val |= PCI_COMMAND_MEMORY; - dra7xx_pcie_writel_rc(pp, PCI_COMMAND, val); + dw_pcie_writel_rc(pp, PCI_COMMAND, val); return 0; } diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c index 2e2d7f00b9e8..f1c544bb8b68 100644 --- a/drivers/pci/host/pci-exynos.c +++ b/drivers/pci/host/pci-exynos.c @@ -29,13 +29,13 @@ #define to_exynos_pcie(x) container_of(x, struct exynos_pcie, pp) struct exynos_pcie { - void __iomem *elbi_base; - void __iomem *phy_base; - void __iomem *block_base; + struct pcie_port pp; + void __iomem *elbi_base; /* DT 0th resource */ + void __iomem *phy_base; /* DT 1st resource */ + void __iomem *block_base; /* DT 2nd resource */ int reset_gpio; struct clk *clk; struct clk *bus_clk; - struct pcie_port pp; }; /* PCIe ELBI registers */ @@ -102,40 +102,40 @@ struct exynos_pcie { #define PCIE_PHY_TRSV3_PD_TSV (0x1 << 7) #define PCIE_PHY_TRSV3_LVCC 0x31c -static inline void exynos_elb_writel(struct exynos_pcie *pcie, u32 val, u32 reg) +static void exynos_elb_writel(struct exynos_pcie *exynos_pcie, u32 val, u32 reg) { - writel(val, pcie->elbi_base + reg); + writel(val, exynos_pcie->elbi_base + reg); } -static inline u32 exynos_elb_readl(struct exynos_pcie *pcie, u32 reg) +static u32 exynos_elb_readl(struct exynos_pcie *exynos_pcie, u32 reg) { - return readl(pcie->elbi_base + reg); + return readl(exynos_pcie->elbi_base + reg); } -static inline void exynos_phy_writel(struct exynos_pcie *pcie, u32 val, u32 reg) +static void exynos_phy_writel(struct exynos_pcie *exynos_pcie, u32 val, u32 reg) { - writel(val, pcie->phy_base + reg); + writel(val, exynos_pcie->phy_base + reg); } -static inline u32 exynos_phy_readl(struct exynos_pcie *pcie, u32 reg) +static u32 exynos_phy_readl(struct exynos_pcie *exynos_pcie, u32 reg) { - return readl(pcie->phy_base + reg); + return readl(exynos_pcie->phy_base + reg); } -static inline void exynos_blk_writel(struct exynos_pcie *pcie, u32 val, u32 reg) +static void exynos_blk_writel(struct exynos_pcie *exynos_pcie, u32 val, u32 reg) { - writel(val, pcie->block_base + reg); + writel(val, exynos_pcie->block_base + reg); } -static inline u32 exynos_blk_readl(struct exynos_pcie *pcie, u32 reg) +static u32 exynos_blk_readl(struct exynos_pcie *exynos_pcie, u32 reg) { - return readl(pcie->block_base + reg); + return readl(exynos_pcie->block_base + reg); } -static void exynos_pcie_sideband_dbi_w_mode(struct pcie_port *pp, bool on) +static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *exynos_pcie, + bool on) { u32 val; - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); if (on) { val = exynos_elb_readl(exynos_pcie, PCIE_ELBI_SLV_AWMISC); @@ -148,10 +148,10 @@ static void exynos_pcie_sideband_dbi_w_mode(struct pcie_port *pp, bool on) } } -static void exynos_pcie_sideband_dbi_r_mode(struct pcie_port *pp, bool on) +static void exynos_pcie_sideband_dbi_r_mode(struct exynos_pcie *exynos_pcie, + bool on) { u32 val; - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); if (on) { val = exynos_elb_readl(exynos_pcie, PCIE_ELBI_SLV_ARMISC); @@ -164,10 +164,9 @@ static void exynos_pcie_sideband_dbi_r_mode(struct pcie_port *pp, bool on) } } -static void exynos_pcie_assert_core_reset(struct pcie_port *pp) +static void exynos_pcie_assert_core_reset(struct exynos_pcie *exynos_pcie) { u32 val; - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); val = exynos_elb_readl(exynos_pcie, PCIE_CORE_RESET); val &= ~PCIE_CORE_RESET_ENABLE; @@ -177,10 +176,9 @@ static void exynos_pcie_assert_core_reset(struct pcie_port *pp) exynos_elb_writel(exynos_pcie, 0, PCIE_NONSTICKY_RESET); } -static void exynos_pcie_deassert_core_reset(struct pcie_port *pp) +static void exynos_pcie_deassert_core_reset(struct exynos_pcie *exynos_pcie) { u32 val; - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); val = exynos_elb_readl(exynos_pcie, PCIE_CORE_RESET); val |= PCIE_CORE_RESET_ENABLE; @@ -193,18 +191,14 @@ static void exynos_pcie_deassert_core_reset(struct pcie_port *pp) exynos_blk_writel(exynos_pcie, 1, PCIE_PHY_MAC_RESET); } -static void exynos_pcie_assert_phy_reset(struct pcie_port *pp) +static void exynos_pcie_assert_phy_reset(struct exynos_pcie *exynos_pcie) { - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); - exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_MAC_RESET); exynos_blk_writel(exynos_pcie, 1, PCIE_PHY_GLOBAL_RESET); } -static void exynos_pcie_deassert_phy_reset(struct pcie_port *pp) +static void exynos_pcie_deassert_phy_reset(struct exynos_pcie *exynos_pcie) { - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); - exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_GLOBAL_RESET); exynos_elb_writel(exynos_pcie, 1, PCIE_PWR_RESET); exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_COMMON_RESET); @@ -213,10 +207,9 @@ static void exynos_pcie_deassert_phy_reset(struct pcie_port *pp) exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_TRSV_RESET); } -static void exynos_pcie_power_on_phy(struct pcie_port *pp) +static void exynos_pcie_power_on_phy(struct exynos_pcie *exynos_pcie) { u32 val; - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); val = exynos_phy_readl(exynos_pcie, PCIE_PHY_COMMON_POWER); val &= ~PCIE_PHY_COMMON_PD_CMN; @@ -239,10 +232,9 @@ static void exynos_pcie_power_on_phy(struct pcie_port *pp) exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV3_POWER); } -static void exynos_pcie_power_off_phy(struct pcie_port *pp) +static void exynos_pcie_power_off_phy(struct exynos_pcie *exynos_pcie) { u32 val; - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); val = exynos_phy_readl(exynos_pcie, PCIE_PHY_COMMON_POWER); val |= PCIE_PHY_COMMON_PD_CMN; @@ -265,10 +257,8 @@ static void exynos_pcie_power_off_phy(struct pcie_port *pp) exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV3_POWER); } -static void exynos_pcie_init_phy(struct pcie_port *pp) +static void exynos_pcie_init_phy(struct exynos_pcie *exynos_pcie) { - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); - /* DCC feedback control off */ exynos_phy_writel(exynos_pcie, 0x29, PCIE_PHY_DCC_FEEDBACK); @@ -305,51 +295,41 @@ static void exynos_pcie_init_phy(struct pcie_port *pp) exynos_phy_writel(exynos_pcie, 0xa0, PCIE_PHY_TRSV3_LVCC); } -static void exynos_pcie_assert_reset(struct pcie_port *pp) +static void exynos_pcie_assert_reset(struct exynos_pcie *exynos_pcie) { - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); + struct pcie_port *pp = &exynos_pcie->pp; + struct device *dev = pp->dev; if (exynos_pcie->reset_gpio >= 0) - devm_gpio_request_one(pp->dev, exynos_pcie->reset_gpio, + devm_gpio_request_one(dev, exynos_pcie->reset_gpio, GPIOF_OUT_INIT_HIGH, "RESET"); } -static int exynos_pcie_establish_link(struct pcie_port *pp) +static int exynos_pcie_establish_link(struct exynos_pcie *exynos_pcie) { - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); + struct pcie_port *pp = &exynos_pcie->pp; + struct device *dev = pp->dev; u32 val; if (dw_pcie_link_up(pp)) { - dev_err(pp->dev, "Link already up\n"); + dev_err(dev, "Link already up\n"); return 0; } - /* assert reset signals */ - exynos_pcie_assert_core_reset(pp); - exynos_pcie_assert_phy_reset(pp); - - /* de-assert phy reset */ - exynos_pcie_deassert_phy_reset(pp); - - /* power on phy */ - exynos_pcie_power_on_phy(pp); - - /* initialize phy */ - exynos_pcie_init_phy(pp); + exynos_pcie_assert_core_reset(exynos_pcie); + exynos_pcie_assert_phy_reset(exynos_pcie); + exynos_pcie_deassert_phy_reset(exynos_pcie); + exynos_pcie_power_on_phy(exynos_pcie); + exynos_pcie_init_phy(exynos_pcie); /* pulse for common reset */ exynos_blk_writel(exynos_pcie, 1, PCIE_PHY_COMMON_RESET); udelay(500); exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_COMMON_RESET); - /* de-assert core reset */ - exynos_pcie_deassert_core_reset(pp); - - /* setup root complex */ + exynos_pcie_deassert_core_reset(exynos_pcie); dw_pcie_setup_rc(pp); - - /* assert reset signal */ - exynos_pcie_assert_reset(pp); + exynos_pcie_assert_reset(exynos_pcie); /* assert LTSSM enable */ exynos_elb_writel(exynos_pcie, PCIE_ELBI_LTSSM_ENABLE, @@ -361,27 +341,23 @@ static int exynos_pcie_establish_link(struct pcie_port *pp) while (exynos_phy_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED) == 0) { val = exynos_blk_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED); - dev_info(pp->dev, "PLL Locked: 0x%x\n", val); + dev_info(dev, "PLL Locked: 0x%x\n", val); } - /* power off phy */ - exynos_pcie_power_off_phy(pp); - + exynos_pcie_power_off_phy(exynos_pcie); return -ETIMEDOUT; } -static void exynos_pcie_clear_irq_pulse(struct pcie_port *pp) +static void exynos_pcie_clear_irq_pulse(struct exynos_pcie *exynos_pcie) { u32 val; - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); val = exynos_elb_readl(exynos_pcie, PCIE_IRQ_PULSE); exynos_elb_writel(exynos_pcie, val, PCIE_IRQ_PULSE); } -static void exynos_pcie_enable_irq_pulse(struct pcie_port *pp) +static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *exynos_pcie) { u32 val; - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); /* enable INTX interrupt */ val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT | @@ -391,23 +367,24 @@ static void exynos_pcie_enable_irq_pulse(struct pcie_port *pp) static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg) { - struct pcie_port *pp = arg; + struct exynos_pcie *exynos_pcie = arg; - exynos_pcie_clear_irq_pulse(pp); + exynos_pcie_clear_irq_pulse(exynos_pcie); return IRQ_HANDLED; } static irqreturn_t exynos_pcie_msi_irq_handler(int irq, void *arg) { - struct pcie_port *pp = arg; + struct exynos_pcie *exynos_pcie = arg; + struct pcie_port *pp = &exynos_pcie->pp; return dw_handle_msi_irq(pp); } -static void exynos_pcie_msi_init(struct pcie_port *pp) +static void exynos_pcie_msi_init(struct exynos_pcie *exynos_pcie) { + struct pcie_port *pp = &exynos_pcie->pp; u32 val; - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); dw_pcie_msi_init(pp); @@ -417,60 +394,64 @@ static void exynos_pcie_msi_init(struct pcie_port *pp) exynos_elb_writel(exynos_pcie, val, PCIE_IRQ_EN_LEVEL); } -static void exynos_pcie_enable_interrupts(struct pcie_port *pp) +static void exynos_pcie_enable_interrupts(struct exynos_pcie *exynos_pcie) { - exynos_pcie_enable_irq_pulse(pp); + exynos_pcie_enable_irq_pulse(exynos_pcie); if (IS_ENABLED(CONFIG_PCI_MSI)) - exynos_pcie_msi_init(pp); + exynos_pcie_msi_init(exynos_pcie); } -static inline u32 exynos_pcie_readl_rc(struct pcie_port *pp, - void __iomem *dbi_base) +static u32 exynos_pcie_readl_rc(struct pcie_port *pp, u32 reg) { + struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); u32 val; - exynos_pcie_sideband_dbi_r_mode(pp, true); - val = readl(dbi_base); - exynos_pcie_sideband_dbi_r_mode(pp, false); + exynos_pcie_sideband_dbi_r_mode(exynos_pcie, true); + val = readl(pp->dbi_base + reg); + exynos_pcie_sideband_dbi_r_mode(exynos_pcie, false); return val; } -static inline void exynos_pcie_writel_rc(struct pcie_port *pp, - u32 val, void __iomem *dbi_base) +static void exynos_pcie_writel_rc(struct pcie_port *pp, u32 reg, u32 val) { - exynos_pcie_sideband_dbi_w_mode(pp, true); - writel(val, dbi_base); - exynos_pcie_sideband_dbi_w_mode(pp, false); + struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); + + exynos_pcie_sideband_dbi_w_mode(exynos_pcie, true); + writel(val, pp->dbi_base + reg); + exynos_pcie_sideband_dbi_w_mode(exynos_pcie, false); } static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, u32 *val) { + struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); int ret; - exynos_pcie_sideband_dbi_r_mode(pp, true); + exynos_pcie_sideband_dbi_r_mode(exynos_pcie, true); ret = dw_pcie_cfg_read(pp->dbi_base + where, size, val); - exynos_pcie_sideband_dbi_r_mode(pp, false); + exynos_pcie_sideband_dbi_r_mode(exynos_pcie, false); return ret; } static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size, u32 val) { + struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); int ret; - exynos_pcie_sideband_dbi_w_mode(pp, true); + exynos_pcie_sideband_dbi_w_mode(exynos_pcie, true); ret = dw_pcie_cfg_write(pp->dbi_base + where, size, val); - exynos_pcie_sideband_dbi_w_mode(pp, false); + exynos_pcie_sideband_dbi_w_mode(exynos_pcie, false); return ret; } static int exynos_pcie_link_up(struct pcie_port *pp) { struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); - u32 val = exynos_elb_readl(exynos_pcie, PCIE_ELBI_RDLH_LINKUP); + u32 val; + val = exynos_elb_readl(exynos_pcie, PCIE_ELBI_RDLH_LINKUP); if (val == PCIE_ELBI_LTSSM_ENABLE) return 1; @@ -479,8 +460,10 @@ static int exynos_pcie_link_up(struct pcie_port *pp) static void exynos_pcie_host_init(struct pcie_port *pp) { - exynos_pcie_establish_link(pp); - exynos_pcie_enable_interrupts(pp); + struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); + + exynos_pcie_establish_link(exynos_pcie); + exynos_pcie_enable_interrupts(exynos_pcie); } static struct pcie_host_ops exynos_pcie_host_ops = { @@ -492,36 +475,38 @@ static struct pcie_host_ops exynos_pcie_host_ops = { .host_init = exynos_pcie_host_init, }; -static int __init exynos_add_pcie_port(struct pcie_port *pp, +static int __init exynos_add_pcie_port(struct exynos_pcie *exynos_pcie, struct platform_device *pdev) { + struct pcie_port *pp = &exynos_pcie->pp; + struct device *dev = pp->dev; int ret; pp->irq = platform_get_irq(pdev, 1); if (!pp->irq) { - dev_err(&pdev->dev, "failed to get irq\n"); + dev_err(dev, "failed to get irq\n"); return -ENODEV; } - ret = devm_request_irq(&pdev->dev, pp->irq, exynos_pcie_irq_handler, - IRQF_SHARED, "exynos-pcie", pp); + ret = devm_request_irq(dev, pp->irq, exynos_pcie_irq_handler, + IRQF_SHARED, "exynos-pcie", exynos_pcie); if (ret) { - dev_err(&pdev->dev, "failed to request irq\n"); + dev_err(dev, "failed to request irq\n"); return ret; } if (IS_ENABLED(CONFIG_PCI_MSI)) { pp->msi_irq = platform_get_irq(pdev, 0); if (!pp->msi_irq) { - dev_err(&pdev->dev, "failed to get msi irq\n"); + dev_err(dev, "failed to get msi irq\n"); return -ENODEV; } - ret = devm_request_irq(&pdev->dev, pp->msi_irq, + ret = devm_request_irq(dev, pp->msi_irq, exynos_pcie_msi_irq_handler, IRQF_SHARED | IRQF_NO_THREAD, - "exynos-pcie", pp); + "exynos-pcie", exynos_pcie); if (ret) { - dev_err(&pdev->dev, "failed to request msi irq\n"); + dev_err(dev, "failed to request msi irq\n"); return ret; } } @@ -531,7 +516,7 @@ static int __init exynos_add_pcie_port(struct pcie_port *pp, ret = dw_pcie_host_init(pp); if (ret) { - dev_err(&pdev->dev, "failed to initialize host\n"); + dev_err(dev, "failed to initialize host\n"); return ret; } @@ -540,37 +525,36 @@ static int __init exynos_add_pcie_port(struct pcie_port *pp, static int __init exynos_pcie_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct exynos_pcie *exynos_pcie; struct pcie_port *pp; - struct device_node *np = pdev->dev.of_node; + struct device_node *np = dev->of_node; struct resource *elbi_base; struct resource *phy_base; struct resource *block_base; int ret; - exynos_pcie = devm_kzalloc(&pdev->dev, sizeof(*exynos_pcie), - GFP_KERNEL); + exynos_pcie = devm_kzalloc(dev, sizeof(*exynos_pcie), GFP_KERNEL); if (!exynos_pcie) return -ENOMEM; pp = &exynos_pcie->pp; - - pp->dev = &pdev->dev; + pp->dev = dev; exynos_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); - exynos_pcie->clk = devm_clk_get(&pdev->dev, "pcie"); + exynos_pcie->clk = devm_clk_get(dev, "pcie"); if (IS_ERR(exynos_pcie->clk)) { - dev_err(&pdev->dev, "Failed to get pcie rc clock\n"); + dev_err(dev, "Failed to get pcie rc clock\n"); return PTR_ERR(exynos_pcie->clk); } ret = clk_prepare_enable(exynos_pcie->clk); if (ret) return ret; - exynos_pcie->bus_clk = devm_clk_get(&pdev->dev, "pcie_bus"); + exynos_pcie->bus_clk = devm_clk_get(dev, "pcie_bus"); if (IS_ERR(exynos_pcie->bus_clk)) { - dev_err(&pdev->dev, "Failed to get pcie bus clock\n"); + dev_err(dev, "Failed to get pcie bus clock\n"); ret = PTR_ERR(exynos_pcie->bus_clk); goto fail_clk; } @@ -579,27 +563,27 @@ static int __init exynos_pcie_probe(struct platform_device *pdev) goto fail_clk; elbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); - exynos_pcie->elbi_base = devm_ioremap_resource(&pdev->dev, elbi_base); + exynos_pcie->elbi_base = devm_ioremap_resource(dev, elbi_base); if (IS_ERR(exynos_pcie->elbi_base)) { ret = PTR_ERR(exynos_pcie->elbi_base); goto fail_bus_clk; } phy_base = platform_get_resource(pdev, IORESOURCE_MEM, 1); - exynos_pcie->phy_base = devm_ioremap_resource(&pdev->dev, phy_base); + exynos_pcie->phy_base = devm_ioremap_resource(dev, phy_base); if (IS_ERR(exynos_pcie->phy_base)) { ret = PTR_ERR(exynos_pcie->phy_base); goto fail_bus_clk; } block_base = platform_get_resource(pdev, IORESOURCE_MEM, 2); - exynos_pcie->block_base = devm_ioremap_resource(&pdev->dev, block_base); + exynos_pcie->block_base = devm_ioremap_resource(dev, block_base); if (IS_ERR(exynos_pcie->block_base)) { ret = PTR_ERR(exynos_pcie->block_base); goto fail_bus_clk; } - ret = exynos_add_pcie_port(pp, pdev); + ret = exynos_add_pcie_port(exynos_pcie, pdev); if (ret < 0) goto fail_bus_clk; diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index ead4a5c3480b..c8cefb078218 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -39,16 +39,15 @@ enum imx6_pcie_variants { }; struct imx6_pcie { + struct pcie_port pp; /* pp.dbi_base is DT 0th resource */ int reset_gpio; bool gpio_active_high; struct clk *pcie_bus; struct clk *pcie_phy; struct clk *pcie_inbound_axi; struct clk *pcie; - struct pcie_port pp; struct regmap *iomuxc_gpr; enum imx6_pcie_variants variant; - void __iomem *mem_base; u32 tx_deemph_gen1; u32 tx_deemph_gen2_3p5db; u32 tx_deemph_gen2_6db; @@ -96,14 +95,15 @@ struct imx6_pcie { #define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5) #define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3) -static int pcie_phy_poll_ack(void __iomem *dbi_base, int exp_val) +static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, int exp_val) { + struct pcie_port *pp = &imx6_pcie->pp; u32 val; u32 max_iterations = 10; u32 wait_counter = 0; do { - val = readl(dbi_base + PCIE_PHY_STAT); + val = dw_pcie_readl_rc(pp, PCIE_PHY_STAT); val = (val >> PCIE_PHY_STAT_ACK_LOC) & 0x1; wait_counter++; @@ -116,123 +116,126 @@ static int pcie_phy_poll_ack(void __iomem *dbi_base, int exp_val) return -ETIMEDOUT; } -static int pcie_phy_wait_ack(void __iomem *dbi_base, int addr) +static int pcie_phy_wait_ack(struct imx6_pcie *imx6_pcie, int addr) { + struct pcie_port *pp = &imx6_pcie->pp; u32 val; int ret; val = addr << PCIE_PHY_CTRL_DATA_LOC; - writel(val, dbi_base + PCIE_PHY_CTRL); + dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, val); val |= (0x1 << PCIE_PHY_CTRL_CAP_ADR_LOC); - writel(val, dbi_base + PCIE_PHY_CTRL); + dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, val); - ret = pcie_phy_poll_ack(dbi_base, 1); + ret = pcie_phy_poll_ack(imx6_pcie, 1); if (ret) return ret; val = addr << PCIE_PHY_CTRL_DATA_LOC; - writel(val, dbi_base + PCIE_PHY_CTRL); + dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, val); - return pcie_phy_poll_ack(dbi_base, 0); + return pcie_phy_poll_ack(imx6_pcie, 0); } /* Read from the 16-bit PCIe PHY control registers (not memory-mapped) */ -static int pcie_phy_read(void __iomem *dbi_base, int addr, int *data) +static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data) { + struct pcie_port *pp = &imx6_pcie->pp; u32 val, phy_ctl; int ret; - ret = pcie_phy_wait_ack(dbi_base, addr); + ret = pcie_phy_wait_ack(imx6_pcie, addr); if (ret) return ret; /* assert Read signal */ phy_ctl = 0x1 << PCIE_PHY_CTRL_RD_LOC; - writel(phy_ctl, dbi_base + PCIE_PHY_CTRL); + dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, phy_ctl); - ret = pcie_phy_poll_ack(dbi_base, 1); + ret = pcie_phy_poll_ack(imx6_pcie, 1); if (ret) return ret; - val = readl(dbi_base + PCIE_PHY_STAT); + val = dw_pcie_readl_rc(pp, PCIE_PHY_STAT); *data = val & 0xffff; /* deassert Read signal */ - writel(0x00, dbi_base + PCIE_PHY_CTRL); + dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, 0x00); - return pcie_phy_poll_ack(dbi_base, 0); + return pcie_phy_poll_ack(imx6_pcie, 0); } -static int pcie_phy_write(void __iomem *dbi_base, int addr, int data) +static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) { + struct pcie_port *pp = &imx6_pcie->pp; u32 var; int ret; /* write addr */ /* cap addr */ - ret = pcie_phy_wait_ack(dbi_base, addr); + ret = pcie_phy_wait_ack(imx6_pcie, addr); if (ret) return ret; var = data << PCIE_PHY_CTRL_DATA_LOC; - writel(var, dbi_base + PCIE_PHY_CTRL); + dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, var); /* capture data */ var |= (0x1 << PCIE_PHY_CTRL_CAP_DAT_LOC); - writel(var, dbi_base + PCIE_PHY_CTRL); + dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, var); - ret = pcie_phy_poll_ack(dbi_base, 1); + ret = pcie_phy_poll_ack(imx6_pcie, 1); if (ret) return ret; /* deassert cap data */ var = data << PCIE_PHY_CTRL_DATA_LOC; - writel(var, dbi_base + PCIE_PHY_CTRL); + dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, var); /* wait for ack de-assertion */ - ret = pcie_phy_poll_ack(dbi_base, 0); + ret = pcie_phy_poll_ack(imx6_pcie, 0); if (ret) return ret; /* assert wr signal */ var = 0x1 << PCIE_PHY_CTRL_WR_LOC; - writel(var, dbi_base + PCIE_PHY_CTRL); + dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, var); /* wait for ack */ - ret = pcie_phy_poll_ack(dbi_base, 1); + ret = pcie_phy_poll_ack(imx6_pcie, 1); if (ret) return ret; /* deassert wr signal */ var = data << PCIE_PHY_CTRL_DATA_LOC; - writel(var, dbi_base + PCIE_PHY_CTRL); + dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, var); /* wait for ack de-assertion */ - ret = pcie_phy_poll_ack(dbi_base, 0); + ret = pcie_phy_poll_ack(imx6_pcie, 0); if (ret) return ret; - writel(0x0, dbi_base + PCIE_PHY_CTRL); + dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, 0x0); return 0; } -static void imx6_pcie_reset_phy(struct pcie_port *pp) +static void imx6_pcie_reset_phy(struct imx6_pcie *imx6_pcie) { u32 tmp; - pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &tmp); + pcie_phy_read(imx6_pcie, PHY_RX_OVRD_IN_LO, &tmp); tmp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN | PHY_RX_OVRD_IN_LO_RX_PLL_EN); - pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, tmp); + pcie_phy_write(imx6_pcie, PHY_RX_OVRD_IN_LO, tmp); usleep_range(2000, 3000); - pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &tmp); + pcie_phy_read(imx6_pcie, PHY_RX_OVRD_IN_LO, &tmp); tmp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN | PHY_RX_OVRD_IN_LO_RX_PLL_EN); - pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, tmp); + pcie_phy_write(imx6_pcie, PHY_RX_OVRD_IN_LO, tmp); } /* Added for PCI abort handling */ @@ -242,9 +245,9 @@ static int imx6q_pcie_abort_handler(unsigned long addr, return 0; } -static int imx6_pcie_assert_core_reset(struct pcie_port *pp) +static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) { - struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); + struct pcie_port *pp = &imx6_pcie->pp; u32 val, gpr1, gpr12; switch (imx6_pcie->variant) { @@ -281,10 +284,10 @@ static int imx6_pcie_assert_core_reset(struct pcie_port *pp) if ((gpr1 & IMX6Q_GPR1_PCIE_REF_CLK_EN) && (gpr12 & IMX6Q_GPR12_PCIE_CTL_2)) { - val = readl(pp->dbi_base + PCIE_PL_PFLR); + val = dw_pcie_readl_rc(pp, PCIE_PL_PFLR); val &= ~PCIE_PL_PFLR_LINK_STATE_MASK; val |= PCIE_PL_PFLR_FORCE_LINK; - writel(val, pp->dbi_base + PCIE_PL_PFLR); + dw_pcie_writel_rc(pp, PCIE_PL_PFLR, val); regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, IMX6Q_GPR12_PCIE_CTL_2, 0 << 10); @@ -296,20 +299,19 @@ static int imx6_pcie_assert_core_reset(struct pcie_port *pp) IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16); break; } - - return 0; } static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) { struct pcie_port *pp = &imx6_pcie->pp; + struct device *dev = pp->dev; int ret = 0; switch (imx6_pcie->variant) { case IMX6SX: ret = clk_prepare_enable(imx6_pcie->pcie_inbound_axi); if (ret) { - dev_err(pp->dev, "unable to enable pcie_axi clock\n"); + dev_err(dev, "unable to enable pcie_axi clock\n"); break; } @@ -336,32 +338,33 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) return ret; } -static int imx6_pcie_deassert_core_reset(struct pcie_port *pp) +static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) { - struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); + struct pcie_port *pp = &imx6_pcie->pp; + struct device *dev = pp->dev; int ret; ret = clk_prepare_enable(imx6_pcie->pcie_phy); if (ret) { - dev_err(pp->dev, "unable to enable pcie_phy clock\n"); - goto err_pcie_phy; + dev_err(dev, "unable to enable pcie_phy clock\n"); + return; } ret = clk_prepare_enable(imx6_pcie->pcie_bus); if (ret) { - dev_err(pp->dev, "unable to enable pcie_bus clock\n"); + dev_err(dev, "unable to enable pcie_bus clock\n"); goto err_pcie_bus; } ret = clk_prepare_enable(imx6_pcie->pcie); if (ret) { - dev_err(pp->dev, "unable to enable pcie clock\n"); + dev_err(dev, "unable to enable pcie clock\n"); goto err_pcie; } ret = imx6_pcie_enable_ref_clk(imx6_pcie); if (ret) { - dev_err(pp->dev, "unable to enable pcie ref clock\n"); + dev_err(dev, "unable to enable pcie ref clock\n"); goto err_ref_clk; } @@ -392,7 +395,7 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp) break; } - return 0; + return; err_ref_clk: clk_disable_unprepare(imx6_pcie->pcie); @@ -400,14 +403,10 @@ err_pcie: clk_disable_unprepare(imx6_pcie->pcie_bus); err_pcie_bus: clk_disable_unprepare(imx6_pcie->pcie_phy); -err_pcie_phy: - return ret; } -static void imx6_pcie_init_phy(struct pcie_port *pp) +static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) { - struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); - if (imx6_pcie->variant == IMX6SX) regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, IMX6SX_GPR12_PCIE_RX_EQ_MASK, @@ -439,45 +438,52 @@ static void imx6_pcie_init_phy(struct pcie_port *pp) imx6_pcie->tx_swing_low << 25); } -static int imx6_pcie_wait_for_link(struct pcie_port *pp) +static int imx6_pcie_wait_for_link(struct imx6_pcie *imx6_pcie) { + struct pcie_port *pp = &imx6_pcie->pp; + struct device *dev = pp->dev; + /* check if the link is up or not */ if (!dw_pcie_wait_for_link(pp)) return 0; - dev_dbg(pp->dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n", - readl(pp->dbi_base + PCIE_PHY_DEBUG_R0), - readl(pp->dbi_base + PCIE_PHY_DEBUG_R1)); + dev_dbg(dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n", + dw_pcie_readl_rc(pp, PCIE_PHY_DEBUG_R0), + dw_pcie_readl_rc(pp, PCIE_PHY_DEBUG_R1)); return -ETIMEDOUT; } -static int imx6_pcie_wait_for_speed_change(struct pcie_port *pp) +static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie) { + struct pcie_port *pp = &imx6_pcie->pp; + struct device *dev = pp->dev; u32 tmp; unsigned int retries; for (retries = 0; retries < 200; retries++) { - tmp = readl(pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + tmp = dw_pcie_readl_rc(pp, PCIE_LINK_WIDTH_SPEED_CONTROL); /* Test if the speed change finished. */ if (!(tmp & PORT_LOGIC_SPEED_CHANGE)) return 0; usleep_range(100, 1000); } - dev_err(pp->dev, "Speed change timeout\n"); + dev_err(dev, "Speed change timeout\n"); return -EINVAL; } static irqreturn_t imx6_pcie_msi_handler(int irq, void *arg) { - struct pcie_port *pp = arg; + struct imx6_pcie *imx6_pcie = arg; + struct pcie_port *pp = &imx6_pcie->pp; return dw_handle_msi_irq(pp); } -static int imx6_pcie_establish_link(struct pcie_port *pp) +static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) { - struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); + struct pcie_port *pp = &imx6_pcie->pp; + struct device *dev = pp->dev; u32 tmp; int ret; @@ -486,76 +492,73 @@ static int imx6_pcie_establish_link(struct pcie_port *pp) * started in Gen2 mode, there is a possibility the devices on the * bus will not be detected at all. This happens with PCIe switches. */ - tmp = readl(pp->dbi_base + PCIE_RC_LCR); + tmp = dw_pcie_readl_rc(pp, PCIE_RC_LCR); tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1; - writel(tmp, pp->dbi_base + PCIE_RC_LCR); + dw_pcie_writel_rc(pp, PCIE_RC_LCR, tmp); /* Start LTSSM. */ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, IMX6Q_GPR12_PCIE_CTL_2, 1 << 10); - ret = imx6_pcie_wait_for_link(pp); + ret = imx6_pcie_wait_for_link(imx6_pcie); if (ret) { - dev_info(pp->dev, "Link never came up\n"); + dev_info(dev, "Link never came up\n"); goto err_reset_phy; } if (imx6_pcie->link_gen == 2) { /* Allow Gen2 mode after the link is up. */ - tmp = readl(pp->dbi_base + PCIE_RC_LCR); + tmp = dw_pcie_readl_rc(pp, PCIE_RC_LCR); tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2; - writel(tmp, pp->dbi_base + PCIE_RC_LCR); + dw_pcie_writel_rc(pp, PCIE_RC_LCR, tmp); } else { - dev_info(pp->dev, "Link: Gen2 disabled\n"); + dev_info(dev, "Link: Gen2 disabled\n"); } /* * Start Directed Speed Change so the best possible speed both link * partners support can be negotiated. */ - tmp = readl(pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + tmp = dw_pcie_readl_rc(pp, PCIE_LINK_WIDTH_SPEED_CONTROL); tmp |= PORT_LOGIC_SPEED_CHANGE; - writel(tmp, pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + dw_pcie_writel_rc(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp); - ret = imx6_pcie_wait_for_speed_change(pp); + ret = imx6_pcie_wait_for_speed_change(imx6_pcie); if (ret) { - dev_err(pp->dev, "Failed to bring link up!\n"); + dev_err(dev, "Failed to bring link up!\n"); goto err_reset_phy; } /* Make sure link training is finished as well! */ - ret = imx6_pcie_wait_for_link(pp); + ret = imx6_pcie_wait_for_link(imx6_pcie); if (ret) { - dev_err(pp->dev, "Failed to bring link up!\n"); + dev_err(dev, "Failed to bring link up!\n"); goto err_reset_phy; } - tmp = readl(pp->dbi_base + PCIE_RC_LCSR); - dev_info(pp->dev, "Link up, Gen%i\n", (tmp >> 16) & 0xf); + tmp = dw_pcie_readl_rc(pp, PCIE_RC_LCSR); + dev_info(dev, "Link up, Gen%i\n", (tmp >> 16) & 0xf); return 0; err_reset_phy: - dev_dbg(pp->dev, "PHY DEBUG_R0=0x%08x DEBUG_R1=0x%08x\n", - readl(pp->dbi_base + PCIE_PHY_DEBUG_R0), - readl(pp->dbi_base + PCIE_PHY_DEBUG_R1)); - imx6_pcie_reset_phy(pp); - + dev_dbg(dev, "PHY DEBUG_R0=0x%08x DEBUG_R1=0x%08x\n", + dw_pcie_readl_rc(pp, PCIE_PHY_DEBUG_R0), + dw_pcie_readl_rc(pp, PCIE_PHY_DEBUG_R1)); + imx6_pcie_reset_phy(imx6_pcie); return ret; } static void imx6_pcie_host_init(struct pcie_port *pp) { - imx6_pcie_assert_core_reset(pp); - - imx6_pcie_init_phy(pp); - - imx6_pcie_deassert_core_reset(pp); + struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); + imx6_pcie_assert_core_reset(imx6_pcie); + imx6_pcie_init_phy(imx6_pcie); + imx6_pcie_deassert_core_reset(imx6_pcie); dw_pcie_setup_rc(pp); - - imx6_pcie_establish_link(pp); + imx6_pcie_establish_link(imx6_pcie); if (IS_ENABLED(CONFIG_PCI_MSI)) dw_pcie_msi_init(pp); @@ -563,7 +566,7 @@ static void imx6_pcie_host_init(struct pcie_port *pp) static int imx6_pcie_link_up(struct pcie_port *pp) { - return readl(pp->dbi_base + PCIE_PHY_DEBUG_R1) & + return dw_pcie_readl_rc(pp, PCIE_PHY_DEBUG_R1) & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP; } @@ -572,24 +575,26 @@ static struct pcie_host_ops imx6_pcie_host_ops = { .host_init = imx6_pcie_host_init, }; -static int __init imx6_add_pcie_port(struct pcie_port *pp, - struct platform_device *pdev) +static int __init imx6_add_pcie_port(struct imx6_pcie *imx6_pcie, + struct platform_device *pdev) { + struct pcie_port *pp = &imx6_pcie->pp; + struct device *dev = pp->dev; int ret; if (IS_ENABLED(CONFIG_PCI_MSI)) { pp->msi_irq = platform_get_irq_byname(pdev, "msi"); if (pp->msi_irq <= 0) { - dev_err(&pdev->dev, "failed to get MSI irq\n"); + dev_err(dev, "failed to get MSI irq\n"); return -ENODEV; } - ret = devm_request_irq(&pdev->dev, pp->msi_irq, + ret = devm_request_irq(dev, pp->msi_irq, imx6_pcie_msi_handler, IRQF_SHARED | IRQF_NO_THREAD, - "mx6-pcie-msi", pp); + "mx6-pcie-msi", imx6_pcie); if (ret) { - dev_err(&pdev->dev, "failed to request MSI irq\n"); + dev_err(dev, "failed to request MSI irq\n"); return ret; } } @@ -599,7 +604,7 @@ static int __init imx6_add_pcie_port(struct pcie_port *pp, ret = dw_pcie_host_init(pp); if (ret) { - dev_err(&pdev->dev, "failed to initialize host\n"); + dev_err(dev, "failed to initialize host\n"); return ret; } @@ -608,75 +613,72 @@ static int __init imx6_add_pcie_port(struct pcie_port *pp, static int __init imx6_pcie_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct imx6_pcie *imx6_pcie; struct pcie_port *pp; - struct device_node *np = pdev->dev.of_node; struct resource *dbi_base; - struct device_node *node = pdev->dev.of_node; + struct device_node *node = dev->of_node; int ret; - imx6_pcie = devm_kzalloc(&pdev->dev, sizeof(*imx6_pcie), GFP_KERNEL); + imx6_pcie = devm_kzalloc(dev, sizeof(*imx6_pcie), GFP_KERNEL); if (!imx6_pcie) return -ENOMEM; pp = &imx6_pcie->pp; - pp->dev = &pdev->dev; + pp->dev = dev; imx6_pcie->variant = - (enum imx6_pcie_variants)of_device_get_match_data(&pdev->dev); + (enum imx6_pcie_variants)of_device_get_match_data(dev); /* Added for PCI abort handling */ hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0, "imprecise external abort"); dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pp->dbi_base = devm_ioremap_resource(&pdev->dev, dbi_base); + pp->dbi_base = devm_ioremap_resource(dev, dbi_base); if (IS_ERR(pp->dbi_base)) return PTR_ERR(pp->dbi_base); /* Fetch GPIOs */ - imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); - imx6_pcie->gpio_active_high = of_property_read_bool(np, + imx6_pcie->reset_gpio = of_get_named_gpio(node, "reset-gpio", 0); + imx6_pcie->gpio_active_high = of_property_read_bool(node, "reset-gpio-active-high"); if (gpio_is_valid(imx6_pcie->reset_gpio)) { - ret = devm_gpio_request_one(&pdev->dev, imx6_pcie->reset_gpio, + ret = devm_gpio_request_one(dev, imx6_pcie->reset_gpio, imx6_pcie->gpio_active_high ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, "PCIe reset"); if (ret) { - dev_err(&pdev->dev, "unable to get reset gpio\n"); + dev_err(dev, "unable to get reset gpio\n"); return ret; } } /* Fetch clocks */ - imx6_pcie->pcie_phy = devm_clk_get(&pdev->dev, "pcie_phy"); + imx6_pcie->pcie_phy = devm_clk_get(dev, "pcie_phy"); if (IS_ERR(imx6_pcie->pcie_phy)) { - dev_err(&pdev->dev, - "pcie_phy clock source missing or invalid\n"); + dev_err(dev, "pcie_phy clock source missing or invalid\n"); return PTR_ERR(imx6_pcie->pcie_phy); } - imx6_pcie->pcie_bus = devm_clk_get(&pdev->dev, "pcie_bus"); + imx6_pcie->pcie_bus = devm_clk_get(dev, "pcie_bus"); if (IS_ERR(imx6_pcie->pcie_bus)) { - dev_err(&pdev->dev, - "pcie_bus clock source missing or invalid\n"); + dev_err(dev, "pcie_bus clock source missing or invalid\n"); return PTR_ERR(imx6_pcie->pcie_bus); } - imx6_pcie->pcie = devm_clk_get(&pdev->dev, "pcie"); + imx6_pcie->pcie = devm_clk_get(dev, "pcie"); if (IS_ERR(imx6_pcie->pcie)) { - dev_err(&pdev->dev, - "pcie clock source missing or invalid\n"); + dev_err(dev, "pcie clock source missing or invalid\n"); return PTR_ERR(imx6_pcie->pcie); } if (imx6_pcie->variant == IMX6SX) { - imx6_pcie->pcie_inbound_axi = devm_clk_get(&pdev->dev, + imx6_pcie->pcie_inbound_axi = devm_clk_get(dev, "pcie_inbound_axi"); if (IS_ERR(imx6_pcie->pcie_inbound_axi)) { - dev_err(&pdev->dev, + dev_err(dev, "pcie_incbound_axi clock missing or invalid\n"); return PTR_ERR(imx6_pcie->pcie_inbound_axi); } @@ -686,7 +688,7 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) imx6_pcie->iomuxc_gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); if (IS_ERR(imx6_pcie->iomuxc_gpr)) { - dev_err(&pdev->dev, "unable to find iomuxc registers\n"); + dev_err(dev, "unable to find iomuxc registers\n"); return PTR_ERR(imx6_pcie->iomuxc_gpr); } @@ -712,12 +714,12 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) imx6_pcie->tx_swing_low = 127; /* Limit link speed */ - ret = of_property_read_u32(pp->dev->of_node, "fsl,max-link-speed", + ret = of_property_read_u32(node, "fsl,max-link-speed", &imx6_pcie->link_gen); if (ret) imx6_pcie->link_gen = 1; - ret = imx6_add_pcie_port(pp, pdev); + ret = imx6_add_pcie_port(imx6_pcie, pdev); if (ret < 0) return ret; @@ -730,7 +732,7 @@ static void imx6_pcie_shutdown(struct platform_device *pdev) struct imx6_pcie *imx6_pcie = platform_get_drvdata(pdev); /* bring down link, so bootloader gets clean state in case of reboot */ - imx6_pcie_assert_core_reset(&imx6_pcie->pp); + imx6_pcie_assert_core_reset(imx6_pcie); } static const struct of_device_id imx6_pcie_of_match[] = { diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c index 41515092eb0d..9397c4667106 100644 --- a/drivers/pci/host/pci-keystone-dw.c +++ b/drivers/pci/host/pci-keystone-dw.c @@ -88,13 +88,24 @@ phys_addr_t ks_dw_pcie_get_msi_addr(struct pcie_port *pp) return ks_pcie->app.start + MSI_IRQ; } +static u32 ks_dw_app_readl(struct keystone_pcie *ks_pcie, u32 offset) +{ + return readl(ks_pcie->va_app_base + offset); +} + +static void ks_dw_app_writel(struct keystone_pcie *ks_pcie, u32 offset, u32 val) +{ + writel(val, ks_pcie->va_app_base + offset); +} + void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset) { struct pcie_port *pp = &ks_pcie->pp; + struct device *dev = pp->dev; u32 pending, vector; int src, virq; - pending = readl(ks_pcie->va_app_base + MSI0_IRQ_STATUS + (offset << 4)); + pending = ks_dw_app_readl(ks_pcie, MSI0_IRQ_STATUS + (offset << 4)); /* * MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit @@ -104,7 +115,7 @@ void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset) if (BIT(src) & pending) { vector = offset + (src << 3); virq = irq_linear_revmap(pp->irq_domain, vector); - dev_dbg(pp->dev, "irq: bit %d, vector %d, virq %d\n", + dev_dbg(dev, "irq: bit %d, vector %d, virq %d\n", src, vector, virq); generic_handle_irq(virq); } @@ -124,9 +135,9 @@ static void ks_dw_pcie_msi_irq_ack(struct irq_data *d) offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); update_reg_offset_bit_pos(offset, ®_offset, &bit_pos); - writel(BIT(bit_pos), - ks_pcie->va_app_base + MSI0_IRQ_STATUS + (reg_offset << 4)); - writel(reg_offset + MSI_IRQ_OFFSET, ks_pcie->va_app_base + IRQ_EOI); + ks_dw_app_writel(ks_pcie, MSI0_IRQ_STATUS + (reg_offset << 4), + BIT(bit_pos)); + ks_dw_app_writel(ks_pcie, IRQ_EOI, reg_offset + MSI_IRQ_OFFSET); } void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) @@ -135,8 +146,8 @@ void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) struct keystone_pcie *ks_pcie = to_keystone_pcie(pp); update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); - writel(BIT(bit_pos), - ks_pcie->va_app_base + MSI0_IRQ_ENABLE_SET + (reg_offset << 4)); + ks_dw_app_writel(ks_pcie, MSI0_IRQ_ENABLE_SET + (reg_offset << 4), + BIT(bit_pos)); } void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) @@ -145,8 +156,8 @@ void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) struct keystone_pcie *ks_pcie = to_keystone_pcie(pp); update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); - writel(BIT(bit_pos), - ks_pcie->va_app_base + MSI0_IRQ_ENABLE_CLR + (reg_offset << 4)); + ks_dw_app_writel(ks_pcie, MSI0_IRQ_ENABLE_CLR + (reg_offset << 4), + BIT(bit_pos)); } static void ks_dw_pcie_msi_irq_mask(struct irq_data *d) @@ -215,6 +226,7 @@ static const struct irq_domain_ops ks_dw_pcie_msi_domain_ops = { int ks_dw_pcie_msi_host_init(struct pcie_port *pp, struct msi_controller *chip) { struct keystone_pcie *ks_pcie = to_keystone_pcie(pp); + struct device *dev = pp->dev; int i; pp->irq_domain = irq_domain_add_linear(ks_pcie->msi_intc_np, @@ -222,7 +234,7 @@ int ks_dw_pcie_msi_host_init(struct pcie_port *pp, struct msi_controller *chip) &ks_dw_pcie_msi_domain_ops, chip); if (!pp->irq_domain) { - dev_err(pp->dev, "irq domain init failed\n"); + dev_err(dev, "irq domain init failed\n"); return -ENXIO; } @@ -237,47 +249,47 @@ void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie) int i; for (i = 0; i < MAX_LEGACY_IRQS; i++) - writel(0x1, ks_pcie->va_app_base + IRQ_ENABLE_SET + (i << 4)); + ks_dw_app_writel(ks_pcie, IRQ_ENABLE_SET + (i << 4), 0x1); } void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset) { struct pcie_port *pp = &ks_pcie->pp; + struct device *dev = pp->dev; u32 pending; int virq; - pending = readl(ks_pcie->va_app_base + IRQ_STATUS + (offset << 4)); + pending = ks_dw_app_readl(ks_pcie, IRQ_STATUS + (offset << 4)); if (BIT(0) & pending) { virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset); - dev_dbg(pp->dev, ": irq: irq_offset %d, virq %d\n", offset, - virq); + dev_dbg(dev, ": irq: irq_offset %d, virq %d\n", offset, virq); generic_handle_irq(virq); } /* EOI the INTx interrupt */ - writel(offset, ks_pcie->va_app_base + IRQ_EOI); + ks_dw_app_writel(ks_pcie, IRQ_EOI, offset); } -void ks_dw_pcie_enable_error_irq(void __iomem *reg_base) +void ks_dw_pcie_enable_error_irq(struct keystone_pcie *ks_pcie) { - writel(ERR_IRQ_ALL, reg_base + ERR_IRQ_ENABLE_SET); + ks_dw_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL); } -irqreturn_t ks_dw_pcie_handle_error_irq(struct device *dev, - void __iomem *reg_base) +irqreturn_t ks_dw_pcie_handle_error_irq(struct keystone_pcie *ks_pcie) { u32 status; - status = readl(reg_base + ERR_IRQ_STATUS_RAW) & ERR_IRQ_ALL; + status = ks_dw_app_readl(ks_pcie, ERR_IRQ_STATUS_RAW) & ERR_IRQ_ALL; if (!status) return IRQ_NONE; if (status & ERR_FATAL_IRQ) - dev_err(dev, "fatal error (status %#010x)\n", status); + dev_err(ks_pcie->pp.dev, "fatal error (status %#010x)\n", + status); /* Ack the IRQ; status bits are RW1C */ - writel(status, reg_base + ERR_IRQ_STATUS); + ks_dw_app_writel(ks_pcie, ERR_IRQ_STATUS, status); return IRQ_HANDLED; } @@ -322,15 +334,15 @@ static const struct irq_domain_ops ks_dw_pcie_legacy_irq_domain_ops = { * Since modification of dbi_cs2 involves different clock domain, read the * status back to ensure the transition is complete. */ -static void ks_dw_pcie_set_dbi_mode(void __iomem *reg_virt) +static void ks_dw_pcie_set_dbi_mode(struct keystone_pcie *ks_pcie) { u32 val; - writel(DBI_CS2_EN_VAL | readl(reg_virt + CMD_STATUS), - reg_virt + CMD_STATUS); + val = ks_dw_app_readl(ks_pcie, CMD_STATUS); + ks_dw_app_writel(ks_pcie, CMD_STATUS, DBI_CS2_EN_VAL | val); do { - val = readl(reg_virt + CMD_STATUS); + val = ks_dw_app_readl(ks_pcie, CMD_STATUS); } while (!(val & DBI_CS2_EN_VAL)); } @@ -340,15 +352,15 @@ static void ks_dw_pcie_set_dbi_mode(void __iomem *reg_virt) * Since modification of dbi_cs2 involves different clock domain, read the * status back to ensure the transition is complete. */ -static void ks_dw_pcie_clear_dbi_mode(void __iomem *reg_virt) +static void ks_dw_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie) { u32 val; - writel(~DBI_CS2_EN_VAL & readl(reg_virt + CMD_STATUS), - reg_virt + CMD_STATUS); + val = ks_dw_app_readl(ks_pcie, CMD_STATUS); + ks_dw_app_writel(ks_pcie, CMD_STATUS, ~DBI_CS2_EN_VAL & val); do { - val = readl(reg_virt + CMD_STATUS); + val = ks_dw_app_readl(ks_pcie, CMD_STATUS); } while (val & DBI_CS2_EN_VAL); } @@ -357,28 +369,29 @@ void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) struct pcie_port *pp = &ks_pcie->pp; u32 start = pp->mem->start, end = pp->mem->end; int i, tr_size; + u32 val; /* Disable BARs for inbound access */ - ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base); - writel(0, pp->dbi_base + PCI_BASE_ADDRESS_0); - writel(0, pp->dbi_base + PCI_BASE_ADDRESS_1); - ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base); + ks_dw_pcie_set_dbi_mode(ks_pcie); + dw_pcie_writel_rc(pp, PCI_BASE_ADDRESS_0, 0); + dw_pcie_writel_rc(pp, PCI_BASE_ADDRESS_1, 0); + ks_dw_pcie_clear_dbi_mode(ks_pcie); /* Set outbound translation size per window division */ - writel(CFG_PCIM_WIN_SZ_IDX & 0x7, ks_pcie->va_app_base + OB_SIZE); + ks_dw_app_writel(ks_pcie, OB_SIZE, CFG_PCIM_WIN_SZ_IDX & 0x7); tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M; /* Using Direct 1:1 mapping of RC <-> PCI memory space */ for (i = 0; (i < CFG_PCIM_WIN_CNT) && (start < end); i++) { - writel(start | 1, ks_pcie->va_app_base + OB_OFFSET_INDEX(i)); - writel(0, ks_pcie->va_app_base + OB_OFFSET_HI(i)); + ks_dw_app_writel(ks_pcie, OB_OFFSET_INDEX(i), start | 1); + ks_dw_app_writel(ks_pcie, OB_OFFSET_HI(i), 0); start += tr_size; } /* Enable OB translation */ - writel(OB_XLAT_EN_VAL | readl(ks_pcie->va_app_base + CMD_STATUS), - ks_pcie->va_app_base + CMD_STATUS); + val = ks_dw_app_readl(ks_pcie, CMD_STATUS); + ks_dw_app_writel(ks_pcie, CMD_STATUS, OB_XLAT_EN_VAL | val); } /** @@ -418,7 +431,7 @@ static void __iomem *ks_pcie_cfg_setup(struct keystone_pcie *ks_pcie, u8 bus, if (bus != 1) regval |= BIT(24); - writel(regval, ks_pcie->va_app_base + CFG_SETUP); + ks_dw_app_writel(ks_pcie, CFG_SETUP, regval); return pp->va_cfg0_base; } @@ -456,19 +469,19 @@ void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp) struct keystone_pcie *ks_pcie = to_keystone_pcie(pp); /* Configure and set up BAR0 */ - ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base); + ks_dw_pcie_set_dbi_mode(ks_pcie); /* Enable BAR0 */ - writel(1, pp->dbi_base + PCI_BASE_ADDRESS_0); - writel(SZ_4K - 1, pp->dbi_base + PCI_BASE_ADDRESS_0); + dw_pcie_writel_rc(pp, PCI_BASE_ADDRESS_0, 1); + dw_pcie_writel_rc(pp, PCI_BASE_ADDRESS_0, SZ_4K - 1); - ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base); + ks_dw_pcie_clear_dbi_mode(ks_pcie); /* * For BAR0, just setting bus address for inbound writes (MSI) should * be sufficient. Use physical address to avoid any conflicts. */ - writel(ks_pcie->app.start, pp->dbi_base + PCI_BASE_ADDRESS_0); + dw_pcie_writel_rc(pp, PCI_BASE_ADDRESS_0, ks_pcie->app.start); } /** @@ -476,8 +489,9 @@ void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp) */ int ks_dw_pcie_link_up(struct pcie_port *pp) { - u32 val = readl(pp->dbi_base + DEBUG0); + u32 val; + val = dw_pcie_readl_rc(pp, DEBUG0); return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0; } @@ -486,13 +500,13 @@ void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie) u32 val; /* Disable Link training */ - val = readl(ks_pcie->va_app_base + CMD_STATUS); + val = ks_dw_app_readl(ks_pcie, CMD_STATUS); val &= ~LTSSM_EN_VAL; - writel(LTSSM_EN_VAL | val, ks_pcie->va_app_base + CMD_STATUS); + ks_dw_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); /* Initiate Link Training */ - val = readl(ks_pcie->va_app_base + CMD_STATUS); - writel(LTSSM_EN_VAL | val, ks_pcie->va_app_base + CMD_STATUS); + val = ks_dw_app_readl(ks_pcie, CMD_STATUS); + ks_dw_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); } /** @@ -506,12 +520,13 @@ int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie, struct device_node *msi_intc_np) { struct pcie_port *pp = &ks_pcie->pp; - struct platform_device *pdev = to_platform_device(pp->dev); + struct device *dev = pp->dev; + struct platform_device *pdev = to_platform_device(dev); struct resource *res; /* Index 0 is the config reg. space address */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pp->dbi_base = devm_ioremap_resource(pp->dev, res); + pp->dbi_base = devm_ioremap_resource(dev, res); if (IS_ERR(pp->dbi_base)) return PTR_ERR(pp->dbi_base); @@ -524,7 +539,7 @@ int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie, /* Index 1 is the application reg. space address */ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - ks_pcie->va_app_base = devm_ioremap_resource(pp->dev, res); + ks_pcie->va_app_base = devm_ioremap_resource(dev, res); if (IS_ERR(ks_pcie->va_app_base)) return PTR_ERR(ks_pcie->va_app_base); @@ -537,7 +552,7 @@ int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie, &ks_dw_pcie_legacy_irq_domain_ops, NULL); if (!ks_pcie->legacy_irq_domain) { - dev_err(pp->dev, "Failed to add irq domain for legacy irqs\n"); + dev_err(dev, "Failed to add irq domain for legacy irqs\n"); return -EINVAL; } diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c index 82b461b5b08a..043c19a05da1 100644 --- a/drivers/pci/host/pci-keystone.c +++ b/drivers/pci/host/pci-keystone.c @@ -89,12 +89,13 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_mrrs); static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) { struct pcie_port *pp = &ks_pcie->pp; + struct device *dev = pp->dev; unsigned int retries; dw_pcie_setup_rc(pp); if (dw_pcie_link_up(pp)) { - dev_err(pp->dev, "Link already up\n"); + dev_err(dev, "Link already up\n"); return 0; } @@ -105,7 +106,7 @@ static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) return 0; } - dev_err(pp->dev, "phy link never came up\n"); + dev_err(dev, "phy link never came up\n"); return -ETIMEDOUT; } @@ -115,9 +116,10 @@ static void ks_pcie_msi_irq_handler(struct irq_desc *desc) struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc); u32 offset = irq - ks_pcie->msi_host_irqs[0]; struct pcie_port *pp = &ks_pcie->pp; + struct device *dev = pp->dev; struct irq_chip *chip = irq_desc_get_chip(desc); - dev_dbg(pp->dev, "%s, irq %d\n", __func__, irq); + dev_dbg(dev, "%s, irq %d\n", __func__, irq); /* * The chained irq handler installation would have replaced normal @@ -142,10 +144,11 @@ static void ks_pcie_legacy_irq_handler(struct irq_desc *desc) unsigned int irq = irq_desc_get_irq(desc); struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc); struct pcie_port *pp = &ks_pcie->pp; + struct device *dev = pp->dev; u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0]; struct irq_chip *chip = irq_desc_get_chip(desc); - dev_dbg(pp->dev, ": Handling legacy irq %d\n", irq); + dev_dbg(dev, ": Handling legacy irq %d\n", irq); /* * The chained irq handler installation would have replaced normal @@ -234,7 +237,7 @@ static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie) } if (ks_pcie->error_irq > 0) - ks_dw_pcie_enable_error_irq(ks_pcie->va_app_base); + ks_dw_pcie_enable_error_irq(ks_pcie); } /* @@ -302,14 +305,14 @@ static irqreturn_t pcie_err_irq_handler(int irq, void *priv) { struct keystone_pcie *ks_pcie = priv; - return ks_dw_pcie_handle_error_irq(ks_pcie->pp.dev, - ks_pcie->va_app_base); + return ks_dw_pcie_handle_error_irq(ks_pcie); } static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie, struct platform_device *pdev) { struct pcie_port *pp = &ks_pcie->pp; + struct device *dev = pp->dev; int ret; ret = ks_pcie_get_irq_controller_info(ks_pcie, @@ -332,12 +335,12 @@ static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie, */ ks_pcie->error_irq = irq_of_parse_and_map(ks_pcie->np, 0); if (ks_pcie->error_irq <= 0) - dev_info(&pdev->dev, "no error IRQ defined\n"); + dev_info(dev, "no error IRQ defined\n"); else { ret = request_irq(ks_pcie->error_irq, pcie_err_irq_handler, IRQF_SHARED, "pcie-error-irq", ks_pcie); if (ret < 0) { - dev_err(&pdev->dev, "failed to request error IRQ %d\n", + dev_err(dev, "failed to request error IRQ %d\n", ks_pcie->error_irq); return ret; } @@ -347,7 +350,7 @@ static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie, pp->ops = &keystone_pcie_host_ops; ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np); if (ret) { - dev_err(&pdev->dev, "failed to initialize host\n"); + dev_err(dev, "failed to initialize host\n"); return ret; } @@ -381,12 +384,12 @@ static int __init ks_pcie_probe(struct platform_device *pdev) struct phy *phy; int ret; - ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie), - GFP_KERNEL); + ks_pcie = devm_kzalloc(dev, sizeof(*ks_pcie), GFP_KERNEL); if (!ks_pcie) return -ENOMEM; pp = &ks_pcie->pp; + pp->dev = dev; /* initialize SerDes Phy if present */ phy = devm_phy_get(dev, "pcie-phy"); @@ -408,7 +411,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev) devm_iounmap(dev, reg_p); devm_release_mem_region(dev, res->start, resource_size(res)); - pp->dev = dev; ks_pcie->np = dev->of_node; platform_set_drvdata(pdev, ks_pcie); ks_pcie->clk = devm_clk_get(dev, "pcie"); diff --git a/drivers/pci/host/pci-keystone.h b/drivers/pci/host/pci-keystone.h index a5b0cb2ba4d7..bc54bafda068 100644 --- a/drivers/pci/host/pci-keystone.h +++ b/drivers/pci/host/pci-keystone.h @@ -17,8 +17,8 @@ #define MAX_LEGACY_HOST_IRQS 4 struct keystone_pcie { + struct pcie_port pp; /* pp.dbi_base is DT 0th res */ struct clk *clk; - struct pcie_port pp; /* PCI Device ID */ u32 device_id; int num_legacy_host_irqs; @@ -34,7 +34,7 @@ struct keystone_pcie { int error_irq; /* Application register space */ - void __iomem *va_app_base; + void __iomem *va_app_base; /* DT 1st resource */ struct resource app; }; @@ -45,9 +45,8 @@ phys_addr_t ks_dw_pcie_get_msi_addr(struct pcie_port *pp); /* Keystone specific PCI controller APIs */ void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie); void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset); -void ks_dw_pcie_enable_error_irq(void __iomem *reg_base); -irqreturn_t ks_dw_pcie_handle_error_irq(struct device *dev, - void __iomem *reg_base); +void ks_dw_pcie_enable_error_irq(struct keystone_pcie *ks_pcie); +irqreturn_t ks_dw_pcie_handle_error_irq(struct keystone_pcie *ks_pcie); int ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie, struct device_node *msi_intc_np); int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c index 114ba819277a..2cb7315e26d0 100644 --- a/drivers/pci/host/pci-layerscape.c +++ b/drivers/pci/host/pci-layerscape.c @@ -45,10 +45,9 @@ struct ls_pcie_drvdata { }; struct ls_pcie { - void __iomem *dbi; + struct pcie_port pp; /* pp.dbi_base is DT regs */ void __iomem *lut; struct regmap *scfg; - struct pcie_port pp; const struct ls_pcie_drvdata *drvdata; int index; }; @@ -59,7 +58,7 @@ static bool ls_pcie_is_bridge(struct ls_pcie *pcie) { u32 header_type; - header_type = ioread8(pcie->dbi + PCI_HEADER_TYPE); + header_type = ioread8(pcie->pp.dbi_base + PCI_HEADER_TYPE); header_type &= 0x7f; return header_type == PCI_HEADER_TYPE_BRIDGE; @@ -68,13 +67,13 @@ static bool ls_pcie_is_bridge(struct ls_pcie *pcie) /* Clear multi-function bit */ static void ls_pcie_clear_multifunction(struct ls_pcie *pcie) { - iowrite8(PCI_HEADER_TYPE_BRIDGE, pcie->dbi + PCI_HEADER_TYPE); + iowrite8(PCI_HEADER_TYPE_BRIDGE, pcie->pp.dbi_base + PCI_HEADER_TYPE); } /* Fix class value */ static void ls_pcie_fix_class(struct ls_pcie *pcie) { - iowrite16(PCI_CLASS_BRIDGE_PCI, pcie->dbi + PCI_CLASS_DEVICE); + iowrite16(PCI_CLASS_BRIDGE_PCI, pcie->pp.dbi_base + PCI_CLASS_DEVICE); } /* Drop MSG TLP except for Vendor MSG */ @@ -82,9 +81,9 @@ static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie) { u32 val; - val = ioread32(pcie->dbi + PCIE_STRFMR1); + val = ioread32(pcie->pp.dbi_base + PCIE_STRFMR1); val &= 0xDFFFFFFF; - iowrite32(val, pcie->dbi + PCIE_STRFMR1); + iowrite32(val, pcie->pp.dbi_base + PCIE_STRFMR1); } static int ls1021_pcie_link_up(struct pcie_port *pp) @@ -106,18 +105,19 @@ static int ls1021_pcie_link_up(struct pcie_port *pp) static void ls1021_pcie_host_init(struct pcie_port *pp) { + struct device *dev = pp->dev; struct ls_pcie *pcie = to_ls_pcie(pp); u32 index[2]; - pcie->scfg = syscon_regmap_lookup_by_phandle(pp->dev->of_node, + pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,pcie-scfg"); if (IS_ERR(pcie->scfg)) { - dev_err(pp->dev, "No syscfg phandle specified\n"); + dev_err(dev, "No syscfg phandle specified\n"); pcie->scfg = NULL; return; } - if (of_property_read_u32_array(pp->dev->of_node, + if (of_property_read_u32_array(dev->of_node, "fsl,pcie-scfg", index, 2)) { pcie->scfg = NULL; return; @@ -148,18 +148,19 @@ static void ls_pcie_host_init(struct pcie_port *pp) { struct ls_pcie *pcie = to_ls_pcie(pp); - iowrite32(1, pcie->dbi + PCIE_DBI_RO_WR_EN); + iowrite32(1, pcie->pp.dbi_base + PCIE_DBI_RO_WR_EN); ls_pcie_fix_class(pcie); ls_pcie_clear_multifunction(pcie); ls_pcie_drop_msg_tlp(pcie); - iowrite32(0, pcie->dbi + PCIE_DBI_RO_WR_EN); + iowrite32(0, pcie->pp.dbi_base + PCIE_DBI_RO_WR_EN); } static int ls_pcie_msi_host_init(struct pcie_port *pp, struct msi_controller *chip) { + struct device *dev = pp->dev; + struct device_node *np = dev->of_node; struct device_node *msi_node; - struct device_node *np = pp->dev->of_node; /* * The MSI domain is set by the generic of_msi_configure(). This @@ -169,7 +170,7 @@ static int ls_pcie_msi_host_init(struct pcie_port *pp, */ msi_node = of_parse_phandle(np, "msi-parent", 0); if (!msi_node) { - dev_err(pp->dev, "failed to find msi-parent\n"); + dev_err(dev, "failed to find msi-parent\n"); return -EINVAL; } @@ -212,19 +213,15 @@ static const struct of_device_id ls_pcie_of_match[] = { { }, }; -static int __init ls_add_pcie_port(struct pcie_port *pp, - struct platform_device *pdev) +static int __init ls_add_pcie_port(struct ls_pcie *pcie) { + struct pcie_port *pp = &pcie->pp; + struct device *dev = pp->dev; int ret; - struct ls_pcie *pcie = to_ls_pcie(pp); - - pp->dev = &pdev->dev; - pp->dbi_base = pcie->dbi; - pp->ops = pcie->drvdata->ops; ret = dw_pcie_host_init(pp); if (ret) { - dev_err(pp->dev, "failed to initialize host\n"); + dev_err(dev, "failed to initialize host\n"); return ret; } @@ -233,38 +230,42 @@ static int __init ls_add_pcie_port(struct pcie_port *pp, static int __init ls_pcie_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; const struct of_device_id *match; struct ls_pcie *pcie; + struct pcie_port *pp; struct resource *dbi_base; int ret; - match = of_match_device(ls_pcie_of_match, &pdev->dev); + match = of_match_device(ls_pcie_of_match, dev); if (!match) return -ENODEV; - pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); + pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); if (!pcie) return -ENOMEM; + pp = &pcie->pp; + pp->dev = dev; + pp->ops = pcie->drvdata->ops; + dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); - pcie->dbi = devm_ioremap_resource(&pdev->dev, dbi_base); - if (IS_ERR(pcie->dbi)) { - dev_err(&pdev->dev, "missing *regs* space\n"); - return PTR_ERR(pcie->dbi); + pcie->pp.dbi_base = devm_ioremap_resource(dev, dbi_base); + if (IS_ERR(pcie->pp.dbi_base)) { + dev_err(dev, "missing *regs* space\n"); + return PTR_ERR(pcie->pp.dbi_base); } pcie->drvdata = match->data; - pcie->lut = pcie->dbi + pcie->drvdata->lut_offset; + pcie->lut = pcie->pp.dbi_base + pcie->drvdata->lut_offset; if (!ls_pcie_is_bridge(pcie)) return -ENODEV; - ret = ls_add_pcie_port(&pcie->pp, pdev); + ret = ls_add_pcie_port(pcie); if (ret < 0) return ret; - platform_set_drvdata(pdev, pcie); - return 0; } diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index 307f81d6b479..45a89d969700 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -1190,13 +1190,13 @@ static void mvebu_pcie_powerdown(struct mvebu_pcie_port *port) static int mvebu_pcie_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct mvebu_pcie *pcie; - struct device_node *np = pdev->dev.of_node; + struct device_node *np = dev->of_node; struct device_node *child; int num, i, ret; - pcie = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pcie), - GFP_KERNEL); + pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); if (!pcie) return -ENOMEM; @@ -1206,7 +1206,7 @@ static int mvebu_pcie_probe(struct platform_device *pdev) /* Get the PCIe memory and I/O aperture */ mvebu_mbus_get_pcie_mem_aperture(&pcie->mem); if (resource_size(&pcie->mem) == 0) { - dev_err(&pdev->dev, "invalid memory aperture size\n"); + dev_err(dev, "invalid memory aperture size\n"); return -EINVAL; } @@ -1224,20 +1224,18 @@ static int mvebu_pcie_probe(struct platform_device *pdev) /* Get the bus range */ ret = of_pci_parse_bus_range(np, &pcie->busn); if (ret) { - dev_err(&pdev->dev, "failed to parse bus-range property: %d\n", - ret); + dev_err(dev, "failed to parse bus-range property: %d\n", ret); return ret; } - num = of_get_available_child_count(pdev->dev.of_node); + num = of_get_available_child_count(np); - pcie->ports = devm_kcalloc(&pdev->dev, num, sizeof(*pcie->ports), - GFP_KERNEL); + pcie->ports = devm_kcalloc(dev, num, sizeof(*pcie->ports), GFP_KERNEL); if (!pcie->ports) return -ENOMEM; i = 0; - for_each_available_child_of_node(pdev->dev.of_node, child) { + for_each_available_child_of_node(np, child) { struct mvebu_pcie_port *port = &pcie->ports[i]; ret = mvebu_pcie_parse_port(pcie, port, child); @@ -1266,8 +1264,7 @@ static int mvebu_pcie_probe(struct platform_device *pdev) port->base = mvebu_pcie_map_registers(pdev, child, port); if (IS_ERR(port->base)) { - dev_err(&pdev->dev, "%s: cannot map registers\n", - port->name); + dev_err(dev, "%s: cannot map registers\n", port->name); port->base = NULL; mvebu_pcie_powerdown(port); continue; diff --git a/drivers/pci/host/pci-rcar-gen2.c b/drivers/pci/host/pci-rcar-gen2.c index 597566f96f5e..1eeefa4df64c 100644 --- a/drivers/pci/host/pci-rcar-gen2.c +++ b/drivers/pci/host/pci-rcar-gen2.c @@ -154,10 +154,11 @@ static int rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) static irqreturn_t rcar_pci_err_irq(int irq, void *pw) { struct rcar_pci_priv *priv = pw; + struct device *dev = priv->dev; u32 status = ioread32(priv->reg + RCAR_PCI_INT_STATUS_REG); if (status & RCAR_PCI_INT_ALLERRORS) { - dev_err(priv->dev, "error irq: status %08x\n", status); + dev_err(dev, "error irq: status %08x\n", status); /* clear the error(s) */ iowrite32(status & RCAR_PCI_INT_ALLERRORS, @@ -170,13 +171,14 @@ static irqreturn_t rcar_pci_err_irq(int irq, void *pw) static void rcar_pci_setup_errirq(struct rcar_pci_priv *priv) { + struct device *dev = priv->dev; int ret; u32 val; - ret = devm_request_irq(priv->dev, priv->irq, rcar_pci_err_irq, + ret = devm_request_irq(dev, priv->irq, rcar_pci_err_irq, IRQF_SHARED, "error irq", priv); if (ret) { - dev_err(priv->dev, "cannot claim IRQ for error handling\n"); + dev_err(dev, "cannot claim IRQ for error handling\n"); return; } @@ -192,15 +194,16 @@ static inline void rcar_pci_setup_errirq(struct rcar_pci_priv *priv) { } static int rcar_pci_setup(int nr, struct pci_sys_data *sys) { struct rcar_pci_priv *priv = sys->private_data; + struct device *dev = priv->dev; void __iomem *reg = priv->reg; u32 val; int ret; - pm_runtime_enable(priv->dev); - pm_runtime_get_sync(priv->dev); + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); val = ioread32(reg + RCAR_PCI_UNIT_REV_REG); - dev_info(priv->dev, "PCI: bus%u revision %x\n", sys->busnr, val); + dev_info(dev, "PCI: bus%u revision %x\n", sys->busnr, val); /* Disable Direct Power Down State and assert reset */ val = ioread32(reg + RCAR_USBCTR_REG) & ~RCAR_USBCTR_DIRPD; @@ -275,7 +278,7 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys) /* Add PCI resources */ pci_add_resource(&sys->resources, &priv->mem_res); - ret = devm_request_pci_bus_resources(priv->dev, &sys->resources); + ret = devm_request_pci_bus_resources(dev, &sys->resources); if (ret < 0) return ret; @@ -311,6 +314,7 @@ static int pci_dma_range_parser_init(struct of_pci_range_parser *parser, static int rcar_pci_parse_map_dma_ranges(struct rcar_pci_priv *pci, struct device_node *np) { + struct device *dev = pci->dev; struct of_pci_range range; struct of_pci_range_parser parser; int index = 0; @@ -331,14 +335,14 @@ static int rcar_pci_parse_map_dma_ranges(struct rcar_pci_priv *pci, /* Catch HW limitations */ if (!(range.flags & IORESOURCE_PREFETCH)) { - dev_err(pci->dev, "window must be prefetchable\n"); + dev_err(dev, "window must be prefetchable\n"); return -EINVAL; } if (pci->window_addr) { u32 lowaddr = 1 << (ffs(pci->window_addr) - 1); if (lowaddr < pci->window_size) { - dev_err(pci->dev, "invalid window size/addr\n"); + dev_err(dev, "invalid window size/addr\n"); return -EINVAL; } } @@ -350,6 +354,7 @@ static int rcar_pci_parse_map_dma_ranges(struct rcar_pci_priv *pci, static int rcar_pci_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct resource *cfg_res, *mem_res; struct rcar_pci_priv *priv; void __iomem *reg; @@ -357,7 +362,7 @@ static int rcar_pci_probe(struct platform_device *pdev) void *hw_private[1]; cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg = devm_ioremap_resource(&pdev->dev, cfg_res); + reg = devm_ioremap_resource(dev, cfg_res); if (IS_ERR(reg)) return PTR_ERR(reg); @@ -368,8 +373,7 @@ static int rcar_pci_probe(struct platform_device *pdev) if (mem_res->start & 0xFFFF) return -EINVAL; - priv = devm_kzalloc(&pdev->dev, - sizeof(struct rcar_pci_priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(struct rcar_pci_priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -378,10 +382,10 @@ static int rcar_pci_probe(struct platform_device *pdev) priv->irq = platform_get_irq(pdev, 0); priv->reg = reg; - priv->dev = &pdev->dev; + priv->dev = dev; if (priv->irq < 0) { - dev_err(&pdev->dev, "no valid irq found\n"); + dev_err(dev, "no valid irq found\n"); return priv->irq; } @@ -390,23 +394,23 @@ static int rcar_pci_probe(struct platform_device *pdev) priv->window_pci = 0x40000000; priv->window_size = SZ_1G; - if (pdev->dev.of_node) { + if (dev->of_node) { struct resource busnr; int ret; - ret = of_pci_parse_bus_range(pdev->dev.of_node, &busnr); + ret = of_pci_parse_bus_range(dev->of_node, &busnr); if (ret < 0) { - dev_err(&pdev->dev, "failed to parse bus-range\n"); + dev_err(dev, "failed to parse bus-range\n"); return ret; } priv->busnr = busnr.start; if (busnr.end != busnr.start) - dev_warn(&pdev->dev, "only one bus number supported\n"); + dev_warn(dev, "only one bus number supported\n"); - ret = rcar_pci_parse_map_dma_ranges(priv, pdev->dev.of_node); + ret = rcar_pci_parse_map_dma_ranges(priv, dev->of_node); if (ret < 0) { - dev_err(&pdev->dev, "failed to parse dma-range\n"); + dev_err(dev, "failed to parse dma-range\n"); return ret; } } else { @@ -421,7 +425,7 @@ static int rcar_pci_probe(struct platform_device *pdev) hw.map_irq = rcar_pci_map_irq; hw.ops = &rcar_pci_ops; hw.setup = rcar_pci_setup; - pci_common_init_dev(&pdev->dev, &hw); + pci_common_init_dev(dev, &hw); return 0; } diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index e2a8e4cab22e..8dfccf733241 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -384,6 +384,7 @@ static unsigned long tegra_pcie_conf_offset(unsigned int devfn, int where) static struct tegra_pcie_bus *tegra_pcie_bus_alloc(struct tegra_pcie *pcie, unsigned int busnr) { + struct device *dev = pcie->dev; pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_XN | L_PTE_MT_DEV_SHARED | L_PTE_SHARED); phys_addr_t cs = pcie->cs->start; @@ -413,8 +414,7 @@ static struct tegra_pcie_bus *tegra_pcie_bus_alloc(struct tegra_pcie *pcie, err = ioremap_page_range(virt, virt + SZ_64K, phys, prot); if (err < 0) { - dev_err(pcie->dev, "ioremap_page_range() failed: %d\n", - err); + dev_err(dev, "ioremap_page_range() failed: %d\n", err); goto unmap; } } @@ -462,6 +462,7 @@ static void __iomem *tegra_pcie_map_bus(struct pci_bus *bus, int where) { struct tegra_pcie *pcie = sys_to_pcie(bus->sysdata); + struct device *dev = pcie->dev; void __iomem *addr = NULL; if (bus->number == 0) { @@ -482,8 +483,7 @@ static void __iomem *tegra_pcie_map_bus(struct pci_bus *bus, addr = (void __iomem *)b->area->addr; if (!addr) { - dev_err(pcie->dev, - "failed to map cfg. space for bus %u\n", + dev_err(dev, "failed to map cfg. space for bus %u\n", bus->number); return NULL; } @@ -584,12 +584,13 @@ static void tegra_pcie_port_disable(struct tegra_pcie_port *port) static void tegra_pcie_port_free(struct tegra_pcie_port *port) { struct tegra_pcie *pcie = port->pcie; + struct device *dev = pcie->dev; - devm_iounmap(pcie->dev, port->base); - devm_release_mem_region(pcie->dev, port->regs.start, + devm_iounmap(dev, port->base); + devm_release_mem_region(dev, port->regs.start, resource_size(&port->regs)); list_del(&port->list); - devm_kfree(pcie->dev, port); + devm_kfree(dev, port); } /* Tegra PCIE root complex wrongly reports device class */ @@ -612,12 +613,13 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable); static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) { struct tegra_pcie *pcie = sys_to_pcie(sys); + struct device *dev = pcie->dev; int err; sys->mem_offset = pcie->offset.mem; sys->io_offset = pcie->offset.io; - err = devm_request_resource(pcie->dev, &iomem_resource, &pcie->io); + err = devm_request_resource(dev, &iomem_resource, &pcie->io); if (err < 0) return err; @@ -631,7 +633,7 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) sys->mem_offset); pci_add_resource(&sys->resources, &pcie->busn); - err = devm_request_pci_bus_resources(pcie->dev, &sys->resources); + err = devm_request_pci_bus_resources(dev, &sys->resources); if (err < 0) return err; @@ -672,6 +674,7 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg) "Peer2Peer error", }; struct tegra_pcie *pcie = arg; + struct device *dev = pcie->dev; u32 code, signature; code = afi_readl(pcie, AFI_INTR_CODE) & AFI_INTR_CODE_MASK; @@ -689,11 +692,9 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg) * happen a lot during enumeration */ if (code == AFI_INTR_MASTER_ABORT) - dev_dbg(pcie->dev, "%s, signature: %08x\n", err_msg[code], - signature); + dev_dbg(dev, "%s, signature: %08x\n", err_msg[code], signature); else - dev_err(pcie->dev, "%s, signature: %08x\n", err_msg[code], - signature); + dev_err(dev, "%s, signature: %08x\n", err_msg[code], signature); if (code == AFI_INTR_TARGET_ABORT || code == AFI_INTR_MASTER_ABORT || code == AFI_INTR_FPCI_DECODE_ERROR) { @@ -701,9 +702,9 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg) u64 address = (u64)fpci << 32 | (signature & 0xfffffffc); if (code == AFI_INTR_MASTER_ABORT) - dev_dbg(pcie->dev, " FPCI address: %10llx\n", address); + dev_dbg(dev, " FPCI address: %10llx\n", address); else - dev_err(pcie->dev, " FPCI address: %10llx\n", address); + dev_err(dev, " FPCI address: %10llx\n", address); } return IRQ_HANDLED; @@ -793,6 +794,7 @@ static int tegra_pcie_pll_wait(struct tegra_pcie *pcie, unsigned long timeout) static int tegra_pcie_phy_enable(struct tegra_pcie *pcie) { + struct device *dev = pcie->dev; const struct tegra_pcie_soc *soc = pcie->soc; u32 value; int err; @@ -829,7 +831,7 @@ static int tegra_pcie_phy_enable(struct tegra_pcie *pcie) /* wait for the PLL to lock */ err = tegra_pcie_pll_wait(pcie, 500); if (err < 0) { - dev_err(pcie->dev, "PLL failed to lock: %d\n", err); + dev_err(dev, "PLL failed to lock: %d\n", err); return err; } @@ -859,7 +861,7 @@ static int tegra_pcie_phy_disable(struct tegra_pcie *pcie) /* override IDDQ */ value = pads_readl(pcie, PADS_CTL); value |= PADS_CTL_IDDQ_1L; - pads_writel(pcie, PADS_CTL, value); + pads_writel(pcie, value, PADS_CTL); /* reset PLL */ value = pads_readl(pcie, soc->pads_pll_ctl); @@ -880,8 +882,7 @@ static int tegra_pcie_port_phy_power_on(struct tegra_pcie_port *port) for (i = 0; i < port->lanes; i++) { err = phy_power_on(port->phys[i]); if (err < 0) { - dev_err(dev, "failed to power on PHY#%u: %d\n", i, - err); + dev_err(dev, "failed to power on PHY#%u: %d\n", i, err); return err; } } @@ -909,6 +910,7 @@ static int tegra_pcie_port_phy_power_off(struct tegra_pcie_port *port) static int tegra_pcie_phy_power_on(struct tegra_pcie *pcie) { + struct device *dev = pcie->dev; const struct tegra_pcie_soc *soc = pcie->soc; struct tegra_pcie_port *port; int err; @@ -920,7 +922,7 @@ static int tegra_pcie_phy_power_on(struct tegra_pcie *pcie) err = tegra_pcie_phy_enable(pcie); if (err < 0) - dev_err(pcie->dev, "failed to power on PHY: %d\n", err); + dev_err(dev, "failed to power on PHY: %d\n", err); return err; } @@ -928,7 +930,7 @@ static int tegra_pcie_phy_power_on(struct tegra_pcie *pcie) list_for_each_entry(port, &pcie->ports, list) { err = tegra_pcie_port_phy_power_on(port); if (err < 0) { - dev_err(pcie->dev, + dev_err(dev, "failed to power on PCIe port %u PHY: %d\n", port->index, err); return err; @@ -946,6 +948,7 @@ static int tegra_pcie_phy_power_on(struct tegra_pcie *pcie) static int tegra_pcie_phy_power_off(struct tegra_pcie *pcie) { + struct device *dev = pcie->dev; struct tegra_pcie_port *port; int err; @@ -956,8 +959,7 @@ static int tegra_pcie_phy_power_off(struct tegra_pcie *pcie) err = tegra_pcie_phy_disable(pcie); if (err < 0) - dev_err(pcie->dev, "failed to power off PHY: %d\n", - err); + dev_err(dev, "failed to power off PHY: %d\n", err); return err; } @@ -965,7 +967,7 @@ static int tegra_pcie_phy_power_off(struct tegra_pcie *pcie) list_for_each_entry(port, &pcie->ports, list) { err = tegra_pcie_port_phy_power_off(port); if (err < 0) { - dev_err(pcie->dev, + dev_err(dev, "failed to power off PCIe port %u PHY: %d\n", port->index, err); return err; @@ -977,6 +979,7 @@ static int tegra_pcie_phy_power_off(struct tegra_pcie *pcie) static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) { + struct device *dev = pcie->dev; const struct tegra_pcie_soc *soc = pcie->soc; struct tegra_pcie_port *port; unsigned long value; @@ -1016,7 +1019,7 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) err = tegra_pcie_phy_power_on(pcie); if (err < 0) { - dev_err(pcie->dev, "failed to power on PHY(s): %d\n", err); + dev_err(dev, "failed to power on PHY(s): %d\n", err); return err; } @@ -1049,13 +1052,14 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) static void tegra_pcie_power_off(struct tegra_pcie *pcie) { + struct device *dev = pcie->dev; int err; /* TODO: disable and unprepare clocks? */ err = tegra_pcie_phy_power_off(pcie); if (err < 0) - dev_err(pcie->dev, "failed to power off PHY(s): %d\n", err); + dev_err(dev, "failed to power off PHY(s): %d\n", err); reset_control_assert(pcie->pcie_xrst); reset_control_assert(pcie->afi_rst); @@ -1065,11 +1069,12 @@ static void tegra_pcie_power_off(struct tegra_pcie *pcie) err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies); if (err < 0) - dev_warn(pcie->dev, "failed to disable regulators: %d\n", err); + dev_warn(dev, "failed to disable regulators: %d\n", err); } static int tegra_pcie_power_on(struct tegra_pcie *pcie) { + struct device *dev = pcie->dev; const struct tegra_pcie_soc *soc = pcie->soc; int err; @@ -1082,13 +1087,13 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie) /* enable regulators */ err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies); if (err < 0) - dev_err(pcie->dev, "failed to enable regulators: %d\n", err); + dev_err(dev, "failed to enable regulators: %d\n", err); err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE, pcie->pex_clk, pcie->pex_rst); if (err) { - dev_err(pcie->dev, "powerup sequence failed: %d\n", err); + dev_err(dev, "powerup sequence failed: %d\n", err); return err; } @@ -1096,22 +1101,21 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie) err = clk_prepare_enable(pcie->afi_clk); if (err < 0) { - dev_err(pcie->dev, "failed to enable AFI clock: %d\n", err); + dev_err(dev, "failed to enable AFI clock: %d\n", err); return err; } if (soc->has_cml_clk) { err = clk_prepare_enable(pcie->cml_clk); if (err < 0) { - dev_err(pcie->dev, "failed to enable CML clock: %d\n", - err); + dev_err(dev, "failed to enable CML clock: %d\n", err); return err; } } err = clk_prepare_enable(pcie->pll_e); if (err < 0) { - dev_err(pcie->dev, "failed to enable PLLE clock: %d\n", err); + dev_err(dev, "failed to enable PLLE clock: %d\n", err); return err; } @@ -1120,22 +1124,23 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie) static int tegra_pcie_clocks_get(struct tegra_pcie *pcie) { + struct device *dev = pcie->dev; const struct tegra_pcie_soc *soc = pcie->soc; - pcie->pex_clk = devm_clk_get(pcie->dev, "pex"); + pcie->pex_clk = devm_clk_get(dev, "pex"); if (IS_ERR(pcie->pex_clk)) return PTR_ERR(pcie->pex_clk); - pcie->afi_clk = devm_clk_get(pcie->dev, "afi"); + pcie->afi_clk = devm_clk_get(dev, "afi"); if (IS_ERR(pcie->afi_clk)) return PTR_ERR(pcie->afi_clk); - pcie->pll_e = devm_clk_get(pcie->dev, "pll_e"); + pcie->pll_e = devm_clk_get(dev, "pll_e"); if (IS_ERR(pcie->pll_e)) return PTR_ERR(pcie->pll_e); if (soc->has_cml_clk) { - pcie->cml_clk = devm_clk_get(pcie->dev, "cml"); + pcie->cml_clk = devm_clk_get(dev, "cml"); if (IS_ERR(pcie->cml_clk)) return PTR_ERR(pcie->cml_clk); } @@ -1145,15 +1150,17 @@ static int tegra_pcie_clocks_get(struct tegra_pcie *pcie) static int tegra_pcie_resets_get(struct tegra_pcie *pcie) { - pcie->pex_rst = devm_reset_control_get(pcie->dev, "pex"); + struct device *dev = pcie->dev; + + pcie->pex_rst = devm_reset_control_get(dev, "pex"); if (IS_ERR(pcie->pex_rst)) return PTR_ERR(pcie->pex_rst); - pcie->afi_rst = devm_reset_control_get(pcie->dev, "afi"); + pcie->afi_rst = devm_reset_control_get(dev, "afi"); if (IS_ERR(pcie->afi_rst)) return PTR_ERR(pcie->afi_rst); - pcie->pcie_xrst = devm_reset_control_get(pcie->dev, "pcie_x"); + pcie->pcie_xrst = devm_reset_control_get(dev, "pcie_x"); if (IS_ERR(pcie->pcie_xrst)) return PTR_ERR(pcie->pcie_xrst); @@ -1162,18 +1169,19 @@ static int tegra_pcie_resets_get(struct tegra_pcie *pcie) static int tegra_pcie_phys_get_legacy(struct tegra_pcie *pcie) { + struct device *dev = pcie->dev; int err; - pcie->phy = devm_phy_optional_get(pcie->dev, "pcie"); + pcie->phy = devm_phy_optional_get(dev, "pcie"); if (IS_ERR(pcie->phy)) { err = PTR_ERR(pcie->phy); - dev_err(pcie->dev, "failed to get PHY: %d\n", err); + dev_err(dev, "failed to get PHY: %d\n", err); return err; } err = phy_init(pcie->phy); if (err < 0) { - dev_err(pcie->dev, "failed to initialize PHY: %d\n", err); + dev_err(dev, "failed to initialize PHY: %d\n", err); return err; } @@ -1256,43 +1264,44 @@ static int tegra_pcie_phys_get(struct tegra_pcie *pcie) static int tegra_pcie_get_resources(struct tegra_pcie *pcie) { - struct platform_device *pdev = to_platform_device(pcie->dev); + struct device *dev = pcie->dev; + struct platform_device *pdev = to_platform_device(dev); struct resource *pads, *afi, *res; int err; err = tegra_pcie_clocks_get(pcie); if (err) { - dev_err(&pdev->dev, "failed to get clocks: %d\n", err); + dev_err(dev, "failed to get clocks: %d\n", err); return err; } err = tegra_pcie_resets_get(pcie); if (err) { - dev_err(&pdev->dev, "failed to get resets: %d\n", err); + dev_err(dev, "failed to get resets: %d\n", err); return err; } err = tegra_pcie_phys_get(pcie); if (err < 0) { - dev_err(&pdev->dev, "failed to get PHYs: %d\n", err); + dev_err(dev, "failed to get PHYs: %d\n", err); return err; } err = tegra_pcie_power_on(pcie); if (err) { - dev_err(&pdev->dev, "failed to power up: %d\n", err); + dev_err(dev, "failed to power up: %d\n", err); return err; } pads = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pads"); - pcie->pads = devm_ioremap_resource(&pdev->dev, pads); + pcie->pads = devm_ioremap_resource(dev, pads); if (IS_ERR(pcie->pads)) { err = PTR_ERR(pcie->pads); goto poweroff; } afi = platform_get_resource_byname(pdev, IORESOURCE_MEM, "afi"); - pcie->afi = devm_ioremap_resource(&pdev->dev, afi); + pcie->afi = devm_ioremap_resource(dev, afi); if (IS_ERR(pcie->afi)) { err = PTR_ERR(pcie->afi); goto poweroff; @@ -1305,7 +1314,7 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie) goto poweroff; } - pcie->cs = devm_request_mem_region(pcie->dev, res->start, + pcie->cs = devm_request_mem_region(dev, res->start, resource_size(res), res->name); if (!pcie->cs) { err = -EADDRNOTAVAIL; @@ -1315,7 +1324,7 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie) /* request interrupt */ err = platform_get_irq_byname(pdev, "intr"); if (err < 0) { - dev_err(&pdev->dev, "failed to get IRQ: %d\n", err); + dev_err(dev, "failed to get IRQ: %d\n", err); goto poweroff; } @@ -1323,7 +1332,7 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie) err = request_irq(pcie->irq, tegra_pcie_isr, IRQF_SHARED, "PCIE", pcie); if (err) { - dev_err(&pdev->dev, "failed to register IRQ: %d\n", err); + dev_err(dev, "failed to register IRQ: %d\n", err); goto poweroff; } @@ -1336,6 +1345,7 @@ poweroff: static int tegra_pcie_put_resources(struct tegra_pcie *pcie) { + struct device *dev = pcie->dev; int err; if (pcie->irq > 0) @@ -1345,7 +1355,7 @@ static int tegra_pcie_put_resources(struct tegra_pcie *pcie) err = phy_exit(pcie->phy); if (err < 0) - dev_err(pcie->dev, "failed to teardown PHY: %d\n", err); + dev_err(dev, "failed to teardown PHY: %d\n", err); return 0; } @@ -1384,6 +1394,7 @@ static void tegra_msi_free(struct tegra_msi *chip, unsigned long irq) static irqreturn_t tegra_pcie_msi_irq(int irq, void *data) { struct tegra_pcie *pcie = data; + struct device *dev = pcie->dev; struct tegra_msi *msi = &pcie->msi; unsigned int i, processed = 0; @@ -1403,13 +1414,13 @@ static irqreturn_t tegra_pcie_msi_irq(int irq, void *data) if (test_bit(index, msi->used)) generic_handle_irq(irq); else - dev_info(pcie->dev, "unhandled MSI\n"); + dev_info(dev, "unhandled MSI\n"); } else { /* * that's weird who triggered this? * just clear it */ - dev_info(pcie->dev, "unexpected MSI\n"); + dev_info(dev, "unexpected MSI\n"); } /* see if there's any more pending in this vector */ @@ -1488,7 +1499,8 @@ static const struct irq_domain_ops msi_domain_ops = { static int tegra_pcie_enable_msi(struct tegra_pcie *pcie) { - struct platform_device *pdev = to_platform_device(pcie->dev); + struct device *dev = pcie->dev; + struct platform_device *pdev = to_platform_device(dev); const struct tegra_pcie_soc *soc = pcie->soc; struct tegra_msi *msi = &pcie->msi; unsigned long base; @@ -1497,20 +1509,20 @@ static int tegra_pcie_enable_msi(struct tegra_pcie *pcie) mutex_init(&msi->lock); - msi->chip.dev = pcie->dev; + msi->chip.dev = dev; msi->chip.setup_irq = tegra_msi_setup_irq; msi->chip.teardown_irq = tegra_msi_teardown_irq; - msi->domain = irq_domain_add_linear(pcie->dev->of_node, INT_PCI_MSI_NR, + msi->domain = irq_domain_add_linear(dev->of_node, INT_PCI_MSI_NR, &msi_domain_ops, &msi->chip); if (!msi->domain) { - dev_err(&pdev->dev, "failed to create IRQ domain\n"); + dev_err(dev, "failed to create IRQ domain\n"); return -ENOMEM; } err = platform_get_irq_byname(pdev, "msi"); if (err < 0) { - dev_err(&pdev->dev, "failed to get IRQ: %d\n", err); + dev_err(dev, "failed to get IRQ: %d\n", err); goto err; } @@ -1519,7 +1531,7 @@ static int tegra_pcie_enable_msi(struct tegra_pcie *pcie) err = request_irq(msi->irq, tegra_pcie_msi_irq, IRQF_NO_THREAD, tegra_msi_irq_chip.name, pcie); if (err < 0) { - dev_err(&pdev->dev, "failed to request IRQ: %d\n", err); + dev_err(dev, "failed to request IRQ: %d\n", err); goto err; } @@ -1594,46 +1606,47 @@ static int tegra_pcie_disable_msi(struct tegra_pcie *pcie) static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes, u32 *xbar) { - struct device_node *np = pcie->dev->of_node; + struct device *dev = pcie->dev; + struct device_node *np = dev->of_node; if (of_device_is_compatible(np, "nvidia,tegra124-pcie")) { switch (lanes) { case 0x0000104: - dev_info(pcie->dev, "4x1, 1x1 configuration\n"); + dev_info(dev, "4x1, 1x1 configuration\n"); *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1; return 0; case 0x0000102: - dev_info(pcie->dev, "2x1, 1x1 configuration\n"); + dev_info(dev, "2x1, 1x1 configuration\n"); *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1; return 0; } } else if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) { switch (lanes) { case 0x00000204: - dev_info(pcie->dev, "4x1, 2x1 configuration\n"); + dev_info(dev, "4x1, 2x1 configuration\n"); *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420; return 0; case 0x00020202: - dev_info(pcie->dev, "2x3 configuration\n"); + dev_info(dev, "2x3 configuration\n"); *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222; return 0; case 0x00010104: - dev_info(pcie->dev, "4x1, 1x2 configuration\n"); + dev_info(dev, "4x1, 1x2 configuration\n"); *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411; return 0; } } else if (of_device_is_compatible(np, "nvidia,tegra20-pcie")) { switch (lanes) { case 0x00000004: - dev_info(pcie->dev, "single-mode configuration\n"); + dev_info(dev, "single-mode configuration\n"); *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE; return 0; case 0x00000202: - dev_info(pcie->dev, "dual-mode configuration\n"); + dev_info(dev, "dual-mode configuration\n"); *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL; return 0; } @@ -1673,7 +1686,8 @@ static bool of_regulator_bulk_available(struct device_node *np, */ static int tegra_pcie_get_legacy_regulators(struct tegra_pcie *pcie) { - struct device_node *np = pcie->dev->of_node; + struct device *dev = pcie->dev; + struct device_node *np = dev->of_node; if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) pcie->num_supplies = 3; @@ -1681,12 +1695,12 @@ static int tegra_pcie_get_legacy_regulators(struct tegra_pcie *pcie) pcie->num_supplies = 2; if (pcie->num_supplies == 0) { - dev_err(pcie->dev, "device %s not supported in legacy mode\n", + dev_err(dev, "device %s not supported in legacy mode\n", np->full_name); return -ENODEV; } - pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, + pcie->supplies = devm_kcalloc(dev, pcie->num_supplies, sizeof(*pcie->supplies), GFP_KERNEL); if (!pcie->supplies) @@ -1698,8 +1712,7 @@ static int tegra_pcie_get_legacy_regulators(struct tegra_pcie *pcie) if (pcie->num_supplies > 2) pcie->supplies[2].supply = "avdd"; - return devm_regulator_bulk_get(pcie->dev, pcie->num_supplies, - pcie->supplies); + return devm_regulator_bulk_get(dev, pcie->num_supplies, pcie->supplies); } /* @@ -1713,13 +1726,14 @@ static int tegra_pcie_get_legacy_regulators(struct tegra_pcie *pcie) */ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask) { - struct device_node *np = pcie->dev->of_node; + struct device *dev = pcie->dev; + struct device_node *np = dev->of_node; unsigned int i = 0; if (of_device_is_compatible(np, "nvidia,tegra124-pcie")) { pcie->num_supplies = 7; - pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, + pcie->supplies = devm_kcalloc(dev, pcie->num_supplies, sizeof(*pcie->supplies), GFP_KERNEL); if (!pcie->supplies) @@ -1746,7 +1760,7 @@ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask) pcie->num_supplies = 4 + (need_pexa ? 2 : 0) + (need_pexb ? 2 : 0); - pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, + pcie->supplies = devm_kcalloc(dev, pcie->num_supplies, sizeof(*pcie->supplies), GFP_KERNEL); if (!pcie->supplies) @@ -1769,7 +1783,7 @@ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask) } else if (of_device_is_compatible(np, "nvidia,tegra20-pcie")) { pcie->num_supplies = 5; - pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, + pcie->supplies = devm_kcalloc(dev, pcie->num_supplies, sizeof(*pcie->supplies), GFP_KERNEL); if (!pcie->supplies) @@ -1782,9 +1796,9 @@ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask) pcie->supplies[4].supply = "vddio-pex-clk"; } - if (of_regulator_bulk_available(pcie->dev->of_node, pcie->supplies, + if (of_regulator_bulk_available(dev->of_node, pcie->supplies, pcie->num_supplies)) - return devm_regulator_bulk_get(pcie->dev, pcie->num_supplies, + return devm_regulator_bulk_get(dev, pcie->num_supplies, pcie->supplies); /* @@ -1792,9 +1806,9 @@ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask) * that the device tree complies with an older version of the device * tree binding. */ - dev_info(pcie->dev, "using legacy DT binding for power supplies\n"); + dev_info(dev, "using legacy DT binding for power supplies\n"); - devm_kfree(pcie->dev, pcie->supplies); + devm_kfree(dev, pcie->supplies); pcie->num_supplies = 0; return tegra_pcie_get_legacy_regulators(pcie); @@ -1802,7 +1816,8 @@ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask) static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) { - struct device_node *np = pcie->dev->of_node, *port; + struct device *dev = pcie->dev; + struct device_node *np = dev->of_node, *port; const struct tegra_pcie_soc *soc = pcie->soc; struct of_pci_range_parser parser; struct of_pci_range range; @@ -1812,7 +1827,7 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) int err; if (of_pci_range_parser_init(&parser, np)) { - dev_err(pcie->dev, "missing \"ranges\" property\n"); + dev_err(dev, "missing \"ranges\" property\n"); return -EINVAL; } @@ -1867,8 +1882,7 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) err = of_pci_parse_bus_range(np, &pcie->busn); if (err < 0) { - dev_err(pcie->dev, "failed to parse ranges property: %d\n", - err); + dev_err(dev, "failed to parse ranges property: %d\n", err); pcie->busn.name = np->name; pcie->busn.start = 0; pcie->busn.end = 0xff; @@ -1883,15 +1897,14 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) err = of_pci_get_devfn(port); if (err < 0) { - dev_err(pcie->dev, "failed to parse address: %d\n", - err); + dev_err(dev, "failed to parse address: %d\n", err); return err; } index = PCI_SLOT(err); if (index < 1 || index > soc->num_ports) { - dev_err(pcie->dev, "invalid port number: %d\n", index); + dev_err(dev, "invalid port number: %d\n", index); return -EINVAL; } @@ -1899,13 +1912,13 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) err = of_property_read_u32(port, "nvidia,num-lanes", &value); if (err < 0) { - dev_err(pcie->dev, "failed to parse # of lanes: %d\n", + dev_err(dev, "failed to parse # of lanes: %d\n", err); return err; } if (value > 16) { - dev_err(pcie->dev, "invalid # of lanes: %u\n", value); + dev_err(dev, "invalid # of lanes: %u\n", value); return -EINVAL; } @@ -1919,14 +1932,13 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) mask |= ((1 << value) - 1) << lane; lane += value; - rp = devm_kzalloc(pcie->dev, sizeof(*rp), GFP_KERNEL); + rp = devm_kzalloc(dev, sizeof(*rp), GFP_KERNEL); if (!rp) return -ENOMEM; err = of_address_to_resource(port, 0, &rp->regs); if (err < 0) { - dev_err(pcie->dev, "failed to parse address: %d\n", - err); + dev_err(dev, "failed to parse address: %d\n", err); return err; } @@ -1936,7 +1948,7 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) rp->pcie = pcie; rp->np = port; - rp->base = devm_ioremap_resource(pcie->dev, &rp->regs); + rp->base = devm_ioremap_resource(dev, &rp->regs); if (IS_ERR(rp->base)) return PTR_ERR(rp->base); @@ -1945,7 +1957,7 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) err = tegra_pcie_get_xbar_config(pcie, lanes, &pcie->xbar_config); if (err < 0) { - dev_err(pcie->dev, "invalid lane configuration\n"); + dev_err(dev, "invalid lane configuration\n"); return err; } @@ -1964,6 +1976,7 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) #define TEGRA_PCIE_LINKUP_TIMEOUT 200 /* up to 1.2 seconds */ static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port) { + struct device *dev = port->pcie->dev; unsigned int retries = 3; unsigned long value; @@ -1986,8 +1999,7 @@ static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port) } while (--timeout); if (!timeout) { - dev_err(port->pcie->dev, "link %u down, retrying\n", - port->index); + dev_err(dev, "link %u down, retrying\n", port->index); goto retry; } @@ -2011,11 +2023,12 @@ retry: static int tegra_pcie_enable(struct tegra_pcie *pcie) { + struct device *dev = pcie->dev; struct tegra_pcie_port *port, *tmp; struct hw_pci hw; list_for_each_entry_safe(port, tmp, &pcie->ports, list) { - dev_info(pcie->dev, "probing port %u, using %u lanes\n", + dev_info(dev, "probing port %u, using %u lanes\n", port->index, port->lanes); tegra_pcie_port_enable(port); @@ -2023,7 +2036,7 @@ static int tegra_pcie_enable(struct tegra_pcie *pcie) if (tegra_pcie_port_check_link(port)) continue; - dev_info(pcie->dev, "link %u down, ignoring\n", port->index); + dev_info(dev, "link %u down, ignoring\n", port->index); tegra_pcie_port_disable(port); tegra_pcie_port_free(port); @@ -2041,8 +2054,7 @@ static int tegra_pcie_enable(struct tegra_pcie *pcie) hw.map_irq = tegra_pcie_map_irq; hw.ops = &tegra_pcie_ops; - pci_common_init_dev(pcie->dev, &hw); - + pci_common_init_dev(dev, &hw); return 0; } @@ -2204,17 +2216,18 @@ remove: static int tegra_pcie_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct tegra_pcie *pcie; int err; - pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); + pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); if (!pcie) return -ENOMEM; - pcie->soc = of_device_get_match_data(&pdev->dev); + pcie->soc = of_device_get_match_data(dev); INIT_LIST_HEAD(&pcie->buses); INIT_LIST_HEAD(&pcie->ports); - pcie->dev = &pdev->dev; + pcie->dev = dev; err = tegra_pcie_parse_dt(pcie); if (err < 0) @@ -2222,7 +2235,7 @@ static int tegra_pcie_probe(struct platform_device *pdev) err = tegra_pcie_get_resources(pcie); if (err < 0) { - dev_err(&pdev->dev, "failed to request resources: %d\n", err); + dev_err(dev, "failed to request resources: %d\n", err); return err; } @@ -2236,27 +2249,23 @@ static int tegra_pcie_probe(struct platform_device *pdev) if (IS_ENABLED(CONFIG_PCI_MSI)) { err = tegra_pcie_enable_msi(pcie); if (err < 0) { - dev_err(&pdev->dev, - "failed to enable MSI support: %d\n", - err); + dev_err(dev, "failed to enable MSI support: %d\n", err); goto put_resources; } } err = tegra_pcie_enable(pcie); if (err < 0) { - dev_err(&pdev->dev, "failed to enable PCIe ports: %d\n", err); + dev_err(dev, "failed to enable PCIe ports: %d\n", err); goto disable_msi; } if (IS_ENABLED(CONFIG_DEBUG_FS)) { err = tegra_pcie_debugfs_init(pcie); if (err < 0) - dev_err(&pdev->dev, "failed to setup debugfs: %d\n", - err); + dev_err(dev, "failed to setup debugfs: %d\n", err); } - platform_set_drvdata(pdev, pcie); return 0; disable_msi: diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c index a81273c23341..1de23d74783f 100644 --- a/drivers/pci/host/pci-xgene.c +++ b/drivers/pci/host/pci-xgene.c @@ -76,6 +76,16 @@ struct xgene_pcie_port { u32 version; }; +static u32 xgene_pcie_readl(struct xgene_pcie_port *port, u32 reg) +{ + return readl(port->csr_base + reg); +} + +static void xgene_pcie_writel(struct xgene_pcie_port *port, u32 reg, u32 val) +{ + writel(val, port->csr_base + reg); +} + static inline u32 pcie_bar_low_val(u32 addr, u32 flags) { return (addr & PCI_BASE_ADDRESS_MEM_MASK) | flags; @@ -112,9 +122,9 @@ static void xgene_pcie_set_rtdid_reg(struct pci_bus *bus, uint devfn) if (!pci_is_root_bus(bus)) rtdid_val = (b << 8) | (d << 3) | f; - writel(rtdid_val, port->csr_base + RTDID); + xgene_pcie_writel(port, RTDID, rtdid_val); /* read the register back to ensure flush */ - readl(port->csr_base + RTDID); + xgene_pcie_readl(port, RTDID); } /* @@ -179,28 +189,28 @@ static struct pci_ops xgene_pcie_ops = { .write = pci_generic_config_write32, }; -static u64 xgene_pcie_set_ib_mask(void __iomem *csr_base, u32 addr, +static u64 xgene_pcie_set_ib_mask(struct xgene_pcie_port *port, u32 addr, u32 flags, u64 size) { u64 mask = (~(size - 1) & PCI_BASE_ADDRESS_MEM_MASK) | flags; u32 val32 = 0; u32 val; - val32 = readl(csr_base + addr); + val32 = xgene_pcie_readl(port, addr); val = (val32 & 0x0000ffff) | (lower_32_bits(mask) << 16); - writel(val, csr_base + addr); + xgene_pcie_writel(port, addr, val); - val32 = readl(csr_base + addr + 0x04); + val32 = xgene_pcie_readl(port, addr + 0x04); val = (val32 & 0xffff0000) | (lower_32_bits(mask) >> 16); - writel(val, csr_base + addr + 0x04); + xgene_pcie_writel(port, addr + 0x04, val); - val32 = readl(csr_base + addr + 0x04); + val32 = xgene_pcie_readl(port, addr + 0x04); val = (val32 & 0x0000ffff) | (upper_32_bits(mask) << 16); - writel(val, csr_base + addr + 0x04); + xgene_pcie_writel(port, addr + 0x04, val); - val32 = readl(csr_base + addr + 0x08); + val32 = xgene_pcie_readl(port, addr + 0x08); val = (val32 & 0xffff0000) | (upper_32_bits(mask) >> 16); - writel(val, csr_base + addr + 0x08); + xgene_pcie_writel(port, addr + 0x08, val); return mask; } @@ -208,32 +218,32 @@ static u64 xgene_pcie_set_ib_mask(void __iomem *csr_base, u32 addr, static void xgene_pcie_linkup(struct xgene_pcie_port *port, u32 *lanes, u32 *speed) { - void __iomem *csr_base = port->csr_base; u32 val32; port->link_up = false; - val32 = readl(csr_base + PCIECORE_CTLANDSTATUS); + val32 = xgene_pcie_readl(port, PCIECORE_CTLANDSTATUS); if (val32 & LINK_UP_MASK) { port->link_up = true; *speed = PIPE_PHY_RATE_RD(val32); - val32 = readl(csr_base + BRIDGE_STATUS_0); + val32 = xgene_pcie_readl(port, BRIDGE_STATUS_0); *lanes = val32 >> 26; } } static int xgene_pcie_init_port(struct xgene_pcie_port *port) { + struct device *dev = port->dev; int rc; - port->clk = clk_get(port->dev, NULL); + port->clk = clk_get(dev, NULL); if (IS_ERR(port->clk)) { - dev_err(port->dev, "clock not available\n"); + dev_err(dev, "clock not available\n"); return -ENODEV; } rc = clk_prepare_enable(port->clk); if (rc) { - dev_err(port->dev, "clock enable failed\n"); + dev_err(dev, "clock enable failed\n"); return rc; } @@ -243,15 +253,16 @@ static int xgene_pcie_init_port(struct xgene_pcie_port *port) static int xgene_pcie_map_reg(struct xgene_pcie_port *port, struct platform_device *pdev) { + struct device *dev = port->dev; struct resource *res; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr"); - port->csr_base = devm_ioremap_resource(port->dev, res); + port->csr_base = devm_ioremap_resource(dev, res); if (IS_ERR(port->csr_base)) return PTR_ERR(port->csr_base); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); - port->cfg_base = devm_ioremap_resource(port->dev, res); + port->cfg_base = devm_ioremap_resource(dev, res); if (IS_ERR(port->cfg_base)) return PTR_ERR(port->cfg_base); port->cfg_addr = res->start; @@ -263,7 +274,7 @@ static void xgene_pcie_setup_ob_reg(struct xgene_pcie_port *port, struct resource *res, u32 offset, u64 cpu_addr, u64 pci_addr) { - void __iomem *base = port->csr_base + offset; + struct device *dev = port->dev; resource_size_t size = resource_size(res); u64 restype = resource_type(res); u64 mask = 0; @@ -280,22 +291,24 @@ static void xgene_pcie_setup_ob_reg(struct xgene_pcie_port *port, if (size >= min_size) mask = ~(size - 1) | flag; else - dev_warn(port->dev, "res size 0x%llx less than minimum 0x%x\n", + dev_warn(dev, "res size 0x%llx less than minimum 0x%x\n", (u64)size, min_size); - writel(lower_32_bits(cpu_addr), base); - writel(upper_32_bits(cpu_addr), base + 0x04); - writel(lower_32_bits(mask), base + 0x08); - writel(upper_32_bits(mask), base + 0x0c); - writel(lower_32_bits(pci_addr), base + 0x10); - writel(upper_32_bits(pci_addr), base + 0x14); + xgene_pcie_writel(port, offset, lower_32_bits(cpu_addr)); + xgene_pcie_writel(port, offset + 0x04, upper_32_bits(cpu_addr)); + xgene_pcie_writel(port, offset + 0x08, lower_32_bits(mask)); + xgene_pcie_writel(port, offset + 0x0c, upper_32_bits(mask)); + xgene_pcie_writel(port, offset + 0x10, lower_32_bits(pci_addr)); + xgene_pcie_writel(port, offset + 0x14, upper_32_bits(pci_addr)); } -static void xgene_pcie_setup_cfg_reg(void __iomem *csr_base, u64 addr) +static void xgene_pcie_setup_cfg_reg(struct xgene_pcie_port *port) { - writel(lower_32_bits(addr), csr_base + CFGBARL); - writel(upper_32_bits(addr), csr_base + CFGBARH); - writel(EN_REG, csr_base + CFGCTL); + u64 addr = port->cfg_addr; + + xgene_pcie_writel(port, CFGBARL, lower_32_bits(addr)); + xgene_pcie_writel(port, CFGBARH, upper_32_bits(addr)); + xgene_pcie_writel(port, CFGCTL, EN_REG); } static int xgene_pcie_map_ranges(struct xgene_pcie_port *port, @@ -310,7 +323,7 @@ static int xgene_pcie_map_ranges(struct xgene_pcie_port *port, struct resource *res = window->res; u64 restype = resource_type(res); - dev_dbg(port->dev, "%pR\n", res); + dev_dbg(dev, "%pR\n", res); switch (restype) { case IORESOURCE_IO: @@ -339,17 +352,18 @@ static int xgene_pcie_map_ranges(struct xgene_pcie_port *port, return -EINVAL; } } - xgene_pcie_setup_cfg_reg(port->csr_base, port->cfg_addr); - + xgene_pcie_setup_cfg_reg(port); return 0; } -static void xgene_pcie_setup_pims(void *addr, u64 pim, u64 size) +static void xgene_pcie_setup_pims(struct xgene_pcie_port *port, u32 pim_reg, + u64 pim, u64 size) { - writel(lower_32_bits(pim), addr); - writel(upper_32_bits(pim) | EN_COHERENCY, addr + 0x04); - writel(lower_32_bits(size), addr + 0x10); - writel(upper_32_bits(size), addr + 0x14); + xgene_pcie_writel(port, pim_reg, lower_32_bits(pim)); + xgene_pcie_writel(port, pim_reg + 0x04, + upper_32_bits(pim) | EN_COHERENCY); + xgene_pcie_writel(port, pim_reg + 0x10, lower_32_bits(size)); + xgene_pcie_writel(port, pim_reg + 0x14, upper_32_bits(size)); } /* @@ -379,10 +393,10 @@ static int xgene_pcie_select_ib_reg(u8 *ib_reg_mask, u64 size) static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port, struct of_pci_range *range, u8 *ib_reg_mask) { - void __iomem *csr_base = port->csr_base; void __iomem *cfg_base = port->cfg_base; + struct device *dev = port->dev; void *bar_addr; - void *pim_addr; + u32 pim_reg; u64 cpu_addr = range->cpu_addr; u64 pci_addr = range->pci_addr; u64 size = range->size; @@ -393,7 +407,7 @@ static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port, region = xgene_pcie_select_ib_reg(ib_reg_mask, range->size); if (region < 0) { - dev_warn(port->dev, "invalid pcie dma-range config\n"); + dev_warn(dev, "invalid pcie dma-range config\n"); return; } @@ -403,29 +417,27 @@ static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port, bar_low = pcie_bar_low_val((u32)cpu_addr, flags); switch (region) { case 0: - xgene_pcie_set_ib_mask(csr_base, BRIDGE_CFG_4, flags, size); + xgene_pcie_set_ib_mask(port, BRIDGE_CFG_4, flags, size); bar_addr = cfg_base + PCI_BASE_ADDRESS_0; writel(bar_low, bar_addr); writel(upper_32_bits(cpu_addr), bar_addr + 0x4); - pim_addr = csr_base + PIM1_1L; + pim_reg = PIM1_1L; break; case 1: - bar_addr = csr_base + IBAR2; - writel(bar_low, bar_addr); - writel(lower_32_bits(mask), csr_base + IR2MSK); - pim_addr = csr_base + PIM2_1L; + xgene_pcie_writel(port, IBAR2, bar_low); + xgene_pcie_writel(port, IR2MSK, lower_32_bits(mask)); + pim_reg = PIM2_1L; break; case 2: - bar_addr = csr_base + IBAR3L; - writel(bar_low, bar_addr); - writel(upper_32_bits(cpu_addr), bar_addr + 0x4); - writel(lower_32_bits(mask), csr_base + IR3MSKL); - writel(upper_32_bits(mask), csr_base + IR3MSKL + 0x4); - pim_addr = csr_base + PIM3_1L; + xgene_pcie_writel(port, IBAR3L, bar_low); + xgene_pcie_writel(port, IBAR3L + 0x4, upper_32_bits(cpu_addr)); + xgene_pcie_writel(port, IR3MSKL, lower_32_bits(mask)); + xgene_pcie_writel(port, IR3MSKL + 0x4, upper_32_bits(mask)); + pim_reg = PIM3_1L; break; } - xgene_pcie_setup_pims(pim_addr, pci_addr, ~(size - 1)); + xgene_pcie_setup_pims(port, pim_reg, pci_addr, ~(size - 1)); } static int pci_dma_range_parser_init(struct of_pci_range_parser *parser, @@ -463,7 +475,7 @@ static int xgene_pcie_parse_map_dma_ranges(struct xgene_pcie_port *port) for_each_of_pci_range(&parser, &range) { u64 end = range.cpu_addr + range.size - 1; - dev_dbg(port->dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n", + dev_dbg(dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n", range.flags, range.cpu_addr, end, range.pci_addr); xgene_pcie_setup_ib_reg(port, &range, &ib_reg_mask); } @@ -476,13 +488,14 @@ static void xgene_pcie_clear_config(struct xgene_pcie_port *port) int i; for (i = PIM1_1L; i <= CFGCTL; i += 4) - writel(0x0, port->csr_base + i); + xgene_pcie_writel(port, i, 0); } static int xgene_pcie_setup(struct xgene_pcie_port *port, struct list_head *res, resource_size_t io_base) { + struct device *dev = port->dev; u32 val, lanes = 0, speed = 0; int ret; @@ -490,7 +503,7 @@ static int xgene_pcie_setup(struct xgene_pcie_port *port, /* setup the vendor and device IDs correctly */ val = (XGENE_PCIE_DEVICEID << 16) | XGENE_PCIE_VENDORID; - writel(val, port->csr_base + BRIDGE_CFG_0); + xgene_pcie_writel(port, BRIDGE_CFG_0, val); ret = xgene_pcie_map_ranges(port, res, io_base); if (ret) @@ -502,27 +515,28 @@ static int xgene_pcie_setup(struct xgene_pcie_port *port, xgene_pcie_linkup(port, &lanes, &speed); if (!port->link_up) - dev_info(port->dev, "(rc) link down\n"); + dev_info(dev, "(rc) link down\n"); else - dev_info(port->dev, "(rc) x%d gen-%d link up\n", - lanes, speed + 1); + dev_info(dev, "(rc) x%d gen-%d link up\n", lanes, speed + 1); return 0; } static int xgene_pcie_probe_bridge(struct platform_device *pdev) { - struct device_node *dn = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct device_node *dn = dev->of_node; struct xgene_pcie_port *port; resource_size_t iobase = 0; struct pci_bus *bus; int ret; LIST_HEAD(res); - port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL); + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); if (!port) return -ENOMEM; - port->node = of_node_get(pdev->dev.of_node); - port->dev = &pdev->dev; + + port->node = of_node_get(dn); + port->dev = dev; port->version = XGENE_PCIE_IP_VER_UNKN; if (of_device_is_compatible(port->node, "apm,xgene-pcie")) @@ -540,7 +554,7 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev) if (ret) return ret; - ret = devm_request_pci_bus_resources(&pdev->dev, &res); + ret = devm_request_pci_bus_resources(dev, &res); if (ret) goto error; @@ -548,8 +562,7 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev) if (ret) goto error; - bus = pci_create_root_bus(&pdev->dev, 0, - &xgene_pcie_ops, port, &res); + bus = pci_create_root_bus(dev, 0, &xgene_pcie_ops, port, &res); if (!bus) { ret = -ENOMEM; goto error; @@ -558,8 +571,6 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev) pci_scan_child_bus(bus); pci_assign_unassigned_bus_resources(bus); pci_bus_add_devices(bus); - - platform_set_drvdata(pdev, port); return 0; error: diff --git a/drivers/pci/host/pcie-altera.c b/drivers/pci/host/pcie-altera.c index c24e96559cbb..b0ac4dfafa0b 100644 --- a/drivers/pci/host/pcie-altera.c +++ b/drivers/pci/host/pcie-altera.c @@ -55,15 +55,19 @@ #define TLP_PAYLOAD_SIZE 0x01 #define TLP_READ_TAG 0x1d #define TLP_WRITE_TAG 0x10 -#define TLP_CFG_DW0(fmttype) (((fmttype) << 24) | TLP_PAYLOAD_SIZE) -#define TLP_CFG_DW1(reqid, tag, be) (((reqid) << 16) | (tag << 8) | (be)) +#define RP_DEVFN 0 +#define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn)) +#define TLP_CFG_DW0(pcie, bus) \ + ((((bus == pcie->root_bus_nr) ? TLP_FMTTYPE_CFGRD0 \ + : TLP_FMTTYPE_CFGRD1) << 24) | \ + TLP_PAYLOAD_SIZE) +#define TLP_CFG_DW1(pcie, tag, be) \ + (((TLP_REQ_ID(pcie->root_bus_nr, RP_DEVFN)) << 16) | (tag << 8) | (be)) #define TLP_CFG_DW2(bus, devfn, offset) \ (((bus) << 24) | ((devfn) << 16) | (offset)) -#define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn)) #define TLP_COMP_STATUS(s) (((s) >> 12) & 7) #define TLP_HDR_SIZE 3 #define TLP_LOOP 500 -#define RP_DEVFN 0 #define LINK_UP_TIMEOUT HZ #define LINK_RETRAIN_TIMEOUT HZ @@ -74,7 +78,7 @@ struct altera_pcie { struct platform_device *pdev; - void __iomem *cra_base; + void __iomem *cra_base; /* DT Cra */ int irq; u8 root_bus_nr; struct irq_domain *irq_domain; @@ -131,7 +135,7 @@ static void tlp_write_tx(struct altera_pcie *pcie, cra_writel(pcie, tlp_rp_regdata->ctrl, RP_TX_CNTRL); } -static bool altera_pcie_valid_config(struct altera_pcie *pcie, +static bool altera_pcie_valid_device(struct altera_pcie *pcie, struct pci_bus *bus, int dev) { /* If there is no link, then there is no device */ @@ -218,13 +222,8 @@ static int tlp_cfg_dword_read(struct altera_pcie *pcie, u8 bus, u32 devfn, { u32 headers[TLP_HDR_SIZE]; - if (bus == pcie->root_bus_nr) - headers[0] = TLP_CFG_DW0(TLP_FMTTYPE_CFGRD0); - else - headers[0] = TLP_CFG_DW0(TLP_FMTTYPE_CFGRD1); - - headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, RP_DEVFN), - TLP_READ_TAG, byte_en); + headers[0] = TLP_CFG_DW0(pcie, bus); + headers[1] = TLP_CFG_DW1(pcie, TLP_READ_TAG, byte_en); headers[2] = TLP_CFG_DW2(bus, devfn, where); tlp_write_packet(pcie, headers, 0, false); @@ -238,13 +237,8 @@ static int tlp_cfg_dword_write(struct altera_pcie *pcie, u8 bus, u32 devfn, u32 headers[TLP_HDR_SIZE]; int ret; - if (bus == pcie->root_bus_nr) - headers[0] = TLP_CFG_DW0(TLP_FMTTYPE_CFGWR0); - else - headers[0] = TLP_CFG_DW0(TLP_FMTTYPE_CFGWR1); - - headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, RP_DEVFN), - TLP_WRITE_TAG, byte_en); + headers[0] = TLP_CFG_DW0(pcie, bus); + headers[1] = TLP_CFG_DW1(pcie, TLP_WRITE_TAG, byte_en); headers[2] = TLP_CFG_DW2(bus, devfn, where); /* check alignment to Qword */ @@ -342,7 +336,7 @@ static int altera_pcie_cfg_read(struct pci_bus *bus, unsigned int devfn, if (altera_pcie_hide_rc_bar(bus, devfn, where)) return PCIBIOS_BAD_REGISTER_NUMBER; - if (!altera_pcie_valid_config(pcie, bus, PCI_SLOT(devfn))) { + if (!altera_pcie_valid_device(pcie, bus, PCI_SLOT(devfn))) { *value = 0xffffffff; return PCIBIOS_DEVICE_NOT_FOUND; } @@ -359,7 +353,7 @@ static int altera_pcie_cfg_write(struct pci_bus *bus, unsigned int devfn, if (altera_pcie_hide_rc_bar(bus, devfn, where)) return PCIBIOS_BAD_REGISTER_NUMBER; - if (!altera_pcie_valid_config(pcie, bus, PCI_SLOT(devfn))) + if (!altera_pcie_valid_device(pcie, bus, PCI_SLOT(devfn))) return PCIBIOS_DEVICE_NOT_FOUND; return _altera_pcie_cfg_write(pcie, bus->number, devfn, where, size, @@ -394,6 +388,7 @@ static int altera_write_cap_word(struct altera_pcie *pcie, u8 busno, static void altera_wait_link_retrain(struct altera_pcie *pcie) { + struct device *dev = &pcie->pdev->dev; u16 reg16; unsigned long start_jiffies; @@ -406,7 +401,7 @@ static void altera_wait_link_retrain(struct altera_pcie *pcie) break; if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT)) { - dev_err(&pcie->pdev->dev, "link retrain timeout\n"); + dev_err(dev, "link retrain timeout\n"); break; } udelay(100); @@ -419,7 +414,7 @@ static void altera_wait_link_retrain(struct altera_pcie *pcie) break; if (time_after(jiffies, start_jiffies + LINK_UP_TIMEOUT)) { - dev_err(&pcie->pdev->dev, "link up timeout\n"); + dev_err(dev, "link up timeout\n"); break; } udelay(100); @@ -460,7 +455,6 @@ static int altera_pcie_intx_map(struct irq_domain *domain, unsigned int irq, { irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq); irq_set_chip_data(irq, domain->host_data); - return 0; } @@ -472,12 +466,14 @@ static void altera_pcie_isr(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct altera_pcie *pcie; + struct device *dev; unsigned long status; u32 bit; u32 virq; chained_irq_enter(chip, desc); pcie = irq_desc_get_handler_data(desc); + dev = &pcie->pdev->dev; while ((status = cra_readl(pcie, P2A_INT_STATUS) & P2A_INT_STS_ALL) != 0) { @@ -489,8 +485,7 @@ static void altera_pcie_isr(struct irq_desc *desc) if (virq) generic_handle_irq(virq); else - dev_err(&pcie->pdev->dev, - "unexpected IRQ, INT%d\n", bit); + dev_err(dev, "unexpected IRQ, INT%d\n", bit); } } @@ -549,30 +544,25 @@ static int altera_pcie_init_irq_domain(struct altera_pcie *pcie) static int altera_pcie_parse_dt(struct altera_pcie *pcie) { - struct resource *cra; + struct device *dev = &pcie->pdev->dev; struct platform_device *pdev = pcie->pdev; + struct resource *cra; cra = platform_get_resource_byname(pdev, IORESOURCE_MEM, "Cra"); - if (!cra) { - dev_err(&pdev->dev, "no Cra memory resource defined\n"); - return -ENODEV; - } - - pcie->cra_base = devm_ioremap_resource(&pdev->dev, cra); + pcie->cra_base = devm_ioremap_resource(dev, cra); if (IS_ERR(pcie->cra_base)) { - dev_err(&pdev->dev, "failed to map cra memory\n"); + dev_err(dev, "failed to map cra memory\n"); return PTR_ERR(pcie->cra_base); } /* setup IRQ */ pcie->irq = platform_get_irq(pdev, 0); if (pcie->irq <= 0) { - dev_err(&pdev->dev, "failed to get IRQ: %d\n", pcie->irq); + dev_err(dev, "failed to get IRQ: %d\n", pcie->irq); return -EINVAL; } irq_set_chained_handler_and_data(pcie->irq, altera_pcie_isr, pcie); - return 0; } @@ -583,12 +573,13 @@ static void altera_pcie_host_init(struct altera_pcie *pcie) static int altera_pcie_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct altera_pcie *pcie; struct pci_bus *bus; struct pci_bus *child; int ret; - pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); + pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); if (!pcie) return -ENOMEM; @@ -596,7 +587,7 @@ static int altera_pcie_probe(struct platform_device *pdev) ret = altera_pcie_parse_dt(pcie); if (ret) { - dev_err(&pdev->dev, "Parsing DT failed\n"); + dev_err(dev, "Parsing DT failed\n"); return ret; } @@ -604,13 +595,13 @@ static int altera_pcie_probe(struct platform_device *pdev) ret = altera_pcie_parse_request_of_pci_ranges(pcie); if (ret) { - dev_err(&pdev->dev, "Failed add resources\n"); + dev_err(dev, "Failed add resources\n"); return ret; } ret = altera_pcie_init_irq_domain(pcie); if (ret) { - dev_err(&pdev->dev, "Failed creating IRQ Domain\n"); + dev_err(dev, "Failed creating IRQ Domain\n"); return ret; } @@ -620,7 +611,7 @@ static int altera_pcie_probe(struct platform_device *pdev) cra_writel(pcie, P2A_INT_ENA_ALL, P2A_INT_ENABLE); altera_pcie_host_init(pcie); - bus = pci_scan_root_bus(&pdev->dev, pcie->root_bus_nr, &altera_pcie_ops, + bus = pci_scan_root_bus(dev, pcie->root_bus_nr, &altera_pcie_ops, pcie, &pcie->resources); if (!bus) return -ENOMEM; @@ -633,8 +624,6 @@ static int altera_pcie_probe(struct platform_device *pdev) pcie_bus_configure_settings(child); pci_bus_add_devices(bus); - - platform_set_drvdata(pdev, pcie); return ret; } diff --git a/drivers/pci/host/pcie-armada8k.c b/drivers/pci/host/pcie-armada8k.c index 0f4f570068e3..0ac0f18690f2 100644 --- a/drivers/pci/host/pcie-armada8k.c +++ b/drivers/pci/host/pcie-armada8k.c @@ -29,34 +29,33 @@ #include "pcie-designware.h" struct armada8k_pcie { - void __iomem *base; + struct pcie_port pp; /* pp.dbi_base is DT ctrl */ struct clk *clk; - struct pcie_port pp; }; #define PCIE_VENDOR_REGS_OFFSET 0x8000 -#define PCIE_GLOBAL_CONTROL_REG 0x0 +#define PCIE_GLOBAL_CONTROL_REG (PCIE_VENDOR_REGS_OFFSET + 0x0) #define PCIE_APP_LTSSM_EN BIT(2) #define PCIE_DEVICE_TYPE_SHIFT 4 #define PCIE_DEVICE_TYPE_MASK 0xF #define PCIE_DEVICE_TYPE_RC 0x4 /* Root complex */ -#define PCIE_GLOBAL_STATUS_REG 0x8 +#define PCIE_GLOBAL_STATUS_REG (PCIE_VENDOR_REGS_OFFSET + 0x8) #define PCIE_GLB_STS_RDLH_LINK_UP BIT(1) #define PCIE_GLB_STS_PHY_LINK_UP BIT(9) -#define PCIE_GLOBAL_INT_CAUSE1_REG 0x1C -#define PCIE_GLOBAL_INT_MASK1_REG 0x20 +#define PCIE_GLOBAL_INT_CAUSE1_REG (PCIE_VENDOR_REGS_OFFSET + 0x1C) +#define PCIE_GLOBAL_INT_MASK1_REG (PCIE_VENDOR_REGS_OFFSET + 0x20) #define PCIE_INT_A_ASSERT_MASK BIT(9) #define PCIE_INT_B_ASSERT_MASK BIT(10) #define PCIE_INT_C_ASSERT_MASK BIT(11) #define PCIE_INT_D_ASSERT_MASK BIT(12) -#define PCIE_ARCACHE_TRC_REG 0x50 -#define PCIE_AWCACHE_TRC_REG 0x54 -#define PCIE_ARUSER_REG 0x5C -#define PCIE_AWUSER_REG 0x60 +#define PCIE_ARCACHE_TRC_REG (PCIE_VENDOR_REGS_OFFSET + 0x50) +#define PCIE_AWCACHE_TRC_REG (PCIE_VENDOR_REGS_OFFSET + 0x54) +#define PCIE_ARUSER_REG (PCIE_VENDOR_REGS_OFFSET + 0x5C) +#define PCIE_AWUSER_REG (PCIE_VENDOR_REGS_OFFSET + 0x60) /* * AR/AW Cache defauls: Normal memory, Write-Back, Read / Write * allocate @@ -72,11 +71,10 @@ struct armada8k_pcie { static int armada8k_pcie_link_up(struct pcie_port *pp) { - struct armada8k_pcie *pcie = to_armada8k_pcie(pp); u32 reg; u32 mask = PCIE_GLB_STS_RDLH_LINK_UP | PCIE_GLB_STS_PHY_LINK_UP; - reg = readl(pcie->base + PCIE_GLOBAL_STATUS_REG); + reg = dw_pcie_readl_rc(pp, PCIE_GLOBAL_STATUS_REG); if ((reg & mask) == mask) return 1; @@ -85,51 +83,50 @@ static int armada8k_pcie_link_up(struct pcie_port *pp) return 0; } -static void armada8k_pcie_establish_link(struct pcie_port *pp) +static void armada8k_pcie_establish_link(struct armada8k_pcie *pcie) { - struct armada8k_pcie *pcie = to_armada8k_pcie(pp); - void __iomem *base = pcie->base; + struct pcie_port *pp = &pcie->pp; u32 reg; if (!dw_pcie_link_up(pp)) { /* Disable LTSSM state machine to enable configuration */ - reg = readl(base + PCIE_GLOBAL_CONTROL_REG); + reg = dw_pcie_readl_rc(pp, PCIE_GLOBAL_CONTROL_REG); reg &= ~(PCIE_APP_LTSSM_EN); - writel(reg, base + PCIE_GLOBAL_CONTROL_REG); + dw_pcie_writel_rc(pp, PCIE_GLOBAL_CONTROL_REG, reg); } /* Set the device to root complex mode */ - reg = readl(base + PCIE_GLOBAL_CONTROL_REG); + reg = dw_pcie_readl_rc(pp, PCIE_GLOBAL_CONTROL_REG); reg &= ~(PCIE_DEVICE_TYPE_MASK << PCIE_DEVICE_TYPE_SHIFT); reg |= PCIE_DEVICE_TYPE_RC << PCIE_DEVICE_TYPE_SHIFT; - writel(reg, base + PCIE_GLOBAL_CONTROL_REG); + dw_pcie_writel_rc(pp, PCIE_GLOBAL_CONTROL_REG, reg); /* Set the PCIe master AxCache attributes */ - writel(ARCACHE_DEFAULT_VALUE, base + PCIE_ARCACHE_TRC_REG); - writel(AWCACHE_DEFAULT_VALUE, base + PCIE_AWCACHE_TRC_REG); + dw_pcie_writel_rc(pp, PCIE_ARCACHE_TRC_REG, ARCACHE_DEFAULT_VALUE); + dw_pcie_writel_rc(pp, PCIE_AWCACHE_TRC_REG, AWCACHE_DEFAULT_VALUE); /* Set the PCIe master AxDomain attributes */ - reg = readl(base + PCIE_ARUSER_REG); + reg = dw_pcie_readl_rc(pp, PCIE_ARUSER_REG); reg &= ~(AX_USER_DOMAIN_MASK << AX_USER_DOMAIN_SHIFT); reg |= DOMAIN_OUTER_SHAREABLE << AX_USER_DOMAIN_SHIFT; - writel(reg, base + PCIE_ARUSER_REG); + dw_pcie_writel_rc(pp, PCIE_ARUSER_REG, reg); - reg = readl(base + PCIE_AWUSER_REG); + reg = dw_pcie_readl_rc(pp, PCIE_AWUSER_REG); reg &= ~(AX_USER_DOMAIN_MASK << AX_USER_DOMAIN_SHIFT); reg |= DOMAIN_OUTER_SHAREABLE << AX_USER_DOMAIN_SHIFT; - writel(reg, base + PCIE_AWUSER_REG); + dw_pcie_writel_rc(pp, PCIE_AWUSER_REG, reg); /* Enable INT A-D interrupts */ - reg = readl(base + PCIE_GLOBAL_INT_MASK1_REG); + reg = dw_pcie_readl_rc(pp, PCIE_GLOBAL_INT_MASK1_REG); reg |= PCIE_INT_A_ASSERT_MASK | PCIE_INT_B_ASSERT_MASK | PCIE_INT_C_ASSERT_MASK | PCIE_INT_D_ASSERT_MASK; - writel(reg, base + PCIE_GLOBAL_INT_MASK1_REG); + dw_pcie_writel_rc(pp, PCIE_GLOBAL_INT_MASK1_REG, reg); if (!dw_pcie_link_up(pp)) { /* Configuration done. Start LTSSM */ - reg = readl(base + PCIE_GLOBAL_CONTROL_REG); + reg = dw_pcie_readl_rc(pp, PCIE_GLOBAL_CONTROL_REG); reg |= PCIE_APP_LTSSM_EN; - writel(reg, base + PCIE_GLOBAL_CONTROL_REG); + dw_pcie_writel_rc(pp, PCIE_GLOBAL_CONTROL_REG, reg); } /* Wait until the link becomes active again */ @@ -139,15 +136,16 @@ static void armada8k_pcie_establish_link(struct pcie_port *pp) static void armada8k_pcie_host_init(struct pcie_port *pp) { + struct armada8k_pcie *pcie = to_armada8k_pcie(pp); + dw_pcie_setup_rc(pp); - armada8k_pcie_establish_link(pp); + armada8k_pcie_establish_link(pcie); } static irqreturn_t armada8k_pcie_irq_handler(int irq, void *arg) { - struct pcie_port *pp = arg; - struct armada8k_pcie *pcie = to_armada8k_pcie(pp); - void __iomem *base = pcie->base; + struct armada8k_pcie *pcie = arg; + struct pcie_port *pp = &pcie->pp; u32 val; /* @@ -155,8 +153,8 @@ static irqreturn_t armada8k_pcie_irq_handler(int irq, void *arg) * PCI device. However, they are also latched into the PCIe * controller, so we simply discard them. */ - val = readl(base + PCIE_GLOBAL_INT_CAUSE1_REG); - writel(val, base + PCIE_GLOBAL_INT_CAUSE1_REG); + val = dw_pcie_readl_rc(pp, PCIE_GLOBAL_INT_CAUSE1_REG); + dw_pcie_writel_rc(pp, PCIE_GLOBAL_INT_CAUSE1_REG, val); return IRQ_HANDLED; } @@ -166,9 +164,10 @@ static struct pcie_host_ops armada8k_pcie_host_ops = { .host_init = armada8k_pcie_host_init, }; -static int armada8k_add_pcie_port(struct pcie_port *pp, +static int armada8k_add_pcie_port(struct armada8k_pcie *pcie, struct platform_device *pdev) { + struct pcie_port *pp = &pcie->pp; struct device *dev = &pdev->dev; int ret; @@ -182,7 +181,7 @@ static int armada8k_add_pcie_port(struct pcie_port *pp, } ret = devm_request_irq(dev, pp->irq, armada8k_pcie_irq_handler, - IRQF_SHARED, "armada8k-pcie", pp); + IRQF_SHARED, "armada8k-pcie", pcie); if (ret) { dev_err(dev, "failed to request irq %d\n", pp->irq); return ret; @@ -217,7 +216,6 @@ static int armada8k_pcie_probe(struct platform_device *pdev) pp = &pcie->pp; pp->dev = dev; - platform_set_drvdata(pdev, pcie); /* Get the dw-pcie unit configuration/control registers base. */ base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl"); @@ -228,9 +226,7 @@ static int armada8k_pcie_probe(struct platform_device *pdev) goto fail; } - pcie->base = pp->dbi_base + PCIE_VENDOR_REGS_OFFSET; - - ret = armada8k_add_pcie_port(pp, pdev); + ret = armada8k_add_pcie_port(pcie, pdev); if (ret) goto fail; diff --git a/drivers/pci/host/pcie-artpec6.c b/drivers/pci/host/pcie-artpec6.c index 39bf1a6df463..212786b27f1a 100644 --- a/drivers/pci/host/pcie-artpec6.c +++ b/drivers/pci/host/pcie-artpec6.c @@ -27,9 +27,9 @@ #define to_artpec6_pcie(x) container_of(x, struct artpec6_pcie, pp) struct artpec6_pcie { - struct pcie_port pp; - struct regmap *regmap; - void __iomem *phy_base; + struct pcie_port pp; /* pp.dbi_base is DT dbi */ + struct regmap *regmap; /* DT axis,syscon-pcie */ + void __iomem *phy_base; /* DT phy */ }; /* PCIe Port Logic registers (memory-mapped) */ @@ -65,18 +65,31 @@ struct artpec6_pcie { #define ARTPEC6_CPU_TO_BUS_ADDR 0x0fffffff -static int artpec6_pcie_establish_link(struct pcie_port *pp) +static u32 artpec6_pcie_readl(struct artpec6_pcie *artpec6_pcie, u32 offset) { - struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pp); + u32 val; + + regmap_read(artpec6_pcie->regmap, offset, &val); + return val; +} + +static void artpec6_pcie_writel(struct artpec6_pcie *artpec6_pcie, u32 offset, u32 val) +{ + regmap_write(artpec6_pcie->regmap, offset, val); +} + +static int artpec6_pcie_establish_link(struct artpec6_pcie *artpec6_pcie) +{ + struct pcie_port *pp = &artpec6_pcie->pp; u32 val; unsigned int retries; /* Hold DW core in reset */ - regmap_read(artpec6_pcie->regmap, PCIECFG, &val); + val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); val |= PCIECFG_CORE_RESET_REQ; - regmap_write(artpec6_pcie->regmap, PCIECFG, val); + artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); - regmap_read(artpec6_pcie->regmap, PCIECFG, &val); + val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); val |= PCIECFG_RISRCREN | /* Receiver term. 50 Ohm */ PCIECFG_MODE_TX_DRV_EN | PCIECFG_CISRREN | /* Reference clock term. 100 Ohm */ @@ -84,27 +97,27 @@ static int artpec6_pcie_establish_link(struct pcie_port *pp) val |= PCIECFG_REFCLK_ENABLE; val &= ~PCIECFG_DBG_OEN; val &= ~PCIECFG_CLKREQ_B; - regmap_write(artpec6_pcie->regmap, PCIECFG, val); + artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); usleep_range(5000, 6000); - regmap_read(artpec6_pcie->regmap, NOCCFG, &val); + val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); val |= NOCCFG_ENABLE_CLK_PCIE; - regmap_write(artpec6_pcie->regmap, NOCCFG, val); + artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); usleep_range(20, 30); - regmap_read(artpec6_pcie->regmap, PCIECFG, &val); + val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); val |= PCIECFG_PCLK_ENABLE | PCIECFG_PLL_ENABLE; - regmap_write(artpec6_pcie->regmap, PCIECFG, val); + artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); usleep_range(6000, 7000); - regmap_read(artpec6_pcie->regmap, NOCCFG, &val); + val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); val &= ~NOCCFG_POWER_PCIE_IDLEREQ; - regmap_write(artpec6_pcie->regmap, NOCCFG, val); + artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); retries = 50; do { usleep_range(1000, 2000); - regmap_read(artpec6_pcie->regmap, NOCCFG, &val); + val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); retries--; } while (retries && (val & (NOCCFG_POWER_PCIE_IDLEACK | NOCCFG_POWER_PCIE_IDLE))); @@ -117,16 +130,16 @@ static int artpec6_pcie_establish_link(struct pcie_port *pp) } while (retries && !(val & PHY_COSPLLLOCK)); /* Take DW core out of reset */ - regmap_read(artpec6_pcie->regmap, PCIECFG, &val); + val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); val &= ~PCIECFG_CORE_RESET_REQ; - regmap_write(artpec6_pcie->regmap, PCIECFG, val); + artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); usleep_range(100, 200); /* * Enable writing to config regs. This is required as the Synopsys * driver changes the class code. That register needs DBI write enable. */ - writel(DBI_RO_WR_EN, pp->dbi_base + MISC_CONTROL_1_OFF); + dw_pcie_writel_rc(pp, MISC_CONTROL_1_OFF, DBI_RO_WR_EN); pp->io_base &= ARTPEC6_CPU_TO_BUS_ADDR; pp->mem_base &= ARTPEC6_CPU_TO_BUS_ADDR; @@ -137,78 +150,69 @@ static int artpec6_pcie_establish_link(struct pcie_port *pp) dw_pcie_setup_rc(pp); /* assert LTSSM enable */ - regmap_read(artpec6_pcie->regmap, PCIECFG, &val); + val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); val |= PCIECFG_LTSSM_ENABLE; - regmap_write(artpec6_pcie->regmap, PCIECFG, val); + artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); /* check if the link is up or not */ if (!dw_pcie_wait_for_link(pp)) return 0; dev_dbg(pp->dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n", - readl(pp->dbi_base + PCIE_PHY_DEBUG_R0), - readl(pp->dbi_base + PCIE_PHY_DEBUG_R1)); + dw_pcie_readl_rc(pp, PCIE_PHY_DEBUG_R0), + dw_pcie_readl_rc(pp, PCIE_PHY_DEBUG_R1)); return -ETIMEDOUT; } -static void artpec6_pcie_enable_interrupts(struct pcie_port *pp) +static void artpec6_pcie_enable_interrupts(struct artpec6_pcie *artpec6_pcie) { + struct pcie_port *pp = &artpec6_pcie->pp; + if (IS_ENABLED(CONFIG_PCI_MSI)) dw_pcie_msi_init(pp); } static void artpec6_pcie_host_init(struct pcie_port *pp) { - artpec6_pcie_establish_link(pp); - artpec6_pcie_enable_interrupts(pp); -} + struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pp); -static int artpec6_pcie_link_up(struct pcie_port *pp) -{ - u32 rc; - - /* - * Get status from Synopsys IP - * link is debug bit 36, debug register 1 starts at bit 32 - */ - rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1) & (0x1 << (36 - 32)); - if (rc) - return 1; - - return 0; + artpec6_pcie_establish_link(artpec6_pcie); + artpec6_pcie_enable_interrupts(artpec6_pcie); } static struct pcie_host_ops artpec6_pcie_host_ops = { - .link_up = artpec6_pcie_link_up, .host_init = artpec6_pcie_host_init, }; static irqreturn_t artpec6_pcie_msi_handler(int irq, void *arg) { - struct pcie_port *pp = arg; + struct artpec6_pcie *artpec6_pcie = arg; + struct pcie_port *pp = &artpec6_pcie->pp; return dw_handle_msi_irq(pp); } -static int artpec6_add_pcie_port(struct pcie_port *pp, +static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie, struct platform_device *pdev) { + struct pcie_port *pp = &artpec6_pcie->pp; + struct device *dev = pp->dev; int ret; if (IS_ENABLED(CONFIG_PCI_MSI)) { pp->msi_irq = platform_get_irq_byname(pdev, "msi"); if (pp->msi_irq <= 0) { - dev_err(&pdev->dev, "failed to get MSI irq\n"); + dev_err(dev, "failed to get MSI irq\n"); return -ENODEV; } - ret = devm_request_irq(&pdev->dev, pp->msi_irq, + ret = devm_request_irq(dev, pp->msi_irq, artpec6_pcie_msi_handler, IRQF_SHARED | IRQF_NO_THREAD, - "artpec6-pcie-msi", pp); + "artpec6-pcie-msi", artpec6_pcie); if (ret) { - dev_err(&pdev->dev, "failed to request MSI irq\n"); + dev_err(dev, "failed to request MSI irq\n"); return ret; } } @@ -218,7 +222,7 @@ static int artpec6_add_pcie_port(struct pcie_port *pp, ret = dw_pcie_host_init(pp); if (ret) { - dev_err(&pdev->dev, "failed to initialize host\n"); + dev_err(dev, "failed to initialize host\n"); return ret; } @@ -227,41 +231,40 @@ static int artpec6_add_pcie_port(struct pcie_port *pp, static int artpec6_pcie_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct artpec6_pcie *artpec6_pcie; struct pcie_port *pp; struct resource *dbi_base; struct resource *phy_base; int ret; - artpec6_pcie = devm_kzalloc(&pdev->dev, sizeof(*artpec6_pcie), - GFP_KERNEL); + artpec6_pcie = devm_kzalloc(dev, sizeof(*artpec6_pcie), GFP_KERNEL); if (!artpec6_pcie) return -ENOMEM; pp = &artpec6_pcie->pp; - pp->dev = &pdev->dev; + pp->dev = dev; dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); - pp->dbi_base = devm_ioremap_resource(&pdev->dev, dbi_base); + pp->dbi_base = devm_ioremap_resource(dev, dbi_base); if (IS_ERR(pp->dbi_base)) return PTR_ERR(pp->dbi_base); phy_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); - artpec6_pcie->phy_base = devm_ioremap_resource(&pdev->dev, phy_base); + artpec6_pcie->phy_base = devm_ioremap_resource(dev, phy_base); if (IS_ERR(artpec6_pcie->phy_base)) return PTR_ERR(artpec6_pcie->phy_base); artpec6_pcie->regmap = - syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + syscon_regmap_lookup_by_phandle(dev->of_node, "axis,syscon-pcie"); if (IS_ERR(artpec6_pcie->regmap)) return PTR_ERR(artpec6_pcie->regmap); - ret = artpec6_add_pcie_port(pp, pdev); + ret = artpec6_add_pcie_port(artpec6_pcie, pdev); if (ret < 0) return ret; - platform_set_drvdata(pdev, artpec6_pcie); return 0; } diff --git a/drivers/pci/host/pcie-designware-plat.c b/drivers/pci/host/pcie-designware-plat.c index 17da005497a5..537f58a664fa 100644 --- a/drivers/pci/host/pcie-designware-plat.c +++ b/drivers/pci/host/pcie-designware-plat.c @@ -25,8 +25,7 @@ #include "pcie-designware.h" struct dw_plat_pcie { - void __iomem *mem_base; - struct pcie_port pp; + struct pcie_port pp; /* pp.dbi_base is DT 0th resource */ }; static irqreturn_t dw_plat_pcie_msi_irq_handler(int irq, void *arg) @@ -52,6 +51,7 @@ static struct pcie_host_ops dw_plat_pcie_host_ops = { static int dw_plat_add_pcie_port(struct pcie_port *pp, struct platform_device *pdev) { + struct device *dev = pp->dev; int ret; pp->irq = platform_get_irq(pdev, 1); @@ -63,11 +63,11 @@ static int dw_plat_add_pcie_port(struct pcie_port *pp, if (pp->msi_irq < 0) return pp->msi_irq; - ret = devm_request_irq(&pdev->dev, pp->msi_irq, + ret = devm_request_irq(dev, pp->msi_irq, dw_plat_pcie_msi_irq_handler, IRQF_SHARED, "dw-plat-pcie-msi", pp); if (ret) { - dev_err(&pdev->dev, "failed to request MSI IRQ\n"); + dev_err(dev, "failed to request MSI IRQ\n"); return ret; } } @@ -77,7 +77,7 @@ static int dw_plat_add_pcie_port(struct pcie_port *pp, ret = dw_pcie_host_init(pp); if (ret) { - dev_err(&pdev->dev, "failed to initialize host\n"); + dev_err(dev, "failed to initialize host\n"); return ret; } @@ -86,31 +86,28 @@ static int dw_plat_add_pcie_port(struct pcie_port *pp, static int dw_plat_pcie_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct dw_plat_pcie *dw_plat_pcie; struct pcie_port *pp; struct resource *res; /* Resource from DT */ int ret; - dw_plat_pcie = devm_kzalloc(&pdev->dev, sizeof(*dw_plat_pcie), - GFP_KERNEL); + dw_plat_pcie = devm_kzalloc(dev, sizeof(*dw_plat_pcie), GFP_KERNEL); if (!dw_plat_pcie) return -ENOMEM; pp = &dw_plat_pcie->pp; - pp->dev = &pdev->dev; + pp->dev = dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dw_plat_pcie->mem_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(dw_plat_pcie->mem_base)) - return PTR_ERR(dw_plat_pcie->mem_base); - - pp->dbi_base = dw_plat_pcie->mem_base; + pp->dbi_base = devm_ioremap_resource(dev, res); + if (IS_ERR(pp->dbi_base)) + return PTR_ERR(pp->dbi_base); ret = dw_plat_add_pcie_port(pp, pdev); if (ret < 0) return ret; - platform_set_drvdata(pdev, dw_plat_pcie); return 0; } diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 74da71ea544a..035f50c03281 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -141,41 +141,35 @@ int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val) return PCIBIOS_SUCCESSFUL; } -static inline u32 dw_pcie_readl_rc(struct pcie_port *pp, u32 reg) +u32 dw_pcie_readl_rc(struct pcie_port *pp, u32 reg) { if (pp->ops->readl_rc) - return pp->ops->readl_rc(pp, pp->dbi_base + reg); + return pp->ops->readl_rc(pp, reg); return readl(pp->dbi_base + reg); } -static inline void dw_pcie_writel_rc(struct pcie_port *pp, u32 val, u32 reg) +void dw_pcie_writel_rc(struct pcie_port *pp, u32 reg, u32 val) { if (pp->ops->writel_rc) - pp->ops->writel_rc(pp, val, pp->dbi_base + reg); + pp->ops->writel_rc(pp, reg, val); else writel(val, pp->dbi_base + reg); } -static inline u32 dw_pcie_readl_unroll(struct pcie_port *pp, u32 index, u32 reg) +static u32 dw_pcie_readl_unroll(struct pcie_port *pp, u32 index, u32 reg) { u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); - if (pp->ops->readl_rc) - return pp->ops->readl_rc(pp, pp->dbi_base + offset + reg); - - return readl(pp->dbi_base + offset + reg); + return dw_pcie_readl_rc(pp, offset + reg); } -static inline void dw_pcie_writel_unroll(struct pcie_port *pp, u32 index, - u32 val, u32 reg) +static void dw_pcie_writel_unroll(struct pcie_port *pp, u32 index, u32 reg, + u32 val) { u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); - if (pp->ops->writel_rc) - pp->ops->writel_rc(pp, val, pp->dbi_base + offset + reg); - else - writel(val, pp->dbi_base + offset + reg); + dw_pcie_writel_rc(pp, offset + reg, val); } static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, @@ -202,35 +196,35 @@ static void dw_pcie_prog_outbound_atu(struct pcie_port *pp, int index, u32 retries, val; if (pp->iatu_unroll_enabled) { - dw_pcie_writel_unroll(pp, index, - lower_32_bits(cpu_addr), PCIE_ATU_UNR_LOWER_BASE); - dw_pcie_writel_unroll(pp, index, - upper_32_bits(cpu_addr), PCIE_ATU_UNR_UPPER_BASE); - dw_pcie_writel_unroll(pp, index, - lower_32_bits(cpu_addr + size - 1), PCIE_ATU_UNR_LIMIT); - dw_pcie_writel_unroll(pp, index, - lower_32_bits(pci_addr), PCIE_ATU_UNR_LOWER_TARGET); - dw_pcie_writel_unroll(pp, index, - upper_32_bits(pci_addr), PCIE_ATU_UNR_UPPER_TARGET); - dw_pcie_writel_unroll(pp, index, - type, PCIE_ATU_UNR_REGION_CTRL1); - dw_pcie_writel_unroll(pp, index, - PCIE_ATU_ENABLE, PCIE_ATU_UNR_REGION_CTRL2); + dw_pcie_writel_unroll(pp, index, PCIE_ATU_UNR_LOWER_BASE, + lower_32_bits(cpu_addr)); + dw_pcie_writel_unroll(pp, index, PCIE_ATU_UNR_UPPER_BASE, + upper_32_bits(cpu_addr)); + dw_pcie_writel_unroll(pp, index, PCIE_ATU_UNR_LIMIT, + lower_32_bits(cpu_addr + size - 1)); + dw_pcie_writel_unroll(pp, index, PCIE_ATU_UNR_LOWER_TARGET, + lower_32_bits(pci_addr)); + dw_pcie_writel_unroll(pp, index, PCIE_ATU_UNR_UPPER_TARGET, + upper_32_bits(pci_addr)); + dw_pcie_writel_unroll(pp, index, PCIE_ATU_UNR_REGION_CTRL1, + type); + dw_pcie_writel_unroll(pp, index, PCIE_ATU_UNR_REGION_CTRL2, + PCIE_ATU_ENABLE); } else { - dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | index, - PCIE_ATU_VIEWPORT); - dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr), - PCIE_ATU_LOWER_BASE); - dw_pcie_writel_rc(pp, upper_32_bits(cpu_addr), - PCIE_ATU_UPPER_BASE); - dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr + size - 1), - PCIE_ATU_LIMIT); - dw_pcie_writel_rc(pp, lower_32_bits(pci_addr), - PCIE_ATU_LOWER_TARGET); - dw_pcie_writel_rc(pp, upper_32_bits(pci_addr), - PCIE_ATU_UPPER_TARGET); - dw_pcie_writel_rc(pp, type, PCIE_ATU_CR1); - dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); + dw_pcie_writel_rc(pp, PCIE_ATU_VIEWPORT, + PCIE_ATU_REGION_OUTBOUND | index); + dw_pcie_writel_rc(pp, PCIE_ATU_LOWER_BASE, + lower_32_bits(cpu_addr)); + dw_pcie_writel_rc(pp, PCIE_ATU_UPPER_BASE, + upper_32_bits(cpu_addr)); + dw_pcie_writel_rc(pp, PCIE_ATU_LIMIT, + lower_32_bits(cpu_addr + size - 1)); + dw_pcie_writel_rc(pp, PCIE_ATU_LOWER_TARGET, + lower_32_bits(pci_addr)); + dw_pcie_writel_rc(pp, PCIE_ATU_UPPER_TARGET, + upper_32_bits(pci_addr)); + dw_pcie_writel_rc(pp, PCIE_ATU_CR1, type); + dw_pcie_writel_rc(pp, PCIE_ATU_CR2, PCIE_ATU_ENABLE); } /* @@ -760,8 +754,8 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus, return ret; } -static int dw_pcie_valid_config(struct pcie_port *pp, - struct pci_bus *bus, int dev) +static int dw_pcie_valid_device(struct pcie_port *pp, struct pci_bus *bus, + int dev) { /* If there is no link, then there is no device */ if (bus->number != pp->root_bus_nr) { @@ -781,7 +775,7 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, { struct pcie_port *pp = bus->sysdata; - if (dw_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0) { + if (!dw_pcie_valid_device(pp, bus, PCI_SLOT(devfn))) { *val = 0xffffffff; return PCIBIOS_DEVICE_NOT_FOUND; } @@ -797,7 +791,7 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn, { struct pcie_port *pp = bus->sysdata; - if (dw_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0) + if (!dw_pcie_valid_device(pp, bus, PCI_SLOT(devfn))) return PCIBIOS_DEVICE_NOT_FOUND; if (bus->number == pp->root_bus_nr) @@ -835,7 +829,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp) dev_err(pp->dev, "num-lanes %u: invalid value\n", pp->lanes); return; } - dw_pcie_writel_rc(pp, val, PCIE_PORT_LINK_CONTROL); + dw_pcie_writel_rc(pp, PCIE_PORT_LINK_CONTROL, val); /* set link width speed control register */ val = dw_pcie_readl_rc(pp, PCIE_LINK_WIDTH_SPEED_CONTROL); @@ -854,30 +848,30 @@ void dw_pcie_setup_rc(struct pcie_port *pp) val |= PORT_LOGIC_LINK_WIDTH_8_LANES; break; } - dw_pcie_writel_rc(pp, val, PCIE_LINK_WIDTH_SPEED_CONTROL); + dw_pcie_writel_rc(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, val); /* setup RC BARs */ - dw_pcie_writel_rc(pp, 0x00000004, PCI_BASE_ADDRESS_0); - dw_pcie_writel_rc(pp, 0x00000000, PCI_BASE_ADDRESS_1); + dw_pcie_writel_rc(pp, PCI_BASE_ADDRESS_0, 0x00000004); + dw_pcie_writel_rc(pp, PCI_BASE_ADDRESS_1, 0x00000000); /* setup interrupt pins */ val = dw_pcie_readl_rc(pp, PCI_INTERRUPT_LINE); val &= 0xffff00ff; val |= 0x00000100; - dw_pcie_writel_rc(pp, val, PCI_INTERRUPT_LINE); + dw_pcie_writel_rc(pp, PCI_INTERRUPT_LINE, val); /* setup bus numbers */ val = dw_pcie_readl_rc(pp, PCI_PRIMARY_BUS); val &= 0xff000000; val |= 0x00010100; - dw_pcie_writel_rc(pp, val, PCI_PRIMARY_BUS); + dw_pcie_writel_rc(pp, PCI_PRIMARY_BUS, val); /* setup command register */ val = dw_pcie_readl_rc(pp, PCI_COMMAND); val &= 0xffff0000; val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_SERR; - dw_pcie_writel_rc(pp, val, PCI_COMMAND); + dw_pcie_writel_rc(pp, PCI_COMMAND, val); /* * If the platform provides ->rd_other_conf, it means the platform diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h index c8e5bc647f49..a567ea288ee2 100644 --- a/drivers/pci/host/pcie-designware.h +++ b/drivers/pci/host/pcie-designware.h @@ -54,9 +54,8 @@ struct pcie_port { }; struct pcie_host_ops { - u32 (*readl_rc)(struct pcie_port *pp, void __iomem *dbi_base); - void (*writel_rc)(struct pcie_port *pp, - u32 val, void __iomem *dbi_base); + u32 (*readl_rc)(struct pcie_port *pp, u32 reg); + void (*writel_rc)(struct pcie_port *pp, u32 reg, u32 val); int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val); int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val); int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus, @@ -73,6 +72,8 @@ struct pcie_host_ops { int (*msi_host_init)(struct pcie_port *pp, struct msi_controller *chip); }; +u32 dw_pcie_readl_rc(struct pcie_port *pp, u32 reg); +void dw_pcie_writel_rc(struct pcie_port *pp, u32 reg, u32 val); int dw_pcie_cfg_read(void __iomem *addr, int size, u32 *val); int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val); irqreturn_t dw_handle_msi_irq(struct pcie_port *pp); diff --git a/drivers/pci/host/pcie-hisi.c b/drivers/pci/host/pcie-hisi.c index 7ee9dfcc45fb..56154c25980c 100644 --- a/drivers/pci/host/pcie-hisi.c +++ b/drivers/pci/host/pcie-hisi.c @@ -22,51 +22,38 @@ #include "pcie-designware.h" -#define PCIE_LTSSM_LINKUP_STATE 0x11 -#define PCIE_LTSSM_STATE_MASK 0x3F -#define PCIE_SUBCTRL_SYS_STATE4_REG 0x6818 -#define PCIE_SYS_STATE4 0x31c -#define PCIE_HIP06_CTRL_OFF 0x1000 +#define PCIE_SUBCTRL_SYS_STATE4_REG 0x6818 +#define PCIE_HIP06_CTRL_OFF 0x1000 +#define PCIE_SYS_STATE4 (PCIE_HIP06_CTRL_OFF + 0x31c) +#define PCIE_LTSSM_LINKUP_STATE 0x11 +#define PCIE_LTSSM_STATE_MASK 0x3F #define to_hisi_pcie(x) container_of(x, struct hisi_pcie, pp) struct hisi_pcie; struct pcie_soc_ops { - int (*hisi_pcie_link_up)(struct hisi_pcie *pcie); + int (*hisi_pcie_link_up)(struct hisi_pcie *hisi_pcie); }; struct hisi_pcie { + struct pcie_port pp; /* pp.dbi_base is DT rc_dbi */ struct regmap *subctrl; - void __iomem *reg_base; u32 port_id; - struct pcie_port pp; struct pcie_soc_ops *soc_ops; }; -static inline void hisi_pcie_apb_writel(struct hisi_pcie *pcie, - u32 val, u32 reg) -{ - writel(val, pcie->reg_base + reg); -} - -static inline u32 hisi_pcie_apb_readl(struct hisi_pcie *pcie, u32 reg) -{ - return readl(pcie->reg_base + reg); -} - /* HipXX PCIe host only supports 32-bit config access */ static int hisi_pcie_cfg_read(struct pcie_port *pp, int where, int size, u32 *val) { u32 reg; u32 reg_val; - struct hisi_pcie *pcie = to_hisi_pcie(pp); void *walker = ®_val; walker += (where & 0x3); reg = where & ~0x3; - reg_val = hisi_pcie_apb_readl(pcie, reg); + reg_val = dw_pcie_readl_rc(pp, reg); if (size == 1) *val = *(u8 __force *) walker; @@ -86,21 +73,20 @@ static int hisi_pcie_cfg_write(struct pcie_port *pp, int where, int size, { u32 reg_val; u32 reg; - struct hisi_pcie *pcie = to_hisi_pcie(pp); void *walker = ®_val; walker += (where & 0x3); reg = where & ~0x3; if (size == 4) - hisi_pcie_apb_writel(pcie, val, reg); + dw_pcie_writel_rc(pp, reg, val); else if (size == 2) { - reg_val = hisi_pcie_apb_readl(pcie, reg); + reg_val = dw_pcie_readl_rc(pp, reg); *(u16 __force *) walker = val; - hisi_pcie_apb_writel(pcie, reg_val, reg); + dw_pcie_writel_rc(pp, reg, reg_val); } else if (size == 1) { - reg_val = hisi_pcie_apb_readl(pcie, reg); + reg_val = dw_pcie_readl_rc(pp, reg); *(u8 __force *) walker = val; - hisi_pcie_apb_writel(pcie, reg_val, reg); + dw_pcie_writel_rc(pp, reg, reg_val); } else return PCIBIOS_BAD_REGISTER_NUMBER; @@ -119,10 +105,10 @@ static int hisi_pcie_link_up_hip05(struct hisi_pcie *hisi_pcie) static int hisi_pcie_link_up_hip06(struct hisi_pcie *hisi_pcie) { + struct pcie_port *pp = &hisi_pcie->pp; u32 val; - val = hisi_pcie_apb_readl(hisi_pcie, PCIE_HIP06_CTRL_OFF + - PCIE_SYS_STATE4); + val = dw_pcie_readl_rc(pp, PCIE_SYS_STATE4); return ((val & PCIE_LTSSM_STATE_MASK) == PCIE_LTSSM_LINKUP_STATE); } @@ -140,19 +126,20 @@ static struct pcie_host_ops hisi_pcie_host_ops = { .link_up = hisi_pcie_link_up, }; -static int hisi_add_pcie_port(struct pcie_port *pp, - struct platform_device *pdev) +static int hisi_add_pcie_port(struct hisi_pcie *hisi_pcie, + struct platform_device *pdev) { + struct pcie_port *pp = &hisi_pcie->pp; + struct device *dev = pp->dev; int ret; u32 port_id; - struct hisi_pcie *hisi_pcie = to_hisi_pcie(pp); - if (of_property_read_u32(pdev->dev.of_node, "port-id", &port_id)) { - dev_err(&pdev->dev, "failed to read port-id\n"); + if (of_property_read_u32(dev->of_node, "port-id", &port_id)) { + dev_err(dev, "failed to read port-id\n"); return -EINVAL; } if (port_id > 3) { - dev_err(&pdev->dev, "Invalid port-id: %d\n", port_id); + dev_err(dev, "Invalid port-id: %d\n", port_id); return -EINVAL; } hisi_pcie->port_id = port_id; @@ -161,7 +148,7 @@ static int hisi_add_pcie_port(struct pcie_port *pp, ret = dw_pcie_host_init(pp); if (ret) { - dev_err(&pdev->dev, "failed to initialize host\n"); + dev_err(dev, "failed to initialize host\n"); return ret; } @@ -170,6 +157,7 @@ static int hisi_add_pcie_port(struct pcie_port *pp, static int hisi_pcie_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct hisi_pcie *hisi_pcie; struct pcie_port *pp; const struct of_device_id *match; @@ -177,40 +165,36 @@ static int hisi_pcie_probe(struct platform_device *pdev) struct device_driver *driver; int ret; - hisi_pcie = devm_kzalloc(&pdev->dev, sizeof(*hisi_pcie), GFP_KERNEL); + hisi_pcie = devm_kzalloc(dev, sizeof(*hisi_pcie), GFP_KERNEL); if (!hisi_pcie) return -ENOMEM; pp = &hisi_pcie->pp; - pp->dev = &pdev->dev; - driver = (pdev->dev).driver; + pp->dev = dev; + driver = dev->driver; - match = of_match_device(driver->of_match_table, &pdev->dev); + match = of_match_device(driver->of_match_table, dev); hisi_pcie->soc_ops = (struct pcie_soc_ops *) match->data; hisi_pcie->subctrl = syscon_regmap_lookup_by_compatible("hisilicon,pcie-sas-subctrl"); if (IS_ERR(hisi_pcie->subctrl)) { - dev_err(pp->dev, "cannot get subctrl base\n"); + dev_err(dev, "cannot get subctrl base\n"); return PTR_ERR(hisi_pcie->subctrl); } reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rc_dbi"); - hisi_pcie->reg_base = devm_ioremap_resource(&pdev->dev, reg); - if (IS_ERR(hisi_pcie->reg_base)) { - dev_err(pp->dev, "cannot get rc_dbi base\n"); - return PTR_ERR(hisi_pcie->reg_base); + pp->dbi_base = devm_ioremap_resource(dev, reg); + if (IS_ERR(pp->dbi_base)) { + dev_err(dev, "cannot get rc_dbi base\n"); + return PTR_ERR(pp->dbi_base); } - hisi_pcie->pp.dbi_base = hisi_pcie->reg_base; - - ret = hisi_add_pcie_port(pp, pdev); + ret = hisi_add_pcie_port(hisi_pcie, pdev); if (ret) return ret; - platform_set_drvdata(pdev, hisi_pcie); - - dev_warn(pp->dev, "only 32-bit config accesses supported; smaller writes may corrupt adjacent RW1C fields\n"); + dev_warn(dev, "only 32-bit config accesses supported; smaller writes may corrupt adjacent RW1C fields\n"); return 0; } diff --git a/drivers/pci/host/pcie-iproc-bcma.c b/drivers/pci/host/pcie-iproc-bcma.c index 0d7bee4a0d26..8ce089043a27 100644 --- a/drivers/pci/host/pcie-iproc-bcma.c +++ b/drivers/pci/host/pcie-iproc-bcma.c @@ -42,19 +42,24 @@ static int iproc_pcie_bcma_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) static int iproc_pcie_bcma_probe(struct bcma_device *bdev) { + struct device *dev = &bdev->dev; struct iproc_pcie *pcie; LIST_HEAD(res); struct resource res_mem; int ret; - pcie = devm_kzalloc(&bdev->dev, sizeof(*pcie), GFP_KERNEL); + pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); if (!pcie) return -ENOMEM; - pcie->dev = &bdev->dev; - bcma_set_drvdata(bdev, pcie); + pcie->dev = dev; pcie->base = bdev->io_addr; + if (!pcie->base) { + dev_err(dev, "no controller registers\n"); + return -ENOMEM; + } + pcie->base_addr = bdev->addr; res_mem.start = bdev->addr_s[0]; @@ -67,10 +72,11 @@ static int iproc_pcie_bcma_probe(struct bcma_device *bdev) ret = iproc_pcie_setup(pcie, &res); if (ret) - dev_err(pcie->dev, "PCIe controller setup failed\n"); + dev_err(dev, "PCIe controller setup failed\n"); pci_free_resource_list(&res); + bcma_set_drvdata(bdev, pcie); return ret; } diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/host/pcie-iproc-platform.c index 1738c5288eb6..a3de087976b3 100644 --- a/drivers/pci/host/pcie-iproc-platform.c +++ b/drivers/pci/host/pcie-iproc-platform.c @@ -40,35 +40,35 @@ MODULE_DEVICE_TABLE(of, iproc_pcie_of_match_table); static int iproc_pcie_pltfm_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; const struct of_device_id *of_id; struct iproc_pcie *pcie; - struct device_node *np = pdev->dev.of_node; + struct device_node *np = dev->of_node; struct resource reg; resource_size_t iobase = 0; LIST_HEAD(res); int ret; - of_id = of_match_device(iproc_pcie_of_match_table, &pdev->dev); + of_id = of_match_device(iproc_pcie_of_match_table, dev); if (!of_id) return -EINVAL; - pcie = devm_kzalloc(&pdev->dev, sizeof(struct iproc_pcie), GFP_KERNEL); + pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); if (!pcie) return -ENOMEM; - pcie->dev = &pdev->dev; + pcie->dev = dev; pcie->type = (enum iproc_pcie_type)of_id->data; - platform_set_drvdata(pdev, pcie); ret = of_address_to_resource(np, 0, ®); if (ret < 0) { - dev_err(pcie->dev, "unable to obtain controller resources\n"); + dev_err(dev, "unable to obtain controller resources\n"); return ret; } - pcie->base = devm_ioremap(pcie->dev, reg.start, resource_size(®)); + pcie->base = devm_ioremap(dev, reg.start, resource_size(®)); if (!pcie->base) { - dev_err(pcie->dev, "unable to map controller registers\n"); + dev_err(dev, "unable to map controller registers\n"); return -ENOMEM; } pcie->base_addr = reg.start; @@ -79,7 +79,7 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) ret = of_property_read_u32(np, "brcm,pcie-ob-axi-offset", &val); if (ret) { - dev_err(pcie->dev, + dev_err(dev, "missing brcm,pcie-ob-axi-offset property\n"); return ret; } @@ -88,7 +88,7 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) ret = of_property_read_u32(np, "brcm,pcie-ob-window-size", &val); if (ret) { - dev_err(pcie->dev, + dev_err(dev, "missing brcm,pcie-ob-window-size property\n"); return ret; } @@ -101,7 +101,7 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) } /* PHY use is optional */ - pcie->phy = devm_phy_get(&pdev->dev, "pcie-phy"); + pcie->phy = devm_phy_get(dev, "pcie-phy"); if (IS_ERR(pcie->phy)) { if (PTR_ERR(pcie->phy) == -EPROBE_DEFER) return -EPROBE_DEFER; @@ -110,7 +110,7 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) ret = of_pci_get_host_bridge_resources(np, 0, 0xff, &res, &iobase); if (ret) { - dev_err(pcie->dev, + dev_err(dev, "unable to get PCI host bridge resources\n"); return ret; } @@ -119,10 +119,11 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) ret = iproc_pcie_setup(pcie, &res); if (ret) - dev_err(pcie->dev, "PCIe controller setup failed\n"); + dev_err(dev, "PCIe controller setup failed\n"); pci_free_resource_list(&res); + platform_set_drvdata(pdev, pcie); return ret; } diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index e167b2f0098d..0b999a9fb843 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -63,6 +63,8 @@ #define OARR_SIZE_CFG_SHIFT 1 #define OARR_SIZE_CFG BIT(OARR_SIZE_CFG_SHIFT) +#define PCI_EXP_CAP 0xac + #define MAX_NUM_OB_WINDOWS 2 #define IPROC_PCIE_REG_INVALID 0xffff @@ -258,9 +260,10 @@ static void iproc_pcie_reset(struct iproc_pcie *pcie) static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus) { + struct device *dev = pcie->dev; u8 hdr_type; u32 link_ctrl, class, val; - u16 pos, link_status; + u16 pos = PCI_EXP_CAP, link_status; bool link_is_active = false; /* @@ -272,14 +275,14 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus) val = iproc_pcie_read_reg(pcie, IPROC_PCIE_LINK_STATUS); if (!(val & PCIE_PHYLINKUP) || !(val & PCIE_DL_ACTIVE)) { - dev_err(pcie->dev, "PHY or data link is INACTIVE!\n"); + dev_err(dev, "PHY or data link is INACTIVE!\n"); return -ENODEV; } /* make sure we are not in EP mode */ pci_bus_read_config_byte(bus, 0, PCI_HEADER_TYPE, &hdr_type); if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE) { - dev_err(pcie->dev, "in EP mode, hdr=%#02x\n", hdr_type); + dev_err(dev, "in EP mode, hdr=%#02x\n", hdr_type); return -EFAULT; } @@ -293,30 +296,27 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus) pci_bus_write_config_dword(bus, 0, PCI_BRIDGE_CTRL_REG_OFFSET, class); /* check link status to see if link is active */ - pos = pci_bus_find_capability(bus, 0, PCI_CAP_ID_EXP); pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA, &link_status); if (link_status & PCI_EXP_LNKSTA_NLW) link_is_active = true; if (!link_is_active) { /* try GEN 1 link speed */ -#define PCI_LINK_STATUS_CTRL_2_OFFSET 0x0dc #define PCI_TARGET_LINK_SPEED_MASK 0xf #define PCI_TARGET_LINK_SPEED_GEN2 0x2 #define PCI_TARGET_LINK_SPEED_GEN1 0x1 pci_bus_read_config_dword(bus, 0, - PCI_LINK_STATUS_CTRL_2_OFFSET, + pos + PCI_EXP_LNKCTL2, &link_ctrl); if ((link_ctrl & PCI_TARGET_LINK_SPEED_MASK) == PCI_TARGET_LINK_SPEED_GEN2) { link_ctrl &= ~PCI_TARGET_LINK_SPEED_MASK; link_ctrl |= PCI_TARGET_LINK_SPEED_GEN1; pci_bus_write_config_dword(bus, 0, - PCI_LINK_STATUS_CTRL_2_OFFSET, + pos + PCI_EXP_LNKCTL2, link_ctrl); msleep(100); - pos = pci_bus_find_capability(bus, 0, PCI_CAP_ID_EXP); pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA, &link_status); if (link_status & PCI_EXP_LNKSTA_NLW) @@ -324,7 +324,7 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus) } } - dev_info(pcie->dev, "link: %s\n", link_is_active ? "UP" : "DOWN"); + dev_info(dev, "link: %s\n", link_is_active ? "UP" : "DOWN"); return link_is_active ? 0 : -ENODEV; } @@ -349,12 +349,13 @@ static int iproc_pcie_setup_ob(struct iproc_pcie *pcie, u64 axi_addr, u64 pci_addr, resource_size_t size) { struct iproc_pcie_ob *ob = &pcie->ob; + struct device *dev = pcie->dev; unsigned i; u64 max_size = (u64)ob->window_size * MAX_NUM_OB_WINDOWS; u64 remainder; if (size > max_size) { - dev_err(pcie->dev, + dev_err(dev, "res size %pap exceeds max supported size 0x%llx\n", &size, max_size); return -EINVAL; @@ -362,15 +363,14 @@ static int iproc_pcie_setup_ob(struct iproc_pcie *pcie, u64 axi_addr, div64_u64_rem(size, ob->window_size, &remainder); if (remainder) { - dev_err(pcie->dev, + dev_err(dev, "res size %pap needs to be multiple of window size %pap\n", &size, &ob->window_size); return -EINVAL; } if (axi_addr < ob->axi_offset) { - dev_err(pcie->dev, - "axi address %pap less than offset %pap\n", + dev_err(dev, "axi address %pap less than offset %pap\n", &axi_addr, &ob->axi_offset); return -EINVAL; } @@ -406,6 +406,7 @@ static int iproc_pcie_setup_ob(struct iproc_pcie *pcie, u64 axi_addr, static int iproc_pcie_map_ranges(struct iproc_pcie *pcie, struct list_head *resources) { + struct device *dev = pcie->dev; struct resource_entry *window; int ret; @@ -425,7 +426,7 @@ static int iproc_pcie_map_ranges(struct iproc_pcie *pcie, return ret; break; default: - dev_err(pcie->dev, "invalid resource %pR\n", res); + dev_err(dev, "invalid resource %pR\n", res); return -EINVAL; } } @@ -455,26 +456,25 @@ static void iproc_pcie_msi_disable(struct iproc_pcie *pcie) int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) { + struct device *dev; int ret; void *sysdata; struct pci_bus *bus; - if (!pcie || !pcie->dev || !pcie->base) - return -EINVAL; - - ret = devm_request_pci_bus_resources(pcie->dev, res); + dev = pcie->dev; + ret = devm_request_pci_bus_resources(dev, res); if (ret) return ret; ret = phy_init(pcie->phy); if (ret) { - dev_err(pcie->dev, "unable to initialize PCIe PHY\n"); + dev_err(dev, "unable to initialize PCIe PHY\n"); return ret; } ret = phy_power_on(pcie->phy); if (ret) { - dev_err(pcie->dev, "unable to power on PCIe PHY\n"); + dev_err(dev, "unable to power on PCIe PHY\n"); goto err_exit_phy; } @@ -486,7 +486,7 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) pcie->reg_offsets = iproc_pcie_reg_paxc; break; default: - dev_err(pcie->dev, "incompatible iProc PCIe interface\n"); + dev_err(dev, "incompatible iProc PCIe interface\n"); ret = -EINVAL; goto err_power_off_phy; } @@ -496,7 +496,7 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) if (pcie->need_ob_cfg) { ret = iproc_pcie_map_ranges(pcie, res); if (ret) { - dev_err(pcie->dev, "map failed\n"); + dev_err(dev, "map failed\n"); goto err_power_off_phy; } } @@ -508,9 +508,9 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) sysdata = pcie; #endif - bus = pci_create_root_bus(pcie->dev, 0, &iproc_pcie_ops, sysdata, res); + bus = pci_create_root_bus(dev, 0, &iproc_pcie_ops, sysdata, res); if (!bus) { - dev_err(pcie->dev, "unable to create PCI root bus\n"); + dev_err(dev, "unable to create PCI root bus\n"); ret = -ENOMEM; goto err_power_off_phy; } @@ -518,7 +518,7 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) ret = iproc_pcie_check_link(pcie, bus); if (ret) { - dev_err(pcie->dev, "no PCIe EP device detected\n"); + dev_err(dev, "no PCIe EP device detected\n"); goto err_rm_root_bus; } @@ -526,7 +526,7 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) if (IS_ENABLED(CONFIG_PCI_MSI)) if (iproc_pcie_msi_enable(pcie)) - dev_info(pcie->dev, "not using iProc MSI\n"); + dev_info(dev, "not using iProc MSI\n"); pci_scan_child_bus(bus); pci_assign_unassigned_bus_resources(bus); diff --git a/drivers/pci/host/pcie-qcom.c b/drivers/pci/host/pcie-qcom.c index 5ec2d440a6b7..ef0a84c7a588 100644 --- a/drivers/pci/host/pcie-qcom.c +++ b/drivers/pci/host/pcie-qcom.c @@ -86,12 +86,10 @@ struct qcom_pcie_ops { }; struct qcom_pcie { - struct pcie_port pp; - struct device *dev; + struct pcie_port pp; /* pp.dbi_base is DT dbi */ + void __iomem *parf; /* DT parf */ + void __iomem *elbi; /* DT elbi */ union qcom_pcie_resources res; - void __iomem *parf; - void __iomem *dbi; - void __iomem *elbi; struct phy *phy; struct gpio_desc *reset; struct qcom_pcie_ops *ops; @@ -136,7 +134,7 @@ static int qcom_pcie_establish_link(struct qcom_pcie *pcie) static int qcom_pcie_get_resources_v0(struct qcom_pcie *pcie) { struct qcom_pcie_resources_v0 *res = &pcie->res.v0; - struct device *dev = pcie->dev; + struct device *dev = pcie->pp.dev; res->vdda = devm_regulator_get(dev, "vdda"); if (IS_ERR(res->vdda)) @@ -188,7 +186,7 @@ static int qcom_pcie_get_resources_v0(struct qcom_pcie *pcie) static int qcom_pcie_get_resources_v1(struct qcom_pcie *pcie) { struct qcom_pcie_resources_v1 *res = &pcie->res.v1; - struct device *dev = pcie->dev; + struct device *dev = pcie->pp.dev; res->vdda = devm_regulator_get(dev, "vdda"); if (IS_ERR(res->vdda)) @@ -237,7 +235,7 @@ static void qcom_pcie_deinit_v0(struct qcom_pcie *pcie) static int qcom_pcie_init_v0(struct qcom_pcie *pcie) { struct qcom_pcie_resources_v0 *res = &pcie->res.v0; - struct device *dev = pcie->dev; + struct device *dev = pcie->pp.dev; u32 val; int ret; @@ -359,7 +357,7 @@ static void qcom_pcie_deinit_v1(struct qcom_pcie *pcie) static int qcom_pcie_init_v1(struct qcom_pcie *pcie) { struct qcom_pcie_resources_v1 *res = &pcie->res.v1; - struct device *dev = pcie->dev; + struct device *dev = pcie->pp.dev; int ret; ret = reset_control_deassert(res->core); @@ -426,7 +424,7 @@ err_res: static int qcom_pcie_link_up(struct pcie_port *pp) { struct qcom_pcie *pcie = to_qcom_pcie(pp); - u16 val = readw(pcie->dbi + PCIE20_CAP + PCI_EXP_LNKSTA); + u16 val = readw(pcie->pp.dbi_base + PCIE20_CAP + PCI_EXP_LNKSTA); return !!(val & PCI_EXP_LNKSTA_DLLLA); } @@ -509,8 +507,8 @@ static int qcom_pcie_probe(struct platform_device *pdev) if (!pcie) return -ENOMEM; + pp = &pcie->pp; pcie->ops = (struct qcom_pcie_ops *)of_device_get_match_data(dev); - pcie->dev = dev; pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_LOW); if (IS_ERR(pcie->reset)) @@ -522,9 +520,9 @@ static int qcom_pcie_probe(struct platform_device *pdev) return PTR_ERR(pcie->parf); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); - pcie->dbi = devm_ioremap_resource(dev, res); - if (IS_ERR(pcie->dbi)) - return PTR_ERR(pcie->dbi); + pp->dbi_base = devm_ioremap_resource(dev, res); + if (IS_ERR(pp->dbi_base)) + return PTR_ERR(pp->dbi_base); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "elbi"); pcie->elbi = devm_ioremap_resource(dev, res); @@ -539,9 +537,7 @@ static int qcom_pcie_probe(struct platform_device *pdev) if (ret) return ret; - pp = &pcie->pp; pp->dev = dev; - pp->dbi_base = pcie->dbi; pp->root_bus_nr = -1; pp->ops = &qcom_pcie_dw_ops; @@ -569,8 +565,6 @@ static int qcom_pcie_probe(struct platform_device *pdev) return ret; } - platform_set_drvdata(pdev, pcie); - return 0; } diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c index e06b1d3b4dea..62700d1896f4 100644 --- a/drivers/pci/host/pcie-rcar.c +++ b/drivers/pci/host/pcie-rcar.c @@ -31,8 +31,6 @@ #include #include -#define DRV_NAME "rcar-pcie" - #define PCIECAR 0x000010 #define PCIECCTLR 0x000018 #define CONFIG_SEND_ENABLE (1 << 31) @@ -397,6 +395,7 @@ static int rcar_pcie_setup(struct list_head *resource, struct rcar_pcie *pci) static void rcar_pcie_force_speedup(struct rcar_pcie *pcie) { + struct device *dev = pcie->dev; unsigned int timeout = 1000; u32 macsr; @@ -404,7 +403,7 @@ static void rcar_pcie_force_speedup(struct rcar_pcie *pcie) return; if (rcar_pci_read_reg(pcie, MACCTLR) & SPEED_CHANGE) { - dev_err(pcie->dev, "Speed change already in progress\n"); + dev_err(dev, "Speed change already in progress\n"); return; } @@ -433,7 +432,7 @@ static void rcar_pcie_force_speedup(struct rcar_pcie *pcie) rcar_pci_write_reg(pcie, macsr, MACSR); if (macsr & SPCHGFAIL) - dev_err(pcie->dev, "Speed change failed\n"); + dev_err(dev, "Speed change failed\n"); goto done; } @@ -441,15 +440,16 @@ static void rcar_pcie_force_speedup(struct rcar_pcie *pcie) msleep(1); }; - dev_err(pcie->dev, "Speed change timed out\n"); + dev_err(dev, "Speed change timed out\n"); done: - dev_info(pcie->dev, "Current link speed is %s GT/s\n", + dev_info(dev, "Current link speed is %s GT/s\n", (macsr & LINK_SPEED) == LINK_SPEED_5_0GTS ? "5" : "2.5"); } static int rcar_pcie_enable(struct rcar_pcie *pcie) { + struct device *dev = pcie->dev; struct pci_bus *bus, *child; LIST_HEAD(res); @@ -461,14 +461,14 @@ static int rcar_pcie_enable(struct rcar_pcie *pcie) pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS); if (IS_ENABLED(CONFIG_PCI_MSI)) - bus = pci_scan_root_bus_msi(pcie->dev, pcie->root_bus_nr, + bus = pci_scan_root_bus_msi(dev, pcie->root_bus_nr, &rcar_pcie_ops, pcie, &res, &pcie->msi.chip); else - bus = pci_scan_root_bus(pcie->dev, pcie->root_bus_nr, + bus = pci_scan_root_bus(dev, pcie->root_bus_nr, &rcar_pcie_ops, pcie, &res); if (!bus) { - dev_err(pcie->dev, "Scanning rootbus failed"); + dev_err(dev, "Scanning rootbus failed"); return -ENODEV; } @@ -487,6 +487,7 @@ static int rcar_pcie_enable(struct rcar_pcie *pcie) static int phy_wait_for_ack(struct rcar_pcie *pcie) { + struct device *dev = pcie->dev; unsigned int timeout = 100; while (timeout--) { @@ -496,7 +497,7 @@ static int phy_wait_for_ack(struct rcar_pcie *pcie) udelay(100); } - dev_err(pcie->dev, "Access to PCIe phy timed out\n"); + dev_err(dev, "Access to PCIe phy timed out\n"); return -ETIMEDOUT; } @@ -697,6 +698,7 @@ static irqreturn_t rcar_pcie_msi_irq(int irq, void *data) { struct rcar_pcie *pcie = data; struct rcar_msi *msi = &pcie->msi; + struct device *dev = pcie->dev; unsigned long reg; reg = rcar_pci_read_reg(pcie, PCIEMSIFR); @@ -717,10 +719,10 @@ static irqreturn_t rcar_pcie_msi_irq(int irq, void *data) if (test_bit(index, msi->used)) generic_handle_irq(irq); else - dev_info(pcie->dev, "unhandled MSI\n"); + dev_info(dev, "unhandled MSI\n"); } else { /* Unknown MSI, just clear it */ - dev_dbg(pcie->dev, "unexpected MSI\n"); + dev_dbg(dev, "unexpected MSI\n"); } /* see if there's any more pending in this vector */ @@ -843,22 +845,22 @@ static const struct irq_domain_ops msi_domain_ops = { static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) { - struct platform_device *pdev = to_platform_device(pcie->dev); + struct device *dev = pcie->dev; struct rcar_msi *msi = &pcie->msi; unsigned long base; int err, i; mutex_init(&msi->lock); - msi->chip.dev = pcie->dev; + msi->chip.dev = dev; msi->chip.setup_irq = rcar_msi_setup_irq; msi->chip.setup_irqs = rcar_msi_setup_irqs; msi->chip.teardown_irq = rcar_msi_teardown_irq; - msi->domain = irq_domain_add_linear(pcie->dev->of_node, INT_PCI_MSI_NR, + msi->domain = irq_domain_add_linear(dev->of_node, INT_PCI_MSI_NR, &msi_domain_ops, &msi->chip); if (!msi->domain) { - dev_err(&pdev->dev, "failed to create IRQ domain\n"); + dev_err(dev, "failed to create IRQ domain\n"); return -ENOMEM; } @@ -866,19 +868,19 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) irq_create_mapping(msi->domain, i); /* Two irqs are for MSI, but they are also used for non-MSI irqs */ - err = devm_request_irq(&pdev->dev, msi->irq1, rcar_pcie_msi_irq, + err = devm_request_irq(dev, msi->irq1, rcar_pcie_msi_irq, IRQF_SHARED | IRQF_NO_THREAD, rcar_msi_irq_chip.name, pcie); if (err < 0) { - dev_err(&pdev->dev, "failed to request IRQ: %d\n", err); + dev_err(dev, "failed to request IRQ: %d\n", err); goto err; } - err = devm_request_irq(&pdev->dev, msi->irq2, rcar_pcie_msi_irq, + err = devm_request_irq(dev, msi->irq2, rcar_pcie_msi_irq, IRQF_SHARED | IRQF_NO_THREAD, rcar_msi_irq_chip.name, pcie); if (err < 0) { - dev_err(&pdev->dev, "failed to request IRQ: %d\n", err); + dev_err(dev, "failed to request IRQ: %d\n", err); goto err; } @@ -899,32 +901,32 @@ err: return err; } -static int rcar_pcie_get_resources(struct platform_device *pdev, - struct rcar_pcie *pcie) +static int rcar_pcie_get_resources(struct rcar_pcie *pcie) { + struct device *dev = pcie->dev; struct resource res; int err, i; - err = of_address_to_resource(pdev->dev.of_node, 0, &res); + err = of_address_to_resource(dev->of_node, 0, &res); if (err) return err; - pcie->base = devm_ioremap_resource(&pdev->dev, &res); + pcie->base = devm_ioremap_resource(dev, &res); if (IS_ERR(pcie->base)) return PTR_ERR(pcie->base); - pcie->clk = devm_clk_get(&pdev->dev, "pcie"); + pcie->clk = devm_clk_get(dev, "pcie"); if (IS_ERR(pcie->clk)) { - dev_err(pcie->dev, "cannot get platform clock\n"); + dev_err(dev, "cannot get platform clock\n"); return PTR_ERR(pcie->clk); } err = clk_prepare_enable(pcie->clk); if (err) return err; - pcie->bus_clk = devm_clk_get(&pdev->dev, "pcie_bus"); + pcie->bus_clk = devm_clk_get(dev, "pcie_bus"); if (IS_ERR(pcie->bus_clk)) { - dev_err(pcie->dev, "cannot get pcie bus clock\n"); + dev_err(dev, "cannot get pcie bus clock\n"); err = PTR_ERR(pcie->bus_clk); goto fail_clk; } @@ -932,17 +934,17 @@ static int rcar_pcie_get_resources(struct platform_device *pdev, if (err) goto fail_clk; - i = irq_of_parse_and_map(pdev->dev.of_node, 0); + i = irq_of_parse_and_map(dev->of_node, 0); if (!i) { - dev_err(pcie->dev, "cannot get platform resources for msi interrupt\n"); + dev_err(dev, "cannot get platform resources for msi interrupt\n"); err = -ENOENT; goto err_map_reg; } pcie->msi.irq1 = i; - i = irq_of_parse_and_map(pdev->dev.of_node, 1); + i = irq_of_parse_and_map(dev->of_node, 1); if (!i) { - dev_err(pcie->dev, "cannot get platform resources for msi interrupt\n"); + dev_err(dev, "cannot get platform resources for msi interrupt\n"); err = -ENOENT; goto err_map_reg; } @@ -1119,60 +1121,60 @@ out_release_res: static int rcar_pcie_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct rcar_pcie *pcie; unsigned int data; const struct of_device_id *of_id; int err; int (*hw_init_fn)(struct rcar_pcie *); - pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); + pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); if (!pcie) return -ENOMEM; - pcie->dev = &pdev->dev; - platform_set_drvdata(pdev, pcie); + pcie->dev = dev; INIT_LIST_HEAD(&pcie->resources); rcar_pcie_parse_request_of_pci_ranges(pcie); - err = rcar_pcie_get_resources(pdev, pcie); + err = rcar_pcie_get_resources(pcie); if (err < 0) { - dev_err(&pdev->dev, "failed to request resources: %d\n", err); + dev_err(dev, "failed to request resources: %d\n", err); return err; } - err = rcar_pcie_parse_map_dma_ranges(pcie, pdev->dev.of_node); + err = rcar_pcie_parse_map_dma_ranges(pcie, dev->of_node); if (err) return err; - of_id = of_match_device(rcar_pcie_of_match, pcie->dev); + of_id = of_match_device(rcar_pcie_of_match, dev); if (!of_id || !of_id->data) return -EINVAL; hw_init_fn = of_id->data; - pm_runtime_enable(pcie->dev); - err = pm_runtime_get_sync(pcie->dev); + pm_runtime_enable(dev); + err = pm_runtime_get_sync(dev); if (err < 0) { - dev_err(pcie->dev, "pm_runtime_get_sync failed\n"); + dev_err(dev, "pm_runtime_get_sync failed\n"); goto err_pm_disable; } /* Failure to get a link might just be that no cards are inserted */ err = hw_init_fn(pcie); if (err) { - dev_info(&pdev->dev, "PCIe link down\n"); + dev_info(dev, "PCIe link down\n"); err = 0; goto err_pm_put; } data = rcar_pci_read_reg(pcie, MACSR); - dev_info(&pdev->dev, "PCIe x%d: link up\n", (data >> 20) & 0x3f); + dev_info(dev, "PCIe x%d: link up\n", (data >> 20) & 0x3f); if (IS_ENABLED(CONFIG_PCI_MSI)) { err = rcar_pcie_enable_msi(pcie); if (err < 0) { - dev_err(&pdev->dev, + dev_err(dev, "failed to enable MSI support: %d\n", err); goto err_pm_put; @@ -1186,16 +1188,16 @@ static int rcar_pcie_probe(struct platform_device *pdev) return 0; err_pm_put: - pm_runtime_put(pcie->dev); + pm_runtime_put(dev); err_pm_disable: - pm_runtime_disable(pcie->dev); + pm_runtime_disable(dev); return err; } static struct platform_driver rcar_pcie_driver = { .driver = { - .name = DRV_NAME, + .name = "rcar-pcie", .of_match_table = rcar_pcie_of_match, .suppress_bind_attrs = true, }, diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index b8c82fc812dc..e0b22dab9b7a 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -972,7 +972,7 @@ static int rockchip_pcie_prog_ob_atu(struct rockchip_pcie *rockchip, return -EINVAL; if (region_no == 0) { if (AXI_REGION_0_SIZE < (2ULL << num_pass_bits)) - return -EINVAL; + return -EINVAL; } if (region_no != 0) { if (AXI_REGION_SIZE < (2ULL << num_pass_bits)) @@ -1091,8 +1091,6 @@ static int rockchip_pcie_probe(struct platform_device *pdev) if (err) goto err_vpcie; - platform_set_drvdata(pdev, rockchip); - rockchip_pcie_enable_interrupts(rockchip); err = rockchip_pcie_init_irq_domain(rockchip); diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-spear13xx.c index 09aed85f275a..3cf197ba7f37 100644 --- a/drivers/pci/host/pcie-spear13xx.c +++ b/drivers/pci/host/pcie-spear13xx.c @@ -25,10 +25,10 @@ #include "pcie-designware.h" struct spear13xx_pcie { + struct pcie_port pp; /* DT dbi is pp.dbi_base */ void __iomem *app_base; struct phy *phy; struct clk *clk; - struct pcie_port pp; bool is_gen1; }; @@ -57,96 +57,26 @@ struct pcie_app_reg { }; /* CR0 ID */ -#define RX_LANE_FLIP_EN_ID 0 -#define TX_LANE_FLIP_EN_ID 1 -#define SYS_AUX_PWR_DET_ID 2 #define APP_LTSSM_ENABLE_ID 3 -#define SYS_ATTEN_BUTTON_PRESSED_ID 4 -#define SYS_MRL_SENSOR_STATE_ID 5 -#define SYS_PWR_FAULT_DET_ID 6 -#define SYS_MRL_SENSOR_CHGED_ID 7 -#define SYS_PRE_DET_CHGED_ID 8 -#define SYS_CMD_CPLED_INT_ID 9 -#define APP_INIT_RST_0_ID 11 -#define APP_REQ_ENTR_L1_ID 12 -#define APP_READY_ENTR_L23_ID 13 -#define APP_REQ_EXIT_L1_ID 14 -#define DEVICE_TYPE_EP (0 << 25) -#define DEVICE_TYPE_LEP (1 << 25) #define DEVICE_TYPE_RC (4 << 25) -#define SYS_INT_ID 29 #define MISCTRL_EN_ID 30 #define REG_TRANSLATION_ENABLE 31 -/* CR1 ID */ -#define APPS_PM_XMT_TURNOFF_ID 2 -#define APPS_PM_XMT_PME_ID 5 - /* CR3 ID */ -#define XMLH_LTSSM_STATE_DETECT_QUIET 0x00 -#define XMLH_LTSSM_STATE_DETECT_ACT 0x01 -#define XMLH_LTSSM_STATE_POLL_ACTIVE 0x02 -#define XMLH_LTSSM_STATE_POLL_COMPLIANCE 0x03 -#define XMLH_LTSSM_STATE_POLL_CONFIG 0x04 -#define XMLH_LTSSM_STATE_PRE_DETECT_QUIET 0x05 -#define XMLH_LTSSM_STATE_DETECT_WAIT 0x06 -#define XMLH_LTSSM_STATE_CFG_LINKWD_START 0x07 -#define XMLH_LTSSM_STATE_CFG_LINKWD_ACEPT 0x08 -#define XMLH_LTSSM_STATE_CFG_LANENUM_WAIT 0x09 -#define XMLH_LTSSM_STATE_CFG_LANENUM_ACEPT 0x0A -#define XMLH_LTSSM_STATE_CFG_COMPLETE 0x0B -#define XMLH_LTSSM_STATE_CFG_IDLE 0x0C -#define XMLH_LTSSM_STATE_RCVRY_LOCK 0x0D -#define XMLH_LTSSM_STATE_RCVRY_SPEED 0x0E -#define XMLH_LTSSM_STATE_RCVRY_RCVRCFG 0x0F -#define XMLH_LTSSM_STATE_RCVRY_IDLE 0x10 -#define XMLH_LTSSM_STATE_L0 0x11 -#define XMLH_LTSSM_STATE_L0S 0x12 -#define XMLH_LTSSM_STATE_L123_SEND_EIDLE 0x13 -#define XMLH_LTSSM_STATE_L1_IDLE 0x14 -#define XMLH_LTSSM_STATE_L2_IDLE 0x15 -#define XMLH_LTSSM_STATE_L2_WAKE 0x16 -#define XMLH_LTSSM_STATE_DISABLED_ENTRY 0x17 -#define XMLH_LTSSM_STATE_DISABLED_IDLE 0x18 -#define XMLH_LTSSM_STATE_DISABLED 0x19 -#define XMLH_LTSSM_STATE_LPBK_ENTRY 0x1A -#define XMLH_LTSSM_STATE_LPBK_ACTIVE 0x1B -#define XMLH_LTSSM_STATE_LPBK_EXIT 0x1C -#define XMLH_LTSSM_STATE_LPBK_EXIT_TIMEOUT 0x1D -#define XMLH_LTSSM_STATE_HOT_RESET_ENTRY 0x1E -#define XMLH_LTSSM_STATE_HOT_RESET 0x1F -#define XMLH_LTSSM_STATE_MASK 0x3F #define XMLH_LINK_UP (1 << 6) -/* CR4 ID */ -#define CFG_MSI_EN_ID 18 - /* CR6 */ -#define INTA_CTRL_INT (1 << 7) -#define INTB_CTRL_INT (1 << 8) -#define INTC_CTRL_INT (1 << 9) -#define INTD_CTRL_INT (1 << 10) #define MSI_CTRL_INT (1 << 26) -/* CR19 ID */ -#define VEN_MSI_REQ_ID 11 -#define VEN_MSI_FUN_NUM_ID 8 -#define VEN_MSI_TC_ID 5 -#define VEN_MSI_VECTOR_ID 0 -#define VEN_MSI_REQ_EN ((u32)0x1 << VEN_MSI_REQ_ID) -#define VEN_MSI_FUN_NUM_MASK ((u32)0x7 << VEN_MSI_FUN_NUM_ID) -#define VEN_MSI_TC_MASK ((u32)0x7 << VEN_MSI_TC_ID) -#define VEN_MSI_VECTOR_MASK ((u32)0x1F << VEN_MSI_VECTOR_ID) - #define EXP_CAP_ID_OFFSET 0x70 #define to_spear13xx_pcie(x) container_of(x, struct spear13xx_pcie, pp) -static int spear13xx_pcie_establish_link(struct pcie_port *pp) +static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie) { - u32 val; - struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pp); + struct pcie_port *pp = &spear13xx_pcie->pp; struct pcie_app_reg *app_reg = spear13xx_pcie->app_base; + u32 val; u32 exp_cap_off = EXP_CAP_ID_OFFSET; if (dw_pcie_link_up(pp)) { @@ -203,9 +133,9 @@ static int spear13xx_pcie_establish_link(struct pcie_port *pp) static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg) { - struct pcie_port *pp = arg; - struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pp); + struct spear13xx_pcie *spear13xx_pcie = arg; struct pcie_app_reg *app_reg = spear13xx_pcie->app_base; + struct pcie_port *pp = &spear13xx_pcie->pp; unsigned int status; status = readl(&app_reg->int_sts); @@ -220,9 +150,9 @@ static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg) return IRQ_HANDLED; } -static void spear13xx_pcie_enable_interrupts(struct pcie_port *pp) +static void spear13xx_pcie_enable_interrupts(struct spear13xx_pcie *spear13xx_pcie) { - struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pp); + struct pcie_port *pp = &spear13xx_pcie->pp; struct pcie_app_reg *app_reg = spear13xx_pcie->app_base; /* Enable MSI interrupt */ @@ -246,8 +176,10 @@ static int spear13xx_pcie_link_up(struct pcie_port *pp) static void spear13xx_pcie_host_init(struct pcie_port *pp) { - spear13xx_pcie_establish_link(pp); - spear13xx_pcie_enable_interrupts(pp); + struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pp); + + spear13xx_pcie_establish_link(spear13xx_pcie); + spear13xx_pcie_enable_interrupts(spear13xx_pcie); } static struct pcie_host_ops spear13xx_pcie_host_ops = { @@ -255,10 +187,11 @@ static struct pcie_host_ops spear13xx_pcie_host_ops = { .host_init = spear13xx_pcie_host_init, }; -static int spear13xx_add_pcie_port(struct pcie_port *pp, - struct platform_device *pdev) +static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie, + struct platform_device *pdev) { - struct device *dev = &pdev->dev; + struct pcie_port *pp = &spear13xx_pcie->pp; + struct device *dev = pp->dev; int ret; pp->irq = platform_get_irq(pdev, 0); @@ -268,7 +201,7 @@ static int spear13xx_add_pcie_port(struct pcie_port *pp, } ret = devm_request_irq(dev, pp->irq, spear13xx_pcie_irq_handler, IRQF_SHARED | IRQF_NO_THREAD, - "spear1340-pcie", pp); + "spear1340-pcie", spear13xx_pcie); if (ret) { dev_err(dev, "failed to request irq %d\n", pp->irq); return ret; @@ -288,10 +221,10 @@ static int spear13xx_add_pcie_port(struct pcie_port *pp, static int spear13xx_pcie_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct spear13xx_pcie *spear13xx_pcie; struct pcie_port *pp; - struct device *dev = &pdev->dev; - struct device_node *np = pdev->dev.of_node; + struct device_node *np = dev->of_node; struct resource *dbi_base; int ret; @@ -323,7 +256,6 @@ static int spear13xx_pcie_probe(struct platform_device *pdev) } pp = &spear13xx_pcie->pp; - pp->dev = dev; dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); @@ -338,7 +270,7 @@ static int spear13xx_pcie_probe(struct platform_device *pdev) if (of_property_read_bool(np, "st,pcie-is-gen1")) spear13xx_pcie->is_gen1 = true; - ret = spear13xx_add_pcie_port(pp, pdev); + ret = spear13xx_add_pcie_port(spear13xx_pcie, pdev); if (ret < 0) goto fail_clk; diff --git a/drivers/pci/host/pcie-xilinx-nwl.c b/drivers/pci/host/pcie-xilinx-nwl.c index 67eae4179290..43eaa4afab94 100644 --- a/drivers/pci/host/pcie-xilinx-nwl.c +++ b/drivers/pci/host/pcie-xilinx-nwl.c @@ -212,6 +212,7 @@ static bool nwl_phy_link_up(struct nwl_pcie *pcie) static int nwl_wait_for_link(struct nwl_pcie *pcie) { + struct device *dev = pcie->dev; int retries; /* check if the link is up or not */ @@ -221,7 +222,7 @@ static int nwl_wait_for_link(struct nwl_pcie *pcie) usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX); } - dev_err(pcie->dev, "PHY link never came up\n"); + dev_err(dev, "PHY link never came up\n"); return -ETIMEDOUT; } @@ -277,6 +278,7 @@ static struct pci_ops nwl_pcie_ops = { static irqreturn_t nwl_pcie_misc_handler(int irq, void *data) { struct nwl_pcie *pcie = data; + struct device *dev = pcie->dev; u32 misc_stat; /* Checking for misc interrupts */ @@ -286,45 +288,43 @@ static irqreturn_t nwl_pcie_misc_handler(int irq, void *data) return IRQ_NONE; if (misc_stat & MSGF_MISC_SR_RXMSG_OVER) - dev_err(pcie->dev, "Received Message FIFO Overflow\n"); + dev_err(dev, "Received Message FIFO Overflow\n"); if (misc_stat & MSGF_MISC_SR_SLAVE_ERR) - dev_err(pcie->dev, "Slave error\n"); + dev_err(dev, "Slave error\n"); if (misc_stat & MSGF_MISC_SR_MASTER_ERR) - dev_err(pcie->dev, "Master error\n"); + dev_err(dev, "Master error\n"); if (misc_stat & MSGF_MISC_SR_I_ADDR_ERR) - dev_err(pcie->dev, - "In Misc Ingress address translation error\n"); + dev_err(dev, "In Misc Ingress address translation error\n"); if (misc_stat & MSGF_MISC_SR_E_ADDR_ERR) - dev_err(pcie->dev, - "In Misc Egress address translation error\n"); + dev_err(dev, "In Misc Egress address translation error\n"); if (misc_stat & MSGF_MISC_SR_FATAL_AER) - dev_err(pcie->dev, "Fatal Error in AER Capability\n"); + dev_err(dev, "Fatal Error in AER Capability\n"); if (misc_stat & MSGF_MISC_SR_NON_FATAL_AER) - dev_err(pcie->dev, "Non-Fatal Error in AER Capability\n"); + dev_err(dev, "Non-Fatal Error in AER Capability\n"); if (misc_stat & MSGF_MISC_SR_CORR_AER) - dev_err(pcie->dev, "Correctable Error in AER Capability\n"); + dev_err(dev, "Correctable Error in AER Capability\n"); if (misc_stat & MSGF_MISC_SR_UR_DETECT) - dev_err(pcie->dev, "Unsupported request Detected\n"); + dev_err(dev, "Unsupported request Detected\n"); if (misc_stat & MSGF_MISC_SR_NON_FATAL_DEV) - dev_err(pcie->dev, "Non-Fatal Error Detected\n"); + dev_err(dev, "Non-Fatal Error Detected\n"); if (misc_stat & MSGF_MISC_SR_FATAL_DEV) - dev_err(pcie->dev, "Fatal Error Detected\n"); + dev_err(dev, "Fatal Error Detected\n"); if (misc_stat & MSGF_MSIC_SR_LINK_AUTO_BWIDTH) - dev_info(pcie->dev, "Link Autonomous Bandwidth Management Status bit set\n"); + dev_info(dev, "Link Autonomous Bandwidth Management Status bit set\n"); if (misc_stat & MSGF_MSIC_SR_LINK_BWIDTH) - dev_info(pcie->dev, "Link Bandwidth Management Status bit set\n"); + dev_info(dev, "Link Bandwidth Management Status bit set\n"); /* Clear misc interrupt status */ nwl_bridge_writel(pcie, misc_stat, MSGF_MISC_STATUS); @@ -494,20 +494,21 @@ static const struct irq_domain_ops dev_msi_domain_ops = { static int nwl_pcie_init_msi_irq_domain(struct nwl_pcie *pcie) { #ifdef CONFIG_PCI_MSI - struct fwnode_handle *fwnode = of_node_to_fwnode(pcie->dev->of_node); + struct device *dev = pcie->dev; + struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node); struct nwl_msi *msi = &pcie->msi; msi->dev_domain = irq_domain_add_linear(NULL, INT_PCI_MSI_NR, &dev_msi_domain_ops, pcie); if (!msi->dev_domain) { - dev_err(pcie->dev, "failed to create dev IRQ domain\n"); + dev_err(dev, "failed to create dev IRQ domain\n"); return -ENOMEM; } msi->msi_domain = pci_msi_create_irq_domain(fwnode, &nwl_msi_domain_info, msi->dev_domain); if (!msi->msi_domain) { - dev_err(pcie->dev, "failed to create msi IRQ domain\n"); + dev_err(dev, "failed to create msi IRQ domain\n"); irq_domain_remove(msi->dev_domain); return -ENOMEM; } @@ -517,12 +518,13 @@ static int nwl_pcie_init_msi_irq_domain(struct nwl_pcie *pcie) static int nwl_pcie_init_irq_domain(struct nwl_pcie *pcie) { - struct device_node *node = pcie->dev->of_node; + struct device *dev = pcie->dev; + struct device_node *node = dev->of_node; struct device_node *legacy_intc_node; legacy_intc_node = of_get_next_child(node, NULL); if (!legacy_intc_node) { - dev_err(pcie->dev, "No legacy intc node found\n"); + dev_err(dev, "No legacy intc node found\n"); return -EINVAL; } @@ -532,7 +534,7 @@ static int nwl_pcie_init_irq_domain(struct nwl_pcie *pcie) pcie); if (!pcie->legacy_irq_domain) { - dev_err(pcie->dev, "failed to create IRQ domain\n"); + dev_err(dev, "failed to create IRQ domain\n"); return -ENOMEM; } @@ -542,7 +544,8 @@ static int nwl_pcie_init_irq_domain(struct nwl_pcie *pcie) static int nwl_pcie_enable_msi(struct nwl_pcie *pcie, struct pci_bus *bus) { - struct platform_device *pdev = to_platform_device(pcie->dev); + struct device *dev = pcie->dev; + struct platform_device *pdev = to_platform_device(dev); struct nwl_msi *msi = &pcie->msi; unsigned long base; int ret; @@ -557,7 +560,7 @@ static int nwl_pcie_enable_msi(struct nwl_pcie *pcie, struct pci_bus *bus) /* Get msi_1 IRQ number */ msi->irq_msi1 = platform_get_irq_byname(pdev, "msi1"); if (msi->irq_msi1 < 0) { - dev_err(&pdev->dev, "failed to get IRQ#%d\n", msi->irq_msi1); + dev_err(dev, "failed to get IRQ#%d\n", msi->irq_msi1); ret = -EINVAL; goto err; } @@ -568,7 +571,7 @@ static int nwl_pcie_enable_msi(struct nwl_pcie *pcie, struct pci_bus *bus) /* Get msi_0 IRQ number */ msi->irq_msi0 = platform_get_irq_byname(pdev, "msi0"); if (msi->irq_msi0 < 0) { - dev_err(&pdev->dev, "failed to get IRQ#%d\n", msi->irq_msi0); + dev_err(dev, "failed to get IRQ#%d\n", msi->irq_msi0); ret = -EINVAL; goto err; } @@ -579,7 +582,7 @@ static int nwl_pcie_enable_msi(struct nwl_pcie *pcie, struct pci_bus *bus) /* Check for msii_present bit */ ret = nwl_bridge_readl(pcie, I_MSII_CAPABILITIES) & MSII_PRESENT; if (!ret) { - dev_err(pcie->dev, "MSI not present\n"); + dev_err(dev, "MSI not present\n"); ret = -EIO; goto err; } @@ -628,13 +631,14 @@ err: static int nwl_pcie_bridge_init(struct nwl_pcie *pcie) { - struct platform_device *pdev = to_platform_device(pcie->dev); + struct device *dev = pcie->dev; + struct platform_device *pdev = to_platform_device(dev); u32 breg_val, ecam_val, first_busno = 0; int err; breg_val = nwl_bridge_readl(pcie, E_BREG_CAPABILITIES) & BREG_PRESENT; if (!breg_val) { - dev_err(pcie->dev, "BREG is not present\n"); + dev_err(dev, "BREG is not present\n"); return breg_val; } @@ -665,7 +669,7 @@ static int nwl_pcie_bridge_init(struct nwl_pcie *pcie) ecam_val = nwl_bridge_readl(pcie, E_ECAM_CAPABILITIES) & E_ECAM_PRESENT; if (!ecam_val) { - dev_err(pcie->dev, "ECAM is not present\n"); + dev_err(dev, "ECAM is not present\n"); return ecam_val; } @@ -692,23 +696,23 @@ static int nwl_pcie_bridge_init(struct nwl_pcie *pcie) writel(ecam_val, (pcie->ecam_base + PCI_PRIMARY_BUS)); if (nwl_pcie_link_up(pcie)) - dev_info(pcie->dev, "Link is UP\n"); + dev_info(dev, "Link is UP\n"); else - dev_info(pcie->dev, "Link is DOWN\n"); + dev_info(dev, "Link is DOWN\n"); /* Get misc IRQ number */ pcie->irq_misc = platform_get_irq_byname(pdev, "misc"); if (pcie->irq_misc < 0) { - dev_err(&pdev->dev, "failed to get misc IRQ %d\n", + dev_err(dev, "failed to get misc IRQ %d\n", pcie->irq_misc); return -EINVAL; } - err = devm_request_irq(pcie->dev, pcie->irq_misc, + err = devm_request_irq(dev, pcie->irq_misc, nwl_pcie_misc_handler, IRQF_SHARED, "nwl_pcie:misc", pcie); if (err) { - dev_err(pcie->dev, "fail to register misc IRQ#%d\n", + dev_err(dev, "fail to register misc IRQ#%d\n", pcie->irq_misc); return err; } @@ -744,31 +748,32 @@ static int nwl_pcie_bridge_init(struct nwl_pcie *pcie) static int nwl_pcie_parse_dt(struct nwl_pcie *pcie, struct platform_device *pdev) { - struct device_node *node = pcie->dev->of_node; + struct device *dev = pcie->dev; + struct device_node *node = dev->of_node; struct resource *res; const char *type; /* Check for device type */ type = of_get_property(node, "device_type", NULL); if (!type || strcmp(type, "pci")) { - dev_err(pcie->dev, "invalid \"device_type\" %s\n", type); + dev_err(dev, "invalid \"device_type\" %s\n", type); return -EINVAL; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "breg"); - pcie->breg_base = devm_ioremap_resource(pcie->dev, res); + pcie->breg_base = devm_ioremap_resource(dev, res); if (IS_ERR(pcie->breg_base)) return PTR_ERR(pcie->breg_base); pcie->phys_breg_base = res->start; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcireg"); - pcie->pcireg_base = devm_ioremap_resource(pcie->dev, res); + pcie->pcireg_base = devm_ioremap_resource(dev, res); if (IS_ERR(pcie->pcireg_base)) return PTR_ERR(pcie->pcireg_base); pcie->phys_pcie_reg_base = res->start; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); - pcie->ecam_base = devm_ioremap_resource(pcie->dev, res); + pcie->ecam_base = devm_ioremap_resource(dev, res); if (IS_ERR(pcie->ecam_base)) return PTR_ERR(pcie->ecam_base); pcie->phys_ecam_base = res->start; @@ -776,8 +781,7 @@ static int nwl_pcie_parse_dt(struct nwl_pcie *pcie, /* Get intx IRQ number */ pcie->irq_intx = platform_get_irq_byname(pdev, "intx"); if (pcie->irq_intx < 0) { - dev_err(&pdev->dev, "failed to get intx IRQ %d\n", - pcie->irq_intx); + dev_err(dev, "failed to get intx IRQ %d\n", pcie->irq_intx); return -EINVAL; } @@ -794,7 +798,8 @@ static const struct of_device_id nwl_pcie_of_match[] = { static int nwl_pcie_probe(struct platform_device *pdev) { - struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; struct nwl_pcie *pcie; struct pci_bus *bus; struct pci_bus *child; @@ -802,42 +807,42 @@ static int nwl_pcie_probe(struct platform_device *pdev) resource_size_t iobase = 0; LIST_HEAD(res); - pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); + pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); if (!pcie) return -ENOMEM; - pcie->dev = &pdev->dev; + pcie->dev = dev; pcie->ecam_value = NWL_ECAM_VALUE_DEFAULT; err = nwl_pcie_parse_dt(pcie, pdev); if (err) { - dev_err(pcie->dev, "Parsing DT failed\n"); + dev_err(dev, "Parsing DT failed\n"); return err; } err = nwl_pcie_bridge_init(pcie); if (err) { - dev_err(pcie->dev, "HW Initialization failed\n"); + dev_err(dev, "HW Initialization failed\n"); return err; } err = of_pci_get_host_bridge_resources(node, 0, 0xff, &res, &iobase); if (err) { - dev_err(pcie->dev, "Getting bridge resources failed\n"); + dev_err(dev, "Getting bridge resources failed\n"); return err; } - err = devm_request_pci_bus_resources(pcie->dev, &res); + err = devm_request_pci_bus_resources(dev, &res); if (err) goto error; err = nwl_pcie_init_irq_domain(pcie); if (err) { - dev_err(pcie->dev, "Failed creating IRQ Domain\n"); + dev_err(dev, "Failed creating IRQ Domain\n"); goto error; } - bus = pci_create_root_bus(&pdev->dev, pcie->root_busno, + bus = pci_create_root_bus(dev, pcie->root_busno, &nwl_pcie_ops, pcie, &res); if (!bus) { err = -ENOMEM; @@ -847,8 +852,7 @@ static int nwl_pcie_probe(struct platform_device *pdev) if (IS_ENABLED(CONFIG_PCI_MSI)) { err = nwl_pcie_enable_msi(pcie, bus); if (err < 0) { - dev_err(&pdev->dev, - "failed to enable MSI support: %d\n", err); + dev_err(dev, "failed to enable MSI support: %d\n", err); goto error; } } @@ -857,7 +861,6 @@ static int nwl_pcie_probe(struct platform_device *pdev) list_for_each_entry(child, &bus->children, node) pcie_bus_configure_settings(child); pci_bus_add_devices(bus); - platform_set_drvdata(pdev, pcie); return 0; error: diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c index be568039d9d0..c8616fadccf1 100644 --- a/drivers/pci/host/pcie-xilinx.c +++ b/drivers/pci/host/pcie-xilinx.c @@ -140,10 +140,11 @@ static inline bool xilinx_pcie_link_is_up(struct xilinx_pcie_port *port) */ static void xilinx_pcie_clear_err_interrupts(struct xilinx_pcie_port *port) { + struct device *dev = port->dev; unsigned long val = pcie_read(port, XILINX_PCIE_REG_RPEFR); if (val & XILINX_PCIE_RPEFR_ERR_VALID) { - dev_dbg(port->dev, "Requester ID %lu\n", + dev_dbg(dev, "Requester ID %lu\n", val & XILINX_PCIE_RPEFR_REQ_ID); pcie_write(port, XILINX_PCIE_RPEFR_ALL_MASK, XILINX_PCIE_REG_RPEFR); @@ -228,11 +229,10 @@ static void xilinx_pcie_destroy_msi(unsigned int irq) /** * xilinx_pcie_assign_msi - Allocate MSI number - * @port: PCIe port structure * * Return: A valid IRQ on success and error value on failure. */ -static int xilinx_pcie_assign_msi(struct xilinx_pcie_port *port) +static int xilinx_pcie_assign_msi(void) { int pos; @@ -275,7 +275,7 @@ static int xilinx_pcie_msi_setup_irq(struct msi_controller *chip, struct msi_msg msg; phys_addr_t msg_addr; - hwirq = xilinx_pcie_assign_msi(port); + hwirq = xilinx_pcie_assign_msi(); if (hwirq < 0) return hwirq; @@ -383,6 +383,7 @@ static const struct irq_domain_ops intx_domain_ops = { static irqreturn_t xilinx_pcie_intr_handler(int irq, void *data) { struct xilinx_pcie_port *port = (struct xilinx_pcie_port *)data; + struct device *dev = port->dev; u32 val, mask, status, msi_data; /* Read interrupt decode and mask registers */ @@ -394,32 +395,32 @@ static irqreturn_t xilinx_pcie_intr_handler(int irq, void *data) return IRQ_NONE; if (status & XILINX_PCIE_INTR_LINK_DOWN) - dev_warn(port->dev, "Link Down\n"); + dev_warn(dev, "Link Down\n"); if (status & XILINX_PCIE_INTR_ECRC_ERR) - dev_warn(port->dev, "ECRC failed\n"); + dev_warn(dev, "ECRC failed\n"); if (status & XILINX_PCIE_INTR_STR_ERR) - dev_warn(port->dev, "Streaming error\n"); + dev_warn(dev, "Streaming error\n"); if (status & XILINX_PCIE_INTR_HOT_RESET) - dev_info(port->dev, "Hot reset\n"); + dev_info(dev, "Hot reset\n"); if (status & XILINX_PCIE_INTR_CFG_TIMEOUT) - dev_warn(port->dev, "ECAM access timeout\n"); + dev_warn(dev, "ECAM access timeout\n"); if (status & XILINX_PCIE_INTR_CORRECTABLE) { - dev_warn(port->dev, "Correctable error message\n"); + dev_warn(dev, "Correctable error message\n"); xilinx_pcie_clear_err_interrupts(port); } if (status & XILINX_PCIE_INTR_NONFATAL) { - dev_warn(port->dev, "Non fatal error message\n"); + dev_warn(dev, "Non fatal error message\n"); xilinx_pcie_clear_err_interrupts(port); } if (status & XILINX_PCIE_INTR_FATAL) { - dev_warn(port->dev, "Fatal error message\n"); + dev_warn(dev, "Fatal error message\n"); xilinx_pcie_clear_err_interrupts(port); } @@ -429,7 +430,7 @@ static irqreturn_t xilinx_pcie_intr_handler(int irq, void *data) /* Check whether interrupt valid */ if (!(val & XILINX_PCIE_RPIFR1_INTR_VALID)) { - dev_warn(port->dev, "RP Intr FIFO1 read error\n"); + dev_warn(dev, "RP Intr FIFO1 read error\n"); goto error; } @@ -451,7 +452,7 @@ static irqreturn_t xilinx_pcie_intr_handler(int irq, void *data) val = pcie_read(port, XILINX_PCIE_REG_RPIFR1); if (!(val & XILINX_PCIE_RPIFR1_INTR_VALID)) { - dev_warn(port->dev, "RP Intr FIFO1 read error\n"); + dev_warn(dev, "RP Intr FIFO1 read error\n"); goto error; } @@ -471,31 +472,31 @@ static irqreturn_t xilinx_pcie_intr_handler(int irq, void *data) } if (status & XILINX_PCIE_INTR_SLV_UNSUPP) - dev_warn(port->dev, "Slave unsupported request\n"); + dev_warn(dev, "Slave unsupported request\n"); if (status & XILINX_PCIE_INTR_SLV_UNEXP) - dev_warn(port->dev, "Slave unexpected completion\n"); + dev_warn(dev, "Slave unexpected completion\n"); if (status & XILINX_PCIE_INTR_SLV_COMPL) - dev_warn(port->dev, "Slave completion timeout\n"); + dev_warn(dev, "Slave completion timeout\n"); if (status & XILINX_PCIE_INTR_SLV_ERRP) - dev_warn(port->dev, "Slave Error Poison\n"); + dev_warn(dev, "Slave Error Poison\n"); if (status & XILINX_PCIE_INTR_SLV_CMPABT) - dev_warn(port->dev, "Slave Completer Abort\n"); + dev_warn(dev, "Slave Completer Abort\n"); if (status & XILINX_PCIE_INTR_SLV_ILLBUR) - dev_warn(port->dev, "Slave Illegal Burst\n"); + dev_warn(dev, "Slave Illegal Burst\n"); if (status & XILINX_PCIE_INTR_MST_DECERR) - dev_warn(port->dev, "Master decode error\n"); + dev_warn(dev, "Master decode error\n"); if (status & XILINX_PCIE_INTR_MST_SLVERR) - dev_warn(port->dev, "Master slave error\n"); + dev_warn(dev, "Master slave error\n"); if (status & XILINX_PCIE_INTR_MST_ERRP) - dev_warn(port->dev, "Master error poison\n"); + dev_warn(dev, "Master error poison\n"); error: /* Clear the Interrupt Decode register */ @@ -554,10 +555,12 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie_port *port) */ static void xilinx_pcie_init_port(struct xilinx_pcie_port *port) { + struct device *dev = port->dev; + if (xilinx_pcie_link_is_up(port)) - dev_info(port->dev, "PCIe Link is UP\n"); + dev_info(dev, "PCIe Link is UP\n"); else - dev_info(port->dev, "PCIe Link is DOWN\n"); + dev_info(dev, "PCIe Link is DOWN\n"); /* Disable all interrupts */ pcie_write(port, ~XILINX_PCIE_IDR_ALL_MASK, @@ -627,8 +630,8 @@ static int xilinx_pcie_parse_dt(struct xilinx_pcie_port *port) */ static int xilinx_pcie_probe(struct platform_device *pdev) { - struct xilinx_pcie_port *port; struct device *dev = &pdev->dev; + struct xilinx_pcie_port *port; struct pci_bus *bus; int err; resource_size_t iobase = 0; @@ -668,15 +671,14 @@ static int xilinx_pcie_probe(struct platform_device *pdev) if (err) goto error; - bus = pci_create_root_bus(&pdev->dev, 0, - &xilinx_pcie_ops, port, &res); + bus = pci_create_root_bus(dev, 0, &xilinx_pcie_ops, port, &res); if (!bus) { err = -ENOMEM; goto error; } #ifdef CONFIG_PCI_MSI - xilinx_pcie_msi_chip.dev = port->dev; + xilinx_pcie_msi_chip.dev = dev; bus->msi = &xilinx_pcie_msi_chip; #endif pci_scan_child_bus(bus); @@ -685,8 +687,6 @@ static int xilinx_pcie_probe(struct platform_device *pdev) pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); #endif pci_bus_add_devices(bus); - platform_set_drvdata(pdev, port); - return 0; error: diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c index 460fa6708bfc..2acdb0d6ea89 100644 --- a/drivers/platform/x86/acerhdf.c +++ b/drivers/platform/x86/acerhdf.c @@ -405,7 +405,7 @@ static inline void acerhdf_enable_kernelmode(void) kernelmode = 1; thz_dev->polling_delay = interval*1000; - thermal_zone_device_update(thz_dev); + thermal_zone_device_update(thz_dev, THERMAL_EVENT_UNSPECIFIED); pr_notice("kernel mode fan control ON\n"); } diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 15f131146501..28551f5a2e07 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -932,30 +932,19 @@ static ssize_t infos_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(infos); -static int parse_arg(const char *buf, unsigned long count, int *val) -{ - if (!count) - return 0; - if (count > 31) - return -EINVAL; - if (sscanf(buf, "%i", val) != 1) - return -EINVAL; - return count; -} - static ssize_t sysfs_acpi_set(struct asus_laptop *asus, const char *buf, size_t count, const char *method) { int rv, value; - rv = parse_arg(buf, count, &value); - if (rv <= 0) + rv = kstrtoint(buf, 0, &value); + if (rv < 0) return rv; if (write_acpi_int(asus->handle, method, value)) return -ENODEV; - return rv; + return count; } /* @@ -975,15 +964,17 @@ static ssize_t ledd_store(struct device *dev, struct device_attribute *attr, struct asus_laptop *asus = dev_get_drvdata(dev); int rv, value; - rv = parse_arg(buf, count, &value); - if (rv > 0) { - if (write_acpi_int(asus->handle, METHOD_LEDD, value)) { - pr_warn("LED display write failed\n"); - return -ENODEV; - } - asus->ledd_status = (u32) value; + rv = kstrtoint(buf, 0, &value); + if (rv < 0) + return rv; + + if (write_acpi_int(asus->handle, METHOD_LEDD, value)) { + pr_warn("LED display write failed\n"); + return -ENODEV; } - return rv; + + asus->ledd_status = (u32) value; + return count; } static DEVICE_ATTR_RW(ledd); @@ -1148,10 +1139,12 @@ static ssize_t display_store(struct device *dev, struct device_attribute *attr, struct asus_laptop *asus = dev_get_drvdata(dev); int rv, value; - rv = parse_arg(buf, count, &value); - if (rv > 0) - asus_set_display(asus, value); - return rv; + rv = kstrtoint(buf, 0, &value); + if (rv < 0) + return rv; + + asus_set_display(asus, value); + return count; } static DEVICE_ATTR_WO(display); @@ -1190,11 +1183,12 @@ static ssize_t ls_switch_store(struct device *dev, struct asus_laptop *asus = dev_get_drvdata(dev); int rv, value; - rv = parse_arg(buf, count, &value); - if (rv > 0) - asus_als_switch(asus, value ? 1 : 0); + rv = kstrtoint(buf, 0, &value); + if (rv < 0) + return rv; - return rv; + asus_als_switch(asus, value ? 1 : 0); + return count; } static DEVICE_ATTR_RW(ls_switch); @@ -1219,14 +1213,15 @@ static ssize_t ls_level_store(struct device *dev, struct device_attribute *attr, struct asus_laptop *asus = dev_get_drvdata(dev); int rv, value; - rv = parse_arg(buf, count, &value); - if (rv > 0) { - value = (0 < value) ? ((15 < value) ? 15 : value) : 0; - /* 0 <= value <= 15 */ - asus_als_level(asus, value); - } + rv = kstrtoint(buf, 0, &value); + if (rv < 0) + return rv; - return rv; + value = (0 < value) ? ((15 < value) ? 15 : value) : 0; + /* 0 <= value <= 15 */ + asus_als_level(asus, value); + + return count; } static DEVICE_ATTR_RW(ls_level); @@ -1301,14 +1296,14 @@ static ssize_t gps_store(struct device *dev, struct device_attribute *attr, int rv, value; int ret; - rv = parse_arg(buf, count, &value); - if (rv <= 0) - return -EINVAL; + rv = kstrtoint(buf, 0, &value); + if (rv < 0) + return rv; ret = asus_gps_switch(asus, !!value); if (ret) return ret; rfkill_set_sw_state(asus->gps.rfkill, !value); - return rv; + return count; } static DEVICE_ATTR_RW(gps); diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index adecc1c555f0..26e4cbc34db8 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "asus-wmi.h" @@ -55,10 +56,34 @@ MODULE_PARM_DESC(wapf, "WAPF value"); static struct quirk_entry *quirks; +static bool asus_q500a_i8042_filter(unsigned char data, unsigned char str, + struct serio *port) +{ + static bool extended; + bool ret = false; + + if (str & I8042_STR_AUXDATA) + return false; + + if (unlikely(data == 0xe1)) { + extended = true; + ret = true; + } else if (unlikely(extended)) { + extended = false; + ret = true; + } + + return ret; +} + static struct quirk_entry quirk_asus_unknown = { .wapf = 0, }; +static struct quirk_entry quirk_asus_q500a = { + .i8042_filter = asus_q500a_i8042_filter, +}; + /* * For those machines that need software to control bt/wifi status * and can't adjust brightness through ACPI interface @@ -87,6 +112,10 @@ static struct quirk_entry quirk_no_rfkill_wapf4 = { .no_rfkill = true, }; +static struct quirk_entry quirk_asus_ux303ub = { + .wmi_backlight_native = true, +}; + static int dmi_matched(const struct dmi_system_id *dmi) { quirks = dmi->driver_data; @@ -94,6 +123,15 @@ static int dmi_matched(const struct dmi_system_id *dmi) } static const struct dmi_system_id asus_quirks[] = { + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. Q500A", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "Q500A"), + }, + .driver_data = &quirk_asus_q500a, + }, { .callback = dmi_matched, .ident = "ASUSTeK COMPUTER INC. U32U", @@ -351,11 +389,22 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_no_rfkill, }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. UX303UB", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "UX303UB"), + }, + .driver_data = &quirk_asus_ux303ub, + }, {}, }; static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) { + int ret; + quirks = &quirk_asus_unknown; dmi_check_system(asus_quirks); @@ -367,6 +416,15 @@ static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) quirks->wapf = wapf; else wapf = quirks->wapf; + + if (quirks->i8042_filter) { + ret = i8042_install_filter(quirks->i8042_filter); + if (ret) { + pr_warn("Unable to install key filter\n"); + return; + } + pr_info("Using i8042 filter function for receiving events\n"); + } } static const struct key_entry asus_nb_wmi_keymap[] = { diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 7c093a0b78bb..ce6ca31a2d09 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -2084,6 +2084,9 @@ static int asus_wmi_add(struct platform_device *pdev) if (asus->driver->quirks->wmi_backlight_power) acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); + if (asus->driver->quirks->wmi_backlight_native) + acpi_video_set_dmi_backlight_type(acpi_backlight_native); + if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { err = asus_wmi_backlight_init(asus); if (err && err != -ENODEV) diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index 5de1df510ebd..0e19014e9f54 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -28,6 +28,7 @@ #define _ASUS_WMI_H_ #include +#include #define ASUS_WMI_KEY_IGNORE (-1) #define ASUS_WMI_BRN_DOWN 0x20 @@ -43,6 +44,7 @@ struct quirk_entry { bool scalar_panel_brightness; bool store_backlight_power; bool wmi_backlight_power; + bool wmi_backlight_native; int wapf; /* * For machines with AMD graphic chips, it will send out WMI event @@ -51,6 +53,9 @@ struct quirk_entry { * and let the ACPI interrupt to send out the key event. */ int no_display_toggle; + + bool (*i8042_filter)(unsigned char data, unsigned char str, + struct serio *serio); }; struct asus_wmi_driver { diff --git a/drivers/platform/x86/dell-smo8800.c b/drivers/platform/x86/dell-smo8800.c index 0aec4fd4c48e..37e646034ef8 100644 --- a/drivers/platform/x86/dell-smo8800.c +++ b/drivers/platform/x86/dell-smo8800.c @@ -24,6 +24,7 @@ #include #include #include +#include struct smo8800_device { u32 irq; /* acpi device irq */ diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index 520b58a04daa..e8b1b836ca2d 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -100,7 +100,7 @@ static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) struct dentry *dir, *file; dir = debugfs_create_dir("pmc_core", NULL); - if (IS_ERR_OR_NULL(dir)) + if (!dir) return -ENOMEM; pmcdev->dbgfs_dir = dir; diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c index a511d518206b..0bf51d574fa9 100644 --- a/drivers/platform/x86/intel_pmc_ipc.c +++ b/drivers/platform/x86/intel_pmc_ipc.c @@ -522,48 +522,36 @@ static struct resource telemetry_res[] = { static int ipc_create_punit_device(void) { struct platform_device *pdev; - int ret; + const struct platform_device_info pdevinfo = { + .parent = ipcdev.dev, + .name = PUNIT_DEVICE_NAME, + .id = -1, + .res = punit_res_array, + .num_res = ARRAY_SIZE(punit_res_array), + }; - pdev = platform_device_alloc(PUNIT_DEVICE_NAME, -1); - if (!pdev) { - dev_err(ipcdev.dev, "Failed to alloc punit platform device\n"); - return -ENOMEM; - } + pdev = platform_device_register_full(&pdevinfo); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); - pdev->dev.parent = ipcdev.dev; - ret = platform_device_add_resources(pdev, punit_res_array, - ARRAY_SIZE(punit_res_array)); - if (ret) { - dev_err(ipcdev.dev, "Failed to add platform punit resources\n"); - goto err; - } - - ret = platform_device_add(pdev); - if (ret) { - dev_err(ipcdev.dev, "Failed to add punit platform device\n"); - goto err; - } ipcdev.punit_dev = pdev; return 0; -err: - platform_device_put(pdev); - return ret; } static int ipc_create_tco_device(void) { struct platform_device *pdev; struct resource *res; - int ret; - - pdev = platform_device_alloc(TCO_DEVICE_NAME, -1); - if (!pdev) { - dev_err(ipcdev.dev, "Failed to alloc tco platform device\n"); - return -ENOMEM; - } - - pdev->dev.parent = ipcdev.dev; + const struct platform_device_info pdevinfo = { + .parent = ipcdev.dev, + .name = TCO_DEVICE_NAME, + .id = -1, + .res = tco_res, + .num_res = ARRAY_SIZE(tco_res), + .data = &tco_info, + .size_data = sizeof(tco_info), + }; res = tco_res + TCO_RESOURCE_ACPI_IO; res->start = ipcdev.acpi_io_base + TCO_BASE_OFFSET; @@ -577,45 +565,26 @@ static int ipc_create_tco_device(void) res->start = ipcdev.gcr_base + TCO_PMC_OFFSET; res->end = res->start + TCO_PMC_SIZE - 1; - ret = platform_device_add_resources(pdev, tco_res, ARRAY_SIZE(tco_res)); - if (ret) { - dev_err(ipcdev.dev, "Failed to add tco platform resources\n"); - goto err; - } + pdev = platform_device_register_full(&pdevinfo); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); - ret = platform_device_add_data(pdev, &tco_info, sizeof(tco_info)); - if (ret) { - dev_err(ipcdev.dev, "Failed to add tco platform data\n"); - goto err; - } - - ret = platform_device_add(pdev); - if (ret) { - dev_err(ipcdev.dev, "Failed to add tco platform device\n"); - goto err; - } ipcdev.tco_dev = pdev; return 0; -err: - platform_device_put(pdev); - return ret; } static int ipc_create_telemetry_device(void) { struct platform_device *pdev; struct resource *res; - int ret; - - pdev = platform_device_alloc(TELEMETRY_DEVICE_NAME, -1); - if (!pdev) { - dev_err(ipcdev.dev, - "Failed to allocate telemetry platform device\n"); - return -ENOMEM; - } - - pdev->dev.parent = ipcdev.dev; + const struct platform_device_info pdevinfo = { + .parent = ipcdev.dev, + .name = TELEMETRY_DEVICE_NAME, + .id = -1, + .res = telemetry_res, + .num_res = ARRAY_SIZE(telemetry_res), + }; res = telemetry_res + TELEMETRY_RESOURCE_PUNIT_SSRAM; res->start = ipcdev.telem_punit_ssram_base; @@ -625,26 +594,13 @@ static int ipc_create_telemetry_device(void) res->start = ipcdev.telem_pmc_ssram_base; res->end = res->start + ipcdev.telem_pmc_ssram_size - 1; - ret = platform_device_add_resources(pdev, telemetry_res, - ARRAY_SIZE(telemetry_res)); - if (ret) { - dev_err(ipcdev.dev, - "Failed to add telemetry platform resources\n"); - goto err; - } + pdev = platform_device_register_full(&pdevinfo); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); - ret = platform_device_add(pdev); - if (ret) { - dev_err(ipcdev.dev, - "Failed to add telemetry platform device\n"); - goto err; - } ipcdev.telemetry_dev = pdev; return 0; -err: - platform_device_put(pdev); - return ret; } static int ipc_create_pmc_devices(void) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 9d60a40d8b3f..074bf2fa1c55 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -321,10 +321,9 @@ static int write_acpi_int(const char *methodName, int val) static acpi_status tci_raw(struct toshiba_acpi_dev *dev, const u32 in[TCI_WORDS], u32 out[TCI_WORDS]) { + union acpi_object in_objs[TCI_WORDS], out_objs[TCI_WORDS + 1]; struct acpi_object_list params; - union acpi_object in_objs[TCI_WORDS]; struct acpi_buffer results; - union acpi_object out_objs[TCI_WORDS + 1]; acpi_status status; int i; @@ -387,9 +386,8 @@ static int sci_open(struct toshiba_acpi_dev *dev) { u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 }; u32 out[TCI_WORDS]; - acpi_status status; + acpi_status status = tci_raw(dev, in, out); - status = tci_raw(dev, in, out); if (ACPI_FAILURE(status)) { pr_err("ACPI call to open SCI failed\n"); return 0; @@ -425,9 +423,8 @@ static void sci_close(struct toshiba_acpi_dev *dev) { u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 }; u32 out[TCI_WORDS]; - acpi_status status; + acpi_status status = tci_raw(dev, in, out); - status = tci_raw(dev, in, out); if (ACPI_FAILURE(status)) { pr_err("ACPI call to close SCI failed\n"); return; @@ -479,10 +476,15 @@ static void toshiba_illumination_available(struct toshiba_acpi_dev *dev) status = tci_raw(dev, in, out); sci_close(dev); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { pr_err("ACPI call to query Illumination support failed\n"); - else if (out[0] == TOS_SUCCESS) - dev->illumination_supported = 1; + return; + } + + if (out[0] != TOS_SUCCESS) + return; + + dev->illumination_supported = 1; } static void toshiba_illumination_set(struct led_classdev *cdev, @@ -509,7 +511,8 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) { struct toshiba_acpi_dev *dev = container_of(cdev, struct toshiba_acpi_dev, led_dev); - u32 state, result; + u32 result; + u32 state; /* First request : initialize communication. */ if (!sci_open(dev)) @@ -546,24 +549,28 @@ static void toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) sci_close(dev); if (ACPI_FAILURE(status)) { pr_err("ACPI call to query kbd illumination support failed\n"); - } else if (out[0] == TOS_SUCCESS) { - /* - * Check for keyboard backlight timeout max value, - * previous kbd backlight implementation set this to - * 0x3c0003, and now the new implementation set this - * to 0x3c001a, use this to distinguish between them. - */ - if (out[3] == SCI_KBD_TIME_MAX) - dev->kbd_type = 2; - else - dev->kbd_type = 1; - /* Get the current keyboard backlight mode */ - dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; - /* Get the current time (1-60 seconds) */ - dev->kbd_time = out[2] >> HCI_MISC_SHIFT; - /* Flag as supported */ - dev->kbd_illum_supported = 1; + return; } + + if (out[0] != TOS_SUCCESS) + return; + + /* + * Check for keyboard backlight timeout max value, + * previous kbd backlight implementation set this to + * 0x3c0003, and now the new implementation set this + * to 0x3c001a, use this to distinguish between them. + */ + if (out[3] == SCI_KBD_TIME_MAX) + dev->kbd_type = 2; + else + dev->kbd_type = 1; + /* Get the current keyboard backlight mode */ + dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; + /* Get the current time (1-60 seconds) */ + dev->kbd_time = out[2] >> HCI_MISC_SHIFT; + /* Flag as supported */ + dev->kbd_illum_supported = 1; } static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) @@ -672,9 +679,9 @@ static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) /* Eco Mode support */ static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) { - acpi_status status; u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 }; u32 out[TCI_WORDS]; + acpi_status status; dev->eco_supported = 0; dev->eco_led_registered = false; @@ -682,7 +689,10 @@ static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) status = tci_raw(dev, in, out); if (ACPI_FAILURE(status)) { pr_err("ACPI call to get ECO led failed\n"); - } else if (out[0] == TOS_INPUT_DATA_ERROR) { + return; + } + + if (out[0] == TOS_INPUT_DATA_ERROR) { /* * If we receive 0x8300 (Input Data Error), it means that the * LED device is present, but that we just screwed the input @@ -694,10 +704,15 @@ static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) */ in[3] = 1; status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { pr_err("ACPI call to get ECO led failed\n"); - else if (out[0] == TOS_SUCCESS) - dev->eco_supported = 1; + return; + } + + if (out[0] != TOS_SUCCESS) + return; + + dev->eco_supported = 1; } } @@ -714,10 +729,11 @@ toshiba_eco_mode_get_status(struct led_classdev *cdev) if (ACPI_FAILURE(status)) { pr_err("ACPI call to get ECO led failed\n"); return LED_OFF; - } else if (out[0] != TOS_SUCCESS) { - return LED_OFF; } + if (out[0] != TOS_SUCCESS) + return LED_OFF; + return out[2] ? LED_FULL : LED_OFF; } @@ -751,10 +767,15 @@ static void toshiba_accelerometer_available(struct toshiba_acpi_dev *dev) * this call also serves as initialization */ status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { pr_err("ACPI call to query the accelerometer failed\n"); - else if (out[0] == TOS_SUCCESS) - dev->accelerometer_supported = 1; + return; + } + + if (out[0] != TOS_SUCCESS) + return; + + dev->accelerometer_supported = 1; } static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, @@ -769,15 +790,18 @@ static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, if (ACPI_FAILURE(status)) { pr_err("ACPI call to query the accelerometer failed\n"); return -EIO; - } else if (out[0] == TOS_NOT_SUPPORTED) { - return -ENODEV; - } else if (out[0] == TOS_SUCCESS) { - *xy = out[2]; - *z = out[4]; - return 0; } - return -EIO; + if (out[0] == TOS_NOT_SUPPORTED) + return -ENODEV; + + if (out[0] != TOS_SUCCESS) + return -EIO; + + *xy = out[2]; + *z = out[4]; + + return 0; } /* Sleep (Charge and Music) utilities support */ @@ -797,24 +821,29 @@ static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); sci_close(dev); return; - } else if (out[0] == TOS_NOT_SUPPORTED) { + } + + if (out[0] != TOS_SUCCESS) { sci_close(dev); return; - } else if (out[0] == TOS_SUCCESS) { - dev->usbsc_mode_base = out[4]; } + dev->usbsc_mode_base = out[4]; + in[5] = SCI_USB_CHARGE_BAT_LVL; status = tci_raw(dev, in, out); sci_close(dev); if (ACPI_FAILURE(status)) { pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); - } else if (out[0] == TOS_SUCCESS) { - dev->usbsc_bat_level = out[2]; - /* Flag as supported */ - dev->usb_sleep_charge_supported = 1; + return; } + if (out[0] != TOS_SUCCESS) + return; + + dev->usbsc_bat_level = out[2]; + /* Flag as supported */ + dev->usb_sleep_charge_supported = 1; } static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, @@ -868,14 +897,19 @@ static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, sci_close(dev); if (ACPI_FAILURE(status)) { pr_err("ACPI call to get USB S&C battery level failed\n"); - } else if (out[0] == TOS_NOT_SUPPORTED) { - return -ENODEV; - } else if (out[0] == TOS_SUCCESS) { - *mode = out[2]; - return 0; + return -EIO; } - return -EIO; + if (out[0] == TOS_NOT_SUPPORTED) + return -ENODEV; + + if (out[0] != TOS_SUCCESS) + return -EIO; + + *mode = out[2]; + + return 0; + } static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, @@ -892,9 +926,12 @@ static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, in[5] = SCI_USB_CHARGE_BAT_LVL; status = tci_raw(dev, in, out); sci_close(dev); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { pr_err("ACPI call to set USB S&C battery level failed\n"); - else if (out[0] == TOS_NOT_SUPPORTED) + return -EIO; + } + + if (out[0] == TOS_NOT_SUPPORTED) return -ENODEV; return out[0] == TOS_SUCCESS ? 0 : -EIO; @@ -915,14 +952,18 @@ static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, sci_close(dev); if (ACPI_FAILURE(status)) { pr_err("ACPI call to get USB Rapid Charge failed\n"); - } else if (out[0] == TOS_NOT_SUPPORTED) { - return -ENODEV; - } else if (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) { - *state = out[2]; - return 0; + return -EIO; } - return -EIO; + if (out[0] == TOS_NOT_SUPPORTED) + return -ENODEV; + + if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2) + return -EIO; + + *state = out[2]; + + return 0; } static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, @@ -939,9 +980,12 @@ static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, in[5] = SCI_USB_CHARGE_RAPID_DSP; status = tci_raw(dev, in, out); sci_close(dev); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { pr_err("ACPI call to set USB Rapid Charge failed\n"); - else if (out[0] == TOS_NOT_SUPPORTED) + return -EIO; + } + + if (out[0] == TOS_NOT_SUPPORTED) return -ENODEV; return (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) ? 0 : -EIO; @@ -1097,14 +1141,18 @@ static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, status = tci_raw(dev, in, out); if (ACPI_FAILURE(status)) { pr_err("ACPI call to get System type failed\n"); - } else if (out[0] == TOS_NOT_SUPPORTED) { - return -ENODEV; - } else if (out[0] == TOS_SUCCESS) { - *type = out[3]; - return 0; + return -EIO; } - return -EIO; + if (out[0] == TOS_NOT_SUPPORTED) + return -ENODEV; + + if (out[0] != TOS_SUCCESS) + return -EIO; + + *type = out[3]; + + return 0; } /* Wireless status (RFKill, WLAN, BT, WWAN) */ @@ -1154,7 +1202,6 @@ static void toshiba_wwan_available(struct toshiba_acpi_dev *dev) */ in[3] = HCI_WIRELESS_WWAN; status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status)) { pr_err("ACPI call to get WWAN status failed\n"); return; @@ -1174,7 +1221,6 @@ static int toshiba_wwan_set(struct toshiba_acpi_dev *dev, u32 state) in[3] = HCI_WIRELESS_WWAN_STATUS; status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status)) { pr_err("ACPI call to set WWAN status failed\n"); return -EIO; @@ -1193,7 +1239,6 @@ static int toshiba_wwan_set(struct toshiba_acpi_dev *dev, u32 state) */ in[3] = HCI_WIRELESS_WWAN_POWER; status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status)) { pr_err("ACPI call to set WWAN power failed\n"); return -EIO; @@ -1216,8 +1261,10 @@ static void toshiba_cooling_method_available(struct toshiba_acpi_dev *dev) dev->max_cooling_method = 0; status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { pr_err("ACPI call to get Cooling Method failed\n"); + return; + } if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2) return; @@ -1244,7 +1291,7 @@ static int toshiba_cooling_method_set(struct toshiba_acpi_dev *dev, u32 state) u32 result = hci_write(dev, HCI_COOLING_METHOD, state); if (result == TOS_FAILURE) - pr_err("ACPI call to get Cooling Method failed\n"); + pr_err("ACPI call to set Cooling Method failed\n"); if (result == TOS_NOT_SUPPORTED) return -ENODEV; @@ -1282,9 +1329,9 @@ static struct proc_dir_entry *toshiba_proc_dir; /* LCD Brightness */ static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) { + int brightness = 0; u32 result; u32 value; - int brightness = 0; if (dev->tr_backlight_supported) { int ret = get_tr_backlight_status(dev, &value); @@ -1301,10 +1348,10 @@ static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) pr_err("ACPI call to get LCD Brightness failed\n"); else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - if (result == TOS_SUCCESS) - return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); - return -EIO; + return result == TOS_SUCCESS ? + brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT) : + -EIO; } static int get_lcd_brightness(struct backlight_device *bd) @@ -1325,15 +1372,15 @@ static int lcd_proc_show(struct seq_file *m, void *v) levels = dev->backlight_dev->props.max_brightness + 1; value = get_lcd_brightness(dev->backlight_dev); - if (value >= 0) { - seq_printf(m, "brightness: %d\n", value); - seq_printf(m, "brightness_levels: %d\n", levels); - return 0; + if (value < 0) { + pr_err("Error reading LCD brightness\n"); + return value; } - pr_err("Error reading LCD brightness\n"); + seq_printf(m, "brightness: %d\n", value); + seq_printf(m, "brightness_levels: %d\n", levels); - return -EIO; + return 0; } static int lcd_proc_open(struct inode *inode, struct file *file) @@ -1377,7 +1424,7 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf, struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); char cmd[42]; size_t len; - int levels = dev->backlight_dev->props.max_brightness + 1; + int levels; int value; len = min(count, sizeof(cmd) - 1); @@ -1385,6 +1432,7 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf, return -EFAULT; cmd[len] = '\0'; + levels = dev->backlight_dev->props.max_brightness + 1; if (sscanf(cmd, " brightness : %i", &value) != 1 && value < 0 && value > levels) return -EINVAL; @@ -1420,20 +1468,21 @@ static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status) static int video_proc_show(struct seq_file *m, void *v) { struct toshiba_acpi_dev *dev = m->private; + int is_lcd, is_crt, is_tv; u32 value; - if (!get_video_status(dev, &value)) { - int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; - int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; - int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; + if (get_video_status(dev, &value)) + return -EIO; - seq_printf(m, "lcd_out: %d\n", is_lcd); - seq_printf(m, "crt_out: %d\n", is_crt); - seq_printf(m, "tv_out: %d\n", is_tv); - return 0; - } + is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; + is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; + is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; - return -EIO; + seq_printf(m, "lcd_out: %d\n", is_lcd); + seq_printf(m, "crt_out: %d\n", is_crt); + seq_printf(m, "tv_out: %d\n", is_tv); + + return 0; } static int video_proc_open(struct inode *inode, struct file *file) @@ -1447,10 +1496,8 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf, struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); char *buffer; char *cmd; + int lcd_out, crt_out, tv_out; int remain = count; - int lcd_out = -1; - int crt_out = -1; - int tv_out = -1; int value; int ret; u32 video_out; @@ -1486,6 +1533,7 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf, kfree(cmd); + lcd_out = crt_out = tv_out = -1; ret = get_video_status(dev, &video_out); if (!ret) { unsigned int new_video_out = video_out; @@ -1980,8 +2028,8 @@ static ssize_t usb_sleep_charge_store(struct device *dev, const char *buf, size_t count) { struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); - u32 mode; int state; + u32 mode; int ret; ret = kstrtoint(buf, 0, &state); @@ -2021,9 +2069,8 @@ static ssize_t sleep_functions_on_battery_show(struct device *dev, char *buf) { struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); + int bat_lvl, status; u32 state; - int bat_lvl; - int status; int ret; int tmp; diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c index 5db495dd018e..be1d137c6079 100644 --- a/drivers/platform/x86/toshiba_bluetooth.c +++ b/drivers/platform/x86/toshiba_bluetooth.c @@ -80,7 +80,9 @@ static int toshiba_bluetooth_present(acpi_handle handle) if (ACPI_FAILURE(result)) { pr_err("ACPI call to query Bluetooth presence failed\n"); return -ENXIO; - } else if (!bt_present) { + } + + if (!bt_present) { pr_info("Bluetooth device not present\n"); return -ENODEV; } diff --git a/drivers/platform/x86/toshiba_haps.c b/drivers/platform/x86/toshiba_haps.c index 7f2afc6b5eb9..b3dec521e2b6 100644 --- a/drivers/platform/x86/toshiba_haps.c +++ b/drivers/platform/x86/toshiba_haps.c @@ -59,7 +59,7 @@ static int toshiba_haps_protection_level(acpi_handle handle, int level) return -EIO; } - pr_info("HDD protection level set to: %d\n", level); + pr_debug("HDD protection level set to: %d\n", level); return 0; } @@ -141,7 +141,7 @@ static struct attribute_group haps_attr_group = { */ static void toshiba_haps_notify(struct acpi_device *device, u32 event) { - pr_info("Received event: 0x%x", event); + pr_debug("Received event: 0x%x", event); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), @@ -168,9 +168,13 @@ static int toshiba_haps_available(acpi_handle handle) * A non existent device as well as having (only) * Solid State Drives can cause the call to fail. */ - status = acpi_evaluate_integer(handle, "_STA", NULL, - &hdd_present); - if (ACPI_FAILURE(status) || !hdd_present) { + status = acpi_evaluate_integer(handle, "_STA", NULL, &hdd_present); + if (ACPI_FAILURE(status)) { + pr_err("ACPI call to query HDD protection failed\n"); + return 0; + } + + if (!hdd_present) { pr_info("HDD protection not available or using SSD\n"); return 0; } diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index d637c933c8a9..58a97d420572 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -193,6 +193,7 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) if (err) break; + memset(&precise_offset, 0, sizeof(precise_offset)); ts = ktime_to_timespec64(xtstamp.device); precise_offset.device.sec = ts.tv_sec; precise_offset.device.nsec = ts.tv_nsec; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 80a566a00d04..bf0128899c09 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -262,6 +262,15 @@ config PWM_LPSS_PLATFORM To compile this driver as a module, choose M here: the module will be called pwm-lpss-platform. +config PWM_MESON + tristate "Amlogic Meson PWM driver" + depends on ARCH_MESON + help + The platform driver for Amlogic Meson PWM controller. + + To compile this driver as a module, choose M here: the module + will be called pwm-meson. + config PWM_MTK_DISP tristate "MediaTek display PWM driver" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index feef1dd29f73..1194c54efcc2 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o +obj-$(CONFIG_PWM_MESON) += pwm-meson.o obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o obj-$(CONFIG_PWM_MXS) += pwm-mxs.o obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 0dbd29e287db..172ef8245811 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -339,6 +339,8 @@ int pwmchip_remove(struct pwm_chip *chip) unsigned int i; int ret = 0; + pwmchip_sysfs_unexport_children(chip); + mutex_lock(&pwm_lock); for (i = 0; i < chip->npwm; i++) { diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c index 65108129d505..01339c152ab0 100644 --- a/drivers/pwm/pwm-berlin.c +++ b/drivers/pwm/pwm-berlin.c @@ -16,6 +16,7 @@ #include #include #include +#include #define BERLIN_PWM_EN 0x0 #define BERLIN_PWM_ENABLE BIT(0) @@ -27,6 +28,13 @@ #define BERLIN_PWM_TCNT 0xc #define BERLIN_PWM_MAX_TCNT 65535 +struct berlin_pwm_channel { + u32 enable; + u32 ctrl; + u32 duty; + u32 tcnt; +}; + struct berlin_pwm_chip { struct pwm_chip chip; struct clk *clk; @@ -55,6 +63,25 @@ static inline void berlin_pwm_writel(struct berlin_pwm_chip *chip, writel_relaxed(value, chip->base + channel * 0x10 + offset); } +static int berlin_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct berlin_pwm_channel *channel; + + channel = kzalloc(sizeof(*channel), GFP_KERNEL); + if (!channel) + return -ENOMEM; + + return pwm_set_chip_data(pwm, channel); +} + +static void berlin_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct berlin_pwm_channel *channel = pwm_get_chip_data(pwm); + + pwm_set_chip_data(pwm, NULL); + kfree(channel); +} + static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev, int duty_ns, int period_ns) { @@ -137,6 +164,8 @@ static void berlin_pwm_disable(struct pwm_chip *chip, } static const struct pwm_ops berlin_pwm_ops = { + .request = berlin_pwm_request, + .free = berlin_pwm_free, .config = berlin_pwm_config, .set_polarity = berlin_pwm_set_polarity, .enable = berlin_pwm_enable, @@ -204,12 +233,67 @@ static int berlin_pwm_remove(struct platform_device *pdev) return ret; } +#ifdef CONFIG_PM_SLEEP +static int berlin_pwm_suspend(struct device *dev) +{ + struct berlin_pwm_chip *pwm = dev_get_drvdata(dev); + unsigned int i; + + for (i = 0; i < pwm->chip.npwm; i++) { + struct berlin_pwm_channel *channel; + + channel = pwm_get_chip_data(&pwm->chip.pwms[i]); + if (!channel) + continue; + + channel->enable = berlin_pwm_readl(pwm, i, BERLIN_PWM_ENABLE); + channel->ctrl = berlin_pwm_readl(pwm, i, BERLIN_PWM_CONTROL); + channel->duty = berlin_pwm_readl(pwm, i, BERLIN_PWM_DUTY); + channel->tcnt = berlin_pwm_readl(pwm, i, BERLIN_PWM_TCNT); + } + + clk_disable_unprepare(pwm->clk); + + return 0; +} + +static int berlin_pwm_resume(struct device *dev) +{ + struct berlin_pwm_chip *pwm = dev_get_drvdata(dev); + unsigned int i; + int ret; + + ret = clk_prepare_enable(pwm->clk); + if (ret) + return ret; + + for (i = 0; i < pwm->chip.npwm; i++) { + struct berlin_pwm_channel *channel; + + channel = pwm_get_chip_data(&pwm->chip.pwms[i]); + if (!channel) + continue; + + berlin_pwm_writel(pwm, i, channel->ctrl, BERLIN_PWM_CONTROL); + berlin_pwm_writel(pwm, i, channel->duty, BERLIN_PWM_DUTY); + berlin_pwm_writel(pwm, i, channel->tcnt, BERLIN_PWM_TCNT); + berlin_pwm_writel(pwm, i, channel->enable, BERLIN_PWM_ENABLE); + } + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(berlin_pwm_pm_ops, berlin_pwm_suspend, + berlin_pwm_resume); + static struct platform_driver berlin_pwm_driver = { .probe = berlin_pwm_probe, .remove = berlin_pwm_remove, .driver = { .name = "berlin-pwm", .of_match_table = berlin_pwm_match, + .pm = &berlin_pwm_pm_ops, }, }; module_platform_driver(berlin_pwm_driver); diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c index 99b9acc1a420..f6ca4e8c6253 100644 --- a/drivers/pwm/pwm-cros-ec.c +++ b/drivers/pwm/pwm-cros-ec.c @@ -38,7 +38,7 @@ static int cros_ec_pwm_set_duty(struct cros_ec_device *ec, u8 index, u16 duty) struct { struct cros_ec_command msg; struct ec_params_pwm_set_duty params; - } buf; + } __packed buf; struct ec_params_pwm_set_duty *params = &buf.params; struct cros_ec_command *msg = &buf.msg; @@ -65,7 +65,7 @@ static int __cros_ec_pwm_get_duty(struct cros_ec_device *ec, u8 index, struct ec_params_pwm_get_duty params; struct ec_response_pwm_get_duty resp; }; - } buf; + } __packed buf; struct ec_params_pwm_get_duty *params = &buf.params; struct ec_response_pwm_get_duty *resp = &buf.resp; struct cros_ec_command *msg = &buf.msg; diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c index 19dc64cab2f0..d7f5f7de030d 100644 --- a/drivers/pwm/pwm-lpc18xx-sct.c +++ b/drivers/pwm/pwm-lpc18xx-sct.c @@ -413,14 +413,18 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev) } for (i = 0; i < lpc18xx_pwm->chip.npwm; i++) { + struct lpc18xx_pwm_data *data; + pwm = &lpc18xx_pwm->chip.pwms[i]; - pwm->chip_data = devm_kzalloc(lpc18xx_pwm->dev, - sizeof(struct lpc18xx_pwm_data), - GFP_KERNEL); - if (!pwm->chip_data) { + + data = devm_kzalloc(lpc18xx_pwm->dev, sizeof(*data), + GFP_KERNEL); + if (!data) { ret = -ENOMEM; goto remove_pwmchip; } + + pwm_set_chip_data(pwm, data); } platform_set_drvdata(pdev, lpc18xx_pwm); diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c new file mode 100644 index 000000000000..381871b2bb46 --- /dev/null +++ b/drivers/pwm/pwm-meson.c @@ -0,0 +1,529 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong + * Copyright (C) 2014 Amlogic, Inc. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * BSD LICENSE + * + * Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong + * Copyright (C) 2014 Amlogic, Inc. + * + * 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. + * * Neither the name of Intel Corporation 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 + * OWNER 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_PWM_A 0x0 +#define REG_PWM_B 0x4 +#define PWM_HIGH_SHIFT 16 + +#define REG_MISC_AB 0x8 +#define MISC_B_CLK_EN BIT(23) +#define MISC_A_CLK_EN BIT(15) +#define MISC_CLK_DIV_MASK 0x7f +#define MISC_B_CLK_DIV_SHIFT 16 +#define MISC_A_CLK_DIV_SHIFT 8 +#define MISC_B_CLK_SEL_SHIFT 6 +#define MISC_A_CLK_SEL_SHIFT 4 +#define MISC_CLK_SEL_WIDTH 2 +#define MISC_B_EN BIT(1) +#define MISC_A_EN BIT(0) + +static const unsigned int mux_reg_shifts[] = { + MISC_A_CLK_SEL_SHIFT, + MISC_B_CLK_SEL_SHIFT +}; + +struct meson_pwm_channel { + unsigned int hi; + unsigned int lo; + u8 pre_div; + + struct pwm_state state; + + struct clk *clk_parent; + struct clk_mux mux; + struct clk *clk; +}; + +struct meson_pwm_data { + const char * const *parent_names; +}; + +struct meson_pwm { + struct pwm_chip chip; + const struct meson_pwm_data *data; + void __iomem *base; + u8 inverter_mask; + spinlock_t lock; +}; + +static inline struct meson_pwm *to_meson_pwm(struct pwm_chip *chip) +{ + return container_of(chip, struct meson_pwm, chip); +} + +static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); + struct device *dev = chip->dev; + int err; + + if (!channel) + return -ENODEV; + + if (channel->clk_parent) { + err = clk_set_parent(channel->clk, channel->clk_parent); + if (err < 0) { + dev_err(dev, "failed to set parent %s for %s: %d\n", + __clk_get_name(channel->clk_parent), + __clk_get_name(channel->clk), err); + return err; + } + } + + err = clk_prepare_enable(channel->clk); + if (err < 0) { + dev_err(dev, "failed to enable clock %s: %d\n", + __clk_get_name(channel->clk), err); + return err; + } + + chip->ops->get_state(chip, pwm, &channel->state); + + return 0; +} + +static void meson_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); + + if (channel) + clk_disable_unprepare(channel->clk); +} + +static int meson_pwm_calc(struct meson_pwm *meson, + struct meson_pwm_channel *channel, unsigned int id, + unsigned int duty, unsigned int period) +{ + unsigned int pre_div, cnt, duty_cnt; + unsigned long fin_freq = -1, fin_ns; + + if (~(meson->inverter_mask >> id) & 0x1) + duty = period - duty; + + if (period == channel->state.period && + duty == channel->state.duty_cycle) + return 0; + + fin_freq = clk_get_rate(channel->clk); + if (fin_freq == 0) { + dev_err(meson->chip.dev, "invalid source clock frequency\n"); + return -EINVAL; + } + + dev_dbg(meson->chip.dev, "fin_freq: %lu Hz\n", fin_freq); + fin_ns = NSEC_PER_SEC / fin_freq; + + /* Calc pre_div with the period */ + for (pre_div = 0; pre_div < MISC_CLK_DIV_MASK; pre_div++) { + cnt = DIV_ROUND_CLOSEST(period, fin_ns * (pre_div + 1)); + dev_dbg(meson->chip.dev, "fin_ns=%lu pre_div=%u cnt=%u\n", + fin_ns, pre_div, cnt); + if (cnt <= 0xffff) + break; + } + + if (pre_div == MISC_CLK_DIV_MASK) { + dev_err(meson->chip.dev, "unable to get period pre_div\n"); + return -EINVAL; + } + + dev_dbg(meson->chip.dev, "period=%u pre_div=%u cnt=%u\n", period, + pre_div, cnt); + + if (duty == period) { + channel->pre_div = pre_div; + channel->hi = cnt; + channel->lo = 0; + } else if (duty == 0) { + channel->pre_div = pre_div; + channel->hi = 0; + channel->lo = cnt; + } else { + /* Then check is we can have the duty with the same pre_div */ + duty_cnt = DIV_ROUND_CLOSEST(duty, fin_ns * (pre_div + 1)); + if (duty_cnt > 0xffff) { + dev_err(meson->chip.dev, "unable to get duty cycle\n"); + return -EINVAL; + } + + dev_dbg(meson->chip.dev, "duty=%u pre_div=%u duty_cnt=%u\n", + duty, pre_div, duty_cnt); + + channel->pre_div = pre_div; + channel->hi = duty_cnt; + channel->lo = cnt - duty_cnt; + } + + return 0; +} + +static void meson_pwm_enable(struct meson_pwm *meson, + struct meson_pwm_channel *channel, + unsigned int id) +{ + u32 value, clk_shift, clk_enable, enable; + unsigned int offset; + + switch (id) { + case 0: + clk_shift = MISC_A_CLK_DIV_SHIFT; + clk_enable = MISC_A_CLK_EN; + enable = MISC_A_EN; + offset = REG_PWM_A; + break; + + case 1: + clk_shift = MISC_B_CLK_DIV_SHIFT; + clk_enable = MISC_B_CLK_EN; + enable = MISC_B_EN; + offset = REG_PWM_B; + break; + + default: + return; + } + + value = readl(meson->base + REG_MISC_AB); + value &= ~(MISC_CLK_DIV_MASK << clk_shift); + value |= channel->pre_div << clk_shift; + value |= clk_enable; + writel(value, meson->base + REG_MISC_AB); + + value = (channel->hi << PWM_HIGH_SHIFT) | channel->lo; + writel(value, meson->base + offset); + + value = readl(meson->base + REG_MISC_AB); + value |= enable; + writel(value, meson->base + REG_MISC_AB); +} + +static void meson_pwm_disable(struct meson_pwm *meson, unsigned int id) +{ + u32 value, enable; + + switch (id) { + case 0: + enable = MISC_A_EN; + break; + + case 1: + enable = MISC_B_EN; + break; + + default: + return; + } + + value = readl(meson->base + REG_MISC_AB); + value &= ~enable; + writel(value, meson->base + REG_MISC_AB); +} + +static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); + struct meson_pwm *meson = to_meson_pwm(chip); + unsigned long flags; + int err = 0; + + if (!state) + return -EINVAL; + + spin_lock_irqsave(&meson->lock, flags); + + if (!state->enabled) { + meson_pwm_disable(meson, pwm->hwpwm); + channel->state.enabled = false; + + goto unlock; + } + + if (state->period != channel->state.period || + state->duty_cycle != channel->state.duty_cycle || + state->polarity != channel->state.polarity) { + if (channel->state.enabled) { + meson_pwm_disable(meson, pwm->hwpwm); + channel->state.enabled = false; + } + + if (state->polarity != channel->state.polarity) { + if (state->polarity == PWM_POLARITY_NORMAL) + meson->inverter_mask |= BIT(pwm->hwpwm); + else + meson->inverter_mask &= ~BIT(pwm->hwpwm); + } + + err = meson_pwm_calc(meson, channel, pwm->hwpwm, + state->duty_cycle, state->period); + if (err < 0) + goto unlock; + + channel->state.polarity = state->polarity; + channel->state.period = state->period; + channel->state.duty_cycle = state->duty_cycle; + } + + if (state->enabled && !channel->state.enabled) { + meson_pwm_enable(meson, channel, pwm->hwpwm); + channel->state.enabled = true; + } + +unlock: + spin_unlock_irqrestore(&meson->lock, flags); + return err; +} + +static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct meson_pwm *meson = to_meson_pwm(chip); + u32 value, mask; + + if (!state) + return; + + switch (pwm->hwpwm) { + case 0: + mask = MISC_A_EN; + break; + + case 1: + mask = MISC_B_EN; + break; + + default: + return; + } + + value = readl(meson->base + REG_MISC_AB); + state->enabled = (value & mask) != 0; +} + +static const struct pwm_ops meson_pwm_ops = { + .request = meson_pwm_request, + .free = meson_pwm_free, + .apply = meson_pwm_apply, + .get_state = meson_pwm_get_state, + .owner = THIS_MODULE, +}; + +static const char * const pwm_meson8b_parent_names[] = { + "xtal", "vid_pll", "fclk_div4", "fclk_div3" +}; + +static const struct meson_pwm_data pwm_meson8b_data = { + .parent_names = pwm_meson8b_parent_names, +}; + +static const char * const pwm_gxbb_parent_names[] = { + "xtal", "hdmi_pll", "fclk_div4", "fclk_div3" +}; + +static const struct meson_pwm_data pwm_gxbb_data = { + .parent_names = pwm_gxbb_parent_names, +}; + +static const struct of_device_id meson_pwm_matches[] = { + { .compatible = "amlogic,meson8b-pwm", .data = &pwm_meson8b_data }, + { .compatible = "amlogic,meson-gxbb-pwm", .data = &pwm_gxbb_data }, + {}, +}; +MODULE_DEVICE_TABLE(of, meson_pwm_matches); + +static int meson_pwm_init_channels(struct meson_pwm *meson, + struct meson_pwm_channel *channels) +{ + struct device *dev = meson->chip.dev; + struct device_node *np = dev->of_node; + struct clk_init_data init; + unsigned int i; + char name[255]; + int err; + + for (i = 0; i < meson->chip.npwm; i++) { + struct meson_pwm_channel *channel = &channels[i]; + + snprintf(name, sizeof(name), "%s#mux%u", np->full_name, i); + + init.name = name; + init.ops = &clk_mux_ops; + init.flags = CLK_IS_BASIC; + init.parent_names = meson->data->parent_names; + init.num_parents = 1 << MISC_CLK_SEL_WIDTH; + + channel->mux.reg = meson->base + REG_MISC_AB; + channel->mux.shift = mux_reg_shifts[i]; + channel->mux.mask = BIT(MISC_CLK_SEL_WIDTH) - 1; + channel->mux.flags = 0; + channel->mux.lock = &meson->lock; + channel->mux.table = NULL; + channel->mux.hw.init = &init; + + channel->clk = devm_clk_register(dev, &channel->mux.hw); + if (IS_ERR(channel->clk)) { + err = PTR_ERR(channel->clk); + dev_err(dev, "failed to register %s: %d\n", name, err); + return err; + } + + snprintf(name, sizeof(name), "clkin%u", i); + + channel->clk_parent = devm_clk_get(dev, name); + if (IS_ERR(channel->clk_parent)) { + err = PTR_ERR(channel->clk_parent); + if (err == -EPROBE_DEFER) + return err; + + channel->clk_parent = NULL; + } + } + + return 0; +} + +static void meson_pwm_add_channels(struct meson_pwm *meson, + struct meson_pwm_channel *channels) +{ + unsigned int i; + + for (i = 0; i < meson->chip.npwm; i++) + pwm_set_chip_data(&meson->chip.pwms[i], &channels[i]); +} + +static int meson_pwm_probe(struct platform_device *pdev) +{ + struct meson_pwm_channel *channels; + struct meson_pwm *meson; + struct resource *regs; + int err; + + meson = devm_kzalloc(&pdev->dev, sizeof(*meson), GFP_KERNEL); + if (!meson) + return -ENOMEM; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + meson->base = devm_ioremap_resource(&pdev->dev, regs); + if (IS_ERR(meson->base)) + return PTR_ERR(meson->base); + + meson->chip.dev = &pdev->dev; + meson->chip.ops = &meson_pwm_ops; + meson->chip.base = -1; + meson->chip.npwm = 2; + meson->chip.of_xlate = of_pwm_xlate_with_flags; + meson->chip.of_pwm_n_cells = 3; + + meson->data = of_device_get_match_data(&pdev->dev); + meson->inverter_mask = BIT(meson->chip.npwm) - 1; + + channels = devm_kcalloc(&pdev->dev, meson->chip.npwm, sizeof(*meson), + GFP_KERNEL); + if (!channels) + return -ENOMEM; + + err = meson_pwm_init_channels(meson, channels); + if (err < 0) + return err; + + err = pwmchip_add(&meson->chip); + if (err < 0) { + dev_err(&pdev->dev, "failed to register PWM chip: %d\n", err); + return err; + } + + meson_pwm_add_channels(meson, channels); + + platform_set_drvdata(pdev, meson); + + return 0; +} + +static int meson_pwm_remove(struct platform_device *pdev) +{ + struct meson_pwm *meson = platform_get_drvdata(pdev); + + return pwmchip_remove(&meson->chip); +} + +static struct platform_driver meson_pwm_driver = { + .driver = { + .name = "meson-pwm", + .of_match_table = meson_pwm_matches, + }, + .probe = meson_pwm_probe, + .remove = meson_pwm_remove, +}; +module_platform_driver(meson_pwm_driver); + +MODULE_ALIAS("platform:meson-pwm"); +MODULE_DESCRIPTION("Amlogic Meson PWM Generator driver"); +MODULE_AUTHOR("Neil Armstrong "); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c index 0ad3385298c0..893940d45f0d 100644 --- a/drivers/pwm/pwm-mtk-disp.c +++ b/drivers/pwm/pwm-mtk-disp.c @@ -18,30 +18,40 @@ #include #include #include +#include #include #include #include #define DISP_PWM_EN 0x00 -#define PWM_ENABLE_MASK BIT(0) -#define DISP_PWM_COMMIT 0x08 -#define PWM_COMMIT_MASK BIT(0) - -#define DISP_PWM_CON_0 0x10 #define PWM_CLKDIV_SHIFT 16 #define PWM_CLKDIV_MAX 0x3ff #define PWM_CLKDIV_MASK (PWM_CLKDIV_MAX << PWM_CLKDIV_SHIFT) -#define DISP_PWM_CON_1 0x14 #define PWM_PERIOD_BIT_WIDTH 12 #define PWM_PERIOD_MASK ((1 << PWM_PERIOD_BIT_WIDTH) - 1) #define PWM_HIGH_WIDTH_SHIFT 16 #define PWM_HIGH_WIDTH_MASK (0x1fff << PWM_HIGH_WIDTH_SHIFT) +struct mtk_pwm_data { + u32 enable_mask; + unsigned int con0; + u32 con0_sel; + unsigned int con1; + + bool has_commit; + unsigned int commit; + unsigned int commit_mask; + + unsigned int bls_debug; + u32 bls_debug_mask; +}; + struct mtk_disp_pwm { struct pwm_chip chip; + const struct mtk_pwm_data *data; struct clk *clk_main; struct clk *clk_mm; void __iomem *base; @@ -106,12 +116,21 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, return err; } - mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_0, PWM_CLKDIV_MASK, + mtk_disp_pwm_update_bits(mdp, mdp->data->con0, + PWM_CLKDIV_MASK, clk_div << PWM_CLKDIV_SHIFT); - mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_1, - PWM_PERIOD_MASK | PWM_HIGH_WIDTH_MASK, value); - mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 1); - mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 0); + mtk_disp_pwm_update_bits(mdp, mdp->data->con1, + PWM_PERIOD_MASK | PWM_HIGH_WIDTH_MASK, + value); + + if (mdp->data->has_commit) { + mtk_disp_pwm_update_bits(mdp, mdp->data->commit, + mdp->data->commit_mask, + mdp->data->commit_mask); + mtk_disp_pwm_update_bits(mdp, mdp->data->commit, + mdp->data->commit_mask, + 0x0); + } clk_disable(mdp->clk_mm); clk_disable(mdp->clk_main); @@ -134,7 +153,8 @@ static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) return err; } - mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 1); + mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask, + mdp->data->enable_mask); return 0; } @@ -143,7 +163,8 @@ static void mtk_disp_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) { struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); - mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 0); + mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask, + 0x0); clk_disable(mdp->clk_mm); clk_disable(mdp->clk_main); @@ -166,6 +187,8 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev) if (!mdp) return -ENOMEM; + mdp->data = of_device_get_match_data(&pdev->dev); + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); mdp->base = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(mdp->base)) @@ -200,6 +223,19 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mdp); + /* + * For MT2701, disable double buffer before writing register + * and select manual mode and use PWM_PERIOD/PWM_HIGH_WIDTH. + */ + if (!mdp->data->has_commit) { + mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug, + mdp->data->bls_debug_mask, + mdp->data->bls_debug_mask); + mtk_disp_pwm_update_bits(mdp, mdp->data->con0, + mdp->data->con0_sel, + mdp->data->con0_sel); + } + return 0; disable_clk_mm: @@ -221,9 +257,30 @@ static int mtk_disp_pwm_remove(struct platform_device *pdev) return ret; } +static const struct mtk_pwm_data mt2701_pwm_data = { + .enable_mask = BIT(16), + .con0 = 0xa8, + .con0_sel = 0x2, + .con1 = 0xac, + .has_commit = false, + .bls_debug = 0xb0, + .bls_debug_mask = 0x3, +}; + +static const struct mtk_pwm_data mt8173_pwm_data = { + .enable_mask = BIT(0), + .con0 = 0x10, + .con0_sel = 0x0, + .con1 = 0x14, + .has_commit = true, + .commit = 0x8, + .commit_mask = 0x1, +}; + static const struct of_device_id mtk_disp_pwm_of_match[] = { - { .compatible = "mediatek,mt8173-disp-pwm" }, - { .compatible = "mediatek,mt6595-disp-pwm" }, + { .compatible = "mediatek,mt2701-disp-pwm", .data = &mt2701_pwm_data}, + { .compatible = "mediatek,mt6595-disp-pwm", .data = &mt8173_pwm_data}, + { .compatible = "mediatek,mt8173-disp-pwm", .data = &mt8173_pwm_data}, { } }; MODULE_DEVICE_TABLE(of, mtk_disp_pwm_of_match); diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c index ada2d326dc3e..f113cda47032 100644 --- a/drivers/pwm/pwm-samsung.c +++ b/drivers/pwm/pwm-samsung.c @@ -193,9 +193,18 @@ static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip *chip, * divider settings and choose the lowest divisor that can generate * frequencies lower than requested. */ - for (div = variant->div_base; div < 4; ++div) - if ((rate >> (variant->bits + div)) < freq) - break; + if (variant->bits < 32) { + /* Only for s3c24xx */ + for (div = variant->div_base; div < 4; ++div) + if ((rate >> (variant->bits + div)) < freq) + break; + } else { + /* + * Other variants have enough counter bits to generate any + * requested rate, so no need to check higher divisors. + */ + div = variant->div_base; + } pwm_samsung_set_divisor(chip, chan, BIT(div)); diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c index 92abbd56b9f7..dd82dc840af9 100644 --- a/drivers/pwm/pwm-sti.c +++ b/drivers/pwm/pwm-sti.c @@ -1,8 +1,10 @@ /* - * PWM device driver for ST SoCs. - * Author: Ajit Pal Singh + * PWM device driver for ST SoCs * - * Copyright (C) 2013-2014 STMicroelectronics (R&D) Limited + * Copyright (C) 2013-2016 STMicroelectronics (R&D) Limited + * + * Author: Ajit Pal Singh + * Lee Jones * * 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 @@ -11,6 +13,7 @@ */ #include +#include #include #include #include @@ -18,43 +21,82 @@ #include #include #include +#include #include #include +#include -#define STI_DS_REG(ch) (4 * (ch)) /* Channel's Duty Cycle register */ -#define STI_PWMCR 0x50 /* Control/Config register */ -#define STI_INTEN 0x54 /* Interrupt Enable/Disable register */ -#define PWM_PRESCALE_LOW_MASK 0x0f -#define PWM_PRESCALE_HIGH_MASK 0xf0 +#define PWM_OUT_VAL(x) (0x00 + (4 * (x))) /* Device's Duty Cycle register */ +#define PWM_CPT_VAL(x) (0x10 + (4 * (x))) /* Capture value */ +#define PWM_CPT_EDGE(x) (0x30 + (4 * (x))) /* Edge to capture on */ + +#define STI_PWM_CTRL 0x50 /* Control/Config register */ +#define STI_INT_EN 0x54 /* Interrupt Enable/Disable register */ +#define STI_INT_STA 0x58 /* Interrupt Status register */ +#define PWM_INT_ACK 0x5c +#define PWM_PRESCALE_LOW_MASK 0x0f +#define PWM_PRESCALE_HIGH_MASK 0xf0 +#define PWM_CPT_EDGE_MASK 0x03 +#define PWM_INT_ACK_MASK 0x1ff + +#define STI_MAX_CPT_DEVS 4 +#define CPT_DC_MAX 0xff /* Regfield IDs */ enum { + /* Bits in PWM_CTRL*/ PWMCLK_PRESCALE_LOW, PWMCLK_PRESCALE_HIGH, - PWM_EN, - PWM_INT_EN, + CPTCLK_PRESCALE, + + PWM_OUT_EN, + PWM_CPT_EN, + + PWM_CPT_INT_EN, + PWM_CPT_INT_STAT, /* Keep last */ MAX_REGFIELDS }; +/* + * Each capture input can be programmed to detect rising-edge, falling-edge, + * either edge or neither egde. + */ +enum sti_cpt_edge { + CPT_EDGE_DISABLED, + CPT_EDGE_RISING, + CPT_EDGE_FALLING, + CPT_EDGE_BOTH, +}; + +struct sti_cpt_ddata { + u32 snapshot[3]; + unsigned int index; + struct mutex lock; + wait_queue_head_t wait; +}; + struct sti_pwm_compat_data { const struct reg_field *reg_fields; - unsigned int num_chan; + unsigned int pwm_num_devs; + unsigned int cpt_num_devs; unsigned int max_pwm_cnt; unsigned int max_prescale; }; struct sti_pwm_chip { struct device *dev; - struct clk *clk; - unsigned long clk_rate; + struct clk *pwm_clk; + struct clk *cpt_clk; struct regmap *regmap; struct sti_pwm_compat_data *cdata; struct regmap_field *prescale_low; struct regmap_field *prescale_high; - struct regmap_field *pwm_en; - struct regmap_field *pwm_int_en; + struct regmap_field *pwm_out_en; + struct regmap_field *pwm_cpt_en; + struct regmap_field *pwm_cpt_int_en; + struct regmap_field *pwm_cpt_int_stat; struct pwm_chip chip; struct pwm_device *cur; unsigned long configured; @@ -64,10 +106,13 @@ struct sti_pwm_chip { }; static const struct reg_field sti_pwm_regfields[MAX_REGFIELDS] = { - [PWMCLK_PRESCALE_LOW] = REG_FIELD(STI_PWMCR, 0, 3), - [PWMCLK_PRESCALE_HIGH] = REG_FIELD(STI_PWMCR, 11, 14), - [PWM_EN] = REG_FIELD(STI_PWMCR, 9, 9), - [PWM_INT_EN] = REG_FIELD(STI_INTEN, 0, 0), + [PWMCLK_PRESCALE_LOW] = REG_FIELD(STI_PWM_CTRL, 0, 3), + [PWMCLK_PRESCALE_HIGH] = REG_FIELD(STI_PWM_CTRL, 11, 14), + [CPTCLK_PRESCALE] = REG_FIELD(STI_PWM_CTRL, 4, 8), + [PWM_OUT_EN] = REG_FIELD(STI_PWM_CTRL, 9, 9), + [PWM_CPT_EN] = REG_FIELD(STI_PWM_CTRL, 10, 10), + [PWM_CPT_INT_EN] = REG_FIELD(STI_INT_EN, 1, 4), + [PWM_CPT_INT_STAT] = REG_FIELD(STI_INT_STA, 1, 4), }; static inline struct sti_pwm_chip *to_sti_pwmchip(struct pwm_chip *chip) @@ -82,61 +127,68 @@ static int sti_pwm_get_prescale(struct sti_pwm_chip *pc, unsigned long period, unsigned int *prescale) { struct sti_pwm_compat_data *cdata = pc->cdata; - unsigned long val; + unsigned long clk_rate; + unsigned long value; unsigned int ps; - /* - * prescale = ((period_ns * clk_rate) / (10^9 * (max_pwm_count + 1)) - 1 - */ - val = NSEC_PER_SEC / pc->clk_rate; - val *= cdata->max_pwm_cnt + 1; - - if (period % val) { + clk_rate = clk_get_rate(pc->pwm_clk); + if (!clk_rate) { + dev_err(pc->dev, "failed to get clock rate\n"); return -EINVAL; - } else { - ps = period / val - 1; - if (ps > cdata->max_prescale) - return -EINVAL; } + + /* + * prescale = ((period_ns * clk_rate) / (10^9 * (max_pwm_cnt + 1)) - 1 + */ + value = NSEC_PER_SEC / clk_rate; + value *= cdata->max_pwm_cnt + 1; + + if (period % value) + return -EINVAL; + + ps = period / value - 1; + if (ps > cdata->max_prescale) + return -EINVAL; + *prescale = ps; return 0; } /* - * For STiH4xx PWM IP, the PWM period is fixed to 256 local clock cycles. - * The only way to change the period (apart from changing the PWM input clock) - * is to change the PWM clock prescaler. - * The prescaler is of 8 bits, so 256 prescaler values and hence - * 256 possible period values are supported (for a particular clock rate). - * The requested period will be applied only if it matches one of these - * 256 values. + * For STiH4xx PWM IP, the PWM period is fixed to 256 local clock cycles. The + * only way to change the period (apart from changing the PWM input clock) is + * to change the PWM clock prescaler. + * + * The prescaler is of 8 bits, so 256 prescaler values and hence 256 possible + * period values are supported (for a particular clock rate). The requested + * period will be applied only if it matches one of these 256 values. */ static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, - int duty_ns, int period_ns) + int duty_ns, int period_ns) { struct sti_pwm_chip *pc = to_sti_pwmchip(chip); struct sti_pwm_compat_data *cdata = pc->cdata; + unsigned int ncfg, value, prescale = 0; struct pwm_device *cur = pc->cur; struct device *dev = pc->dev; - unsigned int prescale = 0, pwmvalx; - int ret; - unsigned int ncfg; bool period_same = false; + int ret; ncfg = hweight_long(pc->configured); if (ncfg) period_same = (period_ns == pwm_get_period(cur)); - /* Allow configuration changes if one of the - * following conditions satisfy. - * 1. No channels have been configured. - * 2. Only one channel has been configured and the new request - * is for the same channel. - * 3. Only one channel has been configured and the new request is - * for a new channel and period of the new channel is same as - * the current configured period. - * 4. More than one channels are configured and period of the new + /* + * Allow configuration changes if one of the following conditions + * satisfy. + * 1. No devices have been configured. + * 2. Only one device has been configured and the new request is for + * the same device. + * 3. Only one device has been configured and the new request is for + * a new device and period of the new device is same as the current + * configured period. + * 4. More than one devices are configured and period of the new * requestis the same as the current period. */ if (!ncfg || @@ -144,7 +196,11 @@ static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ((ncfg == 1) && (pwm->hwpwm != cur->hwpwm) && period_same) || ((ncfg > 1) && period_same)) { /* Enable clock before writing to PWM registers. */ - ret = clk_enable(pc->clk); + ret = clk_enable(pc->pwm_clk); + if (ret) + return ret; + + ret = clk_enable(pc->cpt_clk); if (ret) return ret; @@ -153,15 +209,15 @@ static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, if (ret) goto clk_dis; - ret = - regmap_field_write(pc->prescale_low, - prescale & PWM_PRESCALE_LOW_MASK); + value = prescale & PWM_PRESCALE_LOW_MASK; + + ret = regmap_field_write(pc->prescale_low, value); if (ret) goto clk_dis; - ret = - regmap_field_write(pc->prescale_high, - (prescale & PWM_PRESCALE_HIGH_MASK) >> 4); + value = (prescale & PWM_PRESCALE_HIGH_MASK) >> 4; + + ret = regmap_field_write(pc->prescale_high, value); if (ret) goto clk_dis; } @@ -172,25 +228,26 @@ static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * PWM pulse = (max_pwm_count + 1) local cycles, * that is continuous pulse: signal never goes low. */ - pwmvalx = cdata->max_pwm_cnt * duty_ns / period_ns; + value = cdata->max_pwm_cnt * duty_ns / period_ns; - ret = regmap_write(pc->regmap, STI_DS_REG(pwm->hwpwm), pwmvalx); + ret = regmap_write(pc->regmap, PWM_OUT_VAL(pwm->hwpwm), value); if (ret) goto clk_dis; - ret = regmap_field_write(pc->pwm_int_en, 0); + ret = regmap_field_write(pc->pwm_cpt_int_en, 0); set_bit(pwm->hwpwm, &pc->configured); pc->cur = pwm; - dev_dbg(dev, "prescale:%u, period:%i, duty:%i, pwmvalx:%u\n", - prescale, period_ns, duty_ns, pwmvalx); + dev_dbg(dev, "prescale:%u, period:%i, duty:%i, value:%u\n", + prescale, period_ns, duty_ns, value); } else { return -EINVAL; } clk_dis: - clk_disable(pc->clk); + clk_disable(pc->pwm_clk); + clk_disable(pc->cpt_clk); return ret; } @@ -201,23 +258,30 @@ static int sti_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) int ret = 0; /* - * Since we have a common enable for all PWM channels, - * do not enable if already enabled. + * Since we have a common enable for all PWM devices, do not enable if + * already enabled. */ mutex_lock(&pc->sti_pwm_lock); + if (!pc->en_count) { - ret = clk_enable(pc->clk); + ret = clk_enable(pc->pwm_clk); if (ret) goto out; - ret = regmap_field_write(pc->pwm_en, 1); + ret = clk_enable(pc->cpt_clk); + if (ret) + goto out; + + ret = regmap_field_write(pc->pwm_out_en, 1); if (ret) { - dev_err(dev, "failed to enable PWM device:%d\n", - pwm->hwpwm); + dev_err(dev, "failed to enable PWM device %u: %d\n", + pwm->hwpwm, ret); goto out; } } + pc->en_count++; + out: mutex_unlock(&pc->sti_pwm_lock); return ret; @@ -228,13 +292,17 @@ static void sti_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) struct sti_pwm_chip *pc = to_sti_pwmchip(chip); mutex_lock(&pc->sti_pwm_lock); + if (--pc->en_count) { mutex_unlock(&pc->sti_pwm_lock); return; } - regmap_field_write(pc->pwm_en, 0); - clk_disable(pc->clk); + regmap_field_write(pc->pwm_out_en, 0); + + clk_disable(pc->pwm_clk); + clk_disable(pc->cpt_clk); + mutex_unlock(&pc->sti_pwm_lock); } @@ -245,7 +313,90 @@ static void sti_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) clear_bit(pwm->hwpwm, &pc->configured); } +static int sti_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_capture *result, unsigned long timeout) +{ + struct sti_pwm_chip *pc = to_sti_pwmchip(chip); + struct sti_pwm_compat_data *cdata = pc->cdata; + struct sti_cpt_ddata *ddata = pwm_get_chip_data(pwm); + struct device *dev = pc->dev; + unsigned int effective_ticks; + unsigned long long high, low; + int ret; + + if (pwm->hwpwm >= cdata->cpt_num_devs) { + dev_err(dev, "device %u is not valid\n", pwm->hwpwm); + return -EINVAL; + } + + mutex_lock(&ddata->lock); + ddata->index = 0; + + /* Prepare capture measurement */ + regmap_write(pc->regmap, PWM_CPT_EDGE(pwm->hwpwm), CPT_EDGE_RISING); + regmap_field_write(pc->pwm_cpt_int_en, BIT(pwm->hwpwm)); + + /* Enable capture */ + ret = regmap_field_write(pc->pwm_cpt_en, 1); + if (ret) { + dev_err(dev, "failed to enable PWM capture %u: %d\n", + pwm->hwpwm, ret); + goto out; + } + + ret = wait_event_interruptible_timeout(ddata->wait, ddata->index > 1, + msecs_to_jiffies(timeout)); + + regmap_write(pc->regmap, PWM_CPT_EDGE(pwm->hwpwm), CPT_EDGE_DISABLED); + + if (ret == -ERESTARTSYS) + goto out; + + switch (ddata->index) { + case 0: + case 1: + /* + * Getting here could mean: + * - input signal is constant of less than 1 Hz + * - there is no input signal at all + * + * In such case the frequency is rounded down to 0 + */ + result->period = 0; + result->duty_cycle = 0; + + break; + + case 2: + /* We have everying we need */ + high = ddata->snapshot[1] - ddata->snapshot[0]; + low = ddata->snapshot[2] - ddata->snapshot[1]; + + effective_ticks = clk_get_rate(pc->cpt_clk); + + result->period = (high + low) * NSEC_PER_SEC; + result->period /= effective_ticks; + + result->duty_cycle = high * NSEC_PER_SEC; + result->duty_cycle /= effective_ticks; + + break; + + default: + dev_err(dev, "internal error\n"); + break; + } + +out: + /* Disable capture */ + regmap_field_write(pc->pwm_cpt_en, 0); + + mutex_unlock(&ddata->lock); + return ret; +} + static const struct pwm_ops sti_pwm_ops = { + .capture = sti_pwm_capture, .config = sti_pwm_config, .enable = sti_pwm_enable, .disable = sti_pwm_disable, @@ -253,17 +404,98 @@ static const struct pwm_ops sti_pwm_ops = { .owner = THIS_MODULE, }; +static irqreturn_t sti_pwm_interrupt(int irq, void *data) +{ + struct sti_pwm_chip *pc = data; + struct device *dev = pc->dev; + struct sti_cpt_ddata *ddata; + int devicenum; + unsigned int cpt_int_stat; + unsigned int reg; + int ret = IRQ_NONE; + + ret = regmap_field_read(pc->pwm_cpt_int_stat, &cpt_int_stat); + if (ret) + return ret; + + while (cpt_int_stat) { + devicenum = ffs(cpt_int_stat) - 1; + + ddata = pwm_get_chip_data(&pc->chip.pwms[devicenum]); + + /* + * Capture input: + * _______ _______ + * | | | | + * __| |_________________| |________ + * ^0 ^1 ^2 + * + * Capture start by the first available rising edge. When a + * capture event occurs, capture value (CPT_VALx) is stored, + * index incremented, capture edge changed. + * + * After the capture, if the index > 1, we have collected the + * necessary data so we signal the thread waiting for it and + * disable the capture by setting capture edge to none + */ + + regmap_read(pc->regmap, + PWM_CPT_VAL(devicenum), + &ddata->snapshot[ddata->index]); + + switch (ddata->index) { + case 0: + case 1: + regmap_read(pc->regmap, PWM_CPT_EDGE(devicenum), ®); + reg ^= PWM_CPT_EDGE_MASK; + regmap_write(pc->regmap, PWM_CPT_EDGE(devicenum), reg); + + ddata->index++; + break; + + case 2: + regmap_write(pc->regmap, + PWM_CPT_EDGE(devicenum), + CPT_EDGE_DISABLED); + wake_up(&ddata->wait); + break; + + default: + dev_err(dev, "Internal error\n"); + } + + cpt_int_stat &= ~BIT_MASK(devicenum); + + ret = IRQ_HANDLED; + } + + /* Just ACK everything */ + regmap_write(pc->regmap, PWM_INT_ACK, PWM_INT_ACK_MASK); + + return ret; +} + static int sti_pwm_probe_dt(struct sti_pwm_chip *pc) { struct device *dev = pc->dev; const struct reg_field *reg_fields; struct device_node *np = dev->of_node; struct sti_pwm_compat_data *cdata = pc->cdata; - u32 num_chan; + u32 num_devs; + int ret; - of_property_read_u32(np, "st,pwm-num-chan", &num_chan); - if (num_chan) - cdata->num_chan = num_chan; + ret = of_property_read_u32(np, "st,pwm-num-chan", &num_devs); + if (!ret) + cdata->pwm_num_devs = num_devs; + + ret = of_property_read_u32(np, "st,capture-num-chan", &num_devs); + if (!ret) + cdata->cpt_num_devs = num_devs; + + if (!cdata->pwm_num_devs && !cdata->cpt_num_devs) { + dev_err(dev, "No channels configured\n"); + return -EINVAL; + } reg_fields = cdata->reg_fields; @@ -277,15 +509,26 @@ static int sti_pwm_probe_dt(struct sti_pwm_chip *pc) if (IS_ERR(pc->prescale_high)) return PTR_ERR(pc->prescale_high); - pc->pwm_en = devm_regmap_field_alloc(dev, pc->regmap, - reg_fields[PWM_EN]); - if (IS_ERR(pc->pwm_en)) - return PTR_ERR(pc->pwm_en); - pc->pwm_int_en = devm_regmap_field_alloc(dev, pc->regmap, - reg_fields[PWM_INT_EN]); - if (IS_ERR(pc->pwm_int_en)) - return PTR_ERR(pc->pwm_int_en); + pc->pwm_out_en = devm_regmap_field_alloc(dev, pc->regmap, + reg_fields[PWM_OUT_EN]); + if (IS_ERR(pc->pwm_out_en)) + return PTR_ERR(pc->pwm_out_en); + + pc->pwm_cpt_en = devm_regmap_field_alloc(dev, pc->regmap, + reg_fields[PWM_CPT_EN]); + if (IS_ERR(pc->pwm_cpt_en)) + return PTR_ERR(pc->pwm_cpt_en); + + pc->pwm_cpt_int_en = devm_regmap_field_alloc(dev, pc->regmap, + reg_fields[PWM_CPT_INT_EN]); + if (IS_ERR(pc->pwm_cpt_int_en)) + return PTR_ERR(pc->pwm_cpt_int_en); + + pc->pwm_cpt_int_stat = devm_regmap_field_alloc(dev, pc->regmap, + reg_fields[PWM_CPT_INT_STAT]); + if (PTR_ERR_OR_ZERO(pc->pwm_cpt_int_stat)) + return PTR_ERR(pc->pwm_cpt_int_stat); return 0; } @@ -302,7 +545,8 @@ static int sti_pwm_probe(struct platform_device *pdev) struct sti_pwm_compat_data *cdata; struct sti_pwm_chip *pc; struct resource *res; - int ret; + unsigned int i; + int irq, ret; pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL); if (!pc) @@ -323,14 +567,28 @@ static int sti_pwm_probe(struct platform_device *pdev) if (IS_ERR(pc->regmap)) return PTR_ERR(pc->regmap); + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "Failed to obtain IRQ\n"); + return irq; + } + + ret = devm_request_irq(&pdev->dev, irq, sti_pwm_interrupt, 0, + pdev->name, pc); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request IRQ\n"); + return ret; + } + /* * Setup PWM data with default values: some values could be replaced * with specific ones provided from Device Tree. */ - cdata->reg_fields = &sti_pwm_regfields[0]; + cdata->reg_fields = sti_pwm_regfields; cdata->max_prescale = 0xff; - cdata->max_pwm_cnt = 255; - cdata->num_chan = 1; + cdata->max_pwm_cnt = 255; + cdata->pwm_num_devs = 0; + cdata->cpt_num_devs = 0; pc->cdata = cdata; pc->dev = dev; @@ -341,36 +599,64 @@ static int sti_pwm_probe(struct platform_device *pdev) if (ret) return ret; - pc->clk = of_clk_get_by_name(dev->of_node, "pwm"); - if (IS_ERR(pc->clk)) { + if (!cdata->pwm_num_devs) + goto skip_pwm; + + pc->pwm_clk = of_clk_get_by_name(dev->of_node, "pwm"); + if (IS_ERR(pc->pwm_clk)) { dev_err(dev, "failed to get PWM clock\n"); - return PTR_ERR(pc->clk); + return PTR_ERR(pc->pwm_clk); } - pc->clk_rate = clk_get_rate(pc->clk); - if (!pc->clk_rate) { - dev_err(dev, "failed to get clock rate\n"); - return -EINVAL; - } - - ret = clk_prepare(pc->clk); + ret = clk_prepare(pc->pwm_clk); if (ret) { dev_err(dev, "failed to prepare clock\n"); return ret; } +skip_pwm: + if (!cdata->cpt_num_devs) + goto skip_cpt; + + pc->cpt_clk = of_clk_get_by_name(dev->of_node, "capture"); + if (IS_ERR(pc->cpt_clk)) { + dev_err(dev, "failed to get PWM capture clock\n"); + return PTR_ERR(pc->cpt_clk); + } + + ret = clk_prepare(pc->cpt_clk); + if (ret) { + dev_err(dev, "failed to prepare clock\n"); + return ret; + } + +skip_cpt: pc->chip.dev = dev; pc->chip.ops = &sti_pwm_ops; pc->chip.base = -1; - pc->chip.npwm = pc->cdata->num_chan; + pc->chip.npwm = pc->cdata->pwm_num_devs; pc->chip.can_sleep = true; ret = pwmchip_add(&pc->chip); if (ret < 0) { - clk_unprepare(pc->clk); + clk_unprepare(pc->pwm_clk); + clk_unprepare(pc->cpt_clk); return ret; } + for (i = 0; i < cdata->cpt_num_devs; i++) { + struct sti_cpt_ddata *ddata; + + ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); + if (!ddata) + return -ENOMEM; + + init_waitqueue_head(&ddata->wait); + mutex_init(&ddata->lock); + + pwm_set_chip_data(&pc->chip.pwms[i], ddata); + } + platform_set_drvdata(pdev, pc); return 0; @@ -381,10 +667,11 @@ static int sti_pwm_remove(struct platform_device *pdev) struct sti_pwm_chip *pc = platform_get_drvdata(pdev); unsigned int i; - for (i = 0; i < pc->cdata->num_chan; i++) + for (i = 0; i < pc->cdata->pwm_num_devs; i++) pwm_disable(&pc->chip.pwms[i]); - clk_unprepare(pc->clk); + clk_unprepare(pc->pwm_clk); + clk_unprepare(pc->cpt_clk); return pwmchip_remove(&pc->chip); } diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index 03a99a53c39e..b0803f6c64d9 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -284,6 +284,12 @@ static const struct sun4i_pwm_data sun4i_pwm_data_a20 = { .npwm = 2, }; +static const struct sun4i_pwm_data sun4i_pwm_data_h3 = { + .has_prescaler_bypass = true, + .has_rdy = true, + .npwm = 1, +}; + static const struct of_device_id sun4i_pwm_dt_ids[] = { { .compatible = "allwinner,sun4i-a10-pwm", @@ -297,6 +303,9 @@ static const struct of_device_id sun4i_pwm_dt_ids[] = { }, { .compatible = "allwinner,sun7i-a20-pwm", .data = &sun4i_pwm_data_a20, + }, { + .compatible = "allwinner,sun8i-h3-pwm", + .data = &sun4i_pwm_data_h3, }, { /* sentinel */ }, diff --git a/drivers/pwm/pwm-tipwmss.c b/drivers/pwm/pwm-tipwmss.c index 829f4991c96f..7fa85a1604da 100644 --- a/drivers/pwm/pwm-tipwmss.c +++ b/drivers/pwm/pwm-tipwmss.c @@ -34,7 +34,6 @@ static int pwmss_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; pm_runtime_enable(&pdev->dev); - pm_runtime_get_sync(&pdev->dev); /* Populate all the child nodes here... */ ret = of_platform_populate(node, NULL, NULL, &pdev->dev); @@ -46,31 +45,13 @@ static int pwmss_probe(struct platform_device *pdev) static int pwmss_remove(struct platform_device *pdev) { - pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; } -#ifdef CONFIG_PM_SLEEP -static int pwmss_suspend(struct device *dev) -{ - pm_runtime_put_sync(dev); - return 0; -} - -static int pwmss_resume(struct device *dev) -{ - pm_runtime_get_sync(dev); - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(pwmss_pm_ops, pwmss_suspend, pwmss_resume); - static struct platform_driver pwmss_driver = { .driver = { .name = "pwmss", - .pm = &pwmss_pm_ops, .of_match_table = pwmss_of_match, }, .probe = pwmss_probe, diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c index 04f76725d591..7a993b056638 100644 --- a/drivers/pwm/pwm-twl.c +++ b/drivers/pwm/pwm-twl.c @@ -269,6 +269,22 @@ static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) goto out; } + val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXEN); + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label); + goto out; + } + + val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXEN); + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label); + goto out; + } + twl->twl6030_toggle3 = val; out: mutex_unlock(&twl->mutex); diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index 18ed725594c3..0296d8178ae2 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -409,6 +409,24 @@ void pwmchip_sysfs_unexport(struct pwm_chip *chip) } } +void pwmchip_sysfs_unexport_children(struct pwm_chip *chip) +{ + struct device *parent; + unsigned int i; + + parent = class_find_device(&pwm_class, NULL, chip, + pwmchip_sysfs_match); + if (!parent) + return; + + for (i = 0; i < chip->npwm; i++) { + struct pwm_device *pwm = &chip->pwms[i]; + + if (test_bit(PWMF_EXPORTED, &pwm->flags)) + pwm_unexport_child(parent, pwm); + } +} + static int __init pwm_sysfs_init(void) { return class_register(&pwm_class); diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 3958f50c5975..e0c747aa9f85 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -495,7 +495,8 @@ static irqreturn_t max8973_thermal_irq(int irq, void *data) { struct max8973_chip *mchip = data; - thermal_zone_device_update(mchip->tz_device); + thermal_zone_device_update(mchip->tz_device, + THERMAL_EVENT_UNSPECIFIED); return IRQ_HANDLED; } diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 2d702ca6556f..a13541bdc726 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -186,7 +186,7 @@ config HISI_THERMAL config IMX_THERMAL tristate "Temperature sensor driver for Freescale i.MX SoCs" - depends on CPU_THERMAL + depends on (ARCH_MXC && CPU_THERMAL) || COMPILE_TEST depends on MFD_SYSCON depends on OF help @@ -195,6 +195,26 @@ config IMX_THERMAL cpufreq is used as the cooling device to throttle CPUs when the passive trip is crossed. +config MAX77620_THERMAL + tristate "Temperature sensor driver for Maxim MAX77620 PMIC" + depends on MFD_MAX77620 + depends on OF + help + Support for die junction temperature warning alarm for Maxim + Semiconductor PMIC MAX77620 device. Device generates two alarm + interrupts when PMIC die temperature cross the threshold of + 120 degC and 140 degC. + +config QORIQ_THERMAL + tristate "QorIQ Thermal Monitoring Unit" + depends on THERMAL_OF + depends on HAS_IOMEM + help + Support for Thermal Monitoring Unit (TMU) found on QorIQ platforms. + It supports one critical trip point and one passive trip point. The + cpufreq is used as the cooling device to throttle CPUs when the + passive trip is crossed. + config SPEAR_THERMAL tristate "SPEAr thermal sensor driver" depends on PLAT_SPEAR || COMPILE_TEST @@ -332,6 +352,16 @@ menu "ACPI INT340X thermal drivers" source drivers/thermal/int340x_thermal/Kconfig endmenu +config INTEL_BXT_PMIC_THERMAL + tristate "Intel Broxton PMIC thermal driver" + depends on X86 && INTEL_SOC_PMIC && REGMAP + help + Select this driver for Intel Broxton PMIC with ADC channels monitoring + system temperature measurements and alerts. + This driver is used for monitoring the ADC channels of PMIC and handles + the alert trip point interrupts and notifies the thermal framework with + the trip point and temperature details of the zone. + config INTEL_PCH_THERMAL tristate "Intel PCH Thermal Reporting Driver" depends on X86 && PCI @@ -399,4 +429,9 @@ config GENERIC_ADC_THERMAL to this driver. This driver reports the temperature by reading ADC channel and converts it to temperature based on lookup table. +menu "Qualcomm thermal drivers" +depends on (ARCH_QCOM && OF) || COMPILE_TEST +source "drivers/thermal/qcom/Kconfig" +endmenu + endif diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 10b07c14f8a9..c92eb22a41ff 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -37,6 +37,8 @@ obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o +obj-$(CONFIG_MAX77620_THERMAL) += max77620_thermal.o +obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o @@ -45,8 +47,10 @@ obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o obj-$(CONFIG_INTEL_QUARK_DTS_THERMAL) += intel_quark_dts_thermal.o obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/ +obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o obj-$(CONFIG_ST_THERMAL) += st/ +obj-$(CONFIG_QCOM_TSENS) += qcom/ obj-$(CONFIG_TEGRA_SOCTHERM) += tegra/ obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index a32b41783b77..9ce0e9eef923 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -74,7 +74,7 @@ struct power_table { * cpufreq frequencies. * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device. * @node: list_head to link all cpufreq_cooling_device together. - * @last_load: load measured by the latest call to cpufreq_get_actual_power() + * @last_load: load measured by the latest call to cpufreq_get_requested_power() * @time_in_idle: previous reading of the absolute time that this cpu was idle * @time_in_idle_timestamp: wall time of the last invocation of * get_cpu_idle_time_us() diff --git a/drivers/thermal/db8500_thermal.c b/drivers/thermal/db8500_thermal.c index 652acd8fbe48..e776cea80cfc 100644 --- a/drivers/thermal/db8500_thermal.c +++ b/drivers/thermal/db8500_thermal.c @@ -306,7 +306,7 @@ static void db8500_thermal_work(struct work_struct *work) if (cur_mode == THERMAL_DEVICE_DISABLED) return; - thermal_zone_device_update(pzone->therm_dev); + thermal_zone_device_update(pzone->therm_dev, THERMAL_EVENT_UNSPECIFIED); dev_dbg(&pzone->therm_dev->device, "thermal work finished.\n"); } diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c index 01f0015f80dc..81631b110e17 100644 --- a/drivers/thermal/devfreq_cooling.c +++ b/drivers/thermal/devfreq_cooling.c @@ -312,7 +312,7 @@ static int devfreq_cooling_state2power(struct thermal_cooling_device *cdev, unsigned long freq; u32 static_power; - if (state < 0 || state >= dfc->freq_table_size) + if (state >= dfc->freq_table_size) return -EINVAL; freq = dfc->freq_table[state]; diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c index bb118a152cbb..fc5e5057f0de 100644 --- a/drivers/thermal/gov_bang_bang.c +++ b/drivers/thermal/gov_bang_bang.c @@ -65,7 +65,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) if (instance->target == 0 && tz->temperature >= trip_temp) instance->target = 1; else if (instance->target == 1 && - tz->temperature < trip_temp - trip_hyst) + tz->temperature <= trip_temp - trip_hyst) instance->target = 0; dev_dbg(&instance->cdev->device, "target=%d\n", diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index 97fad8f51e1c..f6429666a1cf 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -237,7 +237,8 @@ static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev) if (!data->sensors[i].tzd) continue; - thermal_zone_device_update(data->sensors[i].tzd); + thermal_zone_device_update(data->sensors[i].tzd, + THERMAL_EVENT_UNSPECIFIED); } return IRQ_HANDLED; diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index e473548b5d28..06912f0602b7 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -246,7 +246,7 @@ static int imx_set_mode(struct thermal_zone_device *tz, } data->mode = mode; - thermal_zone_device_update(tz); + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); return 0; } @@ -457,7 +457,7 @@ static irqreturn_t imx_thermal_alarm_irq_thread(int irq, void *dev) dev_dbg(&data->tz->device, "THERMAL ALARM: T > %d\n", data->alarm_temp / 1000); - thermal_zone_device_update(data->tz); + thermal_zone_device_update(data->tz, THERMAL_EVENT_UNSPECIFIED); return IRQ_HANDLED; } diff --git a/drivers/thermal/int340x_thermal/int3402_thermal.c b/drivers/thermal/int340x_thermal/int3402_thermal.c index 69df3d960303..8e90b3151a42 100644 --- a/drivers/thermal/int340x_thermal/int3402_thermal.c +++ b/drivers/thermal/int340x_thermal/int3402_thermal.c @@ -35,7 +35,8 @@ static void int3402_notify(acpi_handle handle, u32 event, void *data) case INT3402_PERF_CHANGED_EVENT: break; case INT3402_THERMAL_EVENT: - int340x_thermal_zone_device_update(priv->int340x_zone); + int340x_thermal_zone_device_update(priv->int340x_zone, + THERMAL_TRIP_VIOLATED); break; default: break; diff --git a/drivers/thermal/int340x_thermal/int3403_thermal.c b/drivers/thermal/int340x_thermal/int3403_thermal.c index 50a7a08e3a15..c4890c9437eb 100644 --- a/drivers/thermal/int340x_thermal/int3403_thermal.c +++ b/drivers/thermal/int340x_thermal/int3403_thermal.c @@ -25,6 +25,7 @@ #define INT3403_TYPE_CHARGER 0x0B #define INT3403_TYPE_BATTERY 0x0C #define INT3403_PERF_CHANGED_EVENT 0x80 +#define INT3403_PERF_TRIP_POINT_CHANGED 0x81 #define INT3403_THERMAL_EVENT 0x90 /* Preserved structure for future expandbility */ @@ -72,7 +73,13 @@ static void int3403_notify(acpi_handle handle, case INT3403_PERF_CHANGED_EVENT: break; case INT3403_THERMAL_EVENT: - int340x_thermal_zone_device_update(obj->int340x_zone); + int340x_thermal_zone_device_update(obj->int340x_zone, + THERMAL_TRIP_VIOLATED); + break; + case INT3403_PERF_TRIP_POINT_CHANGED: + int340x_thermal_read_trips(obj->int340x_zone); + int340x_thermal_zone_device_update(obj->int340x_zone, + THERMAL_TRIP_CHANGED); break; default: dev_err(&priv->pdev->dev, "Unsupported event [0x%x]\n", event); diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c index b9b2666aa94c..145a5c53ff5c 100644 --- a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c +++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c @@ -177,6 +177,42 @@ static int int340x_thermal_get_trip_config(acpi_handle handle, char *name, return 0; } +int int340x_thermal_read_trips(struct int34x_thermal_zone *int34x_zone) +{ + int trip_cnt = int34x_zone->aux_trip_nr; + int i; + + int34x_zone->crt_trip_id = -1; + if (!int340x_thermal_get_trip_config(int34x_zone->adev->handle, "_CRT", + &int34x_zone->crt_temp)) + int34x_zone->crt_trip_id = trip_cnt++; + + int34x_zone->hot_trip_id = -1; + if (!int340x_thermal_get_trip_config(int34x_zone->adev->handle, "_HOT", + &int34x_zone->hot_temp)) + int34x_zone->hot_trip_id = trip_cnt++; + + int34x_zone->psv_trip_id = -1; + if (!int340x_thermal_get_trip_config(int34x_zone->adev->handle, "_PSV", + &int34x_zone->psv_temp)) + int34x_zone->psv_trip_id = trip_cnt++; + + for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { + char name[5] = { '_', 'A', 'C', '0' + i, '\0' }; + + if (int340x_thermal_get_trip_config(int34x_zone->adev->handle, + name, + &int34x_zone->act_trips[i].temp)) + break; + + int34x_zone->act_trips[i].id = trip_cnt++; + int34x_zone->act_trips[i].valid = true; + } + + return trip_cnt; +} +EXPORT_SYMBOL_GPL(int340x_thermal_read_trips); + static struct thermal_zone_params int340x_thermal_params = { .governor_name = "user_space", .no_hwmon = true, @@ -188,7 +224,7 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev, struct int34x_thermal_zone *int34x_thermal_zone; acpi_status status; unsigned long long trip_cnt; - int trip_mask = 0, i; + int trip_mask = 0; int ret; int34x_thermal_zone = kzalloc(sizeof(*int34x_thermal_zone), @@ -214,28 +250,8 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev, int34x_thermal_zone->aux_trip_nr = trip_cnt; } - int34x_thermal_zone->crt_trip_id = -1; - if (!int340x_thermal_get_trip_config(adev->handle, "_CRT", - &int34x_thermal_zone->crt_temp)) - int34x_thermal_zone->crt_trip_id = trip_cnt++; - int34x_thermal_zone->hot_trip_id = -1; - if (!int340x_thermal_get_trip_config(adev->handle, "_HOT", - &int34x_thermal_zone->hot_temp)) - int34x_thermal_zone->hot_trip_id = trip_cnt++; - int34x_thermal_zone->psv_trip_id = -1; - if (!int340x_thermal_get_trip_config(adev->handle, "_PSV", - &int34x_thermal_zone->psv_temp)) - int34x_thermal_zone->psv_trip_id = trip_cnt++; - for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { - char name[5] = { '_', 'A', 'C', '0' + i, '\0' }; + trip_cnt = int340x_thermal_read_trips(int34x_thermal_zone); - if (int340x_thermal_get_trip_config(adev->handle, name, - &int34x_thermal_zone->act_trips[i].temp)) - break; - - int34x_thermal_zone->act_trips[i].id = trip_cnt++; - int34x_thermal_zone->act_trips[i].valid = true; - } int34x_thermal_zone->lpat_table = acpi_lpat_get_conversion_table( adev->handle); diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h index aaadf724ff2e..5f3ba4775c5c 100644 --- a/drivers/thermal/int340x_thermal/int340x_thermal_zone.h +++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h @@ -46,6 +46,7 @@ struct int34x_thermal_zone { struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *, struct thermal_zone_device_ops *override_ops); void int340x_thermal_zone_remove(struct int34x_thermal_zone *); +int int340x_thermal_read_trips(struct int34x_thermal_zone *int34x_zone); static inline void int340x_thermal_zone_set_priv_data( struct int34x_thermal_zone *tzone, void *priv_data) @@ -60,9 +61,10 @@ static inline void *int340x_thermal_zone_get_priv_data( } static inline void int340x_thermal_zone_device_update( - struct int34x_thermal_zone *tzone) + struct int34x_thermal_zone *tzone, + enum thermal_notify_event event) { - thermal_zone_device_update(tzone->zone); + thermal_zone_device_update(tzone->zone, event); } #endif diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c index 42c1ac057bad..ff3b36f339e3 100644 --- a/drivers/thermal/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/int340x_thermal/processor_thermal_device.c @@ -258,7 +258,8 @@ static void proc_thermal_notify(acpi_handle handle, u32 event, void *data) switch (event) { case PROC_POWER_CAPABILITY_CHANGED: proc_thermal_read_ppcc(proc_priv); - int340x_thermal_zone_device_update(proc_priv->int340x_zone); + int340x_thermal_zone_device_update(proc_priv->int340x_zone, + THERMAL_DEVICE_POWER_CAPABILITY_CHANGED); break; default: dev_err(proc_priv->dev, "Unsupported event [0x%x]\n", event); diff --git a/drivers/thermal/intel_bxt_pmic_thermal.c b/drivers/thermal/intel_bxt_pmic_thermal.c new file mode 100644 index 000000000000..0f19a393ddd8 --- /dev/null +++ b/drivers/thermal/intel_bxt_pmic_thermal.c @@ -0,0 +1,300 @@ +/* + * Intel Broxton PMIC thermal driver + * + * Copyright (C) 2016 Intel Corporation. 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BXTWC_THRM0IRQ 0x4E04 +#define BXTWC_THRM1IRQ 0x4E05 +#define BXTWC_THRM2IRQ 0x4E06 +#define BXTWC_MTHRM0IRQ 0x4E12 +#define BXTWC_MTHRM1IRQ 0x4E13 +#define BXTWC_MTHRM2IRQ 0x4E14 +#define BXTWC_STHRM0IRQ 0x4F19 +#define BXTWC_STHRM1IRQ 0x4F1A +#define BXTWC_STHRM2IRQ 0x4F1B + +struct trip_config_map { + u16 irq_reg; + u16 irq_en; + u16 evt_stat; + u8 irq_mask; + u8 irq_en_mask; + u8 evt_mask; + u8 trip_num; +}; + +struct thermal_irq_map { + char handle[20]; + int num_trips; + const struct trip_config_map *trip_config; +}; + +struct pmic_thermal_data { + const struct thermal_irq_map *maps; + int num_maps; +}; + +static const struct trip_config_map bxtwc_str0_trip_config[] = { + { + .irq_reg = BXTWC_THRM0IRQ, + .irq_mask = 0x01, + .irq_en = BXTWC_MTHRM0IRQ, + .irq_en_mask = 0x01, + .evt_stat = BXTWC_STHRM0IRQ, + .evt_mask = 0x01, + .trip_num = 0 + }, + { + .irq_reg = BXTWC_THRM0IRQ, + .irq_mask = 0x10, + .irq_en = BXTWC_MTHRM0IRQ, + .irq_en_mask = 0x10, + .evt_stat = BXTWC_STHRM0IRQ, + .evt_mask = 0x10, + .trip_num = 1 + } +}; + +static const struct trip_config_map bxtwc_str1_trip_config[] = { + { + .irq_reg = BXTWC_THRM0IRQ, + .irq_mask = 0x02, + .irq_en = BXTWC_MTHRM0IRQ, + .irq_en_mask = 0x02, + .evt_stat = BXTWC_STHRM0IRQ, + .evt_mask = 0x02, + .trip_num = 0 + }, + { + .irq_reg = BXTWC_THRM0IRQ, + .irq_mask = 0x20, + .irq_en = BXTWC_MTHRM0IRQ, + .irq_en_mask = 0x20, + .evt_stat = BXTWC_STHRM0IRQ, + .evt_mask = 0x20, + .trip_num = 1 + }, +}; + +static const struct trip_config_map bxtwc_str2_trip_config[] = { + { + .irq_reg = BXTWC_THRM0IRQ, + .irq_mask = 0x04, + .irq_en = BXTWC_MTHRM0IRQ, + .irq_en_mask = 0x04, + .evt_stat = BXTWC_STHRM0IRQ, + .evt_mask = 0x04, + .trip_num = 0 + }, + { + .irq_reg = BXTWC_THRM0IRQ, + .irq_mask = 0x40, + .irq_en = BXTWC_MTHRM0IRQ, + .irq_en_mask = 0x40, + .evt_stat = BXTWC_STHRM0IRQ, + .evt_mask = 0x40, + .trip_num = 1 + }, +}; + +static const struct trip_config_map bxtwc_str3_trip_config[] = { + { + .irq_reg = BXTWC_THRM2IRQ, + .irq_mask = 0x10, + .irq_en = BXTWC_MTHRM2IRQ, + .irq_en_mask = 0x10, + .evt_stat = BXTWC_STHRM2IRQ, + .evt_mask = 0x10, + .trip_num = 0 + }, +}; + +static const struct thermal_irq_map bxtwc_thermal_irq_map[] = { + { + .handle = "STR0", + .trip_config = bxtwc_str0_trip_config, + .num_trips = ARRAY_SIZE(bxtwc_str0_trip_config), + }, + { + .handle = "STR1", + .trip_config = bxtwc_str1_trip_config, + .num_trips = ARRAY_SIZE(bxtwc_str1_trip_config), + }, + { + .handle = "STR2", + .trip_config = bxtwc_str2_trip_config, + .num_trips = ARRAY_SIZE(bxtwc_str2_trip_config), + }, + { + .handle = "STR3", + .trip_config = bxtwc_str3_trip_config, + .num_trips = ARRAY_SIZE(bxtwc_str3_trip_config), + }, +}; + +static const struct pmic_thermal_data bxtwc_thermal_data = { + .maps = bxtwc_thermal_irq_map, + .num_maps = ARRAY_SIZE(bxtwc_thermal_irq_map), +}; + +static irqreturn_t pmic_thermal_irq_handler(int irq, void *data) +{ + struct platform_device *pdev = data; + struct thermal_zone_device *tzd; + struct pmic_thermal_data *td; + struct intel_soc_pmic *pmic; + struct regmap *regmap; + u8 reg_val, mask, irq_stat, trip; + u16 reg, evt_stat_reg; + int i, j, ret; + + pmic = dev_get_drvdata(pdev->dev.parent); + regmap = pmic->regmap; + td = (struct pmic_thermal_data *) + platform_get_device_id(pdev)->driver_data; + + /* Resolve thermal irqs */ + for (i = 0; i < td->num_maps; i++) { + for (j = 0; j < td->maps[i].num_trips; j++) { + reg = td->maps[i].trip_config[j].irq_reg; + mask = td->maps[i].trip_config[j].irq_mask; + /* + * Read the irq register to resolve whether the + * interrupt was triggered for this sensor + */ + if (regmap_read(regmap, reg, &ret)) + return IRQ_HANDLED; + + reg_val = (u8)ret; + irq_stat = ((u8)ret & mask); + + if (!irq_stat) + continue; + + /* + * Read the status register to find out what + * event occurred i.e a high or a low + */ + evt_stat_reg = td->maps[i].trip_config[j].evt_stat; + if (regmap_read(regmap, evt_stat_reg, &ret)) + return IRQ_HANDLED; + + trip = td->maps[i].trip_config[j].trip_num; + tzd = thermal_zone_get_zone_by_name(td->maps[i].handle); + if (!IS_ERR(tzd)) + thermal_zone_device_update(tzd, + THERMAL_EVENT_UNSPECIFIED); + + /* Clear the appropriate irq */ + regmap_write(regmap, reg, reg_val & mask); + } + } + + return IRQ_HANDLED; +} + +static int pmic_thermal_probe(struct platform_device *pdev) +{ + struct regmap_irq_chip_data *regmap_irq_chip; + struct pmic_thermal_data *thermal_data; + int ret, irq, virq, i, j, pmic_irq_count; + struct intel_soc_pmic *pmic; + struct regmap *regmap; + struct device *dev; + u16 reg; + u8 mask; + + dev = &pdev->dev; + pmic = dev_get_drvdata(pdev->dev.parent); + if (!pmic) { + dev_err(dev, "Failed to get struct intel_soc_pmic pointer\n"); + return -ENODEV; + } + + thermal_data = (struct pmic_thermal_data *) + platform_get_device_id(pdev)->driver_data; + if (!thermal_data) { + dev_err(dev, "No thermal data initialized!!\n"); + return -ENODEV; + } + + regmap = pmic->regmap; + regmap_irq_chip = pmic->irq_chip_data_level2; + + pmic_irq_count = 0; + while ((irq = platform_get_irq(pdev, pmic_irq_count)) != -ENXIO) { + virq = regmap_irq_get_virq(regmap_irq_chip, irq); + if (virq < 0) { + dev_err(dev, "failed to get virq by irq %d\n", irq); + return virq; + } + + ret = devm_request_threaded_irq(&pdev->dev, virq, + NULL, pmic_thermal_irq_handler, + IRQF_ONESHOT, "pmic_thermal", pdev); + + if (ret) { + dev_err(dev, "request irq(%d) failed: %d\n", virq, ret); + return ret; + } + pmic_irq_count++; + } + + /* Enable thermal interrupts */ + for (i = 0; i < thermal_data->num_maps; i++) { + for (j = 0; j < thermal_data->maps[i].num_trips; j++) { + reg = thermal_data->maps[i].trip_config[j].irq_en; + mask = thermal_data->maps[i].trip_config[j].irq_en_mask; + ret = regmap_update_bits(regmap, reg, mask, 0x00); + if (ret) + return ret; + } + } + + return 0; +} + +static const struct platform_device_id pmic_thermal_id_table[] = { + { + .name = "bxt_wcove_thermal", + .driver_data = (kernel_ulong_t)&bxtwc_thermal_data, + }, + {}, +}; + +static struct platform_driver pmic_thermal_driver = { + .probe = pmic_thermal_probe, + .driver = { + .name = "pmic_thermal", + }, + .id_table = pmic_thermal_id_table, +}; + +MODULE_DEVICE_TABLE(platform, pmic_thermal_id_table); +module_platform_driver(pmic_thermal_driver); + +MODULE_AUTHOR("Yegnesh S Iyer "); +MODULE_DESCRIPTION("Intel Broxton PMIC Thermal Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/thermal/intel_soc_dts_iosf.c b/drivers/thermal/intel_soc_dts_iosf.c index f72e1db3216f..e0813dfaa278 100644 --- a/drivers/thermal/intel_soc_dts_iosf.c +++ b/drivers/thermal/intel_soc_dts_iosf.c @@ -391,7 +391,8 @@ void intel_soc_dts_iosf_interrupt_handler(struct intel_soc_dts_sensors *sensors) for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { pr_debug("TZD update for zone %d\n", i); - thermal_zone_device_update(sensors->soc_dts[i].tzone); + thermal_zone_device_update(sensors->soc_dts[i].tzone, + THERMAL_EVENT_UNSPECIFIED); } } else spin_unlock_irqrestore(&sensors->intr_notify_lock, flags); diff --git a/drivers/thermal/max77620_thermal.c b/drivers/thermal/max77620_thermal.c new file mode 100644 index 000000000000..83905ff46e40 --- /dev/null +++ b/drivers/thermal/max77620_thermal.c @@ -0,0 +1,166 @@ +/* + * Junction temperature thermal driver for Maxim Max77620. + * + * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. + * + * Author: Laxman Dewangan + * Mallikarjun Kasoju + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX77620_NORMAL_OPERATING_TEMP 100000 +#define MAX77620_TJALARM1_TEMP 120000 +#define MAX77620_TJALARM2_TEMP 140000 + +struct max77620_therm_info { + struct device *dev; + struct regmap *rmap; + struct thermal_zone_device *tz_device; + int irq_tjalarm1; + int irq_tjalarm2; +}; + +/** + * max77620_thermal_read_temp: Read PMIC die temperatue. + * @data: Device specific data. + * temp: Temperature in millidegrees Celsius + * + * The actual temperature of PMIC die is not available from PMIC. + * PMIC only tells the status if it has crossed or not the threshold level + * of 120degC or 140degC. + * If threshold has not been crossed then assume die temperature as 100degC + * else 120degC or 140deG based on the PMIC die temp threshold status. + * + * Return 0 on success otherwise error number to show reason of failure. + */ + +static int max77620_thermal_read_temp(void *data, int *temp) +{ + struct max77620_therm_info *mtherm = data; + unsigned int val; + int ret; + + ret = regmap_read(mtherm->rmap, MAX77620_REG_STATLBT, &val); + if (ret < 0) { + dev_err(mtherm->dev, "Failed to read STATLBT: %d\n", ret); + return ret; + } + + if (val & MAX77620_IRQ_TJALRM2_MASK) + *temp = MAX77620_TJALARM2_TEMP; + else if (val & MAX77620_IRQ_TJALRM1_MASK) + *temp = MAX77620_TJALARM1_TEMP; + else + *temp = MAX77620_NORMAL_OPERATING_TEMP; + + return 0; +} + +static const struct thermal_zone_of_device_ops max77620_thermal_ops = { + .get_temp = max77620_thermal_read_temp, +}; + +static irqreturn_t max77620_thermal_irq(int irq, void *data) +{ + struct max77620_therm_info *mtherm = data; + + if (irq == mtherm->irq_tjalarm1) + dev_warn(mtherm->dev, "Junction Temp Alarm1(120C) occurred\n"); + else if (irq == mtherm->irq_tjalarm2) + dev_crit(mtherm->dev, "Junction Temp Alarm2(140C) occurred\n"); + + thermal_zone_device_update(mtherm->tz_device, + THERMAL_EVENT_UNSPECIFIED); + + return IRQ_HANDLED; +} + +static int max77620_thermal_probe(struct platform_device *pdev) +{ + struct max77620_therm_info *mtherm; + int ret; + + mtherm = devm_kzalloc(&pdev->dev, sizeof(*mtherm), GFP_KERNEL); + if (!mtherm) + return -ENOMEM; + + mtherm->irq_tjalarm1 = platform_get_irq(pdev, 0); + mtherm->irq_tjalarm2 = platform_get_irq(pdev, 1); + if ((mtherm->irq_tjalarm1 < 0) || (mtherm->irq_tjalarm2 < 0)) { + dev_err(&pdev->dev, "Alarm irq number not available\n"); + return -EINVAL; + } + + pdev->dev.of_node = pdev->dev.parent->of_node; + + mtherm->dev = &pdev->dev; + mtherm->rmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!mtherm->rmap) { + dev_err(&pdev->dev, "Failed to get parent regmap\n"); + return -ENODEV; + } + + mtherm->tz_device = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, + mtherm, &max77620_thermal_ops); + if (IS_ERR(mtherm->tz_device)) { + ret = PTR_ERR(mtherm->tz_device); + dev_err(&pdev->dev, "Failed to register thermal zone: %d\n", + ret); + return ret; + } + + ret = devm_request_threaded_irq(&pdev->dev, mtherm->irq_tjalarm1, NULL, + max77620_thermal_irq, + IRQF_ONESHOT | IRQF_SHARED, + dev_name(&pdev->dev), mtherm); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request irq1: %d\n", ret); + return ret; + } + + ret = devm_request_threaded_irq(&pdev->dev, mtherm->irq_tjalarm2, NULL, + max77620_thermal_irq, + IRQF_ONESHOT | IRQF_SHARED, + dev_name(&pdev->dev), mtherm); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request irq2: %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, mtherm); + + return 0; +} + +static struct platform_device_id max77620_thermal_devtype[] = { + { .name = "max77620-thermal", }, + {}, +}; + +static struct platform_driver max77620_thermal_driver = { + .driver = { + .name = "max77620-thermal", + }, + .probe = max77620_thermal_probe, + .id_table = max77620_thermal_devtype, +}; + +module_platform_driver(max77620_thermal_driver); + +MODULE_DESCRIPTION("Max77620 Junction temperature Thermal driver"); +MODULE_AUTHOR("Laxman Dewangan "); +MODULE_AUTHOR("Mallikarjun Kasoju "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c index 262ab0a2266f..34169c32d495 100644 --- a/drivers/thermal/mtk_thermal.c +++ b/drivers/thermal/mtk_thermal.c @@ -2,6 +2,7 @@ * Copyright (c) 2015 MediaTek Inc. * Author: Hanyi Wu * Sascha Hauer + * Dawei Chien * * 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 @@ -21,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -88,6 +90,7 @@ #define TEMP_ADCVALIDMASK_VALID_HIGH BIT(5) #define TEMP_ADCVALIDMASK_VALID_POS(bit) (bit) +/* MT8173 thermal sensors */ #define MT8173_TS1 0 #define MT8173_TS2 1 #define MT8173_TS3 2 @@ -106,7 +109,12 @@ /* The number of sensing points per bank */ #define MT8173_NUM_SENSORS_PER_ZONE 4 -/* Layout of the fuses providing the calibration data */ +/* + * Layout of the fuses providing the calibration data + * These macros could be used for both MT8173 and MT2701. + * MT8173 has five sensors and need five VTS calibration data, + * and MT2701 has three sensors and need three VTS calibration data. + */ #define MT8173_CALIB_BUF0_VALID BIT(0) #define MT8173_CALIB_BUF1_ADC_GE(x) (((x) >> 22) & 0x3ff) #define MT8173_CALIB_BUF0_VTS_TS1(x) (((x) >> 17) & 0x1ff) @@ -117,24 +125,50 @@ #define MT8173_CALIB_BUF0_DEGC_CALI(x) (((x) >> 1) & 0x3f) #define MT8173_CALIB_BUF0_O_SLOPE(x) (((x) >> 26) & 0x3f) +/* MT2701 thermal sensors */ +#define MT2701_TS1 0 +#define MT2701_TS2 1 +#define MT2701_TSABB 2 + +/* AUXADC channel 11 is used for the temperature sensors */ +#define MT2701_TEMP_AUXADC_CHANNEL 11 + +/* The total number of temperature sensors in the MT2701 */ +#define MT2701_NUM_SENSORS 3 + #define THERMAL_NAME "mtk-thermal" +/* The number of sensing points per bank */ +#define MT2701_NUM_SENSORS_PER_ZONE 3 + struct mtk_thermal; +struct thermal_bank_cfg { + unsigned int num_sensors; + const int *sensors; +}; + struct mtk_thermal_bank { struct mtk_thermal *mt; int id; }; +struct mtk_thermal_data { + s32 num_banks; + s32 num_sensors; + s32 auxadc_channel; + const int *sensor_mux_values; + const int *msr; + const int *adcpnp; + struct thermal_bank_cfg bank_data[]; +}; + struct mtk_thermal { struct device *dev; void __iomem *thermal_base; struct clk *clk_peri_therm; struct clk *clk_auxadc; - - struct mtk_thermal_bank banks[MT8173_NUM_ZONES]; - /* lock: for getting and putting banks */ struct mutex lock; @@ -144,16 +178,44 @@ struct mtk_thermal { s32 o_slope; s32 vts[MT8173_NUM_SENSORS]; + const struct mtk_thermal_data *conf; + struct mtk_thermal_bank banks[]; }; -struct mtk_thermal_bank_cfg { - unsigned int num_sensors; - unsigned int sensors[MT8173_NUM_SENSORS_PER_ZONE]; +/* MT8173 thermal sensor data */ +const int mt8173_bank_data[MT8173_NUM_ZONES][3] = { + { MT8173_TS2, MT8173_TS3 }, + { MT8173_TS2, MT8173_TS4 }, + { MT8173_TS1, MT8173_TS2, MT8173_TSABB }, + { MT8173_TS2 }, }; -static const int sensor_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 }; +const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = { + TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR2 +}; -/* +const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = { + TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3 +}; + +const int mt8173_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 }; + +/* MT2701 thermal sensor data */ +const int mt2701_bank_data[MT2701_NUM_SENSORS] = { + MT2701_TS1, MT2701_TS2, MT2701_TSABB +}; + +const int mt2701_msr[MT2701_NUM_SENSORS_PER_ZONE] = { + TEMP_MSR0, TEMP_MSR1, TEMP_MSR2 +}; + +const int mt2701_adcpnp[MT2701_NUM_SENSORS_PER_ZONE] = { + TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2 +}; + +const int mt2701_mux_values[MT2701_NUM_SENSORS] = { 0, 1, 16 }; + +/** * The MT8173 thermal controller has four banks. Each bank can read up to * four temperature sensors simultaneously. The MT8173 has a total of 5 * temperature sensors. We use each bank to measure a certain area of the @@ -166,42 +228,53 @@ static const int sensor_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 }; * data, and this indeed needs the temperatures of the individual banks * for making better decisions. */ -static const struct mtk_thermal_bank_cfg bank_data[] = { - { - .num_sensors = 2, - .sensors = { MT8173_TS2, MT8173_TS3 }, - }, { - .num_sensors = 2, - .sensors = { MT8173_TS2, MT8173_TS4 }, - }, { - .num_sensors = 3, - .sensors = { MT8173_TS1, MT8173_TS2, MT8173_TSABB }, - }, { - .num_sensors = 1, - .sensors = { MT8173_TS2 }, +static const struct mtk_thermal_data mt8173_thermal_data = { + .auxadc_channel = MT8173_TEMP_AUXADC_CHANNEL, + .num_banks = MT8173_NUM_ZONES, + .num_sensors = MT8173_NUM_SENSORS, + .bank_data = { + { + .num_sensors = 2, + .sensors = mt8173_bank_data[0], + }, { + .num_sensors = 2, + .sensors = mt8173_bank_data[1], + }, { + .num_sensors = 3, + .sensors = mt8173_bank_data[2], + }, { + .num_sensors = 1, + .sensors = mt8173_bank_data[3], + }, }, + .msr = mt8173_msr, + .adcpnp = mt8173_adcpnp, + .sensor_mux_values = mt8173_mux_values, }; -struct mtk_thermal_sense_point { - int msr; - int adcpnp; -}; - -static const struct mtk_thermal_sense_point - sensing_points[MT8173_NUM_SENSORS_PER_ZONE] = { - { - .msr = TEMP_MSR0, - .adcpnp = TEMP_ADCPNP0, - }, { - .msr = TEMP_MSR1, - .adcpnp = TEMP_ADCPNP1, - }, { - .msr = TEMP_MSR2, - .adcpnp = TEMP_ADCPNP2, - }, { - .msr = TEMP_MSR3, - .adcpnp = TEMP_ADCPNP3, +/** + * The MT2701 thermal controller has one bank, which can read up to + * three temperature sensors simultaneously. The MT2701 has a total of 3 + * temperature sensors. + * + * The thermal core only gets the maximum temperature of this one bank, + * so the bank concept wouldn't be necessary here. However, the SVS (Smart + * Voltage Scaling) unit makes its decisions based on the same bank + * data. + */ +static const struct mtk_thermal_data mt2701_thermal_data = { + .auxadc_channel = MT2701_TEMP_AUXADC_CHANNEL, + .num_banks = 1, + .num_sensors = MT2701_NUM_SENSORS, + .bank_data = { + { + .num_sensors = 3, + .sensors = mt2701_bank_data, + }, }, + .msr = mt2701_msr, + .adcpnp = mt2701_adcpnp, + .sensor_mux_values = mt2701_mux_values, }; /** @@ -270,13 +343,16 @@ static void mtk_thermal_put_bank(struct mtk_thermal_bank *bank) static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank) { struct mtk_thermal *mt = bank->mt; + const struct mtk_thermal_data *conf = mt->conf; int i, temp = INT_MIN, max = INT_MIN; u32 raw; - for (i = 0; i < bank_data[bank->id].num_sensors; i++) { - raw = readl(mt->thermal_base + sensing_points[i].msr); + for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) { + raw = readl(mt->thermal_base + conf->msr[i]); - temp = raw_to_mcelsius(mt, bank_data[bank->id].sensors[i], raw); + temp = raw_to_mcelsius(mt, + conf->bank_data[bank->id].sensors[i], + raw); /* * The first read of a sensor often contains very high bogus @@ -299,7 +375,7 @@ static int mtk_read_temp(void *data, int *temperature) int i; int tempmax = INT_MIN; - for (i = 0; i < MT8173_NUM_ZONES; i++) { + for (i = 0; i < mt->conf->num_banks; i++) { struct mtk_thermal_bank *bank = &mt->banks[i]; mtk_thermal_get_bank(bank); @@ -322,7 +398,7 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num, u32 apmixed_phys_base, u32 auxadc_phys_base) { struct mtk_thermal_bank *bank = &mt->banks[num]; - const struct mtk_thermal_bank_cfg *cfg = &bank_data[num]; + const struct mtk_thermal_data *conf = mt->conf; int i; bank->id = num; @@ -368,7 +444,7 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num, * this value will be stored to TEMP_PNPMUXADDR (TEMP_SPARE0) * automatically by hw */ - writel(BIT(MT8173_TEMP_AUXADC_CHANNEL), mt->thermal_base + TEMP_ADCMUX); + writel(BIT(conf->auxadc_channel), mt->thermal_base + TEMP_ADCMUX); /* AHB address for auxadc mux selection */ writel(auxadc_phys_base + AUXADC_CON1_CLR_V, @@ -379,18 +455,18 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num, mt->thermal_base + TEMP_PNPMUXADDR); /* AHB value for auxadc enable */ - writel(BIT(MT8173_TEMP_AUXADC_CHANNEL), mt->thermal_base + TEMP_ADCEN); + writel(BIT(conf->auxadc_channel), mt->thermal_base + TEMP_ADCEN); /* AHB address for auxadc enable (channel 0 immediate mode selected) */ writel(auxadc_phys_base + AUXADC_CON1_SET_V, mt->thermal_base + TEMP_ADCENADDR); /* AHB address for auxadc valid bit */ - writel(auxadc_phys_base + AUXADC_DATA(MT8173_TEMP_AUXADC_CHANNEL), + writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel), mt->thermal_base + TEMP_ADCVALIDADDR); /* AHB address for auxadc voltage output */ - writel(auxadc_phys_base + AUXADC_DATA(MT8173_TEMP_AUXADC_CHANNEL), + writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel), mt->thermal_base + TEMP_ADCVOLTADDR); /* read valid & voltage are at the same register */ @@ -407,11 +483,12 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num, writel(TEMP_ADCWRITECTRL_ADC_MUX_WRITE, mt->thermal_base + TEMP_ADCWRITECTRL); - for (i = 0; i < cfg->num_sensors; i++) - writel(sensor_mux_values[cfg->sensors[i]], - mt->thermal_base + sensing_points[i].adcpnp); + for (i = 0; i < conf->bank_data[num].num_sensors; i++) + writel(conf->sensor_mux_values[conf->bank_data[num].sensors[i]], + mt->thermal_base + conf->adcpnp[i]); - writel((1 << cfg->num_sensors) - 1, mt->thermal_base + TEMP_MONCTL0); + writel((1 << conf->bank_data[num].num_sensors) - 1, + mt->thermal_base + TEMP_MONCTL0); writel(TEMP_ADCWRITECTRL_ADC_PNP_WRITE | TEMP_ADCWRITECTRL_ADC_MUX_WRITE, @@ -442,7 +519,7 @@ static int mtk_thermal_get_calibration_data(struct device *dev, /* Start with default values */ mt->adc_ge = 512; - for (i = 0; i < MT8173_NUM_SENSORS; i++) + for (i = 0; i < mt->conf->num_sensors; i++) mt->vts[i] = 260; mt->degc_cali = 40; mt->o_slope = 0; @@ -486,18 +563,37 @@ out: return ret; } +static const struct of_device_id mtk_thermal_of_match[] = { + { + .compatible = "mediatek,mt8173-thermal", + .data = (void *)&mt8173_thermal_data, + }, + { + .compatible = "mediatek,mt2701-thermal", + .data = (void *)&mt2701_thermal_data, + }, { + }, +}; +MODULE_DEVICE_TABLE(of, mtk_thermal_of_match); + static int mtk_thermal_probe(struct platform_device *pdev) { int ret, i; struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node; struct mtk_thermal *mt; struct resource *res; + const struct of_device_id *of_id; u64 auxadc_phys_base, apmixed_phys_base; + struct thermal_zone_device *tzdev; mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL); if (!mt) return -ENOMEM; + of_id = of_match_device(mtk_thermal_of_match, &pdev->dev); + if (of_id) + mt->conf = (const struct mtk_thermal_data *)of_id->data; + mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm"); if (IS_ERR(mt->clk_peri_therm)) return PTR_ERR(mt->clk_peri_therm); @@ -565,17 +661,23 @@ static int mtk_thermal_probe(struct platform_device *pdev) goto err_disable_clk_auxadc; } - for (i = 0; i < MT8173_NUM_ZONES; i++) + for (i = 0; i < mt->conf->num_banks; i++) mtk_thermal_init_bank(mt, i, apmixed_phys_base, auxadc_phys_base); platform_set_drvdata(pdev, mt); - devm_thermal_zone_of_sensor_register(&pdev->dev, 0, mt, - &mtk_thermal_ops); + tzdev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, mt, + &mtk_thermal_ops); + if (IS_ERR(tzdev)) { + ret = PTR_ERR(tzdev); + goto err_disable_clk_peri_therm; + } return 0; +err_disable_clk_peri_therm: + clk_disable_unprepare(mt->clk_peri_therm); err_disable_clk_auxadc: clk_disable_unprepare(mt->clk_auxadc); @@ -592,13 +694,6 @@ static int mtk_thermal_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id mtk_thermal_of_match[] = { - { - .compatible = "mediatek,mt8173-thermal", - }, { - }, -}; - static struct platform_driver mtk_thermal_driver = { .probe = mtk_thermal_probe, .remove = mtk_thermal_remove, @@ -610,6 +705,7 @@ static struct platform_driver mtk_thermal_driver = { module_platform_driver(mtk_thermal_driver); +MODULE_AUTHOR("Dawei Chien "); MODULE_AUTHOR("Sascha Hauer "); MODULE_AUTHOR("Hanyi Wu "); MODULE_DESCRIPTION("Mediatek thermal driver"); diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index b8e509c60848..d04ec3b9e5ff 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -101,6 +101,17 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz, return data->ops->get_temp(data->sensor_data, temp); } +static int of_thermal_set_trips(struct thermal_zone_device *tz, + int low, int high) +{ + struct __thermal_zone *data = tz->devdata; + + if (!data->ops || !data->ops->set_trips) + return -EINVAL; + + return data->ops->set_trips(data->sensor_data, low, high); +} + /** * of_thermal_get_ntrips - function to export number of available trip * points. @@ -181,9 +192,6 @@ static int of_thermal_set_emul_temp(struct thermal_zone_device *tz, { struct __thermal_zone *data = tz->devdata; - if (!data->ops || !data->ops->set_emul_temp) - return -EINVAL; - return data->ops->set_emul_temp(data->sensor_data, temp); } @@ -191,25 +199,11 @@ static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip, enum thermal_trend *trend) { struct __thermal_zone *data = tz->devdata; - long dev_trend; - int r; if (!data->ops->get_trend) return -EINVAL; - r = data->ops->get_trend(data->sensor_data, &dev_trend); - if (r) - return r; - - /* TODO: These intervals might have some thresholds, but in core code */ - if (dev_trend > 0) - *trend = THERMAL_TREND_RAISING; - else if (dev_trend < 0) - *trend = THERMAL_TREND_DROPPING; - else - *trend = THERMAL_TREND_STABLE; - - return 0; + return data->ops->get_trend(data->sensor_data, trip, trend); } static int of_thermal_bind(struct thermal_zone_device *thermal, @@ -292,7 +286,7 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz, mutex_unlock(&tz->lock); data->mode = mode; - thermal_zone_device_update(tz); + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); return 0; } @@ -427,7 +421,17 @@ thermal_zone_of_add_sensor(struct device_node *zone, tzd->ops->get_temp = of_thermal_get_temp; tzd->ops->get_trend = of_thermal_get_trend; - tzd->ops->set_emul_temp = of_thermal_set_emul_temp; + + /* + * The thermal zone core will calculate the window if they have set the + * optional set_trips pointer. + */ + if (ops->set_trips) + tzd->ops->set_trips = of_thermal_set_trips; + + if (ops->set_emul_temp) + tzd->ops->set_emul_temp = of_thermal_set_emul_temp; + mutex_unlock(&tzd->lock); return tzd; @@ -596,7 +600,7 @@ static int devm_thermal_zone_of_sensor_match(struct device *dev, void *res, * Return: On success returns a valid struct thermal_zone_device, * otherwise, it returns a corresponding ERR_PTR(). Caller must * check the return value with help of IS_ERR() helper. - * Registered hermal_zone_device device will automatically be + * Registered thermal_zone_device device will automatically be * released when device is unbounded. */ struct thermal_zone_device *devm_thermal_zone_of_sensor_register( diff --git a/drivers/thermal/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom-spmi-temp-alarm.c index f8a3c60bef94..819c6d5d7aa7 100644 --- a/drivers/thermal/qcom-spmi-temp-alarm.c +++ b/drivers/thermal/qcom-spmi-temp-alarm.c @@ -150,7 +150,7 @@ static irqreturn_t qpnp_tm_isr(int irq, void *data) { struct qpnp_tm_chip *chip = data; - thermal_zone_device_update(chip->tz_dev); + thermal_zone_device_update(chip->tz_dev, THERMAL_EVENT_UNSPECIFIED); return IRQ_HANDLED; } diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig new file mode 100644 index 000000000000..be32e5abce3c --- /dev/null +++ b/drivers/thermal/qcom/Kconfig @@ -0,0 +1,11 @@ +config QCOM_TSENS + tristate "Qualcomm TSENS Temperature Alarm" + depends on THERMAL + depends on QCOM_QFPROM + depends on ARCH_QCOM || COMPILE_TEST + help + This enables the thermal sysfs driver for the TSENS device. It shows + up in Sysfs as a thermal zone with multiple trip points. Disabling the + thermal zone device via the mode file results in disabling the sensor. + Also able to set threshold temperature for both hot and cold and update + when a threshold is reached. diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile new file mode 100644 index 000000000000..2cc2193637e7 --- /dev/null +++ b/drivers/thermal/qcom/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_QCOM_TSENS) += qcom_tsens.o +qcom_tsens-y += tsens.o tsens-common.o tsens-8916.o tsens-8974.o tsens-8960.o tsens-8996.o diff --git a/drivers/thermal/qcom/tsens-8916.c b/drivers/thermal/qcom/tsens-8916.c new file mode 100644 index 000000000000..fdf561b8b81d --- /dev/null +++ b/drivers/thermal/qcom/tsens-8916.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2015, 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 "tsens.h" + +/* eeprom layout data for 8916 */ +#define BASE0_MASK 0x0000007f +#define BASE1_MASK 0xfe000000 +#define BASE0_SHIFT 0 +#define BASE1_SHIFT 25 + +#define S0_P1_MASK 0x00000f80 +#define S1_P1_MASK 0x003e0000 +#define S2_P1_MASK 0xf8000000 +#define S3_P1_MASK 0x000003e0 +#define S4_P1_MASK 0x000f8000 + +#define S0_P2_MASK 0x0001f000 +#define S1_P2_MASK 0x07c00000 +#define S2_P2_MASK 0x0000001f +#define S3_P2_MASK 0x00007c00 +#define S4_P2_MASK 0x01f00000 + +#define S0_P1_SHIFT 7 +#define S1_P1_SHIFT 17 +#define S2_P1_SHIFT 27 +#define S3_P1_SHIFT 5 +#define S4_P1_SHIFT 15 + +#define S0_P2_SHIFT 12 +#define S1_P2_SHIFT 22 +#define S2_P2_SHIFT 0 +#define S3_P2_SHIFT 10 +#define S4_P2_SHIFT 20 + +#define CAL_SEL_MASK 0xe0000000 +#define CAL_SEL_SHIFT 29 + +static int calibrate_8916(struct tsens_device *tmdev) +{ + int base0 = 0, base1 = 0, i; + u32 p1[5], p2[5]; + int mode = 0; + u32 *qfprom_cdata, *qfprom_csel; + + qfprom_cdata = (u32 *)qfprom_read(tmdev->dev, "calib"); + if (IS_ERR(qfprom_cdata)) + return PTR_ERR(qfprom_cdata); + + qfprom_csel = (u32 *)qfprom_read(tmdev->dev, "calib_sel"); + if (IS_ERR(qfprom_csel)) + return PTR_ERR(qfprom_csel); + + mode = (qfprom_csel[0] & CAL_SEL_MASK) >> CAL_SEL_SHIFT; + dev_dbg(tmdev->dev, "calibration mode is %d\n", mode); + + switch (mode) { + case TWO_PT_CALIB: + base1 = (qfprom_cdata[1] & BASE1_MASK) >> BASE1_SHIFT; + p2[0] = (qfprom_cdata[0] & S0_P2_MASK) >> S0_P2_SHIFT; + p2[1] = (qfprom_cdata[0] & S1_P2_MASK) >> S1_P2_SHIFT; + p2[2] = (qfprom_cdata[1] & S2_P2_MASK) >> S2_P2_SHIFT; + p2[3] = (qfprom_cdata[1] & S3_P2_MASK) >> S3_P2_SHIFT; + p2[4] = (qfprom_cdata[1] & S4_P2_MASK) >> S4_P2_SHIFT; + for (i = 0; i < tmdev->num_sensors; i++) + p2[i] = ((base1 + p2[i]) << 3); + /* Fall through */ + case ONE_PT_CALIB2: + base0 = (qfprom_cdata[0] & BASE0_MASK); + p1[0] = (qfprom_cdata[0] & S0_P1_MASK) >> S0_P1_SHIFT; + p1[1] = (qfprom_cdata[0] & S1_P1_MASK) >> S1_P1_SHIFT; + p1[2] = (qfprom_cdata[0] & S2_P1_MASK) >> S2_P1_SHIFT; + p1[3] = (qfprom_cdata[1] & S3_P1_MASK) >> S3_P1_SHIFT; + p1[4] = (qfprom_cdata[1] & S4_P1_MASK) >> S4_P1_SHIFT; + for (i = 0; i < tmdev->num_sensors; i++) + p1[i] = (((base0) + p1[i]) << 3); + break; + default: + for (i = 0; i < tmdev->num_sensors; i++) { + p1[i] = 500; + p2[i] = 780; + } + break; + } + + compute_intercept_slope(tmdev, p1, p2, mode); + + return 0; +} + +static const struct tsens_ops ops_8916 = { + .init = init_common, + .calibrate = calibrate_8916, + .get_temp = get_temp_common, +}; + +const struct tsens_data data_8916 = { + .num_sensors = 5, + .ops = &ops_8916, + .hw_ids = (unsigned int []){0, 1, 2, 4, 5 }, +}; diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c new file mode 100644 index 000000000000..0451277d3a8f --- /dev/null +++ b/drivers/thermal/qcom/tsens-8960.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2015, 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 "tsens.h" + +#define CAL_MDEGC 30000 + +#define CONFIG_ADDR 0x3640 +#define CONFIG_ADDR_8660 0x3620 +/* CONFIG_ADDR bitmasks */ +#define CONFIG 0x9b +#define CONFIG_MASK 0xf +#define CONFIG_8660 1 +#define CONFIG_SHIFT_8660 28 +#define CONFIG_MASK_8660 (3 << CONFIG_SHIFT_8660) + +#define STATUS_CNTL_ADDR_8064 0x3660 +#define CNTL_ADDR 0x3620 +/* CNTL_ADDR bitmasks */ +#define EN BIT(0) +#define SW_RST BIT(1) +#define SENSOR0_EN BIT(3) +#define SLP_CLK_ENA BIT(26) +#define SLP_CLK_ENA_8660 BIT(24) +#define MEASURE_PERIOD 1 +#define SENSOR0_SHIFT 3 + +/* INT_STATUS_ADDR bitmasks */ +#define MIN_STATUS_MASK BIT(0) +#define LOWER_STATUS_CLR BIT(1) +#define UPPER_STATUS_CLR BIT(2) +#define MAX_STATUS_MASK BIT(3) + +#define THRESHOLD_ADDR 0x3624 +/* THRESHOLD_ADDR bitmasks */ +#define THRESHOLD_MAX_LIMIT_SHIFT 24 +#define THRESHOLD_MIN_LIMIT_SHIFT 16 +#define THRESHOLD_UPPER_LIMIT_SHIFT 8 +#define THRESHOLD_LOWER_LIMIT_SHIFT 0 + +/* Initial temperature threshold values */ +#define LOWER_LIMIT_TH 0x50 +#define UPPER_LIMIT_TH 0xdf +#define MIN_LIMIT_TH 0x0 +#define MAX_LIMIT_TH 0xff + +#define S0_STATUS_ADDR 0x3628 +#define INT_STATUS_ADDR 0x363c +#define TRDY_MASK BIT(7) +#define TIMEOUT_US 100 + +static int suspend_8960(struct tsens_device *tmdev) +{ + int ret; + unsigned int mask; + struct regmap *map = tmdev->map; + + ret = regmap_read(map, THRESHOLD_ADDR, &tmdev->ctx.threshold); + if (ret) + return ret; + + ret = regmap_read(map, CNTL_ADDR, &tmdev->ctx.control); + if (ret) + return ret; + + if (tmdev->num_sensors > 1) + mask = SLP_CLK_ENA | EN; + else + mask = SLP_CLK_ENA_8660 | EN; + + ret = regmap_update_bits(map, CNTL_ADDR, mask, 0); + if (ret) + return ret; + + return 0; +} + +static int resume_8960(struct tsens_device *tmdev) +{ + int ret; + struct regmap *map = tmdev->map; + + ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST); + if (ret) + return ret; + + /* + * Separate CONFIG restore is not needed only for 8660 as + * config is part of CTRL Addr and its restored as such + */ + if (tmdev->num_sensors > 1) { + ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG); + if (ret) + return ret; + } + + ret = regmap_write(map, THRESHOLD_ADDR, tmdev->ctx.threshold); + if (ret) + return ret; + + ret = regmap_write(map, CNTL_ADDR, tmdev->ctx.control); + if (ret) + return ret; + + return 0; +} + +static int enable_8960(struct tsens_device *tmdev, int id) +{ + int ret; + u32 reg, mask; + + ret = regmap_read(tmdev->map, CNTL_ADDR, ®); + if (ret) + return ret; + + mask = BIT(id + SENSOR0_SHIFT); + ret = regmap_write(tmdev->map, CNTL_ADDR, reg | SW_RST); + if (ret) + return ret; + + if (tmdev->num_sensors > 1) + reg |= mask | SLP_CLK_ENA | EN; + else + reg |= mask | SLP_CLK_ENA_8660 | EN; + + ret = regmap_write(tmdev->map, CNTL_ADDR, reg); + if (ret) + return ret; + + return 0; +} + +static void disable_8960(struct tsens_device *tmdev) +{ + int ret; + u32 reg_cntl; + u32 mask; + + mask = GENMASK(tmdev->num_sensors - 1, 0); + mask <<= SENSOR0_SHIFT; + mask |= EN; + + ret = regmap_read(tmdev->map, CNTL_ADDR, ®_cntl); + if (ret) + return; + + reg_cntl &= ~mask; + + if (tmdev->num_sensors > 1) + reg_cntl &= ~SLP_CLK_ENA; + else + reg_cntl &= ~SLP_CLK_ENA_8660; + + regmap_write(tmdev->map, CNTL_ADDR, reg_cntl); +} + +static int init_8960(struct tsens_device *tmdev) +{ + int ret, i; + u32 reg_cntl; + + tmdev->map = dev_get_regmap(tmdev->dev, NULL); + if (!tmdev->map) + return -ENODEV; + + /* + * The status registers for each sensor are discontiguous + * because some SoCs have 5 sensors while others have more + * but the control registers stay in the same place, i.e + * directly after the first 5 status registers. + */ + for (i = 0; i < tmdev->num_sensors; i++) { + if (i >= 5) + tmdev->sensor[i].status = S0_STATUS_ADDR + 40; + tmdev->sensor[i].status += i * 4; + } + + reg_cntl = SW_RST; + ret = regmap_update_bits(tmdev->map, CNTL_ADDR, SW_RST, reg_cntl); + if (ret) + return ret; + + if (tmdev->num_sensors > 1) { + reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18); + reg_cntl &= ~SW_RST; + ret = regmap_update_bits(tmdev->map, CONFIG_ADDR, + CONFIG_MASK, CONFIG); + } else { + reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16); + reg_cntl &= ~CONFIG_MASK_8660; + reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660; + } + + reg_cntl |= GENMASK(tmdev->num_sensors - 1, 0) << SENSOR0_SHIFT; + ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl); + if (ret) + return ret; + + reg_cntl |= EN; + ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl); + if (ret) + return ret; + + return 0; +} + +static int calibrate_8960(struct tsens_device *tmdev) +{ + int i; + char *data; + + ssize_t num_read = tmdev->num_sensors; + struct tsens_sensor *s = tmdev->sensor; + + data = qfprom_read(tmdev->dev, "calib"); + if (IS_ERR(data)) + data = qfprom_read(tmdev->dev, "calib_backup"); + if (IS_ERR(data)) + return PTR_ERR(data); + + for (i = 0; i < num_read; i++, s++) + s->offset = data[i]; + + return 0; +} + +/* Temperature on y axis and ADC-code on x-axis */ +static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s) +{ + int slope, offset; + + slope = thermal_zone_get_slope(s->tzd); + offset = CAL_MDEGC - slope * s->offset; + + return adc_code * slope + offset; +} + +static int get_temp_8960(struct tsens_device *tmdev, int id, int *temp) +{ + int ret; + u32 code, trdy; + const struct tsens_sensor *s = &tmdev->sensor[id]; + unsigned long timeout; + + timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); + do { + ret = regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy); + if (ret) + return ret; + if (!(trdy & TRDY_MASK)) + continue; + ret = regmap_read(tmdev->map, s->status, &code); + if (ret) + return ret; + *temp = code_to_mdegC(code, s); + return 0; + } while (time_before(jiffies, timeout)); + + return -ETIMEDOUT; +} + +static const struct tsens_ops ops_8960 = { + .init = init_8960, + .calibrate = calibrate_8960, + .get_temp = get_temp_8960, + .enable = enable_8960, + .disable = disable_8960, + .suspend = suspend_8960, + .resume = resume_8960, +}; + +const struct tsens_data data_8960 = { + .num_sensors = 11, + .ops = &ops_8960, +}; diff --git a/drivers/thermal/qcom/tsens-8974.c b/drivers/thermal/qcom/tsens-8974.c new file mode 100644 index 000000000000..9baf77e8cbe3 --- /dev/null +++ b/drivers/thermal/qcom/tsens-8974.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2015, 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 "tsens.h" + +/* eeprom layout data for 8974 */ +#define BASE1_MASK 0xff +#define S0_P1_MASK 0x3f00 +#define S1_P1_MASK 0xfc000 +#define S2_P1_MASK 0x3f00000 +#define S3_P1_MASK 0xfc000000 +#define S4_P1_MASK 0x3f +#define S5_P1_MASK 0xfc0 +#define S6_P1_MASK 0x3f000 +#define S7_P1_MASK 0xfc0000 +#define S8_P1_MASK 0x3f000000 +#define S8_P1_MASK_BKP 0x3f +#define S9_P1_MASK 0x3f +#define S9_P1_MASK_BKP 0xfc0 +#define S10_P1_MASK 0xfc0 +#define S10_P1_MASK_BKP 0x3f000 +#define CAL_SEL_0_1 0xc0000000 +#define CAL_SEL_2 0x40000000 +#define CAL_SEL_SHIFT 30 +#define CAL_SEL_SHIFT_2 28 + +#define S0_P1_SHIFT 8 +#define S1_P1_SHIFT 14 +#define S2_P1_SHIFT 20 +#define S3_P1_SHIFT 26 +#define S5_P1_SHIFT 6 +#define S6_P1_SHIFT 12 +#define S7_P1_SHIFT 18 +#define S8_P1_SHIFT 24 +#define S9_P1_BKP_SHIFT 6 +#define S10_P1_SHIFT 6 +#define S10_P1_BKP_SHIFT 12 + +#define BASE2_SHIFT 12 +#define BASE2_BKP_SHIFT 18 +#define S0_P2_SHIFT 20 +#define S0_P2_BKP_SHIFT 26 +#define S1_P2_SHIFT 26 +#define S2_P2_BKP_SHIFT 6 +#define S3_P2_SHIFT 6 +#define S3_P2_BKP_SHIFT 12 +#define S4_P2_SHIFT 12 +#define S4_P2_BKP_SHIFT 18 +#define S5_P2_SHIFT 18 +#define S5_P2_BKP_SHIFT 24 +#define S6_P2_SHIFT 24 +#define S7_P2_BKP_SHIFT 6 +#define S8_P2_SHIFT 6 +#define S8_P2_BKP_SHIFT 12 +#define S9_P2_SHIFT 12 +#define S9_P2_BKP_SHIFT 18 +#define S10_P2_SHIFT 18 +#define S10_P2_BKP_SHIFT 24 + +#define BASE2_MASK 0xff000 +#define BASE2_BKP_MASK 0xfc0000 +#define S0_P2_MASK 0x3f00000 +#define S0_P2_BKP_MASK 0xfc000000 +#define S1_P2_MASK 0xfc000000 +#define S1_P2_BKP_MASK 0x3f +#define S2_P2_MASK 0x3f +#define S2_P2_BKP_MASK 0xfc0 +#define S3_P2_MASK 0xfc0 +#define S3_P2_BKP_MASK 0x3f000 +#define S4_P2_MASK 0x3f000 +#define S4_P2_BKP_MASK 0xfc0000 +#define S5_P2_MASK 0xfc0000 +#define S5_P2_BKP_MASK 0x3f000000 +#define S6_P2_MASK 0x3f000000 +#define S6_P2_BKP_MASK 0x3f +#define S7_P2_MASK 0x3f +#define S7_P2_BKP_MASK 0xfc0 +#define S8_P2_MASK 0xfc0 +#define S8_P2_BKP_MASK 0x3f000 +#define S9_P2_MASK 0x3f000 +#define S9_P2_BKP_MASK 0xfc0000 +#define S10_P2_MASK 0xfc0000 +#define S10_P2_BKP_MASK 0x3f000000 + +#define BKP_SEL 0x3 +#define BKP_REDUN_SEL 0xe0000000 +#define BKP_REDUN_SHIFT 29 + +#define BIT_APPEND 0x3 + +static int calibrate_8974(struct tsens_device *tmdev) +{ + int base1 = 0, base2 = 0, i; + u32 p1[11], p2[11]; + int mode = 0; + u32 *calib, *bkp; + u32 calib_redun_sel; + + calib = (u32 *)qfprom_read(tmdev->dev, "calib"); + if (IS_ERR(calib)) + return PTR_ERR(calib); + + bkp = (u32 *)qfprom_read(tmdev->dev, "calib_backup"); + if (IS_ERR(bkp)) + return PTR_ERR(bkp); + + calib_redun_sel = bkp[1] & BKP_REDUN_SEL; + calib_redun_sel >>= BKP_REDUN_SHIFT; + + if (calib_redun_sel == BKP_SEL) { + mode = (calib[4] & CAL_SEL_0_1) >> CAL_SEL_SHIFT; + mode |= (calib[5] & CAL_SEL_2) >> CAL_SEL_SHIFT_2; + + switch (mode) { + case TWO_PT_CALIB: + base2 = (bkp[2] & BASE2_BKP_MASK) >> BASE2_BKP_SHIFT; + p2[0] = (bkp[2] & S0_P2_BKP_MASK) >> S0_P2_BKP_SHIFT; + p2[1] = (bkp[3] & S1_P2_BKP_MASK); + p2[2] = (bkp[3] & S2_P2_BKP_MASK) >> S2_P2_BKP_SHIFT; + p2[3] = (bkp[3] & S3_P2_BKP_MASK) >> S3_P2_BKP_SHIFT; + p2[4] = (bkp[3] & S4_P2_BKP_MASK) >> S4_P2_BKP_SHIFT; + p2[5] = (calib[4] & S5_P2_BKP_MASK) >> S5_P2_BKP_SHIFT; + p2[6] = (calib[5] & S6_P2_BKP_MASK); + p2[7] = (calib[5] & S7_P2_BKP_MASK) >> S7_P2_BKP_SHIFT; + p2[8] = (calib[5] & S8_P2_BKP_MASK) >> S8_P2_BKP_SHIFT; + p2[9] = (calib[5] & S9_P2_BKP_MASK) >> S9_P2_BKP_SHIFT; + p2[10] = (calib[5] & S10_P2_BKP_MASK) >> S10_P2_BKP_SHIFT; + /* Fall through */ + case ONE_PT_CALIB: + case ONE_PT_CALIB2: + base1 = bkp[0] & BASE1_MASK; + p1[0] = (bkp[0] & S0_P1_MASK) >> S0_P1_SHIFT; + p1[1] = (bkp[0] & S1_P1_MASK) >> S1_P1_SHIFT; + p1[2] = (bkp[0] & S2_P1_MASK) >> S2_P1_SHIFT; + p1[3] = (bkp[0] & S3_P1_MASK) >> S3_P1_SHIFT; + p1[4] = (bkp[1] & S4_P1_MASK); + p1[5] = (bkp[1] & S5_P1_MASK) >> S5_P1_SHIFT; + p1[6] = (bkp[1] & S6_P1_MASK) >> S6_P1_SHIFT; + p1[7] = (bkp[1] & S7_P1_MASK) >> S7_P1_SHIFT; + p1[8] = (bkp[2] & S8_P1_MASK_BKP) >> S8_P1_SHIFT; + p1[9] = (bkp[2] & S9_P1_MASK_BKP) >> S9_P1_BKP_SHIFT; + p1[10] = (bkp[2] & S10_P1_MASK_BKP) >> S10_P1_BKP_SHIFT; + break; + } + } else { + mode = (calib[1] & CAL_SEL_0_1) >> CAL_SEL_SHIFT; + mode |= (calib[3] & CAL_SEL_2) >> CAL_SEL_SHIFT_2; + + switch (mode) { + case TWO_PT_CALIB: + base2 = (calib[2] & BASE2_MASK) >> BASE2_SHIFT; + p2[0] = (calib[2] & S0_P2_MASK) >> S0_P2_SHIFT; + p2[1] = (calib[2] & S1_P2_MASK) >> S1_P2_SHIFT; + p2[2] = (calib[3] & S2_P2_MASK); + p2[3] = (calib[3] & S3_P2_MASK) >> S3_P2_SHIFT; + p2[4] = (calib[3] & S4_P2_MASK) >> S4_P2_SHIFT; + p2[5] = (calib[3] & S5_P2_MASK) >> S5_P2_SHIFT; + p2[6] = (calib[3] & S6_P2_MASK) >> S6_P2_SHIFT; + p2[7] = (calib[4] & S7_P2_MASK); + p2[8] = (calib[4] & S8_P2_MASK) >> S8_P2_SHIFT; + p2[9] = (calib[4] & S9_P2_MASK) >> S9_P2_SHIFT; + p2[10] = (calib[4] & S10_P2_MASK) >> S10_P2_SHIFT; + /* Fall through */ + case ONE_PT_CALIB: + case ONE_PT_CALIB2: + base1 = calib[0] & BASE1_MASK; + p1[0] = (calib[0] & S0_P1_MASK) >> S0_P1_SHIFT; + p1[1] = (calib[0] & S1_P1_MASK) >> S1_P1_SHIFT; + p1[2] = (calib[0] & S2_P1_MASK) >> S2_P1_SHIFT; + p1[3] = (calib[0] & S3_P1_MASK) >> S3_P1_SHIFT; + p1[4] = (calib[1] & S4_P1_MASK); + p1[5] = (calib[1] & S5_P1_MASK) >> S5_P1_SHIFT; + p1[6] = (calib[1] & S6_P1_MASK) >> S6_P1_SHIFT; + p1[7] = (calib[1] & S7_P1_MASK) >> S7_P1_SHIFT; + p1[8] = (calib[1] & S8_P1_MASK) >> S8_P1_SHIFT; + p1[9] = (calib[2] & S9_P1_MASK); + p1[10] = (calib[2] & S10_P1_MASK) >> S10_P1_SHIFT; + break; + } + } + + switch (mode) { + case ONE_PT_CALIB: + for (i = 0; i < tmdev->num_sensors; i++) + p1[i] += (base1 << 2) | BIT_APPEND; + break; + case TWO_PT_CALIB: + for (i = 0; i < tmdev->num_sensors; i++) { + p2[i] += base2; + p2[i] <<= 2; + p2[i] |= BIT_APPEND; + } + /* Fall through */ + case ONE_PT_CALIB2: + for (i = 0; i < tmdev->num_sensors; i++) { + p1[i] += base1; + p1[i] <<= 2; + p1[i] |= BIT_APPEND; + } + break; + default: + for (i = 0; i < tmdev->num_sensors; i++) + p2[i] = 780; + p1[0] = 502; + p1[1] = 509; + p1[2] = 503; + p1[3] = 509; + p1[4] = 505; + p1[5] = 509; + p1[6] = 507; + p1[7] = 510; + p1[8] = 508; + p1[9] = 509; + p1[10] = 508; + break; + } + + compute_intercept_slope(tmdev, p1, p2, mode); + + return 0; +} + +static const struct tsens_ops ops_8974 = { + .init = init_common, + .calibrate = calibrate_8974, + .get_temp = get_temp_common, +}; + +const struct tsens_data data_8974 = { + .num_sensors = 11, + .ops = &ops_8974, +}; diff --git a/drivers/thermal/qcom/tsens-8996.c b/drivers/thermal/qcom/tsens-8996.c new file mode 100644 index 000000000000..e1f77818d8fa --- /dev/null +++ b/drivers/thermal/qcom/tsens-8996.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015, 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 "tsens.h" + +#define STATUS_OFFSET 0x10a0 +#define LAST_TEMP_MASK 0xfff +#define STATUS_VALID_BIT BIT(21) +#define CODE_SIGN_BIT BIT(11) + +static int get_temp_8996(struct tsens_device *tmdev, int id, int *temp) +{ + struct tsens_sensor *s = &tmdev->sensor[id]; + u32 code; + unsigned int sensor_addr; + int last_temp = 0, last_temp2 = 0, last_temp3 = 0, ret; + + sensor_addr = STATUS_OFFSET + s->hw_id * 4; + ret = regmap_read(tmdev->map, sensor_addr, &code); + if (ret) + return ret; + last_temp = code & LAST_TEMP_MASK; + if (code & STATUS_VALID_BIT) + goto done; + + /* Try a second time */ + ret = regmap_read(tmdev->map, sensor_addr, &code); + if (ret) + return ret; + if (code & STATUS_VALID_BIT) { + last_temp = code & LAST_TEMP_MASK; + goto done; + } else { + last_temp2 = code & LAST_TEMP_MASK; + } + + /* Try a third/last time */ + ret = regmap_read(tmdev->map, sensor_addr, &code); + if (ret) + return ret; + if (code & STATUS_VALID_BIT) { + last_temp = code & LAST_TEMP_MASK; + goto done; + } else { + last_temp3 = code & LAST_TEMP_MASK; + } + + if (last_temp == last_temp2) + last_temp = last_temp2; + else if (last_temp2 == last_temp3) + last_temp = last_temp3; +done: + /* Code sign bit is the sign extension for a negative value */ + if (last_temp & CODE_SIGN_BIT) + last_temp |= ~CODE_SIGN_BIT; + + /* Temperatures are in deciCelicius */ + *temp = last_temp * 100; + + return 0; +} + +static const struct tsens_ops ops_8996 = { + .init = init_common, + .get_temp = get_temp_8996, +}; + +const struct tsens_data data_8996 = { + .num_sensors = 13, + .ops = &ops_8996, +}; diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c new file mode 100644 index 000000000000..b1449ad67fc0 --- /dev/null +++ b/drivers/thermal/qcom/tsens-common.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2015, 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 "tsens.h" + +#define S0_ST_ADDR 0x1030 +#define SN_ADDR_OFFSET 0x4 +#define SN_ST_TEMP_MASK 0x3ff +#define CAL_DEGC_PT1 30 +#define CAL_DEGC_PT2 120 +#define SLOPE_FACTOR 1000 +#define SLOPE_DEFAULT 3200 + +char *qfprom_read(struct device *dev, const char *cname) +{ + struct nvmem_cell *cell; + ssize_t data; + char *ret; + + cell = nvmem_cell_get(dev, cname); + if (IS_ERR(cell)) + return ERR_CAST(cell); + + ret = nvmem_cell_read(cell, &data); + nvmem_cell_put(cell); + + return ret; +} + +/* + * Use this function on devices where slope and offset calculations + * depend on calibration data read from qfprom. On others the slope + * and offset values are derived from tz->tzp->slope and tz->tzp->offset + * resp. + */ +void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1, + u32 *p2, u32 mode) +{ + int i; + int num, den; + + for (i = 0; i < tmdev->num_sensors; i++) { + dev_dbg(tmdev->dev, + "sensor%d - data_point1:%#x data_point2:%#x\n", + i, p1[i], p2[i]); + + tmdev->sensor[i].slope = SLOPE_DEFAULT; + if (mode == TWO_PT_CALIB) { + /* + * slope (m) = adc_code2 - adc_code1 (y2 - y1)/ + * temp_120_degc - temp_30_degc (x2 - x1) + */ + num = p2[i] - p1[i]; + num *= SLOPE_FACTOR; + den = CAL_DEGC_PT2 - CAL_DEGC_PT1; + tmdev->sensor[i].slope = num / den; + } + + tmdev->sensor[i].offset = (p1[i] * SLOPE_FACTOR) - + (CAL_DEGC_PT1 * + tmdev->sensor[i].slope); + dev_dbg(tmdev->dev, "offset:%d\n", tmdev->sensor[i].offset); + } +} + +static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s) +{ + int degc, num, den; + + num = (adc_code * SLOPE_FACTOR) - s->offset; + den = s->slope; + + if (num > 0) + degc = num + (den / 2); + else if (num < 0) + degc = num - (den / 2); + else + degc = num; + + degc /= den; + + return degc; +} + +int get_temp_common(struct tsens_device *tmdev, int id, int *temp) +{ + struct tsens_sensor *s = &tmdev->sensor[id]; + u32 code; + unsigned int sensor_addr; + int last_temp = 0, ret; + + sensor_addr = S0_ST_ADDR + s->hw_id * SN_ADDR_OFFSET; + ret = regmap_read(tmdev->map, sensor_addr, &code); + if (ret) + return ret; + last_temp = code & SN_ST_TEMP_MASK; + + *temp = code_to_degc(last_temp, s) * 1000; + + return 0; +} + +static const struct regmap_config tsens_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +int __init init_common(struct tsens_device *tmdev) +{ + void __iomem *base; + + base = of_iomap(tmdev->dev->of_node, 0); + if (!base) + return -EINVAL; + + tmdev->map = devm_regmap_init_mmio(tmdev->dev, base, &tsens_config); + if (IS_ERR(tmdev->map)) { + iounmap(base); + return PTR_ERR(tmdev->map); + } + + return 0; +} diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c new file mode 100644 index 000000000000..3f9fe6aa51cc --- /dev/null +++ b/drivers/thermal/qcom/tsens.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2015, 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 "tsens.h" + +static int tsens_get_temp(void *data, int *temp) +{ + const struct tsens_sensor *s = data; + struct tsens_device *tmdev = s->tmdev; + + return tmdev->ops->get_temp(tmdev, s->id, temp); +} + +static int tsens_get_trend(void *p, int trip, enum thermal_trend *trend) +{ + const struct tsens_sensor *s = p; + struct tsens_device *tmdev = s->tmdev; + + if (tmdev->ops->get_trend) + return tmdev->ops->get_trend(tmdev, s->id, trend); + + return -ENOTSUPP; +} + +static int __maybe_unused tsens_suspend(struct device *dev) +{ + struct tsens_device *tmdev = dev_get_drvdata(dev); + + if (tmdev->ops && tmdev->ops->suspend) + return tmdev->ops->suspend(tmdev); + + return 0; +} + +static int __maybe_unused tsens_resume(struct device *dev) +{ + struct tsens_device *tmdev = dev_get_drvdata(dev); + + if (tmdev->ops && tmdev->ops->resume) + return tmdev->ops->resume(tmdev); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume); + +static const struct of_device_id tsens_table[] = { + { + .compatible = "qcom,msm8916-tsens", + .data = &data_8916, + }, { + .compatible = "qcom,msm8974-tsens", + .data = &data_8974, + }, { + .compatible = "qcom,msm8996-tsens", + .data = &data_8996, + }, + {} +}; +MODULE_DEVICE_TABLE(of, tsens_table); + +static const struct thermal_zone_of_device_ops tsens_of_ops = { + .get_temp = tsens_get_temp, + .get_trend = tsens_get_trend, +}; + +static int tsens_register(struct tsens_device *tmdev) +{ + int i; + struct thermal_zone_device *tzd; + u32 *hw_id, n = tmdev->num_sensors; + + hw_id = devm_kcalloc(tmdev->dev, n, sizeof(u32), GFP_KERNEL); + if (!hw_id) + return -ENOMEM; + + for (i = 0; i < tmdev->num_sensors; i++) { + tmdev->sensor[i].tmdev = tmdev; + tmdev->sensor[i].id = i; + tzd = devm_thermal_zone_of_sensor_register(tmdev->dev, i, + &tmdev->sensor[i], + &tsens_of_ops); + if (IS_ERR(tzd)) + continue; + tmdev->sensor[i].tzd = tzd; + if (tmdev->ops->enable) + tmdev->ops->enable(tmdev, i); + } + return 0; +} + +static int tsens_probe(struct platform_device *pdev) +{ + int ret, i; + struct device *dev; + struct device_node *np; + struct tsens_sensor *s; + struct tsens_device *tmdev; + const struct tsens_data *data; + const struct of_device_id *id; + + if (pdev->dev.of_node) + dev = &pdev->dev; + else + dev = pdev->dev.parent; + + np = dev->of_node; + + id = of_match_node(tsens_table, np); + if (id) + data = id->data; + else + data = &data_8960; + + if (data->num_sensors <= 0) { + dev_err(dev, "invalid number of sensors\n"); + return -EINVAL; + } + + tmdev = devm_kzalloc(dev, sizeof(*tmdev) + + data->num_sensors * sizeof(*s), GFP_KERNEL); + if (!tmdev) + return -ENOMEM; + + tmdev->dev = dev; + tmdev->num_sensors = data->num_sensors; + tmdev->ops = data->ops; + for (i = 0; i < tmdev->num_sensors; i++) { + if (data->hw_ids) + tmdev->sensor[i].hw_id = data->hw_ids[i]; + else + tmdev->sensor[i].hw_id = i; + } + + if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->get_temp) + return -EINVAL; + + ret = tmdev->ops->init(tmdev); + if (ret < 0) { + dev_err(dev, "tsens init failed\n"); + return ret; + } + + if (tmdev->ops->calibrate) { + ret = tmdev->ops->calibrate(tmdev); + if (ret < 0) { + dev_err(dev, "tsens calibration failed\n"); + return ret; + } + } + + ret = tsens_register(tmdev); + + platform_set_drvdata(pdev, tmdev); + + return ret; +} + +static int tsens_remove(struct platform_device *pdev) +{ + struct tsens_device *tmdev = platform_get_drvdata(pdev); + + if (tmdev->ops->disable) + tmdev->ops->disable(tmdev); + + return 0; +} + +static struct platform_driver tsens_driver = { + .probe = tsens_probe, + .remove = tsens_remove, + .driver = { + .name = "qcom-tsens", + .pm = &tsens_pm_ops, + .of_match_table = tsens_table, + }, +}; +module_platform_driver(tsens_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("QCOM Temperature Sensor driver"); +MODULE_ALIAS("platform:qcom-tsens"); diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h new file mode 100644 index 000000000000..911c1978892b --- /dev/null +++ b/drivers/thermal/qcom/tsens.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ +#ifndef __QCOM_TSENS_H__ +#define __QCOM_TSENS_H__ + +#define ONE_PT_CALIB 0x1 +#define ONE_PT_CALIB2 0x2 +#define TWO_PT_CALIB 0x3 + +#include + +struct tsens_device; + +struct tsens_sensor { + struct tsens_device *tmdev; + struct thermal_zone_device *tzd; + int offset; + int id; + int hw_id; + int slope; + u32 status; +}; + +/** + * struct tsens_ops - operations as supported by the tsens device + * @init: Function to initialize the tsens device + * @calibrate: Function to calibrate the tsens device + * @get_temp: Function which returns the temp in millidegC + * @enable: Function to enable (clocks/power) tsens device + * @disable: Function to disable the tsens device + * @suspend: Function to suspend the tsens device + * @resume: Function to resume the tsens device + * @get_trend: Function to get the thermal/temp trend + */ +struct tsens_ops { + /* mandatory callbacks */ + int (*init)(struct tsens_device *); + int (*calibrate)(struct tsens_device *); + int (*get_temp)(struct tsens_device *, int, int *); + /* optional callbacks */ + int (*enable)(struct tsens_device *, int); + void (*disable)(struct tsens_device *); + int (*suspend)(struct tsens_device *); + int (*resume)(struct tsens_device *); + int (*get_trend)(struct tsens_device *, int, enum thermal_trend *); +}; + +/** + * struct tsens_data - tsens instance specific data + * @num_sensors: Max number of sensors supported by platform + * @ops: operations the tsens instance supports + * @hw_ids: Subset of sensors ids supported by platform, if not the first n + */ +struct tsens_data { + const u32 num_sensors; + const struct tsens_ops *ops; + unsigned int *hw_ids; +}; + +/* Registers to be saved/restored across a context loss */ +struct tsens_context { + int threshold; + int control; +}; + +struct tsens_device { + struct device *dev; + u32 num_sensors; + struct regmap *map; + struct regmap_field *status_field; + struct tsens_context ctx; + bool trdy; + const struct tsens_ops *ops; + struct tsens_sensor sensor[0]; +}; + +char *qfprom_read(struct device *, const char *); +void compute_intercept_slope(struct tsens_device *, u32 *, u32 *, u32); +int init_common(struct tsens_device *); +int get_temp_common(struct tsens_device *, int, int *); + +extern const struct tsens_data data_8916, data_8974, data_8960, data_8996; + +#endif /* __QCOM_TSENS_H__ */ diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c new file mode 100644 index 000000000000..644ba526d9ea --- /dev/null +++ b/drivers/thermal/qoriq_thermal.c @@ -0,0 +1,328 @@ +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "thermal_core.h" + +#define SITES_MAX 16 + +/* + * QorIQ TMU Registers + */ +struct qoriq_tmu_site_regs { + u32 tritsr; /* Immediate Temperature Site Register */ + u32 tratsr; /* Average Temperature Site Register */ + u8 res0[0x8]; +}; + +struct qoriq_tmu_regs { + u32 tmr; /* Mode Register */ +#define TMR_DISABLE 0x0 +#define TMR_ME 0x80000000 +#define TMR_ALPF 0x0c000000 + u32 tsr; /* Status Register */ + u32 tmtmir; /* Temperature measurement interval Register */ +#define TMTMIR_DEFAULT 0x0000000f + u8 res0[0x14]; + u32 tier; /* Interrupt Enable Register */ +#define TIER_DISABLE 0x0 + u32 tidr; /* Interrupt Detect Register */ + u32 tiscr; /* Interrupt Site Capture Register */ + u32 ticscr; /* Interrupt Critical Site Capture Register */ + u8 res1[0x10]; + u32 tmhtcrh; /* High Temperature Capture Register */ + u32 tmhtcrl; /* Low Temperature Capture Register */ + u8 res2[0x8]; + u32 tmhtitr; /* High Temperature Immediate Threshold */ + u32 tmhtatr; /* High Temperature Average Threshold */ + u32 tmhtactr; /* High Temperature Average Crit Threshold */ + u8 res3[0x24]; + u32 ttcfgr; /* Temperature Configuration Register */ + u32 tscfgr; /* Sensor Configuration Register */ + u8 res4[0x78]; + struct qoriq_tmu_site_regs site[SITES_MAX]; + u8 res5[0x9f8]; + u32 ipbrr0; /* IP Block Revision Register 0 */ + u32 ipbrr1; /* IP Block Revision Register 1 */ + u8 res6[0x310]; + u32 ttr0cr; /* Temperature Range 0 Control Register */ + u32 ttr1cr; /* Temperature Range 1 Control Register */ + u32 ttr2cr; /* Temperature Range 2 Control Register */ + u32 ttr3cr; /* Temperature Range 3 Control Register */ +}; + +/* + * Thermal zone data + */ +struct qoriq_tmu_data { + struct thermal_zone_device *tz; + struct qoriq_tmu_regs __iomem *regs; + int sensor_id; + bool little_endian; +}; + +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void __iomem *addr) +{ + if (p->little_endian) + iowrite32(val, addr); + else + iowrite32be(val, addr); +} + +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) +{ + if (p->little_endian) + return ioread32(addr); + else + return ioread32be(addr); +} + +static int tmu_get_temp(void *p, int *temp) +{ + u32 val; + struct qoriq_tmu_data *data = p; + + val = tmu_read(data, &data->regs->site[data->sensor_id].tritsr); + *temp = (val & 0xff) * 1000; + + return 0; +} + +static int qoriq_tmu_get_sensor_id(void) +{ + int ret, id; + struct of_phandle_args sensor_specs; + struct device_node *np, *sensor_np; + + np = of_find_node_by_name(NULL, "thermal-zones"); + if (!np) + return -ENODEV; + + sensor_np = of_get_next_child(np, NULL); + ret = of_parse_phandle_with_args(sensor_np, "thermal-sensors", + "#thermal-sensor-cells", + 0, &sensor_specs); + if (ret) { + of_node_put(np); + of_node_put(sensor_np); + return ret; + } + + if (sensor_specs.args_count >= 1) { + id = sensor_specs.args[0]; + WARN(sensor_specs.args_count > 1, + "%s: too many cells in sensor specifier %d\n", + sensor_specs.np->name, sensor_specs.args_count); + } else { + id = 0; + } + + of_node_put(np); + of_node_put(sensor_np); + + return id; +} + +static int qoriq_tmu_calibration(struct platform_device *pdev) +{ + int i, val, len; + u32 range[4]; + const u32 *calibration; + struct device_node *np = pdev->dev.of_node; + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); + + if (of_property_read_u32_array(np, "fsl,tmu-range", range, 4)) { + dev_err(&pdev->dev, "missing calibration range.\n"); + return -ENODEV; + } + + /* Init temperature range registers */ + tmu_write(data, range[0], &data->regs->ttr0cr); + tmu_write(data, range[1], &data->regs->ttr1cr); + tmu_write(data, range[2], &data->regs->ttr2cr); + tmu_write(data, range[3], &data->regs->ttr3cr); + + calibration = of_get_property(np, "fsl,tmu-calibration", &len); + if (calibration == NULL || len % 8) { + dev_err(&pdev->dev, "invalid calibration data.\n"); + return -ENODEV; + } + + for (i = 0; i < len; i += 8, calibration += 2) { + val = of_read_number(calibration, 1); + tmu_write(data, val, &data->regs->ttcfgr); + val = of_read_number(calibration + 1, 1); + tmu_write(data, val, &data->regs->tscfgr); + } + + return 0; +} + +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) +{ + /* Disable interrupt, using polling instead */ + tmu_write(data, TIER_DISABLE, &data->regs->tier); + + /* Set update_interval */ + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); + + /* Disable monitoring */ + tmu_write(data, TMR_DISABLE, &data->regs->tmr); +} + +static struct thermal_zone_of_device_ops tmu_tz_ops = { + .get_temp = tmu_get_temp, +}; + +static int qoriq_tmu_probe(struct platform_device *pdev) +{ + int ret; + const struct thermal_trip *trip; + struct qoriq_tmu_data *data; + struct device_node *np = pdev->dev.of_node; + u32 site = 0; + + if (!np) { + dev_err(&pdev->dev, "Device OF-Node is NULL"); + return -ENODEV; + } + + data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + platform_set_drvdata(pdev, data); + + data->little_endian = of_property_read_bool(np, "little-endian"); + + data->sensor_id = qoriq_tmu_get_sensor_id(); + if (data->sensor_id < 0) { + dev_err(&pdev->dev, "Failed to get sensor id\n"); + ret = -ENODEV; + goto err_iomap; + } + + data->regs = of_iomap(np, 0); + if (!data->regs) { + dev_err(&pdev->dev, "Failed to get memory region\n"); + ret = -ENODEV; + goto err_iomap; + } + + qoriq_tmu_init_device(data); /* TMU initialization */ + + ret = qoriq_tmu_calibration(pdev); /* TMU calibration */ + if (ret < 0) + goto err_tmu; + + data->tz = thermal_zone_of_sensor_register(&pdev->dev, data->sensor_id, + data, &tmu_tz_ops); + if (IS_ERR(data->tz)) { + ret = PTR_ERR(data->tz); + dev_err(&pdev->dev, + "Failed to register thermal zone device %d\n", ret); + goto err_tmu; + } + + trip = of_thermal_get_trip_points(data->tz); + + /* Enable monitoring */ + site |= 0x1 << (15 - data->sensor_id); + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); + + return 0; + +err_tmu: + iounmap(data->regs); + +err_iomap: + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int qoriq_tmu_remove(struct platform_device *pdev) +{ + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); + + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); + + /* Disable monitoring */ + tmu_write(data, TMR_DISABLE, &data->regs->tmr); + + iounmap(data->regs); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int qoriq_tmu_suspend(struct device *dev) +{ + u32 tmr; + struct qoriq_tmu_data *data = dev_get_drvdata(dev); + + /* Disable monitoring */ + tmr = tmu_read(data, &data->regs->tmr); + tmr &= ~TMR_ME; + tmu_write(data, tmr, &data->regs->tmr); + + return 0; +} + +static int qoriq_tmu_resume(struct device *dev) +{ + u32 tmr; + struct qoriq_tmu_data *data = dev_get_drvdata(dev); + + /* Enable monitoring */ + tmr = tmu_read(data, &data->regs->tmr); + tmr |= TMR_ME; + tmu_write(data, tmr, &data->regs->tmr); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, + qoriq_tmu_suspend, qoriq_tmu_resume); + +static const struct of_device_id qoriq_tmu_match[] = { + { .compatible = "fsl,qoriq-tmu", }, + {}, +}; +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); + +static struct platform_driver qoriq_tmu = { + .driver = { + .name = "qoriq_thermal", + .pm = &qoriq_tmu_pm_ops, + .of_match_table = qoriq_tmu_match, + }, + .probe = qoriq_tmu_probe, + .remove = qoriq_tmu_remove, +}; +module_platform_driver(qoriq_tmu); + +MODULE_AUTHOR("Jia Hongtao "); +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index 5f817923f374..73e5fee6cf1d 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c @@ -31,6 +31,8 @@ #include #include +#include "thermal_hwmon.h" + #define IDLE_INTERVAL 5000 #define COMMON_STR 0x00 @@ -75,6 +77,8 @@ struct rcar_thermal_priv { #define rcar_priv_to_dev(priv) ((priv)->common->dev) #define rcar_has_irq_support(priv) ((priv)->common->base) #define rcar_id_to_shift(priv) ((priv)->id * 8) +#define rcar_of_data(dev) ((unsigned long)of_device_get_match_data(dev)) +#define rcar_use_of_thermal(dev) (rcar_of_data(dev) == USE_OF_THERMAL) #define USE_OF_THERMAL 1 static const struct of_device_id rcar_thermal_dt_ids[] = { @@ -354,7 +358,8 @@ static void rcar_thermal_work(struct work_struct *work) return; if (nctemp != cctemp) - thermal_zone_device_update(priv->zone); + thermal_zone_device_update(priv->zone, + THERMAL_EVENT_UNSPECIFIED); } static u32 rcar_thermal_had_changed(struct rcar_thermal_priv *priv, u32 status) @@ -415,7 +420,10 @@ static int rcar_thermal_remove(struct platform_device *pdev) rcar_thermal_for_each_priv(priv, common) { rcar_thermal_irq_disable(priv); - thermal_zone_device_unregister(priv->zone); + if (rcar_use_of_thermal(dev)) + thermal_remove_hwmon_sysfs(priv->zone); + else + thermal_zone_device_unregister(priv->zone); } pm_runtime_put(dev); @@ -430,7 +438,6 @@ static int rcar_thermal_probe(struct platform_device *pdev) struct rcar_thermal_priv *priv; struct device *dev = &pdev->dev; struct resource *res, *irq; - unsigned long of_data = (unsigned long)of_device_get_match_data(dev); int mres = 0; int i; int ret = -ENODEV; @@ -491,7 +498,7 @@ static int rcar_thermal_probe(struct platform_device *pdev) if (ret < 0) goto error_unregister; - if (of_data == USE_OF_THERMAL) + if (rcar_use_of_thermal(dev)) priv->zone = devm_thermal_zone_of_sensor_register( dev, i, priv, &rcar_thermal_zone_of_ops); @@ -508,6 +515,17 @@ static int rcar_thermal_probe(struct platform_device *pdev) goto error_unregister; } + if (rcar_use_of_thermal(dev)) { + /* + * thermal_zone doesn't enable hwmon as default, + * but, enable it here to keep compatible + */ + priv->zone->tzp->no_hwmon = false; + ret = thermal_add_hwmon_sysfs(priv->zone); + if (ret) + goto error_unregister; + } + rcar_thermal_irq_enable(priv); list_move_tail(&priv->list, &common->head); diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 5d491f16a866..e227a9f0acf7 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -96,6 +96,7 @@ struct chip_tsadc_table { * @initialize: SoC special initialize tsadc controller method * @irq_ack: clear the interrupt * @get_temp: get the temperature + * @set_alarm_temp: set the high temperature interrupt * @set_tshut_temp: set the hardware-controlled shutdown temperature * @set_tshut_mode: set the hardware-controlled shutdown mode * @table: the chip-specific conversion table @@ -119,6 +120,8 @@ struct rockchip_tsadc_chip { /* Per-sensor methods */ int (*get_temp)(struct chip_tsadc_table table, int chn, void __iomem *reg, int *temp); + void (*set_alarm_temp)(struct chip_tsadc_table table, + int chn, void __iomem *reg, int temp); void (*set_tshut_temp)(struct chip_tsadc_table table, int chn, void __iomem *reg, int temp); void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m); @@ -183,6 +186,7 @@ struct rockchip_thermal_data { #define TSADCV2_INT_EN 0x08 #define TSADCV2_INT_PD 0x0c #define TSADCV2_DATA(chn) (0x20 + (chn) * 0x04) +#define TSADCV2_COMP_INT(chn) (0x30 + (chn) * 0x04) #define TSADCV2_COMP_SHUT(chn) (0x40 + (chn) * 0x04) #define TSADCV2_HIGHT_INT_DEBOUNCE 0x60 #define TSADCV2_HIGHT_TSHUT_DEBOUNCE 0x64 @@ -207,18 +211,21 @@ struct rockchip_thermal_data { #define TSADCV2_HIGHT_INT_DEBOUNCE_COUNT 4 #define TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT 4 -#define TSADCV2_AUTO_PERIOD_TIME 250 /* msec */ -#define TSADCV2_AUTO_PERIOD_HT_TIME 50 /* msec */ +#define TSADCV2_AUTO_PERIOD_TIME 250 /* 250ms */ +#define TSADCV2_AUTO_PERIOD_HT_TIME 50 /* 50ms */ +#define TSADCV3_AUTO_PERIOD_TIME 1875 /* 2.5ms */ +#define TSADCV3_AUTO_PERIOD_HT_TIME 1875 /* 2.5ms */ + #define TSADCV2_USER_INTER_PD_SOC 0x340 /* 13 clocks */ #define GRF_SARADC_TESTBIT 0x0e644 #define GRF_TSADC_TESTBIT_L 0x0e648 #define GRF_TSADC_TESTBIT_H 0x0e64c -#define GRF_TSADC_TSEN_PD_ON (0x30003 << 0) -#define GRF_TSADC_TSEN_PD_OFF (0x30000 << 0) #define GRF_SARADC_TESTBIT_ON (0x10001 << 2) #define GRF_TSADC_TESTBIT_H_ON (0x10001 << 2) +#define GRF_TSADC_VCM_EN_L (0x10001 << 7) +#define GRF_TSADC_VCM_EN_H (0x10001 << 7) /** * struct tsadc_table - code to temperature conversion table @@ -394,13 +401,17 @@ static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table, int temp) { int high, low, mid; + u32 error = 0; low = 0; high = table.length - 1; mid = (high + low) / 2; - if (temp < table.id[low].temp || temp > table.id[high].temp) - return 0; + /* Return mask code data when the temp is over table range */ + if (temp < table.id[low].temp || temp > table.id[high].temp) { + error = table.data_mask; + goto exit; + } while (low <= high) { if (temp == table.id[mid].temp) @@ -412,7 +423,9 @@ static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table, mid = (low + high) / 2; } - return 0; +exit: + pr_err("Invalid the conversion, error=%d\n", error); + return error; } static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code, @@ -543,14 +556,34 @@ static void rk_tsadcv3_initialize(struct regmap *grf, void __iomem *regs, /* Set interleave value to workround ic time sync issue */ writel_relaxed(TSADCV2_USER_INTER_PD_SOC, regs + TSADCV2_USER_CON); + + writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, + regs + TSADCV2_AUTO_PERIOD); + writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT, + regs + TSADCV2_HIGHT_INT_DEBOUNCE); + writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, + regs + TSADCV2_AUTO_PERIOD_HT); + writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, + regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE); + } else { - regmap_write(grf, GRF_TSADC_TESTBIT_L, GRF_TSADC_TSEN_PD_ON); - mdelay(10); - regmap_write(grf, GRF_TSADC_TESTBIT_L, GRF_TSADC_TSEN_PD_OFF); + /* Enable the voltage common mode feature */ + regmap_write(grf, GRF_TSADC_TESTBIT_L, GRF_TSADC_VCM_EN_L); + regmap_write(grf, GRF_TSADC_TESTBIT_H, GRF_TSADC_VCM_EN_H); + usleep_range(15, 100); /* The spec note says at least 15 us */ regmap_write(grf, GRF_SARADC_TESTBIT, GRF_SARADC_TESTBIT_ON); regmap_write(grf, GRF_TSADC_TESTBIT_H, GRF_TSADC_TESTBIT_H_ON); usleep_range(90, 200); /* The spec note says at least 90 us */ + + writel_relaxed(TSADCV3_AUTO_PERIOD_TIME, + regs + TSADCV2_AUTO_PERIOD); + writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT, + regs + TSADCV2_HIGHT_INT_DEBOUNCE); + writel_relaxed(TSADCV3_AUTO_PERIOD_HT_TIME, + regs + TSADCV2_AUTO_PERIOD_HT); + writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, + regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE); } if (tshut_polarity == TSHUT_HIGH_ACTIVE) @@ -559,14 +592,6 @@ static void rk_tsadcv3_initialize(struct regmap *grf, void __iomem *regs, else writel_relaxed(0U & ~TSADCV2_AUTO_TSHUT_POLARITY_HIGH, regs + TSADCV2_AUTO_CON); - - writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD); - writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT, - regs + TSADCV2_HIGHT_INT_DEBOUNCE); - writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, - regs + TSADCV2_AUTO_PERIOD_HT); - writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, - regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE); } static void rk_tsadcv2_irq_ack(void __iomem *regs) @@ -628,12 +653,34 @@ static int rk_tsadcv2_get_temp(struct chip_tsadc_table table, return rk_tsadcv2_code_to_temp(table, val, temp); } +static void rk_tsadcv2_alarm_temp(struct chip_tsadc_table table, + int chn, void __iomem *regs, int temp) +{ + u32 alarm_value, int_en; + + /* Make sure the value is valid */ + alarm_value = rk_tsadcv2_temp_to_code(table, temp); + if (alarm_value == table.data_mask) + return; + + writel_relaxed(alarm_value & table.data_mask, + regs + TSADCV2_COMP_INT(chn)); + + int_en = readl_relaxed(regs + TSADCV2_INT_EN); + int_en |= TSADCV2_INT_SRC_EN(chn); + writel_relaxed(int_en, regs + TSADCV2_INT_EN); +} + static void rk_tsadcv2_tshut_temp(struct chip_tsadc_table table, int chn, void __iomem *regs, int temp) { u32 tshut_value, val; + /* Make sure the value is valid */ tshut_value = rk_tsadcv2_temp_to_code(table, temp); + if (tshut_value == table.data_mask) + return; + writel_relaxed(tshut_value, regs + TSADCV2_COMP_SHUT(chn)); /* TSHUT will be valid */ @@ -670,6 +717,7 @@ static const struct rockchip_tsadc_chip rk3228_tsadc_data = { .irq_ack = rk_tsadcv3_irq_ack, .control = rk_tsadcv3_control, .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, .set_tshut_temp = rk_tsadcv2_tshut_temp, .set_tshut_mode = rk_tsadcv2_tshut_mode, @@ -694,6 +742,7 @@ static const struct rockchip_tsadc_chip rk3288_tsadc_data = { .irq_ack = rk_tsadcv2_irq_ack, .control = rk_tsadcv2_control, .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, .set_tshut_temp = rk_tsadcv2_tshut_temp, .set_tshut_mode = rk_tsadcv2_tshut_mode, @@ -718,6 +767,7 @@ static const struct rockchip_tsadc_chip rk3366_tsadc_data = { .irq_ack = rk_tsadcv3_irq_ack, .control = rk_tsadcv3_control, .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, .set_tshut_temp = rk_tsadcv2_tshut_temp, .set_tshut_mode = rk_tsadcv2_tshut_mode, @@ -742,6 +792,7 @@ static const struct rockchip_tsadc_chip rk3368_tsadc_data = { .irq_ack = rk_tsadcv2_irq_ack, .control = rk_tsadcv2_control, .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, .set_tshut_temp = rk_tsadcv2_tshut_temp, .set_tshut_mode = rk_tsadcv2_tshut_mode, @@ -766,6 +817,7 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = { .irq_ack = rk_tsadcv3_irq_ack, .control = rk_tsadcv3_control, .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, .set_tshut_temp = rk_tsadcv2_tshut_temp, .set_tshut_mode = rk_tsadcv2_tshut_mode, @@ -821,11 +873,27 @@ static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev) thermal->chip->irq_ack(thermal->regs); for (i = 0; i < thermal->chip->chn_num; i++) - thermal_zone_device_update(thermal->sensors[i].tzd); + thermal_zone_device_update(thermal->sensors[i].tzd, + THERMAL_EVENT_UNSPECIFIED); return IRQ_HANDLED; } +static int rockchip_thermal_set_trips(void *_sensor, int low, int high) +{ + struct rockchip_thermal_sensor *sensor = _sensor; + struct rockchip_thermal_data *thermal = sensor->thermal; + const struct rockchip_tsadc_chip *tsadc = thermal->chip; + + dev_dbg(&thermal->pdev->dev, "%s: sensor %d: low: %d, high %d\n", + __func__, sensor->id, low, high); + + tsadc->set_alarm_temp(tsadc->table, + sensor->id, thermal->regs, high); + + return 0; +} + static int rockchip_thermal_get_temp(void *_sensor, int *out_temp) { struct rockchip_thermal_sensor *sensor = _sensor; @@ -843,6 +911,7 @@ static int rockchip_thermal_get_temp(void *_sensor, int *out_temp) static const struct thermal_zone_of_device_ops rockchip_of_thermal_ops = { .get_temp = rockchip_thermal_get_temp, + .set_trips = rockchip_thermal_set_trips, }; static int rockchip_configure_from_dt(struct device *dev, diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index f3ce94ec73b5..ad1186dd6132 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -225,7 +225,7 @@ static void exynos_report_trigger(struct exynos_tmu_data *p) return; } - thermal_zone_device_update(tz); + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); mutex_lock(&tz->lock); /* Find the level for which trip happened */ diff --git a/drivers/thermal/st/st_thermal_memmap.c b/drivers/thermal/st/st_thermal_memmap.c index fc0c9e198710..91d42319de27 100644 --- a/drivers/thermal/st/st_thermal_memmap.c +++ b/drivers/thermal/st/st_thermal_memmap.c @@ -42,7 +42,8 @@ static irqreturn_t st_mmap_thermal_trip_handler(int irq, void *sdata) { struct st_thermal_sensor *sensor = sdata; - thermal_zone_device_update(sensor->thermal_dev); + thermal_zone_device_update(sensor->thermal_dev, + THERMAL_EVENT_UNSPECIFIED); return IRQ_HANDLED; } diff --git a/drivers/thermal/tango_thermal.c b/drivers/thermal/tango_thermal.c index 70e0d9f406e9..201304aeafeb 100644 --- a/drivers/thermal/tango_thermal.c +++ b/drivers/thermal/tango_thermal.c @@ -64,6 +64,12 @@ static const struct thermal_zone_of_device_ops ops = { .get_temp = tango_get_temp, }; +static void tango_thermal_init(struct tango_thermal_priv *priv) +{ + writel(0, priv->base + TEMPSI_CFG); + writel(CMD_ON, priv->base + TEMPSI_CMD); +} + static int tango_thermal_probe(struct platform_device *pdev) { struct resource *res; @@ -79,14 +85,22 @@ static int tango_thermal_probe(struct platform_device *pdev) if (IS_ERR(priv->base)) return PTR_ERR(priv->base); + platform_set_drvdata(pdev, priv); priv->thresh_idx = IDX_MIN; - writel(0, priv->base + TEMPSI_CFG); - writel(CMD_ON, priv->base + TEMPSI_CMD); + tango_thermal_init(priv); tzdev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, priv, &ops); return PTR_ERR_OR_ZERO(tzdev); } +static int __maybe_unused tango_thermal_resume(struct device *dev) +{ + tango_thermal_init(dev_get_drvdata(dev)); + return 0; +} + +static SIMPLE_DEV_PM_OPS(tango_thermal_pm, NULL, tango_thermal_resume); + static const struct of_device_id tango_sensor_ids[] = { { .compatible = "sigma,smp8758-thermal", @@ -99,6 +113,7 @@ static struct platform_driver tango_thermal_driver = { .driver = { .name = "tango-thermal", .of_match_table = tango_sensor_ids, + .pm = &tango_thermal_pm, }, }; diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c index b8651726201e..7d2db23d71a3 100644 --- a/drivers/thermal/tegra/soctherm.c +++ b/drivers/thermal/tegra/soctherm.c @@ -30,6 +30,7 @@ #include +#include "../thermal_core.h" #include "soctherm.h" #define SENSOR_CONFIG0 0 @@ -67,35 +68,228 @@ #define READBACK_ADD_HALF BIT(7) #define READBACK_NEGATE BIT(0) +/* + * THERMCTL_LEVEL0_GROUP_CPU is defined in soctherm.h + * because it will be used by tegraxxx_soctherm.c + */ +#define THERMCTL_LVL0_CPU0_EN_MASK BIT(8) +#define THERMCTL_LVL0_CPU0_CPU_THROT_MASK (0x3 << 5) +#define THERMCTL_LVL0_CPU0_CPU_THROT_LIGHT 0x1 +#define THERMCTL_LVL0_CPU0_CPU_THROT_HEAVY 0x2 +#define THERMCTL_LVL0_CPU0_GPU_THROT_MASK (0x3 << 3) +#define THERMCTL_LVL0_CPU0_GPU_THROT_LIGHT 0x1 +#define THERMCTL_LVL0_CPU0_GPU_THROT_HEAVY 0x2 +#define THERMCTL_LVL0_CPU0_MEM_THROT_MASK BIT(2) +#define THERMCTL_LVL0_CPU0_STATUS_MASK 0x3 + +#define THERMCTL_LVL0_UP_STATS 0x10 +#define THERMCTL_LVL0_DN_STATS 0x14 + +#define THERMCTL_STATS_CTL 0x94 +#define STATS_CTL_CLR_DN 0x8 +#define STATS_CTL_EN_DN 0x4 +#define STATS_CTL_CLR_UP 0x2 +#define STATS_CTL_EN_UP 0x1 + +#define THROT_GLOBAL_CFG 0x400 +#define THROT_GLOBAL_ENB_MASK BIT(0) + +#define CPU_PSKIP_STATUS 0x418 +#define XPU_PSKIP_STATUS_M_MASK (0xff << 12) +#define XPU_PSKIP_STATUS_N_MASK (0xff << 4) +#define XPU_PSKIP_STATUS_SW_OVERRIDE_MASK BIT(1) +#define XPU_PSKIP_STATUS_ENABLED_MASK BIT(0) + +#define THROT_PRIORITY_LOCK 0x424 +#define THROT_PRIORITY_LOCK_PRIORITY_MASK 0xff + +#define THROT_STATUS 0x428 +#define THROT_STATUS_BREACH_MASK BIT(12) +#define THROT_STATUS_STATE_MASK (0xff << 4) +#define THROT_STATUS_ENABLED_MASK BIT(0) + +#define THROT_PSKIP_CTRL_LITE_CPU 0x430 +#define THROT_PSKIP_CTRL_ENABLE_MASK BIT(31) +#define THROT_PSKIP_CTRL_DIVIDEND_MASK (0xff << 8) +#define THROT_PSKIP_CTRL_DIVISOR_MASK 0xff +#define THROT_PSKIP_CTRL_VECT_GPU_MASK (0x7 << 16) +#define THROT_PSKIP_CTRL_VECT_CPU_MASK (0x7 << 8) +#define THROT_PSKIP_CTRL_VECT2_CPU_MASK 0x7 + +#define THROT_VECT_NONE 0x0 /* 3'b000 */ +#define THROT_VECT_LOW 0x1 /* 3'b001 */ +#define THROT_VECT_MED 0x3 /* 3'b011 */ +#define THROT_VECT_HIGH 0x7 /* 3'b111 */ + +#define THROT_PSKIP_RAMP_LITE_CPU 0x434 +#define THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK BIT(31) +#define THROT_PSKIP_RAMP_DURATION_MASK (0xffff << 8) +#define THROT_PSKIP_RAMP_STEP_MASK 0xff + +#define THROT_PRIORITY_LITE 0x444 +#define THROT_PRIORITY_LITE_PRIO_MASK 0xff + +#define THROT_DELAY_LITE 0x448 +#define THROT_DELAY_LITE_DELAY_MASK 0xff + +/* car register offsets needed for enabling HW throttling */ +#define CAR_SUPER_CCLKG_DIVIDER 0x36c +#define CDIVG_USE_THERM_CONTROLS_MASK BIT(30) + +/* ccroc register offsets needed for enabling HW throttling for Tegra132 */ +#define CCROC_SUPER_CCLKG_DIVIDER 0x024 + +#define CCROC_GLOBAL_CFG 0x148 + +#define CCROC_THROT_PSKIP_RAMP_CPU 0x150 +#define CCROC_THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK BIT(31) +#define CCROC_THROT_PSKIP_RAMP_DURATION_MASK (0xffff << 8) +#define CCROC_THROT_PSKIP_RAMP_STEP_MASK 0xff + +#define CCROC_THROT_PSKIP_CTRL_CPU 0x154 +#define CCROC_THROT_PSKIP_CTRL_ENB_MASK BIT(31) +#define CCROC_THROT_PSKIP_CTRL_DIVIDEND_MASK (0xff << 8) +#define CCROC_THROT_PSKIP_CTRL_DIVISOR_MASK 0xff + /* get val from register(r) mask bits(m) */ #define REG_GET_MASK(r, m) (((r) & (m)) >> (ffs(m) - 1)) /* set val(v) to mask bits(m) of register(r) */ #define REG_SET_MASK(r, m, v) (((r) & ~(m)) | \ (((v) & (m >> (ffs(m) - 1))) << (ffs(m) - 1))) +/* get dividend from the depth */ +#define THROT_DEPTH_DIVIDEND(depth) ((256 * (100 - (depth)) / 100) - 1) + +/* get THROT_PSKIP_xxx offset per LIGHT/HEAVY throt and CPU/GPU dev */ +#define THROT_OFFSET 0x30 +#define THROT_PSKIP_CTRL(throt, dev) (THROT_PSKIP_CTRL_LITE_CPU + \ + (THROT_OFFSET * throt) + (8 * dev)) +#define THROT_PSKIP_RAMP(throt, dev) (THROT_PSKIP_RAMP_LITE_CPU + \ + (THROT_OFFSET * throt) + (8 * dev)) + +/* get THROT_xxx_CTRL offset per LIGHT/HEAVY throt */ +#define THROT_PRIORITY_CTRL(throt) (THROT_PRIORITY_LITE + \ + (THROT_OFFSET * throt)) +#define THROT_DELAY_CTRL(throt) (THROT_DELAY_LITE + \ + (THROT_OFFSET * throt)) + +/* get CCROC_THROT_PSKIP_xxx offset per HIGH/MED/LOW vect*/ +#define CCROC_THROT_OFFSET 0x0c +#define CCROC_THROT_PSKIP_CTRL_CPU_REG(vect) (CCROC_THROT_PSKIP_CTRL_CPU + \ + (CCROC_THROT_OFFSET * vect)) +#define CCROC_THROT_PSKIP_RAMP_CPU_REG(vect) (CCROC_THROT_PSKIP_RAMP_CPU + \ + (CCROC_THROT_OFFSET * vect)) + +/* get THERMCTL_LEVELx offset per CPU/GPU/MEM/TSENSE rg and LEVEL0~3 lv */ +#define THERMCTL_LVL_REGS_SIZE 0x20 +#define THERMCTL_LVL_REG(rg, lv) ((rg) + ((lv) * THERMCTL_LVL_REGS_SIZE)) + static const int min_low_temp = -127000; static const int max_high_temp = 127000; +enum soctherm_throttle_id { + THROTTLE_LIGHT = 0, + THROTTLE_HEAVY, + THROTTLE_SIZE, +}; + +enum soctherm_throttle_dev_id { + THROTTLE_DEV_CPU = 0, + THROTTLE_DEV_GPU, + THROTTLE_DEV_SIZE, +}; + +static const char *const throt_names[] = { + [THROTTLE_LIGHT] = "light", + [THROTTLE_HEAVY] = "heavy", +}; + +struct tegra_soctherm; struct tegra_thermctl_zone { void __iomem *reg; struct device *dev; + struct tegra_soctherm *ts; struct thermal_zone_device *tz; const struct tegra_tsensor_group *sg; }; +struct soctherm_throt_cfg { + const char *name; + unsigned int id; + u8 priority; + u8 cpu_throt_level; + u32 cpu_throt_depth; + struct thermal_cooling_device *cdev; + bool init; +}; + struct tegra_soctherm { struct reset_control *reset; struct clk *clock_tsensor; struct clk *clock_soctherm; void __iomem *regs; - struct thermal_zone_device **thermctl_tzs; + void __iomem *clk_regs; + void __iomem *ccroc_regs; u32 *calib; + struct thermal_zone_device **thermctl_tzs; struct tegra_soctherm_soc *soc; + struct soctherm_throt_cfg throt_cfgs[THROTTLE_SIZE]; + struct dentry *debugfs_dir; }; +/** + * clk_writel() - writes a value to a CAR register + * @ts: pointer to a struct tegra_soctherm + * @v: the value to write + * @reg: the register offset + * + * Writes @v to @reg. No return value. + */ +static inline void clk_writel(struct tegra_soctherm *ts, u32 value, u32 reg) +{ + writel(value, (ts->clk_regs + reg)); +} + +/** + * clk_readl() - reads specified register from CAR IP block + * @ts: pointer to a struct tegra_soctherm + * @reg: register address to be read + * + * Return: the value of the register + */ +static inline u32 clk_readl(struct tegra_soctherm *ts, u32 reg) +{ + return readl(ts->clk_regs + reg); +} + +/** + * ccroc_writel() - writes a value to a CCROC register + * @ts: pointer to a struct tegra_soctherm + * @v: the value to write + * @reg: the register offset + * + * Writes @v to @reg. No return value. + */ +static inline void ccroc_writel(struct tegra_soctherm *ts, u32 value, u32 reg) +{ + writel(value, (ts->ccroc_regs + reg)); +} + +/** + * ccroc_readl() - reads specified register from CCROC IP block + * @ts: pointer to a struct tegra_soctherm + * @reg: register address to be read + * + * Return: the value of the register + */ +static inline u32 ccroc_readl(struct tegra_soctherm *ts, u32 reg) +{ + return readl(ts->ccroc_regs + reg); +} + static void enable_tsensor(struct tegra_soctherm *tegra, unsigned int i) { const struct tegra_tsensor *sensor = &tegra->soc->tsensors[i]; @@ -150,11 +344,17 @@ static int tegra_thermctl_get_temp(void *data, int *out_temp) static int thermtrip_program(struct device *dev, const struct tegra_tsensor_group *sg, int trip_temp); +static int +throttrip_program(struct device *dev, const struct tegra_tsensor_group *sg, + struct soctherm_throt_cfg *stc, int trip_temp); +static struct soctherm_throt_cfg * +find_throttle_cfg_by_name(struct tegra_soctherm *ts, const char *name); static int tegra_thermctl_set_trip_temp(void *data, int trip, int temp) { struct tegra_thermctl_zone *zone = data; struct thermal_zone_device *tz = zone->tz; + struct tegra_soctherm *ts = zone->ts; const struct tegra_tsensor_group *sg = zone->sg; struct device *dev = zone->dev; enum thermal_trip_type type; @@ -167,10 +367,29 @@ static int tegra_thermctl_set_trip_temp(void *data, int trip, int temp) if (ret) return ret; - if (type != THERMAL_TRIP_CRITICAL) - return 0; + if (type == THERMAL_TRIP_CRITICAL) { + return thermtrip_program(dev, sg, temp); + } else if (type == THERMAL_TRIP_HOT) { + int i; - return thermtrip_program(dev, sg, temp); + for (i = 0; i < THROTTLE_SIZE; i++) { + struct thermal_cooling_device *cdev; + struct soctherm_throt_cfg *stc; + + if (!ts->throt_cfgs[i].init) + continue; + + cdev = ts->throt_cfgs[i].cdev; + if (get_thermal_instance(tz, cdev, trip)) + stc = find_throttle_cfg_by_name(ts, cdev->type); + else + continue; + + return throttrip_program(dev, sg, stc, temp); + } + } + + return 0; } static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = { @@ -237,15 +456,111 @@ static int thermtrip_program(struct device *dev, return 0; } +/** + * throttrip_program() - Configures the hardware to throttle the + * pulse if a given sensor group reaches a given temperature + * @dev: ptr to the struct device for the SOC_THERM IP block + * @sg: pointer to the sensor group to set the thermtrip temperature for + * @stc: pointer to the throttle need to be triggered + * @trip_temp: the temperature in millicelsius to trigger the thermal trip at + * + * Sets the thermal trip threshold and throttle event of the given sensor + * group. If this threshold is crossed, the hardware will trigger the + * throttle. + * + * Note that, although @trip_temp is specified in millicelsius, the + * hardware is programmed in degrees Celsius. + * + * Return: 0 upon success, or %-EINVAL upon failure. + */ +static int throttrip_program(struct device *dev, + const struct tegra_tsensor_group *sg, + struct soctherm_throt_cfg *stc, + int trip_temp) +{ + struct tegra_soctherm *ts = dev_get_drvdata(dev); + int temp, cpu_throt, gpu_throt; + unsigned int throt; + u32 r, reg_off; + + if (!dev || !sg || !stc || !stc->init) + return -EINVAL; + + temp = enforce_temp_range(dev, trip_temp) / ts->soc->thresh_grain; + + /* Hardcode LIGHT on LEVEL1 and HEAVY on LEVEL2 */ + throt = stc->id; + reg_off = THERMCTL_LVL_REG(sg->thermctl_lvl0_offset, throt + 1); + + if (throt == THROTTLE_LIGHT) { + cpu_throt = THERMCTL_LVL0_CPU0_CPU_THROT_LIGHT; + gpu_throt = THERMCTL_LVL0_CPU0_GPU_THROT_LIGHT; + } else { + cpu_throt = THERMCTL_LVL0_CPU0_CPU_THROT_HEAVY; + gpu_throt = THERMCTL_LVL0_CPU0_GPU_THROT_HEAVY; + if (throt != THROTTLE_HEAVY) + dev_warn(dev, + "invalid throt id %d - assuming HEAVY", + throt); + } + + r = readl(ts->regs + reg_off); + r = REG_SET_MASK(r, sg->thermctl_lvl0_up_thresh_mask, temp); + r = REG_SET_MASK(r, sg->thermctl_lvl0_dn_thresh_mask, temp); + r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_CPU_THROT_MASK, cpu_throt); + r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_GPU_THROT_MASK, gpu_throt); + r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_EN_MASK, 1); + writel(r, ts->regs + reg_off); + + return 0; +} + +static struct soctherm_throt_cfg * +find_throttle_cfg_by_name(struct tegra_soctherm *ts, const char *name) +{ + unsigned int i; + + for (i = 0; ts->throt_cfgs[i].name; i++) + if (!strcmp(ts->throt_cfgs[i].name, name)) + return &ts->throt_cfgs[i]; + + return NULL; +} + +static int get_hot_temp(struct thermal_zone_device *tz, int *trip, int *temp) +{ + int ntrips, i, ret; + enum thermal_trip_type type; + + ntrips = of_thermal_get_ntrips(tz); + if (ntrips <= 0) + return -EINVAL; + + for (i = 0; i < ntrips; i++) { + ret = tz->ops->get_trip_type(tz, i, &type); + if (ret) + return -EINVAL; + if (type == THERMAL_TRIP_HOT) { + ret = tz->ops->get_trip_temp(tz, i, temp); + if (!ret) + *trip = i; + + return ret; + } + } + + return -EINVAL; +} + /** * tegra_soctherm_set_hwtrips() - set HW trip point from DT data * @dev: struct device * of the SOC_THERM instance * * Configure the SOC_THERM HW trip points, setting "THERMTRIP" - * trip points , using "critical" type trip_temp from thermal - * zone. - * After they have been configured, THERMTRIP will take action - * when the configured SoC thermal sensor group reaches a + * "THROTTLE" trip points , using "critical" or "hot" type trip_temp + * from thermal zone. + * After they have been configured, THERMTRIP or THROTTLE will take + * action when the configured SoC thermal sensor group reaches a * certain temperature. * * Return: 0 upon success, or a negative error code on failure. @@ -254,19 +569,24 @@ static int thermtrip_program(struct device *dev, * THERMTRIP has been enabled successfully when a message similar to * this one appears on the serial console: * "thermtrip: will shut down when sensor group XXX reaches YYYYYY mC" + * THROTTLE has been enabled successfully when a message similar to + * this one appears on the serial console: + * ""throttrip: will throttle when sensor group XXX reaches YYYYYY mC" */ static int tegra_soctherm_set_hwtrips(struct device *dev, const struct tegra_tsensor_group *sg, struct thermal_zone_device *tz) { - int temperature; + struct tegra_soctherm *ts = dev_get_drvdata(dev); + struct soctherm_throt_cfg *stc; + int i, trip, temperature; int ret; ret = tz->ops->get_crit_temp(tz, &temperature); if (ret) { dev_warn(dev, "thermtrip: %s: missing critical temperature\n", sg->name); - return ret; + goto set_throttle; } ret = thermtrip_program(dev, sg, temperature); @@ -280,6 +600,43 @@ static int tegra_soctherm_set_hwtrips(struct device *dev, "thermtrip: will shut down when %s reaches %d mC\n", sg->name, temperature); +set_throttle: + ret = get_hot_temp(tz, &trip, &temperature); + if (ret) { + dev_warn(dev, "throttrip: %s: missing hot temperature\n", + sg->name); + return 0; + } + + for (i = 0; i < THROTTLE_SIZE; i++) { + struct thermal_cooling_device *cdev; + + if (!ts->throt_cfgs[i].init) + continue; + + cdev = ts->throt_cfgs[i].cdev; + if (get_thermal_instance(tz, cdev, trip)) + stc = find_throttle_cfg_by_name(ts, cdev->type); + else + continue; + + ret = throttrip_program(dev, sg, stc, temperature); + if (ret) { + dev_err(dev, "throttrip: %s: error during enable\n", + sg->name); + return ret; + } + + dev_info(dev, + "throttrip: will throttle when %s reaches %d mC\n", + sg->name, temperature); + break; + } + + if (i == THROTTLE_SIZE) + dev_warn(dev, "throttrip: %s: missing throttle cdev\n", + sg->name); + return 0; } @@ -291,7 +648,7 @@ static int regs_show(struct seq_file *s, void *data) const struct tegra_tsensor *tsensors = ts->soc->tsensors; const struct tegra_tsensor_group **ttgs = ts->soc->ttgs; u32 r, state; - int i; + int i, level; seq_puts(s, "-----TSENSE (convert HW)-----\n"); @@ -365,6 +722,81 @@ static int regs_show(struct seq_file *s, void *data) state = REG_GET_MASK(r, SENSOR_TEMP2_MEM_TEMP_MASK); seq_printf(s, " MEM(%d)\n", translate_temp(state)); + for (i = 0; i < ts->soc->num_ttgs; i++) { + seq_printf(s, "%s:\n", ttgs[i]->name); + for (level = 0; level < 4; level++) { + s32 v; + u32 mask; + u16 off = ttgs[i]->thermctl_lvl0_offset; + + r = readl(ts->regs + THERMCTL_LVL_REG(off, level)); + + mask = ttgs[i]->thermctl_lvl0_up_thresh_mask; + state = REG_GET_MASK(r, mask); + v = sign_extend32(state, ts->soc->bptt - 1); + v *= ts->soc->thresh_grain; + seq_printf(s, " %d: Up/Dn(%d /", level, v); + + mask = ttgs[i]->thermctl_lvl0_dn_thresh_mask; + state = REG_GET_MASK(r, mask); + v = sign_extend32(state, ts->soc->bptt - 1); + v *= ts->soc->thresh_grain; + seq_printf(s, "%d ) ", v); + + mask = THERMCTL_LVL0_CPU0_EN_MASK; + state = REG_GET_MASK(r, mask); + seq_printf(s, "En(%d) ", state); + + mask = THERMCTL_LVL0_CPU0_CPU_THROT_MASK; + state = REG_GET_MASK(r, mask); + seq_puts(s, "CPU Throt"); + if (!state) + seq_printf(s, "(%s) ", "none"); + else if (state == THERMCTL_LVL0_CPU0_CPU_THROT_LIGHT) + seq_printf(s, "(%s) ", "L"); + else if (state == THERMCTL_LVL0_CPU0_CPU_THROT_HEAVY) + seq_printf(s, "(%s) ", "H"); + else + seq_printf(s, "(%s) ", "H+L"); + + mask = THERMCTL_LVL0_CPU0_GPU_THROT_MASK; + state = REG_GET_MASK(r, mask); + seq_puts(s, "GPU Throt"); + if (!state) + seq_printf(s, "(%s) ", "none"); + else if (state == THERMCTL_LVL0_CPU0_GPU_THROT_LIGHT) + seq_printf(s, "(%s) ", "L"); + else if (state == THERMCTL_LVL0_CPU0_GPU_THROT_HEAVY) + seq_printf(s, "(%s) ", "H"); + else + seq_printf(s, "(%s) ", "H+L"); + + mask = THERMCTL_LVL0_CPU0_STATUS_MASK; + state = REG_GET_MASK(r, mask); + seq_printf(s, "Status(%s)\n", + state == 0 ? "LO" : + state == 1 ? "In" : + state == 2 ? "Res" : "HI"); + } + } + + r = readl(ts->regs + THERMCTL_STATS_CTL); + seq_printf(s, "STATS: Up(%s) Dn(%s)\n", + r & STATS_CTL_EN_UP ? "En" : "--", + r & STATS_CTL_EN_DN ? "En" : "--"); + + for (level = 0; level < 4; level++) { + u16 off; + + off = THERMCTL_LVL0_UP_STATS; + r = readl(ts->regs + THERMCTL_LVL_REG(off, level)); + seq_printf(s, " Level_%d Up(%d) ", level, r); + + off = THERMCTL_LVL0_DN_STATS; + r = readl(ts->regs + THERMCTL_LVL_REG(off, level)); + seq_printf(s, "Dn(%d)\n", r); + } + r = readl(ts->regs + THERMCTL_THERMTRIP_CTL); state = REG_GET_MASK(r, ttgs[0]->thermtrip_any_en_mask); seq_printf(s, "Thermtrip Any En(%d)\n", state); @@ -376,6 +808,32 @@ static int regs_show(struct seq_file *s, void *data) seq_printf(s, "Thresh(%d)\n", state); } + r = readl(ts->regs + THROT_GLOBAL_CFG); + seq_puts(s, "\n"); + seq_printf(s, "GLOBAL THROTTLE CONFIG: 0x%08x\n", r); + + seq_puts(s, "---------------------------------------------------\n"); + r = readl(ts->regs + THROT_STATUS); + state = REG_GET_MASK(r, THROT_STATUS_BREACH_MASK); + seq_printf(s, "THROT STATUS: breach(%d) ", state); + state = REG_GET_MASK(r, THROT_STATUS_STATE_MASK); + seq_printf(s, "state(%d) ", state); + state = REG_GET_MASK(r, THROT_STATUS_ENABLED_MASK); + seq_printf(s, "enabled(%d)\n", state); + + r = readl(ts->regs + CPU_PSKIP_STATUS); + if (ts->soc->use_ccroc) { + state = REG_GET_MASK(r, XPU_PSKIP_STATUS_ENABLED_MASK); + seq_printf(s, "CPU PSKIP STATUS: enabled(%d)\n", state); + } else { + state = REG_GET_MASK(r, XPU_PSKIP_STATUS_M_MASK); + seq_printf(s, "CPU PSKIP STATUS: M(%d) ", state); + state = REG_GET_MASK(r, XPU_PSKIP_STATUS_N_MASK); + seq_printf(s, "N(%d) ", state); + state = REG_GET_MASK(r, XPU_PSKIP_STATUS_ENABLED_MASK); + seq_printf(s, "enabled(%d)\n", state); + } + return 0; } @@ -449,6 +907,326 @@ static int soctherm_clk_enable(struct platform_device *pdev, bool enable) return 0; } +static int throt_get_cdev_max_state(struct thermal_cooling_device *cdev, + unsigned long *max_state) +{ + *max_state = 1; + return 0; +} + +static int throt_get_cdev_cur_state(struct thermal_cooling_device *cdev, + unsigned long *cur_state) +{ + struct tegra_soctherm *ts = cdev->devdata; + u32 r; + + r = readl(ts->regs + THROT_STATUS); + if (REG_GET_MASK(r, THROT_STATUS_STATE_MASK)) + *cur_state = 1; + else + *cur_state = 0; + + return 0; +} + +static int throt_set_cdev_state(struct thermal_cooling_device *cdev, + unsigned long cur_state) +{ + return 0; +} + +static struct thermal_cooling_device_ops throt_cooling_ops = { + .get_max_state = throt_get_cdev_max_state, + .get_cur_state = throt_get_cdev_cur_state, + .set_cur_state = throt_set_cdev_state, +}; + +/** + * soctherm_init_hw_throt_cdev() - Parse the HW throttle configurations + * and register them as cooling devices. + */ +static void soctherm_init_hw_throt_cdev(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra_soctherm *ts = dev_get_drvdata(dev); + struct device_node *np_stc, *np_stcc; + const char *name; + u32 val; + int i, r; + + for (i = 0; i < THROTTLE_SIZE; i++) { + ts->throt_cfgs[i].name = throt_names[i]; + ts->throt_cfgs[i].id = i; + ts->throt_cfgs[i].init = false; + } + + np_stc = of_get_child_by_name(dev->of_node, "throttle-cfgs"); + if (!np_stc) { + dev_info(dev, + "throttle-cfg: no throttle-cfgs - not enabling\n"); + return; + } + + for_each_child_of_node(np_stc, np_stcc) { + struct soctherm_throt_cfg *stc; + struct thermal_cooling_device *tcd; + + name = np_stcc->name; + stc = find_throttle_cfg_by_name(ts, name); + if (!stc) { + dev_err(dev, + "throttle-cfg: could not find %s\n", name); + continue; + } + + r = of_property_read_u32(np_stcc, "nvidia,priority", &val); + if (r) { + dev_info(dev, + "throttle-cfg: %s: missing priority\n", name); + continue; + } + stc->priority = val; + + if (ts->soc->use_ccroc) { + r = of_property_read_u32(np_stcc, + "nvidia,cpu-throt-level", + &val); + if (r) { + dev_info(dev, + "throttle-cfg: %s: missing cpu-throt-level\n", + name); + continue; + } + stc->cpu_throt_level = val; + } else { + r = of_property_read_u32(np_stcc, + "nvidia,cpu-throt-percent", + &val); + if (r) { + dev_info(dev, + "throttle-cfg: %s: missing cpu-throt-percent\n", + name); + continue; + } + stc->cpu_throt_depth = val; + } + + tcd = thermal_of_cooling_device_register(np_stcc, + (char *)name, ts, + &throt_cooling_ops); + of_node_put(np_stcc); + if (IS_ERR_OR_NULL(tcd)) { + dev_err(dev, + "throttle-cfg: %s: failed to register cooling device\n", + name); + continue; + } + + stc->cdev = tcd; + stc->init = true; + } + + of_node_put(np_stc); +} + +/** + * throttlectl_cpu_level_cfg() - programs CCROC NV_THERM level config + * @level: describing the level LOW/MED/HIGH of throttling + * + * It's necessary to set up the CPU-local CCROC NV_THERM instance with + * the M/N values desired for each level. This function does this. + * + * This function pre-programs the CCROC NV_THERM levels in terms of + * pre-configured "Low", "Medium" or "Heavy" throttle levels which are + * mapped to THROT_LEVEL_LOW, THROT_LEVEL_MED and THROT_LEVEL_HVY. + */ +static void throttlectl_cpu_level_cfg(struct tegra_soctherm *ts, int level) +{ + u8 depth, dividend; + u32 r; + + switch (level) { + case TEGRA_SOCTHERM_THROT_LEVEL_LOW: + depth = 50; + break; + case TEGRA_SOCTHERM_THROT_LEVEL_MED: + depth = 75; + break; + case TEGRA_SOCTHERM_THROT_LEVEL_HIGH: + depth = 80; + break; + case TEGRA_SOCTHERM_THROT_LEVEL_NONE: + return; + default: + return; + } + + dividend = THROT_DEPTH_DIVIDEND(depth); + + /* setup PSKIP in ccroc nv_therm registers */ + r = ccroc_readl(ts, CCROC_THROT_PSKIP_RAMP_CPU_REG(level)); + r = REG_SET_MASK(r, CCROC_THROT_PSKIP_RAMP_DURATION_MASK, 0xff); + r = REG_SET_MASK(r, CCROC_THROT_PSKIP_RAMP_STEP_MASK, 0xf); + ccroc_writel(ts, r, CCROC_THROT_PSKIP_RAMP_CPU_REG(level)); + + r = ccroc_readl(ts, CCROC_THROT_PSKIP_CTRL_CPU_REG(level)); + r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_ENB_MASK, 1); + r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_DIVIDEND_MASK, dividend); + r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_DIVISOR_MASK, 0xff); + ccroc_writel(ts, r, CCROC_THROT_PSKIP_CTRL_CPU_REG(level)); +} + +/** + * throttlectl_cpu_level_select() - program CPU pulse skipper config + * @throt: the LIGHT/HEAVY of throttle event id + * + * Pulse skippers are used to throttle clock frequencies. This + * function programs the pulse skippers based on @throt and platform + * data. This function is used on SoCs which have CPU-local pulse + * skipper control, such as T13x. It programs soctherm's interface to + * Denver:CCROC NV_THERM in terms of Low, Medium and HIGH throttling + * vectors. PSKIP_BYPASS mode is set as required per HW spec. + */ +static void throttlectl_cpu_level_select(struct tegra_soctherm *ts, + enum soctherm_throttle_id throt) +{ + u32 r, throt_vect; + + /* Denver:CCROC NV_THERM interface N:3 Mapping */ + switch (ts->throt_cfgs[throt].cpu_throt_level) { + case TEGRA_SOCTHERM_THROT_LEVEL_LOW: + throt_vect = THROT_VECT_LOW; + break; + case TEGRA_SOCTHERM_THROT_LEVEL_MED: + throt_vect = THROT_VECT_MED; + break; + case TEGRA_SOCTHERM_THROT_LEVEL_HIGH: + throt_vect = THROT_VECT_HIGH; + break; + default: + throt_vect = THROT_VECT_NONE; + break; + } + + r = readl(ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU)); + r = REG_SET_MASK(r, THROT_PSKIP_CTRL_ENABLE_MASK, 1); + r = REG_SET_MASK(r, THROT_PSKIP_CTRL_VECT_CPU_MASK, throt_vect); + r = REG_SET_MASK(r, THROT_PSKIP_CTRL_VECT2_CPU_MASK, throt_vect); + writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU)); + + /* bypass sequencer in soc_therm as it is programmed in ccroc */ + r = REG_SET_MASK(0, THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK, 1); + writel(r, ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU)); +} + +/** + * throttlectl_cpu_mn() - program CPU pulse skipper configuration + * @throt: the LIGHT/HEAVY of throttle event id + * + * Pulse skippers are used to throttle clock frequencies. This + * function programs the pulse skippers based on @throt and platform + * data. This function is used for CPUs that have "remote" pulse + * skipper control, e.g., the CPU pulse skipper is controlled by the + * SOC_THERM IP block. (SOC_THERM is located outside the CPU + * complex.) + */ +static void throttlectl_cpu_mn(struct tegra_soctherm *ts, + enum soctherm_throttle_id throt) +{ + u32 r; + int depth; + u8 dividend; + + depth = ts->throt_cfgs[throt].cpu_throt_depth; + dividend = THROT_DEPTH_DIVIDEND(depth); + + r = readl(ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU)); + r = REG_SET_MASK(r, THROT_PSKIP_CTRL_ENABLE_MASK, 1); + r = REG_SET_MASK(r, THROT_PSKIP_CTRL_DIVIDEND_MASK, dividend); + r = REG_SET_MASK(r, THROT_PSKIP_CTRL_DIVISOR_MASK, 0xff); + writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU)); + + r = readl(ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU)); + r = REG_SET_MASK(r, THROT_PSKIP_RAMP_DURATION_MASK, 0xff); + r = REG_SET_MASK(r, THROT_PSKIP_RAMP_STEP_MASK, 0xf); + writel(r, ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU)); +} + +/** + * soctherm_throttle_program() - programs pulse skippers' configuration + * @throt: the LIGHT/HEAVY of the throttle event id. + * + * Pulse skippers are used to throttle clock frequencies. + * This function programs the pulse skippers. + */ +static void soctherm_throttle_program(struct tegra_soctherm *ts, + enum soctherm_throttle_id throt) +{ + u32 r; + struct soctherm_throt_cfg stc = ts->throt_cfgs[throt]; + + if (!stc.init) + return; + + /* Setup PSKIP parameters */ + if (ts->soc->use_ccroc) + throttlectl_cpu_level_select(ts, throt); + else + throttlectl_cpu_mn(ts, throt); + + r = REG_SET_MASK(0, THROT_PRIORITY_LITE_PRIO_MASK, stc.priority); + writel(r, ts->regs + THROT_PRIORITY_CTRL(throt)); + + r = REG_SET_MASK(0, THROT_DELAY_LITE_DELAY_MASK, 0); + writel(r, ts->regs + THROT_DELAY_CTRL(throt)); + + r = readl(ts->regs + THROT_PRIORITY_LOCK); + r = REG_GET_MASK(r, THROT_PRIORITY_LOCK_PRIORITY_MASK); + if (r >= stc.priority) + return; + r = REG_SET_MASK(0, THROT_PRIORITY_LOCK_PRIORITY_MASK, + stc.priority); + writel(r, ts->regs + THROT_PRIORITY_LOCK); +} + +static void tegra_soctherm_throttle(struct device *dev) +{ + struct tegra_soctherm *ts = dev_get_drvdata(dev); + u32 v; + int i; + + /* configure LOW, MED and HIGH levels for CCROC NV_THERM */ + if (ts->soc->use_ccroc) { + throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_LOW); + throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_MED); + throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_HIGH); + } + + /* Thermal HW throttle programming */ + for (i = 0; i < THROTTLE_SIZE; i++) + soctherm_throttle_program(ts, i); + + v = REG_SET_MASK(0, THROT_GLOBAL_ENB_MASK, 1); + if (ts->soc->use_ccroc) { + ccroc_writel(ts, v, CCROC_GLOBAL_CFG); + + v = ccroc_readl(ts, CCROC_SUPER_CCLKG_DIVIDER); + v = REG_SET_MASK(v, CDIVG_USE_THERM_CONTROLS_MASK, 1); + ccroc_writel(ts, v, CCROC_SUPER_CCLKG_DIVIDER); + } else { + writel(v, ts->regs + THROT_GLOBAL_CFG); + + v = clk_readl(ts, CAR_SUPER_CCLKG_DIVIDER); + v = REG_SET_MASK(v, CDIVG_USE_THERM_CONTROLS_MASK, 1); + clk_writel(ts, v, CAR_SUPER_CCLKG_DIVIDER); + } + + /* initialize stats collection */ + v = STATS_CTL_CLR_DN | STATS_CTL_EN_DN | + STATS_CTL_CLR_UP | STATS_CTL_EN_UP; + writel(v, ts->regs + THERMCTL_STATS_CTL); +} + static void soctherm_init(struct platform_device *pdev) { struct tegra_soctherm *tegra = platform_get_drvdata(pdev); @@ -475,6 +1253,9 @@ static void soctherm_init(struct platform_device *pdev) } writel(pdiv, tegra->regs + SENSOR_PDIV); writel(hotspot, tegra->regs + SENSOR_HOTSPOT_OFF); + + /* Configure hw throttle */ + tegra_soctherm_throttle(&pdev->dev); } static const struct of_device_id tegra_soctherm_of_match[] = { @@ -527,10 +1308,31 @@ static int tegra_soctherm_probe(struct platform_device *pdev) tegra->soc = soc; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "soctherm-reg"); tegra->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(tegra->regs)) + if (IS_ERR(tegra->regs)) { + dev_err(&pdev->dev, "can't get soctherm registers"); return PTR_ERR(tegra->regs); + } + + if (!tegra->soc->use_ccroc) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "car-reg"); + tegra->clk_regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(tegra->clk_regs)) { + dev_err(&pdev->dev, "can't get car clk registers"); + return PTR_ERR(tegra->clk_regs); + } + } else { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "ccroc-reg"); + tegra->ccroc_regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(tegra->ccroc_regs)) { + dev_err(&pdev->dev, "can't get ccroc registers"); + return PTR_ERR(tegra->ccroc_regs); + } + } tegra->reset = devm_reset_control_get(&pdev->dev, "soctherm"); if (IS_ERR(tegra->reset)) { @@ -580,6 +1382,8 @@ static int tegra_soctherm_probe(struct platform_device *pdev) if (err) return err; + soctherm_init_hw_throt_cdev(pdev); + soctherm_init(pdev); for (i = 0; i < soc->num_ttgs; ++i) { @@ -593,6 +1397,7 @@ static int tegra_soctherm_probe(struct platform_device *pdev) zone->reg = tegra->regs + soc->ttgs[i]->sensor_temp_offset; zone->dev = &pdev->dev; zone->sg = soc->ttgs[i]; + zone->ts = tegra; z = devm_thermal_zone_of_sensor_register(&pdev->dev, soc->ttgs[i]->id, zone, @@ -608,7 +1413,9 @@ static int tegra_soctherm_probe(struct platform_device *pdev) tegra->thermctl_tzs[soc->ttgs[i]->id] = z; /* Configure hw trip points */ - tegra_soctherm_set_hwtrips(&pdev->dev, soc->ttgs[i], z); + err = tegra_soctherm_set_hwtrips(&pdev->dev, soc->ttgs[i], z); + if (err) + goto disable_clocks; } soctherm_debug_init(pdev); @@ -661,7 +1468,12 @@ static int __maybe_unused soctherm_resume(struct device *dev) struct thermal_zone_device *tz; tz = tegra->thermctl_tzs[soc->ttgs[i]->id]; - tegra_soctherm_set_hwtrips(dev, soc->ttgs[i], tz); + err = tegra_soctherm_set_hwtrips(dev, soc->ttgs[i], tz); + if (err) { + dev_err(&pdev->dev, + "Resume failed: set hwtrips failed\n"); + return err; + } } return 0; diff --git a/drivers/thermal/tegra/soctherm.h b/drivers/thermal/tegra/soctherm.h index 28e18ec4b4c3..e96ca73fd780 100644 --- a/drivers/thermal/tegra/soctherm.h +++ b/drivers/thermal/tegra/soctherm.h @@ -15,6 +15,11 @@ #ifndef __DRIVERS_THERMAL_TEGRA_SOCTHERM_H #define __DRIVERS_THERMAL_TEGRA_SOCTHERM_H +#define THERMCTL_LEVEL0_GROUP_CPU 0x0 +#define THERMCTL_LEVEL0_GROUP_GPU 0x4 +#define THERMCTL_LEVEL0_GROUP_MEM 0x8 +#define THERMCTL_LEVEL0_GROUP_TSENSE 0xc + #define SENSOR_CONFIG2 8 #define SENSOR_CONFIG2_THERMA_MASK (0xffff << 16) #define SENSOR_CONFIG2_THERMA_SHIFT 16 @@ -65,6 +70,9 @@ struct tegra_tsensor_group { u32 thermtrip_enable_mask; u32 thermtrip_any_en_mask; u32 thermtrip_threshold_mask; + u16 thermctl_lvl0_offset; + u32 thermctl_lvl0_up_thresh_mask; + u32 thermctl_lvl0_dn_thresh_mask; }; struct tegra_tsensor_configuration { @@ -103,6 +111,8 @@ struct tegra_soctherm_soc { const unsigned int num_ttgs; const struct tegra_soctherm_fuse *tfuse; const int thresh_grain; + const unsigned int bptt; + const bool use_ccroc; }; int tegra_calc_shared_calib(const struct tegra_soctherm_fuse *tfuse, diff --git a/drivers/thermal/tegra/tegra124-soctherm.c b/drivers/thermal/tegra/tegra124-soctherm.c index beb9d36b9c8a..36768630f78c 100644 --- a/drivers/thermal/tegra/tegra124-soctherm.c +++ b/drivers/thermal/tegra/tegra124-soctherm.c @@ -28,7 +28,11 @@ #define TEGRA124_THERMTRIP_CPU_THRESH_MASK (0xff << 8) #define TEGRA124_THERMTRIP_TSENSE_THRESH_MASK 0xff +#define TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK (0xff << 17) +#define TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK (0xff << 9) + #define TEGRA124_THRESH_GRAIN 1000 +#define TEGRA124_BPTT 8 static const struct tegra_tsensor_configuration tegra124_tsensor_config = { .tall = 16300, @@ -51,6 +55,9 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_cpu = { .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA124_THERMTRIP_CPU_EN_MASK, .thermtrip_threshold_mask = TEGRA124_THERMTRIP_CPU_THRESH_MASK, + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU, + .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK, + .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group tegra124_tsensor_group_gpu = { @@ -66,6 +73,9 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_gpu = { .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA124_THERMTRIP_GPU_EN_MASK, .thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK, + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU, + .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK, + .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group tegra124_tsensor_group_pll = { @@ -79,6 +89,9 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_pll = { .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA124_THERMTRIP_TSENSE_EN_MASK, .thermtrip_threshold_mask = TEGRA124_THERMTRIP_TSENSE_THRESH_MASK, + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE, + .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK, + .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group tegra124_tsensor_group_mem = { @@ -94,6 +107,9 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_mem = { .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA124_THERMTRIP_MEM_EN_MASK, .thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK, + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM, + .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK, + .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group *tegra124_tsensor_groups[] = { @@ -193,4 +209,6 @@ const struct tegra_soctherm_soc tegra124_soctherm = { .num_ttgs = ARRAY_SIZE(tegra124_tsensor_groups), .tfuse = &tegra124_soctherm_fuse, .thresh_grain = TEGRA124_THRESH_GRAIN, + .bptt = TEGRA124_BPTT, + .use_ccroc = false, }; diff --git a/drivers/thermal/tegra/tegra132-soctherm.c b/drivers/thermal/tegra/tegra132-soctherm.c index e2aa84e1b307..97fa30501eb1 100644 --- a/drivers/thermal/tegra/tegra132-soctherm.c +++ b/drivers/thermal/tegra/tegra132-soctherm.c @@ -28,7 +28,11 @@ #define TEGRA132_THERMTRIP_CPU_THRESH_MASK (0xff << 8) #define TEGRA132_THERMTRIP_TSENSE_THRESH_MASK 0xff +#define TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK (0xff << 17) +#define TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK (0xff << 9) + #define TEGRA132_THRESH_GRAIN 1000 +#define TEGRA132_BPTT 8 static const struct tegra_tsensor_configuration tegra132_tsensor_config = { .tall = 16300, @@ -51,6 +55,9 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_cpu = { .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_CPU_EN_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_CPU_THRESH_MASK, + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU, + .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, + .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group tegra132_tsensor_group_gpu = { @@ -66,6 +73,9 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_gpu = { .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_GPU_EN_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK, + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU, + .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, + .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group tegra132_tsensor_group_pll = { @@ -79,6 +89,9 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_pll = { .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_TSENSE_EN_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_TSENSE_THRESH_MASK, + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE, + .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, + .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group tegra132_tsensor_group_mem = { @@ -94,6 +107,9 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_mem = { .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_MEM_EN_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK, + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM, + .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, + .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group *tegra132_tsensor_groups[] = { @@ -193,4 +209,6 @@ const struct tegra_soctherm_soc tegra132_soctherm = { .num_ttgs = ARRAY_SIZE(tegra132_tsensor_groups), .tfuse = &tegra132_soctherm_fuse, .thresh_grain = TEGRA132_THRESH_GRAIN, + .bptt = TEGRA132_BPTT, + .use_ccroc = true, }; diff --git a/drivers/thermal/tegra/tegra210-soctherm.c b/drivers/thermal/tegra/tegra210-soctherm.c index 19cc0ab66f0e..ad53169a8e95 100644 --- a/drivers/thermal/tegra/tegra210-soctherm.c +++ b/drivers/thermal/tegra/tegra210-soctherm.c @@ -29,7 +29,11 @@ #define TEGRA210_THERMTRIP_CPU_THRESH_MASK (0x1ff << 9) #define TEGRA210_THERMTRIP_TSENSE_THRESH_MASK 0x1ff +#define TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK (0x1ff << 18) +#define TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK (0x1ff << 9) + #define TEGRA210_THRESH_GRAIN 500 +#define TEGRA210_BPTT 9 static const struct tegra_tsensor_configuration tegra210_tsensor_config = { .tall = 16300, @@ -52,6 +56,9 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_cpu = { .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA210_THERMTRIP_CPU_EN_MASK, .thermtrip_threshold_mask = TEGRA210_THERMTRIP_CPU_THRESH_MASK, + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU, + .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK, + .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group tegra210_tsensor_group_gpu = { @@ -67,6 +74,9 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_gpu = { .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA210_THERMTRIP_GPU_EN_MASK, .thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK, + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU, + .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK, + .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group tegra210_tsensor_group_pll = { @@ -80,6 +90,9 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_pll = { .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA210_THERMTRIP_TSENSE_EN_MASK, .thermtrip_threshold_mask = TEGRA210_THERMTRIP_TSENSE_THRESH_MASK, + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE, + .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK, + .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group tegra210_tsensor_group_mem = { @@ -95,6 +108,9 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_mem = { .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA210_THERMTRIP_MEM_EN_MASK, .thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK, + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM, + .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK, + .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK, }; static const struct tegra_tsensor_group *tegra210_tsensor_groups[] = { @@ -194,4 +210,6 @@ const struct tegra_soctherm_soc tegra210_soctherm = { .num_ttgs = ARRAY_SIZE(tegra210_tsensor_groups), .tfuse = &tegra210_soctherm_fuse, .thresh_grain = TEGRA210_THRESH_GRAIN, + .bptt = TEGRA210_BPTT, + .use_ccroc = false, }; diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index e2fc6161dded..226b0b4aced6 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -520,6 +520,56 @@ exit: } EXPORT_SYMBOL_GPL(thermal_zone_get_temp); +void thermal_zone_set_trips(struct thermal_zone_device *tz) +{ + int low = -INT_MAX; + int high = INT_MAX; + int trip_temp, hysteresis; + int i, ret; + + mutex_lock(&tz->lock); + + if (!tz->ops->set_trips || !tz->ops->get_trip_hyst) + goto exit; + + for (i = 0; i < tz->trips; i++) { + int trip_low; + + tz->ops->get_trip_temp(tz, i, &trip_temp); + tz->ops->get_trip_hyst(tz, i, &hysteresis); + + trip_low = trip_temp - hysteresis; + + if (trip_low < tz->temperature && trip_low > low) + low = trip_low; + + if (trip_temp > tz->temperature && trip_temp < high) + high = trip_temp; + } + + /* No need to change trip points */ + if (tz->prev_low_trip == low && tz->prev_high_trip == high) + goto exit; + + tz->prev_low_trip = low; + tz->prev_high_trip = high; + + dev_dbg(&tz->device, + "new temperature boundaries: %d < x < %d\n", low, high); + + /* + * Set a temperature window. When this window is left the driver + * must inform the thermal core via thermal_zone_device_update. + */ + ret = tz->ops->set_trips(tz, low, high); + if (ret) + dev_err(&tz->device, "Failed to set trips: %d\n", ret); + +exit: + mutex_unlock(&tz->lock); +} +EXPORT_SYMBOL_GPL(thermal_zone_set_trips); + static void update_temperature(struct thermal_zone_device *tz) { int temp, ret; @@ -557,7 +607,8 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz) pos->initialized = false; } -void thermal_zone_device_update(struct thermal_zone_device *tz) +void thermal_zone_device_update(struct thermal_zone_device *tz, + enum thermal_notify_event event) { int count; @@ -569,6 +620,10 @@ void thermal_zone_device_update(struct thermal_zone_device *tz) update_temperature(tz); + thermal_zone_set_trips(tz); + + tz->notify_event = event; + for (count = 0; count < tz->trips; count++) handle_thermal_trip(tz, count); } @@ -579,7 +634,7 @@ static void thermal_zone_device_check(struct work_struct *work) struct thermal_zone_device *tz = container_of(work, struct thermal_zone_device, poll_queue.work); - thermal_zone_device_update(tz); + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); } /* sys I/F for thermal zone */ @@ -703,7 +758,7 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr, if (ret) return ret; - thermal_zone_device_update(tz); + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); return count; } @@ -754,6 +809,9 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr, */ ret = tz->ops->set_trip_hyst(tz, trip, temperature); + if (!ret) + thermal_zone_set_trips(tz); + return ret ? ret : count; } @@ -822,7 +880,7 @@ passive_store(struct device *dev, struct device_attribute *attr, tz->forced_passive = state; - thermal_zone_device_update(tz); + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); return count; } @@ -913,7 +971,7 @@ emul_temp_store(struct device *dev, struct device_attribute *attr, } if (!ret) - thermal_zone_device_update(tz); + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); return ret ? ret : count; } @@ -1509,7 +1567,8 @@ __thermal_cooling_device_register(struct device_node *np, mutex_lock(&thermal_list_lock); list_for_each_entry(pos, &thermal_tz_list, node) if (atomic_cmpxchg(&pos->need_update, 1, 0)) - thermal_zone_device_update(pos); + thermal_zone_device_update(pos, + THERMAL_EVENT_UNSPECIFIED); mutex_unlock(&thermal_list_lock); return cdev; @@ -1952,7 +2011,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type, thermal_zone_device_reset(tz); /* Update the new thermal zone and mark it as already updated. */ if (atomic_cmpxchg(&tz->need_update, 1, 0)) - thermal_zone_device_update(tz); + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); return tz; @@ -2069,6 +2128,36 @@ exit: } EXPORT_SYMBOL_GPL(thermal_zone_get_zone_by_name); +/** + * thermal_zone_get_slope - return the slope attribute of the thermal zone + * @tz: thermal zone device with the slope attribute + * + * Return: If the thermal zone device has a slope attribute, return it, else + * return 1. + */ +int thermal_zone_get_slope(struct thermal_zone_device *tz) +{ + if (tz && tz->tzp) + return tz->tzp->slope; + return 1; +} +EXPORT_SYMBOL_GPL(thermal_zone_get_slope); + +/** + * thermal_zone_get_offset - return the offset attribute of the thermal zone + * @tz: thermal zone device with the offset attribute + * + * Return: If the thermal zone device has a offset attribute, return it, else + * return 0. + */ +int thermal_zone_get_offset(struct thermal_zone_device *tz) +{ + if (tz && tz->tzp) + return tz->tzp->offset; + return 0; +} +EXPORT_SYMBOL_GPL(thermal_zone_get_offset); + #ifdef CONFIG_NET static const struct genl_multicast_group thermal_event_mcgrps[] = { { .name = THERMAL_GENL_MCAST_GROUP_NAME, }, @@ -2209,7 +2298,8 @@ static int thermal_pm_notify(struct notifier_block *nb, atomic_set(&in_suspend, 0); list_for_each_entry(tz, &thermal_tz_list, node) { thermal_zone_device_reset(tz); - thermal_zone_device_update(tz); + thermal_zone_device_update(tz, + THERMAL_EVENT_UNSPECIFIED); } break; default: diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c index 15c0a9ac2209..0586bd0f2bab 100644 --- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c +++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c @@ -52,7 +52,7 @@ static void ti_thermal_work(struct work_struct *work) struct ti_thermal_data *data = container_of(work, struct ti_thermal_data, thermal_wq); - thermal_zone_device_update(data->ti_thermal); + thermal_zone_device_update(data->ti_thermal, THERMAL_EVENT_UNSPECIFIED); dev_dbg(&data->ti_thermal->device, "updated thermal zone %s\n", data->ti_thermal->type); @@ -205,7 +205,7 @@ static int ti_thermal_set_mode(struct thermal_zone_device *thermal, data->mode = mode; ti_bandgap_write_update_interval(bgp, data->sensor_id, data->ti_thermal->polling_delay); - thermal_zone_device_update(data->ti_thermal); + thermal_zone_device_update(data->ti_thermal, THERMAL_EVENT_UNSPECIFIED); dev_dbg(&thermal->device, "thermal polling set for duration=%d msec\n", data->ti_thermal->polling_delay); @@ -239,7 +239,7 @@ static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal, return 0; } -static int __ti_thermal_get_trend(void *p, long *trend) +static int __ti_thermal_get_trend(void *p, int trip, enum thermal_trend *trend) { struct ti_thermal_data *data = p; struct ti_bandgap *bgp; @@ -252,22 +252,6 @@ static int __ti_thermal_get_trend(void *p, long *trend) if (ret) return ret; - *trend = tr; - - return 0; -} - -/* Get the temperature trend callback functions for thermal zone */ -static int ti_thermal_get_trend(struct thermal_zone_device *thermal, - int trip, enum thermal_trend *trend) -{ - int ret; - long tr; - - ret = __ti_thermal_get_trend(thermal->devdata, &tr); - if (ret) - return ret; - if (tr > 0) *trend = THERMAL_TREND_RAISING; else if (tr < 0) @@ -278,6 +262,13 @@ static int ti_thermal_get_trend(struct thermal_zone_device *thermal, return 0; } +/* Get the temperature trend callback functions for thermal zone */ +static int ti_thermal_get_trend(struct thermal_zone_device *thermal, + int trip, enum thermal_trend *trend) +{ + return __ti_thermal_get_trend(thermal->devdata, trip, trend); +} + /* Get critical temperature callback functions for thermal zone */ static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal, int *temp) diff --git a/drivers/thermal/user_space.c b/drivers/thermal/user_space.c index 10adcddc8821..c908150c268d 100644 --- a/drivers/thermal/user_space.c +++ b/drivers/thermal/user_space.c @@ -23,19 +23,30 @@ */ #include - +#include #include "thermal_core.h" /** * notify_user_space - Notifies user space about thermal events * @tz - thermal_zone_device + * @trip - Trip point index * * This function notifies the user space through UEvents. */ static int notify_user_space(struct thermal_zone_device *tz, int trip) { + char *thermal_prop[5]; + int i; + mutex_lock(&tz->lock); - kobject_uevent(&tz->device.kobj, KOBJ_CHANGE); + thermal_prop[0] = kasprintf(GFP_KERNEL, "NAME=%s", tz->type); + thermal_prop[1] = kasprintf(GFP_KERNEL, "TEMP=%d", tz->temperature); + thermal_prop[2] = kasprintf(GFP_KERNEL, "TRIP=%d", trip); + thermal_prop[3] = kasprintf(GFP_KERNEL, "EVENT=%d", tz->notify_event); + thermal_prop[4] = NULL; + kobject_uevent_env(&tz->device.kobj, KOBJ_CHANGE, thermal_prop); + for (i = 0; i < 4; ++i) + kfree(thermal_prop[i]); mutex_unlock(&tz->lock); return 0; } diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c index 97f0a2bd93ed..95f4c1bcdb4c 100644 --- a/drivers/thermal/x86_pkg_temp_thermal.c +++ b/drivers/thermal/x86_pkg_temp_thermal.c @@ -348,7 +348,8 @@ static void pkg_temp_thermal_threshold_work_fn(struct work_struct *work) } if (notify) { pr_debug("thermal_zone_device_update\n"); - thermal_zone_device_update(phdev->tzone); + thermal_zone_device_update(phdev->tzone, + THERMAL_EVENT_UNSPECIFIED); } } diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 88b008fb8a4e..af2f117208f1 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -284,12 +284,14 @@ config FB_PM2_FIFO_DISCONNECT config FB_ARMCLCD tristate "ARM PrimeCell PL110 support" depends on ARM || ARM64 || COMPILE_TEST - depends on FB && ARM_AMBA + depends on FB && ARM_AMBA && HAS_IOMEM select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select FB_MODE_HELPERS if OF select VIDEOMODE_HELPERS if OF + select BACKLIGHT_LCD_SUPPORT if OF + select BACKLIGHT_CLASS_DEVICE if OF help This framebuffer device driver is for the ARM PrimeCell PL110 Colour LCD controller. ARM PrimeCells provide the building @@ -305,6 +307,8 @@ config PLAT_VERSATILE_CLCD def_bool ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS || ARCH_INTEGRATOR depends on ARM depends on FB_ARMCLCD && FB=y + select REGMAP + select MFD_SYSCON config FB_ACORN bool "Acorn VIDC support" @@ -2443,7 +2447,6 @@ config FB_SIMPLE source "drivers/video/fbdev/omap/Kconfig" source "drivers/video/fbdev/omap2/Kconfig" -source "drivers/video/fbdev/exynos/Kconfig" source "drivers/video/fbdev/mmp/Kconfig" config FB_SH_MOBILE_MERAM diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile index f6731867dd26..ee8c81405a7f 100644 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -6,8 +6,6 @@ obj-y += core/ -obj-$(CONFIG_EXYNOS_VIDEO) += exynos/ - obj-$(CONFIG_FB_MACMODES) += macmodes.o obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o @@ -79,6 +77,7 @@ obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o obj-$(CONFIG_FB_PVR2) += pvr2fb.o obj-$(CONFIG_FB_VOODOO1) += sstfb.o obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o +obj-$(CONFIG_ARCH_NOMADIK) += amba-clcd-nomadik.o obj-$(CONFIG_PLAT_VERSATILE_CLCD) += amba-clcd-versatile.o obj-$(CONFIG_FB_GOLDFISH) += goldfishfb.o obj-$(CONFIG_FB_68328) += 68328fb.o diff --git a/drivers/video/fbdev/amba-clcd-nomadik.c b/drivers/video/fbdev/amba-clcd-nomadik.c new file mode 100644 index 000000000000..0c06fcaaa6e8 --- /dev/null +++ b/drivers/video/fbdev/amba-clcd-nomadik.c @@ -0,0 +1,259 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "amba-clcd-nomadik.h" + +static struct gpio_desc *grestb; +static struct gpio_desc *scen; +static struct gpio_desc *scl; +static struct gpio_desc *sda; + +static u8 tpg110_readwrite_reg(bool write, u8 address, u8 outval) +{ + int i; + u8 inval = 0; + + /* Assert SCEN */ + gpiod_set_value_cansleep(scen, 1); + ndelay(150); + /* Hammer out the address */ + for (i = 5; i >= 0; i--) { + if (address & BIT(i)) + gpiod_set_value_cansleep(sda, 1); + else + gpiod_set_value_cansleep(sda, 0); + ndelay(150); + /* Send an SCL pulse */ + gpiod_set_value_cansleep(scl, 1); + ndelay(160); + gpiod_set_value_cansleep(scl, 0); + ndelay(160); + } + + if (write) { + /* WRITE */ + gpiod_set_value_cansleep(sda, 0); + } else { + /* READ */ + gpiod_set_value_cansleep(sda, 1); + } + ndelay(150); + /* Send an SCL pulse */ + gpiod_set_value_cansleep(scl, 1); + ndelay(160); + gpiod_set_value_cansleep(scl, 0); + ndelay(160); + + if (!write) + /* HiZ turn-around cycle */ + gpiod_direction_input(sda); + ndelay(150); + /* Send an SCL pulse */ + gpiod_set_value_cansleep(scl, 1); + ndelay(160); + gpiod_set_value_cansleep(scl, 0); + ndelay(160); + + /* Hammer in/out the data */ + for (i = 7; i >= 0; i--) { + int value; + + if (write) { + value = !!(outval & BIT(i)); + gpiod_set_value_cansleep(sda, value); + } else { + value = gpiod_get_value(sda); + if (value) + inval |= BIT(i); + } + ndelay(150); + /* Send an SCL pulse */ + gpiod_set_value_cansleep(scl, 1); + ndelay(160); + gpiod_set_value_cansleep(scl, 0); + ndelay(160); + } + + gpiod_direction_output(sda, 0); + /* Deassert SCEN */ + gpiod_set_value_cansleep(scen, 0); + /* Satisfies SCEN pulse width */ + udelay(1); + + return inval; +} + +static u8 tpg110_read_reg(u8 address) +{ + return tpg110_readwrite_reg(false, address, 0); +} + +static void tpg110_write_reg(u8 address, u8 outval) +{ + tpg110_readwrite_reg(true, address, outval); +} + +static void tpg110_startup(struct device *dev) +{ + u8 val; + + dev_info(dev, "TPG110 display enable\n"); + /* De-assert the reset signal */ + gpiod_set_value_cansleep(grestb, 0); + mdelay(1); + dev_info(dev, "de-asserted GRESTB\n"); + + /* Test display communication */ + tpg110_write_reg(0x00, 0x55); + val = tpg110_read_reg(0x00); + if (val == 0x55) + dev_info(dev, "passed communication test\n"); + val = tpg110_read_reg(0x01); + dev_info(dev, "TPG110 chip ID: %d version: %d\n", + val>>4, val&0x0f); + + /* Show display resolution */ + val = tpg110_read_reg(0x02); + val &= 7; + switch (val) { + case 0x0: + dev_info(dev, "IN 400x240 RGB -> OUT 800x480 RGB (dual scan)"); + break; + case 0x1: + dev_info(dev, "IN 480x272 RGB -> OUT 800x480 RGB (dual scan)"); + break; + case 0x4: + dev_info(dev, "480x640 RGB"); + break; + case 0x5: + dev_info(dev, "480x272 RGB"); + break; + case 0x6: + dev_info(dev, "640x480 RGB"); + break; + case 0x7: + dev_info(dev, "800x480 RGB"); + break; + default: + dev_info(dev, "ILLEGAL RESOLUTION"); + break; + } + + val = tpg110_read_reg(0x03); + dev_info(dev, "resolution is controlled by %s\n", + (val & BIT(7)) ? "software" : "hardware"); +} + +static void tpg110_enable(struct clcd_fb *fb) +{ + struct device *dev = &fb->dev->dev; + static bool startup; + u8 val; + + if (!startup) { + tpg110_startup(dev); + startup = true; + } + + /* Take chip out of standby */ + val = tpg110_read_reg(0x03); + val |= BIT(0); + tpg110_write_reg(0x03, val); +} + +static void tpg110_disable(struct clcd_fb *fb) +{ + u8 val; + + dev_info(&fb->dev->dev, "TPG110 display disable\n"); + val = tpg110_read_reg(0x03); + /* Put into standby */ + val &= ~BIT(0); + tpg110_write_reg(0x03, val); +} + +static void tpg110_init(struct device *dev, struct device_node *np, + struct clcd_board *board) +{ + dev_info(dev, "TPG110 display init\n"); + + grestb = devm_get_gpiod_from_child(dev, "grestb", &np->fwnode); + if (IS_ERR(grestb)) { + dev_err(dev, "no GRESTB GPIO\n"); + return; + } + /* This asserts the GRESTB signal, putting the display into reset */ + gpiod_direction_output(grestb, 1); + + scen = devm_get_gpiod_from_child(dev, "scen", &np->fwnode); + if (IS_ERR(scen)) { + dev_err(dev, "no SCEN GPIO\n"); + return; + } + gpiod_direction_output(scen, 0); + scl = devm_get_gpiod_from_child(dev, "scl", &np->fwnode); + if (IS_ERR(scl)) { + dev_err(dev, "no SCL GPIO\n"); + return; + } + gpiod_direction_output(scl, 0); + sda = devm_get_gpiod_from_child(dev, "sda", &np->fwnode); + if (IS_ERR(sda)) { + dev_err(dev, "no SDA GPIO\n"); + return; + } + gpiod_direction_output(sda, 0); + board->enable = tpg110_enable; + board->disable = tpg110_disable; +} + +int nomadik_clcd_init_panel(struct clcd_fb *fb, + struct device_node *endpoint) +{ + struct device_node *panel; + + panel = of_graph_get_remote_port_parent(endpoint); + if (!panel) + return -ENODEV; + + if (of_device_is_compatible(panel, "tpo,tpg110")) + tpg110_init(&fb->dev->dev, panel, fb->board); + else + dev_info(&fb->dev->dev, "unknown panel\n"); + + /* Unknown panel, fall through */ + return 0; +} +EXPORT_SYMBOL_GPL(nomadik_clcd_init_panel); + +#define PMU_CTRL_OFFSET 0x0000 +#define PMU_CTRL_LCDNDIF BIT(26) + +int nomadik_clcd_init_board(struct amba_device *adev, + struct clcd_board *board) +{ + struct regmap *pmu_regmap; + + dev_info(&adev->dev, "Nomadik CLCD board init\n"); + pmu_regmap = + syscon_regmap_lookup_by_compatible("stericsson,nomadik-pmu"); + if (IS_ERR(pmu_regmap)) { + dev_err(&adev->dev, "could not find PMU syscon regmap\n"); + return PTR_ERR(pmu_regmap); + } + regmap_update_bits(pmu_regmap, + PMU_CTRL_OFFSET, + PMU_CTRL_LCDNDIF, + 0); + dev_info(&adev->dev, "set PMU mux to CLCD mode\n"); + + return 0; +} +EXPORT_SYMBOL_GPL(nomadik_clcd_init_board); diff --git a/drivers/video/fbdev/amba-clcd-nomadik.h b/drivers/video/fbdev/amba-clcd-nomadik.h new file mode 100644 index 000000000000..50aa9bda69fd --- /dev/null +++ b/drivers/video/fbdev/amba-clcd-nomadik.h @@ -0,0 +1,24 @@ +#ifndef _AMBA_CLCD_NOMADIK_H +#define _AMBA_CLCD_NOMADIK_H + +#include + +#ifdef CONFIG_ARCH_NOMADIK +int nomadik_clcd_init_board(struct amba_device *adev, + struct clcd_board *board); +int nomadik_clcd_init_panel(struct clcd_fb *fb, + struct device_node *endpoint); +#else +static inline int nomadik_clcd_init_board(struct amba_device *adev, + struct clcd_board *board) +{ + return 0; +} +static inline int nomadik_clcd_init_panel(struct clcd_fb *fb, + struct device_node *endpoint) +{ + return 0; +} +#endif + +#endif /* inclusion guard */ diff --git a/drivers/video/fbdev/amba-clcd-versatile.c b/drivers/video/fbdev/amba-clcd-versatile.c index a8a22daa3f9d..19ad8645d93c 100644 --- a/drivers/video/fbdev/amba-clcd-versatile.c +++ b/drivers/video/fbdev/amba-clcd-versatile.c @@ -3,6 +3,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include "amba-clcd-versatile.h" static struct clcd_panel vga = { .mode = { @@ -178,3 +184,392 @@ void versatile_clcd_remove_dma(struct clcd_fb *fb) dma_free_wc(&fb->dev->dev, fb->fb.fix.smem_len, fb->fb.screen_base, fb->fb.fix.smem_start); } + +#ifdef CONFIG_OF + +static struct regmap *versatile_syscon_map; +static struct regmap *versatile_ib2_map; + +/* + * We detect the different syscon types from the compatible strings. + */ +enum versatile_clcd { + INTEGRATOR_CLCD_CM, + VERSATILE_CLCD, + REALVIEW_CLCD_EB, + REALVIEW_CLCD_PB1176, + REALVIEW_CLCD_PB11MP, + REALVIEW_CLCD_PBA8, + REALVIEW_CLCD_PBX, +}; + +static const struct of_device_id versatile_clcd_of_match[] = { + { + .compatible = "arm,core-module-integrator", + .data = (void *)INTEGRATOR_CLCD_CM, + }, + { + .compatible = "arm,versatile-sysreg", + .data = (void *)VERSATILE_CLCD, + }, + { + .compatible = "arm,realview-eb-syscon", + .data = (void *)REALVIEW_CLCD_EB, + }, + { + .compatible = "arm,realview-pb1176-syscon", + .data = (void *)REALVIEW_CLCD_PB1176, + }, + { + .compatible = "arm,realview-pb11mp-syscon", + .data = (void *)REALVIEW_CLCD_PB11MP, + }, + { + .compatible = "arm,realview-pba8-syscon", + .data = (void *)REALVIEW_CLCD_PBA8, + }, + { + .compatible = "arm,realview-pbx-syscon", + .data = (void *)REALVIEW_CLCD_PBX, + }, + {}, +}; + +/* + * Core module CLCD control on the Integrator/CP, bits + * 8 thru 19 of the CM_CONTROL register controls a bunch + * of CLCD settings. + */ +#define INTEGRATOR_HDR_CTRL_OFFSET 0x0C +#define INTEGRATOR_CLCD_LCDBIASEN BIT(8) +#define INTEGRATOR_CLCD_LCDBIASUP BIT(9) +#define INTEGRATOR_CLCD_LCDBIASDN BIT(10) +/* Bits 11,12,13 controls the LCD type */ +#define INTEGRATOR_CLCD_LCDMUX_MASK (BIT(11)|BIT(12)|BIT(13)) +#define INTEGRATOR_CLCD_LCDMUX_LCD24 BIT(11) +#define INTEGRATOR_CLCD_LCDMUX_VGA565 BIT(12) +#define INTEGRATOR_CLCD_LCDMUX_SHARP (BIT(11)|BIT(12)) +#define INTEGRATOR_CLCD_LCDMUX_VGA555 BIT(13) +#define INTEGRATOR_CLCD_LCDMUX_VGA24 (BIT(11)|BIT(12)|BIT(13)) +#define INTEGRATOR_CLCD_LCD0_EN BIT(14) +#define INTEGRATOR_CLCD_LCD1_EN BIT(15) +/* R/L flip on Sharp */ +#define INTEGRATOR_CLCD_LCD_STATIC1 BIT(16) +/* U/D flip on Sharp */ +#define INTEGRATOR_CLCD_LCD_STATIC2 BIT(17) +/* No connection on Sharp */ +#define INTEGRATOR_CLCD_LCD_STATIC BIT(18) +/* 0 = 24bit VGA, 1 = 18bit VGA */ +#define INTEGRATOR_CLCD_LCD_N24BITEN BIT(19) + +#define INTEGRATOR_CLCD_MASK (INTEGRATOR_CLCD_LCDBIASEN | \ + INTEGRATOR_CLCD_LCDBIASUP | \ + INTEGRATOR_CLCD_LCDBIASDN | \ + INTEGRATOR_CLCD_LCDMUX_MASK | \ + INTEGRATOR_CLCD_LCD0_EN | \ + INTEGRATOR_CLCD_LCD1_EN | \ + INTEGRATOR_CLCD_LCD_STATIC1 | \ + INTEGRATOR_CLCD_LCD_STATIC2 | \ + INTEGRATOR_CLCD_LCD_STATIC | \ + INTEGRATOR_CLCD_LCD_N24BITEN) + +static void integrator_clcd_enable(struct clcd_fb *fb) +{ + struct fb_var_screeninfo *var = &fb->fb.var; + u32 val; + + dev_info(&fb->dev->dev, "enable Integrator CLCD connectors\n"); + + /* FIXME: really needed? */ + val = INTEGRATOR_CLCD_LCD_STATIC1 | INTEGRATOR_CLCD_LCD_STATIC2 | + INTEGRATOR_CLCD_LCD0_EN | INTEGRATOR_CLCD_LCD1_EN; + if (var->bits_per_pixel <= 8 || + (var->bits_per_pixel == 16 && var->green.length == 5)) + /* Pseudocolor, RGB555, BGR555 */ + val |= INTEGRATOR_CLCD_LCDMUX_VGA555; + else if (fb->fb.var.bits_per_pixel <= 16) + /* truecolor RGB565 */ + val |= INTEGRATOR_CLCD_LCDMUX_VGA565; + else + val = 0; /* no idea for this, don't trust the docs */ + + regmap_update_bits(versatile_syscon_map, + INTEGRATOR_HDR_CTRL_OFFSET, + INTEGRATOR_CLCD_MASK, + val); +} + +/* + * This configuration register in the Versatile and RealView + * family is uniformly present but appears more and more + * unutilized starting with the RealView series. + */ +#define SYS_CLCD 0x50 +#define SYS_CLCD_MODE_MASK (BIT(0)|BIT(1)) +#define SYS_CLCD_MODE_888 0 +#define SYS_CLCD_MODE_5551 BIT(0) +#define SYS_CLCD_MODE_565_R_LSB BIT(1) +#define SYS_CLCD_MODE_565_B_LSB (BIT(0)|BIT(1)) +#define SYS_CLCD_CONNECTOR_MASK (BIT(2)|BIT(3)|BIT(4)|BIT(5)) +#define SYS_CLCD_NLCDIOON BIT(2) +#define SYS_CLCD_VDDPOSSWITCH BIT(3) +#define SYS_CLCD_PWR3V5SWITCH BIT(4) +#define SYS_CLCD_VDDNEGSWITCH BIT(5) +#define SYS_CLCD_TSNSS BIT(6) /* touchscreen enable */ +#define SYS_CLCD_SSPEXP BIT(7) /* SSP expansion enable */ + +/* The Versatile can detect the connected panel type */ +#define SYS_CLCD_CLCDID_MASK (BIT(8)|BIT(9)|BIT(10)|BIT(11)|BIT(12)) +#define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8) +#define SYS_CLCD_ID_SHARP_8_4 (0x01 << 8) +#define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8) +#define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8) +#define SYS_CLCD_ID_VGA (0x1f << 8) + +#define SYS_CLCD_TSNDAV BIT(13) /* data ready from TS */ + +/* IB2 control register for the Versatile daughterboard */ +#define IB2_CTRL 0x00 +#define IB2_CTRL_LCD_SD BIT(1) /* 1 = shut down LCD */ +#define IB2_CTRL_LCD_BL_ON BIT(0) +#define IB2_CTRL_LCD_MASK (BIT(0)|BIT(1)) + +static void versatile_clcd_disable(struct clcd_fb *fb) +{ + dev_info(&fb->dev->dev, "disable Versatile CLCD connectors\n"); + regmap_update_bits(versatile_syscon_map, + SYS_CLCD, + SYS_CLCD_CONNECTOR_MASK, + 0); + + /* If we're on an IB2 daughterboard, turn off display */ + if (versatile_ib2_map) { + dev_info(&fb->dev->dev, "disable IB2 display\n"); + regmap_update_bits(versatile_ib2_map, + IB2_CTRL, + IB2_CTRL_LCD_MASK, + IB2_CTRL_LCD_SD); + } +} + +static void versatile_clcd_enable(struct clcd_fb *fb) +{ + struct fb_var_screeninfo *var = &fb->fb.var; + u32 val = 0; + + dev_info(&fb->dev->dev, "enable Versatile CLCD connectors\n"); + switch (var->green.length) { + case 5: + val |= SYS_CLCD_MODE_5551; + break; + case 6: + if (var->red.offset == 0) + val |= SYS_CLCD_MODE_565_R_LSB; + else + val |= SYS_CLCD_MODE_565_B_LSB; + break; + case 8: + val |= SYS_CLCD_MODE_888; + break; + } + + /* Set up the MUX */ + regmap_update_bits(versatile_syscon_map, + SYS_CLCD, + SYS_CLCD_MODE_MASK, + val); + + /* Then enable the display */ + regmap_update_bits(versatile_syscon_map, + SYS_CLCD, + SYS_CLCD_CONNECTOR_MASK, + SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH); + + /* If we're on an IB2 daughterboard, turn on display */ + if (versatile_ib2_map) { + dev_info(&fb->dev->dev, "enable IB2 display\n"); + regmap_update_bits(versatile_ib2_map, + IB2_CTRL, + IB2_CTRL_LCD_MASK, + IB2_CTRL_LCD_BL_ON); + } +} + +static void versatile_clcd_decode(struct clcd_fb *fb, struct clcd_regs *regs) +{ + clcdfb_decode(fb, regs); + + /* Always clear BGR for RGB565: we do the routing externally */ + if (fb->fb.var.green.length == 6) + regs->cntl &= ~CNTL_BGR; +} + +static void realview_clcd_disable(struct clcd_fb *fb) +{ + dev_info(&fb->dev->dev, "disable RealView CLCD connectors\n"); + regmap_update_bits(versatile_syscon_map, + SYS_CLCD, + SYS_CLCD_CONNECTOR_MASK, + 0); +} + +static void realview_clcd_enable(struct clcd_fb *fb) +{ + dev_info(&fb->dev->dev, "enable RealView CLCD connectors\n"); + regmap_update_bits(versatile_syscon_map, + SYS_CLCD, + SYS_CLCD_CONNECTOR_MASK, + SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH); +} + +struct versatile_panel { + u32 id; + char *compatible; + bool ib2; +}; + +static const struct versatile_panel versatile_panels[] = { + { + .id = SYS_CLCD_ID_VGA, + .compatible = "VGA", + }, + { + .id = SYS_CLCD_ID_SANYO_3_8, + .compatible = "sanyo,tm38qv67a02a", + }, + { + .id = SYS_CLCD_ID_SHARP_8_4, + .compatible = "sharp,lq084v1dg21", + }, + { + .id = SYS_CLCD_ID_EPSON_2_2, + .compatible = "epson,l2f50113t00", + }, + { + .id = SYS_CLCD_ID_SANYO_2_5, + .compatible = "sanyo,alr252rgt", + .ib2 = true, + }, +}; + +static void versatile_panel_probe(struct device *dev, + struct device_node *endpoint) +{ + struct versatile_panel const *vpanel = NULL; + struct device_node *panel = NULL; + u32 val; + int ret; + int i; + + /* + * The Versatile CLCD has a panel auto-detection mechanism. + * We use this and look for the compatible panel in the + * device tree. + */ + ret = regmap_read(versatile_syscon_map, SYS_CLCD, &val); + if (ret) { + dev_err(dev, "cannot read CLCD syscon register\n"); + return; + } + val &= SYS_CLCD_CLCDID_MASK; + + /* First find corresponding panel information */ + for (i = 0; i < ARRAY_SIZE(versatile_panels); i++) { + vpanel = &versatile_panels[i]; + + if (val == vpanel->id) { + dev_err(dev, "autodetected panel \"%s\"\n", + vpanel->compatible); + break; + } + } + if (i == ARRAY_SIZE(versatile_panels)) { + dev_err(dev, "could not auto-detect panel\n"); + return; + } + + panel = of_graph_get_remote_port_parent(endpoint); + if (!panel) { + dev_err(dev, "could not locate panel in DT\n"); + return; + } + if (!of_device_is_compatible(panel, vpanel->compatible)) + dev_err(dev, "panel in DT is not compatible with the " + "auto-detected panel, continuing anyway\n"); + + /* + * If we have a Sanyo 2.5" port + * that we're running on an IB2 and proceed to look for the + * IB2 syscon regmap. + */ + if (!vpanel->ib2) + return; + + versatile_ib2_map = syscon_regmap_lookup_by_compatible( + "arm,versatile-ib2-syscon"); + if (IS_ERR(versatile_ib2_map)) { + dev_err(dev, "could not locate IB2 control register\n"); + versatile_ib2_map = NULL; + return; + } +} + +int versatile_clcd_init_panel(struct clcd_fb *fb, + struct device_node *endpoint) +{ + const struct of_device_id *clcd_id; + enum versatile_clcd versatile_clcd_type; + struct device_node *np; + struct regmap *map; + struct device *dev = &fb->dev->dev; + + np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match, + &clcd_id); + if (!np) { + dev_err(dev, "no Versatile syscon node\n"); + return -ENODEV; + } + versatile_clcd_type = (enum versatile_clcd)clcd_id->data; + + map = syscon_node_to_regmap(np); + if (IS_ERR(map)) { + dev_err(dev, "no Versatile syscon regmap\n"); + return PTR_ERR(map); + } + + switch (versatile_clcd_type) { + case INTEGRATOR_CLCD_CM: + versatile_syscon_map = map; + fb->board->enable = integrator_clcd_enable; + /* Override the caps, we have only these */ + fb->board->caps = CLCD_CAP_5551 | CLCD_CAP_RGB565 | + CLCD_CAP_888; + dev_info(dev, "set up callbacks for Integrator PL110\n"); + break; + case VERSATILE_CLCD: + versatile_syscon_map = map; + fb->board->enable = versatile_clcd_enable; + fb->board->disable = versatile_clcd_disable; + fb->board->decode = versatile_clcd_decode; + versatile_panel_probe(dev, endpoint); + dev_info(dev, "set up callbacks for Versatile\n"); + break; + case REALVIEW_CLCD_EB: + case REALVIEW_CLCD_PB1176: + case REALVIEW_CLCD_PB11MP: + case REALVIEW_CLCD_PBA8: + case REALVIEW_CLCD_PBX: + versatile_syscon_map = map; + fb->board->enable = realview_clcd_enable; + fb->board->disable = realview_clcd_disable; + dev_info(dev, "set up callbacks for RealView PL111\n"); + break; + default: + dev_info(dev, "unknown Versatile system controller\n"); + break; + } + + return 0; +} +EXPORT_SYMBOL_GPL(versatile_clcd_init_panel); +#endif diff --git a/drivers/video/fbdev/amba-clcd-versatile.h b/drivers/video/fbdev/amba-clcd-versatile.h new file mode 100644 index 000000000000..1b14359c2cf6 --- /dev/null +++ b/drivers/video/fbdev/amba-clcd-versatile.h @@ -0,0 +1,17 @@ +/* + * Special local versatile callbacks + */ +#include +#include +#include + +#if defined(CONFIG_PLAT_VERSATILE_CLCD) && defined(CONFIG_OF) +int versatile_clcd_init_panel(struct clcd_fb *fb, + struct device_node *endpoint); +#else +static inline int versatile_clcd_init_panel(struct clcd_fb *fb, + struct device_node *endpoint) +{ + return 0; +} +#endif diff --git a/drivers/video/fbdev/amba-clcd.c b/drivers/video/fbdev/amba-clcd.c index 9b158869cb89..ec2671d98abc 100644 --- a/drivers/video/fbdev/amba-clcd.c +++ b/drivers/video/fbdev/amba-clcd.c @@ -30,10 +30,14 @@ #include #include #include +#include #include