From 456380bb272d3a301c887eee513a3937cc1f48e1 Mon Sep 17 00:00:00 2001 From: "Jason M. Bills" Date: Tue, 22 Oct 2019 14:01:54 -0700 Subject: Update to internal 10-22-19 Signed-off-by: Jason M. Bills --- .../0001-arm-dts-add-DTS-for-Intel-platforms.patch | 473 ++ ...-set-idle-disconnect-to-true-in-all-cases.patch | 34 - ...le-pass-through-on-GPIOE1-and-GPIOE3-free.patch | 121 + ...GPIOE0-and-GPIOE2-pass-through-by-default.patch | 70 + .../linux-aspeed/0005-128MB-flashmap-for-PFR.patch | 30 + .../0005-arm-dts-aspeed-g5-add-espi.patch | 56 - ...w-monitoring-of-power-control-input-GPIOs.patch | 80 + .../0007-New-flash-map-for-intel.patch | 117 - ...aspeed-pwm-tacho-change-default-fan-speed.patch | 28 + .../0008-Add-ASPEED-SGPIO-driver.patch | 764 --- ...port-link-statistics-for-the-NCSI-channel.patch | 54 + .../0009-SGPIO-DT-and-pinctrl-fixup.patch | 244 - ...-drivers-to-sync-with-linux-upstreaming-v.patch | 5566 ------------------- .../0014-arm-dts-aspeed-g5-add-espi.patch | 56 + .../0015-New-flash-map-for-intel.patch | 117 + .../0016-Add-ASPEED-SGPIO-driver.patch | 759 +++ .../0017-SGPIO-DT-and-pinctrl-fixup.patch | 202 + ...-drivers-to-sync-with-linux-upstreaming-v.patch | 5611 ++++++++++++++++++++ .../0020-misc-aspeed-add-lpc-mbox-driver.patch | 10 +- ...021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch | 10 +- .../0022-Add-AST2500-eSPI-driver.patch | 602 ++- .../0026-Add-support-for-new-PECI-commands.patch | 143 +- ...0030-Add-dump-debug-code-into-I2C-drivers.patch | 6 +- ...Add-high-speed-baud-rate-support-for-UART.patch | 63 +- ...ed-Add-Aspeed-UART-routing-control-driver.patch | 18 +- ...m-dts-aspeed-Swap-the-mac-nodes-numbering.patch | 10 +- ...d-PWM-driver-which-uses-FTTMR010-timer-IP.patch | 10 +- .../0040-i2c-Add-mux-hold-unhold-msg-types.patch | 26 +- ...eout-ms-and-retries-device-tree-propertie.patch | 8 +- ...dd-clock-control-logic-into-Aspeed-LPC-BT.patch | 10 +- ...ock-control-logic-into-Aspeed-LPC-SNOOP-d.patch | 10 +- ...dd-clock-control-logic-into-Aspeed-LPC-KC.patch | 14 +- ...-Suppress-excessive-HID-gadget-error-logs.patch | 17 +- .../0051-Add-AST2500-JTAG-device.patch | 6 +- .../0052-drivers-jtag-Add-JTAG-core-driver.patch | 10 +- ...on-jtag-Add-JTAG-core-driver-ioctl-number.patch | 34 +- ...ers-jtag-Add-JTAG-core-driver-Maintainers.patch | 6 +- .../0058-i2c-aspeed-add-general-call-support.patch | 180 - ...-aspeed-fix-master-pending-state-handling.patch | 135 + ...c-aspeed-add-buffer-mode-transfer-support.patch | 1040 ++++ ...-i2c-aspeed-add-DMA-mode-transfer-support.patch | 442 ++ .../0063-i2c-aspeed-add-general-call-support.patch | 180 + ...-set-idle-disconnect-to-true-in-all-cases.patch | 34 + ...-aspeed-fix-master-pending-state-handling.patch | 55 - ...c-aspeed-add-buffer-mode-transfer-support.patch | 886 ---- ...-i2c-aspeed-add-DMA-mode-transfer-support.patch | 442 -- .../0068-i2c-aspeed-add-H-W-timeout-support.patch | 50 +- ...add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch | 8 +- ...-temporary-fix-for-gpiochip-range-setting.patch | 16 +- .../0071-peci-add-a-temporary-workaround.patch | 101 - ...-IO-statistics-to-USB-Mass-storage-gadget.patch | 155 + ...d-refine-HSYNC-VSYNC-polarity-setting-log.patch | 93 + ...-Refine-initialization-flow-in-I2C-driver.patch | 64 + ...076-media-aspeed-clear-garbage-interrupts.patch | 74 + .../recipes-kernel/linux/linux-aspeed/intel.cfg | 73 + .../recipes-kernel/linux/linux-aspeed_%.bbappend | 33 +- 56 files changed, 10563 insertions(+), 8893 deletions(-) create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-platforms.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-set-idle-disconnect-to-true-in-all-cases.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-arm-dts-aspeed-g5-add-espi.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0006-Allow-monitoring-of-power-control-input-GPIOs.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-New-flash-map-for-intel.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-aspeed-pwm-tacho-change-default-fan-speed.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Add-ASPEED-SGPIO-driver.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Report-link-statistics-for-the-NCSI-channel.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0009-SGPIO-DT-and-pinctrl-fixup.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0014-arm-dts-aspeed-g5-add-espi.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0015-New-flash-map-for-intel.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0016-Add-ASPEED-SGPIO-driver.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0017-SGPIO-DT-and-pinctrl-fixup.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0018-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0058-i2c-aspeed-add-general-call-support.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0060-i2c-aspeed-fix-master-pending-state-handling.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0061-i2c-aspeed-add-buffer-mode-transfer-support.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0062-i2c-aspeed-add-DMA-mode-transfer-support.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0063-i2c-aspeed-add-general-call-support.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0064-set-idle-disconnect-to-true-in-all-cases.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0065-i2c-aspeed-fix-master-pending-state-handling.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0066-i2c-aspeed-add-buffer-mode-transfer-support.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0067-i2c-aspeed-add-DMA-mode-transfer-support.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0071-peci-add-a-temporary-workaround.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0073-Add-IO-statistics-to-USB-Mass-storage-gadget.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0074-media-aspeed-refine-HSYNC-VSYNC-polarity-setting-log.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0075-Refine-initialization-flow-in-I2C-driver.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0076-media-aspeed-clear-garbage-interrupts.patch (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux') diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-platforms.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-platforms.patch new file mode 100644 index 000000000..d185171f6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-platforms.patch @@ -0,0 +1,473 @@ +From 965806acbf8eb3f38367958594f0651e1893ddb8 Mon Sep 17 00:00:00 2001 +From: Yuan Li +Date: Tue, 19 Sep 2017 15:55:39 +0800 +Subject: [PATCH] arm: dts: add DTS for Intel platforms + +Add the DTS file for Intel systems. + +Signed-off-by: Yuan Li +Signed-off-by: Yong Li +Signed-off-by: James Feist +Signed-off-by: Jae Hyun Yoo +Signed-off-by: Jason M. Bills +Signed-off-by: Zhu, Yunge +Signed-off-by: Qiang XU +Signed-off-by: Chen Yugang +--- + arch/arm/boot/dts/aspeed-bmc-intel-purley.dts | 444 ++++++++++++++++++++++++++ + 1 file changed, 444 insertions(+) + create mode 100644 arch/arm/boot/dts/aspeed-bmc-intel-purley.dts + +diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts +new file mode 100644 +index 0000000..b901d98 +--- /dev/null ++++ b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts +@@ -0,0 +1,444 @@ ++/dts-v1/; ++ ++#include "aspeed-g5.dtsi" ++#include ++#include ++ ++/ { ++ model = "Purley BMC"; ++ compatible = "intel,purley-bmc", "aspeed,ast2500"; ++ ++ aliases { ++ serial4 = &uart5; ++ }; ++ ++ chosen { ++ stdout-path = &uart5; ++ bootargs = "console=ttyS4,115200 earlyprintk"; ++ }; ++ ++ memory@80000000 { ++ reg = <0x80000000 0x20000000>; ++ }; ++ ++ reserved-memory { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ vga_memory: framebuffer@7f000000 { ++ no-map; ++ reg = <0x7f000000 0x01000000>; ++ }; ++ ++ gfx_memory: framebuffer { ++ size = <0x01000000>; ++ alignment = <0x01000000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; ++ ++ video_engine_memory: jpegbuffer { ++ size = <0x02000000>; /* 32M */ ++ alignment = <0x01000000>; ++ compatible = "shared-dma-pool"; ++ reusable; ++ }; ++ ++ ramoops@9eff0000{ ++ compatible = "ramoops"; ++ reg = <0x9eff0000 0x10000>; ++ record-size = <0x2000>; ++ console-size = <0x2000>; ++ }; ++ }; ++ ++ vga-shared-memory { ++ compatible = "aspeed,ast2500-vga-sharedmem"; ++ reg = <0x9ff00000 0x100000>; ++ }; ++ ++ iio-hwmon { ++ compatible = "iio-hwmon"; ++ io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>, ++ <&adc 4>, <&adc 5>, <&adc 6>, <&adc 7>, ++ <&adc 8>, <&adc 9>, <&adc 10>, <&adc 11>, ++ <&adc 12>, <&adc 13>, <&adc 14>, <&adc 15>; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ identify { ++ default-state = "off"; ++ gpios = <&gpio ASPEED_GPIO(S, 6) GPIO_ACTIVE_LOW>; ++ }; ++ ++ status_amber { ++ default-state = "off"; ++ gpios = <&gpio ASPEED_GPIO(S, 5) GPIO_ACTIVE_LOW>; ++ }; ++ ++ status_green { ++ default-state = "keep"; ++ gpios = <&gpio ASPEED_GPIO(S, 4) GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ beeper { ++ compatible = "pwm-beeper"; ++ pwms = <&timer 5 1000000 0>; ++ }; ++}; ++ ++&fmc { ++ status = "okay"; ++ flash@0 { ++ status = "okay"; ++ m25p,fast-read; ++#include "openbmc-flash-layout-intel-64MB.dtsi" ++ }; ++}; ++ ++&espi { ++ status = "okay"; ++}; ++ ++&jtag { ++ status = "okay"; ++}; ++ ++&peci0 { ++ status = "okay"; ++ gpios = <&gpio ASPEED_GPIO(F, 6) 0>; ++}; ++ ++&syscon { ++ uart-clock-high-speed; ++ status = "okay"; ++}; ++ ++&adc { ++ status = "okay"; ++}; ++ ++&gpio { ++ status = "okay"; ++ gpio-line-names = ++ /*A0-A7*/ "","","","","","","","", ++ /*B0-B7*/ "FM_BMC_BOARD_SKU_ID0_N","FM_BMC_BOARD_SKU_ID1_N","FM_BMC_BOARD_SKU_ID2_N","FM_BMC_BOARD_SKU_ID3_N","FM_BMC_BOARD_SKU_ID4_N","","","", ++ /*C0-C7*/ "","","","","","","","", ++ /*D0-D7*/ "","","","","","","","", ++ /*E0-E7*/ "RESET_BUTTON","RESET_OUT","POWER_BUTTON","POWER_OUT","","DEBUG_EN_N","","", ++ /*F0-F7*/ "NMI_OUT","","","","CPU_ERR0","CPU_ERR1","PLTRST_N","PRDY_N", ++ /*G0-G7*/ "CPU_ERR2","CPU_CATERR","PCH_BMC_THERMTRIP","","","FM_BMC_BOARD_SKU_ID5_N","","", ++ /*H0-H7*/ "","","","","","","","", ++ /*I0-I7*/ "","","","","","","","", ++ /*J0-J7*/ "","","","","","","","", ++ /*K0-K7*/ "","","","","","","","", ++ /*L0-L7*/ "","","","","","","","", ++ /*M0-M7*/ "","","","","","","","", ++ /*N0-N7*/ "","","","","","","","", ++ /*O0-O7*/ "","","","","","","","", ++ /*P0-P7*/ "","","","","","","","", ++ /*Q0-Q7*/ "","","","","","","","PWR_DEBUG_N", ++ /*R0-R7*/ "","XDP_PRST_N","","","","","","", ++ /*S0-S7*/ "","SYSPWROK","RSMRST_N","","","","","", ++ /*T0-T7*/ "","","","","","","","", ++ /*U0-U7*/ "","","","","","","","", ++ /*V0-V7*/ "","","","","","","","", ++ /*W0-W7*/ "","","","","","","","", ++ /*X0-X7*/ "","","","","","","","", ++ /*Y0-Y7*/ "SIO_S3","SIO_S5","","SIO_ONCONTROL","","","","", ++ /*Z0-Z7*/ "","SIO_POWER_GOOD","","","","","","", ++ /*AA0-AA7*/ "P3VBAT_BRIDGE_EN","","","","PREQ_N","TCK_MUX_SEL","SMI","POST_COMPLETE", ++ /*AB0-AB7*/ "","NMI_BUTTON","ID_BUTTON","PS_PWROK","","","","", ++ /*AC0-AC7*/ "","","","","","","",""; ++}; ++ ++&sgpio { ++ status = "okay"; ++ gpio-line-names = ++ /* SGPIO output lines */ ++ /*OA0-OA7*/ "","","","","","","","", ++ /*OB0-OB7*/ "LED_CPU1_CH1_DIMM1_FAULT","LED_CPU1_CH1_DIMM2_FAULT","LED_CPU1_CH2_DIMM1_FAULT","LED_CPU1_CH2_DIMM2_FAULT","LED_CPU1_CH3_DIMM1_FAULT","LED_CPU1_CH3_DIMM2_FAULT","LED_CPU1_CH4_DIMM1_FAULT","LED_CPU1_CH4_DIMM2_FAULT", ++ /*OC0-OC7*/ "LED_CPU1_CH5_DIMM1_FAULT","LED_CPU1_CH5_DIMM2_FAULT","LED_CPU1_CH6_DIMM1_FAULT","LED_CPU1_CH6_DIMM2_FAULT","LED_FAN1_FAULT","LED_FAN2_FAULT","LED_FAN3_FAULT","LED_FAN4_FAULT", ++ /*OD0-OD7*/ "LED_FAN5_FAULT","LED_FAN6_FAULT","LED_FAN7_FAULT","LED_FAN8_FAULT","LED_CPU2_CH1_DIMM1_FAULT","LED_CPU1_CH1_DIMM2_FAULT","LED_CPU2_CH2_DIMM1_FAULT","LED_CPU2_CH2_DIMM2_FAULT", ++ /*OE0-OE7*/ "LED_CPU2_CH3_DIMM1_FAULT","LED_CPU2_CH3_DIMM2_FAULT","LED_CPU2_CH4_DIMM1_FAULT","LED_CPU2_CH4_DIMM2_FAULT","LED_CPU2_CH5_DIMM1_FAULT","LED_CPU2_CH5_DIMM2_FAULT","LED_CPU2_CH6_DIMM1_FAULT","LED_CPU2_CH6_DIMM2_FAULT", ++ /*OF0-OF7*/ "LED_CPU3_CH1_DIMM1_FAULT","LED_CPU3_CH1_DIMM2_FAULT","LED_CPU3_CH2_DIMM1_FAULT","LED_CPU3_CH2_DIMM2_FAULT","LED_CPU3_CH3_DIMM1_FAULT","LED_CPU3_CH3_DIMM2_FAULT","LED_CPU3_CH4_DIMM1_FAULT","LED_CPU3_CH4_DIMM2_FAULT", ++ /*OG0-OG7*/ "LED_CPU3_CH5_DIMM1_FAULT","LED_CPU3_CH5_DIMM2_FAULT","LED_CPU3_CH6_DIMM1_FAULT","LED_CPU3_CH6_DIMM2_FAULT","LED_CPU4_CH1_DIMM1_FAULT","LED_CPU4_CH1_DIMM2_FAULT","LED_CPU4_CH2_DIMM1_FAULT","LED_CPU4_CH2_DIMM2_FAULT", ++ /*OH0-OH7*/ "LED_CPU4_CH3_DIMM1_FAULT","LED_CPU4_CH3_DIMM2_FAULT","LED_CPU4_CH4_DIMM1_FAULT","LED_CPU4_CH4_DIMM2_FAULT","LED_CPU4_CH5_DIMM1_FAULT","LED_CPU4_CH5_DIMM2_FAULT","LED_CPU4_CH6_DIMM1_FAULT","LED_CPU4_CH6_DIMM2_FAULT", ++ /*OI0-OI7*/ "","","","","","","","", ++ /*OJ0-OJ7*/ "","","","","","","","", ++ /*DUMMY*/ "","","","","","","","", ++ /*DUMMY*/ "","","","","","","","", ++ ++ /* SGPIO input lines */ ++ /*IA0-IA7*/ "CPU1_PRESENCE","CPU1_THERMTRIP","CPU1_VRHOT","CPU1_FIVR_FAULT","CPU1_MEM_ABCD_VRHOT","CPU1_MEM_EFGH_VRHOT","","", ++ /*IB0-IB7*/ "","","CPU2_PRESENCE","CPU2_THERMTRIP","CPU2_VRHOT","CPU2_FIVR_FAULT","CPU2_MEM_ABCD_VRHOT","CPU2_MEM_EFGH_VRHOT", ++ /*IC0-IC7*/ "","","","","","","","", ++ /*ID0-ID7*/ "","","","","","","","", ++ /*IE0-IE7*/ "","","","","","","","", ++ /*IF0-IF7*/ "","","","","","","","", ++ /*IG0-IG7*/ "","","","","","","","", ++ /*IH0-IH7*/ "","","","","","","","", ++ /*II0-II7*/ "","","","","","","","", ++ /*IJ0-IJ7*/ "","","","","","","",""; ++}; ++ ++&kcs3 { ++ kcs_addr = <0xCA2>; ++ status = "okay"; ++}; ++ ++&kcs4 { ++ kcs_addr = <0xCA4>; ++ status = "okay"; ++}; ++ ++&lpc_sio { ++ status = "okay"; ++}; ++ ++&lpc_snoop { ++ snoop-ports = <0x80>; ++ status = "okay"; ++}; ++ ++&mbox { ++ status = "okay"; ++}; ++ ++/** ++ * SAFS through SPI1 is available only on Wilson Point. ++ * These pins are used as fan presence checking gpios in WFP ++ * so commenting it out for now. ++ * &spi1 { ++ * status = "okay"; ++ * ++ * flash@0 { ++ * m25p,fast-read; ++ * status = "okay"; ++ * }; ++ *}; ++ */ ++ ++&uart1 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_txd1_default ++ &pinctrl_rxd1_default ++ &pinctrl_nrts1_default ++ &pinctrl_ndtr1_default ++ &pinctrl_ndsr1_default ++ &pinctrl_ncts1_default ++ &pinctrl_ndcd1_default ++ &pinctrl_nri1_default>; ++}; ++ ++&uart2 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_txd2_default ++ &pinctrl_rxd2_default ++ &pinctrl_nrts2_default ++ &pinctrl_ndtr2_default ++ &pinctrl_ndsr2_default ++ &pinctrl_ncts2_default ++ &pinctrl_ndcd2_default ++ &pinctrl_nri2_default>; ++}; ++ ++&uart3 { ++ status = "okay"; ++}; ++ ++&uart4 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <>; ++}; ++ ++&uart5 { ++ status = "okay"; ++}; ++ ++&mac1 { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>; ++}; ++ ++&mac0 { ++ status = "okay"; ++ use-ncsi; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_rmii1_default>; ++}; ++ ++&i2c0 { ++ multi-master; ++ general-call; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c3 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c4 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++ ++ hsbp0@10 { ++ compatible = "slave-mqueue"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; ++ ++&i2c5 { ++ bus-frequency = <1000000>; ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++ ++ smlink0@10 { ++ compatible = "slave-mqueue"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++}; ++ ++&i2c6 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c7 { ++ multi-master; ++ #retries = <3>; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c9 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c11 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&i2c13 { ++ multi-master; ++ aspeed,dma-buf-size = <4095>; ++ aspeed,hw-timeout-ms = <300>; ++ status = "okay"; ++}; ++ ++&gfx { ++ status = "okay"; ++ memory-region = <&gfx_memory>; ++}; ++ ++&vuart { ++ status = "okay"; ++}; ++ ++&pwm_tacho { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default ++ &pinctrl_pwm2_default &pinctrl_pwm3_default ++ &pinctrl_pwm4_default &pinctrl_pwm5_default ++ &pinctrl_pwm6_default &pinctrl_pwm7_default>; ++ ++ fan@0 { ++ reg = <0x00>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x00 0x01>; ++ }; ++ fan@1 { ++ reg = <0x01>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x02 0x03>; ++ }; ++ fan@2 { ++ reg = <0x02>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x04 0x05>; ++ }; ++ fan@3 { ++ reg = <0x03>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x06 0x07>; ++ }; ++ fan@4 { ++ reg = <0x04>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x08 0x09>; ++ }; ++ fan@5 { ++ reg = <0x05>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x0A 0x0B>; ++ }; ++ fan@6 { ++ reg = <0x06>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x0C 0x0D>; ++ }; ++ fan@7 { ++ reg = <0x07>; ++ aspeed,fan-tach-ch = /bits/ 8 <0x0E 0x0F>; ++ }; ++ ++}; ++ ++&timer { ++/* ++ * Available settings: ++ * fttmr010,pwm-outputs = <5>, <6>, <7>, <8>; ++ * pinctrl-0 = <&pinctrl_timer5_default &pinctrl_timer6_default ++ * &pinctrl_timer7_default &pinctrl_timer8_default>; ++ */ ++ fttmr010,pwm-outputs = <5>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_timer5_default>; ++ #pwm-cells = <3>; ++ status = "okay"; ++}; ++ ++&video { ++ status = "okay"; ++ memory-region = <&video_engine_memory>; ++}; ++ ++&vhub { ++ status = "okay"; ++}; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-set-idle-disconnect-to-true-in-all-cases.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-set-idle-disconnect-to-true-in-all-cases.patch deleted file mode 100644 index 925880eff..000000000 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-set-idle-disconnect-to-true-in-all-cases.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 7854a5e094ac49bebf9b2bfdd44db2f8cdd37543 Mon Sep 17 00:00:00 2001 -From: James Feist -Date: Fri, 31 May 2019 15:05:13 -0700 -Subject: [PATCH] set idle-disconnect to true in all cases - -From sysfs this parameter can't be set. We want the -muxes to clean themselves up if possible. Set this to -true. - -Signed-off-by: James Feist ---- - drivers/i2c/muxes/i2c-mux-pca954x.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c -index 923aa3a5a3dc..084c10951890 100644 ---- a/drivers/i2c/muxes/i2c-mux-pca954x.c -+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c -@@ -474,8 +474,12 @@ static int pca954x_probe(struct i2c_client *client, - data->last_chan = 0; /* force the first selection */ - data->idle_state = MUX_IDLE_AS_IS; - -+#if 1 /* Forcibly set the self-disconnect flag */ -+ idle_disconnect_dt = true; -+#else - idle_disconnect_dt = np && - of_property_read_bool(np, "i2c-mux-idle-disconnect"); -+#endif - if (idle_disconnect_dt) - data->idle_state = MUX_IDLE_DISCONNECT; - --- -2.7.4 - diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch new file mode 100644 index 000000000..ecee21f1c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch @@ -0,0 +1,121 @@ +From ae2bcda6000d7ec278ea78d1eda6e8aacbe5a741 Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" +Date: Fri, 3 May 2019 16:12:39 -0700 +Subject: [PATCH] Enable pass-through on GPIOE1 and GPIOE3 free + +This change adds a gpio_disable_free() implementation that checks +if the GPIO being freed is GPIOE1 (33) or GPIOE3 (35) and will +re-enable the pass-through mux. + +Tested: +Requested GPIOs 33 and 35 and used devmem to check that pass-through +was disabled. Then freed them and checked that pass-through was +enabled again. + +Signed-off-by: Jason M. Bills +--- + drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 1 + + drivers/pinctrl/aspeed/pinctrl-aspeed.c | 60 ++++++++++++++++++++++++++++++ + drivers/pinctrl/aspeed/pinctrl-aspeed.h | 3 ++ + 3 files changed, 64 insertions(+) + +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +index d8a804b9f958..5e7f53fab76e 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +@@ -2805,6 +2805,7 @@ static const struct pinmux_ops aspeed_g5_pinmux_ops = { + .get_function_groups = aspeed_pinmux_get_fn_groups, + .set_mux = aspeed_pinmux_set_mux, + .gpio_request_enable = aspeed_gpio_request_enable, ++ .gpio_disable_free = aspeed_gpio_disable_free, + .strict = true, + }; + +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pinctrl-aspeed.c +index 54933665b5f8..aa7d56e99824 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c +@@ -356,6 +356,66 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev, + return aspeed_sig_expr_enable(&pdata->pinmux, expr); + } + ++void aspeed_gpio_disable_free(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned int offset) ++{ ++ const struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); ++ const struct aspeed_pin_desc *pdesc = pdata->pins[offset].drv_data; ++ const struct aspeed_sig_expr ***prios, **funcs, *expr; ++ int ret; ++ ++ /* ++ * If we're freeing GPIOE1 (33) or GPIOE3 (35) then re-enable the ++ * pass-through mux setting; otherwise, do nothing. ++ */ ++ if (offset != 33 && offset != 35) ++ return; ++ ++ dev_dbg(pctldev->dev, ++ "Freeing pass-through pin %s (%d). Re-enabling pass-through.\n", ++ pdesc->name, offset); ++ ++ if (!pdesc) ++ return; ++ ++ prios = pdesc->prios; ++ ++ if (!prios) ++ return; ++ ++ /* Disable any functions of higher priority than GPIO just in case */ ++ while ((funcs = *prios)) { ++ if (aspeed_gpio_in_exprs(funcs)) ++ break; ++ ++ ret = aspeed_disable_sig(&pdata->pinmux, funcs); ++ if (ret) ++ return; ++ ++ prios++; ++ } ++ ++ if (!funcs) { ++ char *signals = get_defined_signals(pdesc); ++ ++ pr_warn("No GPIO signal type found on pin %s (%d). Found: %s\n", ++ pdesc->name, offset, signals); ++ kfree(signals); ++ ++ return; ++ } ++ ++ /* ++ * Pass-through should be one priority higher than the GPIO function, ++ * so decrement our prios and enable that function ++ */ ++ prios--; ++ funcs = *prios; ++ expr = *funcs; ++ aspeed_sig_expr_enable(&pdata->pinmux, expr); ++} ++ + int aspeed_pinctrl_probe(struct platform_device *pdev, + struct pinctrl_desc *pdesc, + struct aspeed_pinctrl_data *pdata) +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.h b/drivers/pinctrl/aspeed/pinctrl-aspeed.h +index a5d83986f32e..c1104341e202 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.h ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.h +@@ -67,6 +67,9 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, + int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset); ++void aspeed_gpio_disable_free(struct pinctrl_dev *pctldev, ++ struct pinctrl_gpio_range *range, ++ unsigned int offset); + int aspeed_pinctrl_probe(struct platform_device *pdev, + struct pinctrl_desc *pdesc, + struct aspeed_pinctrl_data *pdata); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch new file mode 100644 index 000000000..a5bd4d08e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch @@ -0,0 +1,70 @@ +From fa75e700680ea87ab5aa9722bde1667c572f2fe8 Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" +Date: Mon, 6 May 2019 14:18:27 -0700 +Subject: [PATCH] Enable GPIOE0 and GPIOE2 pass-through by default + +This change sets the gpio DT pinctrl default configuration to +enable GPIOE0 and GPIOE2 pass-through. Since this causes +pinctrl_get_select_default() to be called automatically for +the gpio driver to claim the GPIO pins in those groups, we +also need to call pinctrl_put() to release claim on the +pass-through GPIOs so they can be requested at runtime. + +Tested: +Disabled pass-through in uboot and confirmed that after booting +Linux, pass-through is enabled and 'cat /sys/kernel/debug/pinctrl/ +1e6e2000.syscon\:pinctrl-aspeed-g5-pinctrl/pinmux-pins' shows that +the pass-through GPIOs are UNCLAIMED. + +Signed-off-by: Jason M. Bills +--- + arch/arm/boot/dts/aspeed-bmc-intel-purley.dts | 4 ++++ + drivers/gpio/gpio-aspeed.c | 10 ++++++++++ + 2 files changed, 14 insertions(+) + +diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts +index 040b345f55e1..bc6bb41a8e68 100644 +--- a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts ++++ b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts +@@ -117,6 +117,10 @@ + + &gpio { + status = "okay"; ++ /* Enable GPIOE0 and GPIOE2 pass-through by default */ ++ pinctrl-names = "pass-through"; ++ pinctrl-0 = <&pinctrl_gpie0_default ++ &pinctrl_gpie2_default>; + gpio-line-names = + /*A0-A7*/ "","","","","","","","", + /*B0-B7*/ "","","","","","","","", +diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c +index 09e53c5f3b0a..ac33f8134fe6 100644 +--- a/drivers/gpio/gpio-aspeed.c ++++ b/drivers/gpio/gpio-aspeed.c +@@ -1140,6 +1140,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) + { + const struct of_device_id *gpio_id; + struct aspeed_gpio *gpio; ++ struct pinctrl *pinctrl; + int rc, i, banks, err; + u32 ngpio; + +@@ -1190,6 +1191,15 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) + return -ENOMEM; + + /* ++ * Select the pass-through pinctrl config to enable the pass-through ++ * mux for GPIOs E0 and E2. Then call pinctrl_put() to release claim ++ * of the GPIO pins, so they can be requested at runtime. ++ */ ++ pinctrl = pinctrl_get_select(&pdev->dev, "pass-through"); ++ if (pinctrl) ++ pinctrl_put(pinctrl); ++ ++ /* + * Populate it with initial values read from the HW and switch + * all command sources to the ARM by default + */ +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch new file mode 100644 index 000000000..14b7154bf --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch @@ -0,0 +1,30 @@ +From 9a71adc7aecbfdf066ba54c763c2ecd8fb09d3cd Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy +Date: Wed, 6 Feb 2019 15:59:34 +0530 +Subject: [PATCH] Selecting 128MB for PFR + +PFR platforms requires 128MB flash mapping. +This will override the existing 64MB flash map +and loads 128MB flash map. + +Signed-off-by: Vikram Bodireddy +--- + arch/arm/boot/dts/aspeed-bmc-intel-purley.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts +index 4815104459f1..df02bb1aaf36 100644 +--- a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts ++++ b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts +@@ -89,7 +89,7 @@ + flash@0 { + status = "okay"; + m25p,fast-read; +-#include "openbmc-flash-layout-intel-64MB.dtsi" ++#include "openbmc-flash-layout-intel-128MB.dtsi" + }; + }; + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-arm-dts-aspeed-g5-add-espi.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-arm-dts-aspeed-g5-add-espi.patch deleted file mode 100644 index 165596f25..000000000 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-arm-dts-aspeed-g5-add-espi.patch +++ /dev/null @@ -1,56 +0,0 @@ -From f72d4767835e530ce6bc4673ff30cc1099c88af5 Mon Sep 17 00:00:00 2001 -From: Juston Li -Date: Mon, 27 Mar 2017 11:16:00 -0700 -Subject: [PATCH] arm: dts: aspeed-g5: add espi - -Signed-off-by: Juston Li ---- - arch/arm/boot/dts/aspeed-g5.dtsi | 18 +++++++++++++++++- - 1 file changed, 17 insertions(+), 1 deletion(-) - -diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi -index dc58eb8c6969..db82f47339aa 100644 ---- a/arch/arm/boot/dts/aspeed-g5.dtsi -+++ b/arch/arm/boot/dts/aspeed-g5.dtsi -@@ -283,7 +283,7 @@ - #gpio-cells = <2>; - gpio-controller; - compatible = "aspeed,ast2500-gpio"; -- reg = <0x1e780000 0x1000>; -+ reg = <0x1e780000 0x0200>; - interrupts = <20>; - gpio-ranges = <&pinctrl 0 0 220>; - clocks = <&syscon ASPEED_CLK_APB>; -@@ -291,6 +291,15 @@ - #interrupt-cells = <2>; - }; - -+ sgpio: sgpio@1e780200 { -+ #gpio-cells = <2>; -+ gpio-controller; -+ compatible = "aspeed,ast2500-sgpio"; -+ reg = <0x1e780200 0x0100>; -+ interrupts = <40>; -+ interrupt-controller; -+ }; -+ - rtc: rtc@1e781000 { - compatible = "aspeed,ast2500-rtc"; - reg = <0x1e781000 0x18>; -@@ -366,6 +375,13 @@ - status = "disabled"; - }; - -+ espi: espi@1e6ee000 { -+ compatible = "aspeed,ast2500-espi-slave"; -+ reg = <0x1e6ee000 0x100>; -+ interrupts = <23>; -+ status = "disabled"; -+ }; -+ - lpc: lpc@1e789000 { - compatible = "aspeed,ast2500-lpc", "simple-mfd"; - reg = <0x1e789000 0x1000>; --- -2.7.4 - diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0006-Allow-monitoring-of-power-control-input-GPIOs.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0006-Allow-monitoring-of-power-control-input-GPIOs.patch new file mode 100644 index 000000000..c84746359 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0006-Allow-monitoring-of-power-control-input-GPIOs.patch @@ -0,0 +1,80 @@ +From e9d15bf9fdec1cd17c2ed335566b7d463d63fbdb Mon Sep 17 00:00:00 2001 +From: "Jason M. Bills" +Date: Fri, 24 May 2019 12:42:59 -0700 +Subject: [PATCH] Allow monitoring of power control input GPIOs + +The pass-through input GPIOs cannot be monitored because when +requested, pass-through is disabled which causes a change on the +pass-through output. + +The SIO GPIOs cannot be monitored because when requested, the +request is rejected based on the value of the ACPI strap. + +This change removes the register check condition from the pass- +through and desired SIO GPIOs so they can be requsted and +monitored from power control. + +Tested: +For pass-through, I used gpioset to hold a request on the input +GPIOs and confirmed that pass-through remained enabled. + +For SIO, I used gpioget to confirm that I can successfully request +and read the GPIO value. + +Signed-off-by: Jason M. Bills +--- + drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +index 5e7f53fab76e..b08b5325edb1 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +@@ -279,7 +279,7 @@ FUNC_GROUP_DECL(SD2, F19, E21, F20, D20, D21, E20, G18, C21); + + #define B20 32 + SIG_EXPR_LIST_DECL_SINGLE(B20, NCTS3, NCTS3, SIG_DESC_SET(SCU80, 16)); +-SIG_EXPR_DECL_SINGLE(GPIE0IN, GPIE0, GPIE0_DESC); ++SIG_EXPR_DECL_SINGLE(GPIE0IN, GPIE0); + SIG_EXPR_DECL_SINGLE(GPIE0IN, GPIE, GPIE_DESC); + SIG_EXPR_LIST_DECL_DUAL(B20, GPIE0IN, GPIE0, GPIE); + PIN_DECL_2(B20, GPIOE0, NCTS3, GPIE0IN); +@@ -299,7 +299,7 @@ FUNC_GROUP_DECL(GPIE0, B20, C20); + + #define F18 34 + SIG_EXPR_LIST_DECL_SINGLE(F18, NDSR3, NDSR3, SIG_DESC_SET(SCU80, 18)); +-SIG_EXPR_DECL_SINGLE(GPIE2IN, GPIE2, GPIE2_DESC); ++SIG_EXPR_DECL_SINGLE(GPIE2IN, GPIE2); + SIG_EXPR_DECL_SINGLE(GPIE2IN, GPIE, GPIE_DESC); + SIG_EXPR_LIST_DECL_DUAL(F18, GPIE2IN, GPIE2, GPIE); + PIN_DECL_2(F18, GPIOE2, NDSR3, GPIE2IN); +@@ -1412,7 +1412,7 @@ FUNC_GROUP_DECL(ADC15, H4); + + #define R22 192 + SIG_EXPR_DECL_SINGLE(SIOS3, SIOS3, SIG_DESC_SET(SCUA4, 8)); +-SIG_EXPR_DECL_SINGLE(SIOS3, ACPI, ACPI_DESC); ++SIG_EXPR_DECL_SINGLE(SIOS3, ACPI); + SIG_EXPR_LIST_DECL_DUAL(R22, SIOS3, SIOS3, ACPI); + SIG_EXPR_LIST_DECL_SINGLE(R22, DASHR22, DASHR22, SIG_DESC_SET(SCU94, 10)); + PIN_DECL_2(R22, GPIOY0, SIOS3, DASHR22); +@@ -1420,7 +1420,7 @@ FUNC_GROUP_DECL(SIOS3, R22); + + #define R21 193 + SIG_EXPR_DECL_SINGLE(SIOS5, SIOS5, SIG_DESC_SET(SCUA4, 9)); +-SIG_EXPR_DECL_SINGLE(SIOS5, ACPI, ACPI_DESC); ++SIG_EXPR_DECL_SINGLE(SIOS5, ACPI); + SIG_EXPR_LIST_DECL_DUAL(R21, SIOS5, SIOS5, ACPI); + SIG_EXPR_LIST_DECL_SINGLE(R21, DASHR21, DASHR21, SIG_DESC_SET(SCU94, 10)); + PIN_DECL_2(R21, GPIOY1, SIOS5, DASHR21); +@@ -1436,7 +1436,7 @@ FUNC_GROUP_DECL(SIOPWREQ, P22); + + #define P21 195 + SIG_EXPR_DECL_SINGLE(SIOONCTRL, SIOONCTRL, SIG_DESC_SET(SCUA4, 11)); +-SIG_EXPR_DECL_SINGLE(SIOONCTRL, ACPI, ACPI_DESC); ++SIG_EXPR_DECL_SINGLE(SIOONCTRL, ACPI); + SIG_EXPR_LIST_DECL_DUAL(P21, SIOONCTRL, SIOONCTRL, ACPI); + SIG_EXPR_LIST_DECL_SINGLE(P21, DASHP21, DASHP21, SIG_DESC_SET(SCU94, 11)); + PIN_DECL_2(P21, GPIOY3, SIOONCTRL, DASHP21); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-New-flash-map-for-intel.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-New-flash-map-for-intel.patch deleted file mode 100644 index 695491d28..000000000 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-New-flash-map-for-intel.patch +++ /dev/null @@ -1,117 +0,0 @@ -From f57d473a30f208754457bdb63512c307f7499ac8 Mon Sep 17 00:00:00 2001 -From: Vernon Mauery -Date: Mon, 4 Jun 2018 13:45:42 -0700 -Subject: [PATCH] New flash map for Intel - -Signed-off-by: Vernon Mauery -Signed-off-by: Vikram Bodireddy ---- - .../boot/dts/openbmc-flash-layout-intel-128MB.dtsi | 50 ++++++++++++++++++++++ - .../boot/dts/openbmc-flash-layout-intel-64MB.dtsi | 38 ++++++++++++++++ - 2 files changed, 88 insertions(+) - create mode 100644 arch/arm/boot/dts/openbmc-flash-layout-intel-128MB.dtsi - create mode 100644 arch/arm/boot/dts/openbmc-flash-layout-intel-64MB.dtsi - -diff --git a/arch/arm/boot/dts/openbmc-flash-layout-intel-128MB.dtsi b/arch/arm/boot/dts/openbmc-flash-layout-intel-128MB.dtsi -new file mode 100644 -index 000000000000..0d3794423aed ---- /dev/null -+++ b/arch/arm/boot/dts/openbmc-flash-layout-intel-128MB.dtsi -@@ -0,0 +1,50 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+// 128MB flash layout: PFR (active + tmp1/tmp2 + extra) -+// image with common RW partition -+ -+partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ u-boot@0 { -+ reg = <0x0 0x80000>; -+ label = "u-boot"; -+ }; -+ -+ pfm@80000 { -+ reg = <0x80000 0x20000>; -+ label = "pfm"; -+ }; -+ -+ u-boot-env@a0000 { -+ reg = <0xa0000 0x20000>; -+ label = "u-boot-env"; -+ }; -+ -+ sofs@c0000 { -+ reg = <0xc0000 0x200000>; -+ label = "sofs"; -+ }; -+ -+ rwfs@2c0000 { -+ reg = <0x2c0000 0x840000>; -+ label = "rwfs"; -+ }; -+ -+ fit-image-a@b00000 { -+ reg = <0xb00000 0x1f00000>; -+ label = "image-a"; -+ }; -+ -+ rc-image@2a00000 { -+ reg = <0x2a00000 0x2000000>; -+ label = "rc-image"; -+ }; -+ -+ image-staging@4a00000 { -+ reg = <0x4a00000 0x3600000>; -+ label = "image-stg"; -+ }; -+ -+}; -diff --git a/arch/arm/boot/dts/openbmc-flash-layout-intel-64MB.dtsi b/arch/arm/boot/dts/openbmc-flash-layout-intel-64MB.dtsi -new file mode 100644 -index 000000000000..092708f5021f ---- /dev/null -+++ b/arch/arm/boot/dts/openbmc-flash-layout-intel-64MB.dtsi -@@ -0,0 +1,38 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+// 64MB flash layout: redundant image with common RW partition -+ -+partitions { -+ compatible = "fixed-partitions"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ u-boot@0 { -+ reg = <0x0 0x80000>; -+ label = "u-boot"; -+ }; -+ -+ fit-image-a@80000 { -+ reg = <0x80000 0x1b80000>; -+ label = "image-a"; -+ }; -+ -+ sofs@1c00000 { -+ reg = <0x1c00000 0x200000>; -+ label = "sofs"; -+ }; -+ -+ rwfs@1e00000 { -+ reg = <0x1e00000 0x600000>; -+ label = "rwfs"; -+ }; -+ -+ u-boot-env@2400000 { -+ reg = <0x2400000 0x20000>; -+ label = "u-boot-env"; -+ }; -+ -+ fit-image-b@2480000 { -+ reg = <0x2480000 0x1b80000>; -+ label = "image-b"; -+ }; -+}; --- -2.7.4 - diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-aspeed-pwm-tacho-change-default-fan-speed.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-aspeed-pwm-tacho-change-default-fan-speed.patch new file mode 100644 index 000000000..476a07043 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-aspeed-pwm-tacho-change-default-fan-speed.patch @@ -0,0 +1,28 @@ +From b7e8941cf3b1c1c42330207600c91fb23781a77b Mon Sep 17 00:00:00 2001 +From: James Feist +Date: Tue, 2 Jul 2019 10:14:59 -0700 +Subject: [PATCH] aspeed-pwm-tacho: change default fan speed + +Change it from max to 58% + +Signed-off-by: James Feist +--- + drivers/hwmon/aspeed-pwm-tacho.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c +index 40c489be62ea..ae5771f881b5 100644 +--- a/drivers/hwmon/aspeed-pwm-tacho.c ++++ b/drivers/hwmon/aspeed-pwm-tacho.c +@@ -160,7 +160,7 @@ + */ + #define M_TACH_MODE 0x02 /* 10b */ + #define M_TACH_UNIT 0x0210 +-#define INIT_FAN_CTRL 0xFF ++#define INIT_FAN_CTRL 150 /* 58% */ + + /* How long we sleep in us while waiting for an RPM result. */ + #define ASPEED_RPM_STATUS_SLEEP_USEC 500 +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Add-ASPEED-SGPIO-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Add-ASPEED-SGPIO-driver.patch deleted file mode 100644 index 146a725dd..000000000 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Add-ASPEED-SGPIO-driver.patch +++ /dev/null @@ -1,764 +0,0 @@ -From e6923abbc90b5b00bc9ea401fbb2a28971d19cbe Mon Sep 17 00:00:00 2001 -From: "Feist, James" -Date: Tue, 4 Jun 2019 14:00:39 -0700 -Subject: [PATCH] gpio: aspeed: add ASPEED SGPIO driver - -Add SGPIO driver support for Aspeed SoCs. - -Signed-off-by: James Feist -Signed-off-by: Jae Hyun Yoo ---- - drivers/gpio/Kconfig | 8 + - drivers/gpio/Makefile | 1 + - drivers/gpio/sgpio-aspeed.c | 708 ++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 717 insertions(+) - create mode 100644 drivers/gpio/sgpio-aspeed.c - -diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig -index acd40eb51c46..20808e48229a 100644 ---- a/drivers/gpio/Kconfig -+++ b/drivers/gpio/Kconfig -@@ -124,6 +124,14 @@ config GPIO_ASPEED - help - Say Y here to support Aspeed AST2400 and AST2500 GPIO controllers. - -+config SGPIO_ASPEED -+ bool "ASPEED SGPIO support" -+ depends on ARCH_ASPEED -+ select GPIO_GENERIC -+ select GPIOLIB_IRQCHIP -+ help -+ Say Y here to support ASPEED SGPIO functionality. -+ - config GPIO_ATH79 - tristate "Atheros AR71XX/AR724X/AR913X GPIO support" - default y if ATH79 -diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile -index 6700eee860b7..77c6ec0ee98f 100644 ---- a/drivers/gpio/Makefile -+++ b/drivers/gpio/Makefile -@@ -33,6 +33,7 @@ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o - obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o - obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o - obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o -+obj-$(CONFIG_SGPIO_ASPEED) += sgpio-aspeed.o - obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o - obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o - obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o -diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c -new file mode 100644 -index 000000000000..6fb402a3f74d ---- /dev/null -+++ b/drivers/gpio/sgpio-aspeed.c -@@ -0,0 +1,708 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+// Copyright (c) 2019 Intel Corporation -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define ASPEED_SGPIO_CTRL 0x54 -+#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16) -+#define ASPEED_SGPIO_CLK_DIV_MIN 1 -+#define ASPEED_SGPIO_CLK_DIV_MAX 65535 -+#define ASPEED_SGPIO_PINBYTES_MASK GENMASK(9, 6) -+#define ASPEED_SGPIO_PINBYTES_MIN 1 -+#define ASPEED_SGPIO_PINBYTES_MAX 10 -+#define ASPEED_SGPIO_ENABLE BIT(0) -+ -+#define ASPEED_SGPIO_BUS_FREQ_DEFAULT 1000000 -+ -+struct aspeed_bank_props { -+ unsigned int bank; -+ u32 input; -+ u32 output; -+}; -+ -+struct aspeed_sgpio_config { -+ unsigned int nr_pgpios; -+ unsigned int nr_gpios; -+ const struct aspeed_bank_props *props; -+}; -+ -+struct aspeed_sgpio { -+ struct gpio_chip chip; -+ spinlock_t lock; -+ void __iomem *base; -+ int irq; -+ const struct aspeed_sgpio_config *config; -+ -+ u32 *dcache; -+}; -+ -+struct aspeed_sgpio_bank { -+ uint16_t val_reg; -+ uint16_t rdata_reg; -+ uint16_t tolerance_reg; -+ uint16_t irq_regs; -+ bool support_irq; -+ const char names[4][3]; -+}; -+ -+/* -+ * Note: The "val" register returns the input value sampled on the line. -+ * Or, it can be used for writing a value on the line. -+ * -+ * The "rdata" register returns the content of the write latch and thus -+ * can be used to read back what was last written reliably. -+ */ -+ -+static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = { -+ { -+ .val_reg = 0x0000, -+ .rdata_reg = 0x0070, -+ .tolerance_reg = 0x0018, -+ .irq_regs = 0x0004, -+ .support_irq = false, -+ .names = { "OA", "OB", "OC", "OD" }, -+ }, -+ { -+ .val_reg = 0x001C, -+ .rdata_reg = 0x0074, -+ .tolerance_reg = 0x0034, -+ .irq_regs = 0x0020, -+ .support_irq = false, -+ .names = { "OE", "OF", "OG", "OH" }, -+ }, -+ { -+ .val_reg = 0x0038, -+ .rdata_reg = 0x0078, -+ .tolerance_reg = 0x0050, -+ .irq_regs = 0x003C, -+ .support_irq = false, -+ .names = { "OI", "OJ" }, -+ }, -+ { -+ .val_reg = 0x0000, -+ .rdata_reg = 0x0070, -+ .tolerance_reg = 0x0018, -+ .irq_regs = 0x0004, -+ .support_irq = true, -+ .names = { "IA", "IB", "IC", "ID" }, -+ }, -+ { -+ .val_reg = 0x001C, -+ .rdata_reg = 0x0074, -+ .tolerance_reg = 0x0034, -+ .irq_regs = 0x0020, -+ .support_irq = true, -+ .names = { "IE", "IF", "IG", "IH" }, -+ }, -+ { -+ .val_reg = 0x0038, -+ .rdata_reg = 0x0078, -+ .tolerance_reg = 0x0050, -+ .irq_regs = 0x003C, -+ .support_irq = true, -+ .names = { "II", "IJ" }, -+ }, -+}; -+ -+enum aspeed_sgpio_reg { -+ reg_val, -+ reg_rdata, -+ reg_irq_enable, -+ reg_irq_type0, -+ reg_irq_type1, -+ reg_irq_type2, -+ reg_irq_status, -+ reg_tolerance, -+}; -+ -+#define GPIO_IRQ_ENABLE 0x00 -+#define GPIO_IRQ_TYPE0 0x04 -+#define GPIO_IRQ_TYPE1 0x08 -+#define GPIO_IRQ_TYPE2 0x0c -+#define GPIO_IRQ_STATUS 0x10 -+ -+/* This will be resolved at compile time */ -+static inline void __iomem *bank_reg(struct aspeed_sgpio *gpio, -+ const struct aspeed_sgpio_bank *bank, -+ const enum aspeed_sgpio_reg reg) -+{ -+ switch (reg) { -+ case reg_val: -+ return gpio->base + bank->val_reg; -+ case reg_rdata: -+ return gpio->base + bank->rdata_reg; -+ case reg_irq_enable: -+ return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE; -+ case reg_irq_type0: -+ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0; -+ case reg_irq_type1: -+ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1; -+ case reg_irq_type2: -+ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2; -+ case reg_irq_status: -+ return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS; -+ case reg_tolerance: -+ return gpio->base + bank->tolerance_reg; -+ default: -+ WARN_ON(1); -+ } -+ -+ return NULL; -+} -+ -+#define GPIO_BANK(x) ((x) >> 5) -+#define GPIO_OFFSET(x) ((x) & 0x1f) -+#define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) -+ -+static const struct aspeed_sgpio_bank *to_bank(unsigned int offset) -+{ -+ unsigned int bank = GPIO_BANK(offset); -+ -+ WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks)); -+ return &aspeed_sgpio_banks[bank]; -+} -+ -+static inline bool is_bank_props_sentinel(const struct aspeed_bank_props *props) -+{ -+ return !(props->input || props->output); -+} -+ -+static inline const struct aspeed_bank_props *find_bank_props( -+ struct aspeed_sgpio *gpio, unsigned int offset) -+{ -+ const struct aspeed_bank_props *props = gpio->config->props; -+ -+ while (!is_bank_props_sentinel(props)) { -+ if (props->bank == GPIO_BANK(offset)) -+ return props; -+ props++; -+ } -+ -+ return NULL; -+} -+ -+static inline bool have_input(struct aspeed_sgpio *gpio, unsigned int offset) -+{ -+ const struct aspeed_bank_props *props = find_bank_props(gpio, offset); -+ -+ return !props || (props->input & GPIO_BIT(offset)); -+} -+ -+static inline bool have_output(struct aspeed_sgpio *gpio, unsigned int offset) -+{ -+ const struct aspeed_bank_props *props = find_bank_props(gpio, offset); -+ -+ return !props || (props->output & GPIO_BIT(offset)); -+} -+ -+static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset) -+{ -+ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); -+ const struct aspeed_sgpio_bank *bank = to_bank(offset); -+ enum aspeed_sgpio_reg reg; -+ -+ if (have_output(gpio, offset)) -+ reg = reg_rdata; -+ else -+ reg = reg_val; -+ -+ return !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset)); -+} -+ -+static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val) -+{ -+ const struct aspeed_sgpio_bank *bank = to_bank(offset); -+ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); -+ unsigned long flags; -+ u32 reg; -+ -+ if (!have_output(gpio, offset)) -+ return; -+ -+ spin_lock_irqsave(&gpio->lock, flags); -+ -+ reg = ioread32(bank_reg(gpio, bank, reg_rdata)); -+ -+ if (val) -+ reg |= GPIO_BIT(offset); -+ else -+ reg &= ~GPIO_BIT(offset); -+ -+ iowrite32(reg, bank_reg(gpio, bank, reg_val)); -+ -+ spin_unlock_irqrestore(&gpio->lock, flags); -+} -+ -+static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset) -+{ -+ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); -+ -+ if (!have_input(gpio, offset)) -+ return -ENOTSUPP; -+ -+ return 0; -+} -+ -+static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, -+ int val) -+{ -+ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); -+ -+ if (!have_output(gpio, offset)) -+ return -ENOTSUPP; -+ -+ return 0; -+} -+ -+static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset) -+{ -+ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); -+ -+ if (have_output(gpio, offset)) -+ return 0; -+ else if (have_input(gpio, offset)) -+ return 1; -+ -+ return -ENOTSUPP; -+} -+ -+static inline int -+irqd_to_aspeed_sgpio_data(struct irq_data *d, struct aspeed_sgpio **gpio, -+ const struct aspeed_sgpio_bank **bank, -+ u32 *bit, int *offset) -+{ -+ struct aspeed_sgpio *internal; -+ -+ *offset = irqd_to_hwirq(d); -+ -+ internal = irq_data_get_irq_chip_data(d); -+ -+ *gpio = internal; -+ *bank = to_bank(*offset); -+ *bit = GPIO_BIT(*offset); -+ -+ return 0; -+} -+ -+static void aspeed_sgpio_irq_ack(struct irq_data *d) -+{ -+ const struct aspeed_sgpio_bank *bank; -+ struct aspeed_sgpio *gpio; -+ void __iomem *status_addr; -+ unsigned long flags; -+ int rc, offset; -+ u32 bit; -+ -+ rc = irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); -+ if (rc) -+ return; -+ -+ status_addr = bank_reg(gpio, bank, reg_irq_status); -+ -+ spin_lock_irqsave(&gpio->lock, flags); -+ -+ iowrite32(bit, status_addr); -+ -+ spin_unlock_irqrestore(&gpio->lock, flags); -+} -+ -+static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set) -+{ -+ const struct aspeed_sgpio_bank *bank; -+ struct aspeed_sgpio *gpio; -+ unsigned long flags; -+ u32 reg, bit; -+ void __iomem *addr; -+ int rc, offset; -+ -+ rc = irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); -+ if (rc) -+ return; -+ -+ if (!bank->support_irq) -+ return; -+ -+ addr = bank_reg(gpio, bank, reg_irq_enable); -+ -+ spin_lock_irqsave(&gpio->lock, flags); -+ -+ reg = ioread32(addr); -+ if (set) -+ reg |= bit; -+ else -+ reg &= ~bit; -+ -+ iowrite32(reg, addr); -+ -+ spin_unlock_irqrestore(&gpio->lock, flags); -+} -+ -+static void aspeed_sgpio_irq_mask(struct irq_data *d) -+{ -+ aspeed_sgpio_irq_set_mask(d, false); -+} -+ -+static void aspeed_sgpio_irq_unmask(struct irq_data *d) -+{ -+ aspeed_sgpio_irq_set_mask(d, true); -+} -+ -+static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type) -+{ -+ u32 type0 = 0; -+ u32 type1 = 0; -+ u32 type2 = 0; -+ u32 bit, reg; -+ const struct aspeed_sgpio_bank *bank; -+ irq_flow_handler_t handler; -+ struct aspeed_sgpio *gpio; -+ unsigned long flags; -+ void __iomem *addr; -+ int rc, offset; -+ -+ rc = irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); -+ if (rc) -+ return -EINVAL; -+ -+ if (!bank->support_irq) -+ return -ENOTSUPP; -+ -+ switch (type & IRQ_TYPE_SENSE_MASK) { -+ case IRQ_TYPE_EDGE_BOTH: -+ type2 |= bit; -+ /* fall through */ -+ case IRQ_TYPE_EDGE_RISING: -+ type0 |= bit; -+ /* fall through */ -+ case IRQ_TYPE_EDGE_FALLING: -+ handler = handle_edge_irq; -+ break; -+ case IRQ_TYPE_LEVEL_HIGH: -+ type0 |= bit; -+ /* fall through */ -+ case IRQ_TYPE_LEVEL_LOW: -+ type1 |= bit; -+ handler = handle_level_irq; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ spin_lock_irqsave(&gpio->lock, flags); -+ -+ addr = bank_reg(gpio, bank, reg_irq_type0); -+ reg = ioread32(addr); -+ reg = (reg & ~bit) | type0; -+ iowrite32(reg, addr); -+ -+ addr = bank_reg(gpio, bank, reg_irq_type1); -+ reg = ioread32(addr); -+ reg = (reg & ~bit) | type1; -+ iowrite32(reg, addr); -+ -+ addr = bank_reg(gpio, bank, reg_irq_type2); -+ reg = ioread32(addr); -+ reg = (reg & ~bit) | type2; -+ iowrite32(reg, addr); -+ -+ spin_unlock_irqrestore(&gpio->lock, flags); -+ -+ irq_set_handler_locked(d, handler); -+ -+ return 0; -+} -+ -+static void aspeed_sgpio_irq_handler(struct irq_desc *desc) -+{ -+ struct gpio_chip *gc = irq_desc_get_handler_data(desc); -+ struct aspeed_sgpio *data = gpiochip_get_data(gc); -+ struct irq_chip *ic = irq_desc_get_chip(desc); -+ unsigned int i, p, girq; -+ unsigned long reg; -+ -+ chained_irq_enter(ic, desc); -+ -+ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { -+ const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i]; -+ -+ if (!bank->support_irq) -+ continue; -+ -+ reg = ioread32(bank_reg(data, bank, reg_irq_status)); -+ -+ for_each_set_bit(p, ®, 32) { -+ girq = irq_find_mapping(gc->irq.domain, i * 32 + p); -+ generic_handle_irq(girq); -+ } -+ } -+ -+ chained_irq_exit(ic, desc); -+} -+ -+static struct irq_chip aspeed_sgpio_irqchip = { -+ .name = "aspeed-sgpio", -+ .irq_ack = aspeed_sgpio_irq_ack, -+ .irq_mask = aspeed_sgpio_irq_mask, -+ .irq_unmask = aspeed_sgpio_irq_unmask, -+ .irq_set_type = aspeed_sgpio_set_type, -+}; -+ -+static void set_irq_valid_mask(struct aspeed_sgpio *gpio) -+{ -+ const struct aspeed_bank_props *props = gpio->config->props; -+ -+ while (!is_bank_props_sentinel(props)) { -+ unsigned int offset; -+ const unsigned long int input = props->input; -+ -+ /* Pretty crummy approach, but similar to GPIO core */ -+ for_each_clear_bit(offset, &input, 32) { -+ unsigned int i = props->bank * 32 + offset; -+ -+ if (i >= gpio->config->nr_gpios) -+ break; -+ -+ clear_bit(i, gpio->chip.irq.valid_mask); -+ } -+ -+ props++; -+ } -+} -+ -+static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio, -+ struct platform_device *pdev) -+{ -+ const struct aspeed_sgpio_bank *bank; -+ int rc, i; -+ -+ /* Initialize IRQ and tolerant settings */ -+ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { -+ bank = &aspeed_sgpio_banks[i]; -+ -+ /* Value will be reset by WDT reset */ -+ iowrite32(0x00000000, bank_reg(gpio, bank, reg_tolerance)); -+ -+ if (!bank->support_irq) -+ continue; -+ -+ /* disable irq enable bits */ -+ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable)); -+ /* clear status bits */ -+ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status)); -+ /* set rising or level-high irq */ -+ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type0)); -+ /* trigger type is level */ -+ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type1)); -+ /* single trigger mode */ -+ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2)); -+ } -+ -+ rc = platform_get_irq(pdev, 0); -+ if (rc < 0) -+ return rc; -+ -+ gpio->irq = rc; -+ -+ set_irq_valid_mask(gpio); -+ -+ rc = gpiochip_irqchip_add(&gpio->chip, &aspeed_sgpio_irqchip, -+ 0, handle_bad_irq, IRQ_TYPE_NONE); -+ if (rc) { -+ dev_info(&pdev->dev, "Could not add irqchip\n"); -+ return rc; -+ } -+ -+ gpiochip_set_chained_irqchip(&gpio->chip, &aspeed_sgpio_irqchip, -+ gpio->irq, aspeed_sgpio_irq_handler); -+ -+ return 0; -+} -+ -+static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip, -+ unsigned int offset, bool enable) -+{ -+ struct aspeed_sgpio *gpio = gpiochip_get_data(chip); -+ unsigned long flags; -+ void __iomem *treg; -+ u32 val; -+ -+ treg = bank_reg(gpio, to_bank(offset), reg_tolerance); -+ -+ spin_lock_irqsave(&gpio->lock, flags); -+ -+ val = readl(treg); -+ -+ if (enable) -+ val |= GPIO_BIT(offset); -+ else -+ val &= ~GPIO_BIT(offset); -+ -+ writel(val, treg); -+ -+ spin_unlock_irqrestore(&gpio->lock, flags); -+ -+ return 0; -+} -+ -+static int aspeed_sgpio_set_config(struct gpio_chip *chip, unsigned int offset, -+ unsigned long config) -+{ -+ unsigned long param = pinconf_to_config_param(config); -+ u32 arg = pinconf_to_config_argument(config); -+ -+ if (param == PIN_CONFIG_PERSIST_STATE) -+ return aspeed_sgpio_reset_tolerance(chip, offset, arg); -+ -+ return -ENOTSUPP; -+} -+ -+/* -+ * Any banks not specified in a struct aspeed_bank_props array are assumed to -+ * have the properties: -+ * -+ * { .input = 0xffffffff, .output = 0xffffffff } -+ */ -+ -+static const struct aspeed_bank_props ast_sgpio_bank_props[] = { -+ /* input output */ -+ { 0, 0x00000000, 0xffffffff }, /* OA/OB/OC/OD */ -+ { 1, 0x00000000, 0xffffffff }, /* OE/OF/OG/OH */ -+ { 2, 0x00000000, 0x0000ffff }, /* OI/OJ */ -+ { 3, 0xffffffff, 0x00000000 }, /* IA/IB/IC/ID */ -+ { 4, 0xffffffff, 0x00000000 }, /* IE/IF/IG/IH */ -+ { 5, 0x0000ffff, 0x00000000 }, /* II/IJ */ -+ { } -+}; -+ -+/* -+ * This H/W has 80 bidirectional lines so this driver provides total 160 lines -+ * for 80 outputs and 80 inputs. To simplify bank register manipulation, it -+ * uses 96 lines per each input and output set so total 192 lines it has. -+ */ -+static const struct aspeed_sgpio_config ast2400_config = -+ { .nr_pgpios = 224, .nr_gpios = 192, .props = ast_sgpio_bank_props }; -+ -+static const struct aspeed_sgpio_config ast2500_config = -+ { .nr_pgpios = 232, .nr_gpios = 192, .props = ast_sgpio_bank_props }; -+ -+static const struct of_device_id aspeed_sgpio_of_table[] = { -+ { .compatible = "aspeed,ast2400-sgpio", .data = &ast2400_config }, -+ { .compatible = "aspeed,ast2500-sgpio", .data = &ast2500_config }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table); -+ -+static int __init aspeed_sgpio_probe(struct platform_device *pdev) -+{ -+ const struct of_device_id *gpio_id; -+ u32 sgpio_freq, clk_div, nb_gpios; -+ struct aspeed_sgpio *gpio; -+ unsigned long src_freq; -+ struct clk *clk; -+ int rc, banks; -+ -+ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); -+ if (!gpio) -+ return -ENOMEM; -+ -+ gpio->base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(gpio->base)) -+ return PTR_ERR(gpio->base); -+ -+ spin_lock_init(&gpio->lock); -+ -+ gpio_id = of_match_node(aspeed_sgpio_of_table, pdev->dev.of_node); -+ if (!gpio_id) -+ return -EINVAL; -+ -+ gpio->config = gpio_id->data; -+ -+ rc = device_property_read_u32(&pdev->dev, "bus-frequency", &sgpio_freq); -+ if (rc < 0) { -+ dev_warn(&pdev->dev, "Could not read bus-frequency property. Use default.\n"); -+ sgpio_freq = ASPEED_SGPIO_BUS_FREQ_DEFAULT; -+ } -+ -+ clk = devm_clk_get(&pdev->dev, NULL); -+ if (IS_ERR(clk)) { -+ dev_err(&pdev->dev, "Failed to get clk source.\n"); -+ return PTR_ERR(clk); -+ } -+ -+ /* -+ * There is a limitation that SGPIO clock division has to be larger or -+ * equal to 1. And a read back value of clock division is 1-bit left -+ * shifted from the actual value. -+ * -+ * GPIO254[31:16] - Serial GPIO clock division: -+ * Serial GPIO clock period = period of PCLK * 2 * (GPIO254[31:16] + 1) -+ * -+ * SGPIO master controller updates every data input when SGPMLD is low. -+ * For an example, SGPIO clock is 1MHz and number of SGPIO is 80. Each -+ * SGPIO will be updated every 80us. -+ */ -+ src_freq = clk_get_rate(clk); -+ clk_div = src_freq / (2 * sgpio_freq) - 1; -+ if (clk_div < ASPEED_SGPIO_CLK_DIV_MIN) -+ clk_div = ASPEED_SGPIO_CLK_DIV_MIN; -+ else if (clk_div > ASPEED_SGPIO_CLK_DIV_MAX) -+ clk_div = ASPEED_SGPIO_CLK_DIV_MAX; -+ -+ nb_gpios = gpio->config->nr_gpios / 16; -+ if (nb_gpios < ASPEED_SGPIO_PINBYTES_MIN) -+ nb_gpios = ASPEED_SGPIO_PINBYTES_MIN; -+ else if (nb_gpios > ASPEED_SGPIO_PINBYTES_MAX) -+ nb_gpios = ASPEED_SGPIO_PINBYTES_MAX; -+ -+ iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, clk_div) | -+ FIELD_PREP(ASPEED_SGPIO_PINBYTES_MASK, nb_gpios) | -+ ASPEED_SGPIO_ENABLE, -+ gpio->base + ASPEED_SGPIO_CTRL); -+ -+ gpio->chip.parent = &pdev->dev; -+ gpio->chip.ngpio = gpio->config->nr_gpios; -+ -+ gpio->chip.direction_input = aspeed_sgpio_dir_in; -+ gpio->chip.direction_output = aspeed_sgpio_dir_out; -+ gpio->chip.get_direction = aspeed_sgpio_get_direction; -+ gpio->chip.get = aspeed_sgpio_get; -+ gpio->chip.set = aspeed_sgpio_set; -+ gpio->chip.set_config = aspeed_sgpio_set_config; -+ gpio->chip.label = dev_name(&pdev->dev); -+ gpio->chip.base = -1; -+ gpio->chip.irq.need_valid_mask = true; -+ -+ /* Allocate a cache of the output registers */ -+ banks = gpio->config->nr_gpios >> 5; -+ -+ gpio->dcache = devm_kcalloc(&pdev->dev, -+ banks, sizeof(u32), GFP_KERNEL); -+ -+ if (!gpio->dcache) -+ return -ENOMEM; -+ -+ rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); -+ if (rc < 0) -+ return rc; -+ -+ return aspeed_sgpio_setup_irqs(gpio, pdev); -+} -+ -+static struct platform_driver aspeed_sgpio_driver = { -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = aspeed_sgpio_of_table, -+ }, -+}; -+ -+module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe); -+ -+MODULE_AUTHOR("Jae Hyun Yoo "); -+MODULE_DESCRIPTION("Aspeed SGPIO Master Driver"); -+MODULE_LICENSE("GPL v2"); --- -2.7.4 - diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Report-link-statistics-for-the-NCSI-channel.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Report-link-statistics-for-the-NCSI-channel.patch new file mode 100644 index 000000000..643deb659 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Report-link-statistics-for-the-NCSI-channel.patch @@ -0,0 +1,54 @@ +From f3300099b6638df5829e75b1fbfbb6e7ebc8b2b9 Mon Sep 17 00:00:00 2001 +From: Johnathan Mantey +Date: Thu, 1 Aug 2019 11:29:41 -0700 +Subject: [PATCH] Report link statistics for the NCSI channel + +The ftgmac driver does not report the link statistics for the NCSI +channel used for the shared NICs attached to the BMC. Report a fixed +value for the NSCI interface. + +Change-Id: Idb65ca1ce07f06a883417ee44df30ea2c8483107 +Signed-off-by: Johnathan Mantey +--- + drivers/net/ethernet/faraday/ftgmac100.c | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c +index 9b7af94a40bb..4cd679233795 100644 +--- a/drivers/net/ethernet/faraday/ftgmac100.c ++++ b/drivers/net/ethernet/faraday/ftgmac100.c +@@ -1216,10 +1216,30 @@ static int ftgmac100_set_pauseparam(struct net_device *netdev, + return 0; + } + ++int ftgmac100_ethtool_get_link_ksettings(struct net_device *netdev, ++ struct ethtool_link_ksettings *cmd) ++{ ++ struct phy_device *phydev = netdev->phydev; ++ struct ftgmac100 *priv = netdev_priv(netdev); ++ int retval = 0; ++ ++ if (phydev) { ++ phy_ethtool_ksettings_get(phydev, cmd); ++ } else if (priv->use_ncsi) { ++ cmd->base.speed = SPEED_100; ++ cmd->base.duplex = DUPLEX_FULL; ++ cmd->base.autoneg = 0; ++ } else { ++ retval = -ENODEV; ++ } ++ ++ return retval; ++} ++ + static const struct ethtool_ops ftgmac100_ethtool_ops = { + .get_drvinfo = ftgmac100_get_drvinfo, + .get_link = ethtool_op_get_link, +- .get_link_ksettings = phy_ethtool_get_link_ksettings, ++ .get_link_ksettings = ftgmac100_ethtool_get_link_ksettings, + .set_link_ksettings = phy_ethtool_set_link_ksettings, + .nway_reset = phy_ethtool_nway_reset, + .get_ringparam = ftgmac100_get_ringparam, +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0009-SGPIO-DT-and-pinctrl-fixup.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0009-SGPIO-DT-and-pinctrl-fixup.patch deleted file mode 100644 index 4210d9f67..000000000 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0009-SGPIO-DT-and-pinctrl-fixup.patch +++ /dev/null @@ -1,244 +0,0 @@ -From 0f63ecc25766fdf66610d08441e59147a4cbde78 Mon Sep 17 00:00:00 2001 -From: Vernon Mauery -Date: Wed, 16 May 2018 10:03:14 -0700 -Subject: [PATCH] SGPIO DT and pinctrl fixup - -This commit fixes DT and pinctrl for SGPIO use. - -Signed-off-by: Vernon Mauery -Signed-off-by: Jae Hyun Yoo ---- - arch/arm/boot/dts/aspeed-g4.dtsi | 56 +++++++++++------------------- - arch/arm/boot/dts/aspeed-g5.dtsi | 10 ++++++ - drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c | 48 ++++++++++++------------- - drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 4 +++ - 4 files changed, 58 insertions(+), 60 deletions(-) - -diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi -index fd857be397bf..58306a8232c9 100644 ---- a/arch/arm/boot/dts/aspeed-g4.dtsi -+++ b/arch/arm/boot/dts/aspeed-g4.dtsi -@@ -207,6 +207,20 @@ - #interrupt-cells = <2>; - }; - -+ sgpio: sgpio@1e780200 { -+ #gpio-cells = <2>; -+ gpio-controller; -+ compatible = "aspeed,ast2400-sgpio"; -+ reg = <0x1e780200 0x0100>; -+ interrupts = <40>; -+ interrupt-controller; -+ clocks = <&syscon ASPEED_CLK_APB>; -+ bus-frequency = <1000000>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_sgpm_default>; -+ status = "disabled"; -+ }; -+ - timer: timer@1e782000 { - /* This timer is a Faraday FTTMR010 derivative */ - compatible = "aspeed,ast2400-timer"; -@@ -1180,44 +1194,14 @@ - groups = "SD2"; - }; - -- pinctrl_sgpmck_default: sgpmck_default { -- function = "SGPMCK"; -- groups = "SGPMCK"; -- }; -- -- pinctrl_sgpmi_default: sgpmi_default { -- function = "SGPMI"; -- groups = "SGPMI"; -- }; -- -- pinctrl_sgpmld_default: sgpmld_default { -- function = "SGPMLD"; -- groups = "SGPMLD"; -- }; -- -- pinctrl_sgpmo_default: sgpmo_default { -- function = "SGPMO"; -- groups = "SGPMO"; -- }; -- -- pinctrl_sgpsck_default: sgpsck_default { -- function = "SGPSCK"; -- groups = "SGPSCK"; -- }; -- -- pinctrl_sgpsi0_default: sgpsi0_default { -- function = "SGPSI0"; -- groups = "SGPSI0"; -- }; -- -- pinctrl_sgpsi1_default: sgpsi1_default { -- function = "SGPSI1"; -- groups = "SGPSI1"; -+ pinctrl_sgpm_default: sgpm_default { -+ function = "SGPM"; -+ groups = "SGPM"; - }; - -- pinctrl_sgpsld_default: sgpsld_default { -- function = "SGPSLD"; -- groups = "SGPSLD"; -+ pinctrl_sgps_default: sgps_default { -+ function = "SGPS"; -+ groups = "SGPS"; - }; - - pinctrl_sioonctrl_default: sioonctrl_default { -diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi -index db82f47339aa..425a542690de 100644 ---- a/arch/arm/boot/dts/aspeed-g5.dtsi -+++ b/arch/arm/boot/dts/aspeed-g5.dtsi -@@ -298,6 +298,11 @@ - reg = <0x1e780200 0x0100>; - interrupts = <40>; - interrupt-controller; -+ clocks = <&syscon ASPEED_CLK_APB>; -+ bus-frequency = <1000000>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_sgpm_default>; -+ status = "disabled"; - }; - - rtc: rtc@1e781000 { -@@ -1403,6 +1408,11 @@ - groups = "SDA2"; - }; - -+ pinctrl_sgpm_default: sgpm_default { -+ function = "SGPM"; -+ groups = "SGPM"; -+ }; -+ - pinctrl_sgps1_default: sgps1_default { - function = "SGPS1"; - groups = "SGPS1"; -diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c -index 384396cbb22d..a78ed8c33e96 100644 ---- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c -+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c -@@ -423,16 +423,22 @@ SSSF_PIN_DECL(E16, GPIOF6, TXD4, SIG_DESC_SET(SCU80, 30)); - SSSF_PIN_DECL(C17, GPIOF7, RXD4, SIG_DESC_SET(SCU80, 31)); - - #define A14 48 --SSSF_PIN_DECL(A14, GPIOG0, SGPSCK, SIG_DESC_SET(SCU84, 0)); -+SIG_EXPR_LIST_DECL_SINGLE(SGPSCK, SGPS, SIG_DESC_SET(SCU84, 0)); -+SS_PIN_DECL(A14, GPIOG0, SGPSCK); - - #define E13 49 --SSSF_PIN_DECL(E13, GPIOG1, SGPSLD, SIG_DESC_SET(SCU84, 1)); -+SIG_EXPR_LIST_DECL_SINGLE(SGPSLD, SGPS, SIG_DESC_SET(SCU84, 1)); -+SS_PIN_DECL(E13, GPIOG1, SGPSLD); - - #define D13 50 --SSSF_PIN_DECL(D13, GPIOG2, SGPSI0, SIG_DESC_SET(SCU84, 2)); -+SIG_EXPR_LIST_DECL_SINGLE(SGPSIO, SGPS, SIG_DESC_SET(SCU84, 2)); -+SS_PIN_DECL(D13, GPIOG2, SGPSIO); - - #define C13 51 --SSSF_PIN_DECL(C13, GPIOG3, SGPSI1, SIG_DESC_SET(SCU84, 3)); -+SIG_EXPR_LIST_DECL_SINGLE(SGPSI1, SGPS, SIG_DESC_SET(SCU84, 3)); -+SS_PIN_DECL(C13, GPIOG3, SGPSI1); -+ -+FUNC_GROUP_DECL(SGPS, A14, E13, D13, C13); - - #define B13 52 - SIG_EXPR_LIST_DECL_SINGLE(OSCCLK, OSCCLK, SIG_DESC_SET(SCU2C, 1)); -@@ -598,16 +604,22 @@ FUNC_GROUP_DECL(SPI1PASSTHRU, C22, G18, D19, C20, B22, G19, C18, E20); - FUNC_GROUP_DECL(VGABIOS_ROM, B22, G19, C18, E20); - - #define J5 72 --SSSF_PIN_DECL(J5, GPIOJ0, SGPMCK, SIG_DESC_SET(SCU84, 8)); -+SIG_EXPR_LIST_DECL_SINGLE(SGPMCK, SGPM, SIG_DESC_SET(SCU84, 8)); -+SS_PIN_DECL(J5, GPIOJ0, SGPMCK); - - #define J4 73 --SSSF_PIN_DECL(J4, GPIOJ1, SGPMLD, SIG_DESC_SET(SCU84, 9)); -+SIG_EXPR_LIST_DECL_SINGLE(SGPMLD, SGPM, SIG_DESC_SET(SCU84, 9)); -+SS_PIN_DECL(J4, GPIOJ1, SGPMLD); - - #define K5 74 --SSSF_PIN_DECL(K5, GPIOJ2, SGPMO, SIG_DESC_SET(SCU84, 10)); -+SIG_EXPR_LIST_DECL_SINGLE(SGPMO, SGPM, SIG_DESC_SET(SCU84, 10)); -+SS_PIN_DECL(K5, GPIOJ2, SGPMO); - - #define J3 75 --SSSF_PIN_DECL(J3, GPIOJ3, SGPMI, SIG_DESC_SET(SCU84, 11)); -+SIG_EXPR_LIST_DECL_SINGLE(SGPMI, SGPM, SIG_DESC_SET(SCU84, 11)); -+SS_PIN_DECL(J3, GPIOJ3, SGPMI); -+ -+FUNC_GROUP_DECL(SGPM, J5, J4, K5, J3); - - #define T4 76 - SSSF_PIN_DECL(T4, GPIOJ4, VGAHS, SIG_DESC_SET(SCU84, 12)); -@@ -2105,14 +2117,8 @@ static const struct aspeed_pin_group aspeed_g4_groups[] = { - ASPEED_PINCTRL_GROUP(SALT4), - ASPEED_PINCTRL_GROUP(SD1), - ASPEED_PINCTRL_GROUP(SD2), -- ASPEED_PINCTRL_GROUP(SGPMCK), -- ASPEED_PINCTRL_GROUP(SGPMI), -- ASPEED_PINCTRL_GROUP(SGPMLD), -- ASPEED_PINCTRL_GROUP(SGPMO), -- ASPEED_PINCTRL_GROUP(SGPSCK), -- ASPEED_PINCTRL_GROUP(SGPSI0), -- ASPEED_PINCTRL_GROUP(SGPSI1), -- ASPEED_PINCTRL_GROUP(SGPSLD), -+ ASPEED_PINCTRL_GROUP(SGPM), -+ ASPEED_PINCTRL_GROUP(SGPS), - ASPEED_PINCTRL_GROUP(SIOONCTRL), - ASPEED_PINCTRL_GROUP(SIOPBI), - ASPEED_PINCTRL_GROUP(SIOPBO), -@@ -2260,14 +2266,8 @@ static const struct aspeed_pin_function aspeed_g4_functions[] = { - ASPEED_PINCTRL_FUNC(SALT4), - ASPEED_PINCTRL_FUNC(SD1), - ASPEED_PINCTRL_FUNC(SD2), -- ASPEED_PINCTRL_FUNC(SGPMCK), -- ASPEED_PINCTRL_FUNC(SGPMI), -- ASPEED_PINCTRL_FUNC(SGPMLD), -- ASPEED_PINCTRL_FUNC(SGPMO), -- ASPEED_PINCTRL_FUNC(SGPSCK), -- ASPEED_PINCTRL_FUNC(SGPSI0), -- ASPEED_PINCTRL_FUNC(SGPSI1), -- ASPEED_PINCTRL_FUNC(SGPSLD), -+ ASPEED_PINCTRL_FUNC(SGPM), -+ ASPEED_PINCTRL_FUNC(SGPS), - ASPEED_PINCTRL_FUNC(SIOONCTRL), - ASPEED_PINCTRL_FUNC(SIOPBI), - ASPEED_PINCTRL_FUNC(SIOPBO), -diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c -index 6f151e7c8d81..c088f010c554 100644 ---- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c -+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c -@@ -599,6 +599,8 @@ SS_PIN_DECL(N3, GPIOJ2, SGPMO); - SIG_EXPR_LIST_DECL_SINGLE(SGPMI, SGPM, SIG_DESC_SET(SCU84, 11)); - SS_PIN_DECL(N4, GPIOJ3, SGPMI); - -+FUNC_GROUP_DECL(SGPM, R2, L2, N3, N4); -+ - #define N5 76 - SIG_EXPR_LIST_DECL_SINGLE(VGAHS, VGAHS, SIG_DESC_SET(SCU84, 12)); - SIG_EXPR_LIST_DECL_SINGLE(DASHN5, DASHN5, SIG_DESC_SET(SCU94, 8)); -@@ -2149,6 +2151,7 @@ static const struct aspeed_pin_group aspeed_g5_groups[] = { - ASPEED_PINCTRL_GROUP(SD2), - ASPEED_PINCTRL_GROUP(SDA1), - ASPEED_PINCTRL_GROUP(SDA2), -+ ASPEED_PINCTRL_GROUP(SGPM), - ASPEED_PINCTRL_GROUP(SGPS1), - ASPEED_PINCTRL_GROUP(SGPS2), - ASPEED_PINCTRL_GROUP(SIOONCTRL), -@@ -2318,6 +2321,7 @@ static const struct aspeed_pin_function aspeed_g5_functions[] = { - ASPEED_PINCTRL_FUNC(SD2), - ASPEED_PINCTRL_FUNC(SDA1), - ASPEED_PINCTRL_FUNC(SDA2), -+ ASPEED_PINCTRL_FUNC(SGPM), - ASPEED_PINCTRL_FUNC(SGPS1), - ASPEED_PINCTRL_FUNC(SGPS2), - ASPEED_PINCTRL_FUNC(SIOONCTRL), --- -2.7.4 - diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch deleted file mode 100644 index 329a92cd6..000000000 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch +++ /dev/null @@ -1,5566 +0,0 @@ -From 691b8580a1592eddb919e8dd295e6c1f136a4c00 Mon Sep 17 00:00:00 2001 -From: Jae Hyun Yoo -Date: Mon, 7 Jan 2019 09:56:10 -0800 -Subject: [PATCH] Update PECI drivers to sync with linux upstreaming version - -Upstreaming is in holding. It's for adding DTS sensor with PECI -subsystem code update. - -Signed-off-by: Jae Hyun Yoo ---- - Documentation/hwmon/peci-cputemp | 34 +- - drivers/hwmon/Kconfig | 4 +- - drivers/hwmon/peci-cputemp.c | 171 ++++--- - drivers/hwmon/peci-dimmtemp.c | 184 +++++-- - drivers/hwmon/peci-hwmon.h | 9 +- - drivers/mfd/Kconfig | 5 +- - drivers/mfd/intel-peci-client.c | 51 +- - drivers/peci/Kconfig | 46 +- - drivers/peci/Makefile | 7 +- - drivers/peci/busses/Kconfig | 32 ++ - drivers/peci/busses/Makefile | 7 + - drivers/peci/busses/peci-aspeed.c | 492 ++++++++++++++++++ - drivers/peci/busses/peci-npcm.c | 410 +++++++++++++++ - drivers/peci/peci-aspeed.c | 505 ------------------- - drivers/peci/peci-core.c | 914 ++++++++++++++++++---------------- - drivers/peci/peci-dev.c | 346 +++++++++++++ - drivers/peci/peci-npcm.c | 410 --------------- - include/linux/mfd/intel-peci-client.h | 31 +- - include/linux/peci.h | 30 +- - include/uapi/linux/peci-ioctl.h | 416 +++++++++------- - 20 files changed, 2402 insertions(+), 1702 deletions(-) - create mode 100644 drivers/peci/busses/Kconfig - create mode 100644 drivers/peci/busses/Makefile - create mode 100644 drivers/peci/busses/peci-aspeed.c - create mode 100644 drivers/peci/busses/peci-npcm.c - delete mode 100644 drivers/peci/peci-aspeed.c - create mode 100644 drivers/peci/peci-dev.c - delete mode 100644 drivers/peci/peci-npcm.c - -diff --git a/Documentation/hwmon/peci-cputemp b/Documentation/hwmon/peci-cputemp -index 821a9258f2e6..a3a3e465c888 100644 ---- a/Documentation/hwmon/peci-cputemp -+++ b/Documentation/hwmon/peci-cputemp -@@ -51,28 +51,38 @@ temp1_crit Provides shutdown temperature of the CPU package which - temp1_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of - the CPU package. - --temp2_label "Tcontrol" --temp2_input Provides current Tcontrol temperature of the CPU -+temp2_label "DTS" -+temp2_input Provides current DTS temperature of the CPU package. -+temp2_max Provides thermal control temperature of the CPU package -+ which is also known as Tcontrol. -+temp2_crit Provides shutdown temperature of the CPU package which -+ is also known as the maximum processor junction -+ temperature, Tjmax or Tprochot. -+temp2_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of -+ the CPU package. -+ -+temp3_label "Tcontrol" -+temp3_input Provides current Tcontrol temperature of the CPU - package which is also known as Fan Temperature target. - Indicates the relative value from thermal monitor trip - temperature at which fans should be engaged. --temp2_crit Provides Tcontrol critical value of the CPU package -+temp3_crit Provides Tcontrol critical value of the CPU package - which is same to Tjmax. - --temp3_label "Tthrottle" --temp3_input Provides current Tthrottle temperature of the CPU -+temp4_label "Tthrottle" -+temp4_input Provides current Tthrottle temperature of the CPU - package. Used for throttling temperature. If this value - is allowed and lower than Tjmax - the throttle will - occur and reported at lower than Tjmax. - --temp4_label "Tjmax" --temp4_input Provides the maximum junction temperature, Tjmax of the -+temp5_label "Tjmax" -+temp5_input Provides the maximum junction temperature, Tjmax of the - CPU package. - --temp[5-*]_label Provides string "Core X", where X is resolved core -+temp[6-*]_label Provides string "Core X", where X is resolved core - number. --temp[5-*]_input Provides current temperature of each core. --temp[5-*]_max Provides thermal control temperature of the core. --temp[5-*]_crit Provides shutdown temperature of the core. --temp[5-*]_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of -+temp[6-*]_input Provides current temperature of each core. -+temp[6-*]_max Provides thermal control temperature of the core. -+temp[6-*]_crit Provides shutdown temperature of the core. -+temp[6-*]_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of - the core. -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index c0623fa5ba41..7399c3cef30c 100644 ---- a/drivers/hwmon/Kconfig -+++ b/drivers/hwmon/Kconfig -@@ -1333,7 +1333,7 @@ config SENSORS_PECI_CPUTEMP - the PECI Client Command Suite via the processor PECI client. - Check Documentation/hwmon/peci-cputemp for details. - -- This driver can also be built as a module. If so, the module -+ This driver can also be built as a module. If so, the module - will be called peci-cputemp. - - config SENSORS_PECI_DIMMTEMP -@@ -1347,7 +1347,7 @@ config SENSORS_PECI_DIMMTEMP - Suite via the processor PECI client. - Check Documentation/hwmon/peci-dimmtemp for details. - -- This driver can also be built as a module. If so, the module -+ This driver can also be built as a module. If so, the module - will be called peci-dimmtemp. - - source "drivers/hwmon/pmbus/Kconfig" -diff --git a/drivers/hwmon/peci-cputemp.c b/drivers/hwmon/peci-cputemp.c -index 11880c86a854..d0d68e88889f 100644 ---- a/drivers/hwmon/peci-cputemp.c -+++ b/drivers/hwmon/peci-cputemp.c -@@ -1,5 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0 --// Copyright (c) 2018 Intel Corporation -+// Copyright (c) 2018-2019 Intel Corporation - - #include - #include -@@ -9,18 +9,13 @@ - #include - #include "peci-hwmon.h" - --#define DEFAULT_CHANNEL_NUMS 4 -+#define DEFAULT_CHANNEL_NUMS 5 - #define CORETEMP_CHANNEL_NUMS CORE_NUMS_MAX - #define CPUTEMP_CHANNEL_NUMS (DEFAULT_CHANNEL_NUMS + CORETEMP_CHANNEL_NUMS) - --/* The RESOLVED_CORES register in PCU of a client CPU */ --#define REG_RESOLVED_CORES_BUS 1 --#define REG_RESOLVED_CORES_DEVICE 30 --#define REG_RESOLVED_CORES_FUNCTION 3 --#define REG_RESOLVED_CORES_OFFSET 0xB4 -- - struct temp_group { - struct temp_data die; -+ struct temp_data dts; - struct temp_data tcontrol; - struct temp_data tthrottle; - struct temp_data tjmax; -@@ -43,6 +38,7 @@ struct peci_cputemp { - - enum cputemp_channels { - channel_die, -+ channel_dts, - channel_tcontrol, - channel_tthrottle, - channel_tjmax, -@@ -54,6 +50,10 @@ static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = { - HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | - HWMON_T_CRIT_HYST, - -+ /* DTS margin */ -+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | -+ HWMON_T_CRIT_HYST, -+ - /* Tcontrol temperature */ - HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_CRIT, - -@@ -70,6 +70,7 @@ static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = { - - static const char *cputemp_label[CPUTEMP_CHANNEL_NUMS] = { - "Die", -+ "DTS", - "Tcontrol", - "Tthrottle", - "Tjmax", -@@ -92,19 +93,20 @@ static int get_temp_targets(struct peci_cputemp *priv) - s32 tthrottle_offset; - s32 tcontrol_margin; - u8 pkg_cfg[4]; -- int rc; -+ int ret; - -- /** -+ /* - * Just use only the tcontrol marker to determine if target values need - * update. - */ - if (!peci_temp_need_update(&priv->temp.tcontrol)) - return 0; - -- rc = peci_client_read_package_config(priv->mgr, -- MBX_INDEX_TEMP_TARGET, 0, pkg_cfg); -- if (rc) -- return rc; -+ ret = peci_client_read_package_config(priv->mgr, -+ PECI_MBX_INDEX_TEMP_TARGET, 0, -+ pkg_cfg); -+ if (ret) -+ return ret; - - priv->temp.tjmax.value = pkg_cfg[2] * 1000; - -@@ -123,17 +125,16 @@ static int get_temp_targets(struct peci_cputemp *priv) - static int get_die_temp(struct peci_cputemp *priv) - { - struct peci_get_temp_msg msg; -- int rc; -+ int ret; - - if (!peci_temp_need_update(&priv->temp.die)) - return 0; - - msg.addr = priv->mgr->client->addr; - -- rc = peci_command(priv->mgr->client->adapter, PECI_CMD_GET_TEMP, -- &msg); -- if (rc) -- return rc; -+ ret = peci_command(priv->mgr->client->adapter, PECI_CMD_GET_TEMP, &msg); -+ if (ret) -+ return ret; - - /* Note that the tjmax should be available before calling it */ - priv->temp.die.value = priv->temp.tjmax.value + -@@ -144,24 +145,64 @@ static int get_die_temp(struct peci_cputemp *priv) - return 0; - } - -+static int get_dts(struct peci_cputemp *priv) -+{ -+ s32 dts_margin; -+ u8 pkg_cfg[4]; -+ int ret; -+ -+ if (!peci_temp_need_update(&priv->temp.dts)) -+ return 0; -+ -+ ret = peci_client_read_package_config(priv->mgr, -+ PECI_MBX_INDEX_DTS_MARGIN, 0, -+ pkg_cfg); -+ -+ if (ret) -+ return ret; -+ -+ dts_margin = (pkg_cfg[1] << 8) | pkg_cfg[0]; -+ -+ /** -+ * Processors return a value of DTS reading in 10.6 format -+ * (10 bits signed decimal, 6 bits fractional). -+ * Error codes: -+ * 0x8000: General sensor error -+ * 0x8001: Reserved -+ * 0x8002: Underflow on reading value -+ * 0x8003-0x81ff: Reserved -+ */ -+ if (dts_margin >= 0x8000 && dts_margin <= 0x81ff) -+ return -EIO; -+ -+ dts_margin = ten_dot_six_to_millidegree(dts_margin); -+ -+ /* Note that the tcontrol should be available before calling it */ -+ priv->temp.dts.value = priv->temp.tcontrol.value - dts_margin; -+ -+ peci_temp_mark_updated(&priv->temp.dts); -+ -+ return 0; -+} -+ - static int get_core_temp(struct peci_cputemp *priv, int core_index) - { - s32 core_dts_margin; - u8 pkg_cfg[4]; -- int rc; -+ int ret; - - if (!peci_temp_need_update(&priv->temp.core[core_index])) - return 0; - -- rc = peci_client_read_package_config(priv->mgr, -- MBX_INDEX_PER_CORE_DTS_TEMP, -- core_index, pkg_cfg); -- if (rc) -- return rc; -+ ret = peci_client_read_package_config(priv->mgr, -+ PECI_MBX_INDEX_PER_CORE_DTS_TEMP, -+ core_index, pkg_cfg); -+ if (ret) -+ return ret; - - core_dts_margin = le16_to_cpup((__le16 *)pkg_cfg); - -- /** -+ /* - * Processors return a value of the core DTS reading in 10.6 format - * (10 bits signed decimal, 6 bits fractional). - * Error codes: -@@ -192,6 +233,7 @@ static int cputemp_read_string(struct device *dev, - return -EOPNOTSUPP; - - *str = cputemp_label[channel]; -+ - return 0; - } - -@@ -200,26 +242,33 @@ static int cputemp_read(struct device *dev, - u32 attr, int channel, long *val) - { - struct peci_cputemp *priv = dev_get_drvdata(dev); -- int rc, core_index; -+ int ret, core_index; - - if (channel >= CPUTEMP_CHANNEL_NUMS || - !(priv->temp_config[channel] & BIT(attr))) - return -EOPNOTSUPP; - -- rc = get_temp_targets(priv); -- if (rc) -- return rc; -+ ret = get_temp_targets(priv); -+ if (ret) -+ return ret; - - switch (attr) { - case hwmon_temp_input: - switch (channel) { - case channel_die: -- rc = get_die_temp(priv); -- if (rc) -+ ret = get_die_temp(priv); -+ if (ret) - break; - - *val = priv->temp.die.value; - break; -+ case channel_dts: -+ ret = get_dts(priv); -+ if (ret) -+ break; -+ -+ *val = priv->temp.dts.value; -+ break; - case channel_tcontrol: - *val = priv->temp.tcontrol.value; - break; -@@ -231,8 +280,8 @@ static int cputemp_read(struct device *dev, - break; - default: - core_index = channel - DEFAULT_CHANNEL_NUMS; -- rc = get_core_temp(priv, core_index); -- if (rc) -+ ret = get_core_temp(priv, core_index); -+ if (ret) - break; - - *val = priv->temp.core[core_index].value; -@@ -249,11 +298,11 @@ static int cputemp_read(struct device *dev, - *val = priv->temp.tjmax.value - priv->temp.tcontrol.value; - break; - default: -- rc = -EOPNOTSUPP; -+ ret = -EOPNOTSUPP; - break; - } - -- return rc; -+ return ret; - } - - static umode_t cputemp_is_visible(const void *data, -@@ -262,11 +311,11 @@ static umode_t cputemp_is_visible(const void *data, - { - const struct peci_cputemp *priv = data; - -- if (priv->temp_config[channel] & BIT(attr)) -- if (channel < DEFAULT_CHANNEL_NUMS || -- (channel >= DEFAULT_CHANNEL_NUMS && -- (priv->core_mask & BIT(channel - DEFAULT_CHANNEL_NUMS)))) -- return 0444; -+ if ((priv->temp_config[channel] & BIT(attr)) && -+ (channel < DEFAULT_CHANNEL_NUMS || -+ (channel >= DEFAULT_CHANNEL_NUMS && -+ (priv->core_mask & BIT(channel - DEFAULT_CHANNEL_NUMS))))) -+ return 0444; - - return 0; - } -@@ -280,40 +329,43 @@ static const struct hwmon_ops cputemp_ops = { - static int check_resolved_cores(struct peci_cputemp *priv) - { - struct peci_rd_pci_cfg_local_msg msg; -- int rc; -+ int ret; - - /* Get the RESOLVED_CORES register value */ - msg.addr = priv->mgr->client->addr; -- msg.bus = REG_RESOLVED_CORES_BUS; -- msg.device = REG_RESOLVED_CORES_DEVICE; -- msg.function = REG_RESOLVED_CORES_FUNCTION; -- msg.reg = REG_RESOLVED_CORES_OFFSET; -+ msg.bus = 1; -+ msg.device = 30; -+ msg.function = 3; -+ msg.reg = 0xb4; - msg.rx_len = 4; - -- rc = peci_command(priv->mgr->client->adapter, -- PECI_CMD_RD_PCI_CFG_LOCAL, &msg); -- if (rc) -- return rc; -+ ret = peci_command(priv->mgr->client->adapter, -+ PECI_CMD_RD_PCI_CFG_LOCAL, &msg); -+ if (msg.cc != PECI_DEV_CC_SUCCESS) -+ ret = -EAGAIN; -+ if (ret) -+ return ret; - - priv->core_mask = le32_to_cpup((__le32 *)msg.pci_config); - if (!priv->core_mask) - return -EAGAIN; - - dev_dbg(priv->dev, "Scanned resolved cores: 0x%x\n", priv->core_mask); -+ - return 0; - } - - static int create_core_temp_info(struct peci_cputemp *priv) - { -- int rc, i; -+ int ret, i; - -- rc = check_resolved_cores(priv); -- if (rc) -- return rc; -+ ret = check_resolved_cores(priv); -+ if (ret) -+ return ret; - - for (i = 0; i < priv->gen_info->core_max; i++) - if (priv->core_mask & BIT(i)) -- while (i + DEFAULT_CHANNEL_NUMS >= priv->config_idx) -+ while (priv->config_idx <= i + DEFAULT_CHANNEL_NUMS) - priv->temp_config[priv->config_idx++] = - config_table[channel_core]; - -@@ -326,7 +378,7 @@ static int peci_cputemp_probe(struct platform_device *pdev) - struct device *dev = &pdev->dev; - struct peci_cputemp *priv; - struct device *hwmon_dev; -- int rc; -+ int ret; - - if ((mgr->client->adapter->cmd_mask & - (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) != -@@ -346,12 +398,13 @@ static int peci_cputemp_probe(struct platform_device *pdev) - mgr->client->addr - PECI_BASE_ADDR); - - priv->temp_config[priv->config_idx++] = config_table[channel_die]; -+ priv->temp_config[priv->config_idx++] = config_table[channel_dts]; - priv->temp_config[priv->config_idx++] = config_table[channel_tcontrol]; - priv->temp_config[priv->config_idx++] = config_table[channel_tthrottle]; - priv->temp_config[priv->config_idx++] = config_table[channel_tjmax]; - -- rc = create_core_temp_info(priv); -- if (rc) -+ ret = create_core_temp_info(priv); -+ if (ret) - dev_dbg(dev, "Skipped creating core temp info\n"); - - priv->chip.ops = &cputemp_ops; -@@ -385,7 +438,7 @@ MODULE_DEVICE_TABLE(platform, peci_cputemp_ids); - static struct platform_driver peci_cputemp_driver = { - .probe = peci_cputemp_probe, - .id_table = peci_cputemp_ids, -- .driver = { .name = "peci-cputemp", }, -+ .driver = { .name = KBUILD_MODNAME, }, - }; - module_platform_driver(peci_cputemp_driver); - -diff --git a/drivers/hwmon/peci-dimmtemp.c b/drivers/hwmon/peci-dimmtemp.c -index 86a45a90805b..a404b6ea4ba3 100644 ---- a/drivers/hwmon/peci-dimmtemp.c -+++ b/drivers/hwmon/peci-dimmtemp.c -@@ -1,5 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0 --// Copyright (c) 2018 Intel Corporation -+// Copyright (c) 2018-2019 Intel Corporation - - #include - #include -@@ -21,6 +21,8 @@ struct peci_dimmtemp { - struct workqueue_struct *work_queue; - struct delayed_work work_handler; - struct temp_data temp[DIMM_NUMS_MAX]; -+ long temp_max[DIMM_NUMS_MAX]; -+ long temp_crit[DIMM_NUMS_MAX]; - u32 dimm_mask; - int retry_count; - u32 temp_config[DIMM_NUMS_MAX + 1]; -@@ -44,20 +46,106 @@ static int get_dimm_temp(struct peci_dimmtemp *priv, int dimm_no) - { - int dimm_order = dimm_no % priv->gen_info->dimm_idx_max; - int chan_rank = dimm_no / priv->gen_info->dimm_idx_max; -+ struct peci_rd_pci_cfg_local_msg rp_msg; - u8 cfg_data[4]; -- int rc; -+ int ret; - - if (!peci_temp_need_update(&priv->temp[dimm_no])) - return 0; - -- rc = peci_client_read_package_config(priv->mgr, -- MBX_INDEX_DDR_DIMM_TEMP, -- chan_rank, cfg_data); -- if (rc) -- return rc; -+ ret = peci_client_read_package_config(priv->mgr, -+ PECI_MBX_INDEX_DDR_DIMM_TEMP, -+ chan_rank, cfg_data); -+ if (ret) -+ return ret; - - priv->temp[dimm_no].value = cfg_data[dimm_order] * 1000; - -+ switch (priv->gen_info->model) { -+ case INTEL_FAM6_SKYLAKE_X: -+ rp_msg.addr = priv->mgr->client->addr; -+ rp_msg.bus = 2; -+ /* -+ * Device 10, Function 2: IMC 0 channel 0 -> rank 0 -+ * Device 10, Function 6: IMC 0 channel 1 -> rank 1 -+ * Device 11, Function 2: IMC 0 channel 2 -> rank 2 -+ * Device 12, Function 2: IMC 1 channel 0 -> rank 3 -+ * Device 12, Function 6: IMC 1 channel 1 -> rank 4 -+ * Device 13, Function 2: IMC 1 channel 2 -> rank 5 -+ */ -+ rp_msg.device = 10 + chan_rank / 3 * 2 + -+ (chan_rank % 3 == 2 ? 1 : 0); -+ rp_msg.function = chan_rank % 3 == 1 ? 6 : 2; -+ rp_msg.reg = 0x120 + dimm_order * 4; -+ rp_msg.rx_len = 4; -+ -+ ret = peci_command(priv->mgr->client->adapter, -+ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg); -+ if (rp_msg.cc != PECI_DEV_CC_SUCCESS) -+ ret = -EAGAIN; -+ if (ret) -+ return ret; -+ -+ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000; -+ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000; -+ break; -+ case INTEL_FAM6_SKYLAKE_XD: -+ rp_msg.addr = priv->mgr->client->addr; -+ rp_msg.bus = 2; -+ /* -+ * Device 10, Function 2: IMC 0 channel 0 -> rank 0 -+ * Device 10, Function 6: IMC 0 channel 1 -> rank 1 -+ * Device 12, Function 2: IMC 1 channel 0 -> rank 2 -+ * Device 12, Function 6: IMC 1 channel 1 -> rank 3 -+ */ -+ rp_msg.device = 10 + chan_rank / 2 * 2; -+ rp_msg.function = chan_rank % 2 ? 6 : 2; -+ rp_msg.reg = 0x120 + dimm_order * 4; -+ rp_msg.rx_len = 4; -+ -+ ret = peci_command(priv->mgr->client->adapter, -+ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg); -+ if (rp_msg.cc != PECI_DEV_CC_SUCCESS) -+ ret = -EAGAIN; -+ if (ret) -+ return ret; -+ -+ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000; -+ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000; -+ break; -+ case INTEL_FAM6_HASWELL_X: -+ case INTEL_FAM6_BROADWELL_X: -+ rp_msg.addr = priv->mgr->client->addr; -+ rp_msg.bus = 1; -+ /* -+ * Device 20, Function 0: IMC 0 channel 0 -> rank 0 -+ * Device 20, Function 1: IMC 0 channel 1 -> rank 1 -+ * Device 21, Function 0: IMC 0 channel 2 -> rank 2 -+ * Device 21, Function 1: IMC 0 channel 3 -> rank 3 -+ * Device 23, Function 0: IMC 1 channel 0 -> rank 4 -+ * Device 23, Function 1: IMC 1 channel 1 -> rank 5 -+ * Device 24, Function 0: IMC 1 channel 2 -> rank 6 -+ * Device 24, Function 1: IMC 1 channel 3 -> rank 7 -+ */ -+ rp_msg.device = 20 + chan_rank / 2 + chan_rank / 4; -+ rp_msg.function = chan_rank % 2; -+ rp_msg.reg = 0x120 + dimm_order * 4; -+ rp_msg.rx_len = 4; -+ -+ ret = peci_command(priv->mgr->client->adapter, -+ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg); -+ if (rp_msg.cc != PECI_DEV_CC_SUCCESS) -+ ret = -EAGAIN; -+ if (ret) -+ return ret; -+ -+ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000; -+ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000; -+ break; -+ default: -+ return -EOPNOTSUPP; -+ } -+ - peci_temp_mark_updated(&priv->temp[dimm_no]); - - return 0; -@@ -77,6 +165,7 @@ static int dimmtemp_read_string(struct device *dev, - chan_rank = channel / dimm_idx_max; - dimm_idx = channel % dimm_idx_max; - *str = dimmtemp_label[chan_rank][dimm_idx]; -+ - return 0; - } - -@@ -84,17 +173,28 @@ static int dimmtemp_read(struct device *dev, enum hwmon_sensor_types type, - u32 attr, int channel, long *val) - { - struct peci_dimmtemp *priv = dev_get_drvdata(dev); -- int rc; -- -- if (attr != hwmon_temp_input) -- return -EOPNOTSUPP; -- -- rc = get_dimm_temp(priv, channel); -- if (rc) -- return rc; -+ int ret; -+ -+ ret = get_dimm_temp(priv, channel); -+ if (ret) -+ return ret; -+ -+ switch (attr) { -+ case hwmon_temp_input: -+ *val = priv->temp[channel].value; -+ break; -+ case hwmon_temp_max: -+ *val = priv->temp_max[channel]; -+ break; -+ case hwmon_temp_crit: -+ *val = priv->temp_crit[channel]; -+ break; -+ default: -+ ret = -EOPNOTSUPP; -+ break; -+ } - -- *val = priv->temp[channel].value; -- return 0; -+ return ret; - } - - static umode_t dimmtemp_is_visible(const void *data, -@@ -120,16 +220,16 @@ static int check_populated_dimms(struct peci_dimmtemp *priv) - { - u32 chan_rank_max = priv->gen_info->chan_rank_max; - u32 dimm_idx_max = priv->gen_info->dimm_idx_max; -- int chan_rank, dimm_idx, rc; -+ int chan_rank, dimm_idx, ret; - u8 cfg_data[4]; - - for (chan_rank = 0; chan_rank < chan_rank_max; chan_rank++) { -- rc = peci_client_read_package_config(priv->mgr, -- MBX_INDEX_DDR_DIMM_TEMP, -- chan_rank, cfg_data); -- if (rc) { -+ ret = peci_client_read_package_config(priv->mgr, -+ PECI_MBX_INDEX_DDR_DIMM_TEMP, -+ chan_rank, cfg_data); -+ if (ret) { - priv->dimm_mask = 0; -- return rc; -+ return ret; - } - - for (dimm_idx = 0; dimm_idx < dimm_idx_max; dimm_idx++) -@@ -143,17 +243,18 @@ static int check_populated_dimms(struct peci_dimmtemp *priv) - return -EAGAIN; - - dev_dbg(priv->dev, "Scanned populated DIMMs: 0x%x\n", priv->dimm_mask); -+ - return 0; - } - - static int create_dimm_temp_info(struct peci_dimmtemp *priv) - { -- int rc, i, config_idx, channels; -+ int ret, i, config_idx, channels; - struct device *hwmon_dev; - -- rc = check_populated_dimms(priv); -- if (rc) { -- if (rc == -EAGAIN) { -+ ret = check_populated_dimms(priv); -+ if (ret) { -+ if (ret == -EAGAIN) { - if (priv->retry_count < DIMM_MASK_CHECK_RETRY_MAX) { - queue_delayed_work(priv->work_queue, - &priv->work_handler, -@@ -164,11 +265,11 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv) - } else { - dev_err(priv->dev, - "Timeout DIMM temp info creation\n"); -- rc = -ETIMEDOUT; -+ ret = -ETIMEDOUT; - } - } - -- return rc; -+ return ret; - } - - channels = priv->gen_info->chan_rank_max * -@@ -177,7 +278,8 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv) - if (priv->dimm_mask & BIT(i)) - while (i >= config_idx) - priv->temp_config[config_idx++] = -- HWMON_T_LABEL | HWMON_T_INPUT; -+ HWMON_T_LABEL | HWMON_T_INPUT | -+ HWMON_T_MAX | HWMON_T_CRIT; - - priv->chip.ops = &dimmtemp_ops; - priv->chip.info = priv->info; -@@ -192,12 +294,12 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv) - priv, - &priv->chip, - NULL); -- rc = PTR_ERR_OR_ZERO(hwmon_dev); -- if (!rc) -+ ret = PTR_ERR_OR_ZERO(hwmon_dev); -+ if (!ret) - dev_dbg(priv->dev, "%s: sensor '%s'\n", - dev_name(hwmon_dev), priv->name); - -- return rc; -+ return ret; - } - - static void create_dimm_temp_info_delayed(struct work_struct *work) -@@ -205,10 +307,10 @@ static void create_dimm_temp_info_delayed(struct work_struct *work) - struct delayed_work *dwork = to_delayed_work(work); - struct peci_dimmtemp *priv = container_of(dwork, struct peci_dimmtemp, - work_handler); -- int rc; -+ int ret; - -- rc = create_dimm_temp_info(priv); -- if (rc && rc != -EAGAIN) -+ ret = create_dimm_temp_info(priv); -+ if (ret && ret != -EAGAIN) - dev_dbg(priv->dev, "Failed to create DIMM temp info\n"); - } - -@@ -217,7 +319,7 @@ static int peci_dimmtemp_probe(struct platform_device *pdev) - struct peci_client_manager *mgr = dev_get_drvdata(pdev->dev.parent); - struct device *dev = &pdev->dev; - struct peci_dimmtemp *priv; -- int rc; -+ int ret; - - if ((mgr->client->adapter->cmd_mask & - (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) != -@@ -242,8 +344,8 @@ static int peci_dimmtemp_probe(struct platform_device *pdev) - - INIT_DELAYED_WORK(&priv->work_handler, create_dimm_temp_info_delayed); - -- rc = create_dimm_temp_info(priv); -- if (rc && rc != -EAGAIN) { -+ ret = create_dimm_temp_info(priv); -+ if (ret && ret != -EAGAIN) { - dev_err(dev, "Failed to create DIMM temp info\n"); - goto err_free_wq; - } -@@ -252,7 +354,7 @@ static int peci_dimmtemp_probe(struct platform_device *pdev) - - err_free_wq: - destroy_workqueue(priv->work_queue); -- return rc; -+ return ret; - } - - static int peci_dimmtemp_remove(struct platform_device *pdev) -@@ -275,7 +377,7 @@ static struct platform_driver peci_dimmtemp_driver = { - .probe = peci_dimmtemp_probe, - .remove = peci_dimmtemp_remove, - .id_table = peci_dimmtemp_ids, -- .driver = { .name = "peci-dimmtemp", }, -+ .driver = { .name = KBUILD_MODNAME, }, - }; - module_platform_driver(peci_dimmtemp_driver); - -diff --git a/drivers/hwmon/peci-hwmon.h b/drivers/hwmon/peci-hwmon.h -index 6ca1855a86bb..ce6b470eae63 100644 ---- a/drivers/hwmon/peci-hwmon.h -+++ b/drivers/hwmon/peci-hwmon.h -@@ -1,5 +1,5 @@ - /* SPDX-License-Identifier: GPL-2.0 */ --/* Copyright (c) 2018 Intel Corporation */ -+/* Copyright (c) 2018-2019 Intel Corporation */ - - #ifndef __PECI_HWMON_H - #define __PECI_HWMON_H -@@ -29,11 +29,8 @@ struct temp_data { - */ - static inline bool peci_temp_need_update(struct temp_data *temp) - { -- if (temp->valid && -- time_before(jiffies, temp->last_updated + UPDATE_INTERVAL)) -- return false; -- -- return true; -+ return !temp->valid || -+ time_after(jiffies, temp->last_updated + UPDATE_INTERVAL); - } - - /** -diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig -index 75dbcc7da87c..6f7ee4dd08f6 100644 ---- a/drivers/mfd/Kconfig -+++ b/drivers/mfd/Kconfig -@@ -616,7 +616,7 @@ config MFD_INTEL_MSIC - devices used in Intel Medfield platforms. - - config MFD_INTEL_PECI_CLIENT -- bool "Intel PECI client" -+ tristate "Intel PECI client" - depends on (PECI || COMPILE_TEST) - select MFD_CORE - help -@@ -629,6 +629,9 @@ config MFD_INTEL_PECI_CLIENT - Additional drivers must be enabled in order to use the functionality - of the device. - -+ This driver can also be built as a module. If so, the module -+ will be called intel-peci-client. -+ - config MFD_IPAQ_MICRO - bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support" - depends on SA1100_H3100 || SA1100_H3600 -diff --git a/drivers/mfd/intel-peci-client.c b/drivers/mfd/intel-peci-client.c -index d53e4f1078ac..18bf0af0e09e 100644 ---- a/drivers/mfd/intel-peci-client.c -+++ b/drivers/mfd/intel-peci-client.c -@@ -1,12 +1,12 @@ - // SPDX-License-Identifier: GPL-2.0 --// Copyright (c) 2018 Intel Corporation -+// Copyright (c) 2018-2019 Intel Corporation - - #include - #include - #include - #include --#include - #include -+#include - - #define CPU_ID_MODEL_MASK GENMASK(7, 4) - #define CPU_ID_FAMILY_MASK GENMASK(11, 8) -@@ -18,12 +18,6 @@ - #define LOWER_BYTE_MASK GENMASK(7, 0) - #define UPPER_BYTE_MASK GENMASK(16, 8) - --enum cpu_gens { -- CPU_GEN_HSX = 0, /* Haswell Xeon */ -- CPU_GEN_BRX, /* Broadwell Xeon */ -- CPU_GEN_SKX, /* Skylake Xeon */ --}; -- - static struct mfd_cell peci_functions[] = { - { .name = "peci-cputemp", }, - { .name = "peci-dimmtemp", }, -@@ -31,38 +25,45 @@ static struct mfd_cell peci_functions[] = { - }; - - static const struct cpu_gen_info cpu_gen_info_table[] = { -- [CPU_GEN_HSX] = { -+ { /* Haswell Xeon */ - .family = 6, /* Family code */ - .model = INTEL_FAM6_HASWELL_X, - .core_max = CORE_MAX_ON_HSX, - .chan_rank_max = CHAN_RANK_MAX_ON_HSX, - .dimm_idx_max = DIMM_IDX_MAX_ON_HSX }, -- [CPU_GEN_BRX] = { -+ { /* Broadwell Xeon */ - .family = 6, /* Family code */ - .model = INTEL_FAM6_BROADWELL_X, - .core_max = CORE_MAX_ON_BDX, - .chan_rank_max = CHAN_RANK_MAX_ON_BDX, - .dimm_idx_max = DIMM_IDX_MAX_ON_BDX }, -- [CPU_GEN_SKX] = { -+ { /* Skylake Xeon */ - .family = 6, /* Family code */ - .model = INTEL_FAM6_SKYLAKE_X, - .core_max = CORE_MAX_ON_SKX, - .chan_rank_max = CHAN_RANK_MAX_ON_SKX, - .dimm_idx_max = DIMM_IDX_MAX_ON_SKX }, -+ { /* Skylake Xeon D */ -+ .family = 6, /* Family code */ -+ .model = INTEL_FAM6_SKYLAKE_XD, -+ .core_max = CORE_MAX_ON_SKXD, -+ .chan_rank_max = CHAN_RANK_MAX_ON_SKXD, -+ .dimm_idx_max = DIMM_IDX_MAX_ON_SKXD }, - }; - - static int peci_client_get_cpu_gen_info(struct peci_client_manager *priv) - { -+ struct device *dev = &priv->client->dev; - u32 cpu_id; - u16 family; - u8 model; -- int rc; -+ int ret; - int i; - -- rc = peci_get_cpu_id(priv->client->adapter, priv->client->addr, -- &cpu_id); -- if (rc) -- return rc; -+ ret = peci_get_cpu_id(priv->client->adapter, priv->client->addr, -+ &cpu_id); -+ if (ret) -+ return ret; - - family = FIELD_PREP(LOWER_BYTE_MASK, - FIELD_GET(CPU_ID_FAMILY_MASK, cpu_id)) | -@@ -83,11 +84,11 @@ static int peci_client_get_cpu_gen_info(struct peci_client_manager *priv) - } - - if (!priv->gen_info) { -- dev_err(priv->dev, "Can't support this CPU: 0x%x\n", cpu_id); -- rc = -ENODEV; -+ dev_err(dev, "Can't support this CPU: 0x%x\n", cpu_id); -+ ret = -ENODEV; - } - -- return rc; -+ return ret; - } - - static int peci_client_probe(struct peci_client *client) -@@ -103,31 +104,29 @@ static int peci_client_probe(struct peci_client *client) - - dev_set_drvdata(dev, priv); - priv->client = client; -- priv->dev = dev; - cpu_no = client->addr - PECI_BASE_ADDR; - - ret = peci_client_get_cpu_gen_info(priv); - if (ret) - return ret; - -- ret = devm_mfd_add_devices(priv->dev, cpu_no, peci_functions, -+ ret = devm_mfd_add_devices(dev, cpu_no, peci_functions, - ARRAY_SIZE(peci_functions), NULL, 0, NULL); - if (ret < 0) { -- dev_err(priv->dev, "Failed to register child devices: %d\n", -- ret); -+ dev_err(dev, "Failed to register child devices: %d\n", ret); - return ret; - } - - return 0; - } - --#ifdef CONFIG_OF -+#if IS_ENABLED(CONFIG_OF) - static const struct of_device_id peci_client_of_table[] = { - { .compatible = "intel,peci-client" }, - { } - }; - MODULE_DEVICE_TABLE(of, peci_client_of_table); --#endif -+#endif /* CONFIG_OF */ - - static const struct peci_device_id peci_client_ids[] = { - { .name = "peci-client" }, -@@ -139,7 +138,7 @@ static struct peci_driver peci_client_driver = { - .probe = peci_client_probe, - .id_table = peci_client_ids, - .driver = { -- .name = "peci-client", -+ .name = KBUILD_MODNAME, - .of_match_table = of_match_ptr(peci_client_of_table), - }, - }; -diff --git a/drivers/peci/Kconfig b/drivers/peci/Kconfig -index 7293108fb543..9752feee2454 100644 ---- a/drivers/peci/Kconfig -+++ b/drivers/peci/Kconfig -@@ -2,10 +2,12 @@ - # Platform Environment Control Interface (PECI) subsystem configuration - # - -+menu "PECI support" -+ - config PECI -- bool "PECI support" -- select RT_MUTEXES -+ tristate "PECI support" - select CRC8 -+ default n - help - The Platform Environment Control Interface (PECI) is a one-wire bus - interface that provides a communication channel from Intel processors -@@ -14,37 +16,23 @@ config PECI - If you want PECI support, you should say Y here and also to the - specific driver for your bus adapter(s) below. - --if PECI -- --# --# PECI hardware bus configuration --# -- --menu "PECI Hardware Bus support" -- --config PECI_ASPEED -- tristate "ASPEED PECI support" -- select REGMAP_MMIO -- depends on OF -- depends on ARCH_ASPEED || COMPILE_TEST -- help -- Say Y here if you want support for the Platform Environment Control -- Interface (PECI) bus adapter driver on the ASPEED SoCs. -+ This support is also available as a module. If so, the module -+ will be called peci-core. - -- This support is also available as a module. If so, the module -- will be called peci-aspeed. -+if PECI - --config PECI_NPCM -- tristate "Nuvoton NPCM PECI support" -- select REGMAP_MMIO -- depends on OF -- depends on ARCH_NPCM || COMPILE_TEST -+config PECI_CHARDEV -+ tristate "PECI device interface" - help -- Say Y here if you want support for the Platform Environment Control -- Interface (PECI) bus adapter driver on the Nuvoton NPCM SoCs. -+ Say Y here to use peci-* device files, usually found in the /dev -+ directory on your system. They make it possible to have user-space -+ programs use the PECI bus. - - This support is also available as a module. If so, the module -- will be called peci-npcm. --endmenu -+ will be called peci-dev. -+ -+source "drivers/peci/busses/Kconfig" - - endif # PECI -+ -+endmenu -diff --git a/drivers/peci/Makefile b/drivers/peci/Makefile -index 3326da54a21a..da8b0a33fa42 100644 ---- a/drivers/peci/Makefile -+++ b/drivers/peci/Makefile -@@ -1,10 +1,11 @@ -+# SPDX-License-Identifier: GPL-2.0 - # --# Makefile for the PECI core and bus drivers. -+# Makefile for the PECI core drivers. - # - - # Core functionality - obj-$(CONFIG_PECI) += peci-core.o -+obj-$(CONFIG_PECI_CHARDEV) += peci-dev.o - - # Hardware specific bus drivers --obj-$(CONFIG_PECI_ASPEED) += peci-aspeed.o --obj-$(CONFIG_PECI_NPCM) += peci-npcm.o -+obj-y += busses/ -diff --git a/drivers/peci/busses/Kconfig b/drivers/peci/busses/Kconfig -new file mode 100644 -index 000000000000..bfacafb7a7ba ---- /dev/null -+++ b/drivers/peci/busses/Kconfig -@@ -0,0 +1,32 @@ -+# -+# PECI hardware bus configuration -+# -+ -+menu "PECI Hardware Bus support" -+ -+config PECI_ASPEED -+ tristate "ASPEED PECI support" -+ depends on ARCH_ASPEED || COMPILE_TEST -+ depends on OF -+ depends on PECI -+ help -+ Say Y here if you want support for the Platform Environment Control -+ Interface (PECI) bus adapter driver on the ASPEED SoCs. -+ -+ This support is also available as a module. If so, the module -+ will be called peci-aspeed. -+ -+config PECI_NPCM -+ tristate "Nuvoton NPCM PECI support" -+ select REGMAP_MMIO -+ depends on OF -+ depends on ARCH_NPCM || COMPILE_TEST -+ depends on PECI -+ help -+ Say Y here if you want support for the Platform Environment Control -+ Interface (PECI) bus adapter driver on the Nuvoton NPCM SoCs. -+ -+ This support is also available as a module. If so, the module -+ will be called peci-npcm. -+ -+endmenu -diff --git a/drivers/peci/busses/Makefile b/drivers/peci/busses/Makefile -new file mode 100644 -index 000000000000..aa8ce3ae5947 ---- /dev/null -+++ b/drivers/peci/busses/Makefile -@@ -0,0 +1,7 @@ -+# SPDX-License-Identifier: GPL-2.0 -+# -+# Makefile for the PECI hardware bus drivers. -+# -+ -+obj-$(CONFIG_PECI_ASPEED) += peci-aspeed.o -+obj-$(CONFIG_PECI_NPCM) += peci-npcm.o -diff --git a/drivers/peci/busses/peci-aspeed.c b/drivers/peci/busses/peci-aspeed.c -new file mode 100644 -index 000000000000..851b71e32eac ---- /dev/null -+++ b/drivers/peci/busses/peci-aspeed.c -@@ -0,0 +1,492 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Copyright (C) 2012-2017 ASPEED Technology Inc. -+// Copyright (c) 2018-2019 Intel Corporation -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* ASPEED PECI Registers */ -+/* Control Register */ -+#define ASPEED_PECI_CTRL 0x00 -+#define ASPEED_PECI_CTRL_SAMPLING_MASK GENMASK(19, 16) -+#define ASPEED_PECI_CTRL_READ_MODE_MASK GENMASK(13, 12) -+#define ASPEED_PECI_CTRL_READ_MODE_COUNT BIT(12) -+#define ASPEED_PECI_CTRL_READ_MODE_DBG BIT(13) -+#define ASPEED_PECI_CTRL_CLK_SOURCE_MASK BIT(11) -+#define ASPEED_PECI_CTRL_CLK_DIV_MASK GENMASK(10, 8) -+#define ASPEED_PECI_CTRL_INVERT_OUT BIT(7) -+#define ASPEED_PECI_CTRL_INVERT_IN BIT(6) -+#define ASPEED_PECI_CTRL_BUS_CONTENT_EN BIT(5) -+#define ASPEED_PECI_CTRL_PECI_EN BIT(4) -+#define ASPEED_PECI_CTRL_PECI_CLK_EN BIT(0) -+ -+/* Timing Negotiation Register */ -+#define ASPEED_PECI_TIMING_NEGOTIATION 0x04 -+#define ASPEED_PECI_TIMING_MESSAGE_MASK GENMASK(15, 8) -+#define ASPEED_PECI_TIMING_ADDRESS_MASK GENMASK(7, 0) -+ -+/* Command Register */ -+#define ASPEED_PECI_CMD 0x08 -+#define ASPEED_PECI_CMD_PIN_MON BIT(31) -+#define ASPEED_PECI_CMD_STS_MASK GENMASK(27, 24) -+#define ASPEED_PECI_CMD_IDLE_MASK (ASPEED_PECI_CMD_STS_MASK | \ -+ ASPEED_PECI_CMD_PIN_MON) -+#define ASPEED_PECI_CMD_FIRE BIT(0) -+ -+/* Read/Write Length Register */ -+#define ASPEED_PECI_RW_LENGTH 0x0c -+#define ASPEED_PECI_AW_FCS_EN BIT(31) -+#define ASPEED_PECI_READ_LEN_MASK GENMASK(23, 16) -+#define ASPEED_PECI_WRITE_LEN_MASK GENMASK(15, 8) -+#define ASPEED_PECI_TAGET_ADDR_MASK GENMASK(7, 0) -+ -+/* Expected FCS Data Register */ -+#define ASPEED_PECI_EXP_FCS 0x10 -+#define ASPEED_PECI_EXP_READ_FCS_MASK GENMASK(23, 16) -+#define ASPEED_PECI_EXP_AW_FCS_AUTO_MASK GENMASK(15, 8) -+#define ASPEED_PECI_EXP_WRITE_FCS_MASK GENMASK(7, 0) -+ -+/* Captured FCS Data Register */ -+#define ASPEED_PECI_CAP_FCS 0x14 -+#define ASPEED_PECI_CAP_READ_FCS_MASK GENMASK(23, 16) -+#define ASPEED_PECI_CAP_WRITE_FCS_MASK GENMASK(7, 0) -+ -+/* Interrupt Register */ -+#define ASPEED_PECI_INT_CTRL 0x18 -+#define ASPEED_PECI_TIMING_NEGO_SEL_MASK GENMASK(31, 30) -+#define ASPEED_PECI_1ST_BIT_OF_ADDR_NEGO 0 -+#define ASPEED_PECI_2ND_BIT_OF_ADDR_NEGO 1 -+#define ASPEED_PECI_MESSAGE_NEGO 2 -+#define ASPEED_PECI_INT_MASK GENMASK(4, 0) -+#define ASPEED_PECI_INT_BUS_TIMEOUT BIT(4) -+#define ASPEED_PECI_INT_BUS_CONNECT BIT(3) -+#define ASPEED_PECI_INT_W_FCS_BAD BIT(2) -+#define ASPEED_PECI_INT_W_FCS_ABORT BIT(1) -+#define ASPEED_PECI_INT_CMD_DONE BIT(0) -+ -+/* Interrupt Status Register */ -+#define ASPEED_PECI_INT_STS 0x1c -+#define ASPEED_PECI_INT_TIMING_RESULT_MASK GENMASK(29, 16) -+ /* bits[4..0]: Same bit fields in the 'Interrupt Register' */ -+ -+/* Rx/Tx Data Buffer Registers */ -+#define ASPEED_PECI_W_DATA0 0x20 -+#define ASPEED_PECI_W_DATA1 0x24 -+#define ASPEED_PECI_W_DATA2 0x28 -+#define ASPEED_PECI_W_DATA3 0x2c -+#define ASPEED_PECI_R_DATA0 0x30 -+#define ASPEED_PECI_R_DATA1 0x34 -+#define ASPEED_PECI_R_DATA2 0x38 -+#define ASPEED_PECI_R_DATA3 0x3c -+#define ASPEED_PECI_W_DATA4 0x40 -+#define ASPEED_PECI_W_DATA5 0x44 -+#define ASPEED_PECI_W_DATA6 0x48 -+#define ASPEED_PECI_W_DATA7 0x4c -+#define ASPEED_PECI_R_DATA4 0x50 -+#define ASPEED_PECI_R_DATA5 0x54 -+#define ASPEED_PECI_R_DATA6 0x58 -+#define ASPEED_PECI_R_DATA7 0x5c -+#define ASPEED_PECI_DATA_BUF_SIZE_MAX 32 -+ -+/* Timing Negotiation */ -+#define ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT 8 -+#define ASPEED_PECI_RD_SAMPLING_POINT_MAX 15 -+#define ASPEED_PECI_CLK_DIV_DEFAULT 0 -+#define ASPEED_PECI_CLK_DIV_MAX 7 -+#define ASPEED_PECI_MSG_TIMING_DEFAULT 1 -+#define ASPEED_PECI_MSG_TIMING_MAX 255 -+#define ASPEED_PECI_ADDR_TIMING_DEFAULT 1 -+#define ASPEED_PECI_ADDR_TIMING_MAX 255 -+ -+/* Timeout */ -+#define ASPEED_PECI_IDLE_CHECK_TIMEOUT_USEC 50000 -+#define ASPEED_PECI_IDLE_CHECK_INTERVAL_USEC 10000 -+#define ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT 1000 -+#define ASPEED_PECI_CMD_TIMEOUT_MS_MAX 60000 -+ -+struct aspeed_peci { -+ struct peci_adapter *adapter; -+ struct device *dev; -+ void __iomem *base; -+ struct clk *clk; -+ struct reset_control *rst; -+ int irq; -+ spinlock_t lock; /* to sync completion status handling */ -+ struct completion xfer_complete; -+ u32 status; -+ u32 cmd_timeout_ms; -+}; -+ -+static int aspeed_peci_check_idle(struct aspeed_peci *priv) -+{ -+ ulong timeout = jiffies + usecs_to_jiffies(ASPEED_PECI_IDLE_CHECK_TIMEOUT_USEC); -+ u32 cmd_sts; -+ -+ for (;;) { -+ cmd_sts = readl(priv->base + ASPEED_PECI_CMD); -+ if (!(cmd_sts & ASPEED_PECI_CMD_IDLE_MASK)) -+ break; -+ if (time_after(jiffies, timeout)) { -+ cmd_sts = readl(priv->base + ASPEED_PECI_CMD); -+ break; -+ } -+ usleep_range((ASPEED_PECI_IDLE_CHECK_INTERVAL_USEC >> 2) + 1, -+ ASPEED_PECI_IDLE_CHECK_INTERVAL_USEC); -+ } -+ -+ return !(cmd_sts & ASPEED_PECI_CMD_IDLE_MASK) ? 0 : -ETIMEDOUT; -+} -+ -+static int aspeed_peci_xfer(struct peci_adapter *adapter, -+ struct peci_xfer_msg *msg) -+{ -+ struct aspeed_peci *priv = peci_get_adapdata(adapter); -+ long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms); -+ u32 peci_head, peci_state, rx_data = 0; -+ ulong flags; -+ int i, ret; -+ uint reg; -+ -+ if (msg->tx_len > ASPEED_PECI_DATA_BUF_SIZE_MAX || -+ msg->rx_len > ASPEED_PECI_DATA_BUF_SIZE_MAX) -+ return -EINVAL; -+ -+ /* Check command sts and bus idle state */ -+ ret = aspeed_peci_check_idle(priv); -+ if (ret) -+ return ret; /* -ETIMEDOUT */ -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ reinit_completion(&priv->xfer_complete); -+ -+ peci_head = FIELD_PREP(ASPEED_PECI_TAGET_ADDR_MASK, msg->addr) | -+ FIELD_PREP(ASPEED_PECI_WRITE_LEN_MASK, msg->tx_len) | -+ FIELD_PREP(ASPEED_PECI_READ_LEN_MASK, msg->rx_len); -+ -+ writel(peci_head, priv->base + ASPEED_PECI_RW_LENGTH); -+ -+ for (i = 0; i < msg->tx_len; i += 4) { -+ reg = i < 16 ? ASPEED_PECI_W_DATA0 + i % 16 : -+ ASPEED_PECI_W_DATA4 + i % 16; -+ writel(le32_to_cpup((__le32 *)&msg->tx_buf[i]), -+ priv->base + reg); -+ } -+ -+ dev_dbg(priv->dev, "HEAD : 0x%08x\n", peci_head); -+ print_hex_dump_debug("TX : ", DUMP_PREFIX_NONE, 16, 1, -+ msg->tx_buf, msg->tx_len, true); -+ -+ priv->status = 0; -+ writel(ASPEED_PECI_CMD_FIRE, priv->base + ASPEED_PECI_CMD); -+ spin_unlock_irqrestore(&priv->lock, flags); -+ -+ err = wait_for_completion_interruptible_timeout(&priv->xfer_complete, -+ timeout); -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ dev_dbg(priv->dev, "INT_STS : 0x%08x\n", priv->status); -+ peci_state = readl(priv->base + ASPEED_PECI_CMD); -+ dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n", -+ FIELD_GET(ASPEED_PECI_CMD_STS_MASK, peci_state)); -+ -+ writel(0, priv->base + ASPEED_PECI_CMD); -+ -+ if (err <= 0 || priv->status != ASPEED_PECI_INT_CMD_DONE) { -+ if (err < 0) { /* -ERESTARTSYS */ -+ ret = (int)err; -+ goto err_irqrestore; -+ } else if (err == 0) { -+ dev_dbg(priv->dev, "Timeout waiting for a response!\n"); -+ ret = -ETIMEDOUT; -+ goto err_irqrestore; -+ } -+ -+ dev_dbg(priv->dev, "No valid response!\n"); -+ ret = -EIO; -+ goto err_irqrestore; -+ } -+ -+ /* -+ * Note that rx_len and rx_buf size can be an odd number. -+ * Byte handling is more efficient. -+ */ -+ for (i = 0; i < msg->rx_len; i++) { -+ u8 byte_offset = i % 4; -+ -+ if (byte_offset == 0) { -+ reg = i < 16 ? ASPEED_PECI_R_DATA0 + i % 16 : -+ ASPEED_PECI_R_DATA4 + i % 16; -+ rx_data = readl(priv->base + reg); -+ } -+ -+ msg->rx_buf[i] = (u8)(rx_data >> (byte_offset << 3)); -+ } -+ -+ print_hex_dump_debug("RX : ", DUMP_PREFIX_NONE, 16, 1, -+ msg->rx_buf, msg->rx_len, true); -+ -+ peci_state = readl(priv->base + ASPEED_PECI_CMD); -+ dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n", -+ FIELD_GET(ASPEED_PECI_CMD_STS_MASK, peci_state)); -+ dev_dbg(priv->dev, "------------------------\n"); -+ -+err_irqrestore: -+ spin_unlock_irqrestore(&priv->lock, flags); -+ return ret; -+} -+ -+static irqreturn_t aspeed_peci_irq_handler(int irq, void *arg) -+{ -+ struct aspeed_peci *priv = arg; -+ u32 status; -+ -+ spin_lock(&priv->lock); -+ status = readl(priv->base + ASPEED_PECI_INT_STS); -+ writel(status, priv->base + ASPEED_PECI_INT_STS); -+ priv->status |= (status & ASPEED_PECI_INT_MASK); -+ -+ /* -+ * In most cases, interrupt bits will be set one by one but also note -+ * that multiple interrupt bits could be set at the same time. -+ */ -+ if (status & ASPEED_PECI_INT_BUS_TIMEOUT) { -+ dev_dbg(priv->dev, "ASPEED_PECI_INT_BUS_TIMEOUT\n"); -+ } -+ -+ if (status & ASPEED_PECI_INT_BUS_CONNECT) { -+ dev_dbg(priv->dev, "ASPEED_PECI_INT_BUS_CONNECT\n"); -+ } -+ -+ if (status & ASPEED_PECI_INT_W_FCS_BAD) { -+ dev_dbg(priv->dev, "ASPEED_PECI_INT_W_FCS_BAD\n"); -+ } -+ -+ if (status & ASPEED_PECI_INT_W_FCS_ABORT) { -+ dev_dbg(priv->dev, "ASPEED_PECI_INT_W_FCS_ABORT\n"); -+ } -+ -+ /* -+ * All commands should be ended up with a ASPEED_PECI_INT_CMD_DONE bit -+ * set even in an error case. -+ */ -+ if (status & ASPEED_PECI_INT_CMD_DONE) { -+ dev_dbg(priv->dev, "ASPEED_PECI_INT_CMD_DONE\n"); -+ complete(&priv->xfer_complete); -+ } -+ -+ spin_unlock(&priv->lock); -+ return IRQ_HANDLED; -+} -+ -+static int aspeed_peci_init_ctrl(struct aspeed_peci *priv) -+{ -+ u32 msg_timing, addr_timing, rd_sampling_point; -+ u32 clk_freq, clk_divisor, clk_div_val = 0; -+ int ret; -+ -+ priv->clk = devm_clk_get(priv->dev, NULL); -+ if (IS_ERR(priv->clk)) { -+ dev_err(priv->dev, "Failed to get clk source.\n"); -+ return PTR_ERR(priv->clk); -+ } -+ -+ ret = clk_prepare_enable(priv->clk); -+ if (ret) { -+ dev_err(priv->dev, "Failed to enable clock.\n"); -+ return ret; -+ } -+ -+ ret = device_property_read_u32(priv->dev, "clock-frequency", &clk_freq); -+ if (ret) { -+ dev_err(priv->dev, -+ "Could not read clock-frequency property.\n"); -+ clk_disable_unprepare(priv->clk); -+ return ret; -+ } -+ -+ clk_divisor = clk_get_rate(priv->clk) / clk_freq; -+ -+ while ((clk_divisor >> 1) && (clk_div_val < ASPEED_PECI_CLK_DIV_MAX)) -+ clk_div_val++; -+ -+ ret = device_property_read_u32(priv->dev, "msg-timing", &msg_timing); -+ if (ret || msg_timing > ASPEED_PECI_MSG_TIMING_MAX) { -+ if (!ret) -+ dev_warn(priv->dev, -+ "Invalid msg-timing : %u, Use default : %u\n", -+ msg_timing, ASPEED_PECI_MSG_TIMING_DEFAULT); -+ msg_timing = ASPEED_PECI_MSG_TIMING_DEFAULT; -+ } -+ -+ ret = device_property_read_u32(priv->dev, "addr-timing", &addr_timing); -+ if (ret || addr_timing > ASPEED_PECI_ADDR_TIMING_MAX) { -+ if (!ret) -+ dev_warn(priv->dev, -+ "Invalid addr-timing : %u, Use default : %u\n", -+ addr_timing, ASPEED_PECI_ADDR_TIMING_DEFAULT); -+ addr_timing = ASPEED_PECI_ADDR_TIMING_DEFAULT; -+ } -+ -+ ret = device_property_read_u32(priv->dev, "rd-sampling-point", -+ &rd_sampling_point); -+ if (ret || rd_sampling_point > ASPEED_PECI_RD_SAMPLING_POINT_MAX) { -+ if (!ret) -+ dev_warn(priv->dev, -+ "Invalid rd-sampling-point : %u. Use default : %u\n", -+ rd_sampling_point, -+ ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT); -+ rd_sampling_point = ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT; -+ } -+ -+ ret = device_property_read_u32(priv->dev, "cmd-timeout-ms", -+ &priv->cmd_timeout_ms); -+ if (ret || priv->cmd_timeout_ms > ASPEED_PECI_CMD_TIMEOUT_MS_MAX || -+ priv->cmd_timeout_ms == 0) { -+ if (!ret) -+ dev_warn(priv->dev, -+ "Invalid cmd-timeout-ms : %u. Use default : %u\n", -+ priv->cmd_timeout_ms, -+ ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT); -+ priv->cmd_timeout_ms = ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT; -+ } -+ -+ writel(FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK, -+ ASPEED_PECI_CLK_DIV_DEFAULT) | -+ ASPEED_PECI_CTRL_PECI_CLK_EN, priv->base + ASPEED_PECI_CTRL); -+ -+ /* -+ * Timing negotiation period setting. -+ * The unit of the programmed value is 4 times of PECI clock period. -+ */ -+ writel(FIELD_PREP(ASPEED_PECI_TIMING_MESSAGE_MASK, msg_timing) | -+ FIELD_PREP(ASPEED_PECI_TIMING_ADDRESS_MASK, addr_timing), -+ priv->base + ASPEED_PECI_TIMING_NEGOTIATION); -+ -+ /* Clear interrupts */ -+ writel(readl(priv->base + ASPEED_PECI_INT_STS) | ASPEED_PECI_INT_MASK, -+ priv->base + ASPEED_PECI_INT_STS); -+ -+ /* Set timing negotiation mode and enable interrupts */ -+ writel(FIELD_PREP(ASPEED_PECI_TIMING_NEGO_SEL_MASK, -+ ASPEED_PECI_1ST_BIT_OF_ADDR_NEGO) | -+ ASPEED_PECI_INT_MASK, priv->base + ASPEED_PECI_INT_CTRL); -+ -+ /* Read sampling point and clock speed setting */ -+ writel(FIELD_PREP(ASPEED_PECI_CTRL_SAMPLING_MASK, rd_sampling_point) | -+ FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK, clk_div_val) | -+ ASPEED_PECI_CTRL_PECI_EN | ASPEED_PECI_CTRL_PECI_CLK_EN, -+ priv->base + ASPEED_PECI_CTRL); -+ -+ return 0; -+} -+ -+static int aspeed_peci_probe(struct platform_device *pdev) -+{ -+ struct peci_adapter *adapter; -+ struct aspeed_peci *priv; -+ int ret; -+ -+ adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv)); -+ if (!adapter) -+ return -ENOMEM; -+ -+ priv = peci_get_adapdata(adapter); -+ priv->adapter = adapter; -+ priv->dev = &pdev->dev; -+ dev_set_drvdata(&pdev->dev, priv); -+ -+ priv->base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(priv->base)) { -+ ret = PTR_ERR(priv->base); -+ goto err_put_adapter_dev; -+ } -+ -+ priv->irq = platform_get_irq(pdev, 0); -+ if (!priv->irq) { -+ ret = -ENODEV; -+ goto err_put_adapter_dev; -+ } -+ -+ ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_peci_irq_handler, -+ 0, "peci-aspeed-irq", priv); -+ if (ret) -+ goto err_put_adapter_dev; -+ -+ init_completion(&priv->xfer_complete); -+ spin_lock_init(&priv->lock); -+ -+ priv->adapter->owner = THIS_MODULE; -+ priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev)); -+ strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name)); -+ priv->adapter->xfer = aspeed_peci_xfer; -+ priv->adapter->use_dma = false; -+ -+ priv->rst = devm_reset_control_get(&pdev->dev, NULL); -+ if (IS_ERR(priv->rst)) { -+ dev_err(&pdev->dev, -+ "missing or invalid reset controller entry\n"); -+ ret = PTR_ERR(priv->rst); -+ goto err_put_adapter_dev; -+ } -+ reset_control_deassert(priv->rst); -+ -+ ret = aspeed_peci_init_ctrl(priv); -+ if (ret) -+ goto err_put_adapter_dev; -+ -+ ret = peci_add_adapter(priv->adapter); -+ if (ret) -+ goto err_put_adapter_dev; -+ -+ dev_info(&pdev->dev, "peci bus %d registered, irq %d\n", -+ priv->adapter->nr, priv->irq); -+ -+ return 0; -+ -+err_put_adapter_dev: -+ put_device(&adapter->dev); -+ return ret; -+} -+ -+static int aspeed_peci_remove(struct platform_device *pdev) -+{ -+ struct aspeed_peci *priv = dev_get_drvdata(&pdev->dev); -+ -+ clk_disable_unprepare(priv->clk); -+ reset_control_assert(priv->rst); -+ peci_del_adapter(priv->adapter); -+ of_node_put(priv->adapter->dev.of_node); -+ -+ return 0; -+} -+ -+static const struct of_device_id aspeed_peci_of_table[] = { -+ { .compatible = "aspeed,ast2400-peci", }, -+ { .compatible = "aspeed,ast2500-peci", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, aspeed_peci_of_table); -+ -+static struct platform_driver aspeed_peci_driver = { -+ .probe = aspeed_peci_probe, -+ .remove = aspeed_peci_remove, -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = of_match_ptr(aspeed_peci_of_table), -+ }, -+}; -+module_platform_driver(aspeed_peci_driver); -+ -+MODULE_AUTHOR("Ryan Chen "); -+MODULE_AUTHOR("Jae Hyun Yoo "); -+MODULE_DESCRIPTION("ASPEED PECI driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/peci/busses/peci-npcm.c b/drivers/peci/busses/peci-npcm.c -new file mode 100644 -index 000000000000..f632365b1416 ---- /dev/null -+++ b/drivers/peci/busses/peci-npcm.c -@@ -0,0 +1,410 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Copyright (c) 2019 Nuvoton Technology corporation. -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* NPCM7xx GCR module */ -+#define NPCM7XX_INTCR3_OFFSET 0x9C -+#define NPCM7XX_INTCR3_PECIVSEL BIT(19) -+ -+/* NPCM PECI Registers */ -+#define NPCM_PECI_CTL_STS 0x00 -+#define NPCM_PECI_RD_LENGTH 0x04 -+#define NPCM_PECI_ADDR 0x08 -+#define NPCM_PECI_CMD 0x0C -+#define NPCM_PECI_CTL2 0x10 -+#define NPCM_PECI_WR_LENGTH 0x1C -+#define NPCM_PECI_PDDR 0x2C -+#define NPCM_PECI_DAT_INOUT(n) (0x100 + ((n) * 4)) -+ -+#define NPCM_PECI_MAX_REG 0x200 -+ -+/* NPCM_PECI_CTL_STS - 0x00 : Control Register */ -+#define NPCM_PECI_CTRL_DONE_INT_EN BIT(6) -+#define NPCM_PECI_CTRL_ABRT_ERR BIT(4) -+#define NPCM_PECI_CTRL_CRC_ERR BIT(3) -+#define NPCM_PECI_CTRL_DONE BIT(1) -+#define NPCM_PECI_CTRL_START_BUSY BIT(0) -+ -+/* NPCM_PECI_RD_LENGTH - 0x04 : Command Register */ -+#define NPCM_PECI_RD_LEN_MASK GENMASK(6, 0) -+ -+/* NPCM_PECI_CMD - 0x10 : Command Register */ -+#define NPCM_PECI_CTL2_MASK GENMASK(7, 6) -+ -+/* NPCM_PECI_WR_LENGTH - 0x1C : Command Register */ -+#define NPCM_PECI_WR_LEN_MASK GENMASK(6, 0) -+ -+/* NPCM_PECI_PDDR - 0x2C : Command Register */ -+#define NPCM_PECI_PDDR_MASK GENMASK(4, 0) -+ -+#define NPCM_PECI_INT_MASK (NPCM_PECI_CTRL_ABRT_ERR | \ -+ NPCM_PECI_CTRL_CRC_ERR | \ -+ NPCM_PECI_CTRL_DONE) -+ -+#define NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC 50000 -+#define NPCM_PECI_IDLE_CHECK_INTERVAL_USEC 10000 -+#define NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT 1000 -+#define NPCM_PECI_CMD_TIMEOUT_MS_MAX 60000 -+#define NPCM_PECI_HOST_NEG_BIT_RATE_MAX 31 -+#define NPCM_PECI_HOST_NEG_BIT_RATE_MIN 7 -+#define NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT 15 -+#define NPCM_PECI_PULL_DOWN_DEFAULT 0 -+#define NPCM_PECI_PULL_DOWN_MAX 2 -+ -+struct npcm_peci { -+ u32 cmd_timeout_ms; -+ u32 host_bit_rate; -+ struct completion xfer_complete; -+ struct regmap *gcr_regmap; -+ struct peci_adapter *adapter; -+ struct regmap *regmap; -+ u32 status; -+ spinlock_t lock; /* to sync completion status handling */ -+ struct device *dev; -+ struct clk *clk; -+ int irq; -+}; -+ -+static int npcm_peci_xfer_native(struct npcm_peci *priv, -+ struct peci_xfer_msg *msg) -+{ -+ long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms); -+ unsigned long flags; -+ unsigned int msg_rd; -+ u32 cmd_sts; -+ int i, rc; -+ -+ /* Check command sts and bus idle state */ -+ rc = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts, -+ !(cmd_sts & NPCM_PECI_CTRL_START_BUSY), -+ NPCM_PECI_IDLE_CHECK_INTERVAL_USEC, -+ NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC); -+ if (rc) -+ return rc; /* -ETIMEDOUT */ -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ reinit_completion(&priv->xfer_complete); -+ -+ regmap_write(priv->regmap, NPCM_PECI_ADDR, msg->addr); -+ regmap_write(priv->regmap, NPCM_PECI_RD_LENGTH, -+ NPCM_PECI_WR_LEN_MASK & msg->rx_len); -+ regmap_write(priv->regmap, NPCM_PECI_WR_LENGTH, -+ NPCM_PECI_WR_LEN_MASK & msg->tx_len); -+ -+ if (msg->tx_len) { -+ regmap_write(priv->regmap, NPCM_PECI_CMD, msg->tx_buf[0]); -+ -+ for (i = 0; i < (msg->tx_len - 1); i++) -+ regmap_write(priv->regmap, NPCM_PECI_DAT_INOUT(i), -+ msg->tx_buf[i + 1]); -+ } -+ -+ priv->status = 0; -+ regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS, -+ NPCM_PECI_CTRL_START_BUSY, -+ NPCM_PECI_CTRL_START_BUSY); -+ -+ spin_unlock_irqrestore(&priv->lock, flags); -+ -+ err = wait_for_completion_interruptible_timeout(&priv->xfer_complete, -+ timeout); -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ -+ regmap_write(priv->regmap, NPCM_PECI_CMD, 0); -+ -+ if (err <= 0 || priv->status != NPCM_PECI_CTRL_DONE) { -+ if (err < 0) { /* -ERESTARTSYS */ -+ rc = (int)err; -+ goto err_irqrestore; -+ } else if (err == 0) { -+ dev_dbg(priv->dev, "Timeout waiting for a response!\n"); -+ rc = -ETIMEDOUT; -+ goto err_irqrestore; -+ } -+ -+ dev_dbg(priv->dev, "No valid response!\n"); -+ rc = -EIO; -+ goto err_irqrestore; -+ } -+ -+ for (i = 0; i < msg->rx_len; i++) { -+ regmap_read(priv->regmap, NPCM_PECI_DAT_INOUT(i), &msg_rd); -+ msg->rx_buf[i] = (u8)msg_rd; -+ } -+ -+err_irqrestore: -+ spin_unlock_irqrestore(&priv->lock, flags); -+ return rc; -+} -+ -+static irqreturn_t npcm_peci_irq_handler(int irq, void *arg) -+{ -+ struct npcm_peci *priv = arg; -+ u32 status_ack = 0; -+ u32 status; -+ -+ spin_lock(&priv->lock); -+ regmap_read(priv->regmap, NPCM_PECI_CTL_STS, &status); -+ priv->status |= (status & NPCM_PECI_INT_MASK); -+ -+ if (status & NPCM_PECI_CTRL_CRC_ERR) { -+ dev_dbg(priv->dev, "PECI_INT_W_FCS_BAD\n"); -+ status_ack |= NPCM_PECI_CTRL_CRC_ERR; -+ } -+ -+ if (status & NPCM_PECI_CTRL_ABRT_ERR) { -+ dev_dbg(priv->dev, "NPCM_PECI_CTRL_ABRT_ERR\n"); -+ status_ack |= NPCM_PECI_CTRL_ABRT_ERR; -+ } -+ -+ /* -+ * All commands should be ended up with a NPCM_PECI_CTRL_DONE -+ * bit set even in an error case. -+ */ -+ if (status & NPCM_PECI_CTRL_DONE) { -+ dev_dbg(priv->dev, "NPCM_PECI_CTRL_DONE\n"); -+ status_ack |= NPCM_PECI_CTRL_DONE; -+ complete(&priv->xfer_complete); -+ } -+ -+ regmap_write_bits(priv->regmap, NPCM_PECI_CTL_STS, -+ NPCM_PECI_INT_MASK, status_ack); -+ -+ spin_unlock(&priv->lock); -+ return IRQ_HANDLED; -+} -+ -+static int npcm_peci_init_ctrl(struct npcm_peci *priv) -+{ -+ u32 cmd_sts, host_neg_bit_rate = 0, pull_down = 0; -+ int ret; -+ bool volt; -+ -+ priv->clk = devm_clk_get(priv->dev, NULL); -+ if (IS_ERR(priv->clk)) { -+ dev_err(priv->dev, "Failed to get clk source.\n"); -+ return PTR_ERR(priv->clk); -+ } -+ -+ ret = clk_prepare_enable(priv->clk); -+ if (ret) { -+ dev_err(priv->dev, "Failed to enable clock.\n"); -+ return ret; -+ } -+ -+ ret = of_property_read_u32(priv->dev->of_node, "cmd-timeout-ms", -+ &priv->cmd_timeout_ms); -+ if (ret || priv->cmd_timeout_ms > NPCM_PECI_CMD_TIMEOUT_MS_MAX || -+ priv->cmd_timeout_ms == 0) { -+ if (ret) -+ dev_warn(priv->dev, -+ "cmd-timeout-ms not found, use default : %u\n", -+ NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT); -+ else -+ dev_warn(priv->dev, -+ "Invalid cmd-timeout-ms : %u. Use default : %u\n", -+ priv->cmd_timeout_ms, -+ NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT); -+ -+ priv->cmd_timeout_ms = NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT; -+ } -+ -+ if (of_device_is_compatible(priv->dev->of_node, -+ "nuvoton,npcm750-peci")) { -+ priv->gcr_regmap = syscon_regmap_lookup_by_compatible -+ ("nuvoton,npcm750-gcr"); -+ if (!IS_ERR(priv->gcr_regmap)) { -+ volt = of_property_read_bool(priv->dev->of_node, -+ "high-volt-range"); -+ if (volt) -+ regmap_update_bits(priv->gcr_regmap, -+ NPCM7XX_INTCR3_OFFSET, -+ NPCM7XX_INTCR3_PECIVSEL, -+ NPCM7XX_INTCR3_PECIVSEL); -+ else -+ regmap_update_bits(priv->gcr_regmap, -+ NPCM7XX_INTCR3_OFFSET, -+ NPCM7XX_INTCR3_PECIVSEL, 0); -+ } -+ } -+ -+ ret = of_property_read_u32(priv->dev->of_node, "pull-down", -+ &pull_down); -+ if (ret || pull_down > NPCM_PECI_PULL_DOWN_MAX) { -+ if (ret) -+ dev_warn(priv->dev, -+ "pull-down not found, use default : %u\n", -+ NPCM_PECI_PULL_DOWN_DEFAULT); -+ else -+ dev_warn(priv->dev, -+ "Invalid pull-down : %u. Use default : %u\n", -+ pull_down, -+ NPCM_PECI_PULL_DOWN_DEFAULT); -+ pull_down = NPCM_PECI_PULL_DOWN_DEFAULT; -+ } -+ -+ regmap_update_bits(priv->regmap, NPCM_PECI_CTL2, NPCM_PECI_CTL2_MASK, -+ pull_down << 6); -+ -+ ret = of_property_read_u32(priv->dev->of_node, "host-neg-bit-rate", -+ &host_neg_bit_rate); -+ if (ret || host_neg_bit_rate > NPCM_PECI_HOST_NEG_BIT_RATE_MAX || -+ host_neg_bit_rate < NPCM_PECI_HOST_NEG_BIT_RATE_MIN) { -+ if (ret) -+ dev_warn(priv->dev, -+ "host-neg-bit-rate not found, use default : %u\n", -+ NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT); -+ else -+ dev_warn(priv->dev, -+ "Invalid host-neg-bit-rate : %u. Use default : %u\n", -+ host_neg_bit_rate, -+ NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT); -+ host_neg_bit_rate = NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT; -+ } -+ -+ regmap_update_bits(priv->regmap, NPCM_PECI_PDDR, NPCM_PECI_PDDR_MASK, -+ host_neg_bit_rate); -+ -+ priv->host_bit_rate = clk_get_rate(priv->clk) / -+ (4 * (host_neg_bit_rate + 1)); -+ -+ ret = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts, -+ !(cmd_sts & NPCM_PECI_CTRL_START_BUSY), -+ NPCM_PECI_IDLE_CHECK_INTERVAL_USEC, -+ NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC); -+ if (ret) -+ return ret; /* -ETIMEDOUT */ -+ -+ /* PECI interrupt enable */ -+ regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS, -+ NPCM_PECI_CTRL_DONE_INT_EN, -+ NPCM_PECI_CTRL_DONE_INT_EN); -+ -+ return 0; -+} -+ -+static const struct regmap_config npcm_peci_regmap_config = { -+ .reg_bits = 8, -+ .val_bits = 8, -+ .max_register = NPCM_PECI_MAX_REG, -+ .fast_io = true, -+}; -+ -+static int npcm_peci_xfer(struct peci_adapter *adapter, -+ struct peci_xfer_msg *msg) -+{ -+ struct npcm_peci *priv = peci_get_adapdata(adapter); -+ -+ return npcm_peci_xfer_native(priv, msg); -+} -+ -+static int npcm_peci_probe(struct platform_device *pdev) -+{ -+ struct peci_adapter *adapter; -+ struct npcm_peci *priv; -+ struct resource *res; -+ void __iomem *base; -+ int ret; -+ -+ adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv)); -+ if (!adapter) -+ return -ENOMEM; -+ -+ priv = peci_get_adapdata(adapter); -+ priv->adapter = adapter; -+ priv->dev = &pdev->dev; -+ dev_set_drvdata(&pdev->dev, priv); -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(base)) { -+ ret = PTR_ERR(base); -+ goto err_put_adapter_dev; -+ } -+ -+ priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, -+ &npcm_peci_regmap_config); -+ if (IS_ERR(priv->regmap)) { -+ ret = PTR_ERR(priv->regmap); -+ goto err_put_adapter_dev; -+ } -+ -+ priv->irq = platform_get_irq(pdev, 0); -+ if (!priv->irq) { -+ ret = -ENODEV; -+ goto err_put_adapter_dev; -+ } -+ -+ ret = devm_request_irq(&pdev->dev, priv->irq, npcm_peci_irq_handler, -+ 0, "peci-npcm-irq", priv); -+ if (ret) -+ goto err_put_adapter_dev; -+ -+ init_completion(&priv->xfer_complete); -+ spin_lock_init(&priv->lock); -+ -+ priv->adapter->owner = THIS_MODULE; -+ priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev)); -+ strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name)); -+ priv->adapter->xfer = npcm_peci_xfer; -+ -+ ret = npcm_peci_init_ctrl(priv); -+ if (ret) -+ goto err_put_adapter_dev; -+ -+ ret = peci_add_adapter(priv->adapter); -+ if (ret) -+ goto err_put_adapter_dev; -+ -+ dev_info(&pdev->dev, "peci bus %d registered, host negotiation bit rate %dHz", -+ priv->adapter->nr, priv->host_bit_rate); -+ -+ return 0; -+ -+err_put_adapter_dev: -+ put_device(&adapter->dev); -+ return ret; -+} -+ -+static int npcm_peci_remove(struct platform_device *pdev) -+{ -+ struct npcm_peci *priv = dev_get_drvdata(&pdev->dev); -+ -+ clk_disable_unprepare(priv->clk); -+ peci_del_adapter(priv->adapter); -+ of_node_put(priv->adapter->dev.of_node); -+ -+ return 0; -+} -+ -+static const struct of_device_id npcm_peci_of_table[] = { -+ { .compatible = "nuvoton,npcm750-peci", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, npcm_peci_of_table); -+ -+static struct platform_driver npcm_peci_driver = { -+ .probe = npcm_peci_probe, -+ .remove = npcm_peci_remove, -+ .driver = { -+ .name = "peci-npcm", -+ .of_match_table = of_match_ptr(npcm_peci_of_table), -+ }, -+}; -+module_platform_driver(npcm_peci_driver); -+ -+MODULE_AUTHOR("Tomer Maimon "); -+MODULE_DESCRIPTION("NPCM Platform Environment Control Interface (PECI) driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/peci/peci-aspeed.c b/drivers/peci/peci-aspeed.c -deleted file mode 100644 -index 51cb2563ceb6..000000000000 ---- a/drivers/peci/peci-aspeed.c -+++ /dev/null -@@ -1,505 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --// Copyright (C) 2012-2017 ASPEED Technology Inc. --// Copyright (c) 2018 Intel Corporation -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --/* ASPEED PECI Registers */ --#define ASPEED_PECI_CTRL 0x00 --#define ASPEED_PECI_TIMING 0x04 --#define ASPEED_PECI_CMD 0x08 --#define ASPEED_PECI_CMD_CTRL 0x0c --#define ASPEED_PECI_EXP_FCS 0x10 --#define ASPEED_PECI_CAP_FCS 0x14 --#define ASPEED_PECI_INT_CTRL 0x18 --#define ASPEED_PECI_INT_STS 0x1c --#define ASPEED_PECI_W_DATA0 0x20 --#define ASPEED_PECI_W_DATA1 0x24 --#define ASPEED_PECI_W_DATA2 0x28 --#define ASPEED_PECI_W_DATA3 0x2c --#define ASPEED_PECI_R_DATA0 0x30 --#define ASPEED_PECI_R_DATA1 0x34 --#define ASPEED_PECI_R_DATA2 0x38 --#define ASPEED_PECI_R_DATA3 0x3c --#define ASPEED_PECI_W_DATA4 0x40 --#define ASPEED_PECI_W_DATA5 0x44 --#define ASPEED_PECI_W_DATA6 0x48 --#define ASPEED_PECI_W_DATA7 0x4c --#define ASPEED_PECI_R_DATA4 0x50 --#define ASPEED_PECI_R_DATA5 0x54 --#define ASPEED_PECI_R_DATA6 0x58 --#define ASPEED_PECI_R_DATA7 0x5c -- --/* ASPEED_PECI_CTRL - 0x00 : Control Register */ --#define PECI_CTRL_SAMPLING_MASK GENMASK(19, 16) --#define PECI_CTRL_READ_MODE_MASK GENMASK(13, 12) --#define PECI_CTRL_READ_MODE_COUNT BIT(12) --#define PECI_CTRL_READ_MODE_DBG BIT(13) --#define PECI_CTRL_CLK_SOURCE_MASK BIT(11) --#define PECI_CTRL_CLK_DIV_MASK GENMASK(10, 8) --#define PECI_CTRL_INVERT_OUT BIT(7) --#define PECI_CTRL_INVERT_IN BIT(6) --#define PECI_CTRL_BUS_CONTENT_EN BIT(5) --#define PECI_CTRL_PECI_EN BIT(4) --#define PECI_CTRL_PECI_CLK_EN BIT(0) -- --/* ASPEED_PECI_TIMING - 0x04 : Timing Negotiation Register */ --#define PECI_TIMING_MESSAGE_MASK GENMASK(15, 8) --#define PECI_TIMING_ADDRESS_MASK GENMASK(7, 0) -- --/* ASPEED_PECI_CMD - 0x08 : Command Register */ --#define PECI_CMD_PIN_MON BIT(31) --#define PECI_CMD_STS_MASK GENMASK(27, 24) --#define PECI_CMD_IDLE_MASK (PECI_CMD_STS_MASK | PECI_CMD_PIN_MON) --#define PECI_CMD_FIRE BIT(0) -- --/* ASPEED_PECI_LEN - 0x0C : Read/Write Length Register */ --#define PECI_AW_FCS_EN BIT(31) --#define PECI_READ_LEN_MASK GENMASK(23, 16) --#define PECI_WRITE_LEN_MASK GENMASK(15, 8) --#define PECI_TAGET_ADDR_MASK GENMASK(7, 0) -- --/* ASPEED_PECI_EXP_FCS - 0x10 : Expected FCS Data Register */ --#define PECI_EXPECT_READ_FCS_MASK GENMASK(23, 16) --#define PECI_EXPECT_AW_FCS_AUTO_MASK GENMASK(15, 8) --#define PECI_EXPECT_WRITE_FCS_MASK GENMASK(7, 0) -- --/* ASPEED_PECI_CAP_FCS - 0x14 : Captured FCS Data Register */ --#define PECI_CAPTURE_READ_FCS_MASK GENMASK(23, 16) --#define PECI_CAPTURE_WRITE_FCS_MASK GENMASK(7, 0) -- --/* ASPEED_PECI_INT_CTRL/STS - 0x18/0x1c : Interrupt Register */ --#define PECI_INT_TIMING_RESULT_MASK GENMASK(31, 30) --#define PECI_INT_TIMEOUT BIT(4) --#define PECI_INT_CONNECT BIT(3) --#define PECI_INT_W_FCS_BAD BIT(2) --#define PECI_INT_W_FCS_ABORT BIT(1) --#define PECI_INT_CMD_DONE BIT(0) -- --#define PECI_INT_MASK (PECI_INT_TIMEOUT | PECI_INT_CONNECT | \ -- PECI_INT_W_FCS_BAD | PECI_INT_W_FCS_ABORT | \ -- PECI_INT_CMD_DONE) -- --#define PECI_IDLE_CHECK_TIMEOUT_USEC 50000 --#define PECI_IDLE_CHECK_INTERVAL_USEC 10000 -- --#define PECI_RD_SAMPLING_POINT_DEFAULT 8 --#define PECI_RD_SAMPLING_POINT_MAX 15 --#define PECI_CLK_DIV_DEFAULT 0 --#define PECI_CLK_DIV_MAX 7 --#define PECI_MSG_TIMING_DEFAULT 1 --#define PECI_MSG_TIMING_MAX 255 --#define PECI_ADDR_TIMING_DEFAULT 1 --#define PECI_ADDR_TIMING_MAX 255 --#define PECI_CMD_TIMEOUT_MS_DEFAULT 1000 --#define PECI_CMD_TIMEOUT_MS_MAX 60000 -- --struct aspeed_peci { -- struct peci_adapter *adapter; -- struct device *dev; -- struct regmap *regmap; -- struct clk *clk; -- struct reset_control *rst; -- int irq; -- spinlock_t lock; /* to sync completion status handling */ -- struct completion xfer_complete; -- u32 status; -- u32 cmd_timeout_ms; --}; -- --static int aspeed_peci_xfer_native(struct aspeed_peci *priv, -- struct peci_xfer_msg *msg) --{ -- long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms); -- u32 peci_head, peci_state, rx_data, cmd_sts; -- unsigned long flags; -- int i, rc; -- uint reg; -- -- /* Check command sts and bus idle state */ -- rc = regmap_read_poll_timeout(priv->regmap, ASPEED_PECI_CMD, cmd_sts, -- !(cmd_sts & PECI_CMD_IDLE_MASK), -- PECI_IDLE_CHECK_INTERVAL_USEC, -- PECI_IDLE_CHECK_TIMEOUT_USEC); -- if (rc) -- return rc; /* -ETIMEDOUT */ -- -- spin_lock_irqsave(&priv->lock, flags); -- reinit_completion(&priv->xfer_complete); -- -- peci_head = FIELD_PREP(PECI_TAGET_ADDR_MASK, msg->addr) | -- FIELD_PREP(PECI_WRITE_LEN_MASK, msg->tx_len) | -- FIELD_PREP(PECI_READ_LEN_MASK, msg->rx_len); -- -- regmap_write(priv->regmap, ASPEED_PECI_CMD_CTRL, peci_head); -- -- for (i = 0; i < msg->tx_len; i += 4) { -- reg = i < 16 ? ASPEED_PECI_W_DATA0 + i % 16 : -- ASPEED_PECI_W_DATA4 + i % 16; -- regmap_write(priv->regmap, reg, -- le32_to_cpup((__le32 *)&msg->tx_buf[i])); -- } -- -- dev_dbg(priv->dev, "HEAD : 0x%08x\n", peci_head); -- print_hex_dump_debug("TX : ", DUMP_PREFIX_NONE, 16, 1, -- msg->tx_buf, msg->tx_len, true); -- -- priv->status = 0; -- regmap_write(priv->regmap, ASPEED_PECI_CMD, PECI_CMD_FIRE); -- spin_unlock_irqrestore(&priv->lock, flags); -- -- err = wait_for_completion_interruptible_timeout(&priv->xfer_complete, -- timeout); -- -- spin_lock_irqsave(&priv->lock, flags); -- dev_dbg(priv->dev, "INT_STS : 0x%08x\n", priv->status); -- regmap_read(priv->regmap, ASPEED_PECI_CMD, &peci_state); -- dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n", -- FIELD_GET(PECI_CMD_STS_MASK, peci_state)); -- -- regmap_write(priv->regmap, ASPEED_PECI_CMD, 0); -- -- if (err <= 0 || priv->status != PECI_INT_CMD_DONE) { -- if (err < 0) { /* -ERESTARTSYS */ -- rc = (int)err; -- goto err_irqrestore; -- } else if (err == 0) { -- dev_dbg(priv->dev, "Timeout waiting for a response!\n"); -- rc = -ETIMEDOUT; -- goto err_irqrestore; -- } -- -- dev_dbg(priv->dev, "No valid response!\n"); -- rc = -EIO; -- goto err_irqrestore; -- } -- -- /** -- * Note that rx_len and rx_buf size can be an odd number. -- * Byte handling is more efficient. -- */ -- for (i = 0; i < msg->rx_len; i++) { -- u8 byte_offset = i % 4; -- -- if (byte_offset == 0) { -- reg = i < 16 ? ASPEED_PECI_R_DATA0 + i % 16 : -- ASPEED_PECI_R_DATA4 + i % 16; -- regmap_read(priv->regmap, reg, &rx_data); -- } -- -- msg->rx_buf[i] = (u8)(rx_data >> (byte_offset << 3)); -- } -- -- print_hex_dump_debug("RX : ", DUMP_PREFIX_NONE, 16, 1, -- msg->rx_buf, msg->rx_len, true); -- -- regmap_read(priv->regmap, ASPEED_PECI_CMD, &peci_state); -- dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n", -- FIELD_GET(PECI_CMD_STS_MASK, peci_state)); -- dev_dbg(priv->dev, "------------------------\n"); -- --err_irqrestore: -- spin_unlock_irqrestore(&priv->lock, flags); -- return rc; --} -- --static irqreturn_t aspeed_peci_irq_handler(int irq, void *arg) --{ -- struct aspeed_peci *priv = arg; -- u32 status_ack = 0; -- u32 status; -- -- spin_lock(&priv->lock); -- regmap_read(priv->regmap, ASPEED_PECI_INT_STS, &status); -- priv->status |= (status & PECI_INT_MASK); -- -- /** -- * In most cases, interrupt bits will be set one by one but also note -- * that multiple interrupt bits could be set at the same time. -- */ -- if (status & PECI_INT_TIMEOUT) { -- dev_dbg(priv->dev, "PECI_INT_TIMEOUT\n"); -- status_ack |= PECI_INT_TIMEOUT; -- } -- -- if (status & PECI_INT_CONNECT) { -- dev_dbg(priv->dev, "PECI_INT_CONNECT\n"); -- status_ack |= PECI_INT_CONNECT; -- } -- -- if (status & PECI_INT_W_FCS_BAD) { -- dev_dbg(priv->dev, "PECI_INT_W_FCS_BAD\n"); -- status_ack |= PECI_INT_W_FCS_BAD; -- } -- -- if (status & PECI_INT_W_FCS_ABORT) { -- dev_dbg(priv->dev, "PECI_INT_W_FCS_ABORT\n"); -- status_ack |= PECI_INT_W_FCS_ABORT; -- } -- -- /** -- * All commands should be ended up with a PECI_INT_CMD_DONE bit set -- * even in an error case. -- */ -- if (status & PECI_INT_CMD_DONE) { -- dev_dbg(priv->dev, "PECI_INT_CMD_DONE\n"); -- status_ack |= PECI_INT_CMD_DONE; -- complete(&priv->xfer_complete); -- } -- -- regmap_write(priv->regmap, ASPEED_PECI_INT_STS, status_ack); -- spin_unlock(&priv->lock); -- return IRQ_HANDLED; --} -- --static int aspeed_peci_init_ctrl(struct aspeed_peci *priv) --{ -- u32 msg_timing, addr_timing, rd_sampling_point; -- u32 clk_freq, clk_divisor, clk_div_val = 0; -- int ret; -- -- priv->clk = devm_clk_get(priv->dev, NULL); -- if (IS_ERR(priv->clk)) { -- dev_err(priv->dev, "Failed to get clk source.\n"); -- return PTR_ERR(priv->clk); -- } -- -- ret = clk_prepare_enable(priv->clk); -- if (ret) { -- dev_err(priv->dev, "Failed to enable clock.\n"); -- return ret; -- } -- -- ret = of_property_read_u32(priv->dev->of_node, "clock-frequency", -- &clk_freq); -- if (ret) { -- dev_err(priv->dev, -- "Could not read clock-frequency property.\n"); -- clk_disable_unprepare(priv->clk); -- return ret; -- } -- -- clk_divisor = clk_get_rate(priv->clk) / clk_freq; -- -- while ((clk_divisor >> 1) && (clk_div_val < PECI_CLK_DIV_MAX)) -- clk_div_val++; -- -- ret = of_property_read_u32(priv->dev->of_node, "msg-timing", -- &msg_timing); -- if (ret || msg_timing > PECI_MSG_TIMING_MAX) { -- if (!ret) -- dev_warn(priv->dev, -- "Invalid msg-timing : %u, Use default : %u\n", -- msg_timing, PECI_MSG_TIMING_DEFAULT); -- msg_timing = PECI_MSG_TIMING_DEFAULT; -- } -- -- ret = of_property_read_u32(priv->dev->of_node, "addr-timing", -- &addr_timing); -- if (ret || addr_timing > PECI_ADDR_TIMING_MAX) { -- if (!ret) -- dev_warn(priv->dev, -- "Invalid addr-timing : %u, Use default : %u\n", -- addr_timing, PECI_ADDR_TIMING_DEFAULT); -- addr_timing = PECI_ADDR_TIMING_DEFAULT; -- } -- -- ret = of_property_read_u32(priv->dev->of_node, "rd-sampling-point", -- &rd_sampling_point); -- if (ret || rd_sampling_point > PECI_RD_SAMPLING_POINT_MAX) { -- if (!ret) -- dev_warn(priv->dev, -- "Invalid rd-sampling-point : %u. Use default : %u\n", -- rd_sampling_point, -- PECI_RD_SAMPLING_POINT_DEFAULT); -- rd_sampling_point = PECI_RD_SAMPLING_POINT_DEFAULT; -- } -- -- ret = of_property_read_u32(priv->dev->of_node, "cmd-timeout-ms", -- &priv->cmd_timeout_ms); -- if (ret || priv->cmd_timeout_ms > PECI_CMD_TIMEOUT_MS_MAX || -- priv->cmd_timeout_ms == 0) { -- if (!ret) -- dev_warn(priv->dev, -- "Invalid cmd-timeout-ms : %u. Use default : %u\n", -- priv->cmd_timeout_ms, -- PECI_CMD_TIMEOUT_MS_DEFAULT); -- priv->cmd_timeout_ms = PECI_CMD_TIMEOUT_MS_DEFAULT; -- } -- -- regmap_write(priv->regmap, ASPEED_PECI_CTRL, -- FIELD_PREP(PECI_CTRL_CLK_DIV_MASK, PECI_CLK_DIV_DEFAULT) | -- PECI_CTRL_PECI_CLK_EN); -- -- /** -- * Timing negotiation period setting. -- * The unit of the programmed value is 4 times of PECI clock period. -- */ -- regmap_write(priv->regmap, ASPEED_PECI_TIMING, -- FIELD_PREP(PECI_TIMING_MESSAGE_MASK, msg_timing) | -- FIELD_PREP(PECI_TIMING_ADDRESS_MASK, addr_timing)); -- -- /* Clear interrupts */ -- regmap_write(priv->regmap, ASPEED_PECI_INT_STS, PECI_INT_MASK); -- -- /* Enable interrupts */ -- regmap_write(priv->regmap, ASPEED_PECI_INT_CTRL, PECI_INT_MASK); -- -- /* Read sampling point and clock speed setting */ -- regmap_write(priv->regmap, ASPEED_PECI_CTRL, -- FIELD_PREP(PECI_CTRL_SAMPLING_MASK, rd_sampling_point) | -- FIELD_PREP(PECI_CTRL_CLK_DIV_MASK, clk_div_val) | -- PECI_CTRL_PECI_EN | PECI_CTRL_PECI_CLK_EN); -- -- return 0; --} -- --static const struct regmap_config aspeed_peci_regmap_config = { -- .reg_bits = 32, -- .val_bits = 32, -- .reg_stride = 4, -- .max_register = ASPEED_PECI_R_DATA7, -- .val_format_endian = REGMAP_ENDIAN_LITTLE, -- .fast_io = true, --}; -- --static int aspeed_peci_xfer(struct peci_adapter *adapter, -- struct peci_xfer_msg *msg) --{ -- struct aspeed_peci *priv = peci_get_adapdata(adapter); -- -- return aspeed_peci_xfer_native(priv, msg); --} -- --static int aspeed_peci_probe(struct platform_device *pdev) --{ -- struct peci_adapter *adapter; -- struct aspeed_peci *priv; -- struct resource *res; -- void __iomem *base; -- u32 cmd_sts; -- int ret; -- -- adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv)); -- if (!adapter) -- return -ENOMEM; -- -- priv = peci_get_adapdata(adapter); -- priv->adapter = adapter; -- priv->dev = &pdev->dev; -- dev_set_drvdata(&pdev->dev, priv); -- -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- base = devm_ioremap_resource(&pdev->dev, res); -- if (IS_ERR(base)) { -- ret = PTR_ERR(base); -- goto err_put_adapter_dev; -- } -- -- priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, -- &aspeed_peci_regmap_config); -- if (IS_ERR(priv->regmap)) { -- ret = PTR_ERR(priv->regmap); -- goto err_put_adapter_dev; -- } -- -- /** -- * We check that the regmap works on this very first access, -- * but as this is an MMIO-backed regmap, subsequent regmap -- * access is not going to fail and we skip error checks from -- * this point. -- */ -- ret = regmap_read(priv->regmap, ASPEED_PECI_CMD, &cmd_sts); -- if (ret) { -- ret = -EIO; -- goto err_put_adapter_dev; -- } -- -- priv->irq = platform_get_irq(pdev, 0); -- if (!priv->irq) { -- ret = -ENODEV; -- goto err_put_adapter_dev; -- } -- -- ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_peci_irq_handler, -- 0, "peci-aspeed-irq", priv); -- if (ret) -- goto err_put_adapter_dev; -- -- init_completion(&priv->xfer_complete); -- spin_lock_init(&priv->lock); -- -- priv->adapter->owner = THIS_MODULE; -- priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev)); -- strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name)); -- priv->adapter->xfer = aspeed_peci_xfer; -- -- priv->rst = devm_reset_control_get(&pdev->dev, NULL); -- if (IS_ERR(priv->rst)) { -- dev_err(&pdev->dev, -- "missing or invalid reset controller entry"); -- ret = PTR_ERR(priv->rst); -- goto err_put_adapter_dev; -- } -- reset_control_deassert(priv->rst); -- -- ret = aspeed_peci_init_ctrl(priv); -- if (ret) -- goto err_put_adapter_dev; -- -- ret = peci_add_adapter(priv->adapter); -- if (ret) -- goto err_put_adapter_dev; -- -- dev_info(&pdev->dev, "peci bus %d registered, irq %d\n", -- priv->adapter->nr, priv->irq); -- -- return 0; -- --err_put_adapter_dev: -- put_device(&adapter->dev); -- return ret; --} -- --static int aspeed_peci_remove(struct platform_device *pdev) --{ -- struct aspeed_peci *priv = dev_get_drvdata(&pdev->dev); -- -- clk_disable_unprepare(priv->clk); -- reset_control_assert(priv->rst); -- peci_del_adapter(priv->adapter); -- of_node_put(priv->adapter->dev.of_node); -- -- return 0; --} -- --static const struct of_device_id aspeed_peci_of_table[] = { -- { .compatible = "aspeed,ast2400-peci", }, -- { .compatible = "aspeed,ast2500-peci", }, -- { } --}; --MODULE_DEVICE_TABLE(of, aspeed_peci_of_table); -- --static struct platform_driver aspeed_peci_driver = { -- .probe = aspeed_peci_probe, -- .remove = aspeed_peci_remove, -- .driver = { -- .name = "peci-aspeed", -- .of_match_table = of_match_ptr(aspeed_peci_of_table), -- }, --}; --module_platform_driver(aspeed_peci_driver); -- --MODULE_AUTHOR("Ryan Chen "); --MODULE_AUTHOR("Jae Hyun Yoo "); --MODULE_DESCRIPTION("ASPEED PECI driver"); --MODULE_LICENSE("GPL v2"); -diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c -index 6f241469ec7e..48f29de09311 100644 ---- a/drivers/peci/peci-core.c -+++ b/drivers/peci/peci-core.c -@@ -1,38 +1,31 @@ - // SPDX-License-Identifier: GPL-2.0 --// Copyright (c) 2018 Intel Corporation -+// Copyright (c) 2018-2019 Intel Corporation - - #include - #include - #include --#include -+#include - #include - #include - #include - #include - #include -+#include - #include --#include - - /* Mask for getting minor revision number from DIB */ - #define REVISION_NUM_MASK GENMASK(15, 8) - --/* CRC8 table for Assure Write Frame Check */ -+/* CRC8 table for Assured Write Frame Check */ - #define PECI_CRC8_POLYNOMIAL 0x07 - DECLARE_CRC8_TABLE(peci_crc8_table); - --static struct device_type peci_adapter_type; --static struct device_type peci_client_type; -- --/* Max number of peci cdev */ --#define PECI_CDEV_MAX 16 -- --static dev_t peci_devt; - static bool is_registered; - - static DEFINE_MUTEX(core_lock); - static DEFINE_IDR(peci_adapter_idr); - --static struct peci_adapter *peci_get_adapter(int nr) -+struct peci_adapter *peci_get_adapter(int nr) - { - struct peci_adapter *adapter; - -@@ -48,10 +41,12 @@ static struct peci_adapter *peci_get_adapter(int nr) - - out_unlock: - mutex_unlock(&core_lock); -+ - return adapter; - } -+EXPORT_SYMBOL_GPL(peci_get_adapter); - --static void peci_put_adapter(struct peci_adapter *adapter) -+void peci_put_adapter(struct peci_adapter *adapter) - { - if (!adapter) - return; -@@ -59,6 +54,7 @@ static void peci_put_adapter(struct peci_adapter *adapter) - put_device(&adapter->dev); - module_put(adapter->owner); - } -+EXPORT_SYMBOL_GPL(peci_put_adapter); - - static ssize_t name_show(struct device *dev, - struct device_attribute *attr, -@@ -84,10 +80,11 @@ static struct attribute *peci_device_attrs[] = { - }; - ATTRIBUTE_GROUPS(peci_device); - --static struct device_type peci_client_type = { -+struct device_type peci_client_type = { - .groups = peci_device_groups, - .release = peci_client_dev_release, - }; -+EXPORT_SYMBOL_GPL(peci_client_type); - - /** - * peci_verify_client - return parameter as peci_client, or NULL -@@ -103,19 +100,120 @@ struct peci_client *peci_verify_client(struct device *dev) - } - EXPORT_SYMBOL_GPL(peci_verify_client); - --static u8 peci_aw_fcs(u8 *data, int len) -+/** -+ * peci_get_xfer_msg() - get a DMA safe peci_xfer_msg for the given tx and rx -+ * length -+ * @tx_len: the length of tx_buf. May be 0 if tx_buf isn't needed. -+ * @rx_len: the length of rx_buf. May be 0 if rx_buf isn't needed. -+ * -+ * Return: NULL if a DMA safe buffer was not obtained. -+ * Or a valid pointer to be used with DMA. After use, release it by -+ * calling peci_put_xfer_msg(). -+ * -+ * This function must only be called from process context! -+ */ -+struct peci_xfer_msg *peci_get_xfer_msg(u8 tx_len, u8 rx_len) - { -- return crc8(peci_crc8_table, data, (size_t)len, 0); -+ struct peci_xfer_msg *msg; -+ u8 *tx_buf, *rx_buf; -+ -+ if (tx_len) { -+ tx_buf = kzalloc(tx_len, GFP_KERNEL); -+ if (!tx_buf) -+ return NULL; -+ } else { -+ tx_buf = NULL; -+ } -+ -+ if (rx_len) { -+ rx_buf = kzalloc(rx_len, GFP_KERNEL); -+ if (!rx_buf) -+ goto err_free_tx_buf; -+ } else { -+ rx_buf = NULL; -+ } -+ -+ msg = kzalloc(sizeof(struct peci_xfer_msg), GFP_KERNEL); -+ if (!msg) -+ goto err_free_tx_rx_buf; -+ -+ msg->tx_len = tx_len; -+ msg->tx_buf = tx_buf; -+ msg->rx_len = rx_len; -+ msg->rx_buf = rx_buf; -+ -+ return msg; -+ -+err_free_tx_rx_buf: -+ kfree(rx_buf); -+err_free_tx_buf: -+ kfree(tx_buf); -+ -+ return NULL; -+} -+EXPORT_SYMBOL_GPL(peci_get_xfer_msg); -+ -+/** -+ * peci_put_xfer_msg - release a DMA safe peci_xfer_msg -+ * @msg: the message obtained from peci_get_xfer_msg(). May be NULL. -+ */ -+void peci_put_xfer_msg(struct peci_xfer_msg *msg) -+{ -+ if (!msg) -+ return; -+ -+ kfree(msg->rx_buf); -+ kfree(msg->tx_buf); -+ kfree(msg); -+} -+EXPORT_SYMBOL_GPL(peci_put_xfer_msg); -+ -+/* Calculate an Assured Write Frame Check Sequence byte */ -+static int peci_aw_fcs(struct peci_xfer_msg *msg, int len, u8 *aw_fcs) -+{ -+ u8 *tmp_buf; -+ -+ /* Allocate a temporary buffer to use a contiguous byte array */ -+ tmp_buf = kmalloc(len, GFP_KERNEL); -+ if (!tmp_buf) -+ return -ENOMEM; -+ -+ tmp_buf[0] = msg->addr; -+ tmp_buf[1] = msg->tx_len; -+ tmp_buf[2] = msg->rx_len; -+ memcpy(&tmp_buf[3], msg->tx_buf, len - 3); -+ -+ *aw_fcs = crc8(peci_crc8_table, tmp_buf, (size_t)len, 0); -+ -+ kfree(tmp_buf); -+ -+ return 0; - } - - static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg, - bool do_retry, bool has_aw_fcs) - { -- ktime_t start, end; -- s64 elapsed_ms; -- int rc = 0; -+ ulong timeout = jiffies; -+ u8 aw_fcs; -+ int ret; -+ -+ /* -+ * In case if adapter uses DMA, check at here whether tx and rx buffers -+ * are DMA capable or not. -+ */ -+ if (IS_ENABLED(CONFIG_HAS_DMA) && adapter->use_dma) { -+ if (is_vmalloc_addr(msg->tx_buf) || -+ is_vmalloc_addr(msg->rx_buf)) { -+ WARN_ONCE(1, "xfer msg is not dma capable\n"); -+ return -EAGAIN; -+ } else if (object_is_on_stack(msg->tx_buf) || -+ object_is_on_stack(msg->rx_buf)) { -+ WARN_ONCE(1, "xfer msg is on stack\n"); -+ return -EAGAIN; -+ } -+ } - -- /** -+ /* - * For some commands, the PECI originator may need to retry a command if - * the processor PECI client responds with a 0x8x completion code. In - * each instance, the processor PECI client may have started the -@@ -125,55 +223,51 @@ static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg, - */ - - if (do_retry) -- start = ktime_get(); -+ timeout += msecs_to_jiffies(PECI_DEV_RETRY_TIME_MS); - -- do { -- rc = adapter->xfer(adapter, msg); -+ for (;;) { -+ ret = adapter->xfer(adapter, msg); - -- if (!do_retry || rc) -- break; -- -- if (msg->rx_buf[0] == DEV_PECI_CC_SUCCESS) -+ if (!do_retry || ret || !msg->rx_buf) - break; - - /* Retry is needed when completion code is 0x8x */ -- if ((msg->rx_buf[0] & DEV_PECI_CC_RETRY_CHECK_MASK) != -- DEV_PECI_CC_NEED_RETRY) { -- rc = -EIO; -+ if ((msg->rx_buf[0] & PECI_DEV_CC_RETRY_CHECK_MASK) != -+ PECI_DEV_CC_NEED_RETRY) - break; -- } - - /* Set the retry bit to indicate a retry attempt */ -- msg->tx_buf[1] |= DEV_PECI_RETRY_BIT; -+ msg->tx_buf[1] |= PECI_DEV_RETRY_BIT; - - /* Recalculate the AW FCS if it has one */ -- if (has_aw_fcs) -- msg->tx_buf[msg->tx_len - 1] = 0x80 ^ -- peci_aw_fcs((u8 *)msg, -- 2 + msg->tx_len); -+ if (has_aw_fcs) { -+ ret = peci_aw_fcs(msg, 2 + msg->tx_len, &aw_fcs); -+ if (ret) -+ break; -+ -+ msg->tx_buf[msg->tx_len - 1] = 0x80 ^ aw_fcs; -+ } - -- /** -+ /* - * Retry for at least 250ms before returning an error. - * Retry interval guideline: - * No minimum < Retry Interval < No maximum - * (recommend 10ms) - */ -- end = ktime_get(); -- elapsed_ms = ktime_to_ms(ktime_sub(end, start)); -- if (elapsed_ms >= DEV_PECI_RETRY_TIME_MS) { -+ if (time_after(jiffies, timeout)) { - dev_dbg(&adapter->dev, "Timeout retrying xfer!\n"); -- rc = -ETIMEDOUT; -+ ret = -ETIMEDOUT; - break; - } - -- usleep_range((DEV_PECI_RETRY_INTERVAL_USEC >> 2) + 1, -- DEV_PECI_RETRY_INTERVAL_USEC); -- } while (true); -+ usleep_range((PECI_DEV_RETRY_INTERVAL_USEC >> 2) + 1, -+ PECI_DEV_RETRY_INTERVAL_USEC); -+ } - -- if (rc) -- dev_dbg(&adapter->dev, "xfer error, rc: %d\n", rc); -+ if (ret) -+ dev_dbg(&adapter->dev, "xfer error: %d\n", ret); - -- return rc; -+ return ret; - } - - static int peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg) -@@ -190,34 +284,37 @@ static int peci_xfer_with_retries(struct peci_adapter *adapter, - - static int peci_scan_cmd_mask(struct peci_adapter *adapter) - { -- struct peci_xfer_msg msg; -+ struct peci_xfer_msg *msg; - u8 revision; -- int rc = 0; -+ int ret; - u64 dib; - - /* Update command mask just once */ - if (adapter->cmd_mask & BIT(PECI_CMD_XFER)) - return 0; - -- msg.addr = PECI_BASE_ADDR; -- msg.tx_len = GET_DIB_WR_LEN; -- msg.rx_len = GET_DIB_RD_LEN; -- msg.tx_buf[0] = GET_DIB_PECI_CMD; -+ msg = peci_get_xfer_msg(PECI_GET_DIB_WR_LEN, PECI_GET_DIB_RD_LEN); -+ if (!msg) -+ return -ENOMEM; -+ -+ msg->addr = PECI_BASE_ADDR; -+ msg->tx_buf[0] = PECI_GET_DIB_CMD; - -- rc = peci_xfer(adapter, &msg); -- if (rc) -- return rc; -+ ret = peci_xfer(adapter, msg); -+ if (ret) -+ return ret; - -- dib = le64_to_cpup((__le64 *)msg.rx_buf); -+ dib = le64_to_cpup((__le64 *)msg->rx_buf); - - /* Check special case for Get DIB command */ - if (dib == 0) { - dev_dbg(&adapter->dev, "DIB read as 0\n"); -- return -EIO; -+ ret = -EIO; -+ goto out; - } - -- /** -- * Setting up the supporting commands based on minor revision number. -+ /* -+ * Setting up the supporting commands based on revision number. - * See PECI Spec Table 3-1. - */ - revision = FIELD_GET(REVISION_NUM_MASK, dib); -@@ -243,10 +340,14 @@ static int peci_scan_cmd_mask(struct peci_adapter *adapter) - adapter->cmd_mask |= BIT(PECI_CMD_GET_DIB); - adapter->cmd_mask |= BIT(PECI_CMD_PING); - -- return rc; -+out: -+ peci_put_xfer_msg(msg); -+ -+ return ret; - } - --static int peci_cmd_support(struct peci_adapter *adapter, enum peci_cmd cmd) -+static int peci_check_cmd_support(struct peci_adapter *adapter, -+ enum peci_cmd cmd) - { - if (!(adapter->cmd_mask & BIT(PECI_CMD_PING)) && - peci_scan_cmd_mask(adapter) < 0) { -@@ -262,70 +363,87 @@ static int peci_cmd_support(struct peci_adapter *adapter, enum peci_cmd cmd) - return 0; - } - --static int peci_ioctl_xfer(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_xfer(struct peci_adapter *adapter, void *vmsg) - { - struct peci_xfer_msg *msg = vmsg; - - return peci_xfer(adapter, msg); - } - --static int peci_ioctl_ping(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_ping(struct peci_adapter *adapter, void *vmsg) - { - struct peci_ping_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -+ struct peci_xfer_msg *msg; -+ int ret; -+ -+ msg = peci_get_xfer_msg(0, 0); -+ if (!msg) -+ return -ENOMEM; -+ -+ msg->addr = umsg->addr; - -- msg.addr = umsg->addr; -- msg.tx_len = 0; -- msg.rx_len = 0; -+ ret = peci_xfer(adapter, msg); - -- return peci_xfer(adapter, &msg); -+ peci_put_xfer_msg(msg); -+ -+ return ret; - } - --static int peci_ioctl_get_dib(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_get_dib(struct peci_adapter *adapter, void *vmsg) - { - struct peci_get_dib_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -- int rc; -+ struct peci_xfer_msg *msg; -+ int ret; - -- msg.addr = umsg->addr; -- msg.tx_len = GET_DIB_WR_LEN; -- msg.rx_len = GET_DIB_RD_LEN; -- msg.tx_buf[0] = GET_DIB_PECI_CMD; -+ msg = peci_get_xfer_msg(PECI_GET_DIB_WR_LEN, PECI_GET_DIB_RD_LEN); -+ if (!msg) -+ return -ENOMEM; - -- rc = peci_xfer(adapter, &msg); -- if (rc) -- return rc; -+ msg->addr = umsg->addr; -+ msg->tx_buf[0] = PECI_GET_DIB_CMD; - -- umsg->dib = le64_to_cpup((__le64 *)msg.rx_buf); -+ ret = peci_xfer(adapter, msg); -+ if (ret) -+ goto out; - -- return 0; -+ umsg->dib = le64_to_cpup((__le64 *)msg->rx_buf); -+ -+out: -+ peci_put_xfer_msg(msg); -+ -+ return ret; - } - --static int peci_ioctl_get_temp(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_get_temp(struct peci_adapter *adapter, void *vmsg) - { - struct peci_get_temp_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -- int rc; -+ struct peci_xfer_msg *msg; -+ int ret; - -- msg.addr = umsg->addr; -- msg.tx_len = GET_TEMP_WR_LEN; -- msg.rx_len = GET_TEMP_RD_LEN; -- msg.tx_buf[0] = GET_TEMP_PECI_CMD; -+ msg = peci_get_xfer_msg(PECI_GET_TEMP_WR_LEN, PECI_GET_TEMP_RD_LEN); -+ if (!msg) -+ return -ENOMEM; - -- rc = peci_xfer(adapter, &msg); -- if (rc) -- return rc; -+ msg->addr = umsg->addr; -+ msg->tx_buf[0] = PECI_GET_TEMP_CMD; - -- umsg->temp_raw = le16_to_cpup((__le16 *)msg.rx_buf); -+ ret = peci_xfer(adapter, msg); -+ if (ret) -+ goto out; - -- return 0; -+ umsg->temp_raw = le16_to_cpup((__le16 *)msg->rx_buf); -+ -+out: -+ peci_put_xfer_msg(msg); -+ -+ return ret; - } - --static int peci_ioctl_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg) - { - struct peci_rd_pkg_cfg_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -- int rc = 0; -+ struct peci_xfer_msg *msg; -+ int ret; - - /* Per the PECI spec, the read length must be a byte, word, or dword */ - if (umsg->rx_len != 1 && umsg->rx_len != 2 && umsg->rx_len != 4) { -@@ -334,29 +452,35 @@ static int peci_ioctl_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg) - return -EINVAL; - } - -- msg.addr = umsg->addr; -- msg.tx_len = RDPKGCFG_WRITE_LEN; -- /* read lengths of 1 and 2 result in an error, so only use 4 for now */ -- msg.rx_len = RDPKGCFG_READ_LEN_BASE + umsg->rx_len; -- msg.tx_buf[0] = RDPKGCFG_PECI_CMD; -- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ -- /* Host ID is 0 for PECI 3.0 */ -- msg.tx_buf[2] = umsg->index; /* RdPkgConfig index */ -- msg.tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */ -- msg.tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */ -+ msg = peci_get_xfer_msg(PECI_RDPKGCFG_WRITE_LEN, -+ PECI_RDPKGCFG_READ_LEN_BASE + umsg->rx_len); -+ if (!msg) -+ return -ENOMEM; -+ -+ msg->addr = umsg->addr; -+ msg->tx_buf[0] = PECI_RDPKGCFG_CMD; -+ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ -+ /* Host ID is 0 for PECI 3.0 */ -+ msg->tx_buf[2] = umsg->index; /* RdPkgConfig index */ -+ msg->tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */ -+ msg->tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */ - -- rc = peci_xfer_with_retries(adapter, &msg, false); -- if (!rc) -- memcpy(umsg->pkg_config, &msg.rx_buf[1], umsg->rx_len); -+ ret = peci_xfer_with_retries(adapter, msg, false); -+ if (!ret) -+ memcpy(umsg->pkg_config, &msg->rx_buf[1], umsg->rx_len); - -- return rc; -+ umsg->cc = msg->rx_buf[0]; -+ peci_put_xfer_msg(msg); -+ -+ return ret; - } - --static int peci_ioctl_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg) - { - struct peci_wr_pkg_cfg_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -- int rc = 0, i; -+ struct peci_xfer_msg *msg; -+ int ret, i; -+ u8 aw_fcs; - - /* Per the PECI spec, the write length must be a dword */ - if (umsg->tx_len != 4) { -@@ -365,86 +489,116 @@ static int peci_ioctl_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg) - return -EINVAL; - } - -- msg.addr = umsg->addr; -- msg.tx_len = WRPKGCFG_WRITE_LEN_BASE + umsg->tx_len; -- /* read lengths of 1 and 2 result in an error, so only use 4 for now */ -- msg.rx_len = WRPKGCFG_READ_LEN; -- msg.tx_buf[0] = WRPKGCFG_PECI_CMD; -- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ -+ msg = peci_get_xfer_msg(PECI_WRPKGCFG_WRITE_LEN_BASE + umsg->tx_len, -+ PECI_WRPKGCFG_READ_LEN); -+ if (!msg) -+ return -ENOMEM; -+ -+ msg->addr = umsg->addr; -+ msg->tx_buf[0] = PECI_WRPKGCFG_CMD; -+ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ - /* Host ID is 0 for PECI 3.0 */ -- msg.tx_buf[2] = umsg->index; /* RdPkgConfig index */ -- msg.tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */ -- msg.tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */ -+ msg->tx_buf[2] = umsg->index; /* RdPkgConfig index */ -+ msg->tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */ -+ msg->tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */ - for (i = 0; i < umsg->tx_len; i++) -- msg.tx_buf[5 + i] = (u8)(umsg->value >> (i << 3)); -+ msg->tx_buf[5 + i] = (u8)(umsg->value >> (i << 3)); -+ -+ /* Add an Assured Write Frame Check Sequence byte */ -+ ret = peci_aw_fcs(msg, 8 + umsg->tx_len, &aw_fcs); -+ if (ret) -+ goto out; - -- /* Add an Assure Write Frame Check Sequence byte */ -- msg.tx_buf[5 + i] = 0x80 ^ -- peci_aw_fcs((u8 *)&msg, 8 + umsg->tx_len); -+ msg->tx_buf[5 + i] = 0x80 ^ aw_fcs; - -- rc = peci_xfer_with_retries(adapter, &msg, true); -+ ret = peci_xfer_with_retries(adapter, msg, true); - -- return rc; -+out: -+ umsg->cc = msg->rx_buf[0]; -+ peci_put_xfer_msg(msg); -+ -+ return ret; - } - --static int peci_ioctl_rd_ia_msr(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_rd_ia_msr(struct peci_adapter *adapter, void *vmsg) - { - struct peci_rd_ia_msr_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -- int rc = 0; -- -- msg.addr = umsg->addr; -- msg.tx_len = RDIAMSR_WRITE_LEN; -- msg.rx_len = RDIAMSR_READ_LEN; -- msg.tx_buf[0] = RDIAMSR_PECI_CMD; -- msg.tx_buf[1] = 0; -- msg.tx_buf[2] = umsg->thread_id; -- msg.tx_buf[3] = (u8)umsg->address; -- msg.tx_buf[4] = (u8)(umsg->address >> 8); -- -- rc = peci_xfer_with_retries(adapter, &msg, false); -- if (!rc) -- memcpy(&umsg->value, &msg.rx_buf[1], sizeof(uint64_t)); -- -- return rc; -+ struct peci_xfer_msg *msg; -+ int ret; -+ -+ msg = peci_get_xfer_msg(PECI_RDIAMSR_WRITE_LEN, PECI_RDIAMSR_READ_LEN); -+ if (!msg) -+ return -ENOMEM; -+ -+ msg->addr = umsg->addr; -+ msg->tx_buf[0] = PECI_RDIAMSR_CMD; -+ msg->tx_buf[1] = 0; -+ msg->tx_buf[2] = umsg->thread_id; -+ msg->tx_buf[3] = (u8)umsg->address; -+ msg->tx_buf[4] = (u8)(umsg->address >> 8); -+ -+ ret = peci_xfer_with_retries(adapter, msg, false); -+ if (!ret) -+ memcpy(&umsg->value, &msg->rx_buf[1], sizeof(uint64_t)); -+ -+ umsg->cc = msg->rx_buf[0]; -+ peci_put_xfer_msg(msg); -+ -+ return ret; - } - --static int peci_ioctl_rd_pci_cfg(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_wr_ia_msr(struct peci_adapter *adapter, void *vmsg) -+{ -+ return -ENOSYS; /* Not implemented yet */ -+} -+ -+static int peci_cmd_rd_pci_cfg(struct peci_adapter *adapter, void *vmsg) - { - struct peci_rd_pci_cfg_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -+ struct peci_xfer_msg *msg; - u32 address; -- int rc = 0; -+ int ret; -+ -+ msg = peci_get_xfer_msg(PECI_RDPCICFG_WRITE_LEN, -+ PECI_RDPCICFG_READ_LEN); -+ if (!msg) -+ return -ENOMEM; - - address = umsg->reg; /* [11:0] - Register */ - address |= (u32)umsg->function << 12; /* [14:12] - Function */ - address |= (u32)umsg->device << 15; /* [19:15] - Device */ - address |= (u32)umsg->bus << 20; /* [27:20] - Bus */ - /* [31:28] - Reserved */ -- msg.addr = umsg->addr; -- msg.tx_len = RDPCICFG_WRITE_LEN; -- msg.rx_len = RDPCICFG_READ_LEN; -- msg.tx_buf[0] = RDPCICFG_PECI_CMD; -- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ -+ msg->addr = umsg->addr; -+ msg->tx_buf[0] = PECI_RDPCICFG_CMD; -+ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ - /* Host ID is 0 for PECI 3.0 */ -- msg.tx_buf[2] = (u8)address; /* LSB - PCI Config Address */ -- msg.tx_buf[3] = (u8)(address >> 8); /* PCI Config Address */ -- msg.tx_buf[4] = (u8)(address >> 16); /* PCI Config Address */ -- msg.tx_buf[5] = (u8)(address >> 24); /* MSB - PCI Config Address */ -+ msg->tx_buf[2] = (u8)address; /* LSB - PCI Config Address */ -+ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Config Address */ -+ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Config Address */ -+ msg->tx_buf[5] = (u8)(address >> 24); /* MSB - PCI Config Address */ -+ -+ ret = peci_xfer_with_retries(adapter, msg, false); -+ if (!ret) -+ memcpy(umsg->pci_config, &msg->rx_buf[1], 4); - -- rc = peci_xfer_with_retries(adapter, &msg, false); -- if (!rc) -- memcpy(umsg->pci_config, &msg.rx_buf[1], 4); -+ umsg->cc = msg->rx_buf[0]; -+ peci_put_xfer_msg(msg); - -- return rc; -+ return ret; - } - --static int peci_ioctl_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_wr_pci_cfg(struct peci_adapter *adapter, void *vmsg) -+{ -+ return -ENOSYS; /* Not implemented yet */ -+} -+ -+static int peci_cmd_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) - { - struct peci_rd_pci_cfg_local_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -+ struct peci_xfer_msg *msg; - u32 address; -- int rc = 0; -+ int ret; - - /* Per the PECI spec, the read length must be a byte, word, or dword */ - if (umsg->rx_len != 1 && umsg->rx_len != 2 && umsg->rx_len != 4) { -@@ -453,34 +607,42 @@ static int peci_ioctl_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) - return -EINVAL; - } - -+ msg = peci_get_xfer_msg(PECI_RDPCICFGLOCAL_WRITE_LEN, -+ PECI_RDPCICFGLOCAL_READ_LEN_BASE + -+ umsg->rx_len); -+ if (!msg) -+ return -ENOMEM; -+ - address = umsg->reg; /* [11:0] - Register */ - address |= (u32)umsg->function << 12; /* [14:12] - Function */ - address |= (u32)umsg->device << 15; /* [19:15] - Device */ - address |= (u32)umsg->bus << 20; /* [23:20] - Bus */ - -- msg.addr = umsg->addr; -- msg.tx_len = RDPCICFGLOCAL_WRITE_LEN; -- msg.rx_len = RDPCICFGLOCAL_READ_LEN_BASE + umsg->rx_len; -- msg.tx_buf[0] = RDPCICFGLOCAL_PECI_CMD; -- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ -- /* Host ID is 0 for PECI 3.0 */ -- msg.tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */ -- msg.tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */ -- msg.tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */ -+ msg->addr = umsg->addr; -+ msg->tx_buf[0] = PECI_RDPCICFGLOCAL_CMD; -+ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ -+ /* Host ID is 0 for PECI 3.0 */ -+ msg->tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */ -+ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */ -+ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */ -+ -+ ret = peci_xfer_with_retries(adapter, msg, false); -+ if (!ret) -+ memcpy(umsg->pci_config, &msg->rx_buf[1], umsg->rx_len); - -- rc = peci_xfer_with_retries(adapter, &msg, false); -- if (!rc) -- memcpy(umsg->pci_config, &msg.rx_buf[1], umsg->rx_len); -+ umsg->cc = msg->rx_buf[0]; -+ peci_put_xfer_msg(msg); - -- return rc; -+ return ret; - } - --static int peci_ioctl_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) -+static int peci_cmd_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) - { - struct peci_wr_pci_cfg_local_msg *umsg = vmsg; -- struct peci_xfer_msg msg; -- int rc = 0, i; -+ struct peci_xfer_msg *msg; - u32 address; -+ int ret, i; -+ u8 aw_fcs; - - /* Per the PECI spec, the write length must be a byte, word, or dword */ - if (umsg->tx_len != 1 && umsg->tx_len != 2 && umsg->tx_len != 4) { -@@ -489,47 +651,57 @@ static int peci_ioctl_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) - return -EINVAL; - } - -+ msg = peci_get_xfer_msg(PECI_WRPCICFGLOCAL_WRITE_LEN_BASE + -+ umsg->tx_len, PECI_WRPCICFGLOCAL_READ_LEN); -+ if (!msg) -+ return -ENOMEM; -+ - address = umsg->reg; /* [11:0] - Register */ - address |= (u32)umsg->function << 12; /* [14:12] - Function */ - address |= (u32)umsg->device << 15; /* [19:15] - Device */ - address |= (u32)umsg->bus << 20; /* [23:20] - Bus */ - -- msg.addr = umsg->addr; -- msg.tx_len = WRPCICFGLOCAL_WRITE_LEN_BASE + umsg->tx_len; -- msg.rx_len = WRPCICFGLOCAL_READ_LEN; -- msg.tx_buf[0] = WRPCICFGLOCAL_PECI_CMD; -- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ -- /* Host ID is 0 for PECI 3.0 */ -- msg.tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */ -- msg.tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */ -- msg.tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */ -+ msg->addr = umsg->addr; -+ msg->tx_buf[0] = PECI_WRPCICFGLOCAL_CMD; -+ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ -+ /* Host ID is 0 for PECI 3.0 */ -+ msg->tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */ -+ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */ -+ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */ - for (i = 0; i < umsg->tx_len; i++) -- msg.tx_buf[5 + i] = (u8)(umsg->value >> (i << 3)); -+ msg->tx_buf[5 + i] = (u8)(umsg->value >> (i << 3)); -+ -+ /* Add an Assured Write Frame Check Sequence byte */ -+ ret = peci_aw_fcs(msg, 8 + umsg->tx_len, &aw_fcs); -+ if (ret) -+ goto out; -+ -+ msg->tx_buf[5 + i] = 0x80 ^ aw_fcs; - -- /* Add an Assure Write Frame Check Sequence byte */ -- msg.tx_buf[5 + i] = 0x80 ^ -- peci_aw_fcs((u8 *)&msg, 8 + umsg->tx_len); -+ ret = peci_xfer_with_retries(adapter, msg, true); - -- rc = peci_xfer_with_retries(adapter, &msg, true); -+out: -+ umsg->cc = msg->rx_buf[0]; -+ peci_put_xfer_msg(msg); - -- return rc; -+ return ret; - } - --typedef int (*peci_ioctl_fn_type)(struct peci_adapter *, void *); -- --static const peci_ioctl_fn_type peci_ioctl_fn[PECI_CMD_MAX] = { -- peci_ioctl_xfer, -- peci_ioctl_ping, -- peci_ioctl_get_dib, -- peci_ioctl_get_temp, -- peci_ioctl_rd_pkg_cfg, -- peci_ioctl_wr_pkg_cfg, -- peci_ioctl_rd_ia_msr, -- NULL, /* Reserved */ -- peci_ioctl_rd_pci_cfg, -- NULL, /* Reserved */ -- peci_ioctl_rd_pci_cfg_local, -- peci_ioctl_wr_pci_cfg_local, -+typedef int (*peci_cmd_fn_type)(struct peci_adapter *, void *); -+ -+static const peci_cmd_fn_type peci_cmd_fn[PECI_CMD_MAX] = { -+ peci_cmd_xfer, -+ peci_cmd_ping, -+ peci_cmd_get_dib, -+ peci_cmd_get_temp, -+ peci_cmd_rd_pkg_cfg, -+ peci_cmd_wr_pkg_cfg, -+ peci_cmd_rd_ia_msr, -+ peci_cmd_wr_ia_msr, -+ peci_cmd_rd_pci_cfg, -+ peci_cmd_wr_pci_cfg, -+ peci_cmd_rd_pci_cfg_local, -+ peci_cmd_wr_pci_cfg_local, - }; - - /** -@@ -545,109 +717,28 @@ static const peci_ioctl_fn_type peci_ioctl_fn[PECI_CMD_MAX] = { - */ - int peci_command(struct peci_adapter *adapter, enum peci_cmd cmd, void *vmsg) - { -- int rc = 0; -+ int ret; - - if (cmd >= PECI_CMD_MAX || cmd < PECI_CMD_XFER) -- return -EINVAL; -+ return -ENOTTY; - - dev_dbg(&adapter->dev, "%s, cmd=0x%02x\n", __func__, cmd); - -- if (!peci_ioctl_fn[cmd]) -+ if (!peci_cmd_fn[cmd]) - return -EINVAL; - -- rt_mutex_lock(&adapter->bus_lock); -+ mutex_lock(&adapter->bus_lock); - -- rc = peci_cmd_support(adapter, cmd); -- if (!rc) -- rc = peci_ioctl_fn[cmd](adapter, vmsg); -+ ret = peci_check_cmd_support(adapter, cmd); -+ if (!ret) -+ ret = peci_cmd_fn[cmd](adapter, vmsg); - -- rt_mutex_unlock(&adapter->bus_lock); -+ mutex_unlock(&adapter->bus_lock); - -- return rc; -+ return ret; - } - EXPORT_SYMBOL_GPL(peci_command); - --static long peci_ioctl(struct file *file, unsigned int iocmd, unsigned long arg) --{ -- struct peci_adapter *adapter = file->private_data; -- void __user *argp = (void __user *)arg; -- unsigned int msg_len; -- enum peci_cmd cmd; -- int rc = 0; -- u8 *msg; -- -- if (!capable(CAP_SYS_ADMIN)) -- return -EPERM; -- -- dev_dbg(&adapter->dev, "ioctl, cmd=0x%x, arg=0x%lx\n", iocmd, arg); -- -- switch (iocmd) { -- case PECI_IOC_XFER: -- case PECI_IOC_PING: -- case PECI_IOC_GET_DIB: -- case PECI_IOC_GET_TEMP: -- case PECI_IOC_RD_PKG_CFG: -- case PECI_IOC_WR_PKG_CFG: -- case PECI_IOC_RD_IA_MSR: -- case PECI_IOC_RD_PCI_CFG: -- case PECI_IOC_RD_PCI_CFG_LOCAL: -- case PECI_IOC_WR_PCI_CFG_LOCAL: -- cmd = _IOC_NR(iocmd); -- msg_len = _IOC_SIZE(iocmd); -- break; -- -- default: -- dev_dbg(&adapter->dev, "Invalid ioctl cmd : 0x%x\n", iocmd); -- return -ENOTTY; -- } -- -- if (!access_ok(argp, msg_len)) -- return -EFAULT; -- -- msg = memdup_user(argp, msg_len); -- if (IS_ERR(msg)) -- return PTR_ERR(msg); -- -- rc = peci_command(adapter, cmd, msg); -- -- if (!rc && copy_to_user(argp, msg, msg_len)) -- rc = -EFAULT; -- -- kfree(msg); -- return (long)rc; --} -- --static int peci_open(struct inode *inode, struct file *file) --{ -- unsigned int minor = iminor(inode); -- struct peci_adapter *adapter; -- -- adapter = peci_get_adapter(minor); -- if (!adapter) -- return -ENODEV; -- -- file->private_data = adapter; -- -- return 0; --} -- --static int peci_release(struct inode *inode, struct file *file) --{ -- struct peci_adapter *adapter = file->private_data; -- -- peci_put_adapter(adapter); -- file->private_data = NULL; -- -- return 0; --} -- --static const struct file_operations peci_fops = { -- .owner = THIS_MODULE, -- .unlocked_ioctl = peci_ioctl, -- .open = peci_open, -- .release = peci_release, --}; -- - static int peci_detect(struct peci_adapter *adapter, u8 addr) - { - struct peci_ping_msg msg; -@@ -666,9 +757,9 @@ peci_of_match_device(const struct of_device_id *matches, - return NULL; - - return of_match_device(matches, &client->dev); --#else -+#else /* CONFIG_OF */ - return NULL; --#endif -+#endif /* CONFIG_OF */ - } - - static const struct peci_device_id * -@@ -737,6 +828,7 @@ static int peci_device_probe(struct device *dev) - - err_detach_pm_domain: - dev_pm_domain_detach(&client->dev, true); -+ - return status; - } - -@@ -775,13 +867,14 @@ static void peci_device_shutdown(struct device *dev) - driver->shutdown(client); - } - --static struct bus_type peci_bus_type = { -+struct bus_type peci_bus_type = { - .name = "peci", - .match = peci_device_match, - .probe = peci_device_probe, - .remove = peci_device_remove, - .shutdown = peci_device_shutdown, - }; -+EXPORT_SYMBOL_GPL(peci_bus_type); - - static int peci_check_addr_validity(u8 addr) - { -@@ -814,18 +907,22 @@ static int peci_check_client_busy(struct device *dev, void *client_new_p) - int peci_get_cpu_id(struct peci_adapter *adapter, u8 addr, u32 *cpu_id) - { - struct peci_rd_pkg_cfg_msg msg; -- int rc; -+ int ret; - - msg.addr = addr; -- msg.index = MBX_INDEX_CPU_ID; -- msg.param = PKG_ID_CPU_ID; -+ msg.index = PECI_MBX_INDEX_CPU_ID; -+ msg.param = PECI_PKG_ID_CPU_ID; - msg.rx_len = 4; - -- rc = peci_command(adapter, PECI_CMD_RD_PKG_CFG, &msg); -- if (!rc) -- *cpu_id = le32_to_cpup((__le32 *)msg.pkg_config); -+ ret = peci_command(adapter, PECI_CMD_RD_PKG_CFG, &msg); -+ if (msg.cc != PECI_DEV_CC_SUCCESS) -+ ret = -EAGAIN; -+ if (ret) -+ return ret; -+ -+ *cpu_id = le32_to_cpup((__le32 *)msg.pkg_config); - -- return rc; -+ return 0; - } - EXPORT_SYMBOL_GPL(peci_get_cpu_id); - -@@ -833,7 +930,7 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter, - struct peci_board_info const *info) - { - struct peci_client *client; -- int rc; -+ int ret; - - /* Increase reference count for the adapter assigned */ - if (!peci_get_adapter(adapter->nr)) -@@ -847,46 +944,49 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter, - client->addr = info->addr; - strlcpy(client->name, info->type, sizeof(client->name)); - -- rc = peci_check_addr_validity(client->addr); -- if (rc) { -+ ret = peci_check_addr_validity(client->addr); -+ if (ret) { - dev_err(&adapter->dev, "Invalid PECI CPU address 0x%02hx\n", - client->addr); - goto err_free_client_silent; - } - - /* Check online status of client */ -- rc = peci_detect(adapter, client->addr); -- if (rc) -+ ret = peci_detect(adapter, client->addr); -+ if (ret) - goto err_free_client; - -- rc = device_for_each_child(&adapter->dev, client, -- peci_check_client_busy); -- if (rc) -+ ret = device_for_each_child(&adapter->dev, client, -+ peci_check_client_busy); -+ if (ret) - goto err_free_client; - - client->dev.parent = &client->adapter->dev; - client->dev.bus = &peci_bus_type; - client->dev.type = &peci_client_type; -- client->dev.of_node = info->of_node; -+ client->dev.of_node = of_node_get(info->of_node); - dev_set_name(&client->dev, "%d-%02x", adapter->nr, client->addr); - -- rc = device_register(&client->dev); -- if (rc) -- goto err_free_client; -+ ret = device_register(&client->dev); -+ if (ret) -+ goto err_put_of_node; - - dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", - client->name, dev_name(&client->dev)); - - return client; - -+err_put_of_node: -+ of_node_put(info->of_node); - err_free_client: - dev_err(&adapter->dev, - "Failed to register peci client %s at 0x%02x (%d)\n", -- client->name, client->addr, rc); -+ client->name, client->addr, ret); - err_free_client_silent: - kfree(client); - err_put_adapter: - peci_put_adapter(adapter); -+ - return NULL; - } - -@@ -895,8 +995,10 @@ static void peci_unregister_device(struct peci_client *client) - if (!client) - return; - -- if (client->dev.of_node) -+ if (client->dev.of_node) { - of_node_clear_flag(client->dev.of_node, OF_POPULATED); -+ of_node_put(client->dev.of_node); -+ } - - device_unregister(&client->dev); - } -@@ -916,7 +1018,7 @@ static void peci_adapter_dev_release(struct device *dev) - - dev_dbg(dev, "%s: %s\n", __func__, adapter->name); - mutex_destroy(&adapter->userspace_clients_lock); -- rt_mutex_destroy(&adapter->bus_lock); -+ mutex_destroy(&adapter->bus_lock); - kfree(adapter); - } - -@@ -928,7 +1030,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev, - struct peci_board_info info = {}; - struct peci_client *client; - char *blank, end; -- int rc; -+ short addr; -+ int ret; - - /* Parse device type */ - blank = strchr(buf, ' '); -@@ -943,16 +1046,17 @@ static ssize_t peci_sysfs_new_device(struct device *dev, - memcpy(info.type, buf, blank - buf); - - /* Parse remaining parameters, reject extra parameters */ -- rc = sscanf(++blank, "%hi%c", &info.addr, &end); -- if (rc < 1) { -+ ret = sscanf(++blank, "%hi%c", &addr, &end); -+ if (ret < 1) { - dev_err(dev, "%s: Can't parse client address\n", "new_device"); - return -EINVAL; - } -- if (rc > 1 && end != '\n') { -+ if (ret > 1 && end != '\n') { - dev_err(dev, "%s: Extra parameters\n", "new_device"); - return -EINVAL; - } - -+ info.addr = (u8)addr; - client = peci_new_device(adapter, &info); - if (!client) - return -EINVAL; -@@ -961,8 +1065,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev, - mutex_lock(&adapter->userspace_clients_lock); - list_add_tail(&client->detected, &adapter->userspace_clients); - mutex_unlock(&adapter->userspace_clients_lock); -- dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device", -- info.type, info.addr); -+ dev_dbg(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device", -+ info.type, info.addr); - - return count; - } -@@ -975,9 +1079,9 @@ static ssize_t peci_sysfs_delete_device(struct device *dev, - struct peci_adapter *adapter = to_peci_adapter(dev); - struct peci_client *client, *next; - struct peci_board_info info = {}; -- struct peci_driver *driver; - char *blank, end; -- int rc; -+ short addr; -+ int ret; - - /* Parse device type */ - blank = strchr(buf, ' '); -@@ -992,41 +1096,41 @@ static ssize_t peci_sysfs_delete_device(struct device *dev, - memcpy(info.type, buf, blank - buf); - - /* Parse remaining parameters, reject extra parameters */ -- rc = sscanf(++blank, "%hi%c", &info.addr, &end); -- if (rc < 1) { -+ ret = sscanf(++blank, "%hi%c", &addr, &end); -+ if (ret < 1) { - dev_err(dev, "%s: Can't parse client address\n", - "delete_device"); - return -EINVAL; - } -- if (rc > 1 && end != '\n') { -+ if (ret > 1 && end != '\n') { - dev_err(dev, "%s: Extra parameters\n", "delete_device"); - return -EINVAL; - } - -+ info.addr = (u8)addr; -+ - /* Make sure the device was added through sysfs */ -- rc = -ENOENT; -+ ret = -ENOENT; - mutex_lock(&adapter->userspace_clients_lock); - list_for_each_entry_safe(client, next, &adapter->userspace_clients, - detected) { -- driver = to_peci_driver(client->dev.driver); -- - if (client->addr == info.addr && - !strncmp(client->name, info.type, PECI_NAME_SIZE)) { -- dev_info(dev, "%s: Deleting device %s at 0x%02hx\n", -- "delete_device", client->name, client->addr); -+ dev_dbg(dev, "%s: Deleting device %s at 0x%02hx\n", -+ "delete_device", client->name, client->addr); - list_del(&client->detected); - peci_unregister_device(client); -- rc = count; -+ ret = count; - break; - } - } - mutex_unlock(&adapter->userspace_clients_lock); - -- if (rc < 0) -- dev_err(dev, "%s: Can't find device in list\n", -+ if (ret < 0) -+ dev_dbg(dev, "%s: Can't find device in list\n", - "delete_device"); - -- return rc; -+ return ret; - } - static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, 0200, NULL, - peci_sysfs_delete_device); -@@ -1039,10 +1143,11 @@ static struct attribute *peci_adapter_attrs[] = { - }; - ATTRIBUTE_GROUPS(peci_adapter); - --static struct device_type peci_adapter_type = { -+struct device_type peci_adapter_type = { - .groups = peci_adapter_groups, - .release = peci_adapter_dev_release, - }; -+EXPORT_SYMBOL_GPL(peci_adapter_type); - - /** - * peci_verify_adapter - return parameter as peci_adapter, or NULL -@@ -1063,32 +1168,26 @@ static struct peci_client *peci_of_register_device(struct peci_adapter *adapter, - struct device_node *node) - { - struct peci_board_info info = {}; -- struct peci_client *result; -- const __be32 *addr_be; -- int len; -+ struct peci_client *client; -+ u32 addr; -+ int ret; - - dev_dbg(&adapter->dev, "register %pOF\n", node); - -- if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { -- dev_err(&adapter->dev, "modalias failure on %pOF\n", node); -- return ERR_PTR(-EINVAL); -- } -- -- addr_be = of_get_property(node, "reg", &len); -- if (!addr_be || len < sizeof(*addr_be)) { -+ ret = of_property_read_u32(node, "reg", &addr); -+ if (ret) { - dev_err(&adapter->dev, "invalid reg on %pOF\n", node); -- return ERR_PTR(-EINVAL); -+ return ERR_PTR(ret); - } - -- info.addr = be32_to_cpup(addr_be); -- info.of_node = of_node_get(node); -+ info.addr = addr; -+ info.of_node = node; - -- result = peci_new_device(adapter, &info); -- if (!result) -- result = ERR_PTR(-EINVAL); -+ client = peci_new_device(adapter, &info); -+ if (!client) -+ client = ERR_PTR(-EINVAL); - -- of_node_put(node); -- return result; -+ return client; - } - - static void peci_of_register_devices(struct peci_adapter *adapter) -@@ -1119,7 +1218,7 @@ static void peci_of_register_devices(struct peci_adapter *adapter) - - of_node_put(bus); - } --#else -+#else /* CONFIG_OF */ - static void peci_of_register_devices(struct peci_adapter *adapter) { } - #endif /* CONFIG_OF */ - -@@ -1163,9 +1262,7 @@ static struct peci_adapter *peci_of_find_adapter(struct device_node *node) - return adapter; - } - --static int peci_of_notify(struct notifier_block *nb, -- unsigned long action, -- void *arg) -+static int peci_of_notify(struct notifier_block *nb, ulong action, void *arg) - { - struct of_reconfig_data *rd = arg; - struct peci_adapter *adapter; -@@ -1216,7 +1313,7 @@ static int peci_of_notify(struct notifier_block *nb, - static struct notifier_block peci_of_notifier = { - .notifier_call = peci_of_notify, - }; --#else -+#else /* CONFIG_OF_DYNAMIC */ - extern struct notifier_block peci_of_notifier; - #endif /* CONFIG_OF_DYNAMIC */ - -@@ -1240,7 +1337,7 @@ extern struct notifier_block peci_of_notifier; - * - * Return: the peci_adapter structure on success, else NULL. - */ --struct peci_adapter *peci_alloc_adapter(struct device *dev, unsigned int size) -+struct peci_adapter *peci_alloc_adapter(struct device *dev, uint size) - { - struct peci_adapter *adapter; - -@@ -1263,7 +1360,7 @@ EXPORT_SYMBOL_GPL(peci_alloc_adapter); - - static int peci_register_adapter(struct peci_adapter *adapter) - { -- int rc = -EINVAL; -+ int ret = -EINVAL; - - /* Can't register until after driver model init */ - if (WARN_ON(!is_registered)) -@@ -1275,27 +1372,17 @@ static int peci_register_adapter(struct peci_adapter *adapter) - if (WARN(!adapter->xfer, "peci adapter has no xfer function\n")) - goto err_free_idr; - -- rt_mutex_init(&adapter->bus_lock); -+ mutex_init(&adapter->bus_lock); - mutex_init(&adapter->userspace_clients_lock); - INIT_LIST_HEAD(&adapter->userspace_clients); - - dev_set_name(&adapter->dev, "peci-%d", adapter->nr); - -- /* cdev */ -- cdev_init(&adapter->cdev, &peci_fops); -- adapter->cdev.owner = THIS_MODULE; -- adapter->dev.devt = MKDEV(MAJOR(peci_devt), adapter->nr); -- rc = cdev_add(&adapter->cdev, adapter->dev.devt, 1); -- if (rc) { -- pr_err("adapter '%s': can't add cdev (%d)\n", -- adapter->name, rc); -- goto err_free_idr; -- } -- rc = device_add(&adapter->dev); -- if (rc) { -+ ret = device_add(&adapter->dev); -+ if (ret) { - pr_err("adapter '%s': can't add device (%d)\n", -- adapter->name, rc); -- goto err_del_cdev; -+ adapter->name, ret); -+ goto err_free_idr; - } - - dev_dbg(&adapter->dev, "adapter [%s] registered\n", adapter->name); -@@ -1309,13 +1396,11 @@ static int peci_register_adapter(struct peci_adapter *adapter) - - return 0; - --err_del_cdev: -- cdev_del(&adapter->cdev); - err_free_idr: - mutex_lock(&core_lock); - idr_remove(&peci_adapter_idr, adapter->nr); - mutex_unlock(&core_lock); -- return rc; -+ return ret; - } - - static int peci_add_numbered_adapter(struct peci_adapter *adapter) -@@ -1354,12 +1439,10 @@ int peci_add_adapter(struct peci_adapter *adapter) - struct device *dev = &adapter->dev; - int id; - -- if (dev->of_node) { -- id = of_alias_get_id(dev->of_node, "peci"); -- if (id >= 0) { -- adapter->nr = id; -- return peci_add_numbered_adapter(adapter); -- } -+ id = of_alias_get_id(dev->of_node, "peci"); -+ if (id >= 0) { -+ adapter->nr = id; -+ return peci_add_numbered_adapter(adapter); - } - - mutex_lock(&core_lock); -@@ -1411,7 +1494,7 @@ void peci_del_adapter(struct peci_adapter *adapter) - } - mutex_unlock(&adapter->userspace_clients_lock); - -- /** -+ /* - * Detach any active clients. This can't fail, thus we do not - * check the returned value. - */ -@@ -1420,13 +1503,8 @@ void peci_del_adapter(struct peci_adapter *adapter) - /* device name is gone after device_unregister */ - dev_dbg(&adapter->dev, "adapter [%s] unregistered\n", adapter->name); - -- /* free cdev */ -- cdev_del(&adapter->cdev); -- - pm_runtime_disable(&adapter->dev); -- - nr = adapter->nr; -- - device_unregister(&adapter->dev); - - /* free bus id */ -@@ -1436,6 +1514,18 @@ void peci_del_adapter(struct peci_adapter *adapter) - } - EXPORT_SYMBOL_GPL(peci_del_adapter); - -+int peci_for_each_dev(void *data, int (*fn)(struct device *, void *)) -+{ -+ int ret; -+ -+ mutex_lock(&core_lock); -+ ret = bus_for_each_dev(&peci_bus_type, NULL, data, fn); -+ mutex_unlock(&core_lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(peci_for_each_dev); -+ - /** - * peci_register_driver - register a PECI driver - * @owner: owner module of the driver being registered -@@ -1446,7 +1536,7 @@ EXPORT_SYMBOL_GPL(peci_del_adapter); - */ - int peci_register_driver(struct module *owner, struct peci_driver *driver) - { -- int rc; -+ int ret; - - /* Can't register until after driver model init */ - if (WARN_ON(!is_registered)) -@@ -1456,13 +1546,13 @@ int peci_register_driver(struct module *owner, struct peci_driver *driver) - driver->driver.owner = owner; - driver->driver.bus = &peci_bus_type; - -- /** -+ /* - * When registration returns, the driver core - * will have called probe() for all matching-but-unbound devices. - */ -- rc = driver_register(&driver->driver); -- if (rc) -- return rc; -+ ret = driver_register(&driver->driver); -+ if (ret) -+ return ret; - - pr_debug("driver [%s] registered\n", driver->driver.name); - -@@ -1492,13 +1582,6 @@ static int __init peci_init(void) - return ret; - } - -- ret = alloc_chrdev_region(&peci_devt, 0, PECI_CDEV_MAX, "peci"); -- if (ret < 0) { -- pr_err("peci: Failed to allocate chr dev region!\n"); -- bus_unregister(&peci_bus_type); -- return ret; -- } -- - crc8_populate_msb(peci_crc8_table, PECI_CRC8_POLYNOMIAL); - - if (IS_ENABLED(CONFIG_OF_DYNAMIC)) -@@ -1514,11 +1597,10 @@ static void __exit peci_exit(void) - if (IS_ENABLED(CONFIG_OF_DYNAMIC)) - WARN_ON(of_reconfig_notifier_unregister(&peci_of_notifier)); - -- unregister_chrdev_region(peci_devt, PECI_CDEV_MAX); - bus_unregister(&peci_bus_type); - } - --postcore_initcall(peci_init); -+subsys_initcall(peci_init); - module_exit(peci_exit); - - MODULE_AUTHOR("Jason M Biils "); -diff --git a/drivers/peci/peci-dev.c b/drivers/peci/peci-dev.c -new file mode 100644 -index 000000000000..ac9cba0fb429 ---- /dev/null -+++ b/drivers/peci/peci-dev.c -@@ -0,0 +1,346 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Copyright (c) 2018-2019 Intel Corporation -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * A peci_dev represents an peci_adapter ... an PECI or SMBus master, not a -+ * slave (peci_client) with which messages will be exchanged. It's coupled -+ * with a character special file which is accessed by user mode drivers. -+ * -+ * The list of peci_dev structures is parallel to the peci_adapter lists -+ * maintained by the driver model, and is updated using bus notifications. -+ */ -+struct peci_dev { -+ struct list_head list; -+ struct peci_adapter *adapter; -+ struct device *dev; -+ struct cdev cdev; -+}; -+ -+#define PECI_MINORS MINORMASK -+ -+static dev_t peci_devt; -+static LIST_HEAD(peci_dev_list); -+static DEFINE_SPINLOCK(peci_dev_list_lock); -+ -+static struct peci_dev *peci_dev_get_by_minor(uint index) -+{ -+ struct peci_dev *peci_dev; -+ -+ spin_lock(&peci_dev_list_lock); -+ list_for_each_entry(peci_dev, &peci_dev_list, list) { -+ if (peci_dev->adapter->nr == index) -+ goto found; -+ } -+ peci_dev = NULL; -+found: -+ spin_unlock(&peci_dev_list_lock); -+ -+ return peci_dev; -+} -+ -+static struct peci_dev *peci_dev_alloc(struct peci_adapter *adapter) -+{ -+ struct peci_dev *peci_dev; -+ -+ if (adapter->nr >= PECI_MINORS) { -+ printk(KERN_ERR "peci-dev: Out of device minors (%d)\n", -+ adapter->nr); -+ return ERR_PTR(-ENODEV); -+ } -+ -+ peci_dev = kzalloc(sizeof(*peci_dev), GFP_KERNEL); -+ if (!peci_dev) -+ return ERR_PTR(-ENOMEM); -+ peci_dev->adapter = adapter; -+ -+ spin_lock(&peci_dev_list_lock); -+ list_add_tail(&peci_dev->list, &peci_dev_list); -+ spin_unlock(&peci_dev_list_lock); -+ -+ return peci_dev; -+} -+ -+static void peci_dev_put(struct peci_dev *peci_dev) -+{ -+ spin_lock(&peci_dev_list_lock); -+ list_del(&peci_dev->list); -+ spin_unlock(&peci_dev_list_lock); -+ kfree(peci_dev); -+} -+ -+static ssize_t name_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct peci_dev *peci_dev = peci_dev_get_by_minor(MINOR(dev->devt)); -+ -+ if (!peci_dev) -+ return -ENODEV; -+ -+ return sprintf(buf, "%s\n", peci_dev->adapter->name); -+} -+static DEVICE_ATTR_RO(name); -+ -+static struct attribute *peci_dev_attrs[] = { -+ &dev_attr_name.attr, -+ NULL, -+}; -+ATTRIBUTE_GROUPS(peci_dev); -+ -+static long peci_dev_ioctl(struct file *file, uint iocmd, ulong arg) -+{ -+ struct peci_dev *peci_dev = file->private_data; -+ void __user *umsg = (void __user *)arg; -+ struct peci_xfer_msg *xmsg = NULL; -+ struct peci_xfer_msg uxmsg; -+ enum peci_cmd cmd; -+ u8 *msg = NULL; -+ uint msg_len; -+ int ret; -+ -+ cmd = _IOC_NR(iocmd); -+ msg_len = _IOC_SIZE(iocmd); -+ -+ switch (cmd) { -+ case PECI_CMD_XFER: -+ if (msg_len != sizeof(struct peci_xfer_msg)) { -+ ret = -EFAULT; -+ break; -+ } -+ -+ if (copy_from_user(&uxmsg, umsg, msg_len)) { -+ ret = -EFAULT; -+ break; -+ } -+ -+ xmsg = peci_get_xfer_msg(uxmsg.tx_len, uxmsg.rx_len); -+ if (IS_ERR(xmsg)) { -+ ret = PTR_ERR(xmsg); -+ break; -+ } -+ -+ if (uxmsg.tx_len && -+ copy_from_user(xmsg->tx_buf, uxmsg.tx_buf, uxmsg.tx_len)) { -+ ret = -EFAULT; -+ break; -+ } -+ -+ xmsg->addr = uxmsg.addr; -+ xmsg->tx_len = uxmsg.tx_len; -+ xmsg->rx_len = uxmsg.rx_len; -+ -+ ret = peci_command(peci_dev->adapter, cmd, xmsg); -+ if (!ret && xmsg->rx_len && -+ copy_to_user(uxmsg.rx_buf, xmsg->rx_buf, xmsg->rx_len)) -+ ret = -EFAULT; -+ -+ break; -+ -+ default: -+ msg = memdup_user(umsg, msg_len); -+ if (IS_ERR(msg)) { -+ ret = PTR_ERR(msg); -+ break; -+ } -+ -+ ret = peci_command(peci_dev->adapter, cmd, msg); -+ if ((!ret || ret == -ETIMEDOUT) && -+ copy_to_user(umsg, msg, msg_len)) -+ ret = -EFAULT; -+ -+ break; -+ } -+ -+ peci_put_xfer_msg(xmsg); -+ kfree(msg); -+ -+ return (long)ret; -+} -+ -+static int peci_dev_open(struct inode *inode, struct file *file) -+{ -+ struct peci_adapter *adapter; -+ struct peci_dev *peci_dev; -+ -+ peci_dev = peci_dev_get_by_minor(iminor(inode)); -+ if (!peci_dev) -+ return -ENODEV; -+ -+ adapter = peci_get_adapter(peci_dev->adapter->nr); -+ if (!adapter) -+ return -ENODEV; -+ -+ file->private_data = peci_dev; -+ -+ return 0; -+} -+ -+static int peci_dev_release(struct inode *inode, struct file *file) -+{ -+ struct peci_dev *peci_dev = file->private_data; -+ -+ peci_put_adapter(peci_dev->adapter); -+ file->private_data = NULL; -+ -+ return 0; -+} -+ -+static const struct file_operations peci_dev_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = peci_dev_ioctl, -+ .open = peci_dev_open, -+ .release = peci_dev_release, -+ .llseek = no_llseek, -+}; -+ -+static struct class *peci_dev_class; -+ -+static int peci_dev_attach_adapter(struct device *dev, void *dummy) -+{ -+ struct peci_adapter *adapter; -+ struct peci_dev *peci_dev; -+ dev_t devt; -+ int ret; -+ -+ if (dev->type != &peci_adapter_type) -+ return 0; -+ -+ adapter = to_peci_adapter(dev); -+ peci_dev = peci_dev_alloc(adapter); -+ if (IS_ERR(peci_dev)) -+ return PTR_ERR(peci_dev); -+ -+ cdev_init(&peci_dev->cdev, &peci_dev_fops); -+ peci_dev->cdev.owner = THIS_MODULE; -+ devt = MKDEV(MAJOR(peci_devt), adapter->nr); -+ -+ ret = cdev_add(&peci_dev->cdev, devt, 1); -+ if (ret) -+ goto err_put_dev; -+ -+ /* register this peci device with the driver core */ -+ peci_dev->dev = device_create(peci_dev_class, &adapter->dev, devt, NULL, -+ "peci-%d", adapter->nr); -+ if (IS_ERR(peci_dev->dev)) { -+ ret = PTR_ERR(peci_dev->dev); -+ goto err_del_cdev; -+ } -+ -+ pr_info("peci-dev: adapter [%s] registered as minor %d\n", -+ adapter->name, adapter->nr); -+ -+ return 0; -+ -+err_del_cdev: -+ cdev_del(&peci_dev->cdev); -+err_put_dev: -+ peci_dev_put(peci_dev); -+ -+ return ret; -+} -+ -+static int peci_dev_detach_adapter(struct device *dev, void *dummy) -+{ -+ struct peci_adapter *adapter; -+ struct peci_dev *peci_dev; -+ dev_t devt; -+ -+ if (dev->type != &peci_adapter_type) -+ return 0; -+ -+ adapter = to_peci_adapter(dev); -+ peci_dev = peci_dev_get_by_minor(adapter->nr); -+ if (!peci_dev) -+ return 0; -+ -+ cdev_del(&peci_dev->cdev); -+ devt = peci_dev->dev->devt; -+ peci_dev_put(peci_dev); -+ device_destroy(peci_dev_class, devt); -+ -+ pr_info("peci-dev: adapter [%s] unregistered\n", adapter->name); -+ -+ return 0; -+} -+ -+static int peci_dev_notifier_call(struct notifier_block *nb, ulong action, -+ void *data) -+{ -+ struct device *dev = data; -+ -+ switch (action) { -+ case BUS_NOTIFY_ADD_DEVICE: -+ return peci_dev_attach_adapter(dev, NULL); -+ case BUS_NOTIFY_DEL_DEVICE: -+ return peci_dev_detach_adapter(dev, NULL); -+ } -+ -+ return 0; -+} -+ -+static struct notifier_block peci_dev_notifier = { -+ .notifier_call = peci_dev_notifier_call, -+}; -+ -+static int __init peci_dev_init(void) -+{ -+ int ret; -+ -+ printk(KERN_INFO "peci /dev entries driver\n"); -+ -+ ret = alloc_chrdev_region(&peci_devt, 0, PECI_MINORS, "peci"); -+ if (ret < 0) { -+ pr_err("peci: Failed to allocate chr dev region!\n"); -+ bus_unregister(&peci_bus_type); -+ goto err; -+ } -+ -+ peci_dev_class = class_create(THIS_MODULE, "peci-dev"); -+ if (IS_ERR(peci_dev_class)) { -+ ret = PTR_ERR(peci_dev_class); -+ goto err_unreg_chrdev; -+ } -+ peci_dev_class->dev_groups = peci_dev_groups; -+ -+ /* Keep track of adapters which will be added or removed later */ -+ ret = bus_register_notifier(&peci_bus_type, &peci_dev_notifier); -+ if (ret) -+ goto err_destroy_class; -+ -+ /* Bind to already existing adapters right away */ -+ peci_for_each_dev(NULL, peci_dev_attach_adapter); -+ -+ return 0; -+ -+err_destroy_class: -+ class_destroy(peci_dev_class); -+err_unreg_chrdev: -+ unregister_chrdev_region(peci_devt, PECI_MINORS); -+err: -+ printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__); -+ -+ return ret; -+} -+ -+static void __exit peci_dev_exit(void) -+{ -+ bus_unregister_notifier(&peci_bus_type, &peci_dev_notifier); -+ peci_for_each_dev(NULL, peci_dev_detach_adapter); -+ class_destroy(peci_dev_class); -+ unregister_chrdev_region(peci_devt, PECI_MINORS); -+} -+ -+module_init(peci_dev_init); -+module_exit(peci_dev_exit); -+ -+MODULE_AUTHOR("Jae Hyun Yoo "); -+MODULE_DESCRIPTION("PECI /dev entries driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/peci/peci-npcm.c b/drivers/peci/peci-npcm.c -deleted file mode 100644 -index f632365b1416..000000000000 ---- a/drivers/peci/peci-npcm.c -+++ /dev/null -@@ -1,410 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --// Copyright (c) 2019 Nuvoton Technology corporation. -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --/* NPCM7xx GCR module */ --#define NPCM7XX_INTCR3_OFFSET 0x9C --#define NPCM7XX_INTCR3_PECIVSEL BIT(19) -- --/* NPCM PECI Registers */ --#define NPCM_PECI_CTL_STS 0x00 --#define NPCM_PECI_RD_LENGTH 0x04 --#define NPCM_PECI_ADDR 0x08 --#define NPCM_PECI_CMD 0x0C --#define NPCM_PECI_CTL2 0x10 --#define NPCM_PECI_WR_LENGTH 0x1C --#define NPCM_PECI_PDDR 0x2C --#define NPCM_PECI_DAT_INOUT(n) (0x100 + ((n) * 4)) -- --#define NPCM_PECI_MAX_REG 0x200 -- --/* NPCM_PECI_CTL_STS - 0x00 : Control Register */ --#define NPCM_PECI_CTRL_DONE_INT_EN BIT(6) --#define NPCM_PECI_CTRL_ABRT_ERR BIT(4) --#define NPCM_PECI_CTRL_CRC_ERR BIT(3) --#define NPCM_PECI_CTRL_DONE BIT(1) --#define NPCM_PECI_CTRL_START_BUSY BIT(0) -- --/* NPCM_PECI_RD_LENGTH - 0x04 : Command Register */ --#define NPCM_PECI_RD_LEN_MASK GENMASK(6, 0) -- --/* NPCM_PECI_CMD - 0x10 : Command Register */ --#define NPCM_PECI_CTL2_MASK GENMASK(7, 6) -- --/* NPCM_PECI_WR_LENGTH - 0x1C : Command Register */ --#define NPCM_PECI_WR_LEN_MASK GENMASK(6, 0) -- --/* NPCM_PECI_PDDR - 0x2C : Command Register */ --#define NPCM_PECI_PDDR_MASK GENMASK(4, 0) -- --#define NPCM_PECI_INT_MASK (NPCM_PECI_CTRL_ABRT_ERR | \ -- NPCM_PECI_CTRL_CRC_ERR | \ -- NPCM_PECI_CTRL_DONE) -- --#define NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC 50000 --#define NPCM_PECI_IDLE_CHECK_INTERVAL_USEC 10000 --#define NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT 1000 --#define NPCM_PECI_CMD_TIMEOUT_MS_MAX 60000 --#define NPCM_PECI_HOST_NEG_BIT_RATE_MAX 31 --#define NPCM_PECI_HOST_NEG_BIT_RATE_MIN 7 --#define NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT 15 --#define NPCM_PECI_PULL_DOWN_DEFAULT 0 --#define NPCM_PECI_PULL_DOWN_MAX 2 -- --struct npcm_peci { -- u32 cmd_timeout_ms; -- u32 host_bit_rate; -- struct completion xfer_complete; -- struct regmap *gcr_regmap; -- struct peci_adapter *adapter; -- struct regmap *regmap; -- u32 status; -- spinlock_t lock; /* to sync completion status handling */ -- struct device *dev; -- struct clk *clk; -- int irq; --}; -- --static int npcm_peci_xfer_native(struct npcm_peci *priv, -- struct peci_xfer_msg *msg) --{ -- long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms); -- unsigned long flags; -- unsigned int msg_rd; -- u32 cmd_sts; -- int i, rc; -- -- /* Check command sts and bus idle state */ -- rc = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts, -- !(cmd_sts & NPCM_PECI_CTRL_START_BUSY), -- NPCM_PECI_IDLE_CHECK_INTERVAL_USEC, -- NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC); -- if (rc) -- return rc; /* -ETIMEDOUT */ -- -- spin_lock_irqsave(&priv->lock, flags); -- reinit_completion(&priv->xfer_complete); -- -- regmap_write(priv->regmap, NPCM_PECI_ADDR, msg->addr); -- regmap_write(priv->regmap, NPCM_PECI_RD_LENGTH, -- NPCM_PECI_WR_LEN_MASK & msg->rx_len); -- regmap_write(priv->regmap, NPCM_PECI_WR_LENGTH, -- NPCM_PECI_WR_LEN_MASK & msg->tx_len); -- -- if (msg->tx_len) { -- regmap_write(priv->regmap, NPCM_PECI_CMD, msg->tx_buf[0]); -- -- for (i = 0; i < (msg->tx_len - 1); i++) -- regmap_write(priv->regmap, NPCM_PECI_DAT_INOUT(i), -- msg->tx_buf[i + 1]); -- } -- -- priv->status = 0; -- regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS, -- NPCM_PECI_CTRL_START_BUSY, -- NPCM_PECI_CTRL_START_BUSY); -- -- spin_unlock_irqrestore(&priv->lock, flags); -- -- err = wait_for_completion_interruptible_timeout(&priv->xfer_complete, -- timeout); -- -- spin_lock_irqsave(&priv->lock, flags); -- -- regmap_write(priv->regmap, NPCM_PECI_CMD, 0); -- -- if (err <= 0 || priv->status != NPCM_PECI_CTRL_DONE) { -- if (err < 0) { /* -ERESTARTSYS */ -- rc = (int)err; -- goto err_irqrestore; -- } else if (err == 0) { -- dev_dbg(priv->dev, "Timeout waiting for a response!\n"); -- rc = -ETIMEDOUT; -- goto err_irqrestore; -- } -- -- dev_dbg(priv->dev, "No valid response!\n"); -- rc = -EIO; -- goto err_irqrestore; -- } -- -- for (i = 0; i < msg->rx_len; i++) { -- regmap_read(priv->regmap, NPCM_PECI_DAT_INOUT(i), &msg_rd); -- msg->rx_buf[i] = (u8)msg_rd; -- } -- --err_irqrestore: -- spin_unlock_irqrestore(&priv->lock, flags); -- return rc; --} -- --static irqreturn_t npcm_peci_irq_handler(int irq, void *arg) --{ -- struct npcm_peci *priv = arg; -- u32 status_ack = 0; -- u32 status; -- -- spin_lock(&priv->lock); -- regmap_read(priv->regmap, NPCM_PECI_CTL_STS, &status); -- priv->status |= (status & NPCM_PECI_INT_MASK); -- -- if (status & NPCM_PECI_CTRL_CRC_ERR) { -- dev_dbg(priv->dev, "PECI_INT_W_FCS_BAD\n"); -- status_ack |= NPCM_PECI_CTRL_CRC_ERR; -- } -- -- if (status & NPCM_PECI_CTRL_ABRT_ERR) { -- dev_dbg(priv->dev, "NPCM_PECI_CTRL_ABRT_ERR\n"); -- status_ack |= NPCM_PECI_CTRL_ABRT_ERR; -- } -- -- /* -- * All commands should be ended up with a NPCM_PECI_CTRL_DONE -- * bit set even in an error case. -- */ -- if (status & NPCM_PECI_CTRL_DONE) { -- dev_dbg(priv->dev, "NPCM_PECI_CTRL_DONE\n"); -- status_ack |= NPCM_PECI_CTRL_DONE; -- complete(&priv->xfer_complete); -- } -- -- regmap_write_bits(priv->regmap, NPCM_PECI_CTL_STS, -- NPCM_PECI_INT_MASK, status_ack); -- -- spin_unlock(&priv->lock); -- return IRQ_HANDLED; --} -- --static int npcm_peci_init_ctrl(struct npcm_peci *priv) --{ -- u32 cmd_sts, host_neg_bit_rate = 0, pull_down = 0; -- int ret; -- bool volt; -- -- priv->clk = devm_clk_get(priv->dev, NULL); -- if (IS_ERR(priv->clk)) { -- dev_err(priv->dev, "Failed to get clk source.\n"); -- return PTR_ERR(priv->clk); -- } -- -- ret = clk_prepare_enable(priv->clk); -- if (ret) { -- dev_err(priv->dev, "Failed to enable clock.\n"); -- return ret; -- } -- -- ret = of_property_read_u32(priv->dev->of_node, "cmd-timeout-ms", -- &priv->cmd_timeout_ms); -- if (ret || priv->cmd_timeout_ms > NPCM_PECI_CMD_TIMEOUT_MS_MAX || -- priv->cmd_timeout_ms == 0) { -- if (ret) -- dev_warn(priv->dev, -- "cmd-timeout-ms not found, use default : %u\n", -- NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT); -- else -- dev_warn(priv->dev, -- "Invalid cmd-timeout-ms : %u. Use default : %u\n", -- priv->cmd_timeout_ms, -- NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT); -- -- priv->cmd_timeout_ms = NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT; -- } -- -- if (of_device_is_compatible(priv->dev->of_node, -- "nuvoton,npcm750-peci")) { -- priv->gcr_regmap = syscon_regmap_lookup_by_compatible -- ("nuvoton,npcm750-gcr"); -- if (!IS_ERR(priv->gcr_regmap)) { -- volt = of_property_read_bool(priv->dev->of_node, -- "high-volt-range"); -- if (volt) -- regmap_update_bits(priv->gcr_regmap, -- NPCM7XX_INTCR3_OFFSET, -- NPCM7XX_INTCR3_PECIVSEL, -- NPCM7XX_INTCR3_PECIVSEL); -- else -- regmap_update_bits(priv->gcr_regmap, -- NPCM7XX_INTCR3_OFFSET, -- NPCM7XX_INTCR3_PECIVSEL, 0); -- } -- } -- -- ret = of_property_read_u32(priv->dev->of_node, "pull-down", -- &pull_down); -- if (ret || pull_down > NPCM_PECI_PULL_DOWN_MAX) { -- if (ret) -- dev_warn(priv->dev, -- "pull-down not found, use default : %u\n", -- NPCM_PECI_PULL_DOWN_DEFAULT); -- else -- dev_warn(priv->dev, -- "Invalid pull-down : %u. Use default : %u\n", -- pull_down, -- NPCM_PECI_PULL_DOWN_DEFAULT); -- pull_down = NPCM_PECI_PULL_DOWN_DEFAULT; -- } -- -- regmap_update_bits(priv->regmap, NPCM_PECI_CTL2, NPCM_PECI_CTL2_MASK, -- pull_down << 6); -- -- ret = of_property_read_u32(priv->dev->of_node, "host-neg-bit-rate", -- &host_neg_bit_rate); -- if (ret || host_neg_bit_rate > NPCM_PECI_HOST_NEG_BIT_RATE_MAX || -- host_neg_bit_rate < NPCM_PECI_HOST_NEG_BIT_RATE_MIN) { -- if (ret) -- dev_warn(priv->dev, -- "host-neg-bit-rate not found, use default : %u\n", -- NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT); -- else -- dev_warn(priv->dev, -- "Invalid host-neg-bit-rate : %u. Use default : %u\n", -- host_neg_bit_rate, -- NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT); -- host_neg_bit_rate = NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT; -- } -- -- regmap_update_bits(priv->regmap, NPCM_PECI_PDDR, NPCM_PECI_PDDR_MASK, -- host_neg_bit_rate); -- -- priv->host_bit_rate = clk_get_rate(priv->clk) / -- (4 * (host_neg_bit_rate + 1)); -- -- ret = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts, -- !(cmd_sts & NPCM_PECI_CTRL_START_BUSY), -- NPCM_PECI_IDLE_CHECK_INTERVAL_USEC, -- NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC); -- if (ret) -- return ret; /* -ETIMEDOUT */ -- -- /* PECI interrupt enable */ -- regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS, -- NPCM_PECI_CTRL_DONE_INT_EN, -- NPCM_PECI_CTRL_DONE_INT_EN); -- -- return 0; --} -- --static const struct regmap_config npcm_peci_regmap_config = { -- .reg_bits = 8, -- .val_bits = 8, -- .max_register = NPCM_PECI_MAX_REG, -- .fast_io = true, --}; -- --static int npcm_peci_xfer(struct peci_adapter *adapter, -- struct peci_xfer_msg *msg) --{ -- struct npcm_peci *priv = peci_get_adapdata(adapter); -- -- return npcm_peci_xfer_native(priv, msg); --} -- --static int npcm_peci_probe(struct platform_device *pdev) --{ -- struct peci_adapter *adapter; -- struct npcm_peci *priv; -- struct resource *res; -- void __iomem *base; -- int ret; -- -- adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv)); -- if (!adapter) -- return -ENOMEM; -- -- priv = peci_get_adapdata(adapter); -- priv->adapter = adapter; -- priv->dev = &pdev->dev; -- dev_set_drvdata(&pdev->dev, priv); -- -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- base = devm_ioremap_resource(&pdev->dev, res); -- if (IS_ERR(base)) { -- ret = PTR_ERR(base); -- goto err_put_adapter_dev; -- } -- -- priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, -- &npcm_peci_regmap_config); -- if (IS_ERR(priv->regmap)) { -- ret = PTR_ERR(priv->regmap); -- goto err_put_adapter_dev; -- } -- -- priv->irq = platform_get_irq(pdev, 0); -- if (!priv->irq) { -- ret = -ENODEV; -- goto err_put_adapter_dev; -- } -- -- ret = devm_request_irq(&pdev->dev, priv->irq, npcm_peci_irq_handler, -- 0, "peci-npcm-irq", priv); -- if (ret) -- goto err_put_adapter_dev; -- -- init_completion(&priv->xfer_complete); -- spin_lock_init(&priv->lock); -- -- priv->adapter->owner = THIS_MODULE; -- priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev)); -- strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name)); -- priv->adapter->xfer = npcm_peci_xfer; -- -- ret = npcm_peci_init_ctrl(priv); -- if (ret) -- goto err_put_adapter_dev; -- -- ret = peci_add_adapter(priv->adapter); -- if (ret) -- goto err_put_adapter_dev; -- -- dev_info(&pdev->dev, "peci bus %d registered, host negotiation bit rate %dHz", -- priv->adapter->nr, priv->host_bit_rate); -- -- return 0; -- --err_put_adapter_dev: -- put_device(&adapter->dev); -- return ret; --} -- --static int npcm_peci_remove(struct platform_device *pdev) --{ -- struct npcm_peci *priv = dev_get_drvdata(&pdev->dev); -- -- clk_disable_unprepare(priv->clk); -- peci_del_adapter(priv->adapter); -- of_node_put(priv->adapter->dev.of_node); -- -- return 0; --} -- --static const struct of_device_id npcm_peci_of_table[] = { -- { .compatible = "nuvoton,npcm750-peci", }, -- { } --}; --MODULE_DEVICE_TABLE(of, npcm_peci_of_table); -- --static struct platform_driver npcm_peci_driver = { -- .probe = npcm_peci_probe, -- .remove = npcm_peci_remove, -- .driver = { -- .name = "peci-npcm", -- .of_match_table = of_match_ptr(npcm_peci_of_table), -- }, --}; --module_platform_driver(npcm_peci_driver); -- --MODULE_AUTHOR("Tomer Maimon "); --MODULE_DESCRIPTION("NPCM Platform Environment Control Interface (PECI) driver"); --MODULE_LICENSE("GPL v2"); -diff --git a/include/linux/mfd/intel-peci-client.h b/include/linux/mfd/intel-peci-client.h -index 8f6d823a59cd..9854303bbc26 100644 ---- a/include/linux/mfd/intel-peci-client.h -+++ b/include/linux/mfd/intel-peci-client.h -@@ -1,5 +1,5 @@ - /* SPDX-License-Identifier: GPL-2.0 */ --/* Copyright (c) 2018 Intel Corporation */ -+/* Copyright (c) 2018-2019 Intel Corporation */ - - #ifndef __LINUX_MFD_INTEL_PECI_CLIENT_H - #define __LINUX_MFD_INTEL_PECI_CLIENT_H -@@ -9,14 +9,15 @@ - #if IS_ENABLED(CONFIG_X86) - #include - #else --/** -+/* - * Architectures other than x86 cannot include the header file so define these - * at here. These are needed for detecting type of client x86 CPUs behind a PECI - * connection. - */ --#define INTEL_FAM6_HASWELL_X 0x3F --#define INTEL_FAM6_BROADWELL_X 0x4F --#define INTEL_FAM6_SKYLAKE_X 0x55 -+#define INTEL_FAM6_HASWELL_X 0x3F -+#define INTEL_FAM6_BROADWELL_X 0x4F -+#define INTEL_FAM6_SKYLAKE_X 0x55 -+#define INTEL_FAM6_SKYLAKE_XD 0x56 - #endif - - #define CORE_MAX_ON_HSX 18 /* Max number of cores on Haswell */ -@@ -31,6 +32,10 @@ - #define CHAN_RANK_MAX_ON_SKX 6 /* Max number of channel ranks on Skylake */ - #define DIMM_IDX_MAX_ON_SKX 2 /* Max DIMM index per channel on Skylake */ - -+#define CORE_MAX_ON_SKXD 16 /* Max number of cores on Skylake D */ -+#define CHAN_RANK_MAX_ON_SKXD 2 /* Max number of channel ranks on Skylake D */ -+#define DIMM_IDX_MAX_ON_SKXD 2 /* Max DIMM index per channel on Skylake D */ -+ - #define CORE_NUMS_MAX CORE_MAX_ON_SKX - #define CHAN_RANK_MAX CHAN_RANK_MAX_ON_HSX - #define DIMM_IDX_MAX DIMM_IDX_MAX_ON_HSX -@@ -58,7 +63,6 @@ struct cpu_gen_info { - /** - * struct peci_client_manager - PECI client manager information - * @client; pointer to the PECI client -- * @dev: pointer to the struct device - * @name: PECI client manager name - * @gen_info: CPU generation info of the detected CPU - * -@@ -67,7 +71,6 @@ struct cpu_gen_info { - */ - struct peci_client_manager { - struct peci_client *client; -- struct device *dev; - char name[PECI_NAME_SIZE]; - const struct cpu_gen_info *gen_info; - }; -@@ -93,18 +96,22 @@ peci_client_read_package_config(struct peci_client_manager *priv, - u8 index, u16 param, u8 *data) - { - struct peci_rd_pkg_cfg_msg msg; -- int rc; -+ int ret; - - msg.addr = priv->client->addr; - msg.index = index; - msg.param = param; - msg.rx_len = 4; - -- rc = peci_command(priv->client->adapter, PECI_CMD_RD_PKG_CFG, &msg); -- if (!rc) -- memcpy(data, msg.pkg_config, 4); -+ ret = peci_command(priv->client->adapter, PECI_CMD_RD_PKG_CFG, &msg); -+ if (msg.cc != PECI_DEV_CC_SUCCESS) -+ ret = -EAGAIN; -+ if (ret) -+ return ret; -+ -+ memcpy(data, msg.pkg_config, 4); - -- return rc; -+ return 0; - } - - #endif /* __LINUX_MFD_INTEL_PECI_CLIENT_H */ -diff --git a/include/linux/peci.h b/include/linux/peci.h -index d0e47d45d1d0..6fc424dc2a73 100644 ---- a/include/linux/peci.h -+++ b/include/linux/peci.h -@@ -1,19 +1,18 @@ - /* SPDX-License-Identifier: GPL-2.0 */ --/* Copyright (c) 2018 Intel Corporation */ -+/* Copyright (c) 2018-2019 Intel Corporation */ - - #ifndef __LINUX_PECI_H - #define __LINUX_PECI_H - --#include - #include -+#include - #include --#include - - #define PECI_NAME_SIZE 32 - - struct peci_board_info { - char type[PECI_NAME_SIZE]; -- unsigned short addr; /* CPU client address */ -+ u8 addr; /* CPU client address */ - struct device_node *of_node; - }; - -@@ -22,29 +21,29 @@ struct peci_board_info { - * @owner: owner module of the PECI adpater - * @bus_lock: mutex for exclusion of multiple callers - * @dev: device interface to this driver -- * @cdev: character device object to create character device - * @nr: the bus number to map - * @name: name of the adapter - * @userspace_clients_lock: mutex for exclusion of clients handling - * @userspace_clients: list of registered clients - * @xfer: low-level transfer function pointer of the adapter - * @cmd_mask: mask for supportable PECI commands -+ * @use_dma: flag for indicating that adapter uses DMA - * - * Each PECI adapter can communicate with one or more PECI client children. - * These make a small bus, sharing a single wired PECI connection. - */ - struct peci_adapter { - struct module *owner; -- struct rt_mutex bus_lock; -+ struct mutex bus_lock; - struct device dev; -- struct cdev cdev; - int nr; - char name[PECI_NAME_SIZE]; - struct mutex userspace_clients_lock; /* clients list mutex */ - struct list_head userspace_clients; - int (*xfer)(struct peci_adapter *adapter, - struct peci_xfer_msg *msg); -- uint cmd_mask; -+ u32 cmd_mask; -+ bool use_dma; - }; - - static inline struct peci_adapter *to_peci_adapter(void *d) -@@ -87,8 +86,8 @@ static inline struct peci_client *to_peci_client(void *d) - } - - struct peci_device_id { -- char name[PECI_NAME_SIZE]; -- unsigned long driver_data; /* Data private to the driver */ -+ char name[PECI_NAME_SIZE]; -+ ulong driver_data; /* Data private to the driver */ - }; - - /** -@@ -129,13 +128,22 @@ static inline struct peci_driver *to_peci_driver(void *d) - /* use a define to avoid include chaining to get THIS_MODULE */ - #define peci_add_driver(driver) peci_register_driver(THIS_MODULE, driver) - -+extern struct bus_type peci_bus_type; -+extern struct device_type peci_adapter_type; -+extern struct device_type peci_client_type; -+ - int peci_register_driver(struct module *owner, struct peci_driver *drv); - void peci_del_driver(struct peci_driver *driver); - struct peci_client *peci_verify_client(struct device *dev); --struct peci_adapter *peci_alloc_adapter(struct device *dev, unsigned int size); -+struct peci_adapter *peci_alloc_adapter(struct device *dev, uint size); -+struct peci_adapter *peci_get_adapter(int nr); -+void peci_put_adapter(struct peci_adapter *adapter); - int peci_add_adapter(struct peci_adapter *adapter); - void peci_del_adapter(struct peci_adapter *adapter); - struct peci_adapter *peci_verify_adapter(struct device *dev); -+int peci_for_each_dev(void *data, int (*fn)(struct device *, void *)); -+struct peci_xfer_msg *peci_get_xfer_msg(u8 tx_len, u8 rx_len); -+void peci_put_xfer_msg(struct peci_xfer_msg *msg); - int peci_command(struct peci_adapter *adpater, enum peci_cmd cmd, void *vmsg); - int peci_get_cpu_id(struct peci_adapter *adapter, u8 addr, u32 *cpu_id); - -diff --git a/include/uapi/linux/peci-ioctl.h b/include/uapi/linux/peci-ioctl.h -index a6dae71cbff5..253fb42e38b7 100644 ---- a/include/uapi/linux/peci-ioctl.h -+++ b/include/uapi/linux/peci-ioctl.h -@@ -1,5 +1,5 @@ - /* SPDX-License-Identifier: GPL-2.0 */ --/* Copyright (c) 2018 Intel Corporation */ -+/* Copyright (c) 2018-2019 Intel Corporation */ - - #ifndef __PECI_IOCTL_H - #define __PECI_IOCTL_H -@@ -7,136 +7,35 @@ - #include - #include - --/* Base Address of 48d */ --#define PECI_BASE_ADDR 0x30 /* The PECI client's default address of 0x30 */ --#define PECI_OFFSET_MAX 8 /* Max numver of CPU clients */ -- --/* PCI Access */ --#define MAX_PCI_READ_LEN 24 /* Number of bytes of the PCI Space read */ -- --#define PCI_BUS0_CPU0 0x00 --#define PCI_BUS0_CPU1 0x80 --#define PCI_CPUBUSNO_BUS 0x00 --#define PCI_CPUBUSNO_DEV 0x08 --#define PCI_CPUBUSNO_FUNC 0x02 --#define PCI_CPUBUSNO 0xcc --#define PCI_CPUBUSNO_1 0xd0 --#define PCI_CPUBUSNO_VALID 0xd4 -- --/* Package Identifier Read Parameter Value */ --#define PKG_ID_CPU_ID 0x0000 /* CPUID Info */ --#define PKG_ID_PLATFORM_ID 0x0001 /* Platform ID */ --#define PKG_ID_UNCORE_ID 0x0002 /* Uncore Device ID */ --#define PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */ --#define PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */ --#define PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */ -- --/* RdPkgConfig Index */ --#define MBX_INDEX_CPU_ID 0 /* Package Identifier Read */ --#define MBX_INDEX_VR_DEBUG 1 /* VR Debug */ --#define MBX_INDEX_PKG_TEMP_READ 2 /* Package Temperature Read */ --#define MBX_INDEX_ENERGY_COUNTER 3 /* Energy counter */ --#define MBX_INDEX_ENERGY_STATUS 4 /* DDR Energy Status */ --#define MBX_INDEX_WAKE_MODE_BIT 5 /* "Wake on PECI" Mode bit */ --#define MBX_INDEX_EPI 6 /* Efficient Performance Indication */ --#define MBX_INDEX_PKG_RAPL_PERF 8 /* Pkg RAPL Performance Status Read */ --#define MBX_INDEX_PER_CORE_DTS_TEMP 9 /* Per Core DTS Temperature Read */ --#define MBX_INDEX_DTS_MARGIN 10 /* DTS thermal margin */ --#define MBX_INDEX_SKT_PWR_THRTL_DUR 11 /* Socket Power Throttled Duration */ --#define MBX_INDEX_CFG_TDP_CONTROL 12 /* TDP Config Control */ --#define MBX_INDEX_CFG_TDP_LEVELS 13 /* TDP Config Levels */ --#define MBX_INDEX_DDR_DIMM_TEMP 14 /* DDR DIMM Temperature */ --#define MBX_INDEX_CFG_ICCMAX 15 /* Configurable ICCMAX */ --#define MBX_INDEX_TEMP_TARGET 16 /* Temperature Target Read */ --#define MBX_INDEX_CURR_CFG_LIMIT 17 /* Current Config Limit */ --#define MBX_INDEX_DIMM_TEMP_READ 20 /* Package Thermal Status Read */ --#define MBX_INDEX_DRAM_IMC_TMP_READ 22 /* DRAM IMC Temperature Read */ --#define MBX_INDEX_DDR_CH_THERM_STAT 23 /* DDR Channel Thermal Status */ --#define MBX_INDEX_PKG_POWER_LIMIT1 26 /* Package Power Limit1 */ --#define MBX_INDEX_PKG_POWER_LIMIT2 27 /* Package Power Limit2 */ --#define MBX_INDEX_TDP 28 /* Thermal design power minimum */ --#define MBX_INDEX_TDP_HIGH 29 /* Thermal design power maximum */ --#define MBX_INDEX_TDP_UNITS 30 /* Units for power/energy registers */ --#define MBX_INDEX_RUN_TIME 31 /* Accumulated Run Time */ --#define MBX_INDEX_CONSTRAINED_TIME 32 /* Thermally Constrained Time Read */ --#define MBX_INDEX_TURBO_RATIO 33 /* Turbo Activation Ratio */ --#define MBX_INDEX_DDR_RAPL_PL1 34 /* DDR RAPL PL1 */ --#define MBX_INDEX_DDR_PWR_INFO_HIGH 35 /* DRAM Power Info Read (high) */ --#define MBX_INDEX_DDR_PWR_INFO_LOW 36 /* DRAM Power Info Read (low) */ --#define MBX_INDEX_DDR_RAPL_PL2 37 /* DDR RAPL PL2 */ --#define MBX_INDEX_DDR_RAPL_STATUS 38 /* DDR RAPL Performance Status */ --#define MBX_INDEX_DDR_HOT_ABSOLUTE 43 /* DDR Hottest Dimm Absolute Temp */ --#define MBX_INDEX_DDR_HOT_RELATIVE 44 /* DDR Hottest Dimm Relative Temp */ --#define MBX_INDEX_DDR_THROTTLE_TIME 45 /* DDR Throttle Time */ --#define MBX_INDEX_DDR_THERM_STATUS 46 /* DDR Thermal Status */ --#define MBX_INDEX_TIME_AVG_TEMP 47 /* Package time-averaged temperature */ --#define MBX_INDEX_TURBO_RATIO_LIMIT 49 /* Turbo Ratio Limit Read */ --#define MBX_INDEX_HWP_AUTO_OOB 53 /* HWP Autonomous Out-of-band */ --#define MBX_INDEX_DDR_WARM_BUDGET 55 /* DDR Warm Power Budget */ --#define MBX_INDEX_DDR_HOT_BUDGET 56 /* DDR Hot Power Budget */ --#define MBX_INDEX_PKG_PSYS_PWR_LIM3 57 /* Package/Psys Power Limit3 */ --#define MBX_INDEX_PKG_PSYS_PWR_LIM1 58 /* Package/Psys Power Limit1 */ --#define MBX_INDEX_PKG_PSYS_PWR_LIM2 59 /* Package/Psys Power Limit2 */ --#define MBX_INDEX_PKG_PSYS_PWR_LIM4 60 /* Package/Psys Power Limit4 */ --#define MBX_INDEX_PERF_LIMIT_REASON 65 /* Performance Limit Reasons */ -- --/* WrPkgConfig Index */ --#define MBX_INDEX_DIMM_AMBIENT 19 --#define MBX_INDEX_DIMM_TEMP 24 -+/* The PECI client's default address of 0x30 */ -+#define PECI_BASE_ADDR 0x30 -+ -+/* Max number of CPU clients */ -+#define PECI_OFFSET_MAX 8 -+ -+/* PECI read/write data buffer size max */ -+#define PECI_BUFFER_SIZE 255 - - /* Device Specific Completion Code (CC) Definition */ --#define DEV_PECI_CC_SUCCESS 0x40 --#define DEV_PECI_CC_TIMEOUT 0x80 --#define DEV_PECI_CC_OUT_OF_RESOURCE 0x81 --#define DEV_PECI_CC_UNAVAIL_RESOURCE 0x82 --#define DEV_PECI_CC_INVALID_REQ 0x90 -+#define PECI_DEV_CC_SUCCESS 0x40 -+#define PECI_DEV_CC_NEED_RETRY 0x80 -+#define PECI_DEV_CC_OUT_OF_RESOURCE 0x81 -+#define PECI_DEV_CC_UNAVAIL_RESOURCE 0x82 -+#define PECI_DEV_CC_INVALID_REQ 0x90 -+#define PECI_DEV_CC_MCA_ERROR 0x91 -+#define PECI_DEV_CC_CATASTROPHIC_MCA_ERROR 0x93 -+#define PECI_DEV_CC_FATAL_MCA_DETECTED 0x94 -+#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB 0x98 -+#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_IERR 0x9B -+#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_MCA 0x9C - - /* Completion Code mask to check retry needs */ --#define DEV_PECI_CC_RETRY_CHECK_MASK 0xf0 --#define DEV_PECI_CC_NEED_RETRY 0x80 -+#define PECI_DEV_CC_RETRY_CHECK_MASK 0xf0 - - /* Skylake EDS says to retry for 250ms */ --#define DEV_PECI_RETRY_TIME_MS 250 --#define DEV_PECI_RETRY_INTERVAL_USEC 10000 --#define DEV_PECI_RETRY_BIT 0x01 -- --#define GET_TEMP_WR_LEN 1 --#define GET_TEMP_RD_LEN 2 --#define GET_TEMP_PECI_CMD 0x01 -- --#define GET_DIB_WR_LEN 1 --#define GET_DIB_RD_LEN 8 --#define GET_DIB_PECI_CMD 0xf7 -- --#define RDPKGCFG_WRITE_LEN 5 --#define RDPKGCFG_READ_LEN_BASE 1 --#define RDPKGCFG_PECI_CMD 0xa1 -- --#define WRPKGCFG_WRITE_LEN_BASE 6 --#define WRPKGCFG_READ_LEN 1 --#define WRPKGCFG_PECI_CMD 0xa5 -- --#define RDIAMSR_WRITE_LEN 5 --#define RDIAMSR_READ_LEN 9 --#define RDIAMSR_PECI_CMD 0xb1 -- --#define WRIAMSR_PECI_CMD 0xb5 -- --#define RDPCICFG_WRITE_LEN 6 --#define RDPCICFG_READ_LEN 5 --#define RDPCICFG_PECI_CMD 0x61 -- --#define WRPCICFG_PECI_CMD 0x65 -- --#define RDPCICFGLOCAL_WRITE_LEN 5 --#define RDPCICFGLOCAL_READ_LEN_BASE 1 --#define RDPCICFGLOCAL_PECI_CMD 0xe1 -- --#define WRPCICFGLOCAL_WRITE_LEN_BASE 6 --#define WRPCICFGLOCAL_READ_LEN 1 --#define WRPCICFGLOCAL_PECI_CMD 0xe5 -- --#define PECI_BUFFER_SIZE 32 -+#define PECI_DEV_RETRY_TIME_MS 250 -+#define PECI_DEV_RETRY_INTERVAL_USEC 10000 -+#define PECI_DEV_RETRY_BIT 0x01 - - /** - * enum peci_cmd - PECI client commands -@@ -186,11 +85,12 @@ enum peci_cmd { - * raw PECI transfer - */ - struct peci_xfer_msg { -- __u8 addr; -- __u8 tx_len; -- __u8 rx_len; -- __u8 tx_buf[PECI_BUFFER_SIZE]; -- __u8 rx_buf[PECI_BUFFER_SIZE]; -+ __u8 addr; -+ __u8 tx_len; -+ __u8 rx_len; -+ __u8 padding; -+ __u8 *tx_buf; -+ __u8 *rx_buf; - } __attribute__((__packed__)); - - /** -@@ -202,7 +102,8 @@ struct peci_xfer_msg { - * powered-off, etc. - */ - struct peci_ping_msg { -- __u8 addr; -+ __u8 addr; -+ __u8 padding[3]; - } __attribute__((__packed__)); - - /** -@@ -216,8 +117,13 @@ struct peci_ping_msg { - * command. - */ - struct peci_get_dib_msg { -- __u8 addr; -- __u64 dib; -+#define PECI_GET_DIB_WR_LEN 1 -+#define PECI_GET_DIB_RD_LEN 8 -+#define PECI_GET_DIB_CMD 0xf7 -+ -+ __u8 addr; -+ __u8 padding[3]; -+ __u64 dib; - } __attribute__((__packed__)); - - /** -@@ -232,8 +138,13 @@ struct peci_get_dib_msg { - * below the maximum processor junction temperature. - */ - struct peci_get_temp_msg { -- __u8 addr; -- __s16 temp_raw; -+#define PECI_GET_TEMP_WR_LEN 1 -+#define PECI_GET_TEMP_RD_LEN 2 -+#define PECI_GET_TEMP_CMD 0x01 -+ -+ __u8 addr; -+ __u8 padding; -+ __s16 temp_raw; - } __attribute__((__packed__)); - - /** -@@ -242,6 +153,7 @@ struct peci_get_temp_msg { - * @index: encoding index for the requested service - * @param: specific data being requested - * @rx_len: number of data to be read in bytes -+ * @cc: completion code - * @pkg_config: package config data to be read - * - * The RdPkgConfig() command provides read access to the Package Configuration -@@ -251,11 +163,73 @@ struct peci_get_temp_msg { - * DIMM temperatures and so on. - */ - struct peci_rd_pkg_cfg_msg { -- __u8 addr; -- __u8 index; -- __u16 param; -- __u8 rx_len; -- __u8 pkg_config[4]; -+#define PECI_RDPKGCFG_WRITE_LEN 5 -+#define PECI_RDPKGCFG_READ_LEN_BASE 1 -+#define PECI_RDPKGCFG_CMD 0xa1 -+ -+ __u8 addr; -+ __u8 index; -+#define PECI_MBX_INDEX_CPU_ID 0 /* Package Identifier Read */ -+#define PECI_MBX_INDEX_VR_DEBUG 1 /* VR Debug */ -+#define PECI_MBX_INDEX_PKG_TEMP_READ 2 /* Package Temperature Read */ -+#define PECI_MBX_INDEX_ENERGY_COUNTER 3 /* Energy counter */ -+#define PECI_MBX_INDEX_ENERGY_STATUS 4 /* DDR Energy Status */ -+#define PECI_MBX_INDEX_WAKE_MODE_BIT 5 /* "Wake on PECI" Mode bit */ -+#define PECI_MBX_INDEX_EPI 6 /* Efficient Performance Indication */ -+#define PECI_MBX_INDEX_PKG_RAPL_PERF 8 /* Pkg RAPL Performance Status Read */ -+#define PECI_MBX_INDEX_PER_CORE_DTS_TEMP 9 /* Per Core DTS Temperature Read */ -+#define PECI_MBX_INDEX_DTS_MARGIN 10 /* DTS thermal margin */ -+#define PECI_MBX_INDEX_SKT_PWR_THRTL_DUR 11 /* Socket Power Throttled Duration */ -+#define PECI_MBX_INDEX_CFG_TDP_CONTROL 12 /* TDP Config Control */ -+#define PECI_MBX_INDEX_CFG_TDP_LEVELS 13 /* TDP Config Levels */ -+#define PECI_MBX_INDEX_DDR_DIMM_TEMP 14 /* DDR DIMM Temperature */ -+#define PECI_MBX_INDEX_CFG_ICCMAX 15 /* Configurable ICCMAX */ -+#define PECI_MBX_INDEX_TEMP_TARGET 16 /* Temperature Target Read */ -+#define PECI_MBX_INDEX_CURR_CFG_LIMIT 17 /* Current Config Limit */ -+#define PECI_MBX_INDEX_DIMM_TEMP_READ 20 /* Package Thermal Status Read */ -+#define PECI_MBX_INDEX_DRAM_IMC_TMP_READ 22 /* DRAM IMC Temperature Read */ -+#define PECI_MBX_INDEX_DDR_CH_THERM_STAT 23 /* DDR Channel Thermal Status */ -+#define PECI_MBX_INDEX_PKG_POWER_LIMIT1 26 /* Package Power Limit1 */ -+#define PECI_MBX_INDEX_PKG_POWER_LIMIT2 27 /* Package Power Limit2 */ -+#define PECI_MBX_INDEX_TDP 28 /* Thermal design power minimum */ -+#define PECI_MBX_INDEX_TDP_HIGH 29 /* Thermal design power maximum */ -+#define PECI_MBX_INDEX_TDP_UNITS 30 /* Units for power/energy registers */ -+#define PECI_MBX_INDEX_RUN_TIME 31 /* Accumulated Run Time */ -+#define PECI_MBX_INDEX_CONSTRAINED_TIME 32 /* Thermally Constrained Time Read */ -+#define PECI_MBX_INDEX_TURBO_RATIO 33 /* Turbo Activation Ratio */ -+#define PECI_MBX_INDEX_DDR_RAPL_PL1 34 /* DDR RAPL PL1 */ -+#define PECI_MBX_INDEX_DDR_PWR_INFO_HIGH 35 /* DRAM Power Info Read (high) */ -+#define PECI_MBX_INDEX_DDR_PWR_INFO_LOW 36 /* DRAM Power Info Read (low) */ -+#define PECI_MBX_INDEX_DDR_RAPL_PL2 37 /* DDR RAPL PL2 */ -+#define PECI_MBX_INDEX_DDR_RAPL_STATUS 38 /* DDR RAPL Performance Status */ -+#define PECI_MBX_INDEX_DDR_HOT_ABSOLUTE 43 /* DDR Hottest Dimm Absolute Temp */ -+#define PECI_MBX_INDEX_DDR_HOT_RELATIVE 44 /* DDR Hottest Dimm Relative Temp */ -+#define PECI_MBX_INDEX_DDR_THROTTLE_TIME 45 /* DDR Throttle Time */ -+#define PECI_MBX_INDEX_DDR_THERM_STATUS 46 /* DDR Thermal Status */ -+#define PECI_MBX_INDEX_TIME_AVG_TEMP 47 /* Package time-averaged temperature */ -+#define PECI_MBX_INDEX_TURBO_RATIO_LIMIT 49 /* Turbo Ratio Limit Read */ -+#define PECI_MBX_INDEX_HWP_AUTO_OOB 53 /* HWP Autonomous Out-of-band */ -+#define PECI_MBX_INDEX_DDR_WARM_BUDGET 55 /* DDR Warm Power Budget */ -+#define PECI_MBX_INDEX_DDR_HOT_BUDGET 56 /* DDR Hot Power Budget */ -+#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM3 57 /* Package/Psys Power Limit3 */ -+#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM1 58 /* Package/Psys Power Limit1 */ -+#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM2 59 /* Package/Psys Power Limit2 */ -+#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM4 60 /* Package/Psys Power Limit4 */ -+#define PECI_MBX_INDEX_PERF_LIMIT_REASON 65 /* Performance Limit Reasons */ -+ -+ __u16 param; -+/* When index is PECI_MBX_INDEX_CPU_ID */ -+#define PECI_PKG_ID_CPU_ID 0x0000 /* CPUID Info */ -+#define PECI_PKG_ID_PLATFORM_ID 0x0001 /* Platform ID */ -+#define PECI_PKG_ID_UNCORE_ID 0x0002 /* Uncore Device ID */ -+#define PECI_PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */ -+#define PECI_PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */ -+#define PECI_PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */ -+ -+ __u8 rx_len; -+ __u8 cc; -+ __u8 padding[2]; -+ __u8 pkg_config[4]; - } __attribute__((__packed__)); - - /** -@@ -264,6 +238,7 @@ struct peci_rd_pkg_cfg_msg { - * @index: encoding index for the requested service - * @param: specific data being requested - * @tx_len: number of data to be written in bytes -+ * @cc: completion code - * @value: package config data to be written - * - * The WrPkgConfig() command provides write access to the Package Configuration -@@ -272,11 +247,20 @@ struct peci_rd_pkg_cfg_msg { - * may include power limiting, thermal averaging constant programming and so on. - */ - struct peci_wr_pkg_cfg_msg { -- __u8 addr; -- __u8 index; -- __u16 param; -- __u8 tx_len; -- __u32 value; -+#define PECI_WRPKGCFG_WRITE_LEN_BASE 6 -+#define PECI_WRPKGCFG_READ_LEN 1 -+#define PECI_WRPKGCFG_CMD 0xa5 -+ -+ __u8 addr; -+ __u8 index; -+#define PECI_MBX_INDEX_DIMM_AMBIENT 19 -+#define PECI_MBX_INDEX_DIMM_TEMP 24 -+ -+ __u16 param; -+ __u8 tx_len; -+ __u8 cc; -+ __u8 padding[2]; -+ __u32 value; - } __attribute__((__packed__)); - - /** -@@ -284,16 +268,47 @@ struct peci_wr_pkg_cfg_msg { - * @addr: address of the client - * @thread_id: ID of the specific logical processor - * @address: address of MSR to read from -+ * @cc: completion code - * @value: data to be read - * - * The RdIAMSR() PECI command provides read access to Model Specific Registers - * (MSRs) defined in the processor's Intel Architecture (IA). - */ - struct peci_rd_ia_msr_msg { -- __u8 addr; -- __u8 thread_id; -- __u16 address; -- __u64 value; -+#define PECI_RDIAMSR_WRITE_LEN 5 -+#define PECI_RDIAMSR_READ_LEN 9 -+#define PECI_RDIAMSR_CMD 0xb1 -+ -+ __u8 addr; -+ __u8 thread_id; -+ __u16 address; -+ __u8 cc; -+ __u8 padding[3]; -+ __u64 value; -+} __attribute__((__packed__)); -+ -+/** -+ * struct peci_wr_ia_msr_msg - WrIAMSR command -+ * @addr: address of the client -+ * @thread_id: ID of the specific logical processor -+ * @address: address of MSR to write to -+ * @tx_len: number of data to be written in bytes -+ * @cc: completion code -+ * @value: data to be written -+ * -+ * The WrIAMSR() PECI command provides write access to Model Specific Registers -+ * (MSRs) defined in the processor's Intel Architecture (IA). -+ */ -+struct peci_wr_ia_msr_msg { -+#define PECI_WRIAMSR_CMD 0xb5 -+ -+ __u8 addr; -+ __u8 thread_id; -+ __u16 address; -+ __u8 tx_len; -+ __u8 cc; -+ __u8 padding[2]; -+ __u64 value; - } __attribute__((__packed__)); - - /** -@@ -303,6 +318,7 @@ struct peci_rd_ia_msr_msg { - * @device: PCI device number - * @function: specific function to read from - * @reg: specific register to read from -+ * @cc: completion code - * @pci_config: config data to be read - * - * The RdPCIConfig() command provides sideband read access to the PCI -@@ -310,12 +326,56 @@ struct peci_rd_ia_msr_msg { - * processor. - */ - struct peci_rd_pci_cfg_msg { -- __u8 addr; -- __u8 bus; -- __u8 device; -- __u8 function; -- __u16 reg; -- __u8 pci_config[4]; -+#define PECI_RDPCICFG_WRITE_LEN 6 -+#define PECI_RDPCICFG_READ_LEN 5 -+#define PECI_RDPCICFG_READ_LEN_MAX 24 -+#define PECI_RDPCICFG_CMD 0x61 -+ -+ __u8 addr; -+ __u8 bus; -+#define PECI_PCI_BUS0_CPU0 0x00 -+#define PECI_PCI_BUS0_CPU1 0x80 -+#define PECI_PCI_CPUBUSNO_BUS 0x00 -+#define PECI_PCI_CPUBUSNO_DEV 0x08 -+#define PECI_PCI_CPUBUSNO_FUNC 0x02 -+#define PECI_PCI_CPUBUSNO 0xcc -+#define PECI_PCI_CPUBUSNO_1 0xd0 -+#define PECI_PCI_CPUBUSNO_VALID 0xd4 -+ -+ __u8 device; -+ __u8 function; -+ __u16 reg; -+ __u8 cc; -+ __u8 padding[1]; -+ __u8 pci_config[4]; -+} __attribute__((__packed__)); -+ -+/** -+ * struct peci_wr_pci_cfg_msg - WrPCIConfig command -+ * @addr: address of the client -+ * @bus: PCI bus number -+ * @device: PCI device number -+ * @function: specific function to write to -+ * @reg: specific register to write to -+ * @tx_len: number of data to be written in bytes -+ * @cc: completion code -+ * @pci_config: config data to be written -+ * -+ * The RdPCIConfig() command provides sideband write access to the PCI -+ * configuration space maintained in downstream devices external to the -+ * processor. -+ */ -+struct peci_wr_pci_cfg_msg { -+#define PECI_WRPCICFG_CMD 0x65 -+ -+ __u8 addr; -+ __u8 bus; -+ __u8 device; -+ __u8 function; -+ __u16 reg; -+ __u8 tx_len; -+ __u8 cc; -+ __u8 pci_config[4]; - } __attribute__((__packed__)); - - /** -@@ -326,6 +386,7 @@ struct peci_rd_pci_cfg_msg { - * @function: specific function to read from - * @reg: specific register to read from - * @rx_len: number of data to be read in bytes -+ * @cc: completion code - * @pci_config: config data to be read - * - * The RdPCIConfigLocal() command provides sideband read access to the PCI -@@ -333,13 +394,18 @@ struct peci_rd_pci_cfg_msg { - * processor IIO and uncore registers within the PCI configuration space. - */ - struct peci_rd_pci_cfg_local_msg { -- __u8 addr; -- __u8 bus; -- __u8 device; -- __u8 function; -- __u16 reg; -- __u8 rx_len; -- __u8 pci_config[4]; -+#define PECI_RDPCICFGLOCAL_WRITE_LEN 5 -+#define PECI_RDPCICFGLOCAL_READ_LEN_BASE 1 -+#define PECI_RDPCICFGLOCAL_CMD 0xe1 -+ -+ __u8 addr; -+ __u8 bus; -+ __u8 device; -+ __u8 function; -+ __u16 reg; -+ __u8 rx_len; -+ __u8 cc; -+ __u8 pci_config[4]; - } __attribute__((__packed__)); - - /** -@@ -350,6 +416,7 @@ struct peci_rd_pci_cfg_local_msg { - * @function: specific function to read from - * @reg: specific register to read from - * @tx_len: number of data to be written in bytes -+ * @cc: completion code - * @value: config data to be written - * - * The WrPCIConfigLocal() command provides sideband write access to the PCI -@@ -357,13 +424,18 @@ struct peci_rd_pci_cfg_local_msg { - * access this space even before BIOS enumeration of the system buses. - */ - struct peci_wr_pci_cfg_local_msg { -- __u8 addr; -- __u8 bus; -- __u8 device; -- __u8 function; -- __u16 reg; -- __u8 tx_len; -- __u32 value; -+#define PECI_WRPCICFGLOCAL_WRITE_LEN_BASE 6 -+#define PECI_WRPCICFGLOCAL_READ_LEN 1 -+#define PECI_WRPCICFGLOCAL_CMD 0xe5 -+ -+ __u8 addr; -+ __u8 bus; -+ __u8 device; -+ __u8 function; -+ __u16 reg; -+ __u8 tx_len; -+ __u8 cc; -+ __u32 value; - } __attribute__((__packed__)); - - #define PECI_IOC_BASE 0xb7 -@@ -389,9 +461,15 @@ struct peci_wr_pci_cfg_local_msg { - #define PECI_IOC_RD_IA_MSR \ - _IOWR(PECI_IOC_BASE, PECI_CMD_RD_IA_MSR, struct peci_rd_ia_msr_msg) - -+#define PECI_IOC_WR_IA_MSR \ -+ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_IA_MSR, struct peci_wr_ia_msr_msg) -+ - #define PECI_IOC_RD_PCI_CFG \ - _IOWR(PECI_IOC_BASE, PECI_CMD_RD_PCI_CFG, struct peci_rd_pci_cfg_msg) - -+#define PECI_IOC_WR_PCI_CFG \ -+ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_PCI_CFG, struct peci_wr_pci_cfg_msg) -+ - #define PECI_IOC_RD_PCI_CFG_LOCAL \ - _IOWR(PECI_IOC_BASE, PECI_CMD_RD_PCI_CFG_LOCAL, \ - struct peci_rd_pci_cfg_local_msg) --- -2.7.4 - diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0014-arm-dts-aspeed-g5-add-espi.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0014-arm-dts-aspeed-g5-add-espi.patch new file mode 100644 index 000000000..094fc8396 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0014-arm-dts-aspeed-g5-add-espi.patch @@ -0,0 +1,56 @@ +From b70fe24abeef901b3ba8e32b5e5d8aaf35ec061d Mon Sep 17 00:00:00 2001 +From: Juston Li +Date: Mon, 27 Mar 2017 11:16:00 -0700 +Subject: [PATCH] arm: dts: aspeed-g5: add espi + +Signed-off-by: Juston Li +--- + arch/arm/boot/dts/aspeed-g5.dtsi | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index 00f05bd3375d..271f3c96456a 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -311,7 +311,7 @@ + #gpio-cells = <2>; + gpio-controller; + compatible = "aspeed,ast2500-gpio"; +- reg = <0x1e780000 0x1000>; ++ reg = <0x1e780000 0x0200>; + interrupts = <20>; + gpio-ranges = <&pinctrl 0 0 232>; + clocks = <&syscon ASPEED_CLK_APB>; +@@ -319,6 +319,15 @@ + #interrupt-cells = <2>; + }; + ++ sgpio: sgpio@1e780200 { ++ #gpio-cells = <2>; ++ gpio-controller; ++ compatible = "aspeed,ast2500-sgpio"; ++ reg = <0x1e780200 0x0100>; ++ interrupts = <40>; ++ interrupt-controller; ++ }; ++ + rtc: rtc@1e781000 { + compatible = "aspeed,ast2500-rtc"; + reg = <0x1e781000 0x18>; +@@ -394,6 +403,13 @@ + status = "disabled"; + }; + ++ espi: espi@1e6ee000 { ++ compatible = "aspeed,ast2500-espi-slave"; ++ reg = <0x1e6ee000 0x100>; ++ interrupts = <23>; ++ status = "disabled"; ++ }; ++ + lpc: lpc@1e789000 { + compatible = "aspeed,ast2500-lpc", "simple-mfd"; + reg = <0x1e789000 0x1000>; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0015-New-flash-map-for-intel.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0015-New-flash-map-for-intel.patch new file mode 100644 index 000000000..695491d28 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0015-New-flash-map-for-intel.patch @@ -0,0 +1,117 @@ +From f57d473a30f208754457bdb63512c307f7499ac8 Mon Sep 17 00:00:00 2001 +From: Vernon Mauery +Date: Mon, 4 Jun 2018 13:45:42 -0700 +Subject: [PATCH] New flash map for Intel + +Signed-off-by: Vernon Mauery +Signed-off-by: Vikram Bodireddy +--- + .../boot/dts/openbmc-flash-layout-intel-128MB.dtsi | 50 ++++++++++++++++++++++ + .../boot/dts/openbmc-flash-layout-intel-64MB.dtsi | 38 ++++++++++++++++ + 2 files changed, 88 insertions(+) + create mode 100644 arch/arm/boot/dts/openbmc-flash-layout-intel-128MB.dtsi + create mode 100644 arch/arm/boot/dts/openbmc-flash-layout-intel-64MB.dtsi + +diff --git a/arch/arm/boot/dts/openbmc-flash-layout-intel-128MB.dtsi b/arch/arm/boot/dts/openbmc-flash-layout-intel-128MB.dtsi +new file mode 100644 +index 000000000000..0d3794423aed +--- /dev/null ++++ b/arch/arm/boot/dts/openbmc-flash-layout-intel-128MB.dtsi +@@ -0,0 +1,50 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// 128MB flash layout: PFR (active + tmp1/tmp2 + extra) ++// image with common RW partition ++ ++partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ u-boot@0 { ++ reg = <0x0 0x80000>; ++ label = "u-boot"; ++ }; ++ ++ pfm@80000 { ++ reg = <0x80000 0x20000>; ++ label = "pfm"; ++ }; ++ ++ u-boot-env@a0000 { ++ reg = <0xa0000 0x20000>; ++ label = "u-boot-env"; ++ }; ++ ++ sofs@c0000 { ++ reg = <0xc0000 0x200000>; ++ label = "sofs"; ++ }; ++ ++ rwfs@2c0000 { ++ reg = <0x2c0000 0x840000>; ++ label = "rwfs"; ++ }; ++ ++ fit-image-a@b00000 { ++ reg = <0xb00000 0x1f00000>; ++ label = "image-a"; ++ }; ++ ++ rc-image@2a00000 { ++ reg = <0x2a00000 0x2000000>; ++ label = "rc-image"; ++ }; ++ ++ image-staging@4a00000 { ++ reg = <0x4a00000 0x3600000>; ++ label = "image-stg"; ++ }; ++ ++}; +diff --git a/arch/arm/boot/dts/openbmc-flash-layout-intel-64MB.dtsi b/arch/arm/boot/dts/openbmc-flash-layout-intel-64MB.dtsi +new file mode 100644 +index 000000000000..092708f5021f +--- /dev/null ++++ b/arch/arm/boot/dts/openbmc-flash-layout-intel-64MB.dtsi +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// 64MB flash layout: redundant image with common RW partition ++ ++partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ u-boot@0 { ++ reg = <0x0 0x80000>; ++ label = "u-boot"; ++ }; ++ ++ fit-image-a@80000 { ++ reg = <0x80000 0x1b80000>; ++ label = "image-a"; ++ }; ++ ++ sofs@1c00000 { ++ reg = <0x1c00000 0x200000>; ++ label = "sofs"; ++ }; ++ ++ rwfs@1e00000 { ++ reg = <0x1e00000 0x600000>; ++ label = "rwfs"; ++ }; ++ ++ u-boot-env@2400000 { ++ reg = <0x2400000 0x20000>; ++ label = "u-boot-env"; ++ }; ++ ++ fit-image-b@2480000 { ++ reg = <0x2480000 0x1b80000>; ++ label = "image-b"; ++ }; ++}; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0016-Add-ASPEED-SGPIO-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0016-Add-ASPEED-SGPIO-driver.patch new file mode 100644 index 000000000..07bdf60af --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0016-Add-ASPEED-SGPIO-driver.patch @@ -0,0 +1,759 @@ +From ab104c6067683a3a251e2814991474243b7e1cb8 Mon Sep 17 00:00:00 2001 +From: "Feist, James" +Date: Tue, 4 Jun 2019 14:00:39 -0700 +Subject: [PATCH] gpio: aspeed: add ASPEED SGPIO driver + +Add SGPIO driver support for Aspeed SoCs. + +Signed-off-by: James Feist +Signed-off-by: Jae Hyun Yoo +--- + drivers/gpio/Kconfig | 8 + + drivers/gpio/Makefile | 1 + + drivers/gpio/sgpio-aspeed.c | 703 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 712 insertions(+) + create mode 100644 drivers/gpio/sgpio-aspeed.c + +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig +index bb13c266c329..4061686d8651 100644 +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -120,6 +120,14 @@ config GPIO_ASPEED + help + Say Y here to support Aspeed AST2400 and AST2500 GPIO controllers. + ++config SGPIO_ASPEED ++ tristate "ASPEED SGPIO support" ++ depends on (ARCH_ASPEED || COMPILE_TEST) && OF_GPIO ++ select GPIO_GENERIC ++ select GPIOLIB_IRQCHIP ++ help ++ Say Y here to support ASPEED SGPIO functionality. ++ + config GPIO_ATH79 + tristate "Atheros AR71XX/AR724X/AR913X GPIO support" + default y if ATH79 +diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile +index a4e91175c708..bebbd8205c11 100644 +--- a/drivers/gpio/Makefile ++++ b/drivers/gpio/Makefile +@@ -32,6 +32,7 @@ obj-$(CONFIG_GPIO_AMD_FCH) += gpio-amd-fch.o + obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o + obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o + obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o ++obj-$(CONFIG_SGPIO_ASPEED) += sgpio-aspeed.o + obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o + obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o + obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o +diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c +new file mode 100644 +index 000000000000..b6e9ccee774d +--- /dev/null ++++ b/drivers/gpio/sgpio-aspeed.c +@@ -0,0 +1,703 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// Copyright (c) 2019 Intel Corporation ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define ASPEED_SGPIO_CTRL 0x54 ++#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16) ++#define ASPEED_SGPIO_CLK_DIV_MIN 1 ++#define ASPEED_SGPIO_CLK_DIV_MAX 65535 ++#define ASPEED_SGPIO_PINBYTES_MASK GENMASK(9, 6) ++#define ASPEED_SGPIO_PINBYTES_MIN 1 ++#define ASPEED_SGPIO_PINBYTES_MAX 10 ++#define ASPEED_SGPIO_ENABLE BIT(0) ++ ++#define ASPEED_SGPIO_BUS_FREQ_DEFAULT 1000000 ++ ++struct aspeed_bank_props { ++ unsigned int bank; ++ u32 input; ++ u32 output; ++}; ++ ++struct aspeed_sgpio_config { ++ unsigned int nr_pgpios; ++ unsigned int nr_gpios; ++ const struct aspeed_bank_props *props; ++}; ++ ++struct aspeed_sgpio { ++ struct gpio_chip chip; ++ struct irq_chip irqc; ++ spinlock_t lock; ++ void __iomem *base; ++ int irq; ++ const struct aspeed_sgpio_config *config; ++}; ++ ++struct aspeed_sgpio_bank { ++ uint16_t val_reg; ++ uint16_t rdata_reg; ++ uint16_t tolerance_reg; ++ uint16_t irq_regs; ++ bool support_irq; ++ const char names[4][3]; ++}; ++ ++/* ++ * Note: The "val" register returns the input value sampled on the line. ++ * Or, it can be used for writing a value on the line. ++ * ++ * The "rdata" register returns the content of the write latch and thus ++ * can be used to read back what was last written reliably. ++ */ ++ ++static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = { ++ { ++ .val_reg = 0x0000, ++ .rdata_reg = 0x0070, ++ .tolerance_reg = 0x0018, ++ .irq_regs = 0x0004, ++ .support_irq = false, ++ .names = { "OA", "OB", "OC", "OD" }, ++ }, ++ { ++ .val_reg = 0x001C, ++ .rdata_reg = 0x0074, ++ .tolerance_reg = 0x0034, ++ .irq_regs = 0x0020, ++ .support_irq = false, ++ .names = { "OE", "OF", "OG", "OH" }, ++ }, ++ { ++ .val_reg = 0x0038, ++ .rdata_reg = 0x0078, ++ .tolerance_reg = 0x0050, ++ .irq_regs = 0x003C, ++ .support_irq = false, ++ .names = { "OI", "OJ" }, ++ }, ++ { ++ .val_reg = 0x0000, ++ .rdata_reg = 0x0070, ++ .tolerance_reg = 0x0018, ++ .irq_regs = 0x0004, ++ .support_irq = true, ++ .names = { "IA", "IB", "IC", "ID" }, ++ }, ++ { ++ .val_reg = 0x001C, ++ .rdata_reg = 0x0074, ++ .tolerance_reg = 0x0034, ++ .irq_regs = 0x0020, ++ .support_irq = true, ++ .names = { "IE", "IF", "IG", "IH" }, ++ }, ++ { ++ .val_reg = 0x0038, ++ .rdata_reg = 0x0078, ++ .tolerance_reg = 0x0050, ++ .irq_regs = 0x003C, ++ .support_irq = true, ++ .names = { "II", "IJ" }, ++ }, ++}; ++ ++enum aspeed_sgpio_reg { ++ reg_val, ++ reg_rdata, ++ reg_irq_enable, ++ reg_irq_type0, ++ reg_irq_type1, ++ reg_irq_type2, ++ reg_irq_status, ++ reg_tolerance, ++}; ++ ++#define GPIO_IRQ_ENABLE 0x00 ++#define GPIO_IRQ_TYPE0 0x04 ++#define GPIO_IRQ_TYPE1 0x08 ++#define GPIO_IRQ_TYPE2 0x0c ++#define GPIO_IRQ_STATUS 0x10 ++ ++/* This will be resolved at compile time */ ++static inline void __iomem *bank_reg(struct aspeed_sgpio *gpio, ++ const struct aspeed_sgpio_bank *bank, ++ const enum aspeed_sgpio_reg reg) ++{ ++ switch (reg) { ++ case reg_val: ++ return gpio->base + bank->val_reg; ++ case reg_rdata: ++ return gpio->base + bank->rdata_reg; ++ case reg_irq_enable: ++ return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE; ++ case reg_irq_type0: ++ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0; ++ case reg_irq_type1: ++ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1; ++ case reg_irq_type2: ++ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2; ++ case reg_irq_status: ++ return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS; ++ case reg_tolerance: ++ return gpio->base + bank->tolerance_reg; ++ default: ++ WARN_ON(1); ++ } ++ ++ return NULL; ++} ++ ++#define GPIO_BANK(x) ((x) >> 5) ++#define GPIO_OFFSET(x) ((x) & 0x1f) ++#define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) ++ ++static const struct aspeed_sgpio_bank *to_bank(unsigned int offset) ++{ ++ unsigned int bank = GPIO_BANK(offset); ++ ++ WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks)); ++ return &aspeed_sgpio_banks[bank]; ++} ++ ++static inline bool is_bank_props_sentinel(const struct aspeed_bank_props *props) ++{ ++ return !(props->input || props->output); ++} ++ ++static inline const struct aspeed_bank_props *find_bank_props( ++ struct aspeed_sgpio *gpio, unsigned int offset) ++{ ++ const struct aspeed_bank_props *props = gpio->config->props; ++ ++ while (!is_bank_props_sentinel(props)) { ++ if (props->bank == GPIO_BANK(offset)) ++ return props; ++ props++; ++ } ++ ++ return NULL; ++} ++ ++static inline bool have_input(struct aspeed_sgpio *gpio, unsigned int offset) ++{ ++ const struct aspeed_bank_props *props = find_bank_props(gpio, offset); ++ ++ return !props || (props->input & GPIO_BIT(offset)); ++} ++ ++static inline bool have_output(struct aspeed_sgpio *gpio, unsigned int offset) ++{ ++ const struct aspeed_bank_props *props = find_bank_props(gpio, offset); ++ ++ return !props || (props->output & GPIO_BIT(offset)); ++} ++ ++static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset) ++{ ++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); ++ const struct aspeed_sgpio_bank *bank = to_bank(offset); ++ enum aspeed_sgpio_reg reg; ++ ++ if (have_output(gpio, offset)) ++ reg = reg_rdata; ++ else ++ reg = reg_val; ++ ++ return !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset)); ++} ++ ++static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val) ++{ ++ const struct aspeed_sgpio_bank *bank = to_bank(offset); ++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); ++ unsigned long flags; ++ u32 reg; ++ ++ if (!have_output(gpio, offset)) ++ return; ++ ++ spin_lock_irqsave(&gpio->lock, flags); ++ ++ reg = ioread32(bank_reg(gpio, bank, reg_rdata)); ++ ++ if (val) ++ reg |= GPIO_BIT(offset); ++ else ++ reg &= ~GPIO_BIT(offset); ++ ++ iowrite32(reg, bank_reg(gpio, bank, reg_val)); ++ ++ spin_unlock_irqrestore(&gpio->lock, flags); ++} ++ ++static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset) ++{ ++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); ++ ++ if (!have_input(gpio, offset)) ++ return -ENOTSUPP; ++ ++ return 0; ++} ++ ++static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, ++ int val) ++{ ++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); ++ ++ if (!have_output(gpio, offset)) ++ return -ENOTSUPP; ++ ++ aspeed_sgpio_set(gc, offset, val); ++ ++ return 0; ++} ++ ++static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset) ++{ ++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); ++ ++ if (have_output(gpio, offset)) ++ return 0; ++ else if (have_input(gpio, offset)) ++ return 1; ++ ++ return -ENOTSUPP; ++} ++ ++static inline int ++irqd_to_aspeed_sgpio_data(struct irq_data *d, struct aspeed_sgpio **gpio, ++ const struct aspeed_sgpio_bank **bank, ++ u32 *bit, int *offset) ++{ ++ struct aspeed_sgpio *internal; ++ ++ *offset = irqd_to_hwirq(d); ++ ++ internal = irq_data_get_irq_chip_data(d); ++ ++ *gpio = internal; ++ *bank = to_bank(*offset); ++ *bit = GPIO_BIT(*offset); ++ ++ return 0; ++} ++ ++static void aspeed_sgpio_irq_ack(struct irq_data *d) ++{ ++ const struct aspeed_sgpio_bank *bank; ++ struct aspeed_sgpio *gpio; ++ void __iomem *status_addr; ++ unsigned long flags; ++ int rc, offset; ++ u32 bit; ++ ++ rc = irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); ++ if (rc) ++ return; ++ ++ status_addr = bank_reg(gpio, bank, reg_irq_status); ++ ++ spin_lock_irqsave(&gpio->lock, flags); ++ ++ iowrite32(bit, status_addr); ++ ++ spin_unlock_irqrestore(&gpio->lock, flags); ++} ++ ++static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set) ++{ ++ const struct aspeed_sgpio_bank *bank; ++ struct aspeed_sgpio *gpio; ++ unsigned long flags; ++ u32 reg, bit; ++ void __iomem *addr; ++ int rc, offset; ++ ++ rc = irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); ++ if (rc) ++ return; ++ ++ if (!bank->support_irq) ++ return; ++ ++ addr = bank_reg(gpio, bank, reg_irq_enable); ++ ++ spin_lock_irqsave(&gpio->lock, flags); ++ ++ reg = ioread32(addr); ++ if (set) ++ reg |= bit; ++ else ++ reg &= ~bit; ++ ++ iowrite32(reg, addr); ++ ++ spin_unlock_irqrestore(&gpio->lock, flags); ++} ++ ++static void aspeed_sgpio_irq_mask(struct irq_data *d) ++{ ++ aspeed_sgpio_irq_set_mask(d, false); ++} ++ ++static void aspeed_sgpio_irq_unmask(struct irq_data *d) ++{ ++ aspeed_sgpio_irq_set_mask(d, true); ++} ++ ++static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type) ++{ ++ u32 type0 = 0; ++ u32 type1 = 0; ++ u32 type2 = 0; ++ u32 bit, reg; ++ const struct aspeed_sgpio_bank *bank; ++ irq_flow_handler_t handler; ++ struct aspeed_sgpio *gpio; ++ unsigned long flags; ++ void __iomem *addr; ++ int rc, offset; ++ ++ rc = irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); ++ if (rc) ++ return -EINVAL; ++ ++ if (!bank->support_irq) ++ return -ENOTSUPP; ++ ++ switch (type & IRQ_TYPE_SENSE_MASK) { ++ case IRQ_TYPE_EDGE_BOTH: ++ type2 |= bit; ++ /* fall through */ ++ case IRQ_TYPE_EDGE_RISING: ++ type0 |= bit; ++ /* fall through */ ++ case IRQ_TYPE_EDGE_FALLING: ++ handler = handle_edge_irq; ++ break; ++ case IRQ_TYPE_LEVEL_HIGH: ++ type0 |= bit; ++ /* fall through */ ++ case IRQ_TYPE_LEVEL_LOW: ++ type1 |= bit; ++ handler = handle_level_irq; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ spin_lock_irqsave(&gpio->lock, flags); ++ ++ addr = bank_reg(gpio, bank, reg_irq_type0); ++ reg = ioread32(addr); ++ reg = (reg & ~bit) | type0; ++ iowrite32(reg, addr); ++ ++ addr = bank_reg(gpio, bank, reg_irq_type1); ++ reg = ioread32(addr); ++ reg = (reg & ~bit) | type1; ++ iowrite32(reg, addr); ++ ++ addr = bank_reg(gpio, bank, reg_irq_type2); ++ reg = ioread32(addr); ++ reg = (reg & ~bit) | type2; ++ iowrite32(reg, addr); ++ ++ spin_unlock_irqrestore(&gpio->lock, flags); ++ ++ irq_set_handler_locked(d, handler); ++ ++ return 0; ++} ++ ++static void aspeed_sgpio_irq_handler(struct irq_desc *desc) ++{ ++ struct gpio_chip *gc = irq_desc_get_handler_data(desc); ++ struct aspeed_sgpio *data = gpiochip_get_data(gc); ++ struct irq_chip *ic = irq_desc_get_chip(desc); ++ unsigned int i, p, girq; ++ unsigned long reg; ++ ++ chained_irq_enter(ic, desc); ++ ++ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { ++ const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i]; ++ ++ if (!bank->support_irq) ++ continue; ++ ++ reg = ioread32(bank_reg(data, bank, reg_irq_status)); ++ ++ for_each_set_bit(p, ®, 32) { ++ girq = irq_find_mapping(gc->irq.domain, i * 32 + p); ++ generic_handle_irq(girq); ++ } ++ } ++ ++ chained_irq_exit(ic, desc); ++} ++ ++static void aspeed_sgpio_init_irq_valid_mask(struct gpio_chip *gc, ++ unsigned long *valid_mask, ++ unsigned int ngpios) ++{ ++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc); ++ const struct aspeed_bank_props *props = gpio->config->props; ++ ++ while (!is_bank_props_sentinel(props)) { ++ unsigned int offset; ++ const unsigned long int input = props->input; ++ ++ /* Pretty crummy approach, but similar to GPIO core */ ++ for_each_clear_bit(offset, &input, 32) { ++ unsigned int i = props->bank * 32 + offset; ++ ++ if (i >= gpio->chip.ngpio) ++ break; ++ ++ clear_bit(i, valid_mask); ++ } ++ ++ props++; ++ } ++} ++ ++static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio, ++ struct platform_device *pdev) ++{ ++ const struct aspeed_sgpio_bank *bank; ++ struct gpio_irq_chip *girq; ++ int rc, i; ++ ++ /* Initialize IRQ and tolerant settings */ ++ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { ++ bank = &aspeed_sgpio_banks[i]; ++ ++ /* Value will be reset by WDT reset */ ++ iowrite32(0x00000000, bank_reg(gpio, bank, reg_tolerance)); ++ ++ if (!bank->support_irq) ++ continue; ++ ++ /* disable irq enable bits */ ++ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable)); ++ /* clear status bits */ ++ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status)); ++ /* set rising or level-high irq */ ++ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type0)); ++ /* trigger type is level */ ++ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type1)); ++ /* single trigger mode */ ++ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2)); ++ } ++ ++ rc = platform_get_irq(pdev, 0); ++ if (rc < 0) ++ return rc; ++ ++ gpio->irq = rc; ++ girq = &gpio->chip.irq; ++ girq->chip = &gpio->irqc; ++ girq->chip->name = dev_name(&pdev->dev); ++ girq->chip->irq_ack = aspeed_sgpio_irq_ack; ++ girq->chip->irq_mask = aspeed_sgpio_irq_mask; ++ girq->chip->irq_unmask = aspeed_sgpio_irq_unmask; ++ girq->chip->irq_set_type = aspeed_sgpio_set_type; ++ girq->parent_handler = aspeed_sgpio_irq_handler; ++ girq->num_parents = 1; ++ girq->parents = devm_kcalloc(&pdev->dev, 1, ++ sizeof(*girq->parents), ++ GFP_KERNEL); ++ if (!girq->parents) ++ return -ENOMEM; ++ girq->parents[0] = gpio->irq; ++ girq->default_type = IRQ_TYPE_NONE; ++ girq->handler = handle_bad_irq; ++ girq->init_valid_mask = aspeed_sgpio_init_irq_valid_mask; ++ ++ return 0; ++} ++ ++static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip, ++ unsigned int offset, bool enable) ++{ ++ struct aspeed_sgpio *gpio = gpiochip_get_data(chip); ++ unsigned long flags; ++ void __iomem *treg; ++ u32 val; ++ ++ treg = bank_reg(gpio, to_bank(offset), reg_tolerance); ++ ++ spin_lock_irqsave(&gpio->lock, flags); ++ ++ val = readl(treg); ++ ++ if (enable) ++ val |= GPIO_BIT(offset); ++ else ++ val &= ~GPIO_BIT(offset); ++ ++ writel(val, treg); ++ ++ spin_unlock_irqrestore(&gpio->lock, flags); ++ ++ return 0; ++} ++ ++static int aspeed_sgpio_set_config(struct gpio_chip *chip, unsigned int offset, ++ unsigned long config) ++{ ++ unsigned long param = pinconf_to_config_param(config); ++ u32 arg = pinconf_to_config_argument(config); ++ ++ if (param == PIN_CONFIG_PERSIST_STATE) ++ return aspeed_sgpio_reset_tolerance(chip, offset, arg); ++ ++ return -ENOTSUPP; ++} ++ ++/* ++ * Any banks not specified in a struct aspeed_bank_props array are assumed to ++ * have the properties: ++ * ++ * { .input = 0xffffffff, .output = 0xffffffff } ++ */ ++ ++static const struct aspeed_bank_props ast_sgpio_bank_props[] = { ++ /* input output */ ++ { 0, 0x00000000, 0xffffffff }, /* OA/OB/OC/OD */ ++ { 1, 0x00000000, 0xffffffff }, /* OE/OF/OG/OH */ ++ { 2, 0x00000000, 0x0000ffff }, /* OI/OJ */ ++ { 3, 0xffffffff, 0x00000000 }, /* IA/IB/IC/ID */ ++ { 4, 0xffffffff, 0x00000000 }, /* IE/IF/IG/IH */ ++ { 5, 0x0000ffff, 0x00000000 }, /* II/IJ */ ++ { } ++}; ++ ++/* ++ * This H/W has 80 bidirectional lines so this driver provides total 160 lines ++ * for 80 outputs and 80 inputs. To simplify bank register manipulation, it ++ * uses 96 lines per each input and output set so total 192 lines it has. ++ */ ++static const struct aspeed_sgpio_config ast2400_config = ++ { .nr_pgpios = 224, .nr_gpios = 192, .props = ast_sgpio_bank_props }; ++ ++static const struct aspeed_sgpio_config ast2500_config = ++ { .nr_pgpios = 232, .nr_gpios = 192, .props = ast_sgpio_bank_props }; ++ ++static const struct of_device_id aspeed_sgpio_of_table[] = { ++ { .compatible = "aspeed,ast2400-sgpio", .data = &ast2400_config }, ++ { .compatible = "aspeed,ast2500-sgpio", .data = &ast2500_config }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table); ++ ++static int __init aspeed_sgpio_probe(struct platform_device *pdev) ++{ ++ const struct of_device_id *gpio_id; ++ u32 sgpio_freq, clk_div, nb_gpios; ++ struct aspeed_sgpio *gpio; ++ unsigned long src_freq; ++ struct clk *clk; ++ int rc; ++ ++ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); ++ if (!gpio) ++ return -ENOMEM; ++ ++ gpio->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(gpio->base)) ++ return PTR_ERR(gpio->base); ++ ++ spin_lock_init(&gpio->lock); ++ ++ gpio_id = of_match_node(aspeed_sgpio_of_table, pdev->dev.of_node); ++ if (!gpio_id) ++ return -EINVAL; ++ ++ gpio->config = gpio_id->data; ++ ++ rc = device_property_read_u32(&pdev->dev, "bus-frequency", &sgpio_freq); ++ if (rc < 0) { ++ dev_warn(&pdev->dev, "Could not read bus-frequency property. Use default.\n"); ++ sgpio_freq = ASPEED_SGPIO_BUS_FREQ_DEFAULT; ++ } ++ ++ clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(clk)) { ++ rc = PTR_ERR(clk); ++ if (rc != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Failed to get clk source.\n"); ++ return rc; ++ } ++ ++ /* ++ * There is a limitation that SGPIO clock division has to be larger or ++ * equal to 1. And a read back value of clock division is 1-bit left ++ * shifted from the actual value. ++ * ++ * GPIO254[31:16] - Serial GPIO clock division: ++ * Serial GPIO clock period = period of PCLK * 2 * (GPIO254[31:16] + 1) ++ * ++ * SGPIO master controller updates every data input when SGPMLD is low. ++ * For an example, SGPIO clock is 1MHz and number of SGPIO is 80. Each ++ * SGPIO will be updated every 80us. ++ */ ++ src_freq = clk_get_rate(clk); ++ clk_div = src_freq / (2 * sgpio_freq) - 1; ++ if (clk_div < ASPEED_SGPIO_CLK_DIV_MIN) ++ clk_div = ASPEED_SGPIO_CLK_DIV_MIN; ++ else if (clk_div > ASPEED_SGPIO_CLK_DIV_MAX) ++ clk_div = ASPEED_SGPIO_CLK_DIV_MAX; ++ ++ nb_gpios = gpio->config->nr_gpios / 16; ++ if (nb_gpios < ASPEED_SGPIO_PINBYTES_MIN) ++ nb_gpios = ASPEED_SGPIO_PINBYTES_MIN; ++ else if (nb_gpios > ASPEED_SGPIO_PINBYTES_MAX) ++ nb_gpios = ASPEED_SGPIO_PINBYTES_MAX; ++ ++ iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, clk_div) | ++ FIELD_PREP(ASPEED_SGPIO_PINBYTES_MASK, nb_gpios) | ++ ASPEED_SGPIO_ENABLE, ++ gpio->base + ASPEED_SGPIO_CTRL); ++ ++ gpio->chip.parent = &pdev->dev; ++ gpio->chip.ngpio = gpio->config->nr_gpios; ++ ++ gpio->chip.direction_input = aspeed_sgpio_dir_in; ++ gpio->chip.direction_output = aspeed_sgpio_dir_out; ++ gpio->chip.get_direction = aspeed_sgpio_get_direction; ++ gpio->chip.get = aspeed_sgpio_get; ++ gpio->chip.set = aspeed_sgpio_set; ++ gpio->chip.set_config = aspeed_sgpio_set_config; ++ gpio->chip.label = dev_name(&pdev->dev); ++ gpio->chip.base = -1; ++ ++ rc = aspeed_sgpio_setup_irqs(gpio, pdev); ++ if (rc < 0) ++ return rc; ++ ++ return devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); ++} ++ ++static struct platform_driver aspeed_sgpio_driver = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = aspeed_sgpio_of_table, ++ }, ++}; ++ ++module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe); ++ ++MODULE_AUTHOR("Jae Hyun Yoo "); ++MODULE_DESCRIPTION("Aspeed SGPIO Master Driver"); ++MODULE_LICENSE("GPL v2"); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0017-SGPIO-DT-and-pinctrl-fixup.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0017-SGPIO-DT-and-pinctrl-fixup.patch new file mode 100644 index 000000000..6bfcb43c4 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0017-SGPIO-DT-and-pinctrl-fixup.patch @@ -0,0 +1,202 @@ +From 4c5ab7c103b693096ae719abd16bc80b81043beb Mon Sep 17 00:00:00 2001 +From: Vernon Mauery +Date: Wed, 16 May 2018 10:03:14 -0700 +Subject: [PATCH] SGPIO DT and pinctrl fixup + +This commit fixes DT and pinctrl for SGPIO use. + +Signed-off-by: Vernon Mauery +Signed-off-by: Jae Hyun Yoo +--- + arch/arm/boot/dts/aspeed-g4.dtsi | 56 +++++++++++------------------- + arch/arm/boot/dts/aspeed-g5.dtsi | 5 +++ + drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c | 48 ++++++++++++------------- + 3 files changed, 49 insertions(+), 60 deletions(-) + +diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi +index cc78564b2f8d..ee86b41af291 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -255,6 +255,20 @@ + #interrupt-cells = <2>; + }; + ++ sgpio: sgpio@1e780200 { ++ #gpio-cells = <2>; ++ gpio-controller; ++ compatible = "aspeed,ast2400-sgpio"; ++ reg = <0x1e780200 0x0100>; ++ interrupts = <40>; ++ interrupt-controller; ++ clocks = <&syscon ASPEED_CLK_APB>; ++ bus-frequency = <1000000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_sgpm_default>; ++ status = "disabled"; ++ }; ++ + timer: timer@1e782000 { + /* This timer is a Faraday FTTMR010 derivative */ + compatible = "aspeed,ast2400-timer"; +@@ -1228,44 +1242,14 @@ + groups = "SD2"; + }; + +- pinctrl_sgpmck_default: sgpmck_default { +- function = "SGPMCK"; +- groups = "SGPMCK"; +- }; +- +- pinctrl_sgpmi_default: sgpmi_default { +- function = "SGPMI"; +- groups = "SGPMI"; +- }; +- +- pinctrl_sgpmld_default: sgpmld_default { +- function = "SGPMLD"; +- groups = "SGPMLD"; +- }; +- +- pinctrl_sgpmo_default: sgpmo_default { +- function = "SGPMO"; +- groups = "SGPMO"; +- }; +- +- pinctrl_sgpsck_default: sgpsck_default { +- function = "SGPSCK"; +- groups = "SGPSCK"; +- }; +- +- pinctrl_sgpsi0_default: sgpsi0_default { +- function = "SGPSI0"; +- groups = "SGPSI0"; +- }; +- +- pinctrl_sgpsi1_default: sgpsi1_default { +- function = "SGPSI1"; +- groups = "SGPSI1"; ++ pinctrl_sgpm_default: sgpm_default { ++ function = "SGPM"; ++ groups = "SGPM"; + }; + +- pinctrl_sgpsld_default: sgpsld_default { +- function = "SGPSLD"; +- groups = "SGPSLD"; ++ pinctrl_sgps_default: sgps_default { ++ function = "SGPS"; ++ groups = "SGPS"; + }; + + pinctrl_sioonctrl_default: sioonctrl_default { +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index 271f3c96456a..128e0b5bbae2 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -326,6 +326,11 @@ + reg = <0x1e780200 0x0100>; + interrupts = <40>; + interrupt-controller; ++ clocks = <&syscon ASPEED_CLK_APB>; ++ bus-frequency = <1000000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_sgpm_default>; ++ status = "disabled"; + }; + + rtc: rtc@1e781000 { +diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c +index 95ea593fa29d..70284c5f9ad9 100644 +--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c ++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c +@@ -430,16 +430,22 @@ SSSF_PIN_DECL(E16, GPIOF6, TXD4, SIG_DESC_SET(SCU80, 30)); + SSSF_PIN_DECL(C17, GPIOF7, RXD4, SIG_DESC_SET(SCU80, 31)); + + #define A14 48 +-SSSF_PIN_DECL(A14, GPIOG0, SGPSCK, SIG_DESC_SET(SCU84, 0)); ++SIG_EXPR_LIST_DECL_SINGLE(A14, SGPSCK, SGPS, SIG_DESC_SET(SCU84, 0)); ++PIN_DECL_1(A14, GPIOG0, SGPSCK); + + #define E13 49 +-SSSF_PIN_DECL(E13, GPIOG1, SGPSLD, SIG_DESC_SET(SCU84, 1)); ++SIG_EXPR_LIST_DECL_SINGLE(E13, SGPSLD, SGPS, SIG_DESC_SET(SCU84, 1)); ++PIN_DECL_1(E13, GPIOG1, SGPSLD); + + #define D13 50 +-SSSF_PIN_DECL(D13, GPIOG2, SGPSI0, SIG_DESC_SET(SCU84, 2)); ++SIG_EXPR_LIST_DECL_SINGLE(D13, SGPSIO, SGPS, SIG_DESC_SET(SCU84, 2)); ++PIN_DECL_1(D13, GPIOG2, SGPSIO); + + #define C13 51 +-SSSF_PIN_DECL(C13, GPIOG3, SGPSI1, SIG_DESC_SET(SCU84, 3)); ++SIG_EXPR_LIST_DECL_SINGLE(C13, SGPSI1, SGPS, SIG_DESC_SET(SCU84, 3)); ++PIN_DECL_1(C13, GPIOG3, SGPSI1); ++ ++FUNC_GROUP_DECL(SGPS, A14, E13, D13, C13); + + #define B13 52 + SIG_EXPR_LIST_DECL_SINGLE(B13, OSCCLK, OSCCLK, SIG_DESC_SET(SCU2C, 1)); +@@ -613,16 +619,22 @@ FUNC_GROUP_DECL(SPI1PASSTHRU, C22, G18, D19, C20, B22, G19, C18, E20); + FUNC_GROUP_DECL(VGABIOS_ROM, B22, G19, C18, E20); + + #define J5 72 +-SSSF_PIN_DECL(J5, GPIOJ0, SGPMCK, SIG_DESC_SET(SCU84, 8)); ++SIG_EXPR_LIST_DECL_SINGLE(J5, SGPMCK, SGPM, SIG_DESC_SET(SCU84, 8)); ++PIN_DECL_1(J5, GPIOJ0, SGPMCK); + + #define J4 73 +-SSSF_PIN_DECL(J4, GPIOJ1, SGPMLD, SIG_DESC_SET(SCU84, 9)); ++SIG_EXPR_LIST_DECL_SINGLE(J4, SGPMLD, SGPM, SIG_DESC_SET(SCU84, 9)); ++PIN_DECL_1(J4, GPIOJ1, SGPMLD); + + #define K5 74 +-SSSF_PIN_DECL(K5, GPIOJ2, SGPMO, SIG_DESC_SET(SCU84, 10)); ++SIG_EXPR_LIST_DECL_SINGLE(K5, SGPMO, SGPM, SIG_DESC_SET(SCU84, 10)); ++PIN_DECL_1(K5, GPIOJ2, SGPMO); + + #define J3 75 +-SSSF_PIN_DECL(J3, GPIOJ3, SGPMI, SIG_DESC_SET(SCU84, 11)); ++SIG_EXPR_LIST_DECL_SINGLE(J3, SGPMI, SGPM, SIG_DESC_SET(SCU84, 11)); ++PIN_DECL_1(J3, GPIOJ3, SGPMI); ++ ++FUNC_GROUP_DECL(SGPM, J5, J4, K5, J3); + + #define T4 76 + SSSF_PIN_DECL(T4, GPIOJ4, VGAHS, SIG_DESC_SET(SCU84, 12)); +@@ -2234,14 +2246,8 @@ static const struct aspeed_pin_group aspeed_g4_groups[] = { + ASPEED_PINCTRL_GROUP(SALT4), + ASPEED_PINCTRL_GROUP(SD1), + ASPEED_PINCTRL_GROUP(SD2), +- ASPEED_PINCTRL_GROUP(SGPMCK), +- ASPEED_PINCTRL_GROUP(SGPMI), +- ASPEED_PINCTRL_GROUP(SGPMLD), +- ASPEED_PINCTRL_GROUP(SGPMO), +- ASPEED_PINCTRL_GROUP(SGPSCK), +- ASPEED_PINCTRL_GROUP(SGPSI0), +- ASPEED_PINCTRL_GROUP(SGPSI1), +- ASPEED_PINCTRL_GROUP(SGPSLD), ++ ASPEED_PINCTRL_GROUP(SGPM), ++ ASPEED_PINCTRL_GROUP(SGPS), + ASPEED_PINCTRL_GROUP(SIOONCTRL), + ASPEED_PINCTRL_GROUP(SIOPBI), + ASPEED_PINCTRL_GROUP(SIOPBO), +@@ -2389,14 +2395,8 @@ static const struct aspeed_pin_function aspeed_g4_functions[] = { + ASPEED_PINCTRL_FUNC(SALT4), + ASPEED_PINCTRL_FUNC(SD1), + ASPEED_PINCTRL_FUNC(SD2), +- ASPEED_PINCTRL_FUNC(SGPMCK), +- ASPEED_PINCTRL_FUNC(SGPMI), +- ASPEED_PINCTRL_FUNC(SGPMLD), +- ASPEED_PINCTRL_FUNC(SGPMO), +- ASPEED_PINCTRL_FUNC(SGPSCK), +- ASPEED_PINCTRL_FUNC(SGPSI0), +- ASPEED_PINCTRL_FUNC(SGPSI1), +- ASPEED_PINCTRL_FUNC(SGPSLD), ++ ASPEED_PINCTRL_FUNC(SGPM), ++ ASPEED_PINCTRL_FUNC(SGPS), + ASPEED_PINCTRL_FUNC(SIOONCTRL), + ASPEED_PINCTRL_FUNC(SIOPBI), + ASPEED_PINCTRL_FUNC(SIOPBO), +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0018-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0018-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch new file mode 100644 index 000000000..77e413125 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0018-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch @@ -0,0 +1,5611 @@ +From edeea958f026102ce28c8b760f7a96b9ffd7f65a Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo +Date: Mon, 7 Jan 2019 09:56:10 -0800 +Subject: [PATCH] Update PECI drivers to sync with linux upstreaming version + +Upstreaming is in holding. It's for adding DTS sensor with PECI +subsystem code update. + +Signed-off-by: Jae Hyun Yoo +Signed-off-by: Jason M. Bills +--- + Documentation/hwmon/peci-cputemp | 34 +- + drivers/hwmon/Kconfig | 4 +- + drivers/hwmon/peci-cputemp.c | 171 +++--- + drivers/hwmon/peci-dimmtemp.c | 184 +++++-- + drivers/hwmon/peci-hwmon.h | 9 +- + drivers/mfd/Kconfig | 5 +- + drivers/mfd/intel-peci-client.c | 51 +- + drivers/peci/Kconfig | 46 +- + drivers/peci/Makefile | 7 +- + drivers/peci/busses/Kconfig | 32 ++ + drivers/peci/busses/Makefile | 7 + + drivers/peci/busses/peci-aspeed.c | 492 +++++++++++++++++ + drivers/peci/busses/peci-npcm.c | 410 +++++++++++++++ + drivers/peci/peci-aspeed.c | 505 ------------------ + drivers/peci/peci-core.c | 959 +++++++++++++++++++--------------- + drivers/peci/peci-dev.c | 346 ++++++++++++ + drivers/peci/peci-npcm.c | 410 --------------- + include/linux/mfd/intel-peci-client.h | 31 +- + include/linux/peci.h | 30 +- + include/uapi/linux/peci-ioctl.h | 416 +++++++++------ + 20 files changed, 2446 insertions(+), 1703 deletions(-) + create mode 100644 drivers/peci/busses/Kconfig + create mode 100644 drivers/peci/busses/Makefile + create mode 100644 drivers/peci/busses/peci-aspeed.c + create mode 100644 drivers/peci/busses/peci-npcm.c + delete mode 100644 drivers/peci/peci-aspeed.c + create mode 100644 drivers/peci/peci-dev.c + delete mode 100644 drivers/peci/peci-npcm.c + +diff --git a/Documentation/hwmon/peci-cputemp b/Documentation/hwmon/peci-cputemp +index 821a925..a3a3e46 100644 +--- a/Documentation/hwmon/peci-cputemp ++++ b/Documentation/hwmon/peci-cputemp +@@ -51,28 +51,38 @@ temp1_crit Provides shutdown temperature of the CPU package which + temp1_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of + the CPU package. + +-temp2_label "Tcontrol" +-temp2_input Provides current Tcontrol temperature of the CPU ++temp2_label "DTS" ++temp2_input Provides current DTS temperature of the CPU package. ++temp2_max Provides thermal control temperature of the CPU package ++ which is also known as Tcontrol. ++temp2_crit Provides shutdown temperature of the CPU package which ++ is also known as the maximum processor junction ++ temperature, Tjmax or Tprochot. ++temp2_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of ++ the CPU package. ++ ++temp3_label "Tcontrol" ++temp3_input Provides current Tcontrol temperature of the CPU + package which is also known as Fan Temperature target. + Indicates the relative value from thermal monitor trip + temperature at which fans should be engaged. +-temp2_crit Provides Tcontrol critical value of the CPU package ++temp3_crit Provides Tcontrol critical value of the CPU package + which is same to Tjmax. + +-temp3_label "Tthrottle" +-temp3_input Provides current Tthrottle temperature of the CPU ++temp4_label "Tthrottle" ++temp4_input Provides current Tthrottle temperature of the CPU + package. Used for throttling temperature. If this value + is allowed and lower than Tjmax - the throttle will + occur and reported at lower than Tjmax. + +-temp4_label "Tjmax" +-temp4_input Provides the maximum junction temperature, Tjmax of the ++temp5_label "Tjmax" ++temp5_input Provides the maximum junction temperature, Tjmax of the + CPU package. + +-temp[5-*]_label Provides string "Core X", where X is resolved core ++temp[6-*]_label Provides string "Core X", where X is resolved core + number. +-temp[5-*]_input Provides current temperature of each core. +-temp[5-*]_max Provides thermal control temperature of the core. +-temp[5-*]_crit Provides shutdown temperature of the core. +-temp[5-*]_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of ++temp[6-*]_input Provides current temperature of each core. ++temp[6-*]_max Provides thermal control temperature of the core. ++temp[6-*]_crit Provides shutdown temperature of the core. ++temp[6-*]_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of + the core. +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index c0623fa..7399c3c 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -1333,7 +1333,7 @@ config SENSORS_PECI_CPUTEMP + the PECI Client Command Suite via the processor PECI client. + Check Documentation/hwmon/peci-cputemp for details. + +- This driver can also be built as a module. If so, the module ++ This driver can also be built as a module. If so, the module + will be called peci-cputemp. + + config SENSORS_PECI_DIMMTEMP +@@ -1347,7 +1347,7 @@ config SENSORS_PECI_DIMMTEMP + Suite via the processor PECI client. + Check Documentation/hwmon/peci-dimmtemp for details. + +- This driver can also be built as a module. If so, the module ++ This driver can also be built as a module. If so, the module + will be called peci-dimmtemp. + + source "drivers/hwmon/pmbus/Kconfig" +diff --git a/drivers/hwmon/peci-cputemp.c b/drivers/hwmon/peci-cputemp.c +index 11880c8..d0d68e8 100644 +--- a/drivers/hwmon/peci-cputemp.c ++++ b/drivers/hwmon/peci-cputemp.c +@@ -1,5 +1,5 @@ + // SPDX-License-Identifier: GPL-2.0 +-// Copyright (c) 2018 Intel Corporation ++// Copyright (c) 2018-2019 Intel Corporation + + #include + #include +@@ -9,18 +9,13 @@ + #include + #include "peci-hwmon.h" + +-#define DEFAULT_CHANNEL_NUMS 4 ++#define DEFAULT_CHANNEL_NUMS 5 + #define CORETEMP_CHANNEL_NUMS CORE_NUMS_MAX + #define CPUTEMP_CHANNEL_NUMS (DEFAULT_CHANNEL_NUMS + CORETEMP_CHANNEL_NUMS) + +-/* The RESOLVED_CORES register in PCU of a client CPU */ +-#define REG_RESOLVED_CORES_BUS 1 +-#define REG_RESOLVED_CORES_DEVICE 30 +-#define REG_RESOLVED_CORES_FUNCTION 3 +-#define REG_RESOLVED_CORES_OFFSET 0xB4 +- + struct temp_group { + struct temp_data die; ++ struct temp_data dts; + struct temp_data tcontrol; + struct temp_data tthrottle; + struct temp_data tjmax; +@@ -43,6 +38,7 @@ struct peci_cputemp { + + enum cputemp_channels { + channel_die, ++ channel_dts, + channel_tcontrol, + channel_tthrottle, + channel_tjmax, +@@ -54,6 +50,10 @@ static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = { + HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_CRIT_HYST, + ++ /* DTS margin */ ++ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_CRIT_HYST, ++ + /* Tcontrol temperature */ + HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_CRIT, + +@@ -70,6 +70,7 @@ static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = { + + static const char *cputemp_label[CPUTEMP_CHANNEL_NUMS] = { + "Die", ++ "DTS", + "Tcontrol", + "Tthrottle", + "Tjmax", +@@ -92,19 +93,20 @@ static int get_temp_targets(struct peci_cputemp *priv) + s32 tthrottle_offset; + s32 tcontrol_margin; + u8 pkg_cfg[4]; +- int rc; ++ int ret; + +- /** ++ /* + * Just use only the tcontrol marker to determine if target values need + * update. + */ + if (!peci_temp_need_update(&priv->temp.tcontrol)) + return 0; + +- rc = peci_client_read_package_config(priv->mgr, +- MBX_INDEX_TEMP_TARGET, 0, pkg_cfg); +- if (rc) +- return rc; ++ ret = peci_client_read_package_config(priv->mgr, ++ PECI_MBX_INDEX_TEMP_TARGET, 0, ++ pkg_cfg); ++ if (ret) ++ return ret; + + priv->temp.tjmax.value = pkg_cfg[2] * 1000; + +@@ -123,17 +125,16 @@ static int get_temp_targets(struct peci_cputemp *priv) + static int get_die_temp(struct peci_cputemp *priv) + { + struct peci_get_temp_msg msg; +- int rc; ++ int ret; + + if (!peci_temp_need_update(&priv->temp.die)) + return 0; + + msg.addr = priv->mgr->client->addr; + +- rc = peci_command(priv->mgr->client->adapter, PECI_CMD_GET_TEMP, +- &msg); +- if (rc) +- return rc; ++ ret = peci_command(priv->mgr->client->adapter, PECI_CMD_GET_TEMP, &msg); ++ if (ret) ++ return ret; + + /* Note that the tjmax should be available before calling it */ + priv->temp.die.value = priv->temp.tjmax.value + +@@ -144,24 +145,64 @@ static int get_die_temp(struct peci_cputemp *priv) + return 0; + } + ++static int get_dts(struct peci_cputemp *priv) ++{ ++ s32 dts_margin; ++ u8 pkg_cfg[4]; ++ int ret; ++ ++ if (!peci_temp_need_update(&priv->temp.dts)) ++ return 0; ++ ++ ret = peci_client_read_package_config(priv->mgr, ++ PECI_MBX_INDEX_DTS_MARGIN, 0, ++ pkg_cfg); ++ ++ if (ret) ++ return ret; ++ ++ dts_margin = (pkg_cfg[1] << 8) | pkg_cfg[0]; ++ ++ /** ++ * Processors return a value of DTS reading in 10.6 format ++ * (10 bits signed decimal, 6 bits fractional). ++ * Error codes: ++ * 0x8000: General sensor error ++ * 0x8001: Reserved ++ * 0x8002: Underflow on reading value ++ * 0x8003-0x81ff: Reserved ++ */ ++ if (dts_margin >= 0x8000 && dts_margin <= 0x81ff) ++ return -EIO; ++ ++ dts_margin = ten_dot_six_to_millidegree(dts_margin); ++ ++ /* Note that the tcontrol should be available before calling it */ ++ priv->temp.dts.value = priv->temp.tcontrol.value - dts_margin; ++ ++ peci_temp_mark_updated(&priv->temp.dts); ++ ++ return 0; ++} ++ + static int get_core_temp(struct peci_cputemp *priv, int core_index) + { + s32 core_dts_margin; + u8 pkg_cfg[4]; +- int rc; ++ int ret; + + if (!peci_temp_need_update(&priv->temp.core[core_index])) + return 0; + +- rc = peci_client_read_package_config(priv->mgr, +- MBX_INDEX_PER_CORE_DTS_TEMP, +- core_index, pkg_cfg); +- if (rc) +- return rc; ++ ret = peci_client_read_package_config(priv->mgr, ++ PECI_MBX_INDEX_PER_CORE_DTS_TEMP, ++ core_index, pkg_cfg); ++ if (ret) ++ return ret; + + core_dts_margin = le16_to_cpup((__le16 *)pkg_cfg); + +- /** ++ /* + * Processors return a value of the core DTS reading in 10.6 format + * (10 bits signed decimal, 6 bits fractional). + * Error codes: +@@ -192,6 +233,7 @@ static int cputemp_read_string(struct device *dev, + return -EOPNOTSUPP; + + *str = cputemp_label[channel]; ++ + return 0; + } + +@@ -200,26 +242,33 @@ static int cputemp_read(struct device *dev, + u32 attr, int channel, long *val) + { + struct peci_cputemp *priv = dev_get_drvdata(dev); +- int rc, core_index; ++ int ret, core_index; + + if (channel >= CPUTEMP_CHANNEL_NUMS || + !(priv->temp_config[channel] & BIT(attr))) + return -EOPNOTSUPP; + +- rc = get_temp_targets(priv); +- if (rc) +- return rc; ++ ret = get_temp_targets(priv); ++ if (ret) ++ return ret; + + switch (attr) { + case hwmon_temp_input: + switch (channel) { + case channel_die: +- rc = get_die_temp(priv); +- if (rc) ++ ret = get_die_temp(priv); ++ if (ret) + break; + + *val = priv->temp.die.value; + break; ++ case channel_dts: ++ ret = get_dts(priv); ++ if (ret) ++ break; ++ ++ *val = priv->temp.dts.value; ++ break; + case channel_tcontrol: + *val = priv->temp.tcontrol.value; + break; +@@ -231,8 +280,8 @@ static int cputemp_read(struct device *dev, + break; + default: + core_index = channel - DEFAULT_CHANNEL_NUMS; +- rc = get_core_temp(priv, core_index); +- if (rc) ++ ret = get_core_temp(priv, core_index); ++ if (ret) + break; + + *val = priv->temp.core[core_index].value; +@@ -249,11 +298,11 @@ static int cputemp_read(struct device *dev, + *val = priv->temp.tjmax.value - priv->temp.tcontrol.value; + break; + default: +- rc = -EOPNOTSUPP; ++ ret = -EOPNOTSUPP; + break; + } + +- return rc; ++ return ret; + } + + static umode_t cputemp_is_visible(const void *data, +@@ -262,11 +311,11 @@ static umode_t cputemp_is_visible(const void *data, + { + const struct peci_cputemp *priv = data; + +- if (priv->temp_config[channel] & BIT(attr)) +- if (channel < DEFAULT_CHANNEL_NUMS || +- (channel >= DEFAULT_CHANNEL_NUMS && +- (priv->core_mask & BIT(channel - DEFAULT_CHANNEL_NUMS)))) +- return 0444; ++ if ((priv->temp_config[channel] & BIT(attr)) && ++ (channel < DEFAULT_CHANNEL_NUMS || ++ (channel >= DEFAULT_CHANNEL_NUMS && ++ (priv->core_mask & BIT(channel - DEFAULT_CHANNEL_NUMS))))) ++ return 0444; + + return 0; + } +@@ -280,40 +329,43 @@ static const struct hwmon_ops cputemp_ops = { + static int check_resolved_cores(struct peci_cputemp *priv) + { + struct peci_rd_pci_cfg_local_msg msg; +- int rc; ++ int ret; + + /* Get the RESOLVED_CORES register value */ + msg.addr = priv->mgr->client->addr; +- msg.bus = REG_RESOLVED_CORES_BUS; +- msg.device = REG_RESOLVED_CORES_DEVICE; +- msg.function = REG_RESOLVED_CORES_FUNCTION; +- msg.reg = REG_RESOLVED_CORES_OFFSET; ++ msg.bus = 1; ++ msg.device = 30; ++ msg.function = 3; ++ msg.reg = 0xb4; + msg.rx_len = 4; + +- rc = peci_command(priv->mgr->client->adapter, +- PECI_CMD_RD_PCI_CFG_LOCAL, &msg); +- if (rc) +- return rc; ++ ret = peci_command(priv->mgr->client->adapter, ++ PECI_CMD_RD_PCI_CFG_LOCAL, &msg); ++ if (msg.cc != PECI_DEV_CC_SUCCESS) ++ ret = -EAGAIN; ++ if (ret) ++ return ret; + + priv->core_mask = le32_to_cpup((__le32 *)msg.pci_config); + if (!priv->core_mask) + return -EAGAIN; + + dev_dbg(priv->dev, "Scanned resolved cores: 0x%x\n", priv->core_mask); ++ + return 0; + } + + static int create_core_temp_info(struct peci_cputemp *priv) + { +- int rc, i; ++ int ret, i; + +- rc = check_resolved_cores(priv); +- if (rc) +- return rc; ++ ret = check_resolved_cores(priv); ++ if (ret) ++ return ret; + + for (i = 0; i < priv->gen_info->core_max; i++) + if (priv->core_mask & BIT(i)) +- while (i + DEFAULT_CHANNEL_NUMS >= priv->config_idx) ++ while (priv->config_idx <= i + DEFAULT_CHANNEL_NUMS) + priv->temp_config[priv->config_idx++] = + config_table[channel_core]; + +@@ -326,7 +378,7 @@ static int peci_cputemp_probe(struct platform_device *pdev) + struct device *dev = &pdev->dev; + struct peci_cputemp *priv; + struct device *hwmon_dev; +- int rc; ++ int ret; + + if ((mgr->client->adapter->cmd_mask & + (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) != +@@ -346,12 +398,13 @@ static int peci_cputemp_probe(struct platform_device *pdev) + mgr->client->addr - PECI_BASE_ADDR); + + priv->temp_config[priv->config_idx++] = config_table[channel_die]; ++ priv->temp_config[priv->config_idx++] = config_table[channel_dts]; + priv->temp_config[priv->config_idx++] = config_table[channel_tcontrol]; + priv->temp_config[priv->config_idx++] = config_table[channel_tthrottle]; + priv->temp_config[priv->config_idx++] = config_table[channel_tjmax]; + +- rc = create_core_temp_info(priv); +- if (rc) ++ ret = create_core_temp_info(priv); ++ if (ret) + dev_dbg(dev, "Skipped creating core temp info\n"); + + priv->chip.ops = &cputemp_ops; +@@ -385,7 +438,7 @@ MODULE_DEVICE_TABLE(platform, peci_cputemp_ids); + static struct platform_driver peci_cputemp_driver = { + .probe = peci_cputemp_probe, + .id_table = peci_cputemp_ids, +- .driver = { .name = "peci-cputemp", }, ++ .driver = { .name = KBUILD_MODNAME, }, + }; + module_platform_driver(peci_cputemp_driver); + +diff --git a/drivers/hwmon/peci-dimmtemp.c b/drivers/hwmon/peci-dimmtemp.c +index 86a45a9..a404b6e 100644 +--- a/drivers/hwmon/peci-dimmtemp.c ++++ b/drivers/hwmon/peci-dimmtemp.c +@@ -1,5 +1,5 @@ + // SPDX-License-Identifier: GPL-2.0 +-// Copyright (c) 2018 Intel Corporation ++// Copyright (c) 2018-2019 Intel Corporation + + #include + #include +@@ -21,6 +21,8 @@ struct peci_dimmtemp { + struct workqueue_struct *work_queue; + struct delayed_work work_handler; + struct temp_data temp[DIMM_NUMS_MAX]; ++ long temp_max[DIMM_NUMS_MAX]; ++ long temp_crit[DIMM_NUMS_MAX]; + u32 dimm_mask; + int retry_count; + u32 temp_config[DIMM_NUMS_MAX + 1]; +@@ -44,20 +46,106 @@ static int get_dimm_temp(struct peci_dimmtemp *priv, int dimm_no) + { + int dimm_order = dimm_no % priv->gen_info->dimm_idx_max; + int chan_rank = dimm_no / priv->gen_info->dimm_idx_max; ++ struct peci_rd_pci_cfg_local_msg rp_msg; + u8 cfg_data[4]; +- int rc; ++ int ret; + + if (!peci_temp_need_update(&priv->temp[dimm_no])) + return 0; + +- rc = peci_client_read_package_config(priv->mgr, +- MBX_INDEX_DDR_DIMM_TEMP, +- chan_rank, cfg_data); +- if (rc) +- return rc; ++ ret = peci_client_read_package_config(priv->mgr, ++ PECI_MBX_INDEX_DDR_DIMM_TEMP, ++ chan_rank, cfg_data); ++ if (ret) ++ return ret; + + priv->temp[dimm_no].value = cfg_data[dimm_order] * 1000; + ++ switch (priv->gen_info->model) { ++ case INTEL_FAM6_SKYLAKE_X: ++ rp_msg.addr = priv->mgr->client->addr; ++ rp_msg.bus = 2; ++ /* ++ * Device 10, Function 2: IMC 0 channel 0 -> rank 0 ++ * Device 10, Function 6: IMC 0 channel 1 -> rank 1 ++ * Device 11, Function 2: IMC 0 channel 2 -> rank 2 ++ * Device 12, Function 2: IMC 1 channel 0 -> rank 3 ++ * Device 12, Function 6: IMC 1 channel 1 -> rank 4 ++ * Device 13, Function 2: IMC 1 channel 2 -> rank 5 ++ */ ++ rp_msg.device = 10 + chan_rank / 3 * 2 + ++ (chan_rank % 3 == 2 ? 1 : 0); ++ rp_msg.function = chan_rank % 3 == 1 ? 6 : 2; ++ rp_msg.reg = 0x120 + dimm_order * 4; ++ rp_msg.rx_len = 4; ++ ++ ret = peci_command(priv->mgr->client->adapter, ++ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg); ++ if (rp_msg.cc != PECI_DEV_CC_SUCCESS) ++ ret = -EAGAIN; ++ if (ret) ++ return ret; ++ ++ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000; ++ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000; ++ break; ++ case INTEL_FAM6_SKYLAKE_XD: ++ rp_msg.addr = priv->mgr->client->addr; ++ rp_msg.bus = 2; ++ /* ++ * Device 10, Function 2: IMC 0 channel 0 -> rank 0 ++ * Device 10, Function 6: IMC 0 channel 1 -> rank 1 ++ * Device 12, Function 2: IMC 1 channel 0 -> rank 2 ++ * Device 12, Function 6: IMC 1 channel 1 -> rank 3 ++ */ ++ rp_msg.device = 10 + chan_rank / 2 * 2; ++ rp_msg.function = chan_rank % 2 ? 6 : 2; ++ rp_msg.reg = 0x120 + dimm_order * 4; ++ rp_msg.rx_len = 4; ++ ++ ret = peci_command(priv->mgr->client->adapter, ++ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg); ++ if (rp_msg.cc != PECI_DEV_CC_SUCCESS) ++ ret = -EAGAIN; ++ if (ret) ++ return ret; ++ ++ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000; ++ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000; ++ break; ++ case INTEL_FAM6_HASWELL_X: ++ case INTEL_FAM6_BROADWELL_X: ++ rp_msg.addr = priv->mgr->client->addr; ++ rp_msg.bus = 1; ++ /* ++ * Device 20, Function 0: IMC 0 channel 0 -> rank 0 ++ * Device 20, Function 1: IMC 0 channel 1 -> rank 1 ++ * Device 21, Function 0: IMC 0 channel 2 -> rank 2 ++ * Device 21, Function 1: IMC 0 channel 3 -> rank 3 ++ * Device 23, Function 0: IMC 1 channel 0 -> rank 4 ++ * Device 23, Function 1: IMC 1 channel 1 -> rank 5 ++ * Device 24, Function 0: IMC 1 channel 2 -> rank 6 ++ * Device 24, Function 1: IMC 1 channel 3 -> rank 7 ++ */ ++ rp_msg.device = 20 + chan_rank / 2 + chan_rank / 4; ++ rp_msg.function = chan_rank % 2; ++ rp_msg.reg = 0x120 + dimm_order * 4; ++ rp_msg.rx_len = 4; ++ ++ ret = peci_command(priv->mgr->client->adapter, ++ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg); ++ if (rp_msg.cc != PECI_DEV_CC_SUCCESS) ++ ret = -EAGAIN; ++ if (ret) ++ return ret; ++ ++ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000; ++ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ + peci_temp_mark_updated(&priv->temp[dimm_no]); + + return 0; +@@ -77,6 +165,7 @@ static int dimmtemp_read_string(struct device *dev, + chan_rank = channel / dimm_idx_max; + dimm_idx = channel % dimm_idx_max; + *str = dimmtemp_label[chan_rank][dimm_idx]; ++ + return 0; + } + +@@ -84,17 +173,28 @@ static int dimmtemp_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) + { + struct peci_dimmtemp *priv = dev_get_drvdata(dev); +- int rc; +- +- if (attr != hwmon_temp_input) +- return -EOPNOTSUPP; +- +- rc = get_dimm_temp(priv, channel); +- if (rc) +- return rc; ++ int ret; ++ ++ ret = get_dimm_temp(priv, channel); ++ if (ret) ++ return ret; ++ ++ switch (attr) { ++ case hwmon_temp_input: ++ *val = priv->temp[channel].value; ++ break; ++ case hwmon_temp_max: ++ *val = priv->temp_max[channel]; ++ break; ++ case hwmon_temp_crit: ++ *val = priv->temp_crit[channel]; ++ break; ++ default: ++ ret = -EOPNOTSUPP; ++ break; ++ } + +- *val = priv->temp[channel].value; +- return 0; ++ return ret; + } + + static umode_t dimmtemp_is_visible(const void *data, +@@ -120,16 +220,16 @@ static int check_populated_dimms(struct peci_dimmtemp *priv) + { + u32 chan_rank_max = priv->gen_info->chan_rank_max; + u32 dimm_idx_max = priv->gen_info->dimm_idx_max; +- int chan_rank, dimm_idx, rc; ++ int chan_rank, dimm_idx, ret; + u8 cfg_data[4]; + + for (chan_rank = 0; chan_rank < chan_rank_max; chan_rank++) { +- rc = peci_client_read_package_config(priv->mgr, +- MBX_INDEX_DDR_DIMM_TEMP, +- chan_rank, cfg_data); +- if (rc) { ++ ret = peci_client_read_package_config(priv->mgr, ++ PECI_MBX_INDEX_DDR_DIMM_TEMP, ++ chan_rank, cfg_data); ++ if (ret) { + priv->dimm_mask = 0; +- return rc; ++ return ret; + } + + for (dimm_idx = 0; dimm_idx < dimm_idx_max; dimm_idx++) +@@ -143,17 +243,18 @@ static int check_populated_dimms(struct peci_dimmtemp *priv) + return -EAGAIN; + + dev_dbg(priv->dev, "Scanned populated DIMMs: 0x%x\n", priv->dimm_mask); ++ + return 0; + } + + static int create_dimm_temp_info(struct peci_dimmtemp *priv) + { +- int rc, i, config_idx, channels; ++ int ret, i, config_idx, channels; + struct device *hwmon_dev; + +- rc = check_populated_dimms(priv); +- if (rc) { +- if (rc == -EAGAIN) { ++ ret = check_populated_dimms(priv); ++ if (ret) { ++ if (ret == -EAGAIN) { + if (priv->retry_count < DIMM_MASK_CHECK_RETRY_MAX) { + queue_delayed_work(priv->work_queue, + &priv->work_handler, +@@ -164,11 +265,11 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv) + } else { + dev_err(priv->dev, + "Timeout DIMM temp info creation\n"); +- rc = -ETIMEDOUT; ++ ret = -ETIMEDOUT; + } + } + +- return rc; ++ return ret; + } + + channels = priv->gen_info->chan_rank_max * +@@ -177,7 +278,8 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv) + if (priv->dimm_mask & BIT(i)) + while (i >= config_idx) + priv->temp_config[config_idx++] = +- HWMON_T_LABEL | HWMON_T_INPUT; ++ HWMON_T_LABEL | HWMON_T_INPUT | ++ HWMON_T_MAX | HWMON_T_CRIT; + + priv->chip.ops = &dimmtemp_ops; + priv->chip.info = priv->info; +@@ -192,12 +294,12 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv) + priv, + &priv->chip, + NULL); +- rc = PTR_ERR_OR_ZERO(hwmon_dev); +- if (!rc) ++ ret = PTR_ERR_OR_ZERO(hwmon_dev); ++ if (!ret) + dev_dbg(priv->dev, "%s: sensor '%s'\n", + dev_name(hwmon_dev), priv->name); + +- return rc; ++ return ret; + } + + static void create_dimm_temp_info_delayed(struct work_struct *work) +@@ -205,10 +307,10 @@ static void create_dimm_temp_info_delayed(struct work_struct *work) + struct delayed_work *dwork = to_delayed_work(work); + struct peci_dimmtemp *priv = container_of(dwork, struct peci_dimmtemp, + work_handler); +- int rc; ++ int ret; + +- rc = create_dimm_temp_info(priv); +- if (rc && rc != -EAGAIN) ++ ret = create_dimm_temp_info(priv); ++ if (ret && ret != -EAGAIN) + dev_dbg(priv->dev, "Failed to create DIMM temp info\n"); + } + +@@ -217,7 +319,7 @@ static int peci_dimmtemp_probe(struct platform_device *pdev) + struct peci_client_manager *mgr = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct peci_dimmtemp *priv; +- int rc; ++ int ret; + + if ((mgr->client->adapter->cmd_mask & + (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) != +@@ -242,8 +344,8 @@ static int peci_dimmtemp_probe(struct platform_device *pdev) + + INIT_DELAYED_WORK(&priv->work_handler, create_dimm_temp_info_delayed); + +- rc = create_dimm_temp_info(priv); +- if (rc && rc != -EAGAIN) { ++ ret = create_dimm_temp_info(priv); ++ if (ret && ret != -EAGAIN) { + dev_err(dev, "Failed to create DIMM temp info\n"); + goto err_free_wq; + } +@@ -252,7 +354,7 @@ static int peci_dimmtemp_probe(struct platform_device *pdev) + + err_free_wq: + destroy_workqueue(priv->work_queue); +- return rc; ++ return ret; + } + + static int peci_dimmtemp_remove(struct platform_device *pdev) +@@ -275,7 +377,7 @@ static struct platform_driver peci_dimmtemp_driver = { + .probe = peci_dimmtemp_probe, + .remove = peci_dimmtemp_remove, + .id_table = peci_dimmtemp_ids, +- .driver = { .name = "peci-dimmtemp", }, ++ .driver = { .name = KBUILD_MODNAME, }, + }; + module_platform_driver(peci_dimmtemp_driver); + +diff --git a/drivers/hwmon/peci-hwmon.h b/drivers/hwmon/peci-hwmon.h +index 6ca1855..ce6b470 100644 +--- a/drivers/hwmon/peci-hwmon.h ++++ b/drivers/hwmon/peci-hwmon.h +@@ -1,5 +1,5 @@ + /* SPDX-License-Identifier: GPL-2.0 */ +-/* Copyright (c) 2018 Intel Corporation */ ++/* Copyright (c) 2018-2019 Intel Corporation */ + + #ifndef __PECI_HWMON_H + #define __PECI_HWMON_H +@@ -29,11 +29,8 @@ struct temp_data { + */ + static inline bool peci_temp_need_update(struct temp_data *temp) + { +- if (temp->valid && +- time_before(jiffies, temp->last_updated + UPDATE_INTERVAL)) +- return false; +- +- return true; ++ return !temp->valid || ++ time_after(jiffies, temp->last_updated + UPDATE_INTERVAL); + } + + /** +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index 5d89546..46f52a3 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -630,7 +630,7 @@ config MFD_INTEL_MSIC + devices used in Intel Medfield platforms. + + config MFD_INTEL_PECI_CLIENT +- bool "Intel PECI client" ++ tristate "Intel PECI client" + depends on (PECI || COMPILE_TEST) + select MFD_CORE + help +@@ -643,6 +643,9 @@ config MFD_INTEL_PECI_CLIENT + Additional drivers must be enabled in order to use the functionality + of the device. + ++ This driver can also be built as a module. If so, the module ++ will be called intel-peci-client. ++ + config MFD_IPAQ_MICRO + bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support" + depends on SA1100_H3100 || SA1100_H3600 +diff --git a/drivers/mfd/intel-peci-client.c b/drivers/mfd/intel-peci-client.c +index d53e4f1..18bf0af 100644 +--- a/drivers/mfd/intel-peci-client.c ++++ b/drivers/mfd/intel-peci-client.c +@@ -1,12 +1,12 @@ + // SPDX-License-Identifier: GPL-2.0 +-// Copyright (c) 2018 Intel Corporation ++// Copyright (c) 2018-2019 Intel Corporation + + #include + #include + #include + #include +-#include + #include ++#include + + #define CPU_ID_MODEL_MASK GENMASK(7, 4) + #define CPU_ID_FAMILY_MASK GENMASK(11, 8) +@@ -18,12 +18,6 @@ + #define LOWER_BYTE_MASK GENMASK(7, 0) + #define UPPER_BYTE_MASK GENMASK(16, 8) + +-enum cpu_gens { +- CPU_GEN_HSX = 0, /* Haswell Xeon */ +- CPU_GEN_BRX, /* Broadwell Xeon */ +- CPU_GEN_SKX, /* Skylake Xeon */ +-}; +- + static struct mfd_cell peci_functions[] = { + { .name = "peci-cputemp", }, + { .name = "peci-dimmtemp", }, +@@ -31,38 +25,45 @@ static struct mfd_cell peci_functions[] = { + }; + + static const struct cpu_gen_info cpu_gen_info_table[] = { +- [CPU_GEN_HSX] = { ++ { /* Haswell Xeon */ + .family = 6, /* Family code */ + .model = INTEL_FAM6_HASWELL_X, + .core_max = CORE_MAX_ON_HSX, + .chan_rank_max = CHAN_RANK_MAX_ON_HSX, + .dimm_idx_max = DIMM_IDX_MAX_ON_HSX }, +- [CPU_GEN_BRX] = { ++ { /* Broadwell Xeon */ + .family = 6, /* Family code */ + .model = INTEL_FAM6_BROADWELL_X, + .core_max = CORE_MAX_ON_BDX, + .chan_rank_max = CHAN_RANK_MAX_ON_BDX, + .dimm_idx_max = DIMM_IDX_MAX_ON_BDX }, +- [CPU_GEN_SKX] = { ++ { /* Skylake Xeon */ + .family = 6, /* Family code */ + .model = INTEL_FAM6_SKYLAKE_X, + .core_max = CORE_MAX_ON_SKX, + .chan_rank_max = CHAN_RANK_MAX_ON_SKX, + .dimm_idx_max = DIMM_IDX_MAX_ON_SKX }, ++ { /* Skylake Xeon D */ ++ .family = 6, /* Family code */ ++ .model = INTEL_FAM6_SKYLAKE_XD, ++ .core_max = CORE_MAX_ON_SKXD, ++ .chan_rank_max = CHAN_RANK_MAX_ON_SKXD, ++ .dimm_idx_max = DIMM_IDX_MAX_ON_SKXD }, + }; + + static int peci_client_get_cpu_gen_info(struct peci_client_manager *priv) + { ++ struct device *dev = &priv->client->dev; + u32 cpu_id; + u16 family; + u8 model; +- int rc; ++ int ret; + int i; + +- rc = peci_get_cpu_id(priv->client->adapter, priv->client->addr, +- &cpu_id); +- if (rc) +- return rc; ++ ret = peci_get_cpu_id(priv->client->adapter, priv->client->addr, ++ &cpu_id); ++ if (ret) ++ return ret; + + family = FIELD_PREP(LOWER_BYTE_MASK, + FIELD_GET(CPU_ID_FAMILY_MASK, cpu_id)) | +@@ -83,11 +84,11 @@ static int peci_client_get_cpu_gen_info(struct peci_client_manager *priv) + } + + if (!priv->gen_info) { +- dev_err(priv->dev, "Can't support this CPU: 0x%x\n", cpu_id); +- rc = -ENODEV; ++ dev_err(dev, "Can't support this CPU: 0x%x\n", cpu_id); ++ ret = -ENODEV; + } + +- return rc; ++ return ret; + } + + static int peci_client_probe(struct peci_client *client) +@@ -103,31 +104,29 @@ static int peci_client_probe(struct peci_client *client) + + dev_set_drvdata(dev, priv); + priv->client = client; +- priv->dev = dev; + cpu_no = client->addr - PECI_BASE_ADDR; + + ret = peci_client_get_cpu_gen_info(priv); + if (ret) + return ret; + +- ret = devm_mfd_add_devices(priv->dev, cpu_no, peci_functions, ++ ret = devm_mfd_add_devices(dev, cpu_no, peci_functions, + ARRAY_SIZE(peci_functions), NULL, 0, NULL); + if (ret < 0) { +- dev_err(priv->dev, "Failed to register child devices: %d\n", +- ret); ++ dev_err(dev, "Failed to register child devices: %d\n", ret); + return ret; + } + + return 0; + } + +-#ifdef CONFIG_OF ++#if IS_ENABLED(CONFIG_OF) + static const struct of_device_id peci_client_of_table[] = { + { .compatible = "intel,peci-client" }, + { } + }; + MODULE_DEVICE_TABLE(of, peci_client_of_table); +-#endif ++#endif /* CONFIG_OF */ + + static const struct peci_device_id peci_client_ids[] = { + { .name = "peci-client" }, +@@ -139,7 +138,7 @@ static struct peci_driver peci_client_driver = { + .probe = peci_client_probe, + .id_table = peci_client_ids, + .driver = { +- .name = "peci-client", ++ .name = KBUILD_MODNAME, + .of_match_table = of_match_ptr(peci_client_of_table), + }, + }; +diff --git a/drivers/peci/Kconfig b/drivers/peci/Kconfig +index 7293108..9752fee 100644 +--- a/drivers/peci/Kconfig ++++ b/drivers/peci/Kconfig +@@ -2,10 +2,12 @@ + # Platform Environment Control Interface (PECI) subsystem configuration + # + ++menu "PECI support" ++ + config PECI +- bool "PECI support" +- select RT_MUTEXES ++ tristate "PECI support" + select CRC8 ++ default n + help + The Platform Environment Control Interface (PECI) is a one-wire bus + interface that provides a communication channel from Intel processors +@@ -14,37 +16,23 @@ config PECI + If you want PECI support, you should say Y here and also to the + specific driver for your bus adapter(s) below. + +-if PECI +- +-# +-# PECI hardware bus configuration +-# +- +-menu "PECI Hardware Bus support" +- +-config PECI_ASPEED +- tristate "ASPEED PECI support" +- select REGMAP_MMIO +- depends on OF +- depends on ARCH_ASPEED || COMPILE_TEST +- help +- Say Y here if you want support for the Platform Environment Control +- Interface (PECI) bus adapter driver on the ASPEED SoCs. ++ This support is also available as a module. If so, the module ++ will be called peci-core. + +- This support is also available as a module. If so, the module +- will be called peci-aspeed. ++if PECI + +-config PECI_NPCM +- tristate "Nuvoton NPCM PECI support" +- select REGMAP_MMIO +- depends on OF +- depends on ARCH_NPCM || COMPILE_TEST ++config PECI_CHARDEV ++ tristate "PECI device interface" + help +- Say Y here if you want support for the Platform Environment Control +- Interface (PECI) bus adapter driver on the Nuvoton NPCM SoCs. ++ Say Y here to use peci-* device files, usually found in the /dev ++ directory on your system. They make it possible to have user-space ++ programs use the PECI bus. + + This support is also available as a module. If so, the module +- will be called peci-npcm. +-endmenu ++ will be called peci-dev. ++ ++source "drivers/peci/busses/Kconfig" + + endif # PECI ++ ++endmenu +diff --git a/drivers/peci/Makefile b/drivers/peci/Makefile +index 3326da5..da8b0a3 100644 +--- a/drivers/peci/Makefile ++++ b/drivers/peci/Makefile +@@ -1,10 +1,11 @@ ++# SPDX-License-Identifier: GPL-2.0 + # +-# Makefile for the PECI core and bus drivers. ++# Makefile for the PECI core drivers. + # + + # Core functionality + obj-$(CONFIG_PECI) += peci-core.o ++obj-$(CONFIG_PECI_CHARDEV) += peci-dev.o + + # Hardware specific bus drivers +-obj-$(CONFIG_PECI_ASPEED) += peci-aspeed.o +-obj-$(CONFIG_PECI_NPCM) += peci-npcm.o ++obj-y += busses/ +diff --git a/drivers/peci/busses/Kconfig b/drivers/peci/busses/Kconfig +new file mode 100644 +index 0000000..bfacafb +--- /dev/null ++++ b/drivers/peci/busses/Kconfig +@@ -0,0 +1,32 @@ ++# ++# PECI hardware bus configuration ++# ++ ++menu "PECI Hardware Bus support" ++ ++config PECI_ASPEED ++ tristate "ASPEED PECI support" ++ depends on ARCH_ASPEED || COMPILE_TEST ++ depends on OF ++ depends on PECI ++ help ++ Say Y here if you want support for the Platform Environment Control ++ Interface (PECI) bus adapter driver on the ASPEED SoCs. ++ ++ This support is also available as a module. If so, the module ++ will be called peci-aspeed. ++ ++config PECI_NPCM ++ tristate "Nuvoton NPCM PECI support" ++ select REGMAP_MMIO ++ depends on OF ++ depends on ARCH_NPCM || COMPILE_TEST ++ depends on PECI ++ help ++ Say Y here if you want support for the Platform Environment Control ++ Interface (PECI) bus adapter driver on the Nuvoton NPCM SoCs. ++ ++ This support is also available as a module. If so, the module ++ will be called peci-npcm. ++ ++endmenu +diff --git a/drivers/peci/busses/Makefile b/drivers/peci/busses/Makefile +new file mode 100644 +index 0000000..aa8ce3a +--- /dev/null ++++ b/drivers/peci/busses/Makefile +@@ -0,0 +1,7 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Makefile for the PECI hardware bus drivers. ++# ++ ++obj-$(CONFIG_PECI_ASPEED) += peci-aspeed.o ++obj-$(CONFIG_PECI_NPCM) += peci-npcm.o +diff --git a/drivers/peci/busses/peci-aspeed.c b/drivers/peci/busses/peci-aspeed.c +new file mode 100644 +index 0000000..851b71e3 +--- /dev/null ++++ b/drivers/peci/busses/peci-aspeed.c +@@ -0,0 +1,492 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (C) 2012-2017 ASPEED Technology Inc. ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ASPEED PECI Registers */ ++/* Control Register */ ++#define ASPEED_PECI_CTRL 0x00 ++#define ASPEED_PECI_CTRL_SAMPLING_MASK GENMASK(19, 16) ++#define ASPEED_PECI_CTRL_READ_MODE_MASK GENMASK(13, 12) ++#define ASPEED_PECI_CTRL_READ_MODE_COUNT BIT(12) ++#define ASPEED_PECI_CTRL_READ_MODE_DBG BIT(13) ++#define ASPEED_PECI_CTRL_CLK_SOURCE_MASK BIT(11) ++#define ASPEED_PECI_CTRL_CLK_DIV_MASK GENMASK(10, 8) ++#define ASPEED_PECI_CTRL_INVERT_OUT BIT(7) ++#define ASPEED_PECI_CTRL_INVERT_IN BIT(6) ++#define ASPEED_PECI_CTRL_BUS_CONTENT_EN BIT(5) ++#define ASPEED_PECI_CTRL_PECI_EN BIT(4) ++#define ASPEED_PECI_CTRL_PECI_CLK_EN BIT(0) ++ ++/* Timing Negotiation Register */ ++#define ASPEED_PECI_TIMING_NEGOTIATION 0x04 ++#define ASPEED_PECI_TIMING_MESSAGE_MASK GENMASK(15, 8) ++#define ASPEED_PECI_TIMING_ADDRESS_MASK GENMASK(7, 0) ++ ++/* Command Register */ ++#define ASPEED_PECI_CMD 0x08 ++#define ASPEED_PECI_CMD_PIN_MON BIT(31) ++#define ASPEED_PECI_CMD_STS_MASK GENMASK(27, 24) ++#define ASPEED_PECI_CMD_IDLE_MASK (ASPEED_PECI_CMD_STS_MASK | \ ++ ASPEED_PECI_CMD_PIN_MON) ++#define ASPEED_PECI_CMD_FIRE BIT(0) ++ ++/* Read/Write Length Register */ ++#define ASPEED_PECI_RW_LENGTH 0x0c ++#define ASPEED_PECI_AW_FCS_EN BIT(31) ++#define ASPEED_PECI_READ_LEN_MASK GENMASK(23, 16) ++#define ASPEED_PECI_WRITE_LEN_MASK GENMASK(15, 8) ++#define ASPEED_PECI_TAGET_ADDR_MASK GENMASK(7, 0) ++ ++/* Expected FCS Data Register */ ++#define ASPEED_PECI_EXP_FCS 0x10 ++#define ASPEED_PECI_EXP_READ_FCS_MASK GENMASK(23, 16) ++#define ASPEED_PECI_EXP_AW_FCS_AUTO_MASK GENMASK(15, 8) ++#define ASPEED_PECI_EXP_WRITE_FCS_MASK GENMASK(7, 0) ++ ++/* Captured FCS Data Register */ ++#define ASPEED_PECI_CAP_FCS 0x14 ++#define ASPEED_PECI_CAP_READ_FCS_MASK GENMASK(23, 16) ++#define ASPEED_PECI_CAP_WRITE_FCS_MASK GENMASK(7, 0) ++ ++/* Interrupt Register */ ++#define ASPEED_PECI_INT_CTRL 0x18 ++#define ASPEED_PECI_TIMING_NEGO_SEL_MASK GENMASK(31, 30) ++#define ASPEED_PECI_1ST_BIT_OF_ADDR_NEGO 0 ++#define ASPEED_PECI_2ND_BIT_OF_ADDR_NEGO 1 ++#define ASPEED_PECI_MESSAGE_NEGO 2 ++#define ASPEED_PECI_INT_MASK GENMASK(4, 0) ++#define ASPEED_PECI_INT_BUS_TIMEOUT BIT(4) ++#define ASPEED_PECI_INT_BUS_CONNECT BIT(3) ++#define ASPEED_PECI_INT_W_FCS_BAD BIT(2) ++#define ASPEED_PECI_INT_W_FCS_ABORT BIT(1) ++#define ASPEED_PECI_INT_CMD_DONE BIT(0) ++ ++/* Interrupt Status Register */ ++#define ASPEED_PECI_INT_STS 0x1c ++#define ASPEED_PECI_INT_TIMING_RESULT_MASK GENMASK(29, 16) ++ /* bits[4..0]: Same bit fields in the 'Interrupt Register' */ ++ ++/* Rx/Tx Data Buffer Registers */ ++#define ASPEED_PECI_W_DATA0 0x20 ++#define ASPEED_PECI_W_DATA1 0x24 ++#define ASPEED_PECI_W_DATA2 0x28 ++#define ASPEED_PECI_W_DATA3 0x2c ++#define ASPEED_PECI_R_DATA0 0x30 ++#define ASPEED_PECI_R_DATA1 0x34 ++#define ASPEED_PECI_R_DATA2 0x38 ++#define ASPEED_PECI_R_DATA3 0x3c ++#define ASPEED_PECI_W_DATA4 0x40 ++#define ASPEED_PECI_W_DATA5 0x44 ++#define ASPEED_PECI_W_DATA6 0x48 ++#define ASPEED_PECI_W_DATA7 0x4c ++#define ASPEED_PECI_R_DATA4 0x50 ++#define ASPEED_PECI_R_DATA5 0x54 ++#define ASPEED_PECI_R_DATA6 0x58 ++#define ASPEED_PECI_R_DATA7 0x5c ++#define ASPEED_PECI_DATA_BUF_SIZE_MAX 32 ++ ++/* Timing Negotiation */ ++#define ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT 8 ++#define ASPEED_PECI_RD_SAMPLING_POINT_MAX 15 ++#define ASPEED_PECI_CLK_DIV_DEFAULT 0 ++#define ASPEED_PECI_CLK_DIV_MAX 7 ++#define ASPEED_PECI_MSG_TIMING_DEFAULT 1 ++#define ASPEED_PECI_MSG_TIMING_MAX 255 ++#define ASPEED_PECI_ADDR_TIMING_DEFAULT 1 ++#define ASPEED_PECI_ADDR_TIMING_MAX 255 ++ ++/* Timeout */ ++#define ASPEED_PECI_IDLE_CHECK_TIMEOUT_USEC 50000 ++#define ASPEED_PECI_IDLE_CHECK_INTERVAL_USEC 10000 ++#define ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT 1000 ++#define ASPEED_PECI_CMD_TIMEOUT_MS_MAX 60000 ++ ++struct aspeed_peci { ++ struct peci_adapter *adapter; ++ struct device *dev; ++ void __iomem *base; ++ struct clk *clk; ++ struct reset_control *rst; ++ int irq; ++ spinlock_t lock; /* to sync completion status handling */ ++ struct completion xfer_complete; ++ u32 status; ++ u32 cmd_timeout_ms; ++}; ++ ++static int aspeed_peci_check_idle(struct aspeed_peci *priv) ++{ ++ ulong timeout = jiffies + usecs_to_jiffies(ASPEED_PECI_IDLE_CHECK_TIMEOUT_USEC); ++ u32 cmd_sts; ++ ++ for (;;) { ++ cmd_sts = readl(priv->base + ASPEED_PECI_CMD); ++ if (!(cmd_sts & ASPEED_PECI_CMD_IDLE_MASK)) ++ break; ++ if (time_after(jiffies, timeout)) { ++ cmd_sts = readl(priv->base + ASPEED_PECI_CMD); ++ break; ++ } ++ usleep_range((ASPEED_PECI_IDLE_CHECK_INTERVAL_USEC >> 2) + 1, ++ ASPEED_PECI_IDLE_CHECK_INTERVAL_USEC); ++ } ++ ++ return !(cmd_sts & ASPEED_PECI_CMD_IDLE_MASK) ? 0 : -ETIMEDOUT; ++} ++ ++static int aspeed_peci_xfer(struct peci_adapter *adapter, ++ struct peci_xfer_msg *msg) ++{ ++ struct aspeed_peci *priv = peci_get_adapdata(adapter); ++ long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms); ++ u32 peci_head, peci_state, rx_data = 0; ++ ulong flags; ++ int i, ret; ++ uint reg; ++ ++ if (msg->tx_len > ASPEED_PECI_DATA_BUF_SIZE_MAX || ++ msg->rx_len > ASPEED_PECI_DATA_BUF_SIZE_MAX) ++ return -EINVAL; ++ ++ /* Check command sts and bus idle state */ ++ ret = aspeed_peci_check_idle(priv); ++ if (ret) ++ return ret; /* -ETIMEDOUT */ ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ reinit_completion(&priv->xfer_complete); ++ ++ peci_head = FIELD_PREP(ASPEED_PECI_TAGET_ADDR_MASK, msg->addr) | ++ FIELD_PREP(ASPEED_PECI_WRITE_LEN_MASK, msg->tx_len) | ++ FIELD_PREP(ASPEED_PECI_READ_LEN_MASK, msg->rx_len); ++ ++ writel(peci_head, priv->base + ASPEED_PECI_RW_LENGTH); ++ ++ for (i = 0; i < msg->tx_len; i += 4) { ++ reg = i < 16 ? ASPEED_PECI_W_DATA0 + i % 16 : ++ ASPEED_PECI_W_DATA4 + i % 16; ++ writel(le32_to_cpup((__le32 *)&msg->tx_buf[i]), ++ priv->base + reg); ++ } ++ ++ dev_dbg(priv->dev, "HEAD : 0x%08x\n", peci_head); ++ print_hex_dump_debug("TX : ", DUMP_PREFIX_NONE, 16, 1, ++ msg->tx_buf, msg->tx_len, true); ++ ++ priv->status = 0; ++ writel(ASPEED_PECI_CMD_FIRE, priv->base + ASPEED_PECI_CMD); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ err = wait_for_completion_interruptible_timeout(&priv->xfer_complete, ++ timeout); ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ dev_dbg(priv->dev, "INT_STS : 0x%08x\n", priv->status); ++ peci_state = readl(priv->base + ASPEED_PECI_CMD); ++ dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n", ++ FIELD_GET(ASPEED_PECI_CMD_STS_MASK, peci_state)); ++ ++ writel(0, priv->base + ASPEED_PECI_CMD); ++ ++ if (err <= 0 || priv->status != ASPEED_PECI_INT_CMD_DONE) { ++ if (err < 0) { /* -ERESTARTSYS */ ++ ret = (int)err; ++ goto err_irqrestore; ++ } else if (err == 0) { ++ dev_dbg(priv->dev, "Timeout waiting for a response!\n"); ++ ret = -ETIMEDOUT; ++ goto err_irqrestore; ++ } ++ ++ dev_dbg(priv->dev, "No valid response!\n"); ++ ret = -EIO; ++ goto err_irqrestore; ++ } ++ ++ /* ++ * Note that rx_len and rx_buf size can be an odd number. ++ * Byte handling is more efficient. ++ */ ++ for (i = 0; i < msg->rx_len; i++) { ++ u8 byte_offset = i % 4; ++ ++ if (byte_offset == 0) { ++ reg = i < 16 ? ASPEED_PECI_R_DATA0 + i % 16 : ++ ASPEED_PECI_R_DATA4 + i % 16; ++ rx_data = readl(priv->base + reg); ++ } ++ ++ msg->rx_buf[i] = (u8)(rx_data >> (byte_offset << 3)); ++ } ++ ++ print_hex_dump_debug("RX : ", DUMP_PREFIX_NONE, 16, 1, ++ msg->rx_buf, msg->rx_len, true); ++ ++ peci_state = readl(priv->base + ASPEED_PECI_CMD); ++ dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n", ++ FIELD_GET(ASPEED_PECI_CMD_STS_MASK, peci_state)); ++ dev_dbg(priv->dev, "------------------------\n"); ++ ++err_irqrestore: ++ spin_unlock_irqrestore(&priv->lock, flags); ++ return ret; ++} ++ ++static irqreturn_t aspeed_peci_irq_handler(int irq, void *arg) ++{ ++ struct aspeed_peci *priv = arg; ++ u32 status; ++ ++ spin_lock(&priv->lock); ++ status = readl(priv->base + ASPEED_PECI_INT_STS); ++ writel(status, priv->base + ASPEED_PECI_INT_STS); ++ priv->status |= (status & ASPEED_PECI_INT_MASK); ++ ++ /* ++ * In most cases, interrupt bits will be set one by one but also note ++ * that multiple interrupt bits could be set at the same time. ++ */ ++ if (status & ASPEED_PECI_INT_BUS_TIMEOUT) { ++ dev_dbg(priv->dev, "ASPEED_PECI_INT_BUS_TIMEOUT\n"); ++ } ++ ++ if (status & ASPEED_PECI_INT_BUS_CONNECT) { ++ dev_dbg(priv->dev, "ASPEED_PECI_INT_BUS_CONNECT\n"); ++ } ++ ++ if (status & ASPEED_PECI_INT_W_FCS_BAD) { ++ dev_dbg(priv->dev, "ASPEED_PECI_INT_W_FCS_BAD\n"); ++ } ++ ++ if (status & ASPEED_PECI_INT_W_FCS_ABORT) { ++ dev_dbg(priv->dev, "ASPEED_PECI_INT_W_FCS_ABORT\n"); ++ } ++ ++ /* ++ * All commands should be ended up with a ASPEED_PECI_INT_CMD_DONE bit ++ * set even in an error case. ++ */ ++ if (status & ASPEED_PECI_INT_CMD_DONE) { ++ dev_dbg(priv->dev, "ASPEED_PECI_INT_CMD_DONE\n"); ++ complete(&priv->xfer_complete); ++ } ++ ++ spin_unlock(&priv->lock); ++ return IRQ_HANDLED; ++} ++ ++static int aspeed_peci_init_ctrl(struct aspeed_peci *priv) ++{ ++ u32 msg_timing, addr_timing, rd_sampling_point; ++ u32 clk_freq, clk_divisor, clk_div_val = 0; ++ int ret; ++ ++ priv->clk = devm_clk_get(priv->dev, NULL); ++ if (IS_ERR(priv->clk)) { ++ dev_err(priv->dev, "Failed to get clk source.\n"); ++ return PTR_ERR(priv->clk); ++ } ++ ++ ret = clk_prepare_enable(priv->clk); ++ if (ret) { ++ dev_err(priv->dev, "Failed to enable clock.\n"); ++ return ret; ++ } ++ ++ ret = device_property_read_u32(priv->dev, "clock-frequency", &clk_freq); ++ if (ret) { ++ dev_err(priv->dev, ++ "Could not read clock-frequency property.\n"); ++ clk_disable_unprepare(priv->clk); ++ return ret; ++ } ++ ++ clk_divisor = clk_get_rate(priv->clk) / clk_freq; ++ ++ while ((clk_divisor >> 1) && (clk_div_val < ASPEED_PECI_CLK_DIV_MAX)) ++ clk_div_val++; ++ ++ ret = device_property_read_u32(priv->dev, "msg-timing", &msg_timing); ++ if (ret || msg_timing > ASPEED_PECI_MSG_TIMING_MAX) { ++ if (!ret) ++ dev_warn(priv->dev, ++ "Invalid msg-timing : %u, Use default : %u\n", ++ msg_timing, ASPEED_PECI_MSG_TIMING_DEFAULT); ++ msg_timing = ASPEED_PECI_MSG_TIMING_DEFAULT; ++ } ++ ++ ret = device_property_read_u32(priv->dev, "addr-timing", &addr_timing); ++ if (ret || addr_timing > ASPEED_PECI_ADDR_TIMING_MAX) { ++ if (!ret) ++ dev_warn(priv->dev, ++ "Invalid addr-timing : %u, Use default : %u\n", ++ addr_timing, ASPEED_PECI_ADDR_TIMING_DEFAULT); ++ addr_timing = ASPEED_PECI_ADDR_TIMING_DEFAULT; ++ } ++ ++ ret = device_property_read_u32(priv->dev, "rd-sampling-point", ++ &rd_sampling_point); ++ if (ret || rd_sampling_point > ASPEED_PECI_RD_SAMPLING_POINT_MAX) { ++ if (!ret) ++ dev_warn(priv->dev, ++ "Invalid rd-sampling-point : %u. Use default : %u\n", ++ rd_sampling_point, ++ ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT); ++ rd_sampling_point = ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT; ++ } ++ ++ ret = device_property_read_u32(priv->dev, "cmd-timeout-ms", ++ &priv->cmd_timeout_ms); ++ if (ret || priv->cmd_timeout_ms > ASPEED_PECI_CMD_TIMEOUT_MS_MAX || ++ priv->cmd_timeout_ms == 0) { ++ if (!ret) ++ dev_warn(priv->dev, ++ "Invalid cmd-timeout-ms : %u. Use default : %u\n", ++ priv->cmd_timeout_ms, ++ ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT); ++ priv->cmd_timeout_ms = ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT; ++ } ++ ++ writel(FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK, ++ ASPEED_PECI_CLK_DIV_DEFAULT) | ++ ASPEED_PECI_CTRL_PECI_CLK_EN, priv->base + ASPEED_PECI_CTRL); ++ ++ /* ++ * Timing negotiation period setting. ++ * The unit of the programmed value is 4 times of PECI clock period. ++ */ ++ writel(FIELD_PREP(ASPEED_PECI_TIMING_MESSAGE_MASK, msg_timing) | ++ FIELD_PREP(ASPEED_PECI_TIMING_ADDRESS_MASK, addr_timing), ++ priv->base + ASPEED_PECI_TIMING_NEGOTIATION); ++ ++ /* Clear interrupts */ ++ writel(readl(priv->base + ASPEED_PECI_INT_STS) | ASPEED_PECI_INT_MASK, ++ priv->base + ASPEED_PECI_INT_STS); ++ ++ /* Set timing negotiation mode and enable interrupts */ ++ writel(FIELD_PREP(ASPEED_PECI_TIMING_NEGO_SEL_MASK, ++ ASPEED_PECI_1ST_BIT_OF_ADDR_NEGO) | ++ ASPEED_PECI_INT_MASK, priv->base + ASPEED_PECI_INT_CTRL); ++ ++ /* Read sampling point and clock speed setting */ ++ writel(FIELD_PREP(ASPEED_PECI_CTRL_SAMPLING_MASK, rd_sampling_point) | ++ FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK, clk_div_val) | ++ ASPEED_PECI_CTRL_PECI_EN | ASPEED_PECI_CTRL_PECI_CLK_EN, ++ priv->base + ASPEED_PECI_CTRL); ++ ++ return 0; ++} ++ ++static int aspeed_peci_probe(struct platform_device *pdev) ++{ ++ struct peci_adapter *adapter; ++ struct aspeed_peci *priv; ++ int ret; ++ ++ adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv)); ++ if (!adapter) ++ return -ENOMEM; ++ ++ priv = peci_get_adapdata(adapter); ++ priv->adapter = adapter; ++ priv->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, priv); ++ ++ priv->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(priv->base)) { ++ ret = PTR_ERR(priv->base); ++ goto err_put_adapter_dev; ++ } ++ ++ priv->irq = platform_get_irq(pdev, 0); ++ if (!priv->irq) { ++ ret = -ENODEV; ++ goto err_put_adapter_dev; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_peci_irq_handler, ++ 0, "peci-aspeed-irq", priv); ++ if (ret) ++ goto err_put_adapter_dev; ++ ++ init_completion(&priv->xfer_complete); ++ spin_lock_init(&priv->lock); ++ ++ priv->adapter->owner = THIS_MODULE; ++ priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev)); ++ strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name)); ++ priv->adapter->xfer = aspeed_peci_xfer; ++ priv->adapter->use_dma = false; ++ ++ priv->rst = devm_reset_control_get(&pdev->dev, NULL); ++ if (IS_ERR(priv->rst)) { ++ dev_err(&pdev->dev, ++ "missing or invalid reset controller entry\n"); ++ ret = PTR_ERR(priv->rst); ++ goto err_put_adapter_dev; ++ } ++ reset_control_deassert(priv->rst); ++ ++ ret = aspeed_peci_init_ctrl(priv); ++ if (ret) ++ goto err_put_adapter_dev; ++ ++ ret = peci_add_adapter(priv->adapter); ++ if (ret) ++ goto err_put_adapter_dev; ++ ++ dev_info(&pdev->dev, "peci bus %d registered, irq %d\n", ++ priv->adapter->nr, priv->irq); ++ ++ return 0; ++ ++err_put_adapter_dev: ++ put_device(&adapter->dev); ++ return ret; ++} ++ ++static int aspeed_peci_remove(struct platform_device *pdev) ++{ ++ struct aspeed_peci *priv = dev_get_drvdata(&pdev->dev); ++ ++ clk_disable_unprepare(priv->clk); ++ reset_control_assert(priv->rst); ++ peci_del_adapter(priv->adapter); ++ of_node_put(priv->adapter->dev.of_node); ++ ++ return 0; ++} ++ ++static const struct of_device_id aspeed_peci_of_table[] = { ++ { .compatible = "aspeed,ast2400-peci", }, ++ { .compatible = "aspeed,ast2500-peci", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, aspeed_peci_of_table); ++ ++static struct platform_driver aspeed_peci_driver = { ++ .probe = aspeed_peci_probe, ++ .remove = aspeed_peci_remove, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = of_match_ptr(aspeed_peci_of_table), ++ }, ++}; ++module_platform_driver(aspeed_peci_driver); ++ ++MODULE_AUTHOR("Ryan Chen "); ++MODULE_AUTHOR("Jae Hyun Yoo "); ++MODULE_DESCRIPTION("ASPEED PECI driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/peci/busses/peci-npcm.c b/drivers/peci/busses/peci-npcm.c +new file mode 100644 +index 0000000..f632365 +--- /dev/null ++++ b/drivers/peci/busses/peci-npcm.c +@@ -0,0 +1,410 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2019 Nuvoton Technology corporation. ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* NPCM7xx GCR module */ ++#define NPCM7XX_INTCR3_OFFSET 0x9C ++#define NPCM7XX_INTCR3_PECIVSEL BIT(19) ++ ++/* NPCM PECI Registers */ ++#define NPCM_PECI_CTL_STS 0x00 ++#define NPCM_PECI_RD_LENGTH 0x04 ++#define NPCM_PECI_ADDR 0x08 ++#define NPCM_PECI_CMD 0x0C ++#define NPCM_PECI_CTL2 0x10 ++#define NPCM_PECI_WR_LENGTH 0x1C ++#define NPCM_PECI_PDDR 0x2C ++#define NPCM_PECI_DAT_INOUT(n) (0x100 + ((n) * 4)) ++ ++#define NPCM_PECI_MAX_REG 0x200 ++ ++/* NPCM_PECI_CTL_STS - 0x00 : Control Register */ ++#define NPCM_PECI_CTRL_DONE_INT_EN BIT(6) ++#define NPCM_PECI_CTRL_ABRT_ERR BIT(4) ++#define NPCM_PECI_CTRL_CRC_ERR BIT(3) ++#define NPCM_PECI_CTRL_DONE BIT(1) ++#define NPCM_PECI_CTRL_START_BUSY BIT(0) ++ ++/* NPCM_PECI_RD_LENGTH - 0x04 : Command Register */ ++#define NPCM_PECI_RD_LEN_MASK GENMASK(6, 0) ++ ++/* NPCM_PECI_CMD - 0x10 : Command Register */ ++#define NPCM_PECI_CTL2_MASK GENMASK(7, 6) ++ ++/* NPCM_PECI_WR_LENGTH - 0x1C : Command Register */ ++#define NPCM_PECI_WR_LEN_MASK GENMASK(6, 0) ++ ++/* NPCM_PECI_PDDR - 0x2C : Command Register */ ++#define NPCM_PECI_PDDR_MASK GENMASK(4, 0) ++ ++#define NPCM_PECI_INT_MASK (NPCM_PECI_CTRL_ABRT_ERR | \ ++ NPCM_PECI_CTRL_CRC_ERR | \ ++ NPCM_PECI_CTRL_DONE) ++ ++#define NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC 50000 ++#define NPCM_PECI_IDLE_CHECK_INTERVAL_USEC 10000 ++#define NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT 1000 ++#define NPCM_PECI_CMD_TIMEOUT_MS_MAX 60000 ++#define NPCM_PECI_HOST_NEG_BIT_RATE_MAX 31 ++#define NPCM_PECI_HOST_NEG_BIT_RATE_MIN 7 ++#define NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT 15 ++#define NPCM_PECI_PULL_DOWN_DEFAULT 0 ++#define NPCM_PECI_PULL_DOWN_MAX 2 ++ ++struct npcm_peci { ++ u32 cmd_timeout_ms; ++ u32 host_bit_rate; ++ struct completion xfer_complete; ++ struct regmap *gcr_regmap; ++ struct peci_adapter *adapter; ++ struct regmap *regmap; ++ u32 status; ++ spinlock_t lock; /* to sync completion status handling */ ++ struct device *dev; ++ struct clk *clk; ++ int irq; ++}; ++ ++static int npcm_peci_xfer_native(struct npcm_peci *priv, ++ struct peci_xfer_msg *msg) ++{ ++ long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms); ++ unsigned long flags; ++ unsigned int msg_rd; ++ u32 cmd_sts; ++ int i, rc; ++ ++ /* Check command sts and bus idle state */ ++ rc = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts, ++ !(cmd_sts & NPCM_PECI_CTRL_START_BUSY), ++ NPCM_PECI_IDLE_CHECK_INTERVAL_USEC, ++ NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC); ++ if (rc) ++ return rc; /* -ETIMEDOUT */ ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ reinit_completion(&priv->xfer_complete); ++ ++ regmap_write(priv->regmap, NPCM_PECI_ADDR, msg->addr); ++ regmap_write(priv->regmap, NPCM_PECI_RD_LENGTH, ++ NPCM_PECI_WR_LEN_MASK & msg->rx_len); ++ regmap_write(priv->regmap, NPCM_PECI_WR_LENGTH, ++ NPCM_PECI_WR_LEN_MASK & msg->tx_len); ++ ++ if (msg->tx_len) { ++ regmap_write(priv->regmap, NPCM_PECI_CMD, msg->tx_buf[0]); ++ ++ for (i = 0; i < (msg->tx_len - 1); i++) ++ regmap_write(priv->regmap, NPCM_PECI_DAT_INOUT(i), ++ msg->tx_buf[i + 1]); ++ } ++ ++ priv->status = 0; ++ regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS, ++ NPCM_PECI_CTRL_START_BUSY, ++ NPCM_PECI_CTRL_START_BUSY); ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ err = wait_for_completion_interruptible_timeout(&priv->xfer_complete, ++ timeout); ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ regmap_write(priv->regmap, NPCM_PECI_CMD, 0); ++ ++ if (err <= 0 || priv->status != NPCM_PECI_CTRL_DONE) { ++ if (err < 0) { /* -ERESTARTSYS */ ++ rc = (int)err; ++ goto err_irqrestore; ++ } else if (err == 0) { ++ dev_dbg(priv->dev, "Timeout waiting for a response!\n"); ++ rc = -ETIMEDOUT; ++ goto err_irqrestore; ++ } ++ ++ dev_dbg(priv->dev, "No valid response!\n"); ++ rc = -EIO; ++ goto err_irqrestore; ++ } ++ ++ for (i = 0; i < msg->rx_len; i++) { ++ regmap_read(priv->regmap, NPCM_PECI_DAT_INOUT(i), &msg_rd); ++ msg->rx_buf[i] = (u8)msg_rd; ++ } ++ ++err_irqrestore: ++ spin_unlock_irqrestore(&priv->lock, flags); ++ return rc; ++} ++ ++static irqreturn_t npcm_peci_irq_handler(int irq, void *arg) ++{ ++ struct npcm_peci *priv = arg; ++ u32 status_ack = 0; ++ u32 status; ++ ++ spin_lock(&priv->lock); ++ regmap_read(priv->regmap, NPCM_PECI_CTL_STS, &status); ++ priv->status |= (status & NPCM_PECI_INT_MASK); ++ ++ if (status & NPCM_PECI_CTRL_CRC_ERR) { ++ dev_dbg(priv->dev, "PECI_INT_W_FCS_BAD\n"); ++ status_ack |= NPCM_PECI_CTRL_CRC_ERR; ++ } ++ ++ if (status & NPCM_PECI_CTRL_ABRT_ERR) { ++ dev_dbg(priv->dev, "NPCM_PECI_CTRL_ABRT_ERR\n"); ++ status_ack |= NPCM_PECI_CTRL_ABRT_ERR; ++ } ++ ++ /* ++ * All commands should be ended up with a NPCM_PECI_CTRL_DONE ++ * bit set even in an error case. ++ */ ++ if (status & NPCM_PECI_CTRL_DONE) { ++ dev_dbg(priv->dev, "NPCM_PECI_CTRL_DONE\n"); ++ status_ack |= NPCM_PECI_CTRL_DONE; ++ complete(&priv->xfer_complete); ++ } ++ ++ regmap_write_bits(priv->regmap, NPCM_PECI_CTL_STS, ++ NPCM_PECI_INT_MASK, status_ack); ++ ++ spin_unlock(&priv->lock); ++ return IRQ_HANDLED; ++} ++ ++static int npcm_peci_init_ctrl(struct npcm_peci *priv) ++{ ++ u32 cmd_sts, host_neg_bit_rate = 0, pull_down = 0; ++ int ret; ++ bool volt; ++ ++ priv->clk = devm_clk_get(priv->dev, NULL); ++ if (IS_ERR(priv->clk)) { ++ dev_err(priv->dev, "Failed to get clk source.\n"); ++ return PTR_ERR(priv->clk); ++ } ++ ++ ret = clk_prepare_enable(priv->clk); ++ if (ret) { ++ dev_err(priv->dev, "Failed to enable clock.\n"); ++ return ret; ++ } ++ ++ ret = of_property_read_u32(priv->dev->of_node, "cmd-timeout-ms", ++ &priv->cmd_timeout_ms); ++ if (ret || priv->cmd_timeout_ms > NPCM_PECI_CMD_TIMEOUT_MS_MAX || ++ priv->cmd_timeout_ms == 0) { ++ if (ret) ++ dev_warn(priv->dev, ++ "cmd-timeout-ms not found, use default : %u\n", ++ NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT); ++ else ++ dev_warn(priv->dev, ++ "Invalid cmd-timeout-ms : %u. Use default : %u\n", ++ priv->cmd_timeout_ms, ++ NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT); ++ ++ priv->cmd_timeout_ms = NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT; ++ } ++ ++ if (of_device_is_compatible(priv->dev->of_node, ++ "nuvoton,npcm750-peci")) { ++ priv->gcr_regmap = syscon_regmap_lookup_by_compatible ++ ("nuvoton,npcm750-gcr"); ++ if (!IS_ERR(priv->gcr_regmap)) { ++ volt = of_property_read_bool(priv->dev->of_node, ++ "high-volt-range"); ++ if (volt) ++ regmap_update_bits(priv->gcr_regmap, ++ NPCM7XX_INTCR3_OFFSET, ++ NPCM7XX_INTCR3_PECIVSEL, ++ NPCM7XX_INTCR3_PECIVSEL); ++ else ++ regmap_update_bits(priv->gcr_regmap, ++ NPCM7XX_INTCR3_OFFSET, ++ NPCM7XX_INTCR3_PECIVSEL, 0); ++ } ++ } ++ ++ ret = of_property_read_u32(priv->dev->of_node, "pull-down", ++ &pull_down); ++ if (ret || pull_down > NPCM_PECI_PULL_DOWN_MAX) { ++ if (ret) ++ dev_warn(priv->dev, ++ "pull-down not found, use default : %u\n", ++ NPCM_PECI_PULL_DOWN_DEFAULT); ++ else ++ dev_warn(priv->dev, ++ "Invalid pull-down : %u. Use default : %u\n", ++ pull_down, ++ NPCM_PECI_PULL_DOWN_DEFAULT); ++ pull_down = NPCM_PECI_PULL_DOWN_DEFAULT; ++ } ++ ++ regmap_update_bits(priv->regmap, NPCM_PECI_CTL2, NPCM_PECI_CTL2_MASK, ++ pull_down << 6); ++ ++ ret = of_property_read_u32(priv->dev->of_node, "host-neg-bit-rate", ++ &host_neg_bit_rate); ++ if (ret || host_neg_bit_rate > NPCM_PECI_HOST_NEG_BIT_RATE_MAX || ++ host_neg_bit_rate < NPCM_PECI_HOST_NEG_BIT_RATE_MIN) { ++ if (ret) ++ dev_warn(priv->dev, ++ "host-neg-bit-rate not found, use default : %u\n", ++ NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT); ++ else ++ dev_warn(priv->dev, ++ "Invalid host-neg-bit-rate : %u. Use default : %u\n", ++ host_neg_bit_rate, ++ NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT); ++ host_neg_bit_rate = NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT; ++ } ++ ++ regmap_update_bits(priv->regmap, NPCM_PECI_PDDR, NPCM_PECI_PDDR_MASK, ++ host_neg_bit_rate); ++ ++ priv->host_bit_rate = clk_get_rate(priv->clk) / ++ (4 * (host_neg_bit_rate + 1)); ++ ++ ret = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts, ++ !(cmd_sts & NPCM_PECI_CTRL_START_BUSY), ++ NPCM_PECI_IDLE_CHECK_INTERVAL_USEC, ++ NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC); ++ if (ret) ++ return ret; /* -ETIMEDOUT */ ++ ++ /* PECI interrupt enable */ ++ regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS, ++ NPCM_PECI_CTRL_DONE_INT_EN, ++ NPCM_PECI_CTRL_DONE_INT_EN); ++ ++ return 0; ++} ++ ++static const struct regmap_config npcm_peci_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .max_register = NPCM_PECI_MAX_REG, ++ .fast_io = true, ++}; ++ ++static int npcm_peci_xfer(struct peci_adapter *adapter, ++ struct peci_xfer_msg *msg) ++{ ++ struct npcm_peci *priv = peci_get_adapdata(adapter); ++ ++ return npcm_peci_xfer_native(priv, msg); ++} ++ ++static int npcm_peci_probe(struct platform_device *pdev) ++{ ++ struct peci_adapter *adapter; ++ struct npcm_peci *priv; ++ struct resource *res; ++ void __iomem *base; ++ int ret; ++ ++ adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv)); ++ if (!adapter) ++ return -ENOMEM; ++ ++ priv = peci_get_adapdata(adapter); ++ priv->adapter = adapter; ++ priv->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, priv); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(base)) { ++ ret = PTR_ERR(base); ++ goto err_put_adapter_dev; ++ } ++ ++ priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, ++ &npcm_peci_regmap_config); ++ if (IS_ERR(priv->regmap)) { ++ ret = PTR_ERR(priv->regmap); ++ goto err_put_adapter_dev; ++ } ++ ++ priv->irq = platform_get_irq(pdev, 0); ++ if (!priv->irq) { ++ ret = -ENODEV; ++ goto err_put_adapter_dev; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, priv->irq, npcm_peci_irq_handler, ++ 0, "peci-npcm-irq", priv); ++ if (ret) ++ goto err_put_adapter_dev; ++ ++ init_completion(&priv->xfer_complete); ++ spin_lock_init(&priv->lock); ++ ++ priv->adapter->owner = THIS_MODULE; ++ priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev)); ++ strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name)); ++ priv->adapter->xfer = npcm_peci_xfer; ++ ++ ret = npcm_peci_init_ctrl(priv); ++ if (ret) ++ goto err_put_adapter_dev; ++ ++ ret = peci_add_adapter(priv->adapter); ++ if (ret) ++ goto err_put_adapter_dev; ++ ++ dev_info(&pdev->dev, "peci bus %d registered, host negotiation bit rate %dHz", ++ priv->adapter->nr, priv->host_bit_rate); ++ ++ return 0; ++ ++err_put_adapter_dev: ++ put_device(&adapter->dev); ++ return ret; ++} ++ ++static int npcm_peci_remove(struct platform_device *pdev) ++{ ++ struct npcm_peci *priv = dev_get_drvdata(&pdev->dev); ++ ++ clk_disable_unprepare(priv->clk); ++ peci_del_adapter(priv->adapter); ++ of_node_put(priv->adapter->dev.of_node); ++ ++ return 0; ++} ++ ++static const struct of_device_id npcm_peci_of_table[] = { ++ { .compatible = "nuvoton,npcm750-peci", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, npcm_peci_of_table); ++ ++static struct platform_driver npcm_peci_driver = { ++ .probe = npcm_peci_probe, ++ .remove = npcm_peci_remove, ++ .driver = { ++ .name = "peci-npcm", ++ .of_match_table = of_match_ptr(npcm_peci_of_table), ++ }, ++}; ++module_platform_driver(npcm_peci_driver); ++ ++MODULE_AUTHOR("Tomer Maimon "); ++MODULE_DESCRIPTION("NPCM Platform Environment Control Interface (PECI) driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/peci/peci-aspeed.c b/drivers/peci/peci-aspeed.c +deleted file mode 100644 +index 51cb256..0000000 +--- a/drivers/peci/peci-aspeed.c ++++ /dev/null +@@ -1,505 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-// Copyright (C) 2012-2017 ASPEED Technology Inc. +-// Copyright (c) 2018 Intel Corporation +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-/* ASPEED PECI Registers */ +-#define ASPEED_PECI_CTRL 0x00 +-#define ASPEED_PECI_TIMING 0x04 +-#define ASPEED_PECI_CMD 0x08 +-#define ASPEED_PECI_CMD_CTRL 0x0c +-#define ASPEED_PECI_EXP_FCS 0x10 +-#define ASPEED_PECI_CAP_FCS 0x14 +-#define ASPEED_PECI_INT_CTRL 0x18 +-#define ASPEED_PECI_INT_STS 0x1c +-#define ASPEED_PECI_W_DATA0 0x20 +-#define ASPEED_PECI_W_DATA1 0x24 +-#define ASPEED_PECI_W_DATA2 0x28 +-#define ASPEED_PECI_W_DATA3 0x2c +-#define ASPEED_PECI_R_DATA0 0x30 +-#define ASPEED_PECI_R_DATA1 0x34 +-#define ASPEED_PECI_R_DATA2 0x38 +-#define ASPEED_PECI_R_DATA3 0x3c +-#define ASPEED_PECI_W_DATA4 0x40 +-#define ASPEED_PECI_W_DATA5 0x44 +-#define ASPEED_PECI_W_DATA6 0x48 +-#define ASPEED_PECI_W_DATA7 0x4c +-#define ASPEED_PECI_R_DATA4 0x50 +-#define ASPEED_PECI_R_DATA5 0x54 +-#define ASPEED_PECI_R_DATA6 0x58 +-#define ASPEED_PECI_R_DATA7 0x5c +- +-/* ASPEED_PECI_CTRL - 0x00 : Control Register */ +-#define PECI_CTRL_SAMPLING_MASK GENMASK(19, 16) +-#define PECI_CTRL_READ_MODE_MASK GENMASK(13, 12) +-#define PECI_CTRL_READ_MODE_COUNT BIT(12) +-#define PECI_CTRL_READ_MODE_DBG BIT(13) +-#define PECI_CTRL_CLK_SOURCE_MASK BIT(11) +-#define PECI_CTRL_CLK_DIV_MASK GENMASK(10, 8) +-#define PECI_CTRL_INVERT_OUT BIT(7) +-#define PECI_CTRL_INVERT_IN BIT(6) +-#define PECI_CTRL_BUS_CONTENT_EN BIT(5) +-#define PECI_CTRL_PECI_EN BIT(4) +-#define PECI_CTRL_PECI_CLK_EN BIT(0) +- +-/* ASPEED_PECI_TIMING - 0x04 : Timing Negotiation Register */ +-#define PECI_TIMING_MESSAGE_MASK GENMASK(15, 8) +-#define PECI_TIMING_ADDRESS_MASK GENMASK(7, 0) +- +-/* ASPEED_PECI_CMD - 0x08 : Command Register */ +-#define PECI_CMD_PIN_MON BIT(31) +-#define PECI_CMD_STS_MASK GENMASK(27, 24) +-#define PECI_CMD_IDLE_MASK (PECI_CMD_STS_MASK | PECI_CMD_PIN_MON) +-#define PECI_CMD_FIRE BIT(0) +- +-/* ASPEED_PECI_LEN - 0x0C : Read/Write Length Register */ +-#define PECI_AW_FCS_EN BIT(31) +-#define PECI_READ_LEN_MASK GENMASK(23, 16) +-#define PECI_WRITE_LEN_MASK GENMASK(15, 8) +-#define PECI_TAGET_ADDR_MASK GENMASK(7, 0) +- +-/* ASPEED_PECI_EXP_FCS - 0x10 : Expected FCS Data Register */ +-#define PECI_EXPECT_READ_FCS_MASK GENMASK(23, 16) +-#define PECI_EXPECT_AW_FCS_AUTO_MASK GENMASK(15, 8) +-#define PECI_EXPECT_WRITE_FCS_MASK GENMASK(7, 0) +- +-/* ASPEED_PECI_CAP_FCS - 0x14 : Captured FCS Data Register */ +-#define PECI_CAPTURE_READ_FCS_MASK GENMASK(23, 16) +-#define PECI_CAPTURE_WRITE_FCS_MASK GENMASK(7, 0) +- +-/* ASPEED_PECI_INT_CTRL/STS - 0x18/0x1c : Interrupt Register */ +-#define PECI_INT_TIMING_RESULT_MASK GENMASK(31, 30) +-#define PECI_INT_TIMEOUT BIT(4) +-#define PECI_INT_CONNECT BIT(3) +-#define PECI_INT_W_FCS_BAD BIT(2) +-#define PECI_INT_W_FCS_ABORT BIT(1) +-#define PECI_INT_CMD_DONE BIT(0) +- +-#define PECI_INT_MASK (PECI_INT_TIMEOUT | PECI_INT_CONNECT | \ +- PECI_INT_W_FCS_BAD | PECI_INT_W_FCS_ABORT | \ +- PECI_INT_CMD_DONE) +- +-#define PECI_IDLE_CHECK_TIMEOUT_USEC 50000 +-#define PECI_IDLE_CHECK_INTERVAL_USEC 10000 +- +-#define PECI_RD_SAMPLING_POINT_DEFAULT 8 +-#define PECI_RD_SAMPLING_POINT_MAX 15 +-#define PECI_CLK_DIV_DEFAULT 0 +-#define PECI_CLK_DIV_MAX 7 +-#define PECI_MSG_TIMING_DEFAULT 1 +-#define PECI_MSG_TIMING_MAX 255 +-#define PECI_ADDR_TIMING_DEFAULT 1 +-#define PECI_ADDR_TIMING_MAX 255 +-#define PECI_CMD_TIMEOUT_MS_DEFAULT 1000 +-#define PECI_CMD_TIMEOUT_MS_MAX 60000 +- +-struct aspeed_peci { +- struct peci_adapter *adapter; +- struct device *dev; +- struct regmap *regmap; +- struct clk *clk; +- struct reset_control *rst; +- int irq; +- spinlock_t lock; /* to sync completion status handling */ +- struct completion xfer_complete; +- u32 status; +- u32 cmd_timeout_ms; +-}; +- +-static int aspeed_peci_xfer_native(struct aspeed_peci *priv, +- struct peci_xfer_msg *msg) +-{ +- long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms); +- u32 peci_head, peci_state, rx_data, cmd_sts; +- unsigned long flags; +- int i, rc; +- uint reg; +- +- /* Check command sts and bus idle state */ +- rc = regmap_read_poll_timeout(priv->regmap, ASPEED_PECI_CMD, cmd_sts, +- !(cmd_sts & PECI_CMD_IDLE_MASK), +- PECI_IDLE_CHECK_INTERVAL_USEC, +- PECI_IDLE_CHECK_TIMEOUT_USEC); +- if (rc) +- return rc; /* -ETIMEDOUT */ +- +- spin_lock_irqsave(&priv->lock, flags); +- reinit_completion(&priv->xfer_complete); +- +- peci_head = FIELD_PREP(PECI_TAGET_ADDR_MASK, msg->addr) | +- FIELD_PREP(PECI_WRITE_LEN_MASK, msg->tx_len) | +- FIELD_PREP(PECI_READ_LEN_MASK, msg->rx_len); +- +- regmap_write(priv->regmap, ASPEED_PECI_CMD_CTRL, peci_head); +- +- for (i = 0; i < msg->tx_len; i += 4) { +- reg = i < 16 ? ASPEED_PECI_W_DATA0 + i % 16 : +- ASPEED_PECI_W_DATA4 + i % 16; +- regmap_write(priv->regmap, reg, +- le32_to_cpup((__le32 *)&msg->tx_buf[i])); +- } +- +- dev_dbg(priv->dev, "HEAD : 0x%08x\n", peci_head); +- print_hex_dump_debug("TX : ", DUMP_PREFIX_NONE, 16, 1, +- msg->tx_buf, msg->tx_len, true); +- +- priv->status = 0; +- regmap_write(priv->regmap, ASPEED_PECI_CMD, PECI_CMD_FIRE); +- spin_unlock_irqrestore(&priv->lock, flags); +- +- err = wait_for_completion_interruptible_timeout(&priv->xfer_complete, +- timeout); +- +- spin_lock_irqsave(&priv->lock, flags); +- dev_dbg(priv->dev, "INT_STS : 0x%08x\n", priv->status); +- regmap_read(priv->regmap, ASPEED_PECI_CMD, &peci_state); +- dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n", +- FIELD_GET(PECI_CMD_STS_MASK, peci_state)); +- +- regmap_write(priv->regmap, ASPEED_PECI_CMD, 0); +- +- if (err <= 0 || priv->status != PECI_INT_CMD_DONE) { +- if (err < 0) { /* -ERESTARTSYS */ +- rc = (int)err; +- goto err_irqrestore; +- } else if (err == 0) { +- dev_dbg(priv->dev, "Timeout waiting for a response!\n"); +- rc = -ETIMEDOUT; +- goto err_irqrestore; +- } +- +- dev_dbg(priv->dev, "No valid response!\n"); +- rc = -EIO; +- goto err_irqrestore; +- } +- +- /** +- * Note that rx_len and rx_buf size can be an odd number. +- * Byte handling is more efficient. +- */ +- for (i = 0; i < msg->rx_len; i++) { +- u8 byte_offset = i % 4; +- +- if (byte_offset == 0) { +- reg = i < 16 ? ASPEED_PECI_R_DATA0 + i % 16 : +- ASPEED_PECI_R_DATA4 + i % 16; +- regmap_read(priv->regmap, reg, &rx_data); +- } +- +- msg->rx_buf[i] = (u8)(rx_data >> (byte_offset << 3)); +- } +- +- print_hex_dump_debug("RX : ", DUMP_PREFIX_NONE, 16, 1, +- msg->rx_buf, msg->rx_len, true); +- +- regmap_read(priv->regmap, ASPEED_PECI_CMD, &peci_state); +- dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n", +- FIELD_GET(PECI_CMD_STS_MASK, peci_state)); +- dev_dbg(priv->dev, "------------------------\n"); +- +-err_irqrestore: +- spin_unlock_irqrestore(&priv->lock, flags); +- return rc; +-} +- +-static irqreturn_t aspeed_peci_irq_handler(int irq, void *arg) +-{ +- struct aspeed_peci *priv = arg; +- u32 status_ack = 0; +- u32 status; +- +- spin_lock(&priv->lock); +- regmap_read(priv->regmap, ASPEED_PECI_INT_STS, &status); +- priv->status |= (status & PECI_INT_MASK); +- +- /** +- * In most cases, interrupt bits will be set one by one but also note +- * that multiple interrupt bits could be set at the same time. +- */ +- if (status & PECI_INT_TIMEOUT) { +- dev_dbg(priv->dev, "PECI_INT_TIMEOUT\n"); +- status_ack |= PECI_INT_TIMEOUT; +- } +- +- if (status & PECI_INT_CONNECT) { +- dev_dbg(priv->dev, "PECI_INT_CONNECT\n"); +- status_ack |= PECI_INT_CONNECT; +- } +- +- if (status & PECI_INT_W_FCS_BAD) { +- dev_dbg(priv->dev, "PECI_INT_W_FCS_BAD\n"); +- status_ack |= PECI_INT_W_FCS_BAD; +- } +- +- if (status & PECI_INT_W_FCS_ABORT) { +- dev_dbg(priv->dev, "PECI_INT_W_FCS_ABORT\n"); +- status_ack |= PECI_INT_W_FCS_ABORT; +- } +- +- /** +- * All commands should be ended up with a PECI_INT_CMD_DONE bit set +- * even in an error case. +- */ +- if (status & PECI_INT_CMD_DONE) { +- dev_dbg(priv->dev, "PECI_INT_CMD_DONE\n"); +- status_ack |= PECI_INT_CMD_DONE; +- complete(&priv->xfer_complete); +- } +- +- regmap_write(priv->regmap, ASPEED_PECI_INT_STS, status_ack); +- spin_unlock(&priv->lock); +- return IRQ_HANDLED; +-} +- +-static int aspeed_peci_init_ctrl(struct aspeed_peci *priv) +-{ +- u32 msg_timing, addr_timing, rd_sampling_point; +- u32 clk_freq, clk_divisor, clk_div_val = 0; +- int ret; +- +- priv->clk = devm_clk_get(priv->dev, NULL); +- if (IS_ERR(priv->clk)) { +- dev_err(priv->dev, "Failed to get clk source.\n"); +- return PTR_ERR(priv->clk); +- } +- +- ret = clk_prepare_enable(priv->clk); +- if (ret) { +- dev_err(priv->dev, "Failed to enable clock.\n"); +- return ret; +- } +- +- ret = of_property_read_u32(priv->dev->of_node, "clock-frequency", +- &clk_freq); +- if (ret) { +- dev_err(priv->dev, +- "Could not read clock-frequency property.\n"); +- clk_disable_unprepare(priv->clk); +- return ret; +- } +- +- clk_divisor = clk_get_rate(priv->clk) / clk_freq; +- +- while ((clk_divisor >> 1) && (clk_div_val < PECI_CLK_DIV_MAX)) +- clk_div_val++; +- +- ret = of_property_read_u32(priv->dev->of_node, "msg-timing", +- &msg_timing); +- if (ret || msg_timing > PECI_MSG_TIMING_MAX) { +- if (!ret) +- dev_warn(priv->dev, +- "Invalid msg-timing : %u, Use default : %u\n", +- msg_timing, PECI_MSG_TIMING_DEFAULT); +- msg_timing = PECI_MSG_TIMING_DEFAULT; +- } +- +- ret = of_property_read_u32(priv->dev->of_node, "addr-timing", +- &addr_timing); +- if (ret || addr_timing > PECI_ADDR_TIMING_MAX) { +- if (!ret) +- dev_warn(priv->dev, +- "Invalid addr-timing : %u, Use default : %u\n", +- addr_timing, PECI_ADDR_TIMING_DEFAULT); +- addr_timing = PECI_ADDR_TIMING_DEFAULT; +- } +- +- ret = of_property_read_u32(priv->dev->of_node, "rd-sampling-point", +- &rd_sampling_point); +- if (ret || rd_sampling_point > PECI_RD_SAMPLING_POINT_MAX) { +- if (!ret) +- dev_warn(priv->dev, +- "Invalid rd-sampling-point : %u. Use default : %u\n", +- rd_sampling_point, +- PECI_RD_SAMPLING_POINT_DEFAULT); +- rd_sampling_point = PECI_RD_SAMPLING_POINT_DEFAULT; +- } +- +- ret = of_property_read_u32(priv->dev->of_node, "cmd-timeout-ms", +- &priv->cmd_timeout_ms); +- if (ret || priv->cmd_timeout_ms > PECI_CMD_TIMEOUT_MS_MAX || +- priv->cmd_timeout_ms == 0) { +- if (!ret) +- dev_warn(priv->dev, +- "Invalid cmd-timeout-ms : %u. Use default : %u\n", +- priv->cmd_timeout_ms, +- PECI_CMD_TIMEOUT_MS_DEFAULT); +- priv->cmd_timeout_ms = PECI_CMD_TIMEOUT_MS_DEFAULT; +- } +- +- regmap_write(priv->regmap, ASPEED_PECI_CTRL, +- FIELD_PREP(PECI_CTRL_CLK_DIV_MASK, PECI_CLK_DIV_DEFAULT) | +- PECI_CTRL_PECI_CLK_EN); +- +- /** +- * Timing negotiation period setting. +- * The unit of the programmed value is 4 times of PECI clock period. +- */ +- regmap_write(priv->regmap, ASPEED_PECI_TIMING, +- FIELD_PREP(PECI_TIMING_MESSAGE_MASK, msg_timing) | +- FIELD_PREP(PECI_TIMING_ADDRESS_MASK, addr_timing)); +- +- /* Clear interrupts */ +- regmap_write(priv->regmap, ASPEED_PECI_INT_STS, PECI_INT_MASK); +- +- /* Enable interrupts */ +- regmap_write(priv->regmap, ASPEED_PECI_INT_CTRL, PECI_INT_MASK); +- +- /* Read sampling point and clock speed setting */ +- regmap_write(priv->regmap, ASPEED_PECI_CTRL, +- FIELD_PREP(PECI_CTRL_SAMPLING_MASK, rd_sampling_point) | +- FIELD_PREP(PECI_CTRL_CLK_DIV_MASK, clk_div_val) | +- PECI_CTRL_PECI_EN | PECI_CTRL_PECI_CLK_EN); +- +- return 0; +-} +- +-static const struct regmap_config aspeed_peci_regmap_config = { +- .reg_bits = 32, +- .val_bits = 32, +- .reg_stride = 4, +- .max_register = ASPEED_PECI_R_DATA7, +- .val_format_endian = REGMAP_ENDIAN_LITTLE, +- .fast_io = true, +-}; +- +-static int aspeed_peci_xfer(struct peci_adapter *adapter, +- struct peci_xfer_msg *msg) +-{ +- struct aspeed_peci *priv = peci_get_adapdata(adapter); +- +- return aspeed_peci_xfer_native(priv, msg); +-} +- +-static int aspeed_peci_probe(struct platform_device *pdev) +-{ +- struct peci_adapter *adapter; +- struct aspeed_peci *priv; +- struct resource *res; +- void __iomem *base; +- u32 cmd_sts; +- int ret; +- +- adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv)); +- if (!adapter) +- return -ENOMEM; +- +- priv = peci_get_adapdata(adapter); +- priv->adapter = adapter; +- priv->dev = &pdev->dev; +- dev_set_drvdata(&pdev->dev, priv); +- +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- base = devm_ioremap_resource(&pdev->dev, res); +- if (IS_ERR(base)) { +- ret = PTR_ERR(base); +- goto err_put_adapter_dev; +- } +- +- priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, +- &aspeed_peci_regmap_config); +- if (IS_ERR(priv->regmap)) { +- ret = PTR_ERR(priv->regmap); +- goto err_put_adapter_dev; +- } +- +- /** +- * We check that the regmap works on this very first access, +- * but as this is an MMIO-backed regmap, subsequent regmap +- * access is not going to fail and we skip error checks from +- * this point. +- */ +- ret = regmap_read(priv->regmap, ASPEED_PECI_CMD, &cmd_sts); +- if (ret) { +- ret = -EIO; +- goto err_put_adapter_dev; +- } +- +- priv->irq = platform_get_irq(pdev, 0); +- if (!priv->irq) { +- ret = -ENODEV; +- goto err_put_adapter_dev; +- } +- +- ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_peci_irq_handler, +- 0, "peci-aspeed-irq", priv); +- if (ret) +- goto err_put_adapter_dev; +- +- init_completion(&priv->xfer_complete); +- spin_lock_init(&priv->lock); +- +- priv->adapter->owner = THIS_MODULE; +- priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev)); +- strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name)); +- priv->adapter->xfer = aspeed_peci_xfer; +- +- priv->rst = devm_reset_control_get(&pdev->dev, NULL); +- if (IS_ERR(priv->rst)) { +- dev_err(&pdev->dev, +- "missing or invalid reset controller entry"); +- ret = PTR_ERR(priv->rst); +- goto err_put_adapter_dev; +- } +- reset_control_deassert(priv->rst); +- +- ret = aspeed_peci_init_ctrl(priv); +- if (ret) +- goto err_put_adapter_dev; +- +- ret = peci_add_adapter(priv->adapter); +- if (ret) +- goto err_put_adapter_dev; +- +- dev_info(&pdev->dev, "peci bus %d registered, irq %d\n", +- priv->adapter->nr, priv->irq); +- +- return 0; +- +-err_put_adapter_dev: +- put_device(&adapter->dev); +- return ret; +-} +- +-static int aspeed_peci_remove(struct platform_device *pdev) +-{ +- struct aspeed_peci *priv = dev_get_drvdata(&pdev->dev); +- +- clk_disable_unprepare(priv->clk); +- reset_control_assert(priv->rst); +- peci_del_adapter(priv->adapter); +- of_node_put(priv->adapter->dev.of_node); +- +- return 0; +-} +- +-static const struct of_device_id aspeed_peci_of_table[] = { +- { .compatible = "aspeed,ast2400-peci", }, +- { .compatible = "aspeed,ast2500-peci", }, +- { } +-}; +-MODULE_DEVICE_TABLE(of, aspeed_peci_of_table); +- +-static struct platform_driver aspeed_peci_driver = { +- .probe = aspeed_peci_probe, +- .remove = aspeed_peci_remove, +- .driver = { +- .name = "peci-aspeed", +- .of_match_table = of_match_ptr(aspeed_peci_of_table), +- }, +-}; +-module_platform_driver(aspeed_peci_driver); +- +-MODULE_AUTHOR("Ryan Chen "); +-MODULE_AUTHOR("Jae Hyun Yoo "); +-MODULE_DESCRIPTION("ASPEED PECI driver"); +-MODULE_LICENSE("GPL v2"); +diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c +index 6f24146..2a6be04 100644 +--- a/drivers/peci/peci-core.c ++++ b/drivers/peci/peci-core.c +@@ -1,38 +1,31 @@ + // SPDX-License-Identifier: GPL-2.0 +-// Copyright (c) 2018 Intel Corporation ++// Copyright (c) 2018-2019 Intel Corporation + + #include + #include + #include +-#include ++#include + #include + #include + #include + #include + #include ++#include + #include +-#include + + /* Mask for getting minor revision number from DIB */ + #define REVISION_NUM_MASK GENMASK(15, 8) + +-/* CRC8 table for Assure Write Frame Check */ ++/* CRC8 table for Assured Write Frame Check */ + #define PECI_CRC8_POLYNOMIAL 0x07 + DECLARE_CRC8_TABLE(peci_crc8_table); + +-static struct device_type peci_adapter_type; +-static struct device_type peci_client_type; +- +-/* Max number of peci cdev */ +-#define PECI_CDEV_MAX 16 +- +-static dev_t peci_devt; + static bool is_registered; + + static DEFINE_MUTEX(core_lock); + static DEFINE_IDR(peci_adapter_idr); + +-static struct peci_adapter *peci_get_adapter(int nr) ++struct peci_adapter *peci_get_adapter(int nr) + { + struct peci_adapter *adapter; + +@@ -48,10 +41,12 @@ static struct peci_adapter *peci_get_adapter(int nr) + + out_unlock: + mutex_unlock(&core_lock); ++ + return adapter; + } ++EXPORT_SYMBOL_GPL(peci_get_adapter); + +-static void peci_put_adapter(struct peci_adapter *adapter) ++void peci_put_adapter(struct peci_adapter *adapter) + { + if (!adapter) + return; +@@ -59,6 +54,7 @@ static void peci_put_adapter(struct peci_adapter *adapter) + put_device(&adapter->dev); + module_put(adapter->owner); + } ++EXPORT_SYMBOL_GPL(peci_put_adapter); + + static ssize_t name_show(struct device *dev, + struct device_attribute *attr, +@@ -84,10 +80,11 @@ static struct attribute *peci_device_attrs[] = { + }; + ATTRIBUTE_GROUPS(peci_device); + +-static struct device_type peci_client_type = { ++struct device_type peci_client_type = { + .groups = peci_device_groups, + .release = peci_client_dev_release, + }; ++EXPORT_SYMBOL_GPL(peci_client_type); + + /** + * peci_verify_client - return parameter as peci_client, or NULL +@@ -103,19 +100,120 @@ struct peci_client *peci_verify_client(struct device *dev) + } + EXPORT_SYMBOL_GPL(peci_verify_client); + +-static u8 peci_aw_fcs(u8 *data, int len) ++/** ++ * peci_get_xfer_msg() - get a DMA safe peci_xfer_msg for the given tx and rx ++ * length ++ * @tx_len: the length of tx_buf. May be 0 if tx_buf isn't needed. ++ * @rx_len: the length of rx_buf. May be 0 if rx_buf isn't needed. ++ * ++ * Return: NULL if a DMA safe buffer was not obtained. ++ * Or a valid pointer to be used with DMA. After use, release it by ++ * calling peci_put_xfer_msg(). ++ * ++ * This function must only be called from process context! ++ */ ++struct peci_xfer_msg *peci_get_xfer_msg(u8 tx_len, u8 rx_len) ++{ ++ struct peci_xfer_msg *msg; ++ u8 *tx_buf, *rx_buf; ++ ++ if (tx_len) { ++ tx_buf = kzalloc(tx_len, GFP_KERNEL); ++ if (!tx_buf) ++ return NULL; ++ } else { ++ tx_buf = NULL; ++ } ++ ++ if (rx_len) { ++ rx_buf = kzalloc(rx_len, GFP_KERNEL); ++ if (!rx_buf) ++ goto err_free_tx_buf; ++ } else { ++ rx_buf = NULL; ++ } ++ ++ msg = kzalloc(sizeof(struct peci_xfer_msg), GFP_KERNEL); ++ if (!msg) ++ goto err_free_tx_rx_buf; ++ ++ msg->tx_len = tx_len; ++ msg->tx_buf = tx_buf; ++ msg->rx_len = rx_len; ++ msg->rx_buf = rx_buf; ++ ++ return msg; ++ ++err_free_tx_rx_buf: ++ kfree(rx_buf); ++err_free_tx_buf: ++ kfree(tx_buf); ++ ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(peci_get_xfer_msg); ++ ++/** ++ * peci_put_xfer_msg - release a DMA safe peci_xfer_msg ++ * @msg: the message obtained from peci_get_xfer_msg(). May be NULL. ++ */ ++void peci_put_xfer_msg(struct peci_xfer_msg *msg) ++{ ++ if (!msg) ++ return; ++ ++ kfree(msg->rx_buf); ++ kfree(msg->tx_buf); ++ kfree(msg); ++} ++EXPORT_SYMBOL_GPL(peci_put_xfer_msg); ++ ++/* Calculate an Assured Write Frame Check Sequence byte */ ++static int peci_aw_fcs(struct peci_xfer_msg *msg, int len, u8 *aw_fcs) + { +- return crc8(peci_crc8_table, data, (size_t)len, 0); ++ u8 *tmp_buf; ++ ++ /* Allocate a temporary buffer to use a contiguous byte array */ ++ tmp_buf = kmalloc(len, GFP_KERNEL); ++ if (!tmp_buf) ++ return -ENOMEM; ++ ++ tmp_buf[0] = msg->addr; ++ tmp_buf[1] = msg->tx_len; ++ tmp_buf[2] = msg->rx_len; ++ memcpy(&tmp_buf[3], msg->tx_buf, len - 3); ++ ++ *aw_fcs = crc8(peci_crc8_table, tmp_buf, (size_t)len, 0); ++ ++ kfree(tmp_buf); ++ ++ return 0; + } + + static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg, + bool do_retry, bool has_aw_fcs) + { +- ktime_t start, end; +- s64 elapsed_ms; +- int rc = 0; ++ ulong timeout = jiffies; ++ u8 aw_fcs; ++ int ret; ++ ++ /* ++ * In case if adapter uses DMA, check at here whether tx and rx buffers ++ * are DMA capable or not. ++ */ ++ if (IS_ENABLED(CONFIG_HAS_DMA) && adapter->use_dma) { ++ if (is_vmalloc_addr(msg->tx_buf) || ++ is_vmalloc_addr(msg->rx_buf)) { ++ WARN_ONCE(1, "xfer msg is not dma capable\n"); ++ return -EAGAIN; ++ } else if (object_is_on_stack(msg->tx_buf) || ++ object_is_on_stack(msg->rx_buf)) { ++ WARN_ONCE(1, "xfer msg is on stack\n"); ++ return -EAGAIN; ++ } ++ } + +- /** ++ /* + * For some commands, the PECI originator may need to retry a command if + * the processor PECI client responds with a 0x8x completion code. In + * each instance, the processor PECI client may have started the +@@ -125,55 +223,51 @@ static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg, + */ + + if (do_retry) +- start = ktime_get(); ++ timeout += msecs_to_jiffies(PECI_DEV_RETRY_TIME_MS); + +- do { +- rc = adapter->xfer(adapter, msg); ++ for (;;) { ++ ret = adapter->xfer(adapter, msg); + +- if (!do_retry || rc) +- break; +- +- if (msg->rx_buf[0] == DEV_PECI_CC_SUCCESS) ++ if (!do_retry || ret || !msg->rx_buf) + break; + + /* Retry is needed when completion code is 0x8x */ +- if ((msg->rx_buf[0] & DEV_PECI_CC_RETRY_CHECK_MASK) != +- DEV_PECI_CC_NEED_RETRY) { +- rc = -EIO; ++ if ((msg->rx_buf[0] & PECI_DEV_CC_RETRY_CHECK_MASK) != ++ PECI_DEV_CC_NEED_RETRY) + break; +- } + + /* Set the retry bit to indicate a retry attempt */ +- msg->tx_buf[1] |= DEV_PECI_RETRY_BIT; ++ msg->tx_buf[1] |= PECI_DEV_RETRY_BIT; + + /* Recalculate the AW FCS if it has one */ +- if (has_aw_fcs) +- msg->tx_buf[msg->tx_len - 1] = 0x80 ^ +- peci_aw_fcs((u8 *)msg, +- 2 + msg->tx_len); ++ if (has_aw_fcs) { ++ ret = peci_aw_fcs(msg, 2 + msg->tx_len, &aw_fcs); ++ if (ret) ++ break; + +- /** ++ msg->tx_buf[msg->tx_len - 1] = 0x80 ^ aw_fcs; ++ } ++ ++ /* + * Retry for at least 250ms before returning an error. + * Retry interval guideline: + * No minimum < Retry Interval < No maximum + * (recommend 10ms) + */ +- end = ktime_get(); +- elapsed_ms = ktime_to_ms(ktime_sub(end, start)); +- if (elapsed_ms >= DEV_PECI_RETRY_TIME_MS) { ++ if (time_after(jiffies, timeout)) { + dev_dbg(&adapter->dev, "Timeout retrying xfer!\n"); +- rc = -ETIMEDOUT; ++ ret = -ETIMEDOUT; + break; + } + +- usleep_range((DEV_PECI_RETRY_INTERVAL_USEC >> 2) + 1, +- DEV_PECI_RETRY_INTERVAL_USEC); +- } while (true); ++ usleep_range((PECI_DEV_RETRY_INTERVAL_USEC >> 2) + 1, ++ PECI_DEV_RETRY_INTERVAL_USEC); ++ } + +- if (rc) +- dev_dbg(&adapter->dev, "xfer error, rc: %d\n", rc); ++ if (ret) ++ dev_dbg(&adapter->dev, "xfer error: %d\n", ret); + +- return rc; ++ return ret; + } + + static int peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg) +@@ -190,34 +284,37 @@ static int peci_xfer_with_retries(struct peci_adapter *adapter, + + static int peci_scan_cmd_mask(struct peci_adapter *adapter) + { +- struct peci_xfer_msg msg; ++ struct peci_xfer_msg *msg; + u8 revision; +- int rc = 0; ++ int ret; + u64 dib; + + /* Update command mask just once */ + if (adapter->cmd_mask & BIT(PECI_CMD_XFER)) + return 0; + +- msg.addr = PECI_BASE_ADDR; +- msg.tx_len = GET_DIB_WR_LEN; +- msg.rx_len = GET_DIB_RD_LEN; +- msg.tx_buf[0] = GET_DIB_PECI_CMD; ++ msg = peci_get_xfer_msg(PECI_GET_DIB_WR_LEN, PECI_GET_DIB_RD_LEN); ++ if (!msg) ++ return -ENOMEM; ++ ++ msg->addr = PECI_BASE_ADDR; ++ msg->tx_buf[0] = PECI_GET_DIB_CMD; + +- rc = peci_xfer(adapter, &msg); +- if (rc) +- return rc; ++ ret = peci_xfer(adapter, msg); ++ if (ret) ++ return ret; + +- dib = le64_to_cpup((__le64 *)msg.rx_buf); ++ dib = le64_to_cpup((__le64 *)msg->rx_buf); + + /* Check special case for Get DIB command */ + if (dib == 0) { + dev_dbg(&adapter->dev, "DIB read as 0\n"); +- return -EIO; ++ ret = -EIO; ++ goto out; + } + +- /** +- * Setting up the supporting commands based on minor revision number. ++ /* ++ * Setting up the supporting commands based on revision number. + * See PECI Spec Table 3-1. + */ + revision = FIELD_GET(REVISION_NUM_MASK, dib); +@@ -243,10 +340,14 @@ static int peci_scan_cmd_mask(struct peci_adapter *adapter) + adapter->cmd_mask |= BIT(PECI_CMD_GET_DIB); + adapter->cmd_mask |= BIT(PECI_CMD_PING); + +- return rc; ++out: ++ peci_put_xfer_msg(msg); ++ ++ return ret; + } + +-static int peci_cmd_support(struct peci_adapter *adapter, enum peci_cmd cmd) ++static int peci_check_cmd_support(struct peci_adapter *adapter, ++ enum peci_cmd cmd) + { + if (!(adapter->cmd_mask & BIT(PECI_CMD_PING)) && + peci_scan_cmd_mask(adapter) < 0) { +@@ -262,70 +363,130 @@ static int peci_cmd_support(struct peci_adapter *adapter, enum peci_cmd cmd) + return 0; + } + +-static int peci_ioctl_xfer(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_xfer(struct peci_adapter *adapter, void *vmsg) + { + struct peci_xfer_msg *msg = vmsg; ++ u8 aw_fcs; ++ int ret; ++ ++ if (!msg->tx_len) { ++ ret = peci_xfer(adapter, msg); ++ } else { ++ switch (msg->tx_buf[0]) { ++ case PECI_RDPKGCFG_CMD: ++ case PECI_RDIAMSR_CMD: ++ case PECI_RDPCICFG_CMD: ++ case PECI_RDPCICFGLOCAL_CMD: ++ ret = peci_xfer_with_retries(adapter, msg, false); ++ break; ++ case PECI_WRPKGCFG_CMD: ++ case PECI_WRIAMSR_CMD: ++ case PECI_WRPCICFG_CMD: ++ case PECI_WRPCICFGLOCAL_CMD: ++ /* Check if the AW FCS byte is already provided */ ++ ret = peci_aw_fcs(msg, 2 + msg->tx_len, &aw_fcs); ++ if (ret) ++ break; ++ ++ if (msg->tx_buf[msg->tx_len - 1] != (0x80 ^ aw_fcs)) { ++ /* Add an Assured Write Frame Check Sequence byte */ ++ /* Increment the tx_len to include the new byte */ ++ msg->tx_len++; ++ ret = peci_aw_fcs(msg, 2 + msg->tx_len, ++ &aw_fcs); ++ if (ret) ++ break; ++ ++ msg->tx_buf[msg->tx_len - 1] = 0x80 ^ aw_fcs; ++ } ++ ++ ret = peci_xfer_with_retries(adapter, msg, true); ++ break; ++ case PECI_GET_DIB_CMD: ++ case PECI_GET_TEMP_CMD: ++ default: ++ ret = peci_xfer(adapter, msg); ++ break; ++ } ++ } + +- return peci_xfer(adapter, msg); ++ return ret; + } + +-static int peci_ioctl_ping(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_ping(struct peci_adapter *adapter, void *vmsg) + { + struct peci_ping_msg *umsg = vmsg; +- struct peci_xfer_msg msg; ++ struct peci_xfer_msg *msg; ++ int ret; ++ ++ msg = peci_get_xfer_msg(0, 0); ++ if (!msg) ++ return -ENOMEM; + +- msg.addr = umsg->addr; +- msg.tx_len = 0; +- msg.rx_len = 0; ++ msg->addr = umsg->addr; + +- return peci_xfer(adapter, &msg); ++ ret = peci_xfer(adapter, msg); ++ ++ peci_put_xfer_msg(msg); ++ ++ return ret; + } + +-static int peci_ioctl_get_dib(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_get_dib(struct peci_adapter *adapter, void *vmsg) + { + struct peci_get_dib_msg *umsg = vmsg; +- struct peci_xfer_msg msg; +- int rc; ++ struct peci_xfer_msg *msg; ++ int ret; + +- msg.addr = umsg->addr; +- msg.tx_len = GET_DIB_WR_LEN; +- msg.rx_len = GET_DIB_RD_LEN; +- msg.tx_buf[0] = GET_DIB_PECI_CMD; ++ msg = peci_get_xfer_msg(PECI_GET_DIB_WR_LEN, PECI_GET_DIB_RD_LEN); ++ if (!msg) ++ return -ENOMEM; + +- rc = peci_xfer(adapter, &msg); +- if (rc) +- return rc; ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_GET_DIB_CMD; + +- umsg->dib = le64_to_cpup((__le64 *)msg.rx_buf); ++ ret = peci_xfer(adapter, msg); ++ if (ret) ++ goto out; + +- return 0; ++ umsg->dib = le64_to_cpup((__le64 *)msg->rx_buf); ++ ++out: ++ peci_put_xfer_msg(msg); ++ ++ return ret; + } + +-static int peci_ioctl_get_temp(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_get_temp(struct peci_adapter *adapter, void *vmsg) + { + struct peci_get_temp_msg *umsg = vmsg; +- struct peci_xfer_msg msg; +- int rc; ++ struct peci_xfer_msg *msg; ++ int ret; + +- msg.addr = umsg->addr; +- msg.tx_len = GET_TEMP_WR_LEN; +- msg.rx_len = GET_TEMP_RD_LEN; +- msg.tx_buf[0] = GET_TEMP_PECI_CMD; ++ msg = peci_get_xfer_msg(PECI_GET_TEMP_WR_LEN, PECI_GET_TEMP_RD_LEN); ++ if (!msg) ++ return -ENOMEM; + +- rc = peci_xfer(adapter, &msg); +- if (rc) +- return rc; ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_GET_TEMP_CMD; + +- umsg->temp_raw = le16_to_cpup((__le16 *)msg.rx_buf); ++ ret = peci_xfer(adapter, msg); ++ if (ret) ++ goto out; + +- return 0; ++ umsg->temp_raw = le16_to_cpup((__le16 *)msg->rx_buf); ++ ++out: ++ peci_put_xfer_msg(msg); ++ ++ return ret; + } + +-static int peci_ioctl_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg) + { + struct peci_rd_pkg_cfg_msg *umsg = vmsg; +- struct peci_xfer_msg msg; +- int rc = 0; ++ struct peci_xfer_msg *msg; ++ int ret; + + /* Per the PECI spec, the read length must be a byte, word, or dword */ + if (umsg->rx_len != 1 && umsg->rx_len != 2 && umsg->rx_len != 4) { +@@ -334,29 +495,35 @@ static int peci_ioctl_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg) + return -EINVAL; + } + +- msg.addr = umsg->addr; +- msg.tx_len = RDPKGCFG_WRITE_LEN; +- /* read lengths of 1 and 2 result in an error, so only use 4 for now */ +- msg.rx_len = RDPKGCFG_READ_LEN_BASE + umsg->rx_len; +- msg.tx_buf[0] = RDPKGCFG_PECI_CMD; +- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ +- /* Host ID is 0 for PECI 3.0 */ +- msg.tx_buf[2] = umsg->index; /* RdPkgConfig index */ +- msg.tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */ +- msg.tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */ ++ msg = peci_get_xfer_msg(PECI_RDPKGCFG_WRITE_LEN, ++ PECI_RDPKGCFG_READ_LEN_BASE + umsg->rx_len); ++ if (!msg) ++ return -ENOMEM; ++ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_RDPKGCFG_CMD; ++ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ ++ /* Host ID is 0 for PECI 3.0 */ ++ msg->tx_buf[2] = umsg->index; /* RdPkgConfig index */ ++ msg->tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */ ++ msg->tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */ ++ ++ ret = peci_xfer_with_retries(adapter, msg, false); ++ if (!ret) ++ memcpy(umsg->pkg_config, &msg->rx_buf[1], umsg->rx_len); + +- rc = peci_xfer_with_retries(adapter, &msg, false); +- if (!rc) +- memcpy(umsg->pkg_config, &msg.rx_buf[1], umsg->rx_len); ++ umsg->cc = msg->rx_buf[0]; ++ peci_put_xfer_msg(msg); + +- return rc; ++ return ret; + } + +-static int peci_ioctl_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg) + { + struct peci_wr_pkg_cfg_msg *umsg = vmsg; +- struct peci_xfer_msg msg; +- int rc = 0, i; ++ struct peci_xfer_msg *msg; ++ int ret, i; ++ u8 aw_fcs; + + /* Per the PECI spec, the write length must be a dword */ + if (umsg->tx_len != 4) { +@@ -365,86 +532,116 @@ static int peci_ioctl_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg) + return -EINVAL; + } + +- msg.addr = umsg->addr; +- msg.tx_len = WRPKGCFG_WRITE_LEN_BASE + umsg->tx_len; +- /* read lengths of 1 and 2 result in an error, so only use 4 for now */ +- msg.rx_len = WRPKGCFG_READ_LEN; +- msg.tx_buf[0] = WRPKGCFG_PECI_CMD; +- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ ++ msg = peci_get_xfer_msg(PECI_WRPKGCFG_WRITE_LEN_BASE + umsg->tx_len, ++ PECI_WRPKGCFG_READ_LEN); ++ if (!msg) ++ return -ENOMEM; ++ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_WRPKGCFG_CMD; ++ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ + /* Host ID is 0 for PECI 3.0 */ +- msg.tx_buf[2] = umsg->index; /* RdPkgConfig index */ +- msg.tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */ +- msg.tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */ ++ msg->tx_buf[2] = umsg->index; /* RdPkgConfig index */ ++ msg->tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */ ++ msg->tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */ + for (i = 0; i < umsg->tx_len; i++) +- msg.tx_buf[5 + i] = (u8)(umsg->value >> (i << 3)); ++ msg->tx_buf[5 + i] = (u8)(umsg->value >> (i << 3)); ++ ++ /* Add an Assured Write Frame Check Sequence byte */ ++ ret = peci_aw_fcs(msg, 8 + umsg->tx_len, &aw_fcs); ++ if (ret) ++ goto out; ++ ++ msg->tx_buf[5 + i] = 0x80 ^ aw_fcs; + +- /* Add an Assure Write Frame Check Sequence byte */ +- msg.tx_buf[5 + i] = 0x80 ^ +- peci_aw_fcs((u8 *)&msg, 8 + umsg->tx_len); ++ ret = peci_xfer_with_retries(adapter, msg, true); + +- rc = peci_xfer_with_retries(adapter, &msg, true); ++out: ++ umsg->cc = msg->rx_buf[0]; ++ peci_put_xfer_msg(msg); + +- return rc; ++ return ret; + } + +-static int peci_ioctl_rd_ia_msr(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_rd_ia_msr(struct peci_adapter *adapter, void *vmsg) + { + struct peci_rd_ia_msr_msg *umsg = vmsg; +- struct peci_xfer_msg msg; +- int rc = 0; +- +- msg.addr = umsg->addr; +- msg.tx_len = RDIAMSR_WRITE_LEN; +- msg.rx_len = RDIAMSR_READ_LEN; +- msg.tx_buf[0] = RDIAMSR_PECI_CMD; +- msg.tx_buf[1] = 0; +- msg.tx_buf[2] = umsg->thread_id; +- msg.tx_buf[3] = (u8)umsg->address; +- msg.tx_buf[4] = (u8)(umsg->address >> 8); +- +- rc = peci_xfer_with_retries(adapter, &msg, false); +- if (!rc) +- memcpy(&umsg->value, &msg.rx_buf[1], sizeof(uint64_t)); +- +- return rc; ++ struct peci_xfer_msg *msg; ++ int ret; ++ ++ msg = peci_get_xfer_msg(PECI_RDIAMSR_WRITE_LEN, PECI_RDIAMSR_READ_LEN); ++ if (!msg) ++ return -ENOMEM; ++ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_RDIAMSR_CMD; ++ msg->tx_buf[1] = 0; ++ msg->tx_buf[2] = umsg->thread_id; ++ msg->tx_buf[3] = (u8)umsg->address; ++ msg->tx_buf[4] = (u8)(umsg->address >> 8); ++ ++ ret = peci_xfer_with_retries(adapter, msg, false); ++ if (!ret) ++ memcpy(&umsg->value, &msg->rx_buf[1], sizeof(uint64_t)); ++ ++ umsg->cc = msg->rx_buf[0]; ++ peci_put_xfer_msg(msg); ++ ++ return ret; + } + +-static int peci_ioctl_rd_pci_cfg(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_wr_ia_msr(struct peci_adapter *adapter, void *vmsg) ++{ ++ return -ENOSYS; /* Not implemented yet */ ++} ++ ++static int peci_cmd_rd_pci_cfg(struct peci_adapter *adapter, void *vmsg) + { + struct peci_rd_pci_cfg_msg *umsg = vmsg; +- struct peci_xfer_msg msg; ++ struct peci_xfer_msg *msg; + u32 address; +- int rc = 0; ++ int ret; ++ ++ msg = peci_get_xfer_msg(PECI_RDPCICFG_WRITE_LEN, ++ PECI_RDPCICFG_READ_LEN); ++ if (!msg) ++ return -ENOMEM; + + address = umsg->reg; /* [11:0] - Register */ + address |= (u32)umsg->function << 12; /* [14:12] - Function */ + address |= (u32)umsg->device << 15; /* [19:15] - Device */ + address |= (u32)umsg->bus << 20; /* [27:20] - Bus */ + /* [31:28] - Reserved */ +- msg.addr = umsg->addr; +- msg.tx_len = RDPCICFG_WRITE_LEN; +- msg.rx_len = RDPCICFG_READ_LEN; +- msg.tx_buf[0] = RDPCICFG_PECI_CMD; +- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_RDPCICFG_CMD; ++ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ + /* Host ID is 0 for PECI 3.0 */ +- msg.tx_buf[2] = (u8)address; /* LSB - PCI Config Address */ +- msg.tx_buf[3] = (u8)(address >> 8); /* PCI Config Address */ +- msg.tx_buf[4] = (u8)(address >> 16); /* PCI Config Address */ +- msg.tx_buf[5] = (u8)(address >> 24); /* MSB - PCI Config Address */ ++ msg->tx_buf[2] = (u8)address; /* LSB - PCI Config Address */ ++ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Config Address */ ++ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Config Address */ ++ msg->tx_buf[5] = (u8)(address >> 24); /* MSB - PCI Config Address */ ++ ++ ret = peci_xfer_with_retries(adapter, msg, false); ++ if (!ret) ++ memcpy(umsg->pci_config, &msg->rx_buf[1], 4); ++ ++ umsg->cc = msg->rx_buf[0]; ++ peci_put_xfer_msg(msg); + +- rc = peci_xfer_with_retries(adapter, &msg, false); +- if (!rc) +- memcpy(umsg->pci_config, &msg.rx_buf[1], 4); ++ return ret; ++} + +- return rc; ++static int peci_cmd_wr_pci_cfg(struct peci_adapter *adapter, void *vmsg) ++{ ++ return -ENOSYS; /* Not implemented yet */ + } + +-static int peci_ioctl_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) + { + struct peci_rd_pci_cfg_local_msg *umsg = vmsg; +- struct peci_xfer_msg msg; ++ struct peci_xfer_msg *msg; + u32 address; +- int rc = 0; ++ int ret; + + /* Per the PECI spec, the read length must be a byte, word, or dword */ + if (umsg->rx_len != 1 && umsg->rx_len != 2 && umsg->rx_len != 4) { +@@ -453,34 +650,42 @@ static int peci_ioctl_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) + return -EINVAL; + } + ++ msg = peci_get_xfer_msg(PECI_RDPCICFGLOCAL_WRITE_LEN, ++ PECI_RDPCICFGLOCAL_READ_LEN_BASE + ++ umsg->rx_len); ++ if (!msg) ++ return -ENOMEM; ++ + address = umsg->reg; /* [11:0] - Register */ + address |= (u32)umsg->function << 12; /* [14:12] - Function */ + address |= (u32)umsg->device << 15; /* [19:15] - Device */ + address |= (u32)umsg->bus << 20; /* [23:20] - Bus */ + +- msg.addr = umsg->addr; +- msg.tx_len = RDPCICFGLOCAL_WRITE_LEN; +- msg.rx_len = RDPCICFGLOCAL_READ_LEN_BASE + umsg->rx_len; +- msg.tx_buf[0] = RDPCICFGLOCAL_PECI_CMD; +- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ +- /* Host ID is 0 for PECI 3.0 */ +- msg.tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */ +- msg.tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */ +- msg.tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_RDPCICFGLOCAL_CMD; ++ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ ++ /* Host ID is 0 for PECI 3.0 */ ++ msg->tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */ ++ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */ ++ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */ ++ ++ ret = peci_xfer_with_retries(adapter, msg, false); ++ if (!ret) ++ memcpy(umsg->pci_config, &msg->rx_buf[1], umsg->rx_len); + +- rc = peci_xfer_with_retries(adapter, &msg, false); +- if (!rc) +- memcpy(umsg->pci_config, &msg.rx_buf[1], umsg->rx_len); ++ umsg->cc = msg->rx_buf[0]; ++ peci_put_xfer_msg(msg); + +- return rc; ++ return ret; + } + +-static int peci_ioctl_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) ++static int peci_cmd_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) + { + struct peci_wr_pci_cfg_local_msg *umsg = vmsg; +- struct peci_xfer_msg msg; +- int rc = 0, i; ++ struct peci_xfer_msg *msg; + u32 address; ++ int ret, i; ++ u8 aw_fcs; + + /* Per the PECI spec, the write length must be a byte, word, or dword */ + if (umsg->tx_len != 1 && umsg->tx_len != 2 && umsg->tx_len != 4) { +@@ -489,47 +694,57 @@ static int peci_ioctl_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) + return -EINVAL; + } + ++ msg = peci_get_xfer_msg(PECI_WRPCICFGLOCAL_WRITE_LEN_BASE + ++ umsg->tx_len, PECI_WRPCICFGLOCAL_READ_LEN); ++ if (!msg) ++ return -ENOMEM; ++ + address = umsg->reg; /* [11:0] - Register */ + address |= (u32)umsg->function << 12; /* [14:12] - Function */ + address |= (u32)umsg->device << 15; /* [19:15] - Device */ + address |= (u32)umsg->bus << 20; /* [23:20] - Bus */ + +- msg.addr = umsg->addr; +- msg.tx_len = WRPCICFGLOCAL_WRITE_LEN_BASE + umsg->tx_len; +- msg.rx_len = WRPCICFGLOCAL_READ_LEN; +- msg.tx_buf[0] = WRPCICFGLOCAL_PECI_CMD; +- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ +- /* Host ID is 0 for PECI 3.0 */ +- msg.tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */ +- msg.tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */ +- msg.tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_WRPCICFGLOCAL_CMD; ++ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */ ++ /* Host ID is 0 for PECI 3.0 */ ++ msg->tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */ ++ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */ ++ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */ + for (i = 0; i < umsg->tx_len; i++) +- msg.tx_buf[5 + i] = (u8)(umsg->value >> (i << 3)); ++ msg->tx_buf[5 + i] = (u8)(umsg->value >> (i << 3)); ++ ++ /* Add an Assured Write Frame Check Sequence byte */ ++ ret = peci_aw_fcs(msg, 8 + umsg->tx_len, &aw_fcs); ++ if (ret) ++ goto out; + +- /* Add an Assure Write Frame Check Sequence byte */ +- msg.tx_buf[5 + i] = 0x80 ^ +- peci_aw_fcs((u8 *)&msg, 8 + umsg->tx_len); ++ msg->tx_buf[5 + i] = 0x80 ^ aw_fcs; + +- rc = peci_xfer_with_retries(adapter, &msg, true); ++ ret = peci_xfer_with_retries(adapter, msg, true); + +- return rc; ++out: ++ umsg->cc = msg->rx_buf[0]; ++ peci_put_xfer_msg(msg); ++ ++ return ret; + } + +-typedef int (*peci_ioctl_fn_type)(struct peci_adapter *, void *); +- +-static const peci_ioctl_fn_type peci_ioctl_fn[PECI_CMD_MAX] = { +- peci_ioctl_xfer, +- peci_ioctl_ping, +- peci_ioctl_get_dib, +- peci_ioctl_get_temp, +- peci_ioctl_rd_pkg_cfg, +- peci_ioctl_wr_pkg_cfg, +- peci_ioctl_rd_ia_msr, +- NULL, /* Reserved */ +- peci_ioctl_rd_pci_cfg, +- NULL, /* Reserved */ +- peci_ioctl_rd_pci_cfg_local, +- peci_ioctl_wr_pci_cfg_local, ++typedef int (*peci_cmd_fn_type)(struct peci_adapter *, void *); ++ ++static const peci_cmd_fn_type peci_cmd_fn[PECI_CMD_MAX] = { ++ peci_cmd_xfer, ++ peci_cmd_ping, ++ peci_cmd_get_dib, ++ peci_cmd_get_temp, ++ peci_cmd_rd_pkg_cfg, ++ peci_cmd_wr_pkg_cfg, ++ peci_cmd_rd_ia_msr, ++ peci_cmd_wr_ia_msr, ++ peci_cmd_rd_pci_cfg, ++ peci_cmd_wr_pci_cfg, ++ peci_cmd_rd_pci_cfg_local, ++ peci_cmd_wr_pci_cfg_local, + }; + + /** +@@ -545,109 +760,28 @@ static const peci_ioctl_fn_type peci_ioctl_fn[PECI_CMD_MAX] = { + */ + int peci_command(struct peci_adapter *adapter, enum peci_cmd cmd, void *vmsg) + { +- int rc = 0; ++ int ret; + + if (cmd >= PECI_CMD_MAX || cmd < PECI_CMD_XFER) +- return -EINVAL; ++ return -ENOTTY; + + dev_dbg(&adapter->dev, "%s, cmd=0x%02x\n", __func__, cmd); + +- if (!peci_ioctl_fn[cmd]) ++ if (!peci_cmd_fn[cmd]) + return -EINVAL; + +- rt_mutex_lock(&adapter->bus_lock); ++ mutex_lock(&adapter->bus_lock); + +- rc = peci_cmd_support(adapter, cmd); +- if (!rc) +- rc = peci_ioctl_fn[cmd](adapter, vmsg); ++ ret = peci_check_cmd_support(adapter, cmd); ++ if (!ret) ++ ret = peci_cmd_fn[cmd](adapter, vmsg); + +- rt_mutex_unlock(&adapter->bus_lock); ++ mutex_unlock(&adapter->bus_lock); + +- return rc; ++ return ret; + } + EXPORT_SYMBOL_GPL(peci_command); + +-static long peci_ioctl(struct file *file, unsigned int iocmd, unsigned long arg) +-{ +- struct peci_adapter *adapter = file->private_data; +- void __user *argp = (void __user *)arg; +- unsigned int msg_len; +- enum peci_cmd cmd; +- int rc = 0; +- u8 *msg; +- +- if (!capable(CAP_SYS_ADMIN)) +- return -EPERM; +- +- dev_dbg(&adapter->dev, "ioctl, cmd=0x%x, arg=0x%lx\n", iocmd, arg); +- +- switch (iocmd) { +- case PECI_IOC_XFER: +- case PECI_IOC_PING: +- case PECI_IOC_GET_DIB: +- case PECI_IOC_GET_TEMP: +- case PECI_IOC_RD_PKG_CFG: +- case PECI_IOC_WR_PKG_CFG: +- case PECI_IOC_RD_IA_MSR: +- case PECI_IOC_RD_PCI_CFG: +- case PECI_IOC_RD_PCI_CFG_LOCAL: +- case PECI_IOC_WR_PCI_CFG_LOCAL: +- cmd = _IOC_NR(iocmd); +- msg_len = _IOC_SIZE(iocmd); +- break; +- +- default: +- dev_dbg(&adapter->dev, "Invalid ioctl cmd : 0x%x\n", iocmd); +- return -ENOTTY; +- } +- +- if (!access_ok(argp, msg_len)) +- return -EFAULT; +- +- msg = memdup_user(argp, msg_len); +- if (IS_ERR(msg)) +- return PTR_ERR(msg); +- +- rc = peci_command(adapter, cmd, msg); +- +- if (!rc && copy_to_user(argp, msg, msg_len)) +- rc = -EFAULT; +- +- kfree(msg); +- return (long)rc; +-} +- +-static int peci_open(struct inode *inode, struct file *file) +-{ +- unsigned int minor = iminor(inode); +- struct peci_adapter *adapter; +- +- adapter = peci_get_adapter(minor); +- if (!adapter) +- return -ENODEV; +- +- file->private_data = adapter; +- +- return 0; +-} +- +-static int peci_release(struct inode *inode, struct file *file) +-{ +- struct peci_adapter *adapter = file->private_data; +- +- peci_put_adapter(adapter); +- file->private_data = NULL; +- +- return 0; +-} +- +-static const struct file_operations peci_fops = { +- .owner = THIS_MODULE, +- .unlocked_ioctl = peci_ioctl, +- .open = peci_open, +- .release = peci_release, +-}; +- + static int peci_detect(struct peci_adapter *adapter, u8 addr) + { + struct peci_ping_msg msg; +@@ -666,9 +800,9 @@ peci_of_match_device(const struct of_device_id *matches, + return NULL; + + return of_match_device(matches, &client->dev); +-#else ++#else /* CONFIG_OF */ + return NULL; +-#endif ++#endif /* CONFIG_OF */ + } + + static const struct peci_device_id * +@@ -737,6 +871,7 @@ static int peci_device_probe(struct device *dev) + + err_detach_pm_domain: + dev_pm_domain_detach(&client->dev, true); ++ + return status; + } + +@@ -775,13 +910,14 @@ static void peci_device_shutdown(struct device *dev) + driver->shutdown(client); + } + +-static struct bus_type peci_bus_type = { ++struct bus_type peci_bus_type = { + .name = "peci", + .match = peci_device_match, + .probe = peci_device_probe, + .remove = peci_device_remove, + .shutdown = peci_device_shutdown, + }; ++EXPORT_SYMBOL_GPL(peci_bus_type); + + static int peci_check_addr_validity(u8 addr) + { +@@ -814,18 +950,22 @@ static int peci_check_client_busy(struct device *dev, void *client_new_p) + int peci_get_cpu_id(struct peci_adapter *adapter, u8 addr, u32 *cpu_id) + { + struct peci_rd_pkg_cfg_msg msg; +- int rc; ++ int ret; + + msg.addr = addr; +- msg.index = MBX_INDEX_CPU_ID; +- msg.param = PKG_ID_CPU_ID; ++ msg.index = PECI_MBX_INDEX_CPU_ID; ++ msg.param = PECI_PKG_ID_CPU_ID; + msg.rx_len = 4; + +- rc = peci_command(adapter, PECI_CMD_RD_PKG_CFG, &msg); +- if (!rc) +- *cpu_id = le32_to_cpup((__le32 *)msg.pkg_config); ++ ret = peci_command(adapter, PECI_CMD_RD_PKG_CFG, &msg); ++ if (msg.cc != PECI_DEV_CC_SUCCESS) ++ ret = -EAGAIN; ++ if (ret) ++ return ret; ++ ++ *cpu_id = le32_to_cpup((__le32 *)msg.pkg_config); + +- return rc; ++ return 0; + } + EXPORT_SYMBOL_GPL(peci_get_cpu_id); + +@@ -833,7 +973,7 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter, + struct peci_board_info const *info) + { + struct peci_client *client; +- int rc; ++ int ret; + + /* Increase reference count for the adapter assigned */ + if (!peci_get_adapter(adapter->nr)) +@@ -847,46 +987,49 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter, + client->addr = info->addr; + strlcpy(client->name, info->type, sizeof(client->name)); + +- rc = peci_check_addr_validity(client->addr); +- if (rc) { ++ ret = peci_check_addr_validity(client->addr); ++ if (ret) { + dev_err(&adapter->dev, "Invalid PECI CPU address 0x%02hx\n", + client->addr); + goto err_free_client_silent; + } + + /* Check online status of client */ +- rc = peci_detect(adapter, client->addr); +- if (rc) ++ ret = peci_detect(adapter, client->addr); ++ if (ret) + goto err_free_client; + +- rc = device_for_each_child(&adapter->dev, client, +- peci_check_client_busy); +- if (rc) ++ ret = device_for_each_child(&adapter->dev, client, ++ peci_check_client_busy); ++ if (ret) + goto err_free_client; + + client->dev.parent = &client->adapter->dev; + client->dev.bus = &peci_bus_type; + client->dev.type = &peci_client_type; +- client->dev.of_node = info->of_node; ++ client->dev.of_node = of_node_get(info->of_node); + dev_set_name(&client->dev, "%d-%02x", adapter->nr, client->addr); + +- rc = device_register(&client->dev); +- if (rc) +- goto err_free_client; ++ ret = device_register(&client->dev); ++ if (ret) ++ goto err_put_of_node; + + dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", + client->name, dev_name(&client->dev)); + + return client; + ++err_put_of_node: ++ of_node_put(info->of_node); + err_free_client: + dev_err(&adapter->dev, + "Failed to register peci client %s at 0x%02x (%d)\n", +- client->name, client->addr, rc); ++ client->name, client->addr, ret); + err_free_client_silent: + kfree(client); + err_put_adapter: + peci_put_adapter(adapter); ++ + return NULL; + } + +@@ -895,8 +1038,10 @@ static void peci_unregister_device(struct peci_client *client) + if (!client) + return; + +- if (client->dev.of_node) ++ if (client->dev.of_node) { + of_node_clear_flag(client->dev.of_node, OF_POPULATED); ++ of_node_put(client->dev.of_node); ++ } + + device_unregister(&client->dev); + } +@@ -916,7 +1061,7 @@ static void peci_adapter_dev_release(struct device *dev) + + dev_dbg(dev, "%s: %s\n", __func__, adapter->name); + mutex_destroy(&adapter->userspace_clients_lock); +- rt_mutex_destroy(&adapter->bus_lock); ++ mutex_destroy(&adapter->bus_lock); + kfree(adapter); + } + +@@ -928,7 +1073,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev, + struct peci_board_info info = {}; + struct peci_client *client; + char *blank, end; +- int rc; ++ short addr; ++ int ret; + + /* Parse device type */ + blank = strchr(buf, ' '); +@@ -943,16 +1089,17 @@ static ssize_t peci_sysfs_new_device(struct device *dev, + memcpy(info.type, buf, blank - buf); + + /* Parse remaining parameters, reject extra parameters */ +- rc = sscanf(++blank, "%hi%c", &info.addr, &end); +- if (rc < 1) { ++ ret = sscanf(++blank, "%hi%c", &addr, &end); ++ if (ret < 1) { + dev_err(dev, "%s: Can't parse client address\n", "new_device"); + return -EINVAL; + } +- if (rc > 1 && end != '\n') { ++ if (ret > 1 && end != '\n') { + dev_err(dev, "%s: Extra parameters\n", "new_device"); + return -EINVAL; + } + ++ info.addr = (u8)addr; + client = peci_new_device(adapter, &info); + if (!client) + return -EINVAL; +@@ -961,8 +1108,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev, + mutex_lock(&adapter->userspace_clients_lock); + list_add_tail(&client->detected, &adapter->userspace_clients); + mutex_unlock(&adapter->userspace_clients_lock); +- dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device", +- info.type, info.addr); ++ dev_dbg(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device", ++ info.type, info.addr); + + return count; + } +@@ -975,9 +1122,9 @@ static ssize_t peci_sysfs_delete_device(struct device *dev, + struct peci_adapter *adapter = to_peci_adapter(dev); + struct peci_client *client, *next; + struct peci_board_info info = {}; +- struct peci_driver *driver; + char *blank, end; +- int rc; ++ short addr; ++ int ret; + + /* Parse device type */ + blank = strchr(buf, ' '); +@@ -992,41 +1139,41 @@ static ssize_t peci_sysfs_delete_device(struct device *dev, + memcpy(info.type, buf, blank - buf); + + /* Parse remaining parameters, reject extra parameters */ +- rc = sscanf(++blank, "%hi%c", &info.addr, &end); +- if (rc < 1) { ++ ret = sscanf(++blank, "%hi%c", &addr, &end); ++ if (ret < 1) { + dev_err(dev, "%s: Can't parse client address\n", + "delete_device"); + return -EINVAL; + } +- if (rc > 1 && end != '\n') { ++ if (ret > 1 && end != '\n') { + dev_err(dev, "%s: Extra parameters\n", "delete_device"); + return -EINVAL; + } + ++ info.addr = (u8)addr; ++ + /* Make sure the device was added through sysfs */ +- rc = -ENOENT; ++ ret = -ENOENT; + mutex_lock(&adapter->userspace_clients_lock); + list_for_each_entry_safe(client, next, &adapter->userspace_clients, + detected) { +- driver = to_peci_driver(client->dev.driver); +- + if (client->addr == info.addr && + !strncmp(client->name, info.type, PECI_NAME_SIZE)) { +- dev_info(dev, "%s: Deleting device %s at 0x%02hx\n", +- "delete_device", client->name, client->addr); ++ dev_dbg(dev, "%s: Deleting device %s at 0x%02hx\n", ++ "delete_device", client->name, client->addr); + list_del(&client->detected); + peci_unregister_device(client); +- rc = count; ++ ret = count; + break; + } + } + mutex_unlock(&adapter->userspace_clients_lock); + +- if (rc < 0) +- dev_err(dev, "%s: Can't find device in list\n", ++ if (ret < 0) ++ dev_dbg(dev, "%s: Can't find device in list\n", + "delete_device"); + +- return rc; ++ return ret; + } + static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, 0200, NULL, + peci_sysfs_delete_device); +@@ -1039,10 +1186,11 @@ static struct attribute *peci_adapter_attrs[] = { + }; + ATTRIBUTE_GROUPS(peci_adapter); + +-static struct device_type peci_adapter_type = { ++struct device_type peci_adapter_type = { + .groups = peci_adapter_groups, + .release = peci_adapter_dev_release, + }; ++EXPORT_SYMBOL_GPL(peci_adapter_type); + + /** + * peci_verify_adapter - return parameter as peci_adapter, or NULL +@@ -1063,32 +1211,26 @@ static struct peci_client *peci_of_register_device(struct peci_adapter *adapter, + struct device_node *node) + { + struct peci_board_info info = {}; +- struct peci_client *result; +- const __be32 *addr_be; +- int len; ++ struct peci_client *client; ++ u32 addr; ++ int ret; + + dev_dbg(&adapter->dev, "register %pOF\n", node); + +- if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { +- dev_err(&adapter->dev, "modalias failure on %pOF\n", node); +- return ERR_PTR(-EINVAL); +- } +- +- addr_be = of_get_property(node, "reg", &len); +- if (!addr_be || len < sizeof(*addr_be)) { ++ ret = of_property_read_u32(node, "reg", &addr); ++ if (ret) { + dev_err(&adapter->dev, "invalid reg on %pOF\n", node); +- return ERR_PTR(-EINVAL); ++ return ERR_PTR(ret); + } + +- info.addr = be32_to_cpup(addr_be); +- info.of_node = of_node_get(node); ++ info.addr = addr; ++ info.of_node = node; + +- result = peci_new_device(adapter, &info); +- if (!result) +- result = ERR_PTR(-EINVAL); ++ client = peci_new_device(adapter, &info); ++ if (!client) ++ client = ERR_PTR(-EINVAL); + +- of_node_put(node); +- return result; ++ return client; + } + + static void peci_of_register_devices(struct peci_adapter *adapter) +@@ -1119,7 +1261,7 @@ static void peci_of_register_devices(struct peci_adapter *adapter) + + of_node_put(bus); + } +-#else ++#else /* CONFIG_OF */ + static void peci_of_register_devices(struct peci_adapter *adapter) { } + #endif /* CONFIG_OF */ + +@@ -1163,9 +1305,7 @@ static struct peci_adapter *peci_of_find_adapter(struct device_node *node) + return adapter; + } + +-static int peci_of_notify(struct notifier_block *nb, +- unsigned long action, +- void *arg) ++static int peci_of_notify(struct notifier_block *nb, ulong action, void *arg) + { + struct of_reconfig_data *rd = arg; + struct peci_adapter *adapter; +@@ -1216,7 +1356,7 @@ static int peci_of_notify(struct notifier_block *nb, + static struct notifier_block peci_of_notifier = { + .notifier_call = peci_of_notify, + }; +-#else ++#else /* CONFIG_OF_DYNAMIC */ + extern struct notifier_block peci_of_notifier; + #endif /* CONFIG_OF_DYNAMIC */ + +@@ -1240,7 +1380,7 @@ extern struct notifier_block peci_of_notifier; + * + * Return: the peci_adapter structure on success, else NULL. + */ +-struct peci_adapter *peci_alloc_adapter(struct device *dev, unsigned int size) ++struct peci_adapter *peci_alloc_adapter(struct device *dev, uint size) + { + struct peci_adapter *adapter; + +@@ -1263,7 +1403,7 @@ EXPORT_SYMBOL_GPL(peci_alloc_adapter); + + static int peci_register_adapter(struct peci_adapter *adapter) + { +- int rc = -EINVAL; ++ int ret = -EINVAL; + + /* Can't register until after driver model init */ + if (WARN_ON(!is_registered)) +@@ -1275,27 +1415,17 @@ static int peci_register_adapter(struct peci_adapter *adapter) + if (WARN(!adapter->xfer, "peci adapter has no xfer function\n")) + goto err_free_idr; + +- rt_mutex_init(&adapter->bus_lock); ++ mutex_init(&adapter->bus_lock); + mutex_init(&adapter->userspace_clients_lock); + INIT_LIST_HEAD(&adapter->userspace_clients); + + dev_set_name(&adapter->dev, "peci-%d", adapter->nr); + +- /* cdev */ +- cdev_init(&adapter->cdev, &peci_fops); +- adapter->cdev.owner = THIS_MODULE; +- adapter->dev.devt = MKDEV(MAJOR(peci_devt), adapter->nr); +- rc = cdev_add(&adapter->cdev, adapter->dev.devt, 1); +- if (rc) { +- pr_err("adapter '%s': can't add cdev (%d)\n", +- adapter->name, rc); +- goto err_free_idr; +- } +- rc = device_add(&adapter->dev); +- if (rc) { ++ ret = device_add(&adapter->dev); ++ if (ret) { + pr_err("adapter '%s': can't add device (%d)\n", +- adapter->name, rc); +- goto err_del_cdev; ++ adapter->name, ret); ++ goto err_free_idr; + } + + dev_dbg(&adapter->dev, "adapter [%s] registered\n", adapter->name); +@@ -1309,13 +1439,11 @@ static int peci_register_adapter(struct peci_adapter *adapter) + + return 0; + +-err_del_cdev: +- cdev_del(&adapter->cdev); + err_free_idr: + mutex_lock(&core_lock); + idr_remove(&peci_adapter_idr, adapter->nr); + mutex_unlock(&core_lock); +- return rc; ++ return ret; + } + + static int peci_add_numbered_adapter(struct peci_adapter *adapter) +@@ -1354,12 +1482,10 @@ int peci_add_adapter(struct peci_adapter *adapter) + struct device *dev = &adapter->dev; + int id; + +- if (dev->of_node) { +- id = of_alias_get_id(dev->of_node, "peci"); +- if (id >= 0) { +- adapter->nr = id; +- return peci_add_numbered_adapter(adapter); +- } ++ id = of_alias_get_id(dev->of_node, "peci"); ++ if (id >= 0) { ++ adapter->nr = id; ++ return peci_add_numbered_adapter(adapter); + } + + mutex_lock(&core_lock); +@@ -1411,7 +1537,7 @@ void peci_del_adapter(struct peci_adapter *adapter) + } + mutex_unlock(&adapter->userspace_clients_lock); + +- /** ++ /* + * Detach any active clients. This can't fail, thus we do not + * check the returned value. + */ +@@ -1420,13 +1546,8 @@ void peci_del_adapter(struct peci_adapter *adapter) + /* device name is gone after device_unregister */ + dev_dbg(&adapter->dev, "adapter [%s] unregistered\n", adapter->name); + +- /* free cdev */ +- cdev_del(&adapter->cdev); +- + pm_runtime_disable(&adapter->dev); +- + nr = adapter->nr; +- + device_unregister(&adapter->dev); + + /* free bus id */ +@@ -1436,6 +1557,18 @@ void peci_del_adapter(struct peci_adapter *adapter) + } + EXPORT_SYMBOL_GPL(peci_del_adapter); + ++int peci_for_each_dev(void *data, int (*fn)(struct device *, void *)) ++{ ++ int ret; ++ ++ mutex_lock(&core_lock); ++ ret = bus_for_each_dev(&peci_bus_type, NULL, data, fn); ++ mutex_unlock(&core_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(peci_for_each_dev); ++ + /** + * peci_register_driver - register a PECI driver + * @owner: owner module of the driver being registered +@@ -1446,7 +1579,7 @@ EXPORT_SYMBOL_GPL(peci_del_adapter); + */ + int peci_register_driver(struct module *owner, struct peci_driver *driver) + { +- int rc; ++ int ret; + + /* Can't register until after driver model init */ + if (WARN_ON(!is_registered)) +@@ -1456,13 +1589,13 @@ int peci_register_driver(struct module *owner, struct peci_driver *driver) + driver->driver.owner = owner; + driver->driver.bus = &peci_bus_type; + +- /** ++ /* + * When registration returns, the driver core + * will have called probe() for all matching-but-unbound devices. + */ +- rc = driver_register(&driver->driver); +- if (rc) +- return rc; ++ ret = driver_register(&driver->driver); ++ if (ret) ++ return ret; + + pr_debug("driver [%s] registered\n", driver->driver.name); + +@@ -1492,13 +1625,6 @@ static int __init peci_init(void) + return ret; + } + +- ret = alloc_chrdev_region(&peci_devt, 0, PECI_CDEV_MAX, "peci"); +- if (ret < 0) { +- pr_err("peci: Failed to allocate chr dev region!\n"); +- bus_unregister(&peci_bus_type); +- return ret; +- } +- + crc8_populate_msb(peci_crc8_table, PECI_CRC8_POLYNOMIAL); + + if (IS_ENABLED(CONFIG_OF_DYNAMIC)) +@@ -1514,11 +1640,10 @@ static void __exit peci_exit(void) + if (IS_ENABLED(CONFIG_OF_DYNAMIC)) + WARN_ON(of_reconfig_notifier_unregister(&peci_of_notifier)); + +- unregister_chrdev_region(peci_devt, PECI_CDEV_MAX); + bus_unregister(&peci_bus_type); + } + +-postcore_initcall(peci_init); ++subsys_initcall(peci_init); + module_exit(peci_exit); + + MODULE_AUTHOR("Jason M Biils "); +diff --git a/drivers/peci/peci-dev.c b/drivers/peci/peci-dev.c +new file mode 100644 +index 0000000..ac9cba0 +--- /dev/null ++++ b/drivers/peci/peci-dev.c +@@ -0,0 +1,346 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * A peci_dev represents an peci_adapter ... an PECI or SMBus master, not a ++ * slave (peci_client) with which messages will be exchanged. It's coupled ++ * with a character special file which is accessed by user mode drivers. ++ * ++ * The list of peci_dev structures is parallel to the peci_adapter lists ++ * maintained by the driver model, and is updated using bus notifications. ++ */ ++struct peci_dev { ++ struct list_head list; ++ struct peci_adapter *adapter; ++ struct device *dev; ++ struct cdev cdev; ++}; ++ ++#define PECI_MINORS MINORMASK ++ ++static dev_t peci_devt; ++static LIST_HEAD(peci_dev_list); ++static DEFINE_SPINLOCK(peci_dev_list_lock); ++ ++static struct peci_dev *peci_dev_get_by_minor(uint index) ++{ ++ struct peci_dev *peci_dev; ++ ++ spin_lock(&peci_dev_list_lock); ++ list_for_each_entry(peci_dev, &peci_dev_list, list) { ++ if (peci_dev->adapter->nr == index) ++ goto found; ++ } ++ peci_dev = NULL; ++found: ++ spin_unlock(&peci_dev_list_lock); ++ ++ return peci_dev; ++} ++ ++static struct peci_dev *peci_dev_alloc(struct peci_adapter *adapter) ++{ ++ struct peci_dev *peci_dev; ++ ++ if (adapter->nr >= PECI_MINORS) { ++ printk(KERN_ERR "peci-dev: Out of device minors (%d)\n", ++ adapter->nr); ++ return ERR_PTR(-ENODEV); ++ } ++ ++ peci_dev = kzalloc(sizeof(*peci_dev), GFP_KERNEL); ++ if (!peci_dev) ++ return ERR_PTR(-ENOMEM); ++ peci_dev->adapter = adapter; ++ ++ spin_lock(&peci_dev_list_lock); ++ list_add_tail(&peci_dev->list, &peci_dev_list); ++ spin_unlock(&peci_dev_list_lock); ++ ++ return peci_dev; ++} ++ ++static void peci_dev_put(struct peci_dev *peci_dev) ++{ ++ spin_lock(&peci_dev_list_lock); ++ list_del(&peci_dev->list); ++ spin_unlock(&peci_dev_list_lock); ++ kfree(peci_dev); ++} ++ ++static ssize_t name_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct peci_dev *peci_dev = peci_dev_get_by_minor(MINOR(dev->devt)); ++ ++ if (!peci_dev) ++ return -ENODEV; ++ ++ return sprintf(buf, "%s\n", peci_dev->adapter->name); ++} ++static DEVICE_ATTR_RO(name); ++ ++static struct attribute *peci_dev_attrs[] = { ++ &dev_attr_name.attr, ++ NULL, ++}; ++ATTRIBUTE_GROUPS(peci_dev); ++ ++static long peci_dev_ioctl(struct file *file, uint iocmd, ulong arg) ++{ ++ struct peci_dev *peci_dev = file->private_data; ++ void __user *umsg = (void __user *)arg; ++ struct peci_xfer_msg *xmsg = NULL; ++ struct peci_xfer_msg uxmsg; ++ enum peci_cmd cmd; ++ u8 *msg = NULL; ++ uint msg_len; ++ int ret; ++ ++ cmd = _IOC_NR(iocmd); ++ msg_len = _IOC_SIZE(iocmd); ++ ++ switch (cmd) { ++ case PECI_CMD_XFER: ++ if (msg_len != sizeof(struct peci_xfer_msg)) { ++ ret = -EFAULT; ++ break; ++ } ++ ++ if (copy_from_user(&uxmsg, umsg, msg_len)) { ++ ret = -EFAULT; ++ break; ++ } ++ ++ xmsg = peci_get_xfer_msg(uxmsg.tx_len, uxmsg.rx_len); ++ if (IS_ERR(xmsg)) { ++ ret = PTR_ERR(xmsg); ++ break; ++ } ++ ++ if (uxmsg.tx_len && ++ copy_from_user(xmsg->tx_buf, uxmsg.tx_buf, uxmsg.tx_len)) { ++ ret = -EFAULT; ++ break; ++ } ++ ++ xmsg->addr = uxmsg.addr; ++ xmsg->tx_len = uxmsg.tx_len; ++ xmsg->rx_len = uxmsg.rx_len; ++ ++ ret = peci_command(peci_dev->adapter, cmd, xmsg); ++ if (!ret && xmsg->rx_len && ++ copy_to_user(uxmsg.rx_buf, xmsg->rx_buf, xmsg->rx_len)) ++ ret = -EFAULT; ++ ++ break; ++ ++ default: ++ msg = memdup_user(umsg, msg_len); ++ if (IS_ERR(msg)) { ++ ret = PTR_ERR(msg); ++ break; ++ } ++ ++ ret = peci_command(peci_dev->adapter, cmd, msg); ++ if ((!ret || ret == -ETIMEDOUT) && ++ copy_to_user(umsg, msg, msg_len)) ++ ret = -EFAULT; ++ ++ break; ++ } ++ ++ peci_put_xfer_msg(xmsg); ++ kfree(msg); ++ ++ return (long)ret; ++} ++ ++static int peci_dev_open(struct inode *inode, struct file *file) ++{ ++ struct peci_adapter *adapter; ++ struct peci_dev *peci_dev; ++ ++ peci_dev = peci_dev_get_by_minor(iminor(inode)); ++ if (!peci_dev) ++ return -ENODEV; ++ ++ adapter = peci_get_adapter(peci_dev->adapter->nr); ++ if (!adapter) ++ return -ENODEV; ++ ++ file->private_data = peci_dev; ++ ++ return 0; ++} ++ ++static int peci_dev_release(struct inode *inode, struct file *file) ++{ ++ struct peci_dev *peci_dev = file->private_data; ++ ++ peci_put_adapter(peci_dev->adapter); ++ file->private_data = NULL; ++ ++ return 0; ++} ++ ++static const struct file_operations peci_dev_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = peci_dev_ioctl, ++ .open = peci_dev_open, ++ .release = peci_dev_release, ++ .llseek = no_llseek, ++}; ++ ++static struct class *peci_dev_class; ++ ++static int peci_dev_attach_adapter(struct device *dev, void *dummy) ++{ ++ struct peci_adapter *adapter; ++ struct peci_dev *peci_dev; ++ dev_t devt; ++ int ret; ++ ++ if (dev->type != &peci_adapter_type) ++ return 0; ++ ++ adapter = to_peci_adapter(dev); ++ peci_dev = peci_dev_alloc(adapter); ++ if (IS_ERR(peci_dev)) ++ return PTR_ERR(peci_dev); ++ ++ cdev_init(&peci_dev->cdev, &peci_dev_fops); ++ peci_dev->cdev.owner = THIS_MODULE; ++ devt = MKDEV(MAJOR(peci_devt), adapter->nr); ++ ++ ret = cdev_add(&peci_dev->cdev, devt, 1); ++ if (ret) ++ goto err_put_dev; ++ ++ /* register this peci device with the driver core */ ++ peci_dev->dev = device_create(peci_dev_class, &adapter->dev, devt, NULL, ++ "peci-%d", adapter->nr); ++ if (IS_ERR(peci_dev->dev)) { ++ ret = PTR_ERR(peci_dev->dev); ++ goto err_del_cdev; ++ } ++ ++ pr_info("peci-dev: adapter [%s] registered as minor %d\n", ++ adapter->name, adapter->nr); ++ ++ return 0; ++ ++err_del_cdev: ++ cdev_del(&peci_dev->cdev); ++err_put_dev: ++ peci_dev_put(peci_dev); ++ ++ return ret; ++} ++ ++static int peci_dev_detach_adapter(struct device *dev, void *dummy) ++{ ++ struct peci_adapter *adapter; ++ struct peci_dev *peci_dev; ++ dev_t devt; ++ ++ if (dev->type != &peci_adapter_type) ++ return 0; ++ ++ adapter = to_peci_adapter(dev); ++ peci_dev = peci_dev_get_by_minor(adapter->nr); ++ if (!peci_dev) ++ return 0; ++ ++ cdev_del(&peci_dev->cdev); ++ devt = peci_dev->dev->devt; ++ peci_dev_put(peci_dev); ++ device_destroy(peci_dev_class, devt); ++ ++ pr_info("peci-dev: adapter [%s] unregistered\n", adapter->name); ++ ++ return 0; ++} ++ ++static int peci_dev_notifier_call(struct notifier_block *nb, ulong action, ++ void *data) ++{ ++ struct device *dev = data; ++ ++ switch (action) { ++ case BUS_NOTIFY_ADD_DEVICE: ++ return peci_dev_attach_adapter(dev, NULL); ++ case BUS_NOTIFY_DEL_DEVICE: ++ return peci_dev_detach_adapter(dev, NULL); ++ } ++ ++ return 0; ++} ++ ++static struct notifier_block peci_dev_notifier = { ++ .notifier_call = peci_dev_notifier_call, ++}; ++ ++static int __init peci_dev_init(void) ++{ ++ int ret; ++ ++ printk(KERN_INFO "peci /dev entries driver\n"); ++ ++ ret = alloc_chrdev_region(&peci_devt, 0, PECI_MINORS, "peci"); ++ if (ret < 0) { ++ pr_err("peci: Failed to allocate chr dev region!\n"); ++ bus_unregister(&peci_bus_type); ++ goto err; ++ } ++ ++ peci_dev_class = class_create(THIS_MODULE, "peci-dev"); ++ if (IS_ERR(peci_dev_class)) { ++ ret = PTR_ERR(peci_dev_class); ++ goto err_unreg_chrdev; ++ } ++ peci_dev_class->dev_groups = peci_dev_groups; ++ ++ /* Keep track of adapters which will be added or removed later */ ++ ret = bus_register_notifier(&peci_bus_type, &peci_dev_notifier); ++ if (ret) ++ goto err_destroy_class; ++ ++ /* Bind to already existing adapters right away */ ++ peci_for_each_dev(NULL, peci_dev_attach_adapter); ++ ++ return 0; ++ ++err_destroy_class: ++ class_destroy(peci_dev_class); ++err_unreg_chrdev: ++ unregister_chrdev_region(peci_devt, PECI_MINORS); ++err: ++ printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__); ++ ++ return ret; ++} ++ ++static void __exit peci_dev_exit(void) ++{ ++ bus_unregister_notifier(&peci_bus_type, &peci_dev_notifier); ++ peci_for_each_dev(NULL, peci_dev_detach_adapter); ++ class_destroy(peci_dev_class); ++ unregister_chrdev_region(peci_devt, PECI_MINORS); ++} ++ ++module_init(peci_dev_init); ++module_exit(peci_dev_exit); ++ ++MODULE_AUTHOR("Jae Hyun Yoo "); ++MODULE_DESCRIPTION("PECI /dev entries driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/peci/peci-npcm.c b/drivers/peci/peci-npcm.c +deleted file mode 100644 +index f632365..0000000 +--- a/drivers/peci/peci-npcm.c ++++ /dev/null +@@ -1,410 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-// Copyright (c) 2019 Nuvoton Technology corporation. +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-/* NPCM7xx GCR module */ +-#define NPCM7XX_INTCR3_OFFSET 0x9C +-#define NPCM7XX_INTCR3_PECIVSEL BIT(19) +- +-/* NPCM PECI Registers */ +-#define NPCM_PECI_CTL_STS 0x00 +-#define NPCM_PECI_RD_LENGTH 0x04 +-#define NPCM_PECI_ADDR 0x08 +-#define NPCM_PECI_CMD 0x0C +-#define NPCM_PECI_CTL2 0x10 +-#define NPCM_PECI_WR_LENGTH 0x1C +-#define NPCM_PECI_PDDR 0x2C +-#define NPCM_PECI_DAT_INOUT(n) (0x100 + ((n) * 4)) +- +-#define NPCM_PECI_MAX_REG 0x200 +- +-/* NPCM_PECI_CTL_STS - 0x00 : Control Register */ +-#define NPCM_PECI_CTRL_DONE_INT_EN BIT(6) +-#define NPCM_PECI_CTRL_ABRT_ERR BIT(4) +-#define NPCM_PECI_CTRL_CRC_ERR BIT(3) +-#define NPCM_PECI_CTRL_DONE BIT(1) +-#define NPCM_PECI_CTRL_START_BUSY BIT(0) +- +-/* NPCM_PECI_RD_LENGTH - 0x04 : Command Register */ +-#define NPCM_PECI_RD_LEN_MASK GENMASK(6, 0) +- +-/* NPCM_PECI_CMD - 0x10 : Command Register */ +-#define NPCM_PECI_CTL2_MASK GENMASK(7, 6) +- +-/* NPCM_PECI_WR_LENGTH - 0x1C : Command Register */ +-#define NPCM_PECI_WR_LEN_MASK GENMASK(6, 0) +- +-/* NPCM_PECI_PDDR - 0x2C : Command Register */ +-#define NPCM_PECI_PDDR_MASK GENMASK(4, 0) +- +-#define NPCM_PECI_INT_MASK (NPCM_PECI_CTRL_ABRT_ERR | \ +- NPCM_PECI_CTRL_CRC_ERR | \ +- NPCM_PECI_CTRL_DONE) +- +-#define NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC 50000 +-#define NPCM_PECI_IDLE_CHECK_INTERVAL_USEC 10000 +-#define NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT 1000 +-#define NPCM_PECI_CMD_TIMEOUT_MS_MAX 60000 +-#define NPCM_PECI_HOST_NEG_BIT_RATE_MAX 31 +-#define NPCM_PECI_HOST_NEG_BIT_RATE_MIN 7 +-#define NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT 15 +-#define NPCM_PECI_PULL_DOWN_DEFAULT 0 +-#define NPCM_PECI_PULL_DOWN_MAX 2 +- +-struct npcm_peci { +- u32 cmd_timeout_ms; +- u32 host_bit_rate; +- struct completion xfer_complete; +- struct regmap *gcr_regmap; +- struct peci_adapter *adapter; +- struct regmap *regmap; +- u32 status; +- spinlock_t lock; /* to sync completion status handling */ +- struct device *dev; +- struct clk *clk; +- int irq; +-}; +- +-static int npcm_peci_xfer_native(struct npcm_peci *priv, +- struct peci_xfer_msg *msg) +-{ +- long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms); +- unsigned long flags; +- unsigned int msg_rd; +- u32 cmd_sts; +- int i, rc; +- +- /* Check command sts and bus idle state */ +- rc = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts, +- !(cmd_sts & NPCM_PECI_CTRL_START_BUSY), +- NPCM_PECI_IDLE_CHECK_INTERVAL_USEC, +- NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC); +- if (rc) +- return rc; /* -ETIMEDOUT */ +- +- spin_lock_irqsave(&priv->lock, flags); +- reinit_completion(&priv->xfer_complete); +- +- regmap_write(priv->regmap, NPCM_PECI_ADDR, msg->addr); +- regmap_write(priv->regmap, NPCM_PECI_RD_LENGTH, +- NPCM_PECI_WR_LEN_MASK & msg->rx_len); +- regmap_write(priv->regmap, NPCM_PECI_WR_LENGTH, +- NPCM_PECI_WR_LEN_MASK & msg->tx_len); +- +- if (msg->tx_len) { +- regmap_write(priv->regmap, NPCM_PECI_CMD, msg->tx_buf[0]); +- +- for (i = 0; i < (msg->tx_len - 1); i++) +- regmap_write(priv->regmap, NPCM_PECI_DAT_INOUT(i), +- msg->tx_buf[i + 1]); +- } +- +- priv->status = 0; +- regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS, +- NPCM_PECI_CTRL_START_BUSY, +- NPCM_PECI_CTRL_START_BUSY); +- +- spin_unlock_irqrestore(&priv->lock, flags); +- +- err = wait_for_completion_interruptible_timeout(&priv->xfer_complete, +- timeout); +- +- spin_lock_irqsave(&priv->lock, flags); +- +- regmap_write(priv->regmap, NPCM_PECI_CMD, 0); +- +- if (err <= 0 || priv->status != NPCM_PECI_CTRL_DONE) { +- if (err < 0) { /* -ERESTARTSYS */ +- rc = (int)err; +- goto err_irqrestore; +- } else if (err == 0) { +- dev_dbg(priv->dev, "Timeout waiting for a response!\n"); +- rc = -ETIMEDOUT; +- goto err_irqrestore; +- } +- +- dev_dbg(priv->dev, "No valid response!\n"); +- rc = -EIO; +- goto err_irqrestore; +- } +- +- for (i = 0; i < msg->rx_len; i++) { +- regmap_read(priv->regmap, NPCM_PECI_DAT_INOUT(i), &msg_rd); +- msg->rx_buf[i] = (u8)msg_rd; +- } +- +-err_irqrestore: +- spin_unlock_irqrestore(&priv->lock, flags); +- return rc; +-} +- +-static irqreturn_t npcm_peci_irq_handler(int irq, void *arg) +-{ +- struct npcm_peci *priv = arg; +- u32 status_ack = 0; +- u32 status; +- +- spin_lock(&priv->lock); +- regmap_read(priv->regmap, NPCM_PECI_CTL_STS, &status); +- priv->status |= (status & NPCM_PECI_INT_MASK); +- +- if (status & NPCM_PECI_CTRL_CRC_ERR) { +- dev_dbg(priv->dev, "PECI_INT_W_FCS_BAD\n"); +- status_ack |= NPCM_PECI_CTRL_CRC_ERR; +- } +- +- if (status & NPCM_PECI_CTRL_ABRT_ERR) { +- dev_dbg(priv->dev, "NPCM_PECI_CTRL_ABRT_ERR\n"); +- status_ack |= NPCM_PECI_CTRL_ABRT_ERR; +- } +- +- /* +- * All commands should be ended up with a NPCM_PECI_CTRL_DONE +- * bit set even in an error case. +- */ +- if (status & NPCM_PECI_CTRL_DONE) { +- dev_dbg(priv->dev, "NPCM_PECI_CTRL_DONE\n"); +- status_ack |= NPCM_PECI_CTRL_DONE; +- complete(&priv->xfer_complete); +- } +- +- regmap_write_bits(priv->regmap, NPCM_PECI_CTL_STS, +- NPCM_PECI_INT_MASK, status_ack); +- +- spin_unlock(&priv->lock); +- return IRQ_HANDLED; +-} +- +-static int npcm_peci_init_ctrl(struct npcm_peci *priv) +-{ +- u32 cmd_sts, host_neg_bit_rate = 0, pull_down = 0; +- int ret; +- bool volt; +- +- priv->clk = devm_clk_get(priv->dev, NULL); +- if (IS_ERR(priv->clk)) { +- dev_err(priv->dev, "Failed to get clk source.\n"); +- return PTR_ERR(priv->clk); +- } +- +- ret = clk_prepare_enable(priv->clk); +- if (ret) { +- dev_err(priv->dev, "Failed to enable clock.\n"); +- return ret; +- } +- +- ret = of_property_read_u32(priv->dev->of_node, "cmd-timeout-ms", +- &priv->cmd_timeout_ms); +- if (ret || priv->cmd_timeout_ms > NPCM_PECI_CMD_TIMEOUT_MS_MAX || +- priv->cmd_timeout_ms == 0) { +- if (ret) +- dev_warn(priv->dev, +- "cmd-timeout-ms not found, use default : %u\n", +- NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT); +- else +- dev_warn(priv->dev, +- "Invalid cmd-timeout-ms : %u. Use default : %u\n", +- priv->cmd_timeout_ms, +- NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT); +- +- priv->cmd_timeout_ms = NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT; +- } +- +- if (of_device_is_compatible(priv->dev->of_node, +- "nuvoton,npcm750-peci")) { +- priv->gcr_regmap = syscon_regmap_lookup_by_compatible +- ("nuvoton,npcm750-gcr"); +- if (!IS_ERR(priv->gcr_regmap)) { +- volt = of_property_read_bool(priv->dev->of_node, +- "high-volt-range"); +- if (volt) +- regmap_update_bits(priv->gcr_regmap, +- NPCM7XX_INTCR3_OFFSET, +- NPCM7XX_INTCR3_PECIVSEL, +- NPCM7XX_INTCR3_PECIVSEL); +- else +- regmap_update_bits(priv->gcr_regmap, +- NPCM7XX_INTCR3_OFFSET, +- NPCM7XX_INTCR3_PECIVSEL, 0); +- } +- } +- +- ret = of_property_read_u32(priv->dev->of_node, "pull-down", +- &pull_down); +- if (ret || pull_down > NPCM_PECI_PULL_DOWN_MAX) { +- if (ret) +- dev_warn(priv->dev, +- "pull-down not found, use default : %u\n", +- NPCM_PECI_PULL_DOWN_DEFAULT); +- else +- dev_warn(priv->dev, +- "Invalid pull-down : %u. Use default : %u\n", +- pull_down, +- NPCM_PECI_PULL_DOWN_DEFAULT); +- pull_down = NPCM_PECI_PULL_DOWN_DEFAULT; +- } +- +- regmap_update_bits(priv->regmap, NPCM_PECI_CTL2, NPCM_PECI_CTL2_MASK, +- pull_down << 6); +- +- ret = of_property_read_u32(priv->dev->of_node, "host-neg-bit-rate", +- &host_neg_bit_rate); +- if (ret || host_neg_bit_rate > NPCM_PECI_HOST_NEG_BIT_RATE_MAX || +- host_neg_bit_rate < NPCM_PECI_HOST_NEG_BIT_RATE_MIN) { +- if (ret) +- dev_warn(priv->dev, +- "host-neg-bit-rate not found, use default : %u\n", +- NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT); +- else +- dev_warn(priv->dev, +- "Invalid host-neg-bit-rate : %u. Use default : %u\n", +- host_neg_bit_rate, +- NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT); +- host_neg_bit_rate = NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT; +- } +- +- regmap_update_bits(priv->regmap, NPCM_PECI_PDDR, NPCM_PECI_PDDR_MASK, +- host_neg_bit_rate); +- +- priv->host_bit_rate = clk_get_rate(priv->clk) / +- (4 * (host_neg_bit_rate + 1)); +- +- ret = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts, +- !(cmd_sts & NPCM_PECI_CTRL_START_BUSY), +- NPCM_PECI_IDLE_CHECK_INTERVAL_USEC, +- NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC); +- if (ret) +- return ret; /* -ETIMEDOUT */ +- +- /* PECI interrupt enable */ +- regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS, +- NPCM_PECI_CTRL_DONE_INT_EN, +- NPCM_PECI_CTRL_DONE_INT_EN); +- +- return 0; +-} +- +-static const struct regmap_config npcm_peci_regmap_config = { +- .reg_bits = 8, +- .val_bits = 8, +- .max_register = NPCM_PECI_MAX_REG, +- .fast_io = true, +-}; +- +-static int npcm_peci_xfer(struct peci_adapter *adapter, +- struct peci_xfer_msg *msg) +-{ +- struct npcm_peci *priv = peci_get_adapdata(adapter); +- +- return npcm_peci_xfer_native(priv, msg); +-} +- +-static int npcm_peci_probe(struct platform_device *pdev) +-{ +- struct peci_adapter *adapter; +- struct npcm_peci *priv; +- struct resource *res; +- void __iomem *base; +- int ret; +- +- adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv)); +- if (!adapter) +- return -ENOMEM; +- +- priv = peci_get_adapdata(adapter); +- priv->adapter = adapter; +- priv->dev = &pdev->dev; +- dev_set_drvdata(&pdev->dev, priv); +- +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- base = devm_ioremap_resource(&pdev->dev, res); +- if (IS_ERR(base)) { +- ret = PTR_ERR(base); +- goto err_put_adapter_dev; +- } +- +- priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, +- &npcm_peci_regmap_config); +- if (IS_ERR(priv->regmap)) { +- ret = PTR_ERR(priv->regmap); +- goto err_put_adapter_dev; +- } +- +- priv->irq = platform_get_irq(pdev, 0); +- if (!priv->irq) { +- ret = -ENODEV; +- goto err_put_adapter_dev; +- } +- +- ret = devm_request_irq(&pdev->dev, priv->irq, npcm_peci_irq_handler, +- 0, "peci-npcm-irq", priv); +- if (ret) +- goto err_put_adapter_dev; +- +- init_completion(&priv->xfer_complete); +- spin_lock_init(&priv->lock); +- +- priv->adapter->owner = THIS_MODULE; +- priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev)); +- strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name)); +- priv->adapter->xfer = npcm_peci_xfer; +- +- ret = npcm_peci_init_ctrl(priv); +- if (ret) +- goto err_put_adapter_dev; +- +- ret = peci_add_adapter(priv->adapter); +- if (ret) +- goto err_put_adapter_dev; +- +- dev_info(&pdev->dev, "peci bus %d registered, host negotiation bit rate %dHz", +- priv->adapter->nr, priv->host_bit_rate); +- +- return 0; +- +-err_put_adapter_dev: +- put_device(&adapter->dev); +- return ret; +-} +- +-static int npcm_peci_remove(struct platform_device *pdev) +-{ +- struct npcm_peci *priv = dev_get_drvdata(&pdev->dev); +- +- clk_disable_unprepare(priv->clk); +- peci_del_adapter(priv->adapter); +- of_node_put(priv->adapter->dev.of_node); +- +- return 0; +-} +- +-static const struct of_device_id npcm_peci_of_table[] = { +- { .compatible = "nuvoton,npcm750-peci", }, +- { } +-}; +-MODULE_DEVICE_TABLE(of, npcm_peci_of_table); +- +-static struct platform_driver npcm_peci_driver = { +- .probe = npcm_peci_probe, +- .remove = npcm_peci_remove, +- .driver = { +- .name = "peci-npcm", +- .of_match_table = of_match_ptr(npcm_peci_of_table), +- }, +-}; +-module_platform_driver(npcm_peci_driver); +- +-MODULE_AUTHOR("Tomer Maimon "); +-MODULE_DESCRIPTION("NPCM Platform Environment Control Interface (PECI) driver"); +-MODULE_LICENSE("GPL v2"); +diff --git a/include/linux/mfd/intel-peci-client.h b/include/linux/mfd/intel-peci-client.h +index 8f6d823..9854303 100644 +--- a/include/linux/mfd/intel-peci-client.h ++++ b/include/linux/mfd/intel-peci-client.h +@@ -1,5 +1,5 @@ + /* SPDX-License-Identifier: GPL-2.0 */ +-/* Copyright (c) 2018 Intel Corporation */ ++/* Copyright (c) 2018-2019 Intel Corporation */ + + #ifndef __LINUX_MFD_INTEL_PECI_CLIENT_H + #define __LINUX_MFD_INTEL_PECI_CLIENT_H +@@ -9,14 +9,15 @@ + #if IS_ENABLED(CONFIG_X86) + #include + #else +-/** ++/* + * Architectures other than x86 cannot include the header file so define these + * at here. These are needed for detecting type of client x86 CPUs behind a PECI + * connection. + */ +-#define INTEL_FAM6_HASWELL_X 0x3F +-#define INTEL_FAM6_BROADWELL_X 0x4F +-#define INTEL_FAM6_SKYLAKE_X 0x55 ++#define INTEL_FAM6_HASWELL_X 0x3F ++#define INTEL_FAM6_BROADWELL_X 0x4F ++#define INTEL_FAM6_SKYLAKE_X 0x55 ++#define INTEL_FAM6_SKYLAKE_XD 0x56 + #endif + + #define CORE_MAX_ON_HSX 18 /* Max number of cores on Haswell */ +@@ -31,6 +32,10 @@ + #define CHAN_RANK_MAX_ON_SKX 6 /* Max number of channel ranks on Skylake */ + #define DIMM_IDX_MAX_ON_SKX 2 /* Max DIMM index per channel on Skylake */ + ++#define CORE_MAX_ON_SKXD 16 /* Max number of cores on Skylake D */ ++#define CHAN_RANK_MAX_ON_SKXD 2 /* Max number of channel ranks on Skylake D */ ++#define DIMM_IDX_MAX_ON_SKXD 2 /* Max DIMM index per channel on Skylake D */ ++ + #define CORE_NUMS_MAX CORE_MAX_ON_SKX + #define CHAN_RANK_MAX CHAN_RANK_MAX_ON_HSX + #define DIMM_IDX_MAX DIMM_IDX_MAX_ON_HSX +@@ -58,7 +63,6 @@ struct cpu_gen_info { + /** + * struct peci_client_manager - PECI client manager information + * @client; pointer to the PECI client +- * @dev: pointer to the struct device + * @name: PECI client manager name + * @gen_info: CPU generation info of the detected CPU + * +@@ -67,7 +71,6 @@ struct cpu_gen_info { + */ + struct peci_client_manager { + struct peci_client *client; +- struct device *dev; + char name[PECI_NAME_SIZE]; + const struct cpu_gen_info *gen_info; + }; +@@ -93,18 +96,22 @@ peci_client_read_package_config(struct peci_client_manager *priv, + u8 index, u16 param, u8 *data) + { + struct peci_rd_pkg_cfg_msg msg; +- int rc; ++ int ret; + + msg.addr = priv->client->addr; + msg.index = index; + msg.param = param; + msg.rx_len = 4; + +- rc = peci_command(priv->client->adapter, PECI_CMD_RD_PKG_CFG, &msg); +- if (!rc) +- memcpy(data, msg.pkg_config, 4); ++ ret = peci_command(priv->client->adapter, PECI_CMD_RD_PKG_CFG, &msg); ++ if (msg.cc != PECI_DEV_CC_SUCCESS) ++ ret = -EAGAIN; ++ if (ret) ++ return ret; ++ ++ memcpy(data, msg.pkg_config, 4); + +- return rc; ++ return 0; + } + + #endif /* __LINUX_MFD_INTEL_PECI_CLIENT_H */ +diff --git a/include/linux/peci.h b/include/linux/peci.h +index d0e47d4..6fc424d 100644 +--- a/include/linux/peci.h ++++ b/include/linux/peci.h +@@ -1,19 +1,18 @@ + /* SPDX-License-Identifier: GPL-2.0 */ +-/* Copyright (c) 2018 Intel Corporation */ ++/* Copyright (c) 2018-2019 Intel Corporation */ + + #ifndef __LINUX_PECI_H + #define __LINUX_PECI_H + +-#include + #include ++#include + #include +-#include + + #define PECI_NAME_SIZE 32 + + struct peci_board_info { + char type[PECI_NAME_SIZE]; +- unsigned short addr; /* CPU client address */ ++ u8 addr; /* CPU client address */ + struct device_node *of_node; + }; + +@@ -22,29 +21,29 @@ struct peci_board_info { + * @owner: owner module of the PECI adpater + * @bus_lock: mutex for exclusion of multiple callers + * @dev: device interface to this driver +- * @cdev: character device object to create character device + * @nr: the bus number to map + * @name: name of the adapter + * @userspace_clients_lock: mutex for exclusion of clients handling + * @userspace_clients: list of registered clients + * @xfer: low-level transfer function pointer of the adapter + * @cmd_mask: mask for supportable PECI commands ++ * @use_dma: flag for indicating that adapter uses DMA + * + * Each PECI adapter can communicate with one or more PECI client children. + * These make a small bus, sharing a single wired PECI connection. + */ + struct peci_adapter { + struct module *owner; +- struct rt_mutex bus_lock; ++ struct mutex bus_lock; + struct device dev; +- struct cdev cdev; + int nr; + char name[PECI_NAME_SIZE]; + struct mutex userspace_clients_lock; /* clients list mutex */ + struct list_head userspace_clients; + int (*xfer)(struct peci_adapter *adapter, + struct peci_xfer_msg *msg); +- uint cmd_mask; ++ u32 cmd_mask; ++ bool use_dma; + }; + + static inline struct peci_adapter *to_peci_adapter(void *d) +@@ -87,8 +86,8 @@ static inline struct peci_client *to_peci_client(void *d) + } + + struct peci_device_id { +- char name[PECI_NAME_SIZE]; +- unsigned long driver_data; /* Data private to the driver */ ++ char name[PECI_NAME_SIZE]; ++ ulong driver_data; /* Data private to the driver */ + }; + + /** +@@ -129,13 +128,22 @@ static inline struct peci_driver *to_peci_driver(void *d) + /* use a define to avoid include chaining to get THIS_MODULE */ + #define peci_add_driver(driver) peci_register_driver(THIS_MODULE, driver) + ++extern struct bus_type peci_bus_type; ++extern struct device_type peci_adapter_type; ++extern struct device_type peci_client_type; ++ + int peci_register_driver(struct module *owner, struct peci_driver *drv); + void peci_del_driver(struct peci_driver *driver); + struct peci_client *peci_verify_client(struct device *dev); +-struct peci_adapter *peci_alloc_adapter(struct device *dev, unsigned int size); ++struct peci_adapter *peci_alloc_adapter(struct device *dev, uint size); ++struct peci_adapter *peci_get_adapter(int nr); ++void peci_put_adapter(struct peci_adapter *adapter); + int peci_add_adapter(struct peci_adapter *adapter); + void peci_del_adapter(struct peci_adapter *adapter); + struct peci_adapter *peci_verify_adapter(struct device *dev); ++int peci_for_each_dev(void *data, int (*fn)(struct device *, void *)); ++struct peci_xfer_msg *peci_get_xfer_msg(u8 tx_len, u8 rx_len); ++void peci_put_xfer_msg(struct peci_xfer_msg *msg); + int peci_command(struct peci_adapter *adpater, enum peci_cmd cmd, void *vmsg); + int peci_get_cpu_id(struct peci_adapter *adapter, u8 addr, u32 *cpu_id); + +diff --git a/include/uapi/linux/peci-ioctl.h b/include/uapi/linux/peci-ioctl.h +index a6dae71..253fb42 100644 +--- a/include/uapi/linux/peci-ioctl.h ++++ b/include/uapi/linux/peci-ioctl.h +@@ -1,5 +1,5 @@ + /* SPDX-License-Identifier: GPL-2.0 */ +-/* Copyright (c) 2018 Intel Corporation */ ++/* Copyright (c) 2018-2019 Intel Corporation */ + + #ifndef __PECI_IOCTL_H + #define __PECI_IOCTL_H +@@ -7,136 +7,35 @@ + #include + #include + +-/* Base Address of 48d */ +-#define PECI_BASE_ADDR 0x30 /* The PECI client's default address of 0x30 */ +-#define PECI_OFFSET_MAX 8 /* Max numver of CPU clients */ +- +-/* PCI Access */ +-#define MAX_PCI_READ_LEN 24 /* Number of bytes of the PCI Space read */ +- +-#define PCI_BUS0_CPU0 0x00 +-#define PCI_BUS0_CPU1 0x80 +-#define PCI_CPUBUSNO_BUS 0x00 +-#define PCI_CPUBUSNO_DEV 0x08 +-#define PCI_CPUBUSNO_FUNC 0x02 +-#define PCI_CPUBUSNO 0xcc +-#define PCI_CPUBUSNO_1 0xd0 +-#define PCI_CPUBUSNO_VALID 0xd4 +- +-/* Package Identifier Read Parameter Value */ +-#define PKG_ID_CPU_ID 0x0000 /* CPUID Info */ +-#define PKG_ID_PLATFORM_ID 0x0001 /* Platform ID */ +-#define PKG_ID_UNCORE_ID 0x0002 /* Uncore Device ID */ +-#define PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */ +-#define PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */ +-#define PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */ +- +-/* RdPkgConfig Index */ +-#define MBX_INDEX_CPU_ID 0 /* Package Identifier Read */ +-#define MBX_INDEX_VR_DEBUG 1 /* VR Debug */ +-#define MBX_INDEX_PKG_TEMP_READ 2 /* Package Temperature Read */ +-#define MBX_INDEX_ENERGY_COUNTER 3 /* Energy counter */ +-#define MBX_INDEX_ENERGY_STATUS 4 /* DDR Energy Status */ +-#define MBX_INDEX_WAKE_MODE_BIT 5 /* "Wake on PECI" Mode bit */ +-#define MBX_INDEX_EPI 6 /* Efficient Performance Indication */ +-#define MBX_INDEX_PKG_RAPL_PERF 8 /* Pkg RAPL Performance Status Read */ +-#define MBX_INDEX_PER_CORE_DTS_TEMP 9 /* Per Core DTS Temperature Read */ +-#define MBX_INDEX_DTS_MARGIN 10 /* DTS thermal margin */ +-#define MBX_INDEX_SKT_PWR_THRTL_DUR 11 /* Socket Power Throttled Duration */ +-#define MBX_INDEX_CFG_TDP_CONTROL 12 /* TDP Config Control */ +-#define MBX_INDEX_CFG_TDP_LEVELS 13 /* TDP Config Levels */ +-#define MBX_INDEX_DDR_DIMM_TEMP 14 /* DDR DIMM Temperature */ +-#define MBX_INDEX_CFG_ICCMAX 15 /* Configurable ICCMAX */ +-#define MBX_INDEX_TEMP_TARGET 16 /* Temperature Target Read */ +-#define MBX_INDEX_CURR_CFG_LIMIT 17 /* Current Config Limit */ +-#define MBX_INDEX_DIMM_TEMP_READ 20 /* Package Thermal Status Read */ +-#define MBX_INDEX_DRAM_IMC_TMP_READ 22 /* DRAM IMC Temperature Read */ +-#define MBX_INDEX_DDR_CH_THERM_STAT 23 /* DDR Channel Thermal Status */ +-#define MBX_INDEX_PKG_POWER_LIMIT1 26 /* Package Power Limit1 */ +-#define MBX_INDEX_PKG_POWER_LIMIT2 27 /* Package Power Limit2 */ +-#define MBX_INDEX_TDP 28 /* Thermal design power minimum */ +-#define MBX_INDEX_TDP_HIGH 29 /* Thermal design power maximum */ +-#define MBX_INDEX_TDP_UNITS 30 /* Units for power/energy registers */ +-#define MBX_INDEX_RUN_TIME 31 /* Accumulated Run Time */ +-#define MBX_INDEX_CONSTRAINED_TIME 32 /* Thermally Constrained Time Read */ +-#define MBX_INDEX_TURBO_RATIO 33 /* Turbo Activation Ratio */ +-#define MBX_INDEX_DDR_RAPL_PL1 34 /* DDR RAPL PL1 */ +-#define MBX_INDEX_DDR_PWR_INFO_HIGH 35 /* DRAM Power Info Read (high) */ +-#define MBX_INDEX_DDR_PWR_INFO_LOW 36 /* DRAM Power Info Read (low) */ +-#define MBX_INDEX_DDR_RAPL_PL2 37 /* DDR RAPL PL2 */ +-#define MBX_INDEX_DDR_RAPL_STATUS 38 /* DDR RAPL Performance Status */ +-#define MBX_INDEX_DDR_HOT_ABSOLUTE 43 /* DDR Hottest Dimm Absolute Temp */ +-#define MBX_INDEX_DDR_HOT_RELATIVE 44 /* DDR Hottest Dimm Relative Temp */ +-#define MBX_INDEX_DDR_THROTTLE_TIME 45 /* DDR Throttle Time */ +-#define MBX_INDEX_DDR_THERM_STATUS 46 /* DDR Thermal Status */ +-#define MBX_INDEX_TIME_AVG_TEMP 47 /* Package time-averaged temperature */ +-#define MBX_INDEX_TURBO_RATIO_LIMIT 49 /* Turbo Ratio Limit Read */ +-#define MBX_INDEX_HWP_AUTO_OOB 53 /* HWP Autonomous Out-of-band */ +-#define MBX_INDEX_DDR_WARM_BUDGET 55 /* DDR Warm Power Budget */ +-#define MBX_INDEX_DDR_HOT_BUDGET 56 /* DDR Hot Power Budget */ +-#define MBX_INDEX_PKG_PSYS_PWR_LIM3 57 /* Package/Psys Power Limit3 */ +-#define MBX_INDEX_PKG_PSYS_PWR_LIM1 58 /* Package/Psys Power Limit1 */ +-#define MBX_INDEX_PKG_PSYS_PWR_LIM2 59 /* Package/Psys Power Limit2 */ +-#define MBX_INDEX_PKG_PSYS_PWR_LIM4 60 /* Package/Psys Power Limit4 */ +-#define MBX_INDEX_PERF_LIMIT_REASON 65 /* Performance Limit Reasons */ +- +-/* WrPkgConfig Index */ +-#define MBX_INDEX_DIMM_AMBIENT 19 +-#define MBX_INDEX_DIMM_TEMP 24 ++/* The PECI client's default address of 0x30 */ ++#define PECI_BASE_ADDR 0x30 ++ ++/* Max number of CPU clients */ ++#define PECI_OFFSET_MAX 8 ++ ++/* PECI read/write data buffer size max */ ++#define PECI_BUFFER_SIZE 255 + + /* Device Specific Completion Code (CC) Definition */ +-#define DEV_PECI_CC_SUCCESS 0x40 +-#define DEV_PECI_CC_TIMEOUT 0x80 +-#define DEV_PECI_CC_OUT_OF_RESOURCE 0x81 +-#define DEV_PECI_CC_UNAVAIL_RESOURCE 0x82 +-#define DEV_PECI_CC_INVALID_REQ 0x90 ++#define PECI_DEV_CC_SUCCESS 0x40 ++#define PECI_DEV_CC_NEED_RETRY 0x80 ++#define PECI_DEV_CC_OUT_OF_RESOURCE 0x81 ++#define PECI_DEV_CC_UNAVAIL_RESOURCE 0x82 ++#define PECI_DEV_CC_INVALID_REQ 0x90 ++#define PECI_DEV_CC_MCA_ERROR 0x91 ++#define PECI_DEV_CC_CATASTROPHIC_MCA_ERROR 0x93 ++#define PECI_DEV_CC_FATAL_MCA_DETECTED 0x94 ++#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB 0x98 ++#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_IERR 0x9B ++#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_MCA 0x9C + + /* Completion Code mask to check retry needs */ +-#define DEV_PECI_CC_RETRY_CHECK_MASK 0xf0 +-#define DEV_PECI_CC_NEED_RETRY 0x80 ++#define PECI_DEV_CC_RETRY_CHECK_MASK 0xf0 + + /* Skylake EDS says to retry for 250ms */ +-#define DEV_PECI_RETRY_TIME_MS 250 +-#define DEV_PECI_RETRY_INTERVAL_USEC 10000 +-#define DEV_PECI_RETRY_BIT 0x01 +- +-#define GET_TEMP_WR_LEN 1 +-#define GET_TEMP_RD_LEN 2 +-#define GET_TEMP_PECI_CMD 0x01 +- +-#define GET_DIB_WR_LEN 1 +-#define GET_DIB_RD_LEN 8 +-#define GET_DIB_PECI_CMD 0xf7 +- +-#define RDPKGCFG_WRITE_LEN 5 +-#define RDPKGCFG_READ_LEN_BASE 1 +-#define RDPKGCFG_PECI_CMD 0xa1 +- +-#define WRPKGCFG_WRITE_LEN_BASE 6 +-#define WRPKGCFG_READ_LEN 1 +-#define WRPKGCFG_PECI_CMD 0xa5 +- +-#define RDIAMSR_WRITE_LEN 5 +-#define RDIAMSR_READ_LEN 9 +-#define RDIAMSR_PECI_CMD 0xb1 +- +-#define WRIAMSR_PECI_CMD 0xb5 +- +-#define RDPCICFG_WRITE_LEN 6 +-#define RDPCICFG_READ_LEN 5 +-#define RDPCICFG_PECI_CMD 0x61 +- +-#define WRPCICFG_PECI_CMD 0x65 +- +-#define RDPCICFGLOCAL_WRITE_LEN 5 +-#define RDPCICFGLOCAL_READ_LEN_BASE 1 +-#define RDPCICFGLOCAL_PECI_CMD 0xe1 +- +-#define WRPCICFGLOCAL_WRITE_LEN_BASE 6 +-#define WRPCICFGLOCAL_READ_LEN 1 +-#define WRPCICFGLOCAL_PECI_CMD 0xe5 +- +-#define PECI_BUFFER_SIZE 32 ++#define PECI_DEV_RETRY_TIME_MS 250 ++#define PECI_DEV_RETRY_INTERVAL_USEC 10000 ++#define PECI_DEV_RETRY_BIT 0x01 + + /** + * enum peci_cmd - PECI client commands +@@ -186,11 +85,12 @@ enum peci_cmd { + * raw PECI transfer + */ + struct peci_xfer_msg { +- __u8 addr; +- __u8 tx_len; +- __u8 rx_len; +- __u8 tx_buf[PECI_BUFFER_SIZE]; +- __u8 rx_buf[PECI_BUFFER_SIZE]; ++ __u8 addr; ++ __u8 tx_len; ++ __u8 rx_len; ++ __u8 padding; ++ __u8 *tx_buf; ++ __u8 *rx_buf; + } __attribute__((__packed__)); + + /** +@@ -202,7 +102,8 @@ struct peci_xfer_msg { + * powered-off, etc. + */ + struct peci_ping_msg { +- __u8 addr; ++ __u8 addr; ++ __u8 padding[3]; + } __attribute__((__packed__)); + + /** +@@ -216,8 +117,13 @@ struct peci_ping_msg { + * command. + */ + struct peci_get_dib_msg { +- __u8 addr; +- __u64 dib; ++#define PECI_GET_DIB_WR_LEN 1 ++#define PECI_GET_DIB_RD_LEN 8 ++#define PECI_GET_DIB_CMD 0xf7 ++ ++ __u8 addr; ++ __u8 padding[3]; ++ __u64 dib; + } __attribute__((__packed__)); + + /** +@@ -232,8 +138,13 @@ struct peci_get_dib_msg { + * below the maximum processor junction temperature. + */ + struct peci_get_temp_msg { +- __u8 addr; +- __s16 temp_raw; ++#define PECI_GET_TEMP_WR_LEN 1 ++#define PECI_GET_TEMP_RD_LEN 2 ++#define PECI_GET_TEMP_CMD 0x01 ++ ++ __u8 addr; ++ __u8 padding; ++ __s16 temp_raw; + } __attribute__((__packed__)); + + /** +@@ -242,6 +153,7 @@ struct peci_get_temp_msg { + * @index: encoding index for the requested service + * @param: specific data being requested + * @rx_len: number of data to be read in bytes ++ * @cc: completion code + * @pkg_config: package config data to be read + * + * The RdPkgConfig() command provides read access to the Package Configuration +@@ -251,11 +163,73 @@ struct peci_get_temp_msg { + * DIMM temperatures and so on. + */ + struct peci_rd_pkg_cfg_msg { +- __u8 addr; +- __u8 index; +- __u16 param; +- __u8 rx_len; +- __u8 pkg_config[4]; ++#define PECI_RDPKGCFG_WRITE_LEN 5 ++#define PECI_RDPKGCFG_READ_LEN_BASE 1 ++#define PECI_RDPKGCFG_CMD 0xa1 ++ ++ __u8 addr; ++ __u8 index; ++#define PECI_MBX_INDEX_CPU_ID 0 /* Package Identifier Read */ ++#define PECI_MBX_INDEX_VR_DEBUG 1 /* VR Debug */ ++#define PECI_MBX_INDEX_PKG_TEMP_READ 2 /* Package Temperature Read */ ++#define PECI_MBX_INDEX_ENERGY_COUNTER 3 /* Energy counter */ ++#define PECI_MBX_INDEX_ENERGY_STATUS 4 /* DDR Energy Status */ ++#define PECI_MBX_INDEX_WAKE_MODE_BIT 5 /* "Wake on PECI" Mode bit */ ++#define PECI_MBX_INDEX_EPI 6 /* Efficient Performance Indication */ ++#define PECI_MBX_INDEX_PKG_RAPL_PERF 8 /* Pkg RAPL Performance Status Read */ ++#define PECI_MBX_INDEX_PER_CORE_DTS_TEMP 9 /* Per Core DTS Temperature Read */ ++#define PECI_MBX_INDEX_DTS_MARGIN 10 /* DTS thermal margin */ ++#define PECI_MBX_INDEX_SKT_PWR_THRTL_DUR 11 /* Socket Power Throttled Duration */ ++#define PECI_MBX_INDEX_CFG_TDP_CONTROL 12 /* TDP Config Control */ ++#define PECI_MBX_INDEX_CFG_TDP_LEVELS 13 /* TDP Config Levels */ ++#define PECI_MBX_INDEX_DDR_DIMM_TEMP 14 /* DDR DIMM Temperature */ ++#define PECI_MBX_INDEX_CFG_ICCMAX 15 /* Configurable ICCMAX */ ++#define PECI_MBX_INDEX_TEMP_TARGET 16 /* Temperature Target Read */ ++#define PECI_MBX_INDEX_CURR_CFG_LIMIT 17 /* Current Config Limit */ ++#define PECI_MBX_INDEX_DIMM_TEMP_READ 20 /* Package Thermal Status Read */ ++#define PECI_MBX_INDEX_DRAM_IMC_TMP_READ 22 /* DRAM IMC Temperature Read */ ++#define PECI_MBX_INDEX_DDR_CH_THERM_STAT 23 /* DDR Channel Thermal Status */ ++#define PECI_MBX_INDEX_PKG_POWER_LIMIT1 26 /* Package Power Limit1 */ ++#define PECI_MBX_INDEX_PKG_POWER_LIMIT2 27 /* Package Power Limit2 */ ++#define PECI_MBX_INDEX_TDP 28 /* Thermal design power minimum */ ++#define PECI_MBX_INDEX_TDP_HIGH 29 /* Thermal design power maximum */ ++#define PECI_MBX_INDEX_TDP_UNITS 30 /* Units for power/energy registers */ ++#define PECI_MBX_INDEX_RUN_TIME 31 /* Accumulated Run Time */ ++#define PECI_MBX_INDEX_CONSTRAINED_TIME 32 /* Thermally Constrained Time Read */ ++#define PECI_MBX_INDEX_TURBO_RATIO 33 /* Turbo Activation Ratio */ ++#define PECI_MBX_INDEX_DDR_RAPL_PL1 34 /* DDR RAPL PL1 */ ++#define PECI_MBX_INDEX_DDR_PWR_INFO_HIGH 35 /* DRAM Power Info Read (high) */ ++#define PECI_MBX_INDEX_DDR_PWR_INFO_LOW 36 /* DRAM Power Info Read (low) */ ++#define PECI_MBX_INDEX_DDR_RAPL_PL2 37 /* DDR RAPL PL2 */ ++#define PECI_MBX_INDEX_DDR_RAPL_STATUS 38 /* DDR RAPL Performance Status */ ++#define PECI_MBX_INDEX_DDR_HOT_ABSOLUTE 43 /* DDR Hottest Dimm Absolute Temp */ ++#define PECI_MBX_INDEX_DDR_HOT_RELATIVE 44 /* DDR Hottest Dimm Relative Temp */ ++#define PECI_MBX_INDEX_DDR_THROTTLE_TIME 45 /* DDR Throttle Time */ ++#define PECI_MBX_INDEX_DDR_THERM_STATUS 46 /* DDR Thermal Status */ ++#define PECI_MBX_INDEX_TIME_AVG_TEMP 47 /* Package time-averaged temperature */ ++#define PECI_MBX_INDEX_TURBO_RATIO_LIMIT 49 /* Turbo Ratio Limit Read */ ++#define PECI_MBX_INDEX_HWP_AUTO_OOB 53 /* HWP Autonomous Out-of-band */ ++#define PECI_MBX_INDEX_DDR_WARM_BUDGET 55 /* DDR Warm Power Budget */ ++#define PECI_MBX_INDEX_DDR_HOT_BUDGET 56 /* DDR Hot Power Budget */ ++#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM3 57 /* Package/Psys Power Limit3 */ ++#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM1 58 /* Package/Psys Power Limit1 */ ++#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM2 59 /* Package/Psys Power Limit2 */ ++#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM4 60 /* Package/Psys Power Limit4 */ ++#define PECI_MBX_INDEX_PERF_LIMIT_REASON 65 /* Performance Limit Reasons */ ++ ++ __u16 param; ++/* When index is PECI_MBX_INDEX_CPU_ID */ ++#define PECI_PKG_ID_CPU_ID 0x0000 /* CPUID Info */ ++#define PECI_PKG_ID_PLATFORM_ID 0x0001 /* Platform ID */ ++#define PECI_PKG_ID_UNCORE_ID 0x0002 /* Uncore Device ID */ ++#define PECI_PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */ ++#define PECI_PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */ ++#define PECI_PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */ ++ ++ __u8 rx_len; ++ __u8 cc; ++ __u8 padding[2]; ++ __u8 pkg_config[4]; + } __attribute__((__packed__)); + + /** +@@ -264,6 +238,7 @@ struct peci_rd_pkg_cfg_msg { + * @index: encoding index for the requested service + * @param: specific data being requested + * @tx_len: number of data to be written in bytes ++ * @cc: completion code + * @value: package config data to be written + * + * The WrPkgConfig() command provides write access to the Package Configuration +@@ -272,11 +247,20 @@ struct peci_rd_pkg_cfg_msg { + * may include power limiting, thermal averaging constant programming and so on. + */ + struct peci_wr_pkg_cfg_msg { +- __u8 addr; +- __u8 index; +- __u16 param; +- __u8 tx_len; +- __u32 value; ++#define PECI_WRPKGCFG_WRITE_LEN_BASE 6 ++#define PECI_WRPKGCFG_READ_LEN 1 ++#define PECI_WRPKGCFG_CMD 0xa5 ++ ++ __u8 addr; ++ __u8 index; ++#define PECI_MBX_INDEX_DIMM_AMBIENT 19 ++#define PECI_MBX_INDEX_DIMM_TEMP 24 ++ ++ __u16 param; ++ __u8 tx_len; ++ __u8 cc; ++ __u8 padding[2]; ++ __u32 value; + } __attribute__((__packed__)); + + /** +@@ -284,16 +268,47 @@ struct peci_wr_pkg_cfg_msg { + * @addr: address of the client + * @thread_id: ID of the specific logical processor + * @address: address of MSR to read from ++ * @cc: completion code + * @value: data to be read + * + * The RdIAMSR() PECI command provides read access to Model Specific Registers + * (MSRs) defined in the processor's Intel Architecture (IA). + */ + struct peci_rd_ia_msr_msg { +- __u8 addr; +- __u8 thread_id; +- __u16 address; +- __u64 value; ++#define PECI_RDIAMSR_WRITE_LEN 5 ++#define PECI_RDIAMSR_READ_LEN 9 ++#define PECI_RDIAMSR_CMD 0xb1 ++ ++ __u8 addr; ++ __u8 thread_id; ++ __u16 address; ++ __u8 cc; ++ __u8 padding[3]; ++ __u64 value; ++} __attribute__((__packed__)); ++ ++/** ++ * struct peci_wr_ia_msr_msg - WrIAMSR command ++ * @addr: address of the client ++ * @thread_id: ID of the specific logical processor ++ * @address: address of MSR to write to ++ * @tx_len: number of data to be written in bytes ++ * @cc: completion code ++ * @value: data to be written ++ * ++ * The WrIAMSR() PECI command provides write access to Model Specific Registers ++ * (MSRs) defined in the processor's Intel Architecture (IA). ++ */ ++struct peci_wr_ia_msr_msg { ++#define PECI_WRIAMSR_CMD 0xb5 ++ ++ __u8 addr; ++ __u8 thread_id; ++ __u16 address; ++ __u8 tx_len; ++ __u8 cc; ++ __u8 padding[2]; ++ __u64 value; + } __attribute__((__packed__)); + + /** +@@ -303,6 +318,7 @@ struct peci_rd_ia_msr_msg { + * @device: PCI device number + * @function: specific function to read from + * @reg: specific register to read from ++ * @cc: completion code + * @pci_config: config data to be read + * + * The RdPCIConfig() command provides sideband read access to the PCI +@@ -310,12 +326,56 @@ struct peci_rd_ia_msr_msg { + * processor. + */ + struct peci_rd_pci_cfg_msg { +- __u8 addr; +- __u8 bus; +- __u8 device; +- __u8 function; +- __u16 reg; +- __u8 pci_config[4]; ++#define PECI_RDPCICFG_WRITE_LEN 6 ++#define PECI_RDPCICFG_READ_LEN 5 ++#define PECI_RDPCICFG_READ_LEN_MAX 24 ++#define PECI_RDPCICFG_CMD 0x61 ++ ++ __u8 addr; ++ __u8 bus; ++#define PECI_PCI_BUS0_CPU0 0x00 ++#define PECI_PCI_BUS0_CPU1 0x80 ++#define PECI_PCI_CPUBUSNO_BUS 0x00 ++#define PECI_PCI_CPUBUSNO_DEV 0x08 ++#define PECI_PCI_CPUBUSNO_FUNC 0x02 ++#define PECI_PCI_CPUBUSNO 0xcc ++#define PECI_PCI_CPUBUSNO_1 0xd0 ++#define PECI_PCI_CPUBUSNO_VALID 0xd4 ++ ++ __u8 device; ++ __u8 function; ++ __u16 reg; ++ __u8 cc; ++ __u8 padding[1]; ++ __u8 pci_config[4]; ++} __attribute__((__packed__)); ++ ++/** ++ * struct peci_wr_pci_cfg_msg - WrPCIConfig command ++ * @addr: address of the client ++ * @bus: PCI bus number ++ * @device: PCI device number ++ * @function: specific function to write to ++ * @reg: specific register to write to ++ * @tx_len: number of data to be written in bytes ++ * @cc: completion code ++ * @pci_config: config data to be written ++ * ++ * The RdPCIConfig() command provides sideband write access to the PCI ++ * configuration space maintained in downstream devices external to the ++ * processor. ++ */ ++struct peci_wr_pci_cfg_msg { ++#define PECI_WRPCICFG_CMD 0x65 ++ ++ __u8 addr; ++ __u8 bus; ++ __u8 device; ++ __u8 function; ++ __u16 reg; ++ __u8 tx_len; ++ __u8 cc; ++ __u8 pci_config[4]; + } __attribute__((__packed__)); + + /** +@@ -326,6 +386,7 @@ struct peci_rd_pci_cfg_msg { + * @function: specific function to read from + * @reg: specific register to read from + * @rx_len: number of data to be read in bytes ++ * @cc: completion code + * @pci_config: config data to be read + * + * The RdPCIConfigLocal() command provides sideband read access to the PCI +@@ -333,13 +394,18 @@ struct peci_rd_pci_cfg_msg { + * processor IIO and uncore registers within the PCI configuration space. + */ + struct peci_rd_pci_cfg_local_msg { +- __u8 addr; +- __u8 bus; +- __u8 device; +- __u8 function; +- __u16 reg; +- __u8 rx_len; +- __u8 pci_config[4]; ++#define PECI_RDPCICFGLOCAL_WRITE_LEN 5 ++#define PECI_RDPCICFGLOCAL_READ_LEN_BASE 1 ++#define PECI_RDPCICFGLOCAL_CMD 0xe1 ++ ++ __u8 addr; ++ __u8 bus; ++ __u8 device; ++ __u8 function; ++ __u16 reg; ++ __u8 rx_len; ++ __u8 cc; ++ __u8 pci_config[4]; + } __attribute__((__packed__)); + + /** +@@ -350,6 +416,7 @@ struct peci_rd_pci_cfg_local_msg { + * @function: specific function to read from + * @reg: specific register to read from + * @tx_len: number of data to be written in bytes ++ * @cc: completion code + * @value: config data to be written + * + * The WrPCIConfigLocal() command provides sideband write access to the PCI +@@ -357,13 +424,18 @@ struct peci_rd_pci_cfg_local_msg { + * access this space even before BIOS enumeration of the system buses. + */ + struct peci_wr_pci_cfg_local_msg { +- __u8 addr; +- __u8 bus; +- __u8 device; +- __u8 function; +- __u16 reg; +- __u8 tx_len; +- __u32 value; ++#define PECI_WRPCICFGLOCAL_WRITE_LEN_BASE 6 ++#define PECI_WRPCICFGLOCAL_READ_LEN 1 ++#define PECI_WRPCICFGLOCAL_CMD 0xe5 ++ ++ __u8 addr; ++ __u8 bus; ++ __u8 device; ++ __u8 function; ++ __u16 reg; ++ __u8 tx_len; ++ __u8 cc; ++ __u32 value; + } __attribute__((__packed__)); + + #define PECI_IOC_BASE 0xb7 +@@ -389,9 +461,15 @@ struct peci_wr_pci_cfg_local_msg { + #define PECI_IOC_RD_IA_MSR \ + _IOWR(PECI_IOC_BASE, PECI_CMD_RD_IA_MSR, struct peci_rd_ia_msr_msg) + ++#define PECI_IOC_WR_IA_MSR \ ++ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_IA_MSR, struct peci_wr_ia_msr_msg) ++ + #define PECI_IOC_RD_PCI_CFG \ + _IOWR(PECI_IOC_BASE, PECI_CMD_RD_PCI_CFG, struct peci_rd_pci_cfg_msg) + ++#define PECI_IOC_WR_PCI_CFG \ ++ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_PCI_CFG, struct peci_wr_pci_cfg_msg) ++ + #define PECI_IOC_RD_PCI_CFG_LOCAL \ + _IOWR(PECI_IOC_BASE, PECI_CMD_RD_PCI_CFG_LOCAL, \ + struct peci_rd_pci_cfg_local_msg) +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0020-misc-aspeed-add-lpc-mbox-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0020-misc-aspeed-add-lpc-mbox-driver.patch index 884a7018c..a444d39b3 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0020-misc-aspeed-add-lpc-mbox-driver.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0020-misc-aspeed-add-lpc-mbox-driver.patch @@ -1,4 +1,4 @@ -From efa7ad95db45494b2c3685c0688f00174e517e34 Mon Sep 17 00:00:00 2001 +From c1567ac196f176b19b53b6c4e7949809fd01e334 Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Wed, 10 Jul 2019 16:19:33 -0700 Subject: [PATCH] misc: aspeed: add lpc mbox driver @@ -20,10 +20,10 @@ Signed-off-by: Jae Hyun Yoo create mode 100644 drivers/soc/aspeed/aspeed-lpc-mbox.c diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi -index 00848693f455..4b8b0be22cd4 100644 +index ee86b41af291..b7b6e8aa3a12 100644 --- a/arch/arm/boot/dts/aspeed-g4.dtsi +++ b/arch/arm/boot/dts/aspeed-g4.dtsi -@@ -344,6 +344,15 @@ +@@ -394,6 +394,15 @@ sio_regs: regs { compatible = "aspeed,bmc-misc"; }; @@ -40,10 +40,10 @@ index 00848693f455..4b8b0be22cd4 100644 }; diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi -index 8406da6f62a5..9f3bd5bafab5 100644 +index 128e0b5bbae2..12a81155f1ab 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi -@@ -473,6 +473,15 @@ +@@ -503,6 +503,15 @@ sio_regs: regs { compatible = "aspeed,bmc-misc"; }; diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch index b347894be..24eca1bb9 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch @@ -1,4 +1,4 @@ -From 3d1ddeb903f6eaeb06ddc1d6cfbed6374ef31f36 Mon Sep 17 00:00:00 2001 +From 450b6d6e58ca9954fd4b675da8b6bb25d21c020f Mon Sep 17 00:00:00 2001 From: Yong Li Date: Mon, 13 Nov 2017 16:29:44 +0800 Subject: [PATCH] Aspeed LPC SIO driver @@ -44,10 +44,10 @@ index 000000000000..c74ea3a4e5ac + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi -index 07758c9b900b..3df43f925848 100644 +index b7b6e8aa3a12..71563972d2fe 100644 --- a/arch/arm/boot/dts/aspeed-g4.dtsi +++ b/arch/arm/boot/dts/aspeed-g4.dtsi -@@ -345,6 +345,13 @@ +@@ -395,6 +395,13 @@ compatible = "aspeed,bmc-misc"; }; @@ -62,10 +62,10 @@ index 07758c9b900b..3df43f925848 100644 compatible = "aspeed,ast2400-mbox"; reg = <0x180 0x5c>; diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi -index 2387e2d1ff9e..2d6f730a7101 100644 +index 12a81155f1ab..88f75736fe48 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi -@@ -474,6 +474,13 @@ +@@ -504,6 +504,13 @@ compatible = "aspeed,bmc-misc"; }; diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch index a44667436..07283f54d 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch @@ -1,4 +1,4 @@ -From 0f0e0a03218f6a7bdcdd78d319959e6bb974502c Mon Sep 17 00:00:00 2001 +From 6e55e28db5eed85b7717aa4fc92c064f11429f6d Mon Sep 17 00:00:00 2001 From: Haiyue Wang Date: Sat, 24 Feb 2018 11:12:32 +0800 Subject: [PATCH] eSPI: add ASPEED AST2500 eSPI driver to boot a host with PCH @@ -16,15 +16,20 @@ Also for the host power on / off actions, from BMC side, the following VW 3. OOB_RESET_ACK 4. HOST_RESET_ACK +Also, it provides monitoring interface of PLTRST_N signal through +/dev/espi-pltrstn + Signed-off-by: Haiyue Wang +Signed-off-by: Jae Hyun Yoo +Signed-off-by: James Feist --- - .../devicetree/bindings/misc/aspeed,espi-slave.txt | 19 ++ - Documentation/misc-devices/espi-slave.rst | 118 +++++++ + .../devicetree/bindings/misc/aspeed,espi-slave.txt | 19 + + Documentation/misc-devices/espi-slave.rst | 118 ++++++ arch/arm/boot/dts/aspeed-g5.dtsi | 4 + drivers/misc/Kconfig | 8 + drivers/misc/Makefile | 1 + - drivers/misc/aspeed-espi-slave.c | 353 +++++++++++++++++++++ - 6 files changed, 503 insertions(+) + drivers/misc/aspeed-espi-slave.c | 420 +++++++++++++++++++++ + 6 files changed, 570 insertions(+) create mode 100644 Documentation/devicetree/bindings/misc/aspeed,espi-slave.txt create mode 100644 Documentation/misc-devices/espi-slave.rst create mode 100644 drivers/misc/aspeed-espi-slave.c @@ -179,10 +184,10 @@ index 000000000000..887a69a7130a +- Interface Base Specification (for Client and Server Platforms) +`_ diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi -index 2d6f730a7101..0e7f1d2fa08e 100644 +index 88f75736fe48..26671cc4dbd5 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi -@@ -289,6 +289,7 @@ +@@ -317,6 +317,7 @@ clocks = <&syscon ASPEED_CLK_APB>; interrupt-controller; #interrupt-cells = <2>; @@ -190,7 +195,7 @@ index 2d6f730a7101..0e7f1d2fa08e 100644 }; sgpio: sgpio@1e780200 { -@@ -383,6 +384,9 @@ +@@ -413,6 +414,9 @@ reg = <0x1e6ee000 0x100>; interrupts = <23>; status = "disabled"; @@ -201,10 +206,10 @@ index 2d6f730a7101..0e7f1d2fa08e 100644 lpc: lpc@1e789000 { diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig -index 9d96469fb41c..b6acddaa9421 100644 +index d681b7201f8c..50814caba1d3 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig -@@ -473,6 +473,14 @@ config VEXPRESS_SYSCFG +@@ -455,6 +455,14 @@ config VEXPRESS_SYSCFG bus. System Configuration interface is one of the possible means of generating transactions on this bus. @@ -220,10 +225,10 @@ index 9d96469fb41c..b6acddaa9421 100644 depends on PCI select CRC32 diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile -index e13de4f0798f..f91f66a15484 100644 +index fdd404120ed8..f168e6713440 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile -@@ -54,6 +54,7 @@ obj-$(CONFIG_GENWQE) += genwqe/ +@@ -53,6 +53,7 @@ obj-$(CONFIG_GENWQE) += genwqe/ obj-$(CONFIG_ECHO) += echo/ obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o obj-$(CONFIG_CXL_BASE) += cxl/ @@ -233,363 +238,430 @@ index e13de4f0798f..f91f66a15484 100644 obj-y += cardreader/ diff --git a/drivers/misc/aspeed-espi-slave.c b/drivers/misc/aspeed-espi-slave.c new file mode 100644 -index 000000000000..36ae867ca6f9 +index 000000000000..b0fc01692d3a --- /dev/null +++ b/drivers/misc/aspeed-espi-slave.c -@@ -0,0 +1,353 @@ +@@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2012-2015, ASPEED Technology Inc. -+ * Copyright (c) 2015-2018, Intel Corporation. -+ */ ++// Copyright (c) 2015-2019, Intel Corporation. + -+#include +#include -+#include ++#include +#include +#include +#include +#include +#include +#include -+#include +#include -+#include -+#include -+#include -+ -+#define DEVICE_NAME "aspeed-espi-slave" -+ -+#define ESPI_CTRL 0x00 -+#define ESPI_CTRL_SW_RESET GENMASK(31, 24) -+#define ESPI_CTRL_OOB_CHRDY BIT(4) -+#define ESPI_ISR 0x08 -+#define ESPI_ISR_HW_RESET BIT(31) -+#define ESPI_ISR_VW_SYS_EVT1 BIT(22) -+#define ESPI_ISR_VW_SYS_EVT BIT(8) -+#define ESPI_IER 0x0C -+#define ESPI_DATA_PORT 0x28 -+#define ESPI_DATA_PORT_ASPEED 0xa8 -+#define ESPI_SYS_IER 0x94 -+#define ESPI_SYS_EVENT 0x98 -+#define ESPI_SYS_INT_T0 0x110 -+#define ESPI_SYS_INT_T1 0x114 -+#define ESPI_SYS_INT_T2 0x118 -+#define ESPI_SYS_ISR 0x11C -+#define ESPI_SYSEVT_HOST_RST_ACK BIT(27) -+#define ESPI_SYSEVT_SLAVE_BOOT_STATUS BIT(23) -+#define ESPI_SYSEVT_SLAVE_BOOT_DONE BIT(20) -+#define ESPI_SYSEVT_OOB_RST_ACK BIT(16) -+#define ESPI_SYSEVT_HOST_RST_WARN BIT(8) -+#define ESPI_SYSEVT_OOB_RST_WARN BIT(6) -+#define ESPI_SYSEVT_PLT_RST_N BIT(5) -+#define ESPI_SYS1_IER 0x100 -+#define ESPI_SYS1_EVENT 0x104 -+#define ESPI_SYS1_INT_T0 0x120 -+#define ESPI_SYS1_INT_T1 0x124 -+#define ESPI_SYS1_INT_T2 0x128 -+#define ESPI_SYS1_ISR 0x12C -+#define ESPI_SYSEVT1_SUS_ACK BIT(20) -+#define ESPI_SYSEVT1_SUS_WARN BIT(0) -+ -+struct aspeed_espi_slave_data { -+ struct regmap *map; -+ struct clk *clk; ++#include ++#include ++#include ++ ++#define ASPEED_ESPI_CTRL 0x00 ++#define ASPEED_ESPI_CTRL_SW_RESET GENMASK(31, 24) ++#define ASPEED_ESPI_CTRL_OOB_CHRDY BIT(4) ++#define ASPEED_ESPI_INT_STS 0x08 ++#define ASPEED_ESPI_HW_RESET BIT(31) ++#define ASPEED_ESPI_VW_SYSEVT1 BIT(22) ++#define ASPEED_ESPI_VW_SYSEVT BIT(8) ++#define ASPEED_ESPI_INT_EN 0x0C ++#define ASPEED_ESPI_DATA_PORT 0x28 ++#define ASPEED_ESPI_SYSEVT_INT_EN 0x94 ++#define ASPEED_ESPI_SYSEVT 0x98 ++#define ASPEED_ESPI_SYSEVT_HOST_RST_ACK BIT(27) ++#define ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS BIT(23) ++#define ASPEED_ESPI_SYSEVT_SLAVE_BOOT_DONE BIT(20) ++#define ASPEED_ESPI_SYSEVT_OOB_RST_ACK BIT(16) ++#define ASPEED_ESPI_SYSEVT_INT_T0 0x110 ++#define ASPEED_ESPI_SYSEVT_INT_T1 0x114 ++#define ASPEED_ESPI_SYSEVT_INT_T2 0x118 ++#define ASPEED_ESPI_SYSEVT_INT_STS 0x11C ++#define ASPEED_ESPI_SYSEVT_HOST_RST_WARN BIT(8) ++#define ASPEED_ESPI_SYSEVT_OOB_RST_WARN BIT(6) ++#define ASPEED_ESPI_SYSEVT_PLTRSTN BIT(5) ++#define ASPEED_ESPI_SYSEVT1_INT_EN 0x100 ++#define ASPEED_ESPI_SYSEVT1 0x104 ++#define ASPEED_ESPI_SYSEVT1_SUS_ACK BIT(20) ++#define ASPEED_ESPI_SYSEVT1_INT_T0 0x120 ++#define ASPEED_ESPI_SYSEVT1_INT_T1 0x124 ++#define ASPEED_ESPI_SYSEVT1_INT_T2 0x128 ++#define ASPEED_ESPI_SYSEVT1_INT_STS 0x12C ++#define ASPEED_ESPI_SYSEVT1_SUS_WARN BIT(0) ++ ++#define ASPEED_ESPI_INT_MASK \ ++ (ASPEED_ESPI_HW_RESET | \ ++ ASPEED_ESPI_VW_SYSEVT1 | \ ++ ASPEED_ESPI_VW_SYSEVT) ++ ++/* ++ * Setup Interrupt Type / Enable of System Event from Master ++ * T2 T1 T0 ++ * 1) HOST_RST_WARN : Dual Edge 1 0 0 ++ * 2) OOB_RST_WARN : Dual Edge 1 0 0 ++ * 3) PLTRSTN : Dual Edge 1 0 0 ++ */ ++#define ASPEED_ESPI_SYSEVT_INT_T0_MASK 0 ++#define ASPEED_ESPI_SYSEVT_INT_T1_MASK 0 ++#define ASPEED_ESPI_SYSEVT_INT_T2_MASK \ ++ (ASPEED_ESPI_SYSEVT_HOST_RST_WARN | \ ++ ASPEED_ESPI_SYSEVT_OOB_RST_WARN | \ ++ ASPEED_ESPI_SYSEVT_PLTRSTN) ++#define ASPEED_ESPI_SYSEVT_INT_MASK \ ++ (ASPEED_ESPI_SYSEVT_INT_T0_MASK | \ ++ ASPEED_ESPI_SYSEVT_INT_T1_MASK | \ ++ ASPEED_ESPI_SYSEVT_INT_T2_MASK) ++ ++/* ++ * Setup Interrupt Type / Enable of System Event 1 from Master ++ * T2 T1 T0 ++ * 1) SUS_WARN : Rising Edge 0 0 1 ++ */ ++#define ASPEED_ESPI_SYSEVT1_INT_T0_MASK ASPEED_ESPI_SYSEVT1_SUS_WARN ++#define ASPEED_ESPI_SYSEVT1_INT_T1_MASK 0 ++#define ASPEED_ESPI_SYSEVT1_INT_T2_MASK 0 ++#define ASPEED_ESPI_SYSEVT1_INT_MASK \ ++ (ASPEED_ESPI_SYSEVT1_INT_T0_MASK | \ ++ ASPEED_ESPI_SYSEVT1_INT_T1_MASK | \ ++ ASPEED_ESPI_SYSEVT1_INT_T2_MASK) ++ ++struct aspeed_espi { ++ struct regmap *map; ++ struct clk *clk; ++ struct device *dev; ++ int irq; ++ ++ /* for PLTRST_N signal monitoring interface */ ++ struct miscdevice pltrstn_miscdev; ++ spinlock_t pltrstn_lock; /* for PLTRST_N signal sampling */ ++ wait_queue_head_t pltrstn_waitq; ++ char pltrstn; +}; + -+static void aspeed_espi_slave_sys_event(struct platform_device *pdev) ++static void aspeed_espi_sys_event(struct aspeed_espi *priv) +{ -+ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev); -+ struct device *dev = &pdev->dev; + u32 sts, evt; + -+ if (regmap_read(priv->map, ESPI_SYS_ISR, &sts) != 0 || -+ regmap_read(priv->map, ESPI_SYS_EVENT, &evt) != 0) { -+ dev_err(dev, "regmap_read failed\n"); -+ return; -+ } ++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT_INT_STS, &sts); ++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT, &evt); + -+ dev_dbg(dev, "sys: sts = %08x, evt = %08x\n", sts, evt); ++ dev_dbg(priv->dev, "sys: sts = %08x, evt = %08x\n", sts, evt); + -+ if ((evt & ESPI_SYSEVT_SLAVE_BOOT_STATUS) == 0) { -+ dev_info(dev, "Setting espi slave boot done\n"); -+ regmap_write(priv->map, ESPI_SYS_EVENT, -+ evt | ESPI_SYSEVT_SLAVE_BOOT_STATUS | -+ ESPI_SYSEVT_SLAVE_BOOT_DONE); ++ if (!(evt & ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS)) { ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT, ++ evt | ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS | ++ ASPEED_ESPI_SYSEVT_SLAVE_BOOT_DONE); ++ dev_dbg(priv->dev, "Setting espi slave boot done\n"); + } -+#if 0 -+ if (sts & ESPI_SYSEVT_HOST_RST_WARN) { -+ dev_info(dev, "ESPI_SYSEVT_HOST_RST_WARN; %s ack\n", -+ (evt & ESPI_SYSEVT_HOST_RST_WARN ? "send" : "clr")); -+ regmap_write_bits(priv->map, ESPI_SYS_EVENT, -+ ESPI_SYSEVT_HOST_RST_ACK, -+ evt & ESPI_SYSEVT_HOST_RST_WARN ? -+ ESPI_SYSEVT_HOST_RST_ACK : 0); ++ if (sts & ASPEED_ESPI_SYSEVT_HOST_RST_WARN && ++ evt & ASPEED_ESPI_SYSEVT_HOST_RST_WARN) { ++ regmap_write_bits(priv->map, ASPEED_ESPI_SYSEVT, ++ ASPEED_ESPI_SYSEVT_HOST_RST_ACK, ++ ASPEED_ESPI_SYSEVT_HOST_RST_ACK); ++ dev_dbg(priv->dev, "SYSEVT_HOST_RST_WARN: acked\n"); + } -+ if (sts & ESPI_SYSEVT_OOB_RST_WARN) { -+ dev_info(dev, "ESPI_SYSEVT_OOB_RST_WARN; %s ack\n", -+ (evt & ESPI_SYSEVT_OOB_RST_WARN ? "send" : "clr")); -+ regmap_write_bits(priv->map, ESPI_SYS_EVENT, -+ ESPI_SYSEVT_OOB_RST_ACK, -+ evt & ESPI_SYSEVT_OOB_RST_WARN ? -+ ESPI_SYSEVT_OOB_RST_ACK : 0); ++ if (sts & ASPEED_ESPI_SYSEVT_OOB_RST_WARN && ++ evt & ASPEED_ESPI_SYSEVT_OOB_RST_WARN) { ++ regmap_write_bits(priv->map, ASPEED_ESPI_SYSEVT, ++ ASPEED_ESPI_SYSEVT_OOB_RST_ACK, ++ ASPEED_ESPI_SYSEVT_OOB_RST_ACK); ++ dev_dbg(priv->dev, "SYSEVT_OOB_RST_WARN: acked\n"); + } -+#else -+ if (sts & ESPI_SYSEVT_HOST_RST_WARN) { -+ if (evt & ESPI_SYSEVT_HOST_RST_WARN) { -+ dev_info(dev, "ESPI_SYSEVT_HOST_RST_WARN; send ack\n"); -+ regmap_write_bits(priv->map, ESPI_SYS_EVENT, -+ ESPI_SYSEVT_HOST_RST_ACK, ESPI_SYSEVT_HOST_RST_ACK); -+ } ++ if (sts & ASPEED_ESPI_SYSEVT_PLTRSTN || priv->pltrstn == 'U') { ++ priv->pltrstn = (evt & ASPEED_ESPI_SYSEVT_PLTRSTN) ? '1' : '0'; ++ wake_up_interruptible(&priv->pltrstn_waitq); ++ dev_dbg(priv->dev, "SYSEVT_PLTRSTN: %c\n", priv->pltrstn); + } -+ if (sts & ESPI_SYSEVT_OOB_RST_WARN) { -+ if (evt & ESPI_SYSEVT_OOB_RST_WARN) { -+ dev_info(dev, "ESPI_SYSEVT_OOB_RST_WARN; send ack\n"); -+ regmap_write_bits(priv->map, ESPI_SYS_EVENT, -+ ESPI_SYSEVT_OOB_RST_ACK, ESPI_SYSEVT_OOB_RST_ACK); -+ } -+ } -+#endif -+ regmap_write(priv->map, ESPI_SYS_ISR, sts); ++ ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_STS, sts); +} + -+static void aspeed_espi_slave_sys1_event(struct platform_device *pdev) ++static void aspeed_espi_sys_event1(struct aspeed_espi *priv) +{ -+ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev); -+ struct device *dev = &pdev->dev; + u32 sts, evt; + -+ if (regmap_read(priv->map, ESPI_SYS1_ISR, &sts) != 0 || -+ regmap_read(priv->map, ESPI_SYS1_EVENT, &evt) != 0) { -+ dev_err(dev, "regmap_read failed\n"); -+ return; -+ } -+ dev_dbg(dev, "sys1: sts = %08x, evt = %08x\n", sts, evt); -+ -+#if 0 -+ if (sts & ESPI_SYSEVT1_SUS_WARN) { -+ dev_info(dev, "ESPI_SYSEVT1_SUS_WARN; %s ack\n", -+ (evt & ESPI_SYSEVT1_SUS_WARN ? "send" : "clr")); -+ regmap_write_bits(priv->map, ESPI_SYS1_EVENT, -+ ESPI_SYSEVT1_SUS_ACK, -+ evt & ESPI_SYSEVT1_SUS_WARN ? -+ ESPI_SYSEVT1_SUS_ACK : 0); -+ } -+#else -+ if (sts & ESPI_SYSEVT1_SUS_WARN) { -+ if (evt & ESPI_SYSEVT1_SUS_WARN) { -+ dev_info(dev, "ESPI_SYSEVT_OOB_RST_WARN; send ack\n"); -+ regmap_write_bits(priv->map, ESPI_SYS1_EVENT, -+ ESPI_SYSEVT1_SUS_ACK, ESPI_SYSEVT1_SUS_ACK); -+ } ++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT1_INT_STS, &sts); ++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT1, &evt); ++ ++ dev_dbg(priv->dev, "sys event1: sts = %08x, evt = %08x\n", sts, evt); ++ ++ if (sts & ASPEED_ESPI_SYSEVT1_SUS_WARN && ++ evt & ASPEED_ESPI_SYSEVT1_SUS_WARN) { ++ regmap_write_bits(priv->map, ASPEED_ESPI_SYSEVT1, ++ ASPEED_ESPI_SYSEVT1_SUS_ACK, ++ ASPEED_ESPI_SYSEVT1_SUS_ACK); ++ dev_dbg(priv->dev, "SYSEVT1_SUS_WARN: acked\n"); + } -+#endif -+ regmap_write(priv->map, ESPI_SYS1_ISR, sts); ++ ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_STS, sts); +} + -+static void aspeed_espi_slave_boot_ack(struct platform_device *pdev) ++static void aspeed_espi_boot_ack(struct aspeed_espi *priv) +{ -+ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev); -+ struct device *dev = &pdev->dev; + u32 evt; + -+ if (regmap_read(priv->map, ESPI_SYS_EVENT, &evt) == 0 && -+ (evt & ESPI_SYSEVT_SLAVE_BOOT_STATUS) == 0) { -+ dev_info(dev, "Setting espi slave boot done\n"); -+ regmap_write(priv->map, ESPI_SYS_EVENT, -+ evt | ESPI_SYSEVT_SLAVE_BOOT_STATUS | -+ ESPI_SYSEVT_SLAVE_BOOT_DONE); ++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT, &evt); ++ if (!(evt & ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS)) { ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT, ++ evt | ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS | ++ ASPEED_ESPI_SYSEVT_SLAVE_BOOT_DONE); ++ dev_dbg(priv->dev, "Setting espi slave boot done\n"); + } + -+ if (regmap_read(priv->map, ESPI_SYS1_EVENT, &evt) == 0 && -+ (evt & ESPI_SYSEVT1_SUS_WARN) != 0 && -+ (evt & ESPI_SYSEVT1_SUS_ACK) == 0) { -+ dev_info(dev, "Boot SUS WARN set; send ack\n"); -+ regmap_write(priv->map, ESPI_SYS1_EVENT, -+ evt | ESPI_SYSEVT1_SUS_ACK); ++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT1, &evt); ++ if (evt & ASPEED_ESPI_SYSEVT1_SUS_WARN && ++ !(evt & ASPEED_ESPI_SYSEVT1_SUS_ACK)) { ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1, ++ evt | ASPEED_ESPI_SYSEVT1_SUS_ACK); ++ dev_dbg(priv->dev, "Boot SYSEVT1_SUS_WARN: acked\n"); + } +} + -+static irqreturn_t aspeed_espi_slave_irq(int irq, void *arg) ++static irqreturn_t aspeed_espi_irq(int irq, void *arg) +{ -+ struct platform_device *pdev = arg; -+ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev); -+ struct device *dev = &pdev->dev; -+ u32 sts; -+ -+ if (regmap_read(priv->map, ESPI_ISR, &sts) != 0) { -+ dev_err(dev, "regmap_read failed\n"); -+ return IRQ_NONE; -+ } ++ struct aspeed_espi *priv = arg; ++ u32 sts, sts_handled = 0; + -+ dev_dbg(dev, "ESPI_ISR: %08x\n", sts); ++ regmap_read(priv->map, ASPEED_ESPI_INT_STS, &sts); + -+ if (sts & ESPI_ISR_VW_SYS_EVT) -+ aspeed_espi_slave_sys_event(pdev); ++ dev_dbg(priv->dev, "INT_STS: 0x%08x\n", sts); + -+ if (sts & ESPI_ISR_VW_SYS_EVT1) -+ aspeed_espi_slave_sys1_event(pdev); ++ if (sts & ASPEED_ESPI_VW_SYSEVT) { ++ aspeed_espi_sys_event(priv); ++ sts_handled |= ASPEED_ESPI_VW_SYSEVT; ++ } + -+ /* -+ if (sts & ESPI_ISR_HW_RESET) { -+ regmap_write_bits(priv->map, ESPI_CTRL, -+ ESPI_CTRL_SW_RESET, 0); -+ regmap_write_bits(priv->map, ESPI_CTRL, -+ ESPI_CTRL_SW_RESET, ESPI_CTRL_SW_RESET); ++ if (sts & ASPEED_ESPI_VW_SYSEVT1) { ++ aspeed_espi_sys_event1(priv); ++ sts_handled |= ASPEED_ESPI_VW_SYSEVT1; ++ } + -+ aspeed_espi_slave_boot_ack(pdev); ++ if (sts & ASPEED_ESPI_HW_RESET) { ++ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL, ++ ASPEED_ESPI_CTRL_SW_RESET, 0); ++ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL, ++ ASPEED_ESPI_CTRL_SW_RESET, ++ ASPEED_ESPI_CTRL_SW_RESET); ++ aspeed_espi_boot_ack(priv); ++ sts_handled |= ASPEED_ESPI_HW_RESET; + } -+ */ + -+ regmap_write(priv->map, ESPI_ISR, sts); ++ regmap_write(priv->map, ASPEED_ESPI_INT_STS, sts); + -+ return IRQ_HANDLED; ++ return sts != sts_handled ? IRQ_NONE : IRQ_HANDLED; +} + -+/* Setup Interrupt Type/Enable of System Event from Master -+ * T2 T1 T0 -+ * 1). HOST_RST_WARN : Dual Edge 1 0 0 -+ * 2). OOB_RST_WARN : Dual Edge 1 0 0 -+ * 3). PLTRST_N : Dual Edge 1 0 0 -+ */ -+#define ESPI_SYS_INT_T0_SET 0x00000000 -+#define ESPI_SYS_INT_T1_SET 0x00000000 -+#define ESPI_SYS_INT_T2_SET \ -+(ESPI_SYSEVT_HOST_RST_WARN | ESPI_SYSEVT_OOB_RST_WARN | ESPI_SYSEVT_PLT_RST_N) -+#define ESPI_SYS_INT_SET \ -+(ESPI_SYSEVT_HOST_RST_WARN | ESPI_SYSEVT_OOB_RST_WARN | ESPI_SYSEVT_PLT_RST_N) -+ -+/* Setup Interrupt Type/Enable of System Event 1 from Master -+ * T2 T1 T0 -+ * 1). SUS_WARN : Rising Edge 0 0 1 -+ */ -+#define ESPI_SYS1_INT_T0_SET ESPI_SYSEVT1_SUS_WARN -+#define ESPI_SYS1_INT_T1_SET 0x00000000 -+#define ESPI_SYS1_INT_T2_SET 0x00000000 -+#define ESPI_SYS1_INT_SET ESPI_SYSEVT1_SUS_WARN ++static void aspeed_espi_config_irq(struct aspeed_espi *priv) ++{ ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_T0, ++ ASPEED_ESPI_SYSEVT_INT_T0_MASK); ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_T1, ++ ASPEED_ESPI_SYSEVT_INT_T1_MASK); ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_T2, ++ ASPEED_ESPI_SYSEVT_INT_T2_MASK); ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_EN, ++ ASPEED_ESPI_SYSEVT_INT_MASK); ++ ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_T0, ++ ASPEED_ESPI_SYSEVT1_INT_T0_MASK); ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_T1, ++ ASPEED_ESPI_SYSEVT1_INT_T1_MASK); ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_T2, ++ ASPEED_ESPI_SYSEVT1_INT_T2_MASK); ++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_EN, ++ ASPEED_ESPI_SYSEVT1_INT_MASK); ++ ++ regmap_write(priv->map, ASPEED_ESPI_INT_EN, ASPEED_ESPI_INT_MASK); ++ ++ aspeed_espi_boot_ack(priv); ++} + -+static int aspeed_espi_slave_config_irq(struct platform_device *pdev) ++static inline struct aspeed_espi *to_aspeed_espi(struct file *filp) +{ -+ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev); -+ struct device *dev = &pdev->dev; -+ int irq; -+ int rc; ++ return container_of(filp->private_data, struct aspeed_espi, ++ pltrstn_miscdev); ++} + -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) -+ return irq; ++static int aspeed_espi_pltrstn_open(struct inode *inode, struct file *filp) ++{ ++ if ((filp->f_flags & O_ACCMODE) != O_RDONLY) ++ return -EACCES; + -+ regmap_write_bits(priv->map, ESPI_CTRL, ESPI_CTRL_OOB_CHRDY, -+ ESPI_CTRL_OOB_CHRDY); ++ return 0; ++} + -+ regmap_write(priv->map, ESPI_SYS_INT_T0, ESPI_SYS_INT_T0_SET); -+ regmap_write(priv->map, ESPI_SYS_INT_T1, ESPI_SYS_INT_T1_SET); -+ regmap_write(priv->map, ESPI_SYS_INT_T2, ESPI_SYS_INT_T2_SET); -+ regmap_write(priv->map, ESPI_SYS_IER, ESPI_SYS_INT_SET); ++static ssize_t aspeed_espi_pltrstn_read(struct file *filp, char __user *buf, ++ size_t count, loff_t *offset) ++{ ++ struct aspeed_espi *priv = to_aspeed_espi(filp); ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ char old_sample; ++ int ret = 0; + -+ regmap_write(priv->map, ESPI_SYS1_INT_T0, ESPI_SYS1_INT_T0_SET); -+ regmap_write(priv->map, ESPI_SYS1_INT_T1, ESPI_SYS1_INT_T1_SET); -+ regmap_write(priv->map, ESPI_SYS1_INT_T2, ESPI_SYS1_INT_T2_SET); -+ regmap_write(priv->map, ESPI_SYS1_IER, ESPI_SYS1_INT_SET); ++ spin_lock_irqsave(&priv->pltrstn_lock, flags); + -+ regmap_write(priv->map, ESPI_IER, 0xFFFFFFFF); ++ add_wait_queue(&priv->pltrstn_waitq, &wait); ++ set_current_state(TASK_INTERRUPTIBLE); + -+ aspeed_espi_slave_boot_ack(pdev); ++ old_sample = priv->pltrstn; + -+ rc = devm_request_irq(dev, irq, aspeed_espi_slave_irq, IRQF_SHARED, -+ dev_name(dev), pdev); -+ if (rc < 0) -+ return rc; ++ do { ++ char new_sample = priv->pltrstn; + -+ return 0; ++ if (filp->f_flags & O_NONBLOCK || old_sample != new_sample) { ++ ret = put_user(new_sample, (unsigned long __user *)buf); ++ if (!ret) ++ ret = sizeof(new_sample); ++ } else if (signal_pending(current)) { ++ ret = -ERESTARTSYS; ++ } ++ ++ if (!ret) { ++ spin_unlock_irqrestore(&priv->pltrstn_lock, flags); ++ schedule(); ++ spin_lock_irqsave(&priv->pltrstn_lock, flags); ++ } ++ } while (!ret); ++ ++ remove_wait_queue(&priv->pltrstn_waitq, &wait); ++ set_current_state(TASK_RUNNING); ++ ++ spin_unlock_irqrestore(&priv->pltrstn_lock, flags); ++ ++ return ret; +} + -+static const struct regmap_config espi_slave_regmap_cfg = { -+ .reg_bits = 32, -+ .reg_stride = 4, -+ .val_bits = 32, -+ .max_register = ESPI_SYS1_ISR, ++static const struct file_operations aspeed_espi_pltrstn_fops = { ++ .owner = THIS_MODULE, ++ .open = aspeed_espi_pltrstn_open, ++ .read = aspeed_espi_pltrstn_read, ++}; ++ ++static const struct regmap_config aspeed_espi_regmap_cfg = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .max_register = ASPEED_ESPI_SYSEVT1_INT_STS, +}; + -+static int aspeed_espi_slave_probe(struct platform_device *pdev) ++static int aspeed_espi_probe(struct platform_device *pdev) +{ -+ struct aspeed_espi_slave_data *priv; -+ struct device *dev = &pdev->dev; ++ struct aspeed_espi *priv; + struct resource *res; + void __iomem *regs; -+ int rc; ++ u32 ctrl; ++ int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ regs = devm_ioremap_resource(dev, res); ++ regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + -+ priv->map = devm_regmap_init_mmio(dev, regs, &espi_slave_regmap_cfg); ++ dev_set_drvdata(&pdev->dev, priv); ++ priv->dev = &pdev->dev; ++ ++ priv->map = devm_regmap_init_mmio(&pdev->dev, regs, ++ &aspeed_espi_regmap_cfg); + if (IS_ERR(priv->map)) + return PTR_ERR(priv->map); + -+ priv->clk = devm_clk_get(dev, NULL); ++ spin_lock_init(&priv->pltrstn_lock); ++ init_waitqueue_head(&priv->pltrstn_waitq); ++ priv->pltrstn = 'U'; /* means it's not reported yet from master */ ++ ++ priv->irq = platform_get_irq(pdev, 0); ++ if (priv->irq < 0) ++ return priv->irq; ++ ++ aspeed_espi_config_irq(priv); ++ ++ ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_espi_irq, 0, ++ "aspeed-espi-irq", priv); ++ if (ret) ++ return ret; ++ ++ priv->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(priv->clk)) { -+ dev_err(dev, "couldn't get clock\n"); -+ return PTR_ERR(priv->clk); ++ ret = PTR_ERR(priv->clk); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "couldn't get clock\n"); ++ return ret; + } -+ rc = clk_prepare_enable(priv->clk); -+ if (rc) { -+ dev_err(dev, "couldn't enable clock\n"); -+ return rc; ++ ret = clk_prepare_enable(priv->clk); ++ if (ret) { ++ dev_err(&pdev->dev, "couldn't enable clock\n"); ++ return ret; + } + -+ dev_set_name(dev, DEVICE_NAME); -+ -+ platform_set_drvdata(pdev, priv); -+ -+ rc = aspeed_espi_slave_config_irq(pdev); -+ if (rc) { -+ platform_set_drvdata(pdev, NULL); -+ goto err; ++ /* ++ * We check that the regmap works on this very first access, but as this ++ * is an MMIO-backed regmap, subsequent regmap access is not going to ++ * fail and we skip error checks from this point. ++ */ ++ ret = regmap_read(priv->map, ASPEED_ESPI_CTRL, &ctrl); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to read ctrl register\n"); ++ goto err_clk_disable_out; ++ } ++ regmap_write(priv->map, ASPEED_ESPI_CTRL, ++ ctrl | ASPEED_ESPI_CTRL_OOB_CHRDY); ++ ++ priv->pltrstn_miscdev.minor = MISC_DYNAMIC_MINOR; ++ priv->pltrstn_miscdev.name = "espi-pltrstn"; ++ priv->pltrstn_miscdev.fops = &aspeed_espi_pltrstn_fops; ++ priv->pltrstn_miscdev.parent = &pdev->dev; ++ ++ ret = misc_register(&priv->pltrstn_miscdev); ++ if (ret) { ++ dev_err(&pdev->dev, "Unable to register device\n"); ++ goto err_clk_disable_out; + } + -+ dev_info(dev, "aspeed,ast2500-espi-slave probe complete\n"); ++ dev_info(&pdev->dev, "eSPI registered, irq %d\n", priv->irq); ++ + return 0; + -+err: ++err_clk_disable_out: + clk_disable_unprepare(priv->clk); -+ return rc; -+} + ++ return ret; ++} + -+static int aspeed_espi_slave_remove(struct platform_device *pdev) ++static int aspeed_espi_remove(struct platform_device *pdev) +{ -+ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev); ++ struct aspeed_espi *priv = dev_get_drvdata(&pdev->dev); + ++ misc_deregister(&priv->pltrstn_miscdev); + clk_disable_unprepare(priv->clk); + + return 0; +} + -+static const struct of_device_id of_espi_slave_match_table[] = { ++static const struct of_device_id of_espi_match_table[] = { + { .compatible = "aspeed,ast2500-espi-slave" }, + { } +}; -+MODULE_DEVICE_TABLE(of, of_espi_slave_match_table); ++MODULE_DEVICE_TABLE(of, of_espi_match_table); + -+static struct platform_driver aspeed_espi_slave_driver = { -+ .driver = { -+ .name = DEVICE_NAME, -+ .of_match_table = of_match_ptr(of_espi_slave_match_table), ++static struct platform_driver aspeed_espi_driver = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = of_match_ptr(of_espi_match_table), + }, -+ .probe = aspeed_espi_slave_probe, -+ .remove = aspeed_espi_slave_remove, ++ .probe = aspeed_espi_probe, ++ .remove = aspeed_espi_remove, +}; -+module_platform_driver(aspeed_espi_slave_driver); ++module_platform_driver(aspeed_espi_driver); + -+MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Haiyue Wang "); -+MODULE_DESCRIPTION("Linux device interface to the eSPI slave"); ++MODULE_AUTHOR("Jae Hyun Yoo "); ++MODULE_DESCRIPTION("Aspeed eSPI driver"); ++MODULE_LICENSE("GPL v2"); -- 2.7.4 diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch index 53060daf7..4dc14d3b1 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch @@ -1,24 +1,26 @@ -From 8d5f080b38d1b652eb5fdd3a7b74164906680ab7 Mon Sep 17 00:00:00 2001 +From 5f43a95bd032279440196a1c9802e1dec5d24a65 Mon Sep 17 00:00:00 2001 From: "Jason M. Bills" Date: Wed, 4 Apr 2018 13:52:39 -0700 Subject: [PATCH] Add support for new PECI commands Signed-off-by: Jason M. Bills Signed-off-by: Jae Hyun Yoo +Signed-off-by: Zhu, Yunge --- - drivers/peci/peci-core.c | 396 ++++++++++++++++++++++++++++++++++++++++ - include/uapi/linux/peci-ioctl.h | 146 +++++++++++++++ - 2 files changed, 542 insertions(+) + drivers/peci/peci-core.c | 430 ++++++++++++++++++++++++++++++++++++++++ + include/uapi/linux/peci-ioctl.h | 179 +++++++++++++++++ + 2 files changed, 609 insertions(+) diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c -index d1f0df8b139a..b99ba788a032 100644 +index 2a6be04..43a86a0 100644 --- a/drivers/peci/peci-core.c +++ b/drivers/peci/peci-core.c -@@ -318,6 +318,12 @@ static int peci_scan_cmd_mask(struct peci_adapter *adapter) +@@ -318,6 +318,13 @@ static int peci_scan_cmd_mask(struct peci_adapter *adapter) * See PECI Spec Table 3-1. */ revision = FIELD_GET(REVISION_NUM_MASK, dib); + if (revision >= 0x40) { /* Rev. 4.0 */ ++ adapter->cmd_mask |= BIT(PECI_CMD_RD_IA_MSREX); + adapter->cmd_mask |= BIT(PECI_CMD_RD_END_PT_CFG); + adapter->cmd_mask |= BIT(PECI_CMD_WR_END_PT_CFG); + adapter->cmd_mask |= BIT(PECI_CMD_CRASHDUMP_DISC); @@ -27,7 +29,61 @@ index d1f0df8b139a..b99ba788a032 100644 if (revision >= 0x36) /* Rev. 3.6 */ adapter->cmd_mask |= BIT(PECI_CMD_WR_IA_MSR); if (revision >= 0x35) /* Rev. 3.5 */ -@@ -687,6 +693,392 @@ static int peci_cmd_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) +@@ -375,14 +382,18 @@ static int peci_cmd_xfer(struct peci_adapter *adapter, void *vmsg) + switch (msg->tx_buf[0]) { + case PECI_RDPKGCFG_CMD: + case PECI_RDIAMSR_CMD: ++ case PECI_RDIAMSREX_CMD: + case PECI_RDPCICFG_CMD: + case PECI_RDPCICFGLOCAL_CMD: ++ case PECI_RDENDPTCFG_CMD: ++ case PECI_CRASHDUMP_CMD: + ret = peci_xfer_with_retries(adapter, msg, false); + break; + case PECI_WRPKGCFG_CMD: + case PECI_WRIAMSR_CMD: + case PECI_WRPCICFG_CMD: + case PECI_WRPCICFGLOCAL_CMD: ++ case PECI_WRENDPTCFG_CMD: + /* Check if the AW FCS byte is already provided */ + ret = peci_aw_fcs(msg, 2 + msg->tx_len, &aw_fcs); + if (ret) +@@ -590,6 +601,34 @@ static int peci_cmd_rd_ia_msr(struct peci_adapter *adapter, void *vmsg) + return ret; + } + ++static int peci_cmd_rd_ia_msrex(struct peci_adapter *adapter, void *vmsg) ++{ ++ struct peci_rd_ia_msrex_msg *umsg = vmsg; ++ struct peci_xfer_msg *msg; ++ int ret; ++ ++ msg = peci_get_xfer_msg(PECI_RDIAMSREX_WRITE_LEN, PECI_RDIAMSREX_READ_LEN); ++ if (!msg) ++ return -ENOMEM; ++ ++ msg->addr = umsg->addr; ++ msg->tx_buf[0] = PECI_RDIAMSREX_CMD; ++ msg->tx_buf[1] = 0; ++ msg->tx_buf[2] = (u8)umsg->thread_id; ++ msg->tx_buf[3] = (u8)(umsg->thread_id >> 8); ++ msg->tx_buf[4] = (u8)umsg->address; ++ msg->tx_buf[5] = (u8)(umsg->address >> 8); ++ ++ ret = peci_xfer_with_retries(adapter, msg, false); ++ if (!ret) ++ memcpy(&umsg->value, &msg->rx_buf[1], sizeof(uint64_t)); ++ ++ umsg->cc = msg->rx_buf[0]; ++ peci_put_xfer_msg(msg); ++ ++ return ret; ++} ++ + static int peci_cmd_wr_ia_msr(struct peci_adapter *adapter, void *vmsg) + { + return -ENOSYS; /* Not implemented yet */ +@@ -730,6 +769,392 @@ static int peci_cmd_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg) return ret; } @@ -420,7 +476,12 @@ index d1f0df8b139a..b99ba788a032 100644 typedef int (*peci_cmd_fn_type)(struct peci_adapter *, void *); static const peci_cmd_fn_type peci_cmd_fn[PECI_CMD_MAX] = { -@@ -702,6 +1094,10 @@ static const peci_cmd_fn_type peci_cmd_fn[PECI_CMD_MAX] = { +@@ -741,10 +1166,15 @@ static const peci_cmd_fn_type peci_cmd_fn[PECI_CMD_MAX] = { + peci_cmd_wr_pkg_cfg, + peci_cmd_rd_ia_msr, + peci_cmd_wr_ia_msr, ++ peci_cmd_rd_ia_msrex, + peci_cmd_rd_pci_cfg, peci_cmd_wr_pci_cfg, peci_cmd_rd_pci_cfg_local, peci_cmd_wr_pci_cfg_local, @@ -432,10 +493,23 @@ index d1f0df8b139a..b99ba788a032 100644 /** diff --git a/include/uapi/linux/peci-ioctl.h b/include/uapi/linux/peci-ioctl.h -index 253fb42e38b7..405cd8edbcbf 100644 +index 253fb42..1158254 100644 --- a/include/uapi/linux/peci-ioctl.h +++ b/include/uapi/linux/peci-ioctl.h -@@ -71,6 +71,10 @@ enum peci_cmd { +@@ -47,6 +47,7 @@ + * @PECI_CMD_WR_PKG_CFG: write access to the PCS (Package Configuration Space) + * @PECI_CMD_RD_IA_MSR: read access to MSRs (Model Specific Registers) + * @PECI_CMD_WR_IA_MSR: write access to MSRs (Model Specific Registers) ++ * @PECI_CMD_RD_IA_MSREX: read access to MSRs (Model Specific Registers) + * @PECI_CMD_RD_PCI_CFG: sideband read access to the PCI configuration space + * maintained in downstream devices external to the processor + * @PECI_CMD_WR_PCI_CFG: sideband write access to the PCI configuration space +@@ -67,10 +68,15 @@ enum peci_cmd { + PECI_CMD_WR_PKG_CFG, + PECI_CMD_RD_IA_MSR, + PECI_CMD_WR_IA_MSR, ++ PECI_CMD_RD_IA_MSREX, + PECI_CMD_RD_PCI_CFG, PECI_CMD_WR_PCI_CFG, PECI_CMD_RD_PCI_CFG_LOCAL, PECI_CMD_WR_PCI_CFG_LOCAL, @@ -446,7 +520,42 @@ index 253fb42e38b7..405cd8edbcbf 100644 PECI_CMD_MAX }; -@@ -438,6 +442,132 @@ struct peci_wr_pci_cfg_local_msg { +@@ -312,6 +318,34 @@ struct peci_wr_ia_msr_msg { + } __attribute__((__packed__)); + + /** ++ * struct peci_rd_ia_msrex_msg - RdIAMSREX command ++ * @addr: address of the client ++ * @thread_id: ID of the specific logical processor ++ * @address: address of MSR to read from ++ * @cc: completion code ++ * @value: data to be read ++ * ++ * The RdIAMSREX() PECI command provides read access to Model Specific Registers ++ * (MSRs) defined in the processor's Intel Architecture (IA). ++ * The differences between RdIAMSREX() and RdIAMSR() are that: ++ * (1)RdIAMSR() can only read MC registers, RdIAMSREX() can read all MSRs ++ * (2)thread_id of RdIAMSR() is u8, thread_id of RdIAMSREX() is u16 ++ */ ++struct peci_rd_ia_msrex_msg { ++#define PECI_RDIAMSREX_WRITE_LEN 6 ++#define PECI_RDIAMSREX_READ_LEN 9 ++#define PECI_RDIAMSREX_CMD 0xd1 ++ ++ __u8 addr; ++ __u8 padding0; ++ __u16 thread_id; ++ __u16 address; ++ __u8 cc; ++ __u8 padding1; ++ __u64 value; ++} __attribute__((__packed__)); ++ ++/** + * struct peci_rd_pci_cfg_msg - RdPCIConfig command + * @addr: address of the client + * @bus: PCI bus number +@@ -438,6 +472,132 @@ struct peci_wr_pci_cfg_local_msg { __u32 value; } __attribute__((__packed__)); @@ -579,7 +688,17 @@ index 253fb42e38b7..405cd8edbcbf 100644 #define PECI_IOC_BASE 0xb7 #define PECI_IOC_XFER \ -@@ -478,4 +608,20 @@ struct peci_wr_pci_cfg_local_msg { +@@ -464,6 +624,9 @@ struct peci_wr_pci_cfg_local_msg { + #define PECI_IOC_WR_IA_MSR \ + _IOWR(PECI_IOC_BASE, PECI_CMD_WR_IA_MSR, struct peci_wr_ia_msr_msg) + ++#define PECI_IOC_RD_IA_MSREX \ ++ _IOWR(PECI_IOC_BASE, PECI_CMD_RD_IA_MSREX, struct peci_rd_ia_msrex_msg) ++ + #define PECI_IOC_RD_PCI_CFG \ + _IOWR(PECI_IOC_BASE, PECI_CMD_RD_PCI_CFG, struct peci_rd_pci_cfg_msg) + +@@ -478,4 +641,20 @@ struct peci_wr_pci_cfg_local_msg { _IOWR(PECI_IOC_BASE, PECI_CMD_WR_PCI_CFG_LOCAL, \ struct peci_wr_pci_cfg_local_msg) diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0030-Add-dump-debug-code-into-I2C-drivers.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0030-Add-dump-debug-code-into-I2C-drivers.patch index d828233fe..bef1d0ae8 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0030-Add-dump-debug-code-into-I2C-drivers.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0030-Add-dump-debug-code-into-I2C-drivers.patch @@ -1,4 +1,4 @@ -From 38c04788647a95e3951674eb802f1f99ecdde164 Mon Sep 17 00:00:00 2001 +From 8b9bca54ec03fb80834eb8d15dd599293af6d971 Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Fri, 29 Jun 2018 11:00:02 -0700 Subject: [PATCH] Add dump debug code into I2C drivers @@ -20,7 +20,7 @@ Signed-off-by: Jae Hyun Yoo 2 files changed, 50 insertions(+) diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c -index fa66951b05d0..434b753def3b 100644 +index c2a6e5a27314..e1719b1f2020 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -163,6 +163,21 @@ struct aspeed_i2c_bus { @@ -65,7 +65,7 @@ index fa66951b05d0..434b753def3b 100644 return bus->master_xfer_result; } -@@ -1061,6 +1082,11 @@ static struct platform_driver aspeed_i2c_bus_driver = { +@@ -1065,6 +1086,11 @@ static struct platform_driver aspeed_i2c_bus_driver = { }; module_platform_driver(aspeed_i2c_bus_driver); diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0031-Add-high-speed-baud-rate-support-for-UART.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0031-Add-high-speed-baud-rate-support-for-UART.patch index 803701286..931483954 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0031-Add-high-speed-baud-rate-support-for-UART.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0031-Add-high-speed-baud-rate-support-for-UART.patch @@ -1,4 +1,4 @@ -From 01c8d6a5146cd39c2286f659e21f1a1042aa741a Mon Sep 17 00:00:00 2001 +From d80fcbb3e9d95a7e926598290012eea88a7c474d Mon Sep 17 00:00:00 2001 From: Yong Li Date: Wed, 2 Jan 2019 15:06:43 +0800 Subject: [PATCH] Add high speed baud rate support for UART @@ -14,29 +14,29 @@ bootloader(u-boot) will set SCU4C based on the environment configuration Signed-off-by: Yong Li --- - drivers/clk/clk-aspeed.c | 41 +++++++++++++++++++++++++++----- + drivers/clk/clk-aspeed.c | 44 +++++++++++++++++++++++++++----- include/dt-bindings/clock/aspeed-clock.h | 2 ++ - 2 files changed, 37 insertions(+), 6 deletions(-) + 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c -index 42b4df6ba249..97c27820db3e 100644 +index 9bd5155598d6..24d56a724969 100644 --- a/drivers/clk/clk-aspeed.c +++ b/drivers/clk/clk-aspeed.c @@ -14,7 +14,9 @@ - #include + #include "clk-aspeed.h" --#define ASPEED_NUM_CLKS 36 +-#define ASPEED_NUM_CLKS 38 +#define ASPEED_NUM_CLKS ASPEED_CLK_MAX -+#define UART_HIGH_SPEED_CLK 192000000 -+#define UART_LOW_SPEED_CLK 24000000 ++#define UART_HIGH_SPEED_CLK 192000000 ++#define UART_LOW_SPEED_CLK 24000000 #define ASPEED_RESET2_OFFSET 32 -@@ -28,6 +30,12 @@ - #define AST2400_HPLL_BYPASS_EN BIT(17) +@@ -29,6 +31,12 @@ #define ASPEED_MISC_CTRL 0x2c #define UART_DIV13_EN BIT(12) + #define ASPEED_MAC_CLK_DLY 0x48 +#define ASPEED_MISC2_CTRL 0x4c +#define UART1_HS_CLK_EN BIT(24) +#define UART2_HS_CLK_EN BIT(25) @@ -46,35 +46,38 @@ index 42b4df6ba249..97c27820db3e 100644 #define ASPEED_STRAP 0x70 #define CLKIN_25MHZ_EN BIT(23) #define AST2400_CLK_SOURCE_SEL BIT(18) -@@ -446,7 +454,7 @@ static int aspeed_clk_probe(struct platform_device *pdev) +@@ -386,7 +394,7 @@ static int aspeed_clk_probe(struct platform_device *pdev) struct aspeed_reset *ar; struct regmap *map; struct clk_hw *hw; - u32 val, rate; -+ u32 val, uart_clock_div; ++ u32 val, rate, rate_hi; int i, ret; map = syscon_node_to_regmap(dev->of_node); -@@ -481,15 +489,23 @@ static int aspeed_clk_probe(struct platform_device *pdev) +@@ -420,16 +428,25 @@ static int aspeed_clk_probe(struct platform_device *pdev) + /* UART clock div13 setting */ regmap_read(map, ASPEED_MISC_CTRL, &val); - if (val & UART_DIV13_EN) +- if (val & UART_DIV13_EN) - rate = 24000000 / 13; -+ uart_clock_div = 13; - else +- else - rate = 24000000; -+ uart_clock_div = 1; -+ ++ if (val & UART_DIV13_EN) { ++ rate = UART_LOW_SPEED_CLK / 13; ++ rate_hi = UART_HIGH_SPEED_CLK / 13; ++ } else { ++ rate = UART_LOW_SPEED_CLK; ++ rate_hi = UART_HIGH_SPEED_CLK; ++ } /* TODO: Find the parent data for the uart clock */ -- hw = clk_hw_register_fixed_rate(dev, "uart", NULL, 0, rate); -+ hw = clk_hw_register_fixed_rate(dev, "uart", NULL, 0, -+ UART_LOW_SPEED_CLK / uart_clock_div); + hw = clk_hw_register_fixed_rate(dev, "uart", NULL, 0, rate); if (IS_ERR(hw)) return PTR_ERR(hw); aspeed_clk_data->hws[ASPEED_CLK_UART] = hw; + hw = clk_hw_register_fixed_rate(dev, "uart-hs", "usb-port1-gate", 0, -+ UART_HIGH_SPEED_CLK / uart_clock_div); ++ rate_hi); + if (IS_ERR(hw)) + return PTR_ERR(hw); + aspeed_clk_data->hws[ASPEED_CLK_UART_HS] = hw; @@ -82,7 +85,7 @@ index 42b4df6ba249..97c27820db3e 100644 /* * Memory controller (M-PLL) PLL. This clock is configured by the * bootloader, and is exposed to Linux as a read-only clock rate. -@@ -570,9 +586,22 @@ static int aspeed_clk_probe(struct platform_device *pdev) +@@ -539,9 +556,22 @@ static int aspeed_clk_probe(struct platform_device *pdev) * UART[1..5] clock source mux */ @@ -105,7 +108,7 @@ index 42b4df6ba249..97c27820db3e 100644 /* Special case: the USB port 1 clock (bit 14) is always * working the opposite way from the other ones. -@@ -580,7 +609,7 @@ static int aspeed_clk_probe(struct platform_device *pdev) +@@ -549,7 +579,7 @@ static int aspeed_clk_probe(struct platform_device *pdev) gate_flags = (gd->clock_idx == 14) ? 0 : CLK_GATE_SET_TO_DISABLE; hw = aspeed_clk_hw_register_gate(dev, gd->name, @@ -115,15 +118,15 @@ index 42b4df6ba249..97c27820db3e 100644 map, gd->clock_idx, diff --git a/include/dt-bindings/clock/aspeed-clock.h b/include/dt-bindings/clock/aspeed-clock.h -index f43738607d77..335879505a72 100644 +index 64e245fb113f..df2f9fdfe5c1 100644 --- a/include/dt-bindings/clock/aspeed-clock.h +++ b/include/dt-bindings/clock/aspeed-clock.h -@@ -39,6 +39,8 @@ - #define ASPEED_CLK_BCLK 33 - #define ASPEED_CLK_MPLL 34 +@@ -41,6 +41,8 @@ #define ASPEED_CLK_24M 35 -+#define ASPEED_CLK_UART_HS 36 -+#define ASPEED_CLK_MAX 37 + #define ASPEED_CLK_GATE_MAC1RCLK 36 + #define ASPEED_CLK_GATE_MAC2RCLK 37 ++#define ASPEED_CLK_UART_HS 38 ++#define ASPEED_CLK_MAX 39 #define ASPEED_RESET_XDMA 0 #define ASPEED_RESET_MCTP 1 diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0032-misc-aspeed-Add-Aspeed-UART-routing-control-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0032-misc-aspeed-Add-Aspeed-UART-routing-control-driver.patch index 8c18e87ef..82e90c059 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0032-misc-aspeed-Add-Aspeed-UART-routing-control-driver.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0032-misc-aspeed-Add-Aspeed-UART-routing-control-driver.patch @@ -1,4 +1,4 @@ -From 0928704f3b593217662f980221406fcf6db39377 Mon Sep 17 00:00:00 2001 +From af686df07d23080834332b63fe37ee28b630ca2f Mon Sep 17 00:00:00 2001 From: Oskar Senft Date: Wed, 8 Aug 2018 10:15:05 -0400 Subject: [PATCH] misc: aspeed: Add Aspeed UART routing control driver. @@ -102,10 +102,10 @@ index 000000000000..afaf17cb7eda +$ cat /sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1 +io1 io2 io3 io4 uart2 [uart3] uart4 io6 diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts -index 4815104459f1..3094e90c9def 100644 +index 0aa2ac82cae4..403f29a74281 100644 --- a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts +++ b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts -@@ -233,6 +233,10 @@ +@@ -260,6 +260,10 @@ status = "okay"; }; @@ -117,10 +117,10 @@ index 4815104459f1..3094e90c9def 100644 status = "okay"; diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi -index 0e7f1d2fa08e..6e0b40eb939f 100644 +index 26671cc4dbd5..8288002e4f02 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi -@@ -493,6 +493,12 @@ +@@ -524,6 +524,12 @@ status = "disabled"; }; }; @@ -134,10 +134,10 @@ index 0e7f1d2fa08e..6e0b40eb939f 100644 peci: bus@1e78b000 { diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig -index b6acddaa9421..78e8fc892209 100644 +index 50814caba1d3..439f3b0de702 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig -@@ -481,6 +481,12 @@ config ASPEED_ESPI_SLAVE +@@ -463,6 +463,12 @@ config ASPEED_ESPI_SLAVE Control Aspeed ast2500 eSPI slave controller to handle event which needs the firmware's processing. @@ -151,10 +151,10 @@ index b6acddaa9421..78e8fc892209 100644 depends on PCI select CRC32 diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile -index f91f66a15484..7337b8bcd0a3 100644 +index f168e6713440..87958cb74d00 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile -@@ -55,6 +55,7 @@ obj-$(CONFIG_ECHO) += echo/ +@@ -54,6 +54,7 @@ obj-$(CONFIG_ECHO) += echo/ obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o obj-$(CONFIG_CXL_BASE) += cxl/ obj-$(CONFIG_ASPEED_ESPI_SLAVE) += aspeed-espi-slave.o diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0034-arm-dts-aspeed-Swap-the-mac-nodes-numbering.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0034-arm-dts-aspeed-Swap-the-mac-nodes-numbering.patch index 7f556de64..08f406ac1 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0034-arm-dts-aspeed-Swap-the-mac-nodes-numbering.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0034-arm-dts-aspeed-Swap-the-mac-nodes-numbering.patch @@ -1,4 +1,4 @@ -From fcea191a6e0eb869c62b5d1ea8a6e914a540fcfb Mon Sep 17 00:00:00 2001 +From 89112c3971a540302834e5e987a1dec236bd752d Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Wed, 3 Oct 2018 10:17:58 -0700 Subject: [PATCH] arm: dts: aspeed: Swap the mac nodes numbering @@ -13,10 +13,10 @@ Signed-off-by: Jae Hyun Yoo 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi -index 3df43f925848..618abeab539b 100644 +index 71563972d2fe..78251541a109 100644 --- a/arch/arm/boot/dts/aspeed-g4.dtsi +++ b/arch/arm/boot/dts/aspeed-g4.dtsi -@@ -101,14 +101,6 @@ +@@ -121,14 +121,6 @@ reg = <0x1e6c2000 0x80>; }; @@ -31,7 +31,7 @@ index 3df43f925848..618abeab539b 100644 mac1: ethernet@1e680000 { compatible = "aspeed,ast2400-mac", "faraday,ftgmac100"; reg = <0x1e680000 0x180>; -@@ -117,6 +109,14 @@ +@@ -137,6 +129,14 @@ status = "disabled"; }; @@ -47,7 +47,7 @@ index 3df43f925848..618abeab539b 100644 compatible = "aspeed,ast2400-ehci", "generic-ehci"; reg = <0x1e6a1000 0x100>; diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi -index 6e0b40eb939f..b8c85fad2a39 100644 +index 8288002e4f02..6d2c4494ce04 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi @@ -149,14 +149,6 @@ diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch index c115d23d0..6d8ec4883 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch @@ -1,4 +1,4 @@ -From 7ac4709dd92c608ca4c8ff0046a434c8f465a80c Mon Sep 17 00:00:00 2001 +From e2df269568c6c0c8c8edbca73118c2dbdaea75bd Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Mon, 11 Feb 2019 17:02:35 -0800 Subject: [PATCH] Add Aspeed PWM driver which uses FTTMR010 timer IP @@ -18,10 +18,10 @@ Signed-off-by: Jae Hyun Yoo create mode 100644 drivers/pwm/pwm-fttmr010.c diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi -index b8c85fad2a39..88ac8e08b6ae 100644 +index 6d2c4494ce04..653e03a0fa4c 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi -@@ -312,7 +312,7 @@ +@@ -342,7 +342,7 @@ timer: timer@1e782000 { /* This timer is a Faraday FTTMR010 derivative */ @@ -31,7 +31,7 @@ index b8c85fad2a39..88ac8e08b6ae 100644 interrupts = <16 17 18 35 36 37 38 39>; clocks = <&syscon ASPEED_CLK_APB>; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig -index dff5a93f7daa..5759439a3947 100644 +index a7e57516959e..3388f837fcf9 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -171,6 +171,15 @@ config PWM_FSL_FTM @@ -51,7 +51,7 @@ index dff5a93f7daa..5759439a3947 100644 tristate "HiSilicon BVT PWM support" depends on ARCH_HISI || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile -index c368599d36c0..937d212bb02a 100644 +index 76b555b51887..19ecfd82d8c5 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_PWM_CRC) += pwm-crc.o diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch index b2057d247..ce77494f4 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch @@ -1,4 +1,4 @@ -From ed13e7eb07e6cb8bdc1eb4563de30b469a9beb26 Mon Sep 17 00:00:00 2001 +From be693c1c21979c067623434aa653f85a83c8eac7 Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Fri, 15 Feb 2019 16:05:09 -0800 Subject: [PATCH] i2c: Add mux hold/unhold msg types @@ -48,7 +48,7 @@ Signed-off-by: Jae Hyun Yoo 6 files changed, 214 insertions(+), 16 deletions(-) diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c -index 9e43508d4567..8a480d269542 100644 +index 9c440fa6a3dd..53ff27cae5d3 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -1299,6 +1299,25 @@ int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr) @@ -100,7 +100,7 @@ index 9e43508d4567..8a480d269542 100644 */ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { -+ enum i2c_hold_msg_type hold_msg; ++ enum i2c_hold_msg_type hold_msg = I2C_HOLD_MSG_NONE; unsigned long orig_jiffies; + unsigned long timeout; int ret, try; @@ -219,18 +219,18 @@ index 3ac426a8ab5a..f7bf95101e34 100644 return res; } diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c -index 603252fa1284..d3f55243e701 100644 +index 774507b54b57..c6e433238b22 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c -@@ -26,6 +26,7 @@ - #include +@@ -27,6 +27,7 @@ #include #include + #include +#include /* multiplexer per channel data */ struct i2c_mux_priv { -@@ -35,21 +36,57 @@ struct i2c_mux_priv { +@@ -36,21 +37,57 @@ struct i2c_mux_priv { u32 chan_id; }; @@ -290,7 +290,7 @@ index 603252fa1284..d3f55243e701 100644 return ret; } -@@ -60,15 +97,32 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap, +@@ -61,15 +98,32 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap, struct i2c_mux_priv *priv = adap->algo_data; struct i2c_mux_core *muxc = priv->muxc; struct i2c_adapter *parent = muxc->parent; @@ -325,7 +325,7 @@ index 603252fa1284..d3f55243e701 100644 return ret; } -@@ -81,16 +135,33 @@ static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap, +@@ -82,16 +136,33 @@ static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap, struct i2c_mux_priv *priv = adap->algo_data; struct i2c_mux_core *muxc = priv->muxc; struct i2c_adapter *parent = muxc->parent; @@ -361,7 +361,7 @@ index 603252fa1284..d3f55243e701 100644 return ret; } -@@ -103,16 +174,33 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap, +@@ -104,16 +175,33 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap, struct i2c_mux_priv *priv = adap->algo_data; struct i2c_mux_core *muxc = priv->muxc; struct i2c_adapter *parent = muxc->parent; @@ -431,10 +431,10 @@ index c5a977320f82..47f8763d6ed2 100644 int max_adapters; struct i2c_adapter *adapter[0]; diff --git a/include/linux/i2c.h b/include/linux/i2c.h -index 1308126fc384..3ee92c6a442d 100644 +index fa5552c2307b..92c795ce9081 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h -@@ -699,6 +699,13 @@ struct i2c_adapter { +@@ -711,6 +711,13 @@ struct i2c_adapter { const struct i2c_adapter_quirks *quirks; struct irq_domain *host_notify_domain; @@ -448,7 +448,7 @@ index 1308126fc384..3ee92c6a442d 100644 }; #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev) -@@ -998,4 +1005,22 @@ static inline struct i2c_client *i2c_acpi_new_device(struct device *dev, +@@ -1005,4 +1012,22 @@ static inline struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle ha } #endif /* CONFIG_ACPI */ diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch index 25f494652..0a9bccf23 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch @@ -1,4 +1,4 @@ -From c55d6bb49cfbd39a7c0848076c84166def65936e Mon Sep 17 00:00:00 2001 +From 04af6987c904225fdd4657e7b87874edd11c4e0b Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Thu, 7 Mar 2019 15:17:40 -0800 Subject: [PATCH] Add bus-timeout-ms and #retries device tree properties @@ -59,10 +59,10 @@ index 44efafdfd7f5..e382931cf3d6 100644 used by the device. I2C core will assign "irq" interrupt (or the very first interrupt if not using interrupt names) as primary interrupt for the slave. diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c -index 434b753def3b..99bd30953531 100644 +index e1719b1f2020..58bdbe472721 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c -@@ -1014,7 +1014,6 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) +@@ -1018,7 +1018,6 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) spin_lock_init(&bus->lock); init_completion(&bus->cmd_complete); bus->adap.owner = THIS_MODULE; @@ -71,7 +71,7 @@ index 434b753def3b..99bd30953531 100644 bus->adap.dev.parent = &pdev->dev; bus->adap.dev.of_node = pdev->dev.of_node; diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c -index 8a480d269542..69b798a2d31e 100644 +index 302d2d0c87d0..825e2d85d5a7 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -1320,6 +1320,7 @@ static void i2c_adapter_hold_timer_callback(struct timer_list *t) diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch index 035945cf3..139d06df0 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch @@ -1,4 +1,4 @@ -From c4e7b89ee20dc28e10fae7eb0859e4fa9d3e8643 Mon Sep 17 00:00:00 2001 +From 4d90c5ba05ee3e8a4bf5e4c1a5fdcf2664b1800b Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Wed, 13 Mar 2019 15:04:16 -0700 Subject: [PATCH] char: ipmi: Add clock control logic into Aspeed LPC BT driver @@ -42,10 +42,10 @@ index 028268fd99ee..d13887d60f19 100644 + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; }; diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi -index 618abeab539b..c2388bb7c678 100644 +index 78251541a109..b3b6720fb6fb 100644 --- a/arch/arm/boot/dts/aspeed-g4.dtsi +++ b/arch/arm/boot/dts/aspeed-g4.dtsi -@@ -337,6 +337,7 @@ +@@ -387,6 +387,7 @@ ibt: ibt@c0 { compatible = "aspeed,ast2400-ibt-bmc"; reg = <0xc0 0x18>; @@ -54,10 +54,10 @@ index 618abeab539b..c2388bb7c678 100644 status = "disabled"; }; diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi -index 88ac8e08b6ae..88b318fd287b 100644 +index 653e03a0fa4c..49f792eafdd1 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi -@@ -470,6 +470,7 @@ +@@ -500,6 +500,7 @@ ibt: ibt@c0 { compatible = "aspeed,ast2500-ibt-bmc"; reg = <0xc0 0x18>; diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch index c335fb3ec..cd20e77ac 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch @@ -1,4 +1,4 @@ -From a5bbf0f5943d3a6be6e58a4b78d6d18694ceb859 Mon Sep 17 00:00:00 2001 +From f2e7fb51e4832a0da2fdb8fb267471b54581312b Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Wed, 13 Mar 2019 15:27:48 -0700 Subject: [PATCH] misc: Add clock control logic into Aspeed LPC SNOOP driver @@ -22,10 +22,10 @@ Signed-off-by: Jae Hyun Yoo 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi -index c2388bb7c678..70aca75d65e0 100644 +index b3b6720fb6fb..58c5148194a3 100644 --- a/arch/arm/boot/dts/aspeed-g4.dtsi +++ b/arch/arm/boot/dts/aspeed-g4.dtsi -@@ -320,6 +320,7 @@ +@@ -370,6 +370,7 @@ compatible = "aspeed,ast2400-lpc-snoop"; reg = <0x0 0x80>; interrupts = <8>; @@ -34,10 +34,10 @@ index c2388bb7c678..70aca75d65e0 100644 }; diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi -index 88b318fd287b..f4a5d06f1000 100644 +index 49f792eafdd1..955789d8c736 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi -@@ -453,6 +453,7 @@ +@@ -483,6 +483,7 @@ compatible = "aspeed,ast2500-lpc-snoop"; reg = <0x0 0x80>; interrupts = <8>; diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch index 499662ac3..cfff0a842 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch @@ -1,4 +1,4 @@ -From 27675470115548612cee9153903aaffffb68177b Mon Sep 17 00:00:00 2001 +From 9a6eafbba9f5d972065f65431093ec74968cae39 Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Wed, 13 Mar 2019 15:36:34 -0700 Subject: [PATCH] char: ipmi: Add clock control logic into Aspeed LPC KCS @@ -45,10 +45,10 @@ index d98a9bf45d6c..3453eb0bf8f2 100644 kcs_addr = <0xCA2>; status = "okay"; diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi -index 1c00828da913..f04006f4cd27 100644 +index 58c5148194a3..14e5dc260a3b 100644 --- a/arch/arm/boot/dts/aspeed-g4.dtsi +++ b/arch/arm/boot/dts/aspeed-g4.dtsi -@@ -298,6 +298,33 @@ +@@ -348,6 +348,33 @@ lpc_bmc: lpc-bmc@0 { compatible = "aspeed,ast2400-lpc-bmc"; reg = <0x0 0x80>; @@ -82,7 +82,7 @@ index 1c00828da913..f04006f4cd27 100644 }; lpc_host: lpc-host@80 { -@@ -309,6 +336,14 @@ +@@ -359,6 +386,14 @@ #size-cells = <1>; ranges = <0x0 0x80 0x1e0>; @@ -98,7 +98,7 @@ index 1c00828da913..f04006f4cd27 100644 compatible = "aspeed,ast2400-lpc-ctrl"; reg = <0x0 0x80>; diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi -index f2292bdfef91..d46b9ffc79de 100644 +index 955789d8c736..19739183c1c8 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi @@ -135,7 +135,7 @@ @@ -110,7 +110,7 @@ index f2292bdfef91..d46b9ffc79de 100644 interrupt-controller; #interrupt-cells = <1>; valid-sources = <0xfefff7ff 0x0807ffff>; -@@ -410,18 +410,21 @@ +@@ -440,18 +440,21 @@ compatible = "aspeed,ast2500-kcs-bmc"; interrupts = <8>; kcs_chan = <1>; @@ -132,7 +132,7 @@ index f2292bdfef91..d46b9ffc79de 100644 status = "disabled"; }; }; -@@ -439,6 +442,7 @@ +@@ -469,6 +472,7 @@ compatible = "aspeed,ast2500-kcs-bmc"; interrupts = <8>; kcs_chan = <4>; diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0049-Suppress-excessive-HID-gadget-error-logs.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0049-Suppress-excessive-HID-gadget-error-logs.patch index d0f98b9c1..4a87f2d76 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0049-Suppress-excessive-HID-gadget-error-logs.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0049-Suppress-excessive-HID-gadget-error-logs.patch @@ -1,4 +1,4 @@ -From 7dd0a7c62e5885bb726ef2bd5007e79a50932c38 Mon Sep 17 00:00:00 2001 +From 5b9ec5081492b461710cb82e7ecc93fd3af8ad34 Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Mon, 18 Mar 2019 14:06:36 -0700 Subject: [PATCH] Suppress excessive HID gadget error logs @@ -18,13 +18,22 @@ This should be a downstream only customization. Do not upstream it. Signed-off-by: Jae Hyun Yoo --- - drivers/usb/gadget/function/f_hid.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) + drivers/usb/gadget/function/f_hid.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c -index f3816a5c861e..3a94584a9dbc 100644 +index f3816a5c861e..c96c0f6f1df0 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c +@@ -320,7 +320,7 @@ static void f_hidg_req_complete(struct usb_ep *ep, struct usb_request *req) + struct f_hidg *hidg = (struct f_hidg *)ep->driver_data; + unsigned long flags; + +- if (req->status != 0) { ++ if (req->status != 0 && req->status != -ESHUTDOWN) { + ERROR(hidg->func.config->cdev, + "End Point Request ERROR: %d\n", req->status); + } @@ -395,8 +395,10 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, status = usb_ep_queue(hidg->in_ep, req, GFP_ATOMIC); diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0051-Add-AST2500-JTAG-device.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0051-Add-AST2500-JTAG-device.patch index d9379f565..02bb6527f 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0051-Add-AST2500-JTAG-device.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0051-Add-AST2500-JTAG-device.patch @@ -1,4 +1,4 @@ -From 278740d23c1eac792c64608af4bfa3fae640965f Mon Sep 17 00:00:00 2001 +From ce35414258a8541a8b81a4a8a929bcf9cdface97 Mon Sep 17 00:00:00 2001 From: "Hunt, Bryan" Date: Mon, 6 May 2019 10:02:14 -0700 Subject: [PATCH] Add AST2500d JTAG driver @@ -11,10 +11,10 @@ Signed-off-by: Hunt, Bryan 1 file changed, 9 insertions(+) diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi -index ed0b7217f55f..89a9febf6f14 100644 +index 19739183c1c8..3d615708a0cd 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi -@@ -389,6 +389,15 @@ +@@ -419,6 +419,15 @@ pinctrl-0 = <&pinctrl_espi_default>; }; diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0052-drivers-jtag-Add-JTAG-core-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0052-drivers-jtag-Add-JTAG-core-driver.patch index 3047746ca..4162046e7 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0052-drivers-jtag-Add-JTAG-core-driver.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0052-drivers-jtag-Add-JTAG-core-driver.patch @@ -1,4 +1,4 @@ -From 520416545a47cffe66815f31bc1465eab8864554 Mon Sep 17 00:00:00 2001 +From 45dd8ca9bb83b688aa0d0b5472fd0b1ed9fcf29a Mon Sep 17 00:00:00 2001 From: "Corona, Ernesto" Date: Fri, 7 Jun 2019 07:37:39 -0800 Subject: [PATCH v29 1/6] drivers: jtag: Add JTAG core driver @@ -267,20 +267,20 @@ Comments pointed by Tobias Klauser create mode 100644 include/uapi/linux/jtag.h diff --git a/drivers/Kconfig b/drivers/Kconfig -index 339ac306ded6..fb970bbe6b03 100644 +index 92f4a9bb83f1..7403af7ffa85 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig -@@ -234,4 +234,5 @@ source "drivers/counter/Kconfig" +@@ -232,4 +232,5 @@ source "drivers/counter/Kconfig" source "drivers/peci/Kconfig" +source "drivers/jtag/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile -index 18d91cd5ac0f..b4d21c963923 100644 +index 47cad1b9f992..cd240910c56e 100644 --- a/drivers/Makefile +++ b/drivers/Makefile -@@ -189,3 +189,4 @@ obj-$(CONFIG_GNSS) += gnss/ +@@ -188,3 +188,4 @@ obj-$(CONFIG_GNSS) += gnss/ obj-$(CONFIG_INTERCONNECT) += interconnect/ obj-$(CONFIG_COUNTER) += counter/ obj-$(CONFIG_PECI) += peci/ diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch index a7dccc4b6..3efe2c5f3 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch @@ -1,7 +1,7 @@ -From ba0c35ae070cffcb384fc76e23a38e00142b128d Mon Sep 17 00:00:00 2001 +From d5efb0ec2b28bc1074472ab4eaa937dcbe490f6a Mon Sep 17 00:00:00 2001 From: "Corona, Ernesto" -Date: Wed, 10 Mar 2019 11:48:18 -0800 -Subject: [PATCH v29 5/6] Documentation jtag: Add JTAG core driver ioctl number +Date: Sun, 10 Mar 2019 11:48:18 -0800 +Subject: [PATCH] Documentation jtag: Add JTAG core driver ioctl number JTAG class driver provide infrastructure to support hardware/software JTAG platform drivers. It provide user layer API interface for flashing @@ -36,22 +36,22 @@ Cc: Arnd Bergmann Cc: Steven A Filary Cc: Bryan Hunt --- - Documentation/ioctl/ioctl-number.txt | 2 ++ + Documentation/ioctl/ioctl-number.rst | 2 ++ 1 file changed, 2 insertions(+) -diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt -index c955814..f732118 100644 ---- a/Documentation/ioctl/ioctl-number.txt -+++ b/Documentation/ioctl/ioctl-number.txt -@@ -323,6 +323,8 @@ Code Seq#(hex) Include File Comments - 0xB0 all RATIO devices in development: - - 0xB1 00-1F PPPoX -+0xB2 00-0F linux/jtag.h JTAG driver -+ - 0xB3 00 linux/mmc/ioctl.h - 0xB4 00-0F linux/gpio.h - 0xB5 00-0F uapi/linux/rpmsg.h +diff --git a/Documentation/ioctl/ioctl-number.rst b/Documentation/ioctl/ioctl-number.rst +index 7f8dcae7a230..4d25966d44e5 100644 +--- a/Documentation/ioctl/ioctl-number.rst ++++ b/Documentation/ioctl/ioctl-number.rst +@@ -332,6 +332,8 @@ Code Seq# Include File Comments + + 0xB1 00-1F PPPoX + ++0xB2 00-0F linux/jtag.h JTAG driver ++ + 0xB3 00 linux/mmc/ioctl.h + 0xB4 00-0F linux/gpio.h + 0xB5 00-0F uapi/linux/rpmsg.h -- 2.7.4 diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch index 47a532590..b5f5a93a0 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch @@ -1,4 +1,4 @@ -From 8598b57423967f5851484533a1b09a04bafa235b Mon Sep 17 00:00:00 2001 +From 01fc94b1193f4e97d498e2bcb05dfe21b991b01d Mon Sep 17 00:00:00 2001 From: "Corona, Ernesto" Date: Sun, 10 Mar 2019 11:49:37 -0800 Subject: [PATCH v29 6/6] drivers: jtag: Add JTAG core driver Maintainers @@ -24,10 +24,10 @@ Cc: Bryan Hunt 1 file changed, 11 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS -index e0925f221e25..2cd0a46f9a1a 100644 +index f5c5eaa69f2f..92b0932c4b9f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -8521,6 +8521,17 @@ L: linux-serial@vger.kernel.org +@@ -8709,6 +8709,17 @@ L: linux-serial@vger.kernel.org S: Orphan F: drivers/tty/serial/jsm/ diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0058-i2c-aspeed-add-general-call-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0058-i2c-aspeed-add-general-call-support.patch deleted file mode 100644 index 7d5e006d1..000000000 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0058-i2c-aspeed-add-general-call-support.patch +++ /dev/null @@ -1,180 +0,0 @@ -From f5b6d42c1710a4c1314bc0160f904aa01f501e96 Mon Sep 17 00:00:00 2001 -From: Jae Hyun Yoo -Date: Wed, 1 May 2019 13:27:34 -0700 -Subject: [PATCH] i2c: aspeed: add general call support - -This commit adds general call support into Aspeed I2C driver. -This is downstream only customization so it should not go into -upstream. - -Signed-off-by: Jae Hyun Yoo ---- - .../devicetree/bindings/i2c/i2c-aspeed.txt | 1 + - drivers/i2c/busses/i2c-aspeed.c | 39 ++++++++++++++++++++++ - drivers/i2c/i2c-slave-mqueue.c | 4 ++- - include/linux/i2c.h | 1 + - 4 files changed, 44 insertions(+), 1 deletion(-) - -diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt -index 7da7e813b2b0..724ee9f35c10 100644 ---- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt -+++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt -@@ -16,6 +16,7 @@ Optional Properties: - - bus-frequency : frequency of the bus clock in Hz defaults to 100 kHz when not - specified - - multi-master : states that there is another master active on this bus. -+- general-call : enables general call receiving. - - bus-timeout-ms: bus timeout in milliseconds defaults to 1 second when not - specified. - - #retries : Number of retries for master transfer. -diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c -index 99bd30953531..8f26060bd685 100644 ---- a/drivers/i2c/busses/i2c-aspeed.c -+++ b/drivers/i2c/busses/i2c-aspeed.c -@@ -47,6 +47,7 @@ - #define ASPEED_I2CD_SDA_DRIVE_1T_EN BIT(8) - #define ASPEED_I2CD_M_SDA_DRIVE_1T_EN BIT(7) - #define ASPEED_I2CD_M_HIGH_SPEED_EN BIT(6) -+#define ASPEED_I2CD_GCALL_EN BIT(2) - #define ASPEED_I2CD_SLAVE_EN BIT(1) - #define ASPEED_I2CD_MASTER_EN BIT(0) - -@@ -71,6 +72,7 @@ - */ - #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14) - #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13) -+#define ASPEED_I2CD_INTR_GCALL_ADDR BIT(8) - #define ASPEED_I2CD_INTR_SLAVE_MATCH BIT(7) - #define ASPEED_I2CD_INTR_SCL_TIMEOUT BIT(6) - #define ASPEED_I2CD_INTR_ABNORMAL BIT(5) -@@ -130,6 +132,8 @@ enum aspeed_i2c_slave_state { - ASPEED_I2C_SLAVE_READ_PROCESSED, - ASPEED_I2C_SLAVE_WRITE_REQUESTED, - ASPEED_I2C_SLAVE_WRITE_RECEIVED, -+ ASPEED_I2C_SLAVE_GCALL_START, -+ ASPEED_I2C_SLAVE_GCALL_REQUESTED, - ASPEED_I2C_SLAVE_STOP, - }; - -@@ -160,6 +164,8 @@ struct aspeed_i2c_bus { - #if IS_ENABLED(CONFIG_I2C_SLAVE) - struct i2c_client *slave; - enum aspeed_i2c_slave_state slave_state; -+ /* General call */ -+ bool general_call; - #endif /* CONFIG_I2C_SLAVE */ - }; - -@@ -266,6 +272,12 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - bus->slave_state = ASPEED_I2C_SLAVE_START; - } - -+ /* General call was requested, restart state machine. */ -+ if (irq_status & ASPEED_I2CD_INTR_GCALL_ADDR) { -+ irq_handled |= ASPEED_I2CD_INTR_GCALL_ADDR; -+ bus->slave_state = ASPEED_I2C_SLAVE_GCALL_START; -+ } -+ - /* Slave is not currently active, irq was for someone else. */ - if (bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE) - return irq_handled; -@@ -284,6 +296,21 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - else - bus->slave_state = - ASPEED_I2C_SLAVE_WRITE_REQUESTED; -+ } else if (bus->slave_state == ASPEED_I2C_SLAVE_GCALL_START) { -+ /* -+ * I2C spec defines the second byte meaning like below. -+ * 0x06 : Reset and write programmable part of slave -+ * address by hardware. -+ * 0x04 : Write programmable part of slave address by -+ * hardware. -+ * 0x00 : No allowed. -+ * -+ * But in OpenBMC, we are going to use this -+ * 'General call' feature for IPMB message broadcasting -+ * so it delivers all data as is without any specific -+ * handling of the second byte. -+ */ -+ bus->slave_state = ASPEED_I2C_SLAVE_GCALL_REQUESTED; - } - irq_handled |= ASPEED_I2CD_INTR_RX_DONE; - } -@@ -326,11 +353,16 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - case ASPEED_I2C_SLAVE_WRITE_RECEIVED: - i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value); - break; -+ case ASPEED_I2C_SLAVE_GCALL_REQUESTED: -+ bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED; -+ i2c_slave_event(slave, I2C_SLAVE_GCALL_REQUESTED, &value); -+ break; - case ASPEED_I2C_SLAVE_STOP: - i2c_slave_event(slave, I2C_SLAVE_STOP, &value); - bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE; - break; - case ASPEED_I2C_SLAVE_START: -+ case ASPEED_I2C_SLAVE_GCALL_START: - /* Slave was just started. Waiting for the next event. */; - break; - default: -@@ -738,6 +770,8 @@ static void __aspeed_i2c_reg_slave(struct aspeed_i2c_bus *bus, u16 slave_addr) - /* Turn on slave mode. */ - func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG); - func_ctrl_reg_val |= ASPEED_I2CD_SLAVE_EN; -+ if (bus->general_call) -+ func_ctrl_reg_val |= ASPEED_I2CD_GCALL_EN; - writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG); - } - -@@ -776,6 +810,8 @@ static int aspeed_i2c_unreg_slave(struct i2c_client *client) - /* Turn off slave mode. */ - func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG); - func_ctrl_reg_val &= ~ASPEED_I2CD_SLAVE_EN; -+ if (bus->general_call) -+ func_ctrl_reg_val &= ~ASPEED_I2CD_GCALL_EN; - writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG); - - bus->slave = NULL; -@@ -920,6 +956,9 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus, - bus->base + ASPEED_I2C_FUN_CTRL_REG); - - #if IS_ENABLED(CONFIG_I2C_SLAVE) -+ if (of_property_read_bool(pdev->dev.of_node, "general-call")) -+ bus->general_call = true; -+ - /* If slave has already been registered, re-enable it. */ - if (bus->slave) - __aspeed_i2c_reg_slave(bus, bus->slave->addr); -diff --git a/drivers/i2c/i2c-slave-mqueue.c b/drivers/i2c/i2c-slave-mqueue.c -index 2c7a6038409c..1d4db584b393 100644 ---- a/drivers/i2c/i2c-slave-mqueue.c -+++ b/drivers/i2c/i2c-slave-mqueue.c -@@ -56,10 +56,12 @@ static int i2c_slave_mqueue_callback(struct i2c_client *client, - - switch (event) { - case I2C_SLAVE_WRITE_REQUESTED: -+ case I2C_SLAVE_GCALL_REQUESTED: - mq->truncated = 0; - - msg->len = 1; -- msg->buf[0] = client->addr << 1; -+ msg->buf[0] = event == I2C_SLAVE_GCALL_REQUESTED ? -+ 0 : client->addr << 1; - break; - - case I2C_SLAVE_WRITE_RECEIVED: -diff --git a/include/linux/i2c.h b/include/linux/i2c.h -index 3ee92c6a442d..dfdccb2acb24 100644 ---- a/include/linux/i2c.h -+++ b/include/linux/i2c.h -@@ -359,6 +359,7 @@ enum i2c_slave_event { - I2C_SLAVE_WRITE_REQUESTED, - I2C_SLAVE_READ_PROCESSED, - I2C_SLAVE_WRITE_RECEIVED, -+ I2C_SLAVE_GCALL_REQUESTED, - I2C_SLAVE_STOP, - }; - --- -2.7.4 - diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0060-i2c-aspeed-fix-master-pending-state-handling.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0060-i2c-aspeed-fix-master-pending-state-handling.patch new file mode 100644 index 000000000..d38c089af --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0060-i2c-aspeed-fix-master-pending-state-handling.patch @@ -0,0 +1,135 @@ +From ca5e5e784ada4da11caebf6ba6852e1ff8a13bf7 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo +Date: Tue, 11 Jun 2019 14:59:53 -0700 +Subject: [PATCH] i2c: aspeed: fix master pending state handling + +In case of master pending state, it should not trigger a master +command, otherwise data could be corrupted because this H/W shares +the same data buffer for slave and master operations. It also means +that H/W command queue handling is unreliable because of the buffer +sharing issue. To fix this issue, it clears command queue if a +master command is queued in pending state to use S/W solution +instead of H/W command queue handling. Also, it refines restarting +mechanism of the pending master command. + +Fixes: 2e57b7cebb98 ("i2c: aspeed: Add multi-master use case support") + +Signed-off-by: Jae Hyun Yoo +--- + drivers/i2c/busses/i2c-aspeed.c | 54 ++++++++++++++++++++++++++--------------- + 1 file changed, 34 insertions(+), 20 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index 58bdbe472721..7becfcd67142 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -108,6 +108,12 @@ + #define ASPEED_I2CD_S_TX_CMD BIT(2) + #define ASPEED_I2CD_M_TX_CMD BIT(1) + #define ASPEED_I2CD_M_START_CMD BIT(0) ++#define ASPEED_I2CD_MASTER_CMDS_MASK \ ++ (ASPEED_I2CD_M_STOP_CMD | \ ++ ASPEED_I2CD_M_S_RX_CMD_LAST | \ ++ ASPEED_I2CD_M_RX_CMD | \ ++ ASPEED_I2CD_M_TX_CMD | \ ++ ASPEED_I2CD_M_START_CMD) + + /* 0x18 : I2CD Slave Device Address Register */ + #define ASPEED_I2CD_DEV_ADDR_MASK GENMASK(6, 0) +@@ -351,18 +357,19 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) + struct i2c_msg *msg = &bus->msgs[bus->msgs_index]; + u8 slave_addr = i2c_8bit_addr_from_msg(msg); + +- bus->master_state = ASPEED_I2C_MASTER_START; +- + #if IS_ENABLED(CONFIG_I2C_SLAVE) + /* + * If it's requested in the middle of a slave session, set the master + * state to 'pending' then H/W will continue handling this master + * command when the bus comes back to the idle state. + */ +- if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE) ++ if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE) { + bus->master_state = ASPEED_I2C_MASTER_PENDING; ++ return; ++ } + #endif /* CONFIG_I2C_SLAVE */ + ++ bus->master_state = ASPEED_I2C_MASTER_START; + bus->buf_index = 0; + + if (msg->flags & I2C_M_RD) { +@@ -437,20 +444,6 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + } + } + +-#if IS_ENABLED(CONFIG_I2C_SLAVE) +- /* +- * A pending master command will be started by H/W when the bus comes +- * back to idle state after completing a slave operation so change the +- * master state from 'pending' to 'start' at here if slave is inactive. +- */ +- if (bus->master_state == ASPEED_I2C_MASTER_PENDING) { +- if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE) +- goto out_no_complete; +- +- bus->master_state = ASPEED_I2C_MASTER_START; +- } +-#endif /* CONFIG_I2C_SLAVE */ +- + /* Master is not currently active, irq was for someone else. */ + if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE || + bus->master_state == ASPEED_I2C_MASTER_PENDING) +@@ -477,11 +470,15 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + #if IS_ENABLED(CONFIG_I2C_SLAVE) + /* + * If a peer master starts a xfer immediately after it queues a +- * master command, change its state to 'pending' then H/W will +- * continue the queued master xfer just after completing the +- * slave mode session. ++ * master command, clear the queued master command and change ++ * its state to 'pending'. To simplify handling of pending ++ * cases, it uses S/W solution instead of H/W command queue ++ * handling. + */ + if (unlikely(irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH)) { ++ writel(readl(bus->base + ASPEED_I2C_CMD_REG) & ++ ~ASPEED_I2CD_MASTER_CMDS_MASK, ++ bus->base + ASPEED_I2C_CMD_REG); + bus->master_state = ASPEED_I2C_MASTER_PENDING; + dev_dbg(bus->dev, + "master goes pending due to a slave start\n"); +@@ -644,6 +641,14 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id) + irq_handled |= aspeed_i2c_master_irq(bus, + irq_remaining); + } ++ ++ /* ++ * Start a pending master command at here if a slave operation is ++ * completed. ++ */ ++ if (bus->master_state == ASPEED_I2C_MASTER_PENDING && ++ bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE) ++ aspeed_i2c_do_start(bus); + #else + irq_handled = aspeed_i2c_master_irq(bus, irq_remaining); + #endif /* CONFIG_I2C_SLAVE */ +@@ -707,6 +712,15 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap, + ASPEED_I2CD_BUS_BUSY_STS)) + aspeed_i2c_recover_bus(bus); + ++ /* ++ * If timed out and the state is still pending, drop the pending ++ * master command. ++ */ ++ spin_lock_irqsave(&bus->lock, flags); ++ if (bus->master_state == ASPEED_I2C_MASTER_PENDING) ++ bus->master_state = ASPEED_I2C_MASTER_INACTIVE; ++ spin_unlock_irqrestore(&bus->lock, flags); ++ + return -ETIMEDOUT; + } + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0061-i2c-aspeed-add-buffer-mode-transfer-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0061-i2c-aspeed-add-buffer-mode-transfer-support.patch new file mode 100644 index 000000000..8e91b5ced --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0061-i2c-aspeed-add-buffer-mode-transfer-support.patch @@ -0,0 +1,1040 @@ +From 0bc5efede7c99da41fc0cbadfb1644b428ead9d3 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo +Date: Tue, 11 Jun 2019 15:07:08 -0700 +Subject: [PATCH] i2c: aspeed: add buffer mode transfer support + +Byte mode currently this driver uses makes lots of interrupt call +which isn't good for performance and it makes the driver very +timing sensitive. To improve performance of the driver, this commit +adds buffer mode transfer support which uses I2C SRAM buffer +instead of using a single byte buffer. + +AST2400: +It has 2 KBytes (256 Bytes x 8 pages) of I2C SRAM buffer pool from +0x1e78a800 to 0x1e78afff that can be used for all busses with +buffer pool manipulation. To simplify implementation for supporting +both AST2400 and AST2500, it assigns each 128 Bytes per bus without +using buffer pool manipulation so total 1792 Bytes of I2C SRAM +buffer will be used. + +AST2500: +It has 16 Bytes of individual I2C SRAM buffer per each bus and its +range is from 0x1e78a200 to 0x1e78a2df, so it doesn't have 'buffer +page selection' bit field in the Function control register, and +neither 'base address pointer' bit field in the Pool buffer control +register it has. To simplify implementation for supporting both +AST2400 and AST2500, it writes zeros on those register bit fields +but it's okay because it does nothing in AST2500. + +It provides buffer based master and slave data transfer. + +Signed-off-by: Jae Hyun Yoo +--- + .../devicetree/bindings/i2c/i2c-aspeed.txt | 40 ++- + arch/arm/boot/dts/aspeed-g4.dtsi | 47 ++-- + arch/arm/boot/dts/aspeed-g5.dtsi | 47 ++-- + arch/arm/boot/dts/aspeed-g6.dtsi | 34 +-- + drivers/i2c/busses/i2c-aspeed.c | 294 ++++++++++++++++++--- + 5 files changed, 366 insertions(+), 96 deletions(-) + +diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +index 7da7e813b2b0..0ff3539cee95 100644 +--- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt ++++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +@@ -3,7 +3,10 @@ Device tree configuration for the I2C busses on the AST24XX and AST25XX SoCs. + Required Properties: + - #address-cells : should be 1 + - #size-cells : should be 0 +-- reg : address offset and range of bus ++- reg : Address offset and range of bus registers. ++ An additional SRAM buffer address offset and range is ++ optional in case of enabling I2C dedicated SRAM for ++ buffer mode transfer support. + - compatible : should be "aspeed,ast2400-i2c-bus" + or "aspeed,ast2500-i2c-bus" + - clocks : root clock of bus, should reference the APB +@@ -28,12 +31,21 @@ i2c { + #size-cells = <1>; + ranges = <0 0x1e78a000 0x1000>; + +- i2c_ic: interrupt-controller@0 { +- #interrupt-cells = <1>; +- compatible = "aspeed,ast2400-i2c-ic"; ++ i2c_gr: i2c-global-regs@0 { ++ compatible = "aspeed,ast2500-i2c-gr", "syscon"; + reg = <0x0 0x40>; +- interrupts = <12>; +- interrupt-controller; ++ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0x0 0x0 0x40>; ++ ++ i2c_ic: interrupt-controller@0 { ++ #interrupt-cells = <1>; ++ compatible = "aspeed,ast2500-i2c-ic"; ++ reg = <0x0 0x4>; ++ interrupts = <12>; ++ interrupt-controller; ++ }; + }; + + i2c0: i2c-bus@40 { +@@ -41,11 +53,25 @@ i2c { + #size-cells = <0>; + #interrupt-cells = <1>; + reg = <0x40 0x40>; +- compatible = "aspeed,ast2400-i2c-bus"; ++ compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; + bus-frequency = <100000>; + interrupts = <0>; + interrupt-parent = <&i2c_ic>; + }; ++ ++ /* buffer mode transfer enabled */ ++ i2c1: i2c-bus@80 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #interrupt-cells = <1>; ++ reg = <0x80 0x40>, <0x210 0x10>; ++ compatible = "aspeed,ast2500-i2c-bus"; ++ clocks = <&syscon ASPEED_CLK_APB>; ++ resets = <&syscon ASPEED_RESET_I2C>; ++ bus-frequency = <100000>; ++ interrupts = <1>; ++ interrupt-parent = <&i2c_ic>; ++ }; + }; +diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi +index 14e5dc260a3b..68f40a89c91f 100644 +--- a/arch/arm/boot/dts/aspeed-g4.dtsi ++++ b/arch/arm/boot/dts/aspeed-g4.dtsi +@@ -519,12 +519,21 @@ + }; + + &i2c { +- i2c_ic: interrupt-controller@0 { +- #interrupt-cells = <1>; +- compatible = "aspeed,ast2400-i2c-ic"; ++ i2c_gr: i2c-global-regs@0 { ++ compatible = "aspeed,ast2400-i2c-gr", "syscon"; + reg = <0x0 0x40>; +- interrupts = <12>; +- interrupt-controller; ++ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0x0 0x0 0x40>; ++ ++ i2c_ic: interrupt-controller@0 { ++ #interrupt-cells = <1>; ++ compatible = "aspeed,ast2400-i2c-ic"; ++ reg = <0x0 0x4>; ++ interrupts = <12>; ++ interrupt-controller; ++ }; + }; + + i2c0: i2c-bus@40 { +@@ -532,7 +541,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x40 0x40>; ++ reg = <0x40 0x40>, <0x800 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -548,7 +557,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x80 0x40>; ++ reg = <0x80 0x40>, <0x880 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -564,7 +573,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0xc0 0x40>; ++ reg = <0xc0 0x40>, <0x900 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -581,7 +590,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x100 0x40>; ++ reg = <0x100 0x40>, <0x980 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -598,7 +607,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x140 0x40>; ++ reg = <0x140 0x40>, <0xa00 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -615,7 +624,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x180 0x40>; ++ reg = <0x180 0x40>, <0xa80 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -632,7 +641,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x1c0 0x40>; ++ reg = <0x1c0 0x40>, <0xb00 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -649,7 +658,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x300 0x40>; ++ reg = <0x300 0x40>, <0xb80 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -666,7 +675,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x340 0x40>; ++ reg = <0x340 0x40>, <0xc00 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -683,7 +692,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x380 0x40>; ++ reg = <0x380 0x40>, <0xc80 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -700,7 +709,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x3c0 0x40>; ++ reg = <0x3c0 0x40>, <0xd00 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -717,7 +726,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x400 0x40>; ++ reg = <0x400 0x40>, <0xd80 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -734,7 +743,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x440 0x40>; ++ reg = <0x440 0x40>, <0xe00 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -751,7 +760,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x480 0x40>; ++ reg = <0x480 0x40>, <0xe80 0x80>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi +index 3d615708a0cd..fdc669ebfb84 100644 +--- a/arch/arm/boot/dts/aspeed-g5.dtsi ++++ b/arch/arm/boot/dts/aspeed-g5.dtsi +@@ -616,12 +616,21 @@ + }; + + &i2c { +- i2c_ic: interrupt-controller@0 { +- #interrupt-cells = <1>; +- compatible = "aspeed,ast2500-i2c-ic"; ++ i2c_gr: i2c-global-regs@0 { ++ compatible = "aspeed,ast2500-i2c-gr", "syscon"; + reg = <0x0 0x40>; +- interrupts = <12>; +- interrupt-controller; ++ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0x0 0x0 0x40>; ++ ++ i2c_ic: interrupt-controller@0 { ++ #interrupt-cells = <1>; ++ compatible = "aspeed,ast2500-i2c-ic"; ++ reg = <0x0 0x4>; ++ interrupts = <12>; ++ interrupt-controller; ++ }; + }; + + i2c0: i2c-bus@40 { +@@ -629,7 +638,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x40 0x40>; ++ reg = <0x40 0x40>, <0x200 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -645,7 +654,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x80 0x40>; ++ reg = <0x80 0x40>, <0x210 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -661,7 +670,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0xc0 0x40>; ++ reg = <0xc0 0x40>, <0x220 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -678,7 +687,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x100 0x40>; ++ reg = <0x100 0x40>, <0x230 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -695,7 +704,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x140 0x40>; ++ reg = <0x140 0x40>, <0x240 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -712,7 +721,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x180 0x40>; ++ reg = <0x180 0x40>, <0x250 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -729,7 +738,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x1c0 0x40>; ++ reg = <0x1c0 0x40>, <0x260 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -746,7 +755,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x300 0x40>; ++ reg = <0x300 0x40>, <0x270 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -763,7 +772,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x340 0x40>; ++ reg = <0x340 0x40>, <0x280 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -780,7 +789,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x380 0x40>; ++ reg = <0x380 0x40>, <0x290 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -797,7 +806,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x3c0 0x40>; ++ reg = <0x3c0 0x40>, <0x2a0 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -814,7 +823,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x400 0x40>; ++ reg = <0x400 0x40>, <0x2b0 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -831,7 +840,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x440 0x40>; ++ reg = <0x440 0x40>, <0x2c0 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -848,7 +857,7 @@ + #size-cells = <0>; + #interrupt-cells = <1>; + +- reg = <0x480 0x40>; ++ reg = <0x480 0x40>, <0x2d0 0x10>; + compatible = "aspeed,ast2500-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; +diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi +index 2ad90a906266..2dd89efee37c 100644 +--- a/arch/arm/boot/dts/aspeed-g6.dtsi ++++ b/arch/arm/boot/dts/aspeed-g6.dtsi +@@ -530,11 +530,11 @@ + #include "aspeed-g6-pinctrl.dtsi" + + &i2c { +- i2c0: i2c-bus@40 { ++ i2c0: i2c-bus@80 { + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x80 0x80>; ++ reg = <0x80 0x80>, <0xc00 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB1>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -549,7 +549,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x100 0x80>; ++ reg = <0x100 0x80>, <0xc20 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB1>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -564,7 +564,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x180 0x80>; ++ reg = <0x180 0x80>, <0xc40 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB1>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -579,7 +579,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x200 0x80>; ++ reg = <0x200 0x80>, <0xc60 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB1>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -594,7 +594,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x280 0x80>; ++ reg = <0x280 0x80>, <0xc80 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB1>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -609,7 +609,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x300 0x80>; ++ reg = <0x300 0x80>, <0xca0 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB1>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -624,7 +624,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x380 0x80>; ++ reg = <0x380 0x80>, <0xcc0 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB1>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -639,7 +639,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x400 0x80>; ++ reg = <0x400 0x80>, <0xce0 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB1>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -654,7 +654,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x480 0x80>; ++ reg = <0x480 0x80>, <0xd00 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB1>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -669,7 +669,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x500 0x80>; ++ reg = <0x500 0x80>, <0xd20 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB1>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -684,7 +684,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x580 0x80>; ++ reg = <0x580 0x80>, <0xd40 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB1>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -699,7 +699,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x600 0x80>; ++ reg = <0x600 0x80>, <0xd60 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB1>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -714,7 +714,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x680 0x80>; ++ reg = <0x680 0x80>, <0xd80 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB1>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -729,7 +729,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x700 0x80>; ++ reg = <0x700 0x80>, <0xda0 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB1>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -744,7 +744,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x780 0x80>; ++ reg = <0x780 0x80>, <0xdc0 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB1>; + resets = <&syscon ASPEED_RESET_I2C>; +@@ -759,7 +759,7 @@ + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; +- reg = <0x800 0x80>; ++ reg = <0x800 0x80>, <0xde0 0x20>; + compatible = "aspeed,ast2600-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB1>; + resets = <&syscon ASPEED_RESET_I2C>; +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index b9f425739940..3831466912b4 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -7,6 +7,7 @@ + * Copyright 2017 Google, Inc. + */ + ++#include + #include + #include + #include +@@ -19,15 +20,24 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include ++#include + #include + #include + +-/* I2C Register */ ++/* I2C Global Registers */ ++/* 0x00 : I2CG Interrupt Status Register */ ++/* 0x08 : I2CG Interrupt Target Assignment */ ++/* 0x0c : I2CG Global Control Register (AST2500) */ ++#define ASPEED_I2CG_GLOBAL_CTRL_REG 0x0c ++#define ASPEED_I2CG_SRAM_BUFFER_EN BIT(0) ++ ++/* I2C Bus Registers */ + #define ASPEED_I2C_FUN_CTRL_REG 0x00 + #define ASPEED_I2C_AC_TIMING_REG1 0x04 + #define ASPEED_I2C_AC_TIMING_REG2 0x08 +@@ -35,14 +45,12 @@ + #define ASPEED_I2C_INTR_STS_REG 0x10 + #define ASPEED_I2C_CMD_REG 0x14 + #define ASPEED_I2C_DEV_ADDR_REG 0x18 ++#define ASPEED_I2C_BUF_CTRL_REG 0x1c + #define ASPEED_I2C_BYTE_BUF_REG 0x20 + +-/* Global Register Definition */ +-/* 0x00 : I2C Interrupt Status Register */ +-/* 0x08 : I2C Interrupt Target Assignment */ +- + /* Device Register Definition */ + /* 0x00 : I2CD Function Control Register */ ++#define ASPEED_I2CD_BUFFER_PAGE_SEL_MASK GENMASK(22, 20) + #define ASPEED_I2CD_MULTI_MASTER_DIS BIT(15) + #define ASPEED_I2CD_SDA_DRIVE_1T_EN BIT(8) + #define ASPEED_I2CD_M_SDA_DRIVE_1T_EN BIT(7) +@@ -102,6 +110,8 @@ + #define ASPEED_I2CD_BUS_RECOVER_CMD BIT(11) + + /* Command Bit */ ++#define ASPEED_I2CD_RX_BUFF_ENABLE BIT(7) ++#define ASPEED_I2CD_TX_BUFF_ENABLE BIT(6) + #define ASPEED_I2CD_M_STOP_CMD BIT(5) + #define ASPEED_I2CD_M_S_RX_CMD_LAST BIT(4) + #define ASPEED_I2CD_M_RX_CMD BIT(3) +@@ -112,6 +122,13 @@ + /* 0x18 : I2CD Slave Device Address Register */ + #define ASPEED_I2CD_DEV_ADDR_MASK GENMASK(6, 0) + ++/* 0x1c : I2CD Buffer Control Register */ ++/* Use 8-bits or 6-bits wide bit fileds to support both AST2400 and AST2500 */ ++#define ASPEED_I2CD_BUF_RX_COUNT_MASK GENMASK(31, 24) ++#define ASPEED_I2CD_BUF_RX_SIZE_MASK GENMASK(23, 16) ++#define ASPEED_I2CD_BUF_TX_COUNT_MASK GENMASK(15, 8) ++#define ASPEED_I2CD_BUF_OFFSET_MASK GENMASK(5, 0) ++ + enum aspeed_i2c_master_state { + ASPEED_I2C_MASTER_INACTIVE, + ASPEED_I2C_MASTER_PENDING, +@@ -157,6 +174,11 @@ struct aspeed_i2c_bus { + int master_xfer_result; + /* Multi-master */ + bool multi_master; ++ /* Buffer mode */ ++ void __iomem *buf_base; ++ size_t buf_size; ++ u8 buf_offset; ++ u8 buf_page; + #if IS_ENABLED(CONFIG_I2C_SLAVE) + struct i2c_client *slave; + enum aspeed_i2c_slave_state slave_state; +@@ -253,6 +275,7 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + { + u32 command, irq_handled = 0; + struct i2c_client *slave = bus->slave; ++ int i, len; + u8 value; + + if (!slave) +@@ -275,7 +298,12 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + + /* Slave was sent something. */ + if (irq_status & ASPEED_I2CD_INTR_RX_DONE) { +- value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; ++ if (bus->buf_base && ++ bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && ++ !(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP)) ++ value = readb(bus->buf_base); ++ else ++ value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; + /* Handle address frame. */ + if (bus->slave_state == ASPEED_I2C_SLAVE_START) { + if (value & 0x1) +@@ -290,6 +318,20 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + + /* Slave was asked to stop. */ + if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) { ++ if (bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && ++ irq_status & ASPEED_I2CD_INTR_RX_DONE) { ++ if (bus->buf_base) { ++ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, ++ readl(bus->base + ++ ASPEED_I2C_BUF_CTRL_REG)); ++ for (i = 0; i < len; i++) { ++ value = readb(bus->buf_base + i); ++ i2c_slave_event(slave, ++ I2C_SLAVE_WRITE_RECEIVED, ++ &value); ++ } ++ } ++ } + irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP; + bus->slave_state = ASPEED_I2C_SLAVE_STOP; + } +@@ -322,9 +364,36 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + case ASPEED_I2C_SLAVE_WRITE_REQUESTED: + bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED; + i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); ++ if (bus->buf_base) { ++ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, ++ bus->buf_size - 1) | ++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, ++ bus->buf_offset), ++ bus->base + ASPEED_I2C_BUF_CTRL_REG); ++ writel(ASPEED_I2CD_RX_BUFF_ENABLE, ++ bus->base + ASPEED_I2C_CMD_REG); ++ } + break; + case ASPEED_I2C_SLAVE_WRITE_RECEIVED: + i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value); ++ if (bus->buf_base) { ++ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, ++ readl(bus->base + ++ ASPEED_I2C_BUF_CTRL_REG)); ++ for (i = 1; i < len; i++) { ++ value = readb(bus->buf_base + i); ++ i2c_slave_event(slave, ++ I2C_SLAVE_WRITE_RECEIVED, ++ &value); ++ } ++ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, ++ bus->buf_size - 1) | ++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, ++ bus->buf_offset), ++ bus->base + ASPEED_I2C_BUF_CTRL_REG); ++ writel(ASPEED_I2CD_RX_BUFF_ENABLE, ++ bus->base + ASPEED_I2C_CMD_REG); ++ } + break; + case ASPEED_I2C_SLAVE_STOP: + i2c_slave_event(slave, I2C_SLAVE_STOP, &value); +@@ -350,6 +419,8 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) + u32 command = ASPEED_I2CD_M_START_CMD | ASPEED_I2CD_M_TX_CMD; + struct i2c_msg *msg = &bus->msgs[bus->msgs_index]; + u8 slave_addr = i2c_8bit_addr_from_msg(msg); ++ u8 wbuf[4]; ++ int len; + + #if IS_ENABLED(CONFIG_I2C_SLAVE) + /* +@@ -368,12 +439,66 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) + + if (msg->flags & I2C_M_RD) { + command |= ASPEED_I2CD_M_RX_CMD; +- /* Need to let the hardware know to NACK after RX. */ +- if (msg->len == 1 && !(msg->flags & I2C_M_RECV_LEN)) +- command |= ASPEED_I2CD_M_S_RX_CMD_LAST; ++ ++ if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { ++ command |= ASPEED_I2CD_RX_BUFF_ENABLE; ++ ++ if (msg->len > bus->buf_size) { ++ len = bus->buf_size; ++ } else { ++ len = msg->len; ++ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; ++ } ++ ++ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, ++ len - 1) | ++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, ++ bus->buf_offset), ++ bus->base + ASPEED_I2C_BUF_CTRL_REG); ++ } else { ++ /* Need to let the hardware know to NACK after RX. */ ++ if (msg->len == 1 && !(msg->flags & I2C_M_RECV_LEN)) ++ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; ++ } ++ } else { ++ if (bus->buf_base) { ++ int i; ++ ++ command |= ASPEED_I2CD_TX_BUFF_ENABLE; ++ ++ if (msg->len + 1 > bus->buf_size) ++ len = bus->buf_size; ++ else ++ len = msg->len + 1; ++ ++ /* ++ * Yeah, it looks clumsy but byte writings on a remapped ++ * I2C SRAM cause corruptions so use this way to make ++ * dword writings. ++ */ ++ wbuf[0] = slave_addr; ++ for (i = 1; i < len; i++) { ++ wbuf[i % 4] = msg->buf[i - 1]; ++ if (i % 4 == 3) ++ writel(*(u32 *)wbuf, ++ bus->buf_base + i - 3); ++ } ++ if (--i % 4 != 3) ++ writel(*(u32 *)wbuf, ++ bus->buf_base + i - (i % 4)); ++ ++ bus->buf_index = len - 1; ++ ++ writel(FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, ++ len - 1) | ++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, ++ bus->buf_offset), ++ bus->base + ASPEED_I2C_BUF_CTRL_REG); ++ } + } + +- writel(slave_addr, bus->base + ASPEED_I2C_BYTE_BUF_REG); ++ if (!(command & ASPEED_I2CD_TX_BUFF_ENABLE)) ++ writel(slave_addr, bus->base + ASPEED_I2C_BYTE_BUF_REG); + writel(command, bus->base + ASPEED_I2C_CMD_REG); + } + +@@ -413,7 +538,7 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + u32 irq_handled = 0, command = 0; + struct i2c_msg *msg; + u8 recv_byte; +- int ret; ++ int ret, len; + + if (irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) { + bus->master_state = ASPEED_I2C_MASTER_INACTIVE; +@@ -526,11 +651,43 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + /* fall through */ + case ASPEED_I2C_MASTER_TX_FIRST: + if (bus->buf_index < msg->len) { ++ command = ASPEED_I2CD_M_TX_CMD; ++ ++ if (bus->buf_base) { ++ u8 wbuf[4]; ++ int i; ++ ++ command |= ASPEED_I2CD_TX_BUFF_ENABLE; ++ ++ if (msg->len - bus->buf_index > bus->buf_size) ++ len = bus->buf_size; ++ else ++ len = msg->len - bus->buf_index; ++ ++ for (i = 0; i < len; i++) { ++ wbuf[i % 4] = msg->buf[bus->buf_index ++ + i]; ++ if (i % 4 == 3) ++ writel(*(u32 *)wbuf, ++ bus->buf_base + i - 3); ++ } ++ if (--i % 4 != 3) ++ writel(*(u32 *)wbuf, ++ bus->buf_base + i - (i % 4)); ++ ++ bus->buf_index += len; ++ ++ writel(FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, ++ len - 1) | ++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, ++ bus->buf_offset), ++ bus->base + ASPEED_I2C_BUF_CTRL_REG); ++ } else { ++ writel(msg->buf[bus->buf_index++], ++ bus->base + ASPEED_I2C_BYTE_BUF_REG); ++ } ++ writel(command, bus->base + ASPEED_I2C_CMD_REG); + bus->master_state = ASPEED_I2C_MASTER_TX; +- writel(msg->buf[bus->buf_index++], +- bus->base + ASPEED_I2C_BYTE_BUF_REG); +- writel(ASPEED_I2CD_M_TX_CMD, +- bus->base + ASPEED_I2C_CMD_REG); + } else { + aspeed_i2c_next_msg_or_stop(bus); + } +@@ -547,25 +704,56 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + } + irq_handled |= ASPEED_I2CD_INTR_RX_DONE; + +- recv_byte = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; +- msg->buf[bus->buf_index++] = recv_byte; +- +- if (msg->flags & I2C_M_RECV_LEN) { +- if (unlikely(recv_byte > I2C_SMBUS_BLOCK_MAX)) { +- bus->cmd_err = -EPROTO; +- aspeed_i2c_do_stop(bus); +- goto out_no_complete; ++ if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { ++ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, ++ readl(bus->base + ++ ASPEED_I2C_BUF_CTRL_REG)); ++ memcpy_fromio(msg->buf + bus->buf_index, ++ bus->buf_base, len); ++ bus->buf_index += len; ++ } else { ++ recv_byte = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) ++ >> 8; ++ msg->buf[bus->buf_index++] = recv_byte; ++ ++ if (msg->flags & I2C_M_RECV_LEN) { ++ if (unlikely(recv_byte > I2C_SMBUS_BLOCK_MAX)) { ++ bus->cmd_err = -EPROTO; ++ aspeed_i2c_do_stop(bus); ++ goto out_no_complete; ++ } ++ msg->len = recv_byte + ++ ((msg->flags & I2C_CLIENT_PEC) ? ++ 2 : 1); ++ msg->flags &= ~I2C_M_RECV_LEN; + } +- msg->len = recv_byte + +- ((msg->flags & I2C_CLIENT_PEC) ? 2 : 1); +- msg->flags &= ~I2C_M_RECV_LEN; + } + + if (bus->buf_index < msg->len) { +- bus->master_state = ASPEED_I2C_MASTER_RX; + command = ASPEED_I2CD_M_RX_CMD; +- if (bus->buf_index + 1 == msg->len) +- command |= ASPEED_I2CD_M_S_RX_CMD_LAST; ++ bus->master_state = ASPEED_I2C_MASTER_RX; ++ if (bus->buf_base) { ++ command |= ASPEED_I2CD_RX_BUFF_ENABLE; ++ ++ if (msg->len - bus->buf_index > ++ bus->buf_size) { ++ len = bus->buf_size; ++ } else { ++ len = msg->len - bus->buf_index; ++ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; ++ } ++ ++ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, ++ len - 1) | ++ FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, ++ 0) | ++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, ++ bus->buf_offset), ++ bus->base + ASPEED_I2C_BUF_CTRL_REG); ++ } else { ++ if (bus->buf_index + 1 == msg->len) ++ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; ++ } + writel(command, bus->base + ASPEED_I2C_CMD_REG); + } else { + aspeed_i2c_next_msg_or_stop(bus); +@@ -911,6 +1099,9 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus, + if (ret < 0) + return ret; + ++ fun_ctrl_reg |= FIELD_PREP(ASPEED_I2CD_BUFFER_PAGE_SEL_MASK, ++ bus->buf_page); ++ + if (of_property_read_bool(pdev->dev.of_node, "multi-master")) + bus->multi_master = true; + else +@@ -972,16 +1163,15 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + { + const struct of_device_id *match; + struct aspeed_i2c_bus *bus; ++ bool sram_enabled = true; + struct clk *parent_clk; +- struct resource *res; + int irq, ret; + + bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL); + if (!bus) + return -ENOMEM; + +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- bus->base = devm_ioremap_resource(&pdev->dev, res); ++ bus->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(bus->base)) + return PTR_ERR(bus->base); + +@@ -1015,6 +1205,42 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + bus->get_clk_reg_val = (u32 (*)(struct device *, u32)) + match->data; + ++ /* Enable I2C SRAM in case of AST2500 */ ++ if (of_device_is_compatible(pdev->dev.of_node, ++ "aspeed,ast2500-i2c-bus")) { ++ struct regmap *gr_regmap = syscon_regmap_lookup_by_compatible( ++ "aspeed,ast2500-i2c-gr"); ++ if (IS_ERR(gr_regmap)) ++ ret = PTR_ERR(gr_regmap); ++ else ++ ret = regmap_update_bits(gr_regmap, ++ ASPEED_I2CG_GLOBAL_CTRL_REG, ++ ASPEED_I2CG_SRAM_BUFFER_EN, ++ ASPEED_I2CG_SRAM_BUFFER_EN); ++ ++ if (ret) ++ sram_enabled = false; ++ } ++ ++ if (sram_enabled) { ++ struct resource *res = platform_get_resource(pdev, ++ IORESOURCE_MEM, 1); ++ ++ if (res) ++ bus->buf_base = devm_ioremap_resource(&pdev->dev, res); ++ ++ if (!IS_ERR_OR_NULL(bus->buf_base) && resource_size(res) >= 2) { ++ bus->buf_size = resource_size(res); ++ if (of_device_is_compatible(pdev->dev.of_node, ++ "aspeed,ast2400-i2c-bus")) { ++ bus->buf_page = ((res->start >> 8) & ++ GENMASK(3, 0)) - 8; ++ bus->buf_offset = (res->start >> 2) & ++ ASPEED_I2CD_BUF_OFFSET_MASK; ++ } ++ } ++ } ++ + /* Initialize the I2C adapter */ + spin_lock_init(&bus->lock); + init_completion(&bus->cmd_complete); +@@ -1050,8 +1276,8 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + + platform_set_drvdata(pdev, bus); + +- dev_info(bus->dev, "i2c bus %d registered, irq %d\n", +- bus->adap.nr, irq); ++ dev_info(bus->dev, "i2c bus %d registered (%s mode), irq %d\n", ++ bus->adap.nr, bus->buf_base ? "buffer" : "byte", irq); + + return 0; + } +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0062-i2c-aspeed-add-DMA-mode-transfer-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0062-i2c-aspeed-add-DMA-mode-transfer-support.patch new file mode 100644 index 000000000..f3021d410 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0062-i2c-aspeed-add-DMA-mode-transfer-support.patch @@ -0,0 +1,442 @@ +From 09aece99e18a0fd0612c865394424afa74050171 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo +Date: Tue, 18 Jun 2019 08:47:50 -0700 +Subject: [PATCH] i2c: aspeed: add DMA mode transfer support + +This commit adds DMA mode transfer support. + +Only AST2500 supports DMA mode under some limitations: +I2C is sharing the DMA H/W with UHCI host controller and MCTP +controller. Since those controllers operate with DMA mode only, I2C +has to use buffer mode or byte mode instead if one of those +controllers is enabled. Also make sure that if SD/eMMC or Port80 +snoop uses DMA mode instead of PIO or FIFO respectively, I2C can't +use DMA mode. + +Signed-off-by: Jae Hyun Yoo +--- + .../devicetree/bindings/i2c/i2c-aspeed.txt | 25 +++ + drivers/i2c/busses/i2c-aspeed.c | 231 +++++++++++++++++++-- + 2 files changed, 241 insertions(+), 15 deletions(-) + +diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +index 0ff3539cee95..d3f4a39f7ba6 100644 +--- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt ++++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +@@ -22,6 +22,16 @@ Optional Properties: + - bus-timeout-ms: bus timeout in milliseconds defaults to 1 second when not + specified. + - #retries : Number of retries for master transfer. ++- aspeed,dma-buf-size : size of DMA buffer (from 2 to 4095 in case of AST2500) ++ Only AST2500 supports DMA mode under some limitations: ++ I2C is sharing the DMA H/W with UHCI host controller ++ and MCTP controller. Since those controllers operate ++ with DMA mode only, I2C has to use buffer mode or byte ++ mode instead if one of those controllers is enabled. ++ Also make sure that if SD/eMMC or Port80 snoop uses ++ DMA mode instead of PIO or FIFO respectively, I2C ++ can't use DMA mode. IF both DMA and buffer modes are ++ enabled, DMA mode will be selected. + + Example: + +@@ -74,4 +84,19 @@ i2c { + interrupts = <1>; + interrupt-parent = <&i2c_ic>; + }; ++ ++ /* DMA mode transfer enabled */ ++ i2c2: i2c-bus@c0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #interrupt-cells = <1>; ++ reg = <0xc0 0x40>; ++ aspeed,dma-buf-size = <4095>; ++ compatible = "aspeed,ast2500-i2c-bus"; ++ clocks = <&syscon ASPEED_CLK_APB>; ++ resets = <&syscon ASPEED_RESET_I2C>; ++ bus-frequency = <100000>; ++ interrupts = <2>; ++ interrupt-parent = <&i2c_ic>; ++ }; + }; +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index e37f0764d184..4567ec3498dc 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -10,6 +10,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -47,6 +49,8 @@ + #define ASPEED_I2C_DEV_ADDR_REG 0x18 + #define ASPEED_I2C_BUF_CTRL_REG 0x1c + #define ASPEED_I2C_BYTE_BUF_REG 0x20 ++#define ASPEED_I2C_DMA_ADDR_REG 0x24 ++#define ASPEED_I2C_DMA_LEN_REG 0x28 + + /* Device Register Definition */ + /* 0x00 : I2CD Function Control Register */ +@@ -110,6 +114,8 @@ + #define ASPEED_I2CD_BUS_RECOVER_CMD BIT(11) + + /* Command Bit */ ++#define ASPEED_I2CD_RX_DMA_ENABLE BIT(9) ++#define ASPEED_I2CD_TX_DMA_ENABLE BIT(8) + #define ASPEED_I2CD_RX_BUFF_ENABLE BIT(7) + #define ASPEED_I2CD_TX_BUFF_ENABLE BIT(6) + #define ASPEED_I2CD_M_STOP_CMD BIT(5) +@@ -129,6 +135,14 @@ + #define ASPEED_I2CD_BUF_TX_COUNT_MASK GENMASK(15, 8) + #define ASPEED_I2CD_BUF_OFFSET_MASK GENMASK(5, 0) + ++/* 0x24 : I2CD DMA Mode Buffer Address Register */ ++#define ASPEED_I2CD_DMA_ADDR_MASK GENMASK(31, 2) ++#define ASPEED_I2CD_DMA_ALIGN 4 ++ ++/* 0x28 : I2CD DMA Transfer Length Register */ ++#define ASPEED_I2CD_DMA_LEN_SHIFT 0 ++#define ASPEED_I2CD_DMA_LEN_MASK GENMASK(11, 0) ++ + enum aspeed_i2c_master_state { + ASPEED_I2C_MASTER_INACTIVE, + ASPEED_I2C_MASTER_PENDING, +@@ -179,6 +193,12 @@ struct aspeed_i2c_bus { + size_t buf_size; + u8 buf_offset; + u8 buf_page; ++ /* DMA mode */ ++ struct dma_pool *dma_pool; ++ dma_addr_t dma_handle; ++ u8 *dma_buf; ++ size_t dma_buf_size; ++ size_t dma_len; + #if IS_ENABLED(CONFIG_I2C_SLAVE) + struct i2c_client *slave; + enum aspeed_i2c_slave_state slave_state; +@@ -298,9 +318,13 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + + /* Slave was sent something. */ + if (irq_status & ASPEED_I2CD_INTR_RX_DONE) { +- if (bus->buf_base && ++ if (bus->dma_buf && + bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && + !(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP)) ++ value = bus->dma_buf[0]; ++ else if (bus->buf_base && ++ bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && ++ !(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP)) + value = readb(bus->buf_base); + else + value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; +@@ -320,7 +344,18 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) { + if (bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && + irq_status & ASPEED_I2CD_INTR_RX_DONE) { +- if (bus->buf_base) { ++ if (bus->dma_buf) { ++ len = bus->dma_buf_size - ++ FIELD_GET(ASPEED_I2CD_DMA_LEN_MASK, ++ readl(bus->base + ++ ASPEED_I2C_DMA_LEN_REG)); ++ for (i = 0; i < len; i++) { ++ value = bus->dma_buf[i]; ++ i2c_slave_event(slave, ++ I2C_SLAVE_WRITE_RECEIVED, ++ &value); ++ } ++ } else if (bus->buf_base) { + len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, + readl(bus->base + + ASPEED_I2C_BUF_CTRL_REG)); +@@ -364,7 +399,15 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + case ASPEED_I2C_SLAVE_WRITE_REQUESTED: + bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED; + i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); +- if (bus->buf_base) { ++ if (bus->dma_buf) { ++ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, ++ bus->base + ASPEED_I2C_DMA_ADDR_REG); ++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, ++ bus->dma_buf_size), ++ bus->base + ASPEED_I2C_DMA_LEN_REG); ++ writel(ASPEED_I2CD_RX_DMA_ENABLE, ++ bus->base + ASPEED_I2C_CMD_REG); ++ } else if (bus->buf_base) { + writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, + bus->buf_size - 1) | + FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, +@@ -376,7 +419,25 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + break; + case ASPEED_I2C_SLAVE_WRITE_RECEIVED: + i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value); +- if (bus->buf_base) { ++ if (bus->dma_buf) { ++ len = bus->dma_buf_size - ++ FIELD_GET(ASPEED_I2CD_DMA_LEN_MASK, ++ readl(bus->base + ++ ASPEED_I2C_DMA_LEN_REG)); ++ for (i = 1; i < len; i++) { ++ value = bus->dma_buf[i]; ++ i2c_slave_event(slave, ++ I2C_SLAVE_WRITE_RECEIVED, ++ &value); ++ } ++ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, ++ bus->base + ASPEED_I2C_DMA_ADDR_REG); ++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, ++ bus->dma_buf_size), ++ bus->base + ASPEED_I2C_DMA_LEN_REG); ++ writel(ASPEED_I2CD_RX_DMA_ENABLE, ++ bus->base + ASPEED_I2C_CMD_REG); ++ } else if (bus->buf_base) { + len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, + readl(bus->base + + ASPEED_I2C_BUF_CTRL_REG)); +@@ -440,7 +501,23 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) + if (msg->flags & I2C_M_RD) { + command |= ASPEED_I2CD_M_RX_CMD; + +- if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { ++ if (bus->dma_buf && !(msg->flags & I2C_M_RECV_LEN)) { ++ command |= ASPEED_I2CD_RX_DMA_ENABLE; ++ ++ if (msg->len > bus->dma_buf_size) { ++ len = bus->dma_buf_size; ++ } else { ++ len = msg->len; ++ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; ++ } ++ ++ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, ++ bus->base + ASPEED_I2C_DMA_ADDR_REG); ++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, ++ len), ++ bus->base + ASPEED_I2C_DMA_LEN_REG); ++ bus->dma_len = len; ++ } else if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { + command |= ASPEED_I2CD_RX_BUFF_ENABLE; + + if (msg->len > bus->buf_size) { +@@ -461,7 +538,26 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) + command |= ASPEED_I2CD_M_S_RX_CMD_LAST; + } + } else { +- if (bus->buf_base) { ++ if (bus->dma_buf) { ++ command |= ASPEED_I2CD_TX_DMA_ENABLE; ++ ++ if (msg->len + 1 > bus->dma_buf_size) ++ len = bus->dma_buf_size; ++ else ++ len = msg->len + 1; ++ ++ bus->dma_buf[0] = slave_addr; ++ memcpy(bus->dma_buf + 1, msg->buf, len); ++ ++ bus->buf_index = len - 1; ++ ++ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, ++ bus->base + ASPEED_I2C_DMA_ADDR_REG); ++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, ++ len), ++ bus->base + ASPEED_I2C_DMA_LEN_REG); ++ bus->dma_len = len; ++ } else if (bus->buf_base) { + int i; + + command |= ASPEED_I2CD_TX_BUFF_ENABLE; +@@ -497,7 +593,8 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) + } + } + +- if (!(command & ASPEED_I2CD_TX_BUFF_ENABLE)) ++ if (!(command & (ASPEED_I2CD_TX_BUFF_ENABLE | ++ ASPEED_I2CD_TX_DMA_ENABLE))) + writel(slave_addr, bus->base + ASPEED_I2C_BYTE_BUF_REG); + writel(command, bus->base + ASPEED_I2C_CMD_REG); + } +@@ -653,7 +750,28 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + if (bus->buf_index < msg->len) { + command = ASPEED_I2CD_M_TX_CMD; + +- if (bus->buf_base) { ++ if (bus->dma_buf) { ++ command |= ASPEED_I2CD_TX_DMA_ENABLE; ++ ++ if (msg->len - bus->buf_index > ++ bus->dma_buf_size) ++ len = bus->dma_buf_size; ++ else ++ len = msg->len - bus->buf_index; ++ ++ memcpy(bus->dma_buf, msg->buf + bus->buf_index, ++ len); ++ ++ bus->buf_index += len; ++ ++ writel(bus->dma_handle & ++ ASPEED_I2CD_DMA_ADDR_MASK, ++ bus->base + ASPEED_I2C_DMA_ADDR_REG); ++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, ++ len), ++ bus->base + ASPEED_I2C_DMA_LEN_REG); ++ bus->dma_len = len; ++ } else if (bus->buf_base) { + u8 wbuf[4]; + int i; + +@@ -704,7 +822,15 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + } + irq_handled |= ASPEED_I2CD_INTR_RX_DONE; + +- if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { ++ if (bus->dma_buf && !(msg->flags & I2C_M_RECV_LEN)) { ++ len = bus->dma_len - ++ FIELD_GET(ASPEED_I2CD_DMA_LEN_MASK, ++ readl(bus->base + ++ ASPEED_I2C_DMA_LEN_REG)); ++ ++ memcpy(msg->buf + bus->buf_index, bus->dma_buf, len); ++ bus->buf_index += len; ++ } else if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { + len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, + readl(bus->base + + ASPEED_I2C_BUF_CTRL_REG)); +@@ -732,7 +858,25 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + if (bus->buf_index < msg->len) { + command = ASPEED_I2CD_M_RX_CMD; + bus->master_state = ASPEED_I2C_MASTER_RX; +- if (bus->buf_base) { ++ if (bus->dma_buf) { ++ command |= ASPEED_I2CD_RX_DMA_ENABLE; ++ ++ if (msg->len - bus->buf_index > ++ bus->dma_buf_size) { ++ len = bus->dma_buf_size; ++ } else { ++ len = msg->len - bus->buf_index; ++ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; ++ } ++ ++ writel(bus->dma_handle & ++ ASPEED_I2CD_DMA_ADDR_MASK, ++ bus->base + ASPEED_I2C_DMA_ADDR_REG); ++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, ++ len), ++ bus->base + ASPEED_I2C_DMA_LEN_REG); ++ bus->dma_len = len; ++ } else if (bus->buf_base) { + command |= ASPEED_I2CD_RX_BUFF_ENABLE; + + if (msg->len - bus->buf_index > +@@ -1222,7 +1366,51 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + sram_enabled = false; + } + +- if (sram_enabled) { ++ /* ++ * Only AST2500 supports DMA mode under some limitations: ++ * I2C is sharing the DMA H/W with UHCI host controller and MCTP ++ * controller. Since those controllers operate with DMA mode only, I2C ++ * has to use buffer mode or byte mode instead if one of those ++ * controllers is enabled. Also make sure that if SD/eMMC or Port80 ++ * snoop uses DMA mode instead of PIO or FIFO respectively, I2C can't ++ * use DMA mode. ++ */ ++ if (sram_enabled && !IS_ENABLED(CONFIG_USB_UHCI_ASPEED) && ++ of_device_is_compatible(pdev->dev.of_node, ++ "aspeed,ast2500-i2c-bus")) { ++ u32 dma_len_max = ASPEED_I2CD_DMA_LEN_MASK >> ++ ASPEED_I2CD_DMA_LEN_SHIFT; ++ ++ ret = device_property_read_u32(&pdev->dev, ++ "aspeed,dma-buf-size", ++ &bus->dma_buf_size); ++ if (!ret && bus->dma_buf_size > dma_len_max) ++ bus->dma_buf_size = dma_len_max; ++ } ++ ++ if (bus->dma_buf_size) { ++ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { ++ dev_warn(&pdev->dev, "No suitable DMA available\n"); ++ } else { ++ bus->dma_pool = dma_pool_create("i2c-aspeed", ++ &pdev->dev, ++ bus->dma_buf_size, ++ ASPEED_I2CD_DMA_ALIGN, ++ 0); ++ if (bus->dma_pool) ++ bus->dma_buf = dma_pool_alloc(bus->dma_pool, ++ GFP_KERNEL, ++ &bus->dma_handle); ++ ++ if (!bus->dma_buf) { ++ dev_warn(&pdev->dev, ++ "Cannot allocate DMA buffer\n"); ++ dma_pool_destroy(bus->dma_pool); ++ } ++ } ++ } ++ ++ if (!bus->dma_buf && sram_enabled) { + struct resource *res = platform_get_resource(pdev, + IORESOURCE_MEM, 1); + +@@ -1262,24 +1450,33 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + */ + ret = aspeed_i2c_init(bus, pdev); + if (ret < 0) +- return ret; ++ goto out_free_dma_buf; + + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + ret = devm_request_irq(&pdev->dev, irq, aspeed_i2c_bus_irq, + 0, dev_name(&pdev->dev), bus); + if (ret < 0) +- return ret; ++ goto out_free_dma_buf; + + ret = i2c_add_adapter(&bus->adap); + if (ret < 0) +- return ret; ++ goto out_free_dma_buf; + + platform_set_drvdata(pdev, bus); + + dev_info(bus->dev, "i2c bus %d registered (%s mode), irq %d\n", +- bus->adap.nr, bus->buf_base ? "buffer" : "byte", irq); ++ bus->adap.nr, bus->dma_buf ? "dma" : ++ bus->buf_base ? "buffer" : "byte", ++ irq); + + return 0; ++ ++out_free_dma_buf: ++ if (bus->dma_buf) ++ dma_pool_free(bus->dma_pool, bus->dma_buf, bus->dma_handle); ++ dma_pool_destroy(bus->dma_pool); ++ ++ return ret; + } + + static int aspeed_i2c_remove_bus(struct platform_device *pdev) +@@ -1297,6 +1494,10 @@ static int aspeed_i2c_remove_bus(struct platform_device *pdev) + + reset_control_assert(bus->rst); + ++ if (bus->dma_buf) ++ dma_pool_free(bus->dma_pool, bus->dma_buf, bus->dma_handle); ++ dma_pool_destroy(bus->dma_pool); ++ + i2c_del_adapter(&bus->adap); + + return 0; +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0063-i2c-aspeed-add-general-call-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0063-i2c-aspeed-add-general-call-support.patch new file mode 100644 index 000000000..381197a64 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0063-i2c-aspeed-add-general-call-support.patch @@ -0,0 +1,180 @@ +From f9f2e586985f90197b30208599bd37a9fd7a7f63 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo +Date: Wed, 1 May 2019 13:27:34 -0700 +Subject: [PATCH] i2c: aspeed: add general call support + +This commit adds general call support into Aspeed I2C driver. +This is downstream only customization so it should not go into +upstream. + +Signed-off-by: Jae Hyun Yoo +--- + .../devicetree/bindings/i2c/i2c-aspeed.txt | 1 + + drivers/i2c/busses/i2c-aspeed.c | 39 ++++++++++++++++++++++ + drivers/i2c/i2c-slave-mqueue.c | 4 ++- + include/linux/i2c.h | 1 + + 4 files changed, 44 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +index d3f4a39f7ba6..c1ee99398517 100644 +--- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt ++++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt +@@ -19,6 +19,7 @@ Optional Properties: + - bus-frequency : frequency of the bus clock in Hz defaults to 100 kHz when not + specified + - multi-master : states that there is another master active on this bus. ++- general-call : enables general call receiving. + - bus-timeout-ms: bus timeout in milliseconds defaults to 1 second when not + specified. + - #retries : Number of retries for master transfer. +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index 4567ec3498dc..3e72068f6a2b 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -59,6 +59,7 @@ + #define ASPEED_I2CD_SDA_DRIVE_1T_EN BIT(8) + #define ASPEED_I2CD_M_SDA_DRIVE_1T_EN BIT(7) + #define ASPEED_I2CD_M_HIGH_SPEED_EN BIT(6) ++#define ASPEED_I2CD_GCALL_EN BIT(2) + #define ASPEED_I2CD_SLAVE_EN BIT(1) + #define ASPEED_I2CD_MASTER_EN BIT(0) + +@@ -83,6 +84,7 @@ + */ + #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14) + #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13) ++#define ASPEED_I2CD_INTR_GCALL_ADDR BIT(8) + #define ASPEED_I2CD_INTR_SLAVE_MATCH BIT(7) + #define ASPEED_I2CD_INTR_SCL_TIMEOUT BIT(6) + #define ASPEED_I2CD_INTR_ABNORMAL BIT(5) +@@ -161,6 +163,8 @@ enum aspeed_i2c_slave_state { + ASPEED_I2C_SLAVE_READ_PROCESSED, + ASPEED_I2C_SLAVE_WRITE_REQUESTED, + ASPEED_I2C_SLAVE_WRITE_RECEIVED, ++ ASPEED_I2C_SLAVE_GCALL_START, ++ ASPEED_I2C_SLAVE_GCALL_REQUESTED, + ASPEED_I2C_SLAVE_STOP, + }; + +@@ -202,6 +206,8 @@ struct aspeed_i2c_bus { + #if IS_ENABLED(CONFIG_I2C_SLAVE) + struct i2c_client *slave; + enum aspeed_i2c_slave_state slave_state; ++ /* General call */ ++ bool general_call; + #endif /* CONFIG_I2C_SLAVE */ + }; + +@@ -309,6 +315,12 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + bus->slave_state = ASPEED_I2C_SLAVE_START; + } + ++ /* General call was requested, restart state machine. */ ++ if (irq_status & ASPEED_I2CD_INTR_GCALL_ADDR) { ++ irq_handled |= ASPEED_I2CD_INTR_GCALL_ADDR; ++ bus->slave_state = ASPEED_I2C_SLAVE_GCALL_START; ++ } ++ + /* Slave is not currently active, irq was for someone else. */ + if (bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE) + return irq_handled; +@@ -336,6 +348,21 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + else + bus->slave_state = + ASPEED_I2C_SLAVE_WRITE_REQUESTED; ++ } else if (bus->slave_state == ASPEED_I2C_SLAVE_GCALL_START) { ++ /* ++ * I2C spec defines the second byte meaning like below. ++ * 0x06 : Reset and write programmable part of slave ++ * address by hardware. ++ * 0x04 : Write programmable part of slave address by ++ * hardware. ++ * 0x00 : No allowed. ++ * ++ * But in OpenBMC, we are going to use this ++ * 'General call' feature for IPMB message broadcasting ++ * so it delivers all data as is without any specific ++ * handling of the second byte. ++ */ ++ bus->slave_state = ASPEED_I2C_SLAVE_GCALL_REQUESTED; + } + irq_handled |= ASPEED_I2CD_INTR_RX_DONE; + } +@@ -456,11 +483,16 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) + bus->base + ASPEED_I2C_CMD_REG); + } + break; ++ case ASPEED_I2C_SLAVE_GCALL_REQUESTED: ++ bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED; ++ i2c_slave_event(slave, I2C_SLAVE_GCALL_REQUESTED, &value); ++ break; + case ASPEED_I2C_SLAVE_STOP: + i2c_slave_event(slave, I2C_SLAVE_STOP, &value); + bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE; + break; + case ASPEED_I2C_SLAVE_START: ++ case ASPEED_I2C_SLAVE_GCALL_START: + /* Slave was just started. Waiting for the next event. */; + break; + default: +@@ -1071,6 +1103,8 @@ static void __aspeed_i2c_reg_slave(struct aspeed_i2c_bus *bus, u16 slave_addr) + /* Turn on slave mode. */ + func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG); + func_ctrl_reg_val |= ASPEED_I2CD_SLAVE_EN; ++ if (bus->general_call) ++ func_ctrl_reg_val |= ASPEED_I2CD_GCALL_EN; + writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG); + } + +@@ -1109,6 +1143,8 @@ static int aspeed_i2c_unreg_slave(struct i2c_client *client) + /* Turn off slave mode. */ + func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG); + func_ctrl_reg_val &= ~ASPEED_I2CD_SLAVE_EN; ++ if (bus->general_call) ++ func_ctrl_reg_val &= ~ASPEED_I2CD_GCALL_EN; + writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG); + + bus->slave = NULL; +@@ -1256,6 +1292,9 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus, + bus->base + ASPEED_I2C_FUN_CTRL_REG); + + #if IS_ENABLED(CONFIG_I2C_SLAVE) ++ if (of_property_read_bool(pdev->dev.of_node, "general-call")) ++ bus->general_call = true; ++ + /* If slave has already been registered, re-enable it. */ + if (bus->slave) + __aspeed_i2c_reg_slave(bus, bus->slave->addr); +diff --git a/drivers/i2c/i2c-slave-mqueue.c b/drivers/i2c/i2c-slave-mqueue.c +index 2c7a6038409c..1d4db584b393 100644 +--- a/drivers/i2c/i2c-slave-mqueue.c ++++ b/drivers/i2c/i2c-slave-mqueue.c +@@ -56,10 +56,12 @@ static int i2c_slave_mqueue_callback(struct i2c_client *client, + + switch (event) { + case I2C_SLAVE_WRITE_REQUESTED: ++ case I2C_SLAVE_GCALL_REQUESTED: + mq->truncated = 0; + + msg->len = 1; +- msg->buf[0] = client->addr << 1; ++ msg->buf[0] = event == I2C_SLAVE_GCALL_REQUESTED ? ++ 0 : client->addr << 1; + break; + + case I2C_SLAVE_WRITE_RECEIVED: +diff --git a/include/linux/i2c.h b/include/linux/i2c.h +index 92c795ce9081..1e5c74888160 100644 +--- a/include/linux/i2c.h ++++ b/include/linux/i2c.h +@@ -365,6 +365,7 @@ enum i2c_slave_event { + I2C_SLAVE_WRITE_REQUESTED, + I2C_SLAVE_READ_PROCESSED, + I2C_SLAVE_WRITE_RECEIVED, ++ I2C_SLAVE_GCALL_REQUESTED, + I2C_SLAVE_STOP, + }; + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0064-set-idle-disconnect-to-true-in-all-cases.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0064-set-idle-disconnect-to-true-in-all-cases.patch new file mode 100644 index 000000000..925880eff --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0064-set-idle-disconnect-to-true-in-all-cases.patch @@ -0,0 +1,34 @@ +From 7854a5e094ac49bebf9b2bfdd44db2f8cdd37543 Mon Sep 17 00:00:00 2001 +From: James Feist +Date: Fri, 31 May 2019 15:05:13 -0700 +Subject: [PATCH] set idle-disconnect to true in all cases + +From sysfs this parameter can't be set. We want the +muxes to clean themselves up if possible. Set this to +true. + +Signed-off-by: James Feist +--- + drivers/i2c/muxes/i2c-mux-pca954x.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c +index 923aa3a5a3dc..084c10951890 100644 +--- a/drivers/i2c/muxes/i2c-mux-pca954x.c ++++ b/drivers/i2c/muxes/i2c-mux-pca954x.c +@@ -474,8 +474,12 @@ static int pca954x_probe(struct i2c_client *client, + data->last_chan = 0; /* force the first selection */ + data->idle_state = MUX_IDLE_AS_IS; + ++#if 1 /* Forcibly set the self-disconnect flag */ ++ idle_disconnect_dt = true; ++#else + idle_disconnect_dt = np && + of_property_read_bool(np, "i2c-mux-idle-disconnect"); ++#endif + if (idle_disconnect_dt) + data->idle_state = MUX_IDLE_DISCONNECT; + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0065-i2c-aspeed-fix-master-pending-state-handling.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0065-i2c-aspeed-fix-master-pending-state-handling.patch deleted file mode 100644 index 003a96c8d..000000000 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0065-i2c-aspeed-fix-master-pending-state-handling.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 4a05d2506e7cb7fb3ad323a16861f09279b4da39 Mon Sep 17 00:00:00 2001 -From: Jae Hyun Yoo -Date: Tue, 11 Jun 2019 14:59:53 -0700 -Subject: [PATCH] i2c: aspeed: fix master pending state handling - -In case of a master pending state, it should not trigger the master -command because this H/W is sharing the same byte buffer for slave -and master operation, so this commit fixes the issue with making -the master command triggering happens when the state goes to active -state. - -Signed-off-by: Jae Hyun Yoo ---- - drivers/i2c/busses/i2c-aspeed.c | 9 +++++---- - 1 file changed, 5 insertions(+), 4 deletions(-) - -diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c -index 8f26060bd685..d8143c24d3a7 100644 ---- a/drivers/i2c/busses/i2c-aspeed.c -+++ b/drivers/i2c/busses/i2c-aspeed.c -@@ -383,18 +383,19 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) - struct i2c_msg *msg = &bus->msgs[bus->msgs_index]; - u8 slave_addr = i2c_8bit_addr_from_msg(msg); - -- bus->master_state = ASPEED_I2C_MASTER_START; -- - #if IS_ENABLED(CONFIG_I2C_SLAVE) - /* - * If it's requested in the middle of a slave session, set the master - * state to 'pending' then H/W will continue handling this master - * command when the bus comes back to the idle state. - */ -- if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE) -+ if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE) { - bus->master_state = ASPEED_I2C_MASTER_PENDING; -+ return; -+ } - #endif /* CONFIG_I2C_SLAVE */ - -+ bus->master_state = ASPEED_I2C_MASTER_START; - bus->buf_index = 0; - - if (msg->flags & I2C_M_RD) { -@@ -479,7 +480,7 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE) - goto out_no_complete; - -- bus->master_state = ASPEED_I2C_MASTER_START; -+ aspeed_i2c_do_start(bus); - } - #endif /* CONFIG_I2C_SLAVE */ - --- -2.7.4 - diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0066-i2c-aspeed-add-buffer-mode-transfer-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0066-i2c-aspeed-add-buffer-mode-transfer-support.patch deleted file mode 100644 index 9b96b400b..000000000 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0066-i2c-aspeed-add-buffer-mode-transfer-support.patch +++ /dev/null @@ -1,886 +0,0 @@ -From 36128aacdc8b642b9ee080e493abbc00de345f1d Mon Sep 17 00:00:00 2001 -From: Jae Hyun Yoo -Date: Tue, 11 Jun 2019 15:07:08 -0700 -Subject: [PATCH] i2c: aspeed: add buffer mode transfer support - -Byte mode currently this driver uses makes lots of interrupt call -which isn't good for performance and it makes the driver very -timing sensitive. To improve performance of the driver, this commit -adds buffer mode transfer support which uses I2C SRAM buffer -instead of using a single byte buffer. - -AST2400: -It has 2 KBytes (256 Bytes x 8 pages) of I2C SRAM buffer pool from -0x1e78a800 to 0x1e78afff that can be used for all busses with -buffer pool manipulation. To simplify implementation for supporting -both AST2400 and AST2500, it assigns each 128 Bytes per bus without -using buffer pool manipulation so total 1792 Bytes of I2C SRAM -buffer will be used. - -AST2500: -It has 16 Bytes of individual I2C SRAM buffer per each bus and its -range is from 0x1e78a200 to 0x1e78a2df, so it doesn't have 'buffer -page selection' bit field in the Function control register, and -neither 'base address pointer' bit field in the Pool buffer control -register it has. To simplify implementation for supporting both -AST2400 and AST2500, it writes zeros on those register bit fields -but it's okay because it does nothing in AST2500. - -It provides buffer based master and slave data transfer. - -Signed-off-by: Jae Hyun Yoo ---- - .../devicetree/bindings/i2c/i2c-aspeed.txt | 40 ++- - arch/arm/boot/dts/aspeed-g4.dtsi | 47 ++-- - arch/arm/boot/dts/aspeed-g5.dtsi | 47 ++-- - drivers/i2c/busses/i2c-aspeed.c | 294 ++++++++++++++++++--- - 4 files changed, 349 insertions(+), 79 deletions(-) - -diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt -index 724ee9f35c10..e1a0ae7a8c08 100644 ---- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt -+++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt -@@ -3,7 +3,10 @@ Device tree configuration for the I2C busses on the AST24XX and AST25XX SoCs. - Required Properties: - - #address-cells : should be 1 - - #size-cells : should be 0 --- reg : address offset and range of bus -+- reg : Address offset and range of bus registers. -+ An additional SRAM buffer address offset and range is -+ optional in case of enabling I2C dedicated SRAM for -+ buffer mode transfer support. - - compatible : should be "aspeed,ast2400-i2c-bus" - or "aspeed,ast2500-i2c-bus" - - clocks : root clock of bus, should reference the APB -@@ -29,12 +32,21 @@ i2c { - #size-cells = <1>; - ranges = <0 0x1e78a000 0x1000>; - -- i2c_ic: interrupt-controller@0 { -- #interrupt-cells = <1>; -- compatible = "aspeed,ast2400-i2c-ic"; -+ i2c_gr: i2c-global-regs@0 { -+ compatible = "aspeed,ast2500-i2c-gr", "syscon"; - reg = <0x0 0x40>; -- interrupts = <12>; -- interrupt-controller; -+ -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges = <0x0 0x0 0x40>; -+ -+ i2c_ic: interrupt-controller@0 { -+ #interrupt-cells = <1>; -+ compatible = "aspeed,ast2500-i2c-ic"; -+ reg = <0x0 0x4>; -+ interrupts = <12>; -+ interrupt-controller; -+ }; - }; - - i2c0: i2c-bus@40 { -@@ -42,11 +54,25 @@ i2c { - #size-cells = <0>; - #interrupt-cells = <1>; - reg = <0x40 0x40>; -- compatible = "aspeed,ast2400-i2c-bus"; -+ compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; - bus-frequency = <100000>; - interrupts = <0>; - interrupt-parent = <&i2c_ic>; - }; -+ -+ /* buffer mode transfer enabled */ -+ i2c1: i2c-bus@80 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ #interrupt-cells = <1>; -+ reg = <0x80 0x40>, <0x210 0x10>; -+ compatible = "aspeed,ast2500-i2c-bus"; -+ clocks = <&syscon ASPEED_CLK_APB>; -+ resets = <&syscon ASPEED_RESET_I2C>; -+ bus-frequency = <100000>; -+ interrupts = <1>; -+ interrupt-parent = <&i2c_ic>; -+ }; - }; -diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi -index 47a5029f5bdb..052b1b6b4dc7 100644 ---- a/arch/arm/boot/dts/aspeed-g4.dtsi -+++ b/arch/arm/boot/dts/aspeed-g4.dtsi -@@ -469,12 +469,21 @@ - }; - - &i2c { -- i2c_ic: interrupt-controller@0 { -- #interrupt-cells = <1>; -- compatible = "aspeed,ast2400-i2c-ic"; -+ i2c_gr: i2c-global-regs@0 { -+ compatible = "aspeed,ast2400-i2c-gr", "syscon"; - reg = <0x0 0x40>; -- interrupts = <12>; -- interrupt-controller; -+ -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges = <0x0 0x0 0x40>; -+ -+ i2c_ic: interrupt-controller@0 { -+ #interrupt-cells = <1>; -+ compatible = "aspeed,ast2400-i2c-ic"; -+ reg = <0x0 0x4>; -+ interrupts = <12>; -+ interrupt-controller; -+ }; - }; - - i2c0: i2c-bus@40 { -@@ -482,7 +491,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x40 0x40>; -+ reg = <0x40 0x40>, <0x800 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -498,7 +507,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x80 0x40>; -+ reg = <0x80 0x40>, <0x880 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -514,7 +523,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0xc0 0x40>; -+ reg = <0xc0 0x40>, <0x900 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -531,7 +540,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x100 0x40>; -+ reg = <0x100 0x40>, <0x980 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -548,7 +557,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x140 0x40>; -+ reg = <0x140 0x40>, <0xa00 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -565,7 +574,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x180 0x40>; -+ reg = <0x180 0x40>, <0xa80 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -582,7 +591,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x1c0 0x40>; -+ reg = <0x1c0 0x40>, <0xb00 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -599,7 +608,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x300 0x40>; -+ reg = <0x300 0x40>, <0xb80 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -616,7 +625,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x340 0x40>; -+ reg = <0x340 0x40>, <0xc00 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -633,7 +642,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x380 0x40>; -+ reg = <0x380 0x40>, <0xc80 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -650,7 +659,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x3c0 0x40>; -+ reg = <0x3c0 0x40>, <0xd00 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -667,7 +676,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x400 0x40>; -+ reg = <0x400 0x40>, <0xd80 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -684,7 +693,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x440 0x40>; -+ reg = <0x440 0x40>, <0xe00 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -701,7 +710,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x480 0x40>; -+ reg = <0x480 0x40>, <0xe80 0x80>; - compatible = "aspeed,ast2400-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi -index 89a9febf6f14..2d2173d598e4 100644 ---- a/arch/arm/boot/dts/aspeed-g5.dtsi -+++ b/arch/arm/boot/dts/aspeed-g5.dtsi -@@ -586,12 +586,21 @@ - }; - - &i2c { -- i2c_ic: interrupt-controller@0 { -- #interrupt-cells = <1>; -- compatible = "aspeed,ast2500-i2c-ic"; -+ i2c_gr: i2c-global-regs@0 { -+ compatible = "aspeed,ast2500-i2c-gr", "syscon"; - reg = <0x0 0x40>; -- interrupts = <12>; -- interrupt-controller; -+ -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges = <0x0 0x0 0x40>; -+ -+ i2c_ic: interrupt-controller@0 { -+ #interrupt-cells = <1>; -+ compatible = "aspeed,ast2500-i2c-ic"; -+ reg = <0x0 0x4>; -+ interrupts = <12>; -+ interrupt-controller; -+ }; - }; - - i2c0: i2c-bus@40 { -@@ -599,7 +608,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x40 0x40>; -+ reg = <0x40 0x40>, <0x200 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -615,7 +624,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x80 0x40>; -+ reg = <0x80 0x40>, <0x210 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -631,7 +640,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0xc0 0x40>; -+ reg = <0xc0 0x40>, <0x220 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -648,7 +657,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x100 0x40>; -+ reg = <0x100 0x40>, <0x230 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -665,7 +674,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x140 0x40>; -+ reg = <0x140 0x40>, <0x240 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -682,7 +691,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x180 0x40>; -+ reg = <0x180 0x40>, <0x250 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -699,7 +708,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x1c0 0x40>; -+ reg = <0x1c0 0x40>, <0x260 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -716,7 +725,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x300 0x40>; -+ reg = <0x300 0x40>, <0x270 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -733,7 +742,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x340 0x40>; -+ reg = <0x340 0x40>, <0x280 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -750,7 +759,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x380 0x40>; -+ reg = <0x380 0x40>, <0x290 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -767,7 +776,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x3c0 0x40>; -+ reg = <0x3c0 0x40>, <0x2a0 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -784,7 +793,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x400 0x40>; -+ reg = <0x400 0x40>, <0x2b0 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -801,7 +810,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x440 0x40>; -+ reg = <0x440 0x40>, <0x2c0 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -@@ -818,7 +827,7 @@ - #size-cells = <0>; - #interrupt-cells = <1>; - -- reg = <0x480 0x40>; -+ reg = <0x480 0x40>, <0x2d0 0x10>; - compatible = "aspeed,ast2500-i2c-bus"; - clocks = <&syscon ASPEED_CLK_APB>; - resets = <&syscon ASPEED_RESET_I2C>; -diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c -index d8143c24d3a7..b721fb1d6d4c 100644 ---- a/drivers/i2c/busses/i2c-aspeed.c -+++ b/drivers/i2c/busses/i2c-aspeed.c -@@ -7,6 +7,7 @@ - * Copyright 2017 Google, Inc. - */ - -+#include - #include - #include - #include -@@ -19,15 +20,24 @@ - #include - #include - #include -+#include - #include - #include - #include - #include - #include -+#include - #include - #include - --/* I2C Register */ -+/* I2C Global Registers */ -+/* 0x00 : I2CG Interrupt Status Register */ -+/* 0x08 : I2CG Interrupt Target Assignment */ -+/* 0x0c : I2CG Global Control Register (AST2500) */ -+#define ASPEED_I2CG_GLOBAL_CTRL_REG 0x0c -+#define ASPEED_I2CG_SRAM_BUFFER_EN BIT(0) -+ -+/* I2C Bus Registers */ - #define ASPEED_I2C_FUN_CTRL_REG 0x00 - #define ASPEED_I2C_AC_TIMING_REG1 0x04 - #define ASPEED_I2C_AC_TIMING_REG2 0x08 -@@ -35,14 +45,12 @@ - #define ASPEED_I2C_INTR_STS_REG 0x10 - #define ASPEED_I2C_CMD_REG 0x14 - #define ASPEED_I2C_DEV_ADDR_REG 0x18 -+#define ASPEED_I2C_BUF_CTRL_REG 0x1c - #define ASPEED_I2C_BYTE_BUF_REG 0x20 - --/* Global Register Definition */ --/* 0x00 : I2C Interrupt Status Register */ --/* 0x08 : I2C Interrupt Target Assignment */ -- - /* Device Register Definition */ - /* 0x00 : I2CD Function Control Register */ -+#define ASPEED_I2CD_BUFFER_PAGE_SEL_MASK GENMASK(22, 20) - #define ASPEED_I2CD_MULTI_MASTER_DIS BIT(15) - #define ASPEED_I2CD_SDA_DRIVE_1T_EN BIT(8) - #define ASPEED_I2CD_M_SDA_DRIVE_1T_EN BIT(7) -@@ -104,6 +112,8 @@ - #define ASPEED_I2CD_BUS_RECOVER_CMD BIT(11) - - /* Command Bit */ -+#define ASPEED_I2CD_RX_BUFF_ENABLE BIT(7) -+#define ASPEED_I2CD_TX_BUFF_ENABLE BIT(6) - #define ASPEED_I2CD_M_STOP_CMD BIT(5) - #define ASPEED_I2CD_M_S_RX_CMD_LAST BIT(4) - #define ASPEED_I2CD_M_RX_CMD BIT(3) -@@ -114,6 +124,13 @@ - /* 0x18 : I2CD Slave Device Address Register */ - #define ASPEED_I2CD_DEV_ADDR_MASK GENMASK(6, 0) - -+/* 0x1c : I2CD Buffer Control Register */ -+/* Use 8-bits or 6-bits wide bit fileds to support both AST2400 and AST2500 */ -+#define ASPEED_I2CD_BUF_RX_COUNT_MASK GENMASK(31, 24) -+#define ASPEED_I2CD_BUF_RX_SIZE_MASK GENMASK(23, 16) -+#define ASPEED_I2CD_BUF_TX_COUNT_MASK GENMASK(15, 8) -+#define ASPEED_I2CD_BUF_OFFSET_MASK GENMASK(5, 0) -+ - enum aspeed_i2c_master_state { - ASPEED_I2C_MASTER_INACTIVE, - ASPEED_I2C_MASTER_PENDING, -@@ -161,6 +178,11 @@ struct aspeed_i2c_bus { - int master_xfer_result; - /* Multi-master */ - bool multi_master; -+ /* Buffer mode */ -+ void __iomem *buf_base; -+ size_t buf_size; -+ u8 buf_offset; -+ u8 buf_page; - #if IS_ENABLED(CONFIG_I2C_SLAVE) - struct i2c_client *slave; - enum aspeed_i2c_slave_state slave_state; -@@ -259,6 +281,7 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - { - u32 command, irq_handled = 0; - struct i2c_client *slave = bus->slave; -+ int i, len; - u8 value; - - if (!slave) -@@ -287,7 +310,12 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - - /* Slave was sent something. */ - if (irq_status & ASPEED_I2CD_INTR_RX_DONE) { -- value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; -+ if (bus->buf_base && -+ bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && -+ !(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP)) -+ value = readb(bus->buf_base); -+ else -+ value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; - /* Handle address frame. */ - if (bus->slave_state == ASPEED_I2C_SLAVE_START) { - if (value & 0x1) -@@ -317,6 +345,20 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - - /* Slave was asked to stop. */ - if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) { -+ if (bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && -+ irq_status & ASPEED_I2CD_INTR_RX_DONE) { -+ if (bus->buf_base) { -+ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, -+ readl(bus->base + -+ ASPEED_I2C_BUF_CTRL_REG)); -+ for (i = 0; i < len; i++) { -+ value = readb(bus->buf_base + i); -+ i2c_slave_event(slave, -+ I2C_SLAVE_WRITE_RECEIVED, -+ &value); -+ } -+ } -+ } - irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP; - bus->slave_state = ASPEED_I2C_SLAVE_STOP; - } -@@ -349,9 +391,36 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - case ASPEED_I2C_SLAVE_WRITE_REQUESTED: - bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED; - i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); -+ if (bus->buf_base) { -+ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, -+ bus->buf_size - 1) | -+ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, -+ bus->buf_offset), -+ bus->base + ASPEED_I2C_BUF_CTRL_REG); -+ writel(ASPEED_I2CD_RX_BUFF_ENABLE, -+ bus->base + ASPEED_I2C_CMD_REG); -+ } - break; - case ASPEED_I2C_SLAVE_WRITE_RECEIVED: - i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value); -+ if (bus->buf_base) { -+ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, -+ readl(bus->base + -+ ASPEED_I2C_BUF_CTRL_REG)); -+ for (i = 1; i < len; i++) { -+ value = readb(bus->buf_base + i); -+ i2c_slave_event(slave, -+ I2C_SLAVE_WRITE_RECEIVED, -+ &value); -+ } -+ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, -+ bus->buf_size - 1) | -+ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, -+ bus->buf_offset), -+ bus->base + ASPEED_I2C_BUF_CTRL_REG); -+ writel(ASPEED_I2CD_RX_BUFF_ENABLE, -+ bus->base + ASPEED_I2C_CMD_REG); -+ } - break; - case ASPEED_I2C_SLAVE_GCALL_REQUESTED: - bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED; -@@ -382,6 +451,8 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) - u32 command = ASPEED_I2CD_M_START_CMD | ASPEED_I2CD_M_TX_CMD; - struct i2c_msg *msg = &bus->msgs[bus->msgs_index]; - u8 slave_addr = i2c_8bit_addr_from_msg(msg); -+ u8 wbuf[4]; -+ int len; - - #if IS_ENABLED(CONFIG_I2C_SLAVE) - /* -@@ -400,12 +471,66 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) - - if (msg->flags & I2C_M_RD) { - command |= ASPEED_I2CD_M_RX_CMD; -- /* Need to let the hardware know to NACK after RX. */ -- if (msg->len == 1 && !(msg->flags & I2C_M_RECV_LEN)) -- command |= ASPEED_I2CD_M_S_RX_CMD_LAST; -+ -+ if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { -+ command |= ASPEED_I2CD_RX_BUFF_ENABLE; -+ -+ if (msg->len > bus->buf_size) { -+ len = bus->buf_size; -+ } else { -+ len = msg->len; -+ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; -+ } -+ -+ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, -+ len - 1) | -+ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, -+ bus->buf_offset), -+ bus->base + ASPEED_I2C_BUF_CTRL_REG); -+ } else { -+ /* Need to let the hardware know to NACK after RX. */ -+ if (msg->len == 1 && !(msg->flags & I2C_M_RECV_LEN)) -+ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; -+ } -+ } else { -+ if (bus->buf_base) { -+ int i; -+ -+ command |= ASPEED_I2CD_TX_BUFF_ENABLE; -+ -+ if (msg->len + 1 > bus->buf_size) -+ len = bus->buf_size; -+ else -+ len = msg->len + 1; -+ -+ /* -+ * Yeah, it looks clumsy but byte writings on a remapped -+ * I2C SRAM cause corruptions so use this way to make -+ * dword writings. -+ */ -+ wbuf[0] = slave_addr; -+ for (i = 1; i < len; i++) { -+ wbuf[i % 4] = msg->buf[i - 1]; -+ if (i % 4 == 3) -+ writel(*(u32 *)wbuf, -+ bus->buf_base + i - 3); -+ } -+ if (--i % 4 != 3) -+ writel(*(u32 *)wbuf, -+ bus->buf_base + i - (i % 4)); -+ -+ bus->buf_index = len - 1; -+ -+ writel(FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, -+ len - 1) | -+ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, -+ bus->buf_offset), -+ bus->base + ASPEED_I2C_BUF_CTRL_REG); -+ } - } - -- writel(slave_addr, bus->base + ASPEED_I2C_BYTE_BUF_REG); -+ if (!(command & ASPEED_I2CD_TX_BUFF_ENABLE)) -+ writel(slave_addr, bus->base + ASPEED_I2C_BYTE_BUF_REG); - writel(command, bus->base + ASPEED_I2C_CMD_REG); - } - -@@ -445,7 +570,7 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - u32 irq_handled = 0, command = 0; - struct i2c_msg *msg; - u8 recv_byte; -- int ret; -+ int ret, len; - - if (irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) { - bus->master_state = ASPEED_I2C_MASTER_INACTIVE; -@@ -558,11 +683,43 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - /* fall through */ - case ASPEED_I2C_MASTER_TX_FIRST: - if (bus->buf_index < msg->len) { -+ command = ASPEED_I2CD_M_TX_CMD; -+ -+ if (bus->buf_base) { -+ u8 wbuf[4]; -+ int i; -+ -+ command |= ASPEED_I2CD_TX_BUFF_ENABLE; -+ -+ if (msg->len - bus->buf_index > bus->buf_size) -+ len = bus->buf_size; -+ else -+ len = msg->len - bus->buf_index; -+ -+ for (i = 0; i < len; i++) { -+ wbuf[i % 4] = msg->buf[bus->buf_index -+ + i]; -+ if (i % 4 == 3) -+ writel(*(u32 *)wbuf, -+ bus->buf_base + i - 3); -+ } -+ if (--i % 4 != 3) -+ writel(*(u32 *)wbuf, -+ bus->buf_base + i - (i % 4)); -+ -+ bus->buf_index += len; -+ -+ writel(FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, -+ len - 1) | -+ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, -+ bus->buf_offset), -+ bus->base + ASPEED_I2C_BUF_CTRL_REG); -+ } else { -+ writel(msg->buf[bus->buf_index++], -+ bus->base + ASPEED_I2C_BYTE_BUF_REG); -+ } -+ writel(command, bus->base + ASPEED_I2C_CMD_REG); - bus->master_state = ASPEED_I2C_MASTER_TX; -- writel(msg->buf[bus->buf_index++], -- bus->base + ASPEED_I2C_BYTE_BUF_REG); -- writel(ASPEED_I2CD_M_TX_CMD, -- bus->base + ASPEED_I2C_CMD_REG); - } else { - aspeed_i2c_next_msg_or_stop(bus); - } -@@ -579,25 +736,56 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - } - irq_handled |= ASPEED_I2CD_INTR_RX_DONE; - -- recv_byte = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; -- msg->buf[bus->buf_index++] = recv_byte; -- -- if (msg->flags & I2C_M_RECV_LEN) { -- if (unlikely(recv_byte > I2C_SMBUS_BLOCK_MAX)) { -- bus->cmd_err = -EPROTO; -- aspeed_i2c_do_stop(bus); -- goto out_no_complete; -+ if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { -+ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, -+ readl(bus->base + -+ ASPEED_I2C_BUF_CTRL_REG)); -+ memcpy_fromio(msg->buf + bus->buf_index, -+ bus->buf_base, len); -+ bus->buf_index += len; -+ } else { -+ recv_byte = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) -+ >> 8; -+ msg->buf[bus->buf_index++] = recv_byte; -+ -+ if (msg->flags & I2C_M_RECV_LEN) { -+ if (unlikely(recv_byte > I2C_SMBUS_BLOCK_MAX)) { -+ bus->cmd_err = -EPROTO; -+ aspeed_i2c_do_stop(bus); -+ goto out_no_complete; -+ } -+ msg->len = recv_byte + -+ ((msg->flags & I2C_CLIENT_PEC) ? -+ 2 : 1); -+ msg->flags &= ~I2C_M_RECV_LEN; - } -- msg->len = recv_byte + -- ((msg->flags & I2C_CLIENT_PEC) ? 2 : 1); -- msg->flags &= ~I2C_M_RECV_LEN; - } - - if (bus->buf_index < msg->len) { -- bus->master_state = ASPEED_I2C_MASTER_RX; - command = ASPEED_I2CD_M_RX_CMD; -- if (bus->buf_index + 1 == msg->len) -- command |= ASPEED_I2CD_M_S_RX_CMD_LAST; -+ bus->master_state = ASPEED_I2C_MASTER_RX; -+ if (bus->buf_base) { -+ command |= ASPEED_I2CD_RX_BUFF_ENABLE; -+ -+ if (msg->len - bus->buf_index > -+ bus->buf_size) { -+ len = bus->buf_size; -+ } else { -+ len = msg->len - bus->buf_index; -+ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; -+ } -+ -+ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, -+ len - 1) | -+ FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, -+ 0) | -+ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, -+ bus->buf_offset), -+ bus->base + ASPEED_I2C_BUF_CTRL_REG); -+ } else { -+ if (bus->buf_index + 1 == msg->len) -+ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; -+ } - writel(command, bus->base + ASPEED_I2C_CMD_REG); - } else { - aspeed_i2c_next_msg_or_stop(bus); -@@ -947,6 +1135,9 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus, - if (ret < 0) - return ret; - -+ fun_ctrl_reg |= FIELD_PREP(ASPEED_I2CD_BUFFER_PAGE_SEL_MASK, -+ bus->buf_page); -+ - if (of_property_read_bool(pdev->dev.of_node, "multi-master")) - bus->multi_master = true; - else -@@ -1007,16 +1198,15 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) - { - const struct of_device_id *match; - struct aspeed_i2c_bus *bus; -+ bool sram_enabled = true; - struct clk *parent_clk; -- struct resource *res; - int irq, ret; - - bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL); - if (!bus) - return -ENOMEM; - -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- bus->base = devm_ioremap_resource(&pdev->dev, res); -+ bus->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(bus->base)) - return PTR_ERR(bus->base); - -@@ -1050,6 +1240,42 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) - bus->get_clk_reg_val = (u32 (*)(struct device *, u32)) - match->data; - -+ /* Enable I2C SRAM in case of AST2500 */ -+ if (of_device_is_compatible(pdev->dev.of_node, -+ "aspeed,ast2500-i2c-bus")) { -+ struct regmap *gr_regmap = syscon_regmap_lookup_by_compatible( -+ "aspeed,ast2500-i2c-gr"); -+ if (IS_ERR(gr_regmap)) -+ ret = PTR_ERR(gr_regmap); -+ else -+ ret = regmap_update_bits(gr_regmap, -+ ASPEED_I2CG_GLOBAL_CTRL_REG, -+ ASPEED_I2CG_SRAM_BUFFER_EN, -+ ASPEED_I2CG_SRAM_BUFFER_EN); -+ -+ if (ret) -+ sram_enabled = false; -+ } -+ -+ if (sram_enabled) { -+ struct resource *res = platform_get_resource(pdev, -+ IORESOURCE_MEM, 1); -+ -+ bus->buf_base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(bus->buf_base) || resource_size(res) < 2) { -+ bus->buf_base = NULL; -+ } else { -+ bus->buf_size = resource_size(res); -+ if (of_device_is_compatible(pdev->dev.of_node, -+ "aspeed,ast2400-i2c-bus")) { -+ bus->buf_page = ((res->start >> 8) & -+ GENMASK(3, 0)) - 8; -+ bus->buf_offset = (res->start >> 2) & -+ ASPEED_I2CD_BUF_OFFSET_MASK; -+ } -+ } -+ } -+ - /* Initialize the I2C adapter */ - spin_lock_init(&bus->lock); - init_completion(&bus->cmd_complete); -@@ -1085,8 +1311,8 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) - - platform_set_drvdata(pdev, bus); - -- dev_info(bus->dev, "i2c bus %d registered, irq %d\n", -- bus->adap.nr, irq); -+ dev_info(bus->dev, "i2c bus %d registered (%s mode), irq %d\n", -+ bus->adap.nr, bus->buf_base ? "buffer" : "byte", irq); - - return 0; - } --- -2.7.4 - diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0067-i2c-aspeed-add-DMA-mode-transfer-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0067-i2c-aspeed-add-DMA-mode-transfer-support.patch deleted file mode 100644 index a051dbc4d..000000000 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0067-i2c-aspeed-add-DMA-mode-transfer-support.patch +++ /dev/null @@ -1,442 +0,0 @@ -From 7defe387ea07af3d48feb4daec78d54a284105f1 Mon Sep 17 00:00:00 2001 -From: Jae Hyun Yoo -Date: Tue, 18 Jun 2019 08:47:50 -0700 -Subject: [PATCH] i2c: aspeed: add DMA mode transfer support - -This commit adds DMA mode transfer support. - -Only AST2500 supports DMA mode under some limitations: -I2C is sharing the DMA H/W with UHCI host controller and MCTP -controller. Since those controllers operate with DMA mode only, I2C -has to use buffer mode or byte mode instead if one of those -controllers is enabled. Also make sure that if SD/eMMC or Port80 -snoop uses DMA mode instead of PIO or FIFO respectively, I2C can't -use DMA mode. - -Signed-off-by: Jae Hyun Yoo ---- - .../devicetree/bindings/i2c/i2c-aspeed.txt | 25 +++ - drivers/i2c/busses/i2c-aspeed.c | 231 +++++++++++++++++++-- - 2 files changed, 241 insertions(+), 15 deletions(-) - -diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt -index e1a0ae7a8c08..97142516399a 100644 ---- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt -+++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt -@@ -19,6 +19,16 @@ Optional Properties: - - bus-frequency : frequency of the bus clock in Hz defaults to 100 kHz when not - specified - - multi-master : states that there is another master active on this bus. -+- aspeed,dma-buf-size : size of DMA buffer (from 2 to 4095 in case of AST2500). -+ Only AST2500 supports DMA mode under some limitations: -+ I2C is sharing the DMA H/W with UHCI host controller -+ and MCTP controller. Since those controllers operate -+ with DMA mode only, I2C has to use buffer mode or byte -+ mode instead if one of those controllers is enabled. -+ Also make sure that if SD/eMMC or Port80 snoop uses -+ DMA mode instead of PIO or FIFO respectively, I2C -+ can't use DMA mode. IF both DMA and buffer modes are -+ enabled, DMA mode will be selected. - - general-call : enables general call receiving. - - bus-timeout-ms: bus timeout in milliseconds defaults to 1 second when not - specified. -@@ -75,4 +85,19 @@ i2c { - interrupts = <1>; - interrupt-parent = <&i2c_ic>; - }; -+ -+ /* DMA mode transfer enabled */ -+ i2c2: i2c-bus@c0 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ #interrupt-cells = <1>; -+ reg = <0xc0 0x40>; -+ aspeed,dma-buf-size = <4095>; -+ compatible = "aspeed,ast2500-i2c-bus"; -+ clocks = <&syscon ASPEED_CLK_APB>; -+ resets = <&syscon ASPEED_RESET_I2C>; -+ bus-frequency = <100000>; -+ interrupts = <2>; -+ interrupt-parent = <&i2c_ic>; -+ }; - }; -diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c -index b721fb1d6d4c..127bc69952ca 100644 ---- a/drivers/i2c/busses/i2c-aspeed.c -+++ b/drivers/i2c/busses/i2c-aspeed.c -@@ -10,6 +10,8 @@ - #include - #include - #include -+#include -+#include - #include - #include - #include -@@ -47,6 +49,8 @@ - #define ASPEED_I2C_DEV_ADDR_REG 0x18 - #define ASPEED_I2C_BUF_CTRL_REG 0x1c - #define ASPEED_I2C_BYTE_BUF_REG 0x20 -+#define ASPEED_I2C_DMA_ADDR_REG 0x24 -+#define ASPEED_I2C_DMA_LEN_REG 0x28 - - /* Device Register Definition */ - /* 0x00 : I2CD Function Control Register */ -@@ -112,6 +116,8 @@ - #define ASPEED_I2CD_BUS_RECOVER_CMD BIT(11) - - /* Command Bit */ -+#define ASPEED_I2CD_RX_DMA_ENABLE BIT(9) -+#define ASPEED_I2CD_TX_DMA_ENABLE BIT(8) - #define ASPEED_I2CD_RX_BUFF_ENABLE BIT(7) - #define ASPEED_I2CD_TX_BUFF_ENABLE BIT(6) - #define ASPEED_I2CD_M_STOP_CMD BIT(5) -@@ -131,6 +137,14 @@ - #define ASPEED_I2CD_BUF_TX_COUNT_MASK GENMASK(15, 8) - #define ASPEED_I2CD_BUF_OFFSET_MASK GENMASK(5, 0) - -+/* 0x24 : I2CD DMA Mode Buffer Address Register */ -+#define ASPEED_I2CD_DMA_ADDR_MASK GENMASK(31, 2) -+#define ASPEED_I2CD_DMA_ALIGN 4 -+ -+/* 0x28 : I2CD DMA Transfer Length Register */ -+#define ASPEED_I2CD_DMA_LEN_SHIFT 0 -+#define ASPEED_I2CD_DMA_LEN_MASK GENMASK(11, 0) -+ - enum aspeed_i2c_master_state { - ASPEED_I2C_MASTER_INACTIVE, - ASPEED_I2C_MASTER_PENDING, -@@ -183,6 +197,12 @@ struct aspeed_i2c_bus { - size_t buf_size; - u8 buf_offset; - u8 buf_page; -+ /* DMA mode */ -+ struct dma_pool *dma_pool; -+ dma_addr_t dma_handle; -+ u8 *dma_buf; -+ size_t dma_buf_size; -+ size_t dma_len; - #if IS_ENABLED(CONFIG_I2C_SLAVE) - struct i2c_client *slave; - enum aspeed_i2c_slave_state slave_state; -@@ -310,9 +330,13 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - - /* Slave was sent something. */ - if (irq_status & ASPEED_I2CD_INTR_RX_DONE) { -- if (bus->buf_base && -+ if (bus->dma_buf && - bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && - !(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP)) -+ value = bus->dma_buf[0]; -+ else if (bus->buf_base && -+ bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && -+ !(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP)) - value = readb(bus->buf_base); - else - value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; -@@ -347,7 +371,18 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) { - if (bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && - irq_status & ASPEED_I2CD_INTR_RX_DONE) { -- if (bus->buf_base) { -+ if (bus->dma_buf) { -+ len = bus->dma_buf_size - -+ FIELD_GET(ASPEED_I2CD_DMA_LEN_MASK, -+ readl(bus->base + -+ ASPEED_I2C_DMA_LEN_REG)); -+ for (i = 0; i < len; i++) { -+ value = bus->dma_buf[i]; -+ i2c_slave_event(slave, -+ I2C_SLAVE_WRITE_RECEIVED, -+ &value); -+ } -+ } else if (bus->buf_base) { - len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, - readl(bus->base + - ASPEED_I2C_BUF_CTRL_REG)); -@@ -391,7 +426,15 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - case ASPEED_I2C_SLAVE_WRITE_REQUESTED: - bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED; - i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); -- if (bus->buf_base) { -+ if (bus->dma_buf) { -+ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, -+ bus->base + ASPEED_I2C_DMA_ADDR_REG); -+ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, -+ bus->dma_buf_size), -+ bus->base + ASPEED_I2C_DMA_LEN_REG); -+ writel(ASPEED_I2CD_RX_DMA_ENABLE, -+ bus->base + ASPEED_I2C_CMD_REG); -+ } else if (bus->buf_base) { - writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, - bus->buf_size - 1) | - FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, -@@ -403,7 +446,25 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - break; - case ASPEED_I2C_SLAVE_WRITE_RECEIVED: - i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value); -- if (bus->buf_base) { -+ if (bus->dma_buf) { -+ len = bus->dma_buf_size - -+ FIELD_GET(ASPEED_I2CD_DMA_LEN_MASK, -+ readl(bus->base + -+ ASPEED_I2C_DMA_LEN_REG)); -+ for (i = 1; i < len; i++) { -+ value = bus->dma_buf[i]; -+ i2c_slave_event(slave, -+ I2C_SLAVE_WRITE_RECEIVED, -+ &value); -+ } -+ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, -+ bus->base + ASPEED_I2C_DMA_ADDR_REG); -+ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, -+ bus->dma_buf_size), -+ bus->base + ASPEED_I2C_DMA_LEN_REG); -+ writel(ASPEED_I2CD_RX_DMA_ENABLE, -+ bus->base + ASPEED_I2C_CMD_REG); -+ } else if (bus->buf_base) { - len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, - readl(bus->base + - ASPEED_I2C_BUF_CTRL_REG)); -@@ -472,7 +533,23 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) - if (msg->flags & I2C_M_RD) { - command |= ASPEED_I2CD_M_RX_CMD; - -- if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { -+ if (bus->dma_buf && !(msg->flags & I2C_M_RECV_LEN)) { -+ command |= ASPEED_I2CD_RX_DMA_ENABLE; -+ -+ if (msg->len > bus->dma_buf_size) { -+ len = bus->dma_buf_size; -+ } else { -+ len = msg->len; -+ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; -+ } -+ -+ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, -+ bus->base + ASPEED_I2C_DMA_ADDR_REG); -+ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, -+ len), -+ bus->base + ASPEED_I2C_DMA_LEN_REG); -+ bus->dma_len = len; -+ } else if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { - command |= ASPEED_I2CD_RX_BUFF_ENABLE; - - if (msg->len > bus->buf_size) { -@@ -493,7 +570,26 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) - command |= ASPEED_I2CD_M_S_RX_CMD_LAST; - } - } else { -- if (bus->buf_base) { -+ if (bus->dma_buf) { -+ command |= ASPEED_I2CD_TX_DMA_ENABLE; -+ -+ if (msg->len + 1 > bus->dma_buf_size) -+ len = bus->dma_buf_size; -+ else -+ len = msg->len + 1; -+ -+ bus->dma_buf[0] = slave_addr; -+ memcpy(bus->dma_buf + 1, msg->buf, len); -+ -+ bus->buf_index = len - 1; -+ -+ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, -+ bus->base + ASPEED_I2C_DMA_ADDR_REG); -+ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, -+ len), -+ bus->base + ASPEED_I2C_DMA_LEN_REG); -+ bus->dma_len = len; -+ } else if (bus->buf_base) { - int i; - - command |= ASPEED_I2CD_TX_BUFF_ENABLE; -@@ -529,7 +625,8 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) - } - } - -- if (!(command & ASPEED_I2CD_TX_BUFF_ENABLE)) -+ if (!(command & (ASPEED_I2CD_TX_BUFF_ENABLE | -+ ASPEED_I2CD_TX_DMA_ENABLE))) - writel(slave_addr, bus->base + ASPEED_I2C_BYTE_BUF_REG); - writel(command, bus->base + ASPEED_I2C_CMD_REG); - } -@@ -685,7 +782,28 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - if (bus->buf_index < msg->len) { - command = ASPEED_I2CD_M_TX_CMD; - -- if (bus->buf_base) { -+ if (bus->dma_buf) { -+ command |= ASPEED_I2CD_TX_DMA_ENABLE; -+ -+ if (msg->len - bus->buf_index > -+ bus->dma_buf_size) -+ len = bus->dma_buf_size; -+ else -+ len = msg->len - bus->buf_index; -+ -+ memcpy(bus->dma_buf, msg->buf + bus->buf_index, -+ len); -+ -+ bus->buf_index += len; -+ -+ writel(bus->dma_handle & -+ ASPEED_I2CD_DMA_ADDR_MASK, -+ bus->base + ASPEED_I2C_DMA_ADDR_REG); -+ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, -+ len), -+ bus->base + ASPEED_I2C_DMA_LEN_REG); -+ bus->dma_len = len; -+ } else if (bus->buf_base) { - u8 wbuf[4]; - int i; - -@@ -736,7 +854,15 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - } - irq_handled |= ASPEED_I2CD_INTR_RX_DONE; - -- if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { -+ if (bus->dma_buf && !(msg->flags & I2C_M_RECV_LEN)) { -+ len = bus->dma_len - -+ FIELD_GET(ASPEED_I2CD_DMA_LEN_MASK, -+ readl(bus->base + -+ ASPEED_I2C_DMA_LEN_REG)); -+ -+ memcpy(msg->buf + bus->buf_index, bus->dma_buf, len); -+ bus->buf_index += len; -+ } else if (bus->buf_base && !(msg->flags & I2C_M_RECV_LEN)) { - len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, - readl(bus->base + - ASPEED_I2C_BUF_CTRL_REG)); -@@ -764,7 +890,25 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) - if (bus->buf_index < msg->len) { - command = ASPEED_I2CD_M_RX_CMD; - bus->master_state = ASPEED_I2C_MASTER_RX; -- if (bus->buf_base) { -+ if (bus->dma_buf) { -+ command |= ASPEED_I2CD_RX_DMA_ENABLE; -+ -+ if (msg->len - bus->buf_index > -+ bus->dma_buf_size) { -+ len = bus->dma_buf_size; -+ } else { -+ len = msg->len - bus->buf_index; -+ command |= ASPEED_I2CD_M_S_RX_CMD_LAST; -+ } -+ -+ writel(bus->dma_handle & -+ ASPEED_I2CD_DMA_ADDR_MASK, -+ bus->base + ASPEED_I2C_DMA_ADDR_REG); -+ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, -+ len), -+ bus->base + ASPEED_I2C_DMA_LEN_REG); -+ bus->dma_len = len; -+ } else if (bus->buf_base) { - command |= ASPEED_I2CD_RX_BUFF_ENABLE; - - if (msg->len - bus->buf_index > -@@ -1257,7 +1401,51 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) - sram_enabled = false; - } - -- if (sram_enabled) { -+ /* -+ * Only AST2500 supports DMA mode under some limitations: -+ * I2C is sharing the DMA H/W with UHCI host controller and MCTP -+ * controller. Since those controllers operate with DMA mode only, I2C -+ * has to use buffer mode or byte mode instead if one of those -+ * controllers is enabled. Also make sure that if SD/eMMC or Port80 -+ * snoop uses DMA mode instead of PIO or FIFO respectively, I2C can't -+ * use DMA mode. -+ */ -+ if (sram_enabled && !IS_ENABLED(CONFIG_USB_UHCI_ASPEED) && -+ of_device_is_compatible(pdev->dev.of_node, -+ "aspeed,ast2500-i2c-bus")) { -+ u32 dma_len_max = ASPEED_I2CD_DMA_LEN_MASK >> -+ ASPEED_I2CD_DMA_LEN_SHIFT; -+ -+ ret = device_property_read_u32(&pdev->dev, -+ "aspeed,dma-buf-size", -+ &bus->dma_buf_size); -+ if (!ret && bus->dma_buf_size > dma_len_max) -+ bus->dma_buf_size = dma_len_max; -+ } -+ -+ if (bus->dma_buf_size) { -+ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { -+ dev_warn(&pdev->dev, "No suitable DMA available\n"); -+ } else { -+ bus->dma_pool = dma_pool_create("i2c-aspeed", -+ &pdev->dev, -+ bus->dma_buf_size, -+ ASPEED_I2CD_DMA_ALIGN, -+ 0); -+ if (bus->dma_pool) -+ bus->dma_buf = dma_pool_alloc(bus->dma_pool, -+ GFP_KERNEL, -+ &bus->dma_handle); -+ -+ if (!bus->dma_buf) { -+ dev_warn(&pdev->dev, -+ "Cannot allocate DMA buffer\n"); -+ dma_pool_destroy(bus->dma_pool); -+ } -+ } -+ } -+ -+ if (!bus->dma_buf && sram_enabled) { - struct resource *res = platform_get_resource(pdev, - IORESOURCE_MEM, 1); - -@@ -1297,24 +1485,33 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) - */ - ret = aspeed_i2c_init(bus, pdev); - if (ret < 0) -- return ret; -+ goto out_free_dma_buf; - - irq = irq_of_parse_and_map(pdev->dev.of_node, 0); - ret = devm_request_irq(&pdev->dev, irq, aspeed_i2c_bus_irq, - 0, dev_name(&pdev->dev), bus); - if (ret < 0) -- return ret; -+ goto out_free_dma_buf; - - ret = i2c_add_adapter(&bus->adap); - if (ret < 0) -- return ret; -+ goto out_free_dma_buf; - - platform_set_drvdata(pdev, bus); - - dev_info(bus->dev, "i2c bus %d registered (%s mode), irq %d\n", -- bus->adap.nr, bus->buf_base ? "buffer" : "byte", irq); -+ bus->adap.nr, bus->dma_buf ? "dma" : -+ bus->buf_base ? "buffer" : "byte", -+ irq); - - return 0; -+ -+out_free_dma_buf: -+ if (bus->dma_buf) -+ dma_pool_free(bus->dma_pool, bus->dma_buf, bus->dma_handle); -+ dma_pool_destroy(bus->dma_pool); -+ -+ return ret; - } - - static int aspeed_i2c_remove_bus(struct platform_device *pdev) -@@ -1332,6 +1529,10 @@ static int aspeed_i2c_remove_bus(struct platform_device *pdev) - - reset_control_assert(bus->rst); - -+ if (bus->dma_buf) -+ dma_pool_free(bus->dma_pool, bus->dma_buf, bus->dma_handle); -+ dma_pool_destroy(bus->dma_pool); -+ - i2c_del_adapter(&bus->adap); - - return 0; --- -2.7.4 - diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0068-i2c-aspeed-add-H-W-timeout-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0068-i2c-aspeed-add-H-W-timeout-support.patch index f4dfd6cfa..ba564e695 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0068-i2c-aspeed-add-H-W-timeout-support.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0068-i2c-aspeed-add-H-W-timeout-support.patch @@ -1,4 +1,4 @@ -From 9a43b47fb794fd195912c6956783b021a46307f8 Mon Sep 17 00:00:00 2001 +From 25a38287274f9c39eb8355d51ba06203efdb07aa Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Thu, 11 Jul 2019 13:53:34 -0700 Subject: [PATCH] i2c: aspeed: add H/W timeout support @@ -7,14 +7,22 @@ This commit adds I2C H/W timeout support. Signed-off-by: Jae Hyun Yoo --- - drivers/i2c/busses/i2c-aspeed.c | 79 +++++++++++++++++++++++++++++++++++++---- - 1 file changed, 73 insertions(+), 6 deletions(-) + drivers/i2c/busses/i2c-aspeed.c | 82 ++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 76 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c -index 0ed9a27850e6..ecb5793036cc 100644 +index 127bc69952ca..542b0f4017eb 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c -@@ -71,10 +71,14 @@ +@@ -55,6 +55,7 @@ + /* Device Register Definition */ + /* 0x00 : I2CD Function Control Register */ + #define ASPEED_I2CD_BUFFER_PAGE_SEL_MASK GENMASK(22, 20) ++#define ASPEED_I2CD_BUS_AUTO_RECOVERY_EN BIT(17) + #define ASPEED_I2CD_MULTI_MASTER_DIS BIT(15) + #define ASPEED_I2CD_SDA_DRIVE_1T_EN BIT(8) + #define ASPEED_I2CD_M_SDA_DRIVE_1T_EN BIT(7) +@@ -71,10 +72,14 @@ #define ASPEED_I2CD_TIME_SCL_HIGH_MASK GENMASK(19, 16) #define ASPEED_I2CD_TIME_SCL_LOW_SHIFT 12 #define ASPEED_I2CD_TIME_SCL_LOW_MASK GENMASK(15, 12) @@ -30,7 +38,7 @@ index 0ed9a27850e6..ecb5793036cc 100644 /* 0x0c : I2CD Interrupt Control Register & * 0x10 : I2CD Interrupt Status Register -@@ -82,6 +86,7 @@ +@@ -82,6 +87,7 @@ * These share bit definitions, so use the same values for the enable & * status bits. */ @@ -38,7 +46,7 @@ index 0ed9a27850e6..ecb5793036cc 100644 #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14) #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13) #define ASPEED_I2CD_INTR_GCALL_ADDR BIT(8) -@@ -98,8 +103,11 @@ +@@ -98,8 +104,11 @@ ASPEED_I2CD_INTR_SCL_TIMEOUT | \ ASPEED_I2CD_INTR_ABNORMAL | \ ASPEED_I2CD_INTR_ARBIT_LOSS) @@ -51,7 +59,7 @@ index 0ed9a27850e6..ecb5793036cc 100644 ASPEED_I2CD_INTR_BUS_RECOVER_DONE | \ ASPEED_I2CD_INTR_SCL_TIMEOUT | \ ASPEED_I2CD_INTR_ABNORMAL | \ -@@ -180,6 +188,7 @@ struct aspeed_i2c_bus { +@@ -180,6 +189,7 @@ struct aspeed_i2c_bus { u32 divisor); unsigned long parent_clk_frequency; u32 bus_frequency; @@ -59,7 +67,7 @@ index 0ed9a27850e6..ecb5793036cc 100644 /* Transaction state. */ enum aspeed_i2c_master_state master_state; struct i2c_msg *msgs; -@@ -297,6 +306,14 @@ static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus) +@@ -297,6 +307,14 @@ static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus) } #if IS_ENABLED(CONFIG_I2C_SLAVE) @@ -74,7 +82,7 @@ index 0ed9a27850e6..ecb5793036cc 100644 static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) { u32 command, irq_handled = 0; -@@ -307,6 +324,14 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) +@@ -307,6 +325,14 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) if (!slave) return 0; @@ -89,7 +97,7 @@ index 0ed9a27850e6..ecb5793036cc 100644 command = readl(bus->base + ASPEED_I2C_CMD_REG); /* Slave was requested, restart state machine. */ -@@ -649,7 +674,7 @@ static void aspeed_i2c_next_msg_or_stop(struct aspeed_i2c_bus *bus) +@@ -649,7 +675,7 @@ static void aspeed_i2c_next_msg_or_stop(struct aspeed_i2c_bus *bus) } } @@ -98,7 +106,7 @@ index 0ed9a27850e6..ecb5793036cc 100644 { if (irq_status & ASPEED_I2CD_INTR_ARBIT_LOSS) return -EAGAIN; -@@ -680,9 +705,9 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) +@@ -680,9 +706,9 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) * should clear the command queue effectively taking us back to the * INACTIVE state. */ @@ -110,7 +118,7 @@ index 0ed9a27850e6..ecb5793036cc 100644 irq_status); irq_handled |= (irq_status & ASPEED_I2CD_INTR_MASTER_ERRORS); if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) { -@@ -1251,6 +1276,7 @@ static u32 aspeed_i2c_25xx_get_clk_reg_val(struct device *dev, u32 divisor) +@@ -1251,6 +1277,7 @@ static u32 aspeed_i2c_25xx_get_clk_reg_val(struct device *dev, u32 divisor) /* precondition: bus.lock has been acquired. */ static int aspeed_i2c_init_clk(struct aspeed_i2c_bus *bus) { @@ -118,7 +126,7 @@ index 0ed9a27850e6..ecb5793036cc 100644 u32 divisor, clk_reg_val; divisor = DIV_ROUND_UP(bus->parent_clk_frequency, bus->bus_frequency); -@@ -1259,8 +1285,46 @@ static int aspeed_i2c_init_clk(struct aspeed_i2c_bus *bus) +@@ -1259,8 +1286,46 @@ static int aspeed_i2c_init_clk(struct aspeed_i2c_bus *bus) ASPEED_I2CD_TIME_THDSTA_MASK | ASPEED_I2CD_TIME_TACST_MASK); clk_reg_val |= bus->get_clk_reg_val(bus->dev, divisor); @@ -166,16 +174,18 @@ index 0ed9a27850e6..ecb5793036cc 100644 return 0; } -@@ -1464,6 +1528,9 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) - } - } +@@ -1275,6 +1340,11 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus, + /* Disable everything. */ + writel(0, bus->base + ASPEED_I2C_FUN_CTRL_REG); + device_property_read_u32(&pdev->dev, "aspeed,hw-timeout-ms", + &bus->hw_timeout_ms); ++ if (bus->hw_timeout_ms) ++ fun_ctrl_reg |= ASPEED_I2CD_BUS_AUTO_RECOVERY_EN; + - /* Initialize the I2C adapter */ - spin_lock_init(&bus->lock); - init_completion(&bus->cmd_complete); + ret = aspeed_i2c_init_clk(bus); + if (ret < 0) + return ret; -- 2.7.4 diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch index dc38c81f3..8fc35243c 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch @@ -1,4 +1,4 @@ -From 085bde1e91d85435c44a752bd59d38cf31465518 Mon Sep 17 00:00:00 2001 +From 6ffb52e1f1d80fd3116fccef045bcdc78d2d361c Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Thu, 11 Jul 2019 14:04:39 -0700 Subject: [PATCH] i2c: aspeed: add SLAVE_ADDR_RECEIVED_PENDING interrupt @@ -15,10 +15,10 @@ Signed-off-by: Jae Hyun Yoo 1 file changed, 13 insertions(+) diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c -index d41f377de9dc..46de9a01a0eb 100644 +index bcc354d11e29..0070366e9d6d 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c -@@ -86,6 +86,7 @@ +@@ -87,6 +87,7 @@ * These share bit definitions, so use the same values for the enable & * status bits. */ @@ -26,7 +26,7 @@ index d41f377de9dc..46de9a01a0eb 100644 #define ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT BIT(15) #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14) #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13) -@@ -353,6 +354,18 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) +@@ -354,6 +355,18 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n", irq_status, command); diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch index 4af5be95d..bcee8bc6c 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch @@ -1,4 +1,4 @@ -From 9195eef3fec7022ca52ac9791c19de2362ed042e Mon Sep 17 00:00:00 2001 +From 89e1d083726d4d56703a6787f4707d61a2c0efd1 Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Fri, 19 Jul 2019 12:54:38 -0700 Subject: [PATCH] gpio: aspeed: temporary fix for gpiochip range setting @@ -14,31 +14,31 @@ Signed-off-by: Jae Hyun Yoo 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c -index e426452a28f7..d4aaf7fa8e4b 100644 +index ac33f8134fe6..4f1a40b3a73f 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c -@@ -1189,7 +1189,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) +@@ -1181,7 +1181,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) gpio->chip.set = aspeed_gpio_set; gpio->chip.set_config = aspeed_gpio_set_config; gpio->chip.label = dev_name(&pdev->dev); - gpio->chip.base = -1; + gpio->chip.base = 0; - gpio->chip.irq.need_valid_mask = true; /* Allocate a cache of the output registers */ + banks = DIV_ROUND_UP(gpio->chip.ngpio, 32); diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c -index 6fb402a3f74d..2f4c0aab0bf2 100644 +index d2dbfce531a4..792ef0d70ecf 100644 --- a/drivers/gpio/sgpio-aspeed.c +++ b/drivers/gpio/sgpio-aspeed.c -@@ -675,7 +675,7 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev) +@@ -678,7 +678,7 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev) gpio->chip.set = aspeed_sgpio_set; gpio->chip.set_config = aspeed_sgpio_set_config; gpio->chip.label = dev_name(&pdev->dev); - gpio->chip.base = -1; + gpio->chip.base = gpio->config->nr_pgpios; - gpio->chip.irq.need_valid_mask = true; - /* Allocate a cache of the output registers */ + rc = aspeed_sgpio_setup_irqs(gpio, pdev); + if (rc < 0) -- 2.7.4 diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0071-peci-add-a-temporary-workaround.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0071-peci-add-a-temporary-workaround.patch deleted file mode 100644 index e32ec54ac..000000000 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0071-peci-add-a-temporary-workaround.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 3394fabbd17ad7263feeb0f4ae593056237f0647 Mon Sep 17 00:00:00 2001 -From: Jae Hyun Yoo -Date: Tue, 30 Jul 2019 13:01:58 -0700 -Subject: [PATCH] peci: add a temporary workaround - -To cover a PECI issue, this commit makes PECI driver block all PECI -commands when PLTRST_N signal is 0. - -Also, it adds 'use_wa' module parameter for platforms that don't have -the PLTRST_N gpio input so that the WA can be disabled through the -module parameter. - -This is a temporary workaround. - -Signed-off-by: Jae Hyun Yoo ---- - drivers/peci/busses/peci-aspeed.c | 11 +++++++++++ - drivers/peci/peci-core.c | 11 +++++++++++ - include/linux/peci.h | 1 + - 3 files changed, 23 insertions(+) - -diff --git a/drivers/peci/busses/peci-aspeed.c b/drivers/peci/busses/peci-aspeed.c -index 8a0dd40730cc..76394ab32854 100644 ---- a/drivers/peci/busses/peci-aspeed.c -+++ b/drivers/peci/busses/peci-aspeed.c -@@ -10,6 +10,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -445,6 +446,16 @@ static int aspeed_peci_probe(struct platform_device *pdev) - if (ret) - goto err_put_adapter_dev; - -+ priv->adapter->pltrst_pin = of_get_gpio(pdev->dev.of_node, 0); -+ if (gpio_is_valid(priv->adapter->pltrst_pin)) { -+ ret = devm_gpio_request(&pdev->dev, priv->adapter->pltrst_pin, -+ "peci-aspeed"); -+ if (ret < 0) { -+ priv->adapter->pltrst_pin = -1; -+ dev_err(&pdev->dev, "error requesting pltrst gpio\n"); -+ } -+ } -+ - ret = peci_add_adapter(priv->adapter); - if (ret) - goto err_put_adapter_dev; -diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c -index b99ba788a032..2e3b9a0c83e9 100644 ---- a/drivers/peci/peci-core.c -+++ b/drivers/peci/peci-core.c -@@ -5,6 +5,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -190,6 +191,11 @@ static int peci_aw_fcs(struct peci_xfer_msg *msg, int len, u8 *aw_fcs) - return 0; - } - -+/* Temporary WA */ -+static bool use_wa __read_mostly = true; -+module_param_named(use_wa, use_wa, bool, 0644); -+MODULE_PARM_DESC(use_wa, "flag for enabling of WA"); -+ - static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg, - bool do_retry, bool has_aw_fcs) - { -@@ -197,6 +203,11 @@ static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg, - u8 aw_fcs; - int ret; - -+ /* Temporary WA */ -+ if (use_wa && gpio_is_valid(adapter->pltrst_pin) && -+ gpio_get_value(adapter->pltrst_pin) == 0) -+ return -EAGAIN; -+ - /* - * In case if adapter uses DMA, check at here whether tx and rx buffers - * are DMA capable or not. -diff --git a/include/linux/peci.h b/include/linux/peci.h -index 6fc424dc2a73..e589cb258a2a 100644 ---- a/include/linux/peci.h -+++ b/include/linux/peci.h -@@ -44,6 +44,7 @@ struct peci_adapter { - struct peci_xfer_msg *msg); - u32 cmd_mask; - bool use_dma; -+ int pltrst_pin; - }; - - static inline struct peci_adapter *to_peci_adapter(void *d) --- -2.7.4 - diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0073-Add-IO-statistics-to-USB-Mass-storage-gadget.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0073-Add-IO-statistics-to-USB-Mass-storage-gadget.patch new file mode 100644 index 000000000..41969349e --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0073-Add-IO-statistics-to-USB-Mass-storage-gadget.patch @@ -0,0 +1,155 @@ +From 5c82e0b33f2a373d5e19569635f108cfa096f53e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Adrian=20Ambro=C5=BCewicz?= +Date: Mon, 29 Jul 2019 10:19:00 +0200 +Subject: [PATCH] Add IO stats to USB Mass Storage gadget +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Introduces new attribute to Mass Storage Gadget ConfigFS : stats. +It's read-only attribute which contains statistics of read/write operations +based on LUN transaction counters (IO number and bytes transferred). + +Goal is to provide a way to observe whether simulated device is actually +used by host. Statistics on hosted file / nbd level are not always viable +due to page cache having severe impact on actual IO statistics. +This attribute should provide information about host IO on USB Gadget as +close to endpoint as possible. + +Attribute is tied completely to configFS implementation and it's lifecycle +is managed by Kernel and user. Driver implements a handler which populates +output buffer on read. + +Tests performed: +- mounted USB Mass Storage gadget, new attribute showed up in gadget tree +- attribute was monitored for changes during IO performed on host machine +- removed device, attribute (along with other device attributes) was gone + +Signed-off-by: Adrian Ambrożewicz +--- + drivers/usb/gadget/function/f_mass_storage.c | 12 ++++++++++++ + drivers/usb/gadget/function/storage_common.c | 9 +++++++++ + drivers/usb/gadget/function/storage_common.h | 29 ++++++++++++++++++++++++++++ + 3 files changed, 50 insertions(+) + +diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c +index 7c96c4665178..ecc3c68a7882 100644 +--- a/drivers/usb/gadget/function/f_mass_storage.c ++++ b/drivers/usb/gadget/function/f_mass_storage.c +@@ -710,6 +710,8 @@ static int do_read(struct fsg_common *common) + amount_left -= nread; + common->residue -= nread; + ++ fsg_stats_rd_attempt(&curlun->stats, nread); ++ + /* + * Except at the end of the transfer, nread will be + * equal to the buffer size, which is divisible by the +@@ -907,6 +909,8 @@ static int do_write(struct fsg_common *common) + amount_left_to_write -= nwritten; + common->residue -= nwritten; + ++ fsg_stats_wr_attempt(&curlun->stats, nwritten); ++ + /* If an error occurred, report it and its position */ + if (nwritten < amount) { + curlun->sense_data = SS_WRITE_ERROR; +@@ -3122,6 +3126,13 @@ static ssize_t fsg_lun_opts_inquiry_string_store(struct config_item *item, + + CONFIGFS_ATTR(fsg_lun_opts_, inquiry_string); + ++static ssize_t fsg_lun_opts_stats_show(struct config_item *item, char *page) ++{ ++ return fsg_show_stats(to_fsg_lun_opts(item)->lun, page); ++} ++ ++CONFIGFS_ATTR_RO(fsg_lun_opts_, stats); ++ + static struct configfs_attribute *fsg_lun_attrs[] = { + &fsg_lun_opts_attr_file, + &fsg_lun_opts_attr_ro, +@@ -3129,6 +3140,7 @@ static struct configfs_attribute *fsg_lun_attrs[] = { + &fsg_lun_opts_attr_cdrom, + &fsg_lun_opts_attr_nofua, + &fsg_lun_opts_attr_inquiry_string, ++ &fsg_lun_opts_attr_stats, + NULL, + }; + +diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c +index f7e6c42558eb..2325b97961df 100644 +--- a/drivers/usb/gadget/function/storage_common.c ++++ b/drivers/usb/gadget/function/storage_common.c +@@ -371,6 +371,15 @@ ssize_t fsg_show_inquiry_string(struct fsg_lun *curlun, char *buf) + } + EXPORT_SYMBOL_GPL(fsg_show_inquiry_string); + ++ssize_t fsg_show_stats(struct fsg_lun *curlun, char *buf) ++{ ++ return sprintf(buf, "read cnt: %u\n" "read sum: %llu\n" ++ "write cnt: %u\n" "write sum: %llu\n", ++ curlun->stats.read.count, curlun->stats.read.bytes, ++ curlun->stats.write.count, curlun->stats.write.bytes); ++} ++EXPORT_SYMBOL_GPL(fsg_show_stats); ++ + /* + * The caller must hold fsg->filesem for reading when calling this function. + */ +diff --git a/drivers/usb/gadget/function/storage_common.h b/drivers/usb/gadget/function/storage_common.h +index e5e3a2553aaa..447021ba821a 100644 +--- a/drivers/usb/gadget/function/storage_common.h ++++ b/drivers/usb/gadget/function/storage_common.h +@@ -95,6 +95,32 @@ do { \ + */ + #define INQUIRY_STRING_LEN ((size_t) (8 + 16 + 4 + 1)) + ++struct fsg_stats_cnt { ++ u64 bytes; ++ u32 count; ++}; ++ ++struct fsg_stats { ++ struct fsg_stats_cnt read; ++ struct fsg_stats_cnt write; ++}; ++ ++static inline void fsg_stats_update(struct fsg_stats_cnt *cnt, u64 diff) ++{ ++ cnt->count++; ++ cnt->bytes += diff; ++} ++ ++static inline void fsg_stats_wr_attempt(struct fsg_stats *stats, u64 b_written) ++{ ++ fsg_stats_update(&stats->write, b_written); ++} ++ ++static inline void fsg_stats_rd_attempt(struct fsg_stats *stats, u64 b_read) ++{ ++ fsg_stats_update(&stats->read, b_read); ++} ++ + struct fsg_lun { + struct file *filp; + loff_t file_length; +@@ -120,6 +146,8 @@ struct fsg_lun { + const char *name; /* "lun.name" */ + const char **name_pfx; /* "function.name" */ + char inquiry_string[INQUIRY_STRING_LEN]; ++ ++ struct fsg_stats stats; + }; + + static inline bool fsg_lun_is_open(struct fsg_lun *curlun) +@@ -213,6 +241,7 @@ ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, + ssize_t fsg_show_inquiry_string(struct fsg_lun *curlun, char *buf); + ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf); + ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf); ++ssize_t fsg_show_stats(struct fsg_lun *curlun, char *buf); + ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, + const char *buf, size_t count); + ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count); +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0074-media-aspeed-refine-HSYNC-VSYNC-polarity-setting-log.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0074-media-aspeed-refine-HSYNC-VSYNC-polarity-setting-log.patch new file mode 100644 index 000000000..4118e366c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0074-media-aspeed-refine-HSYNC-VSYNC-polarity-setting-log.patch @@ -0,0 +1,93 @@ +From 1032b062669b7ee041d2f5a9f4729953655efe61 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo +Date: Wed, 4 Sep 2019 14:52:40 -0700 +Subject: [PATCH] media: aspeed: refine HSYNC/VSYNC polarity setting logic + +Sometimes it detects weird resolutions such as 1024x287 when the +actual resolution is 1280x768. To resolve this issue, this commit +refines HSYNC/VSYNC polarity setting code for mode detection by +clearing the bits as normal polarity at the beginning of the first +mode detection like datasheet suggested, and refines polarity +setting logic so that the bits can be set or cleared properly. + +Signed-off-by: Jae Hyun Yoo +--- + drivers/media/platform/aspeed-video.c | 45 ++++++++++++++++++----------------- + 1 file changed, 23 insertions(+), 22 deletions(-) + +diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c +index 4ef37cfc8446..455c6af81236 100644 +--- a/drivers/media/platform/aspeed-video.c ++++ b/drivers/media/platform/aspeed-video.c +@@ -614,7 +614,7 @@ static void aspeed_video_check_and_set_polarity(struct aspeed_video *video) + int i; + int hsync_counter = 0; + int vsync_counter = 0; +- u32 sts; ++ u32 sts, ctrl; + + for (i = 0; i < NUM_POLARITY_CHECKS; ++i) { + sts = aspeed_video_read(video, VE_MODE_DETECT_STATUS); +@@ -629,30 +629,29 @@ static void aspeed_video_check_and_set_polarity(struct aspeed_video *video) + hsync_counter++; + } + +- if (hsync_counter < 0 || vsync_counter < 0) { +- u32 ctrl = 0; ++ ctrl = aspeed_video_read(video, VE_CTRL); + +- if (hsync_counter < 0) { +- ctrl = VE_CTRL_HSYNC_POL; +- video->detected_timings.polarities &= +- ~V4L2_DV_HSYNC_POS_POL; +- } else { +- video->detected_timings.polarities |= +- V4L2_DV_HSYNC_POS_POL; +- } +- +- if (vsync_counter < 0) { +- ctrl = VE_CTRL_VSYNC_POL; +- video->detected_timings.polarities &= +- ~V4L2_DV_VSYNC_POS_POL; +- } else { +- video->detected_timings.polarities |= +- V4L2_DV_VSYNC_POS_POL; +- } ++ if (hsync_counter < 0) { ++ ctrl |= VE_CTRL_HSYNC_POL; ++ video->detected_timings.polarities &= ++ ~V4L2_DV_HSYNC_POS_POL; ++ } else { ++ ctrl &= ~VE_CTRL_HSYNC_POL; ++ video->detected_timings.polarities |= ++ V4L2_DV_HSYNC_POS_POL; ++ } + +- if (ctrl) +- aspeed_video_update(video, VE_CTRL, 0, ctrl); ++ if (vsync_counter < 0) { ++ ctrl |= VE_CTRL_VSYNC_POL; ++ video->detected_timings.polarities &= ++ ~V4L2_DV_VSYNC_POS_POL; ++ } else { ++ ctrl &= ~VE_CTRL_VSYNC_POL; ++ video->detected_timings.polarities |= ++ V4L2_DV_VSYNC_POS_POL; + } ++ ++ aspeed_video_write(video, VE_CTRL, ctrl); + } + + static bool aspeed_video_alloc_buf(struct aspeed_video *video, +@@ -741,6 +740,8 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) + } + + set_bit(VIDEO_RES_DETECT, &video->flags); ++ aspeed_video_update(video, VE_CTRL, ++ VE_CTRL_VSYNC_POL | VE_CTRL_HSYNC_POL, 0); + aspeed_video_enable_mode_detect(video); + + rc = wait_event_interruptible_timeout(video->wait, +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0075-Refine-initialization-flow-in-I2C-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0075-Refine-initialization-flow-in-I2C-driver.patch new file mode 100644 index 000000000..363f25368 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0075-Refine-initialization-flow-in-I2C-driver.patch @@ -0,0 +1,64 @@ +From a98e86429ce520cab3505c76ce02703837ef79b9 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo +Date: Mon, 23 Sep 2019 13:48:49 -0700 +Subject: [PATCH] Refine initialization flow in I2C driver + +Since we enabled I2C busses in u-boot, we need to disable the I2C +bus and clear all garbage interrupts when kernel probes the bus. +This commit refines the initialization flow by adding a bus reset +at the beginning of probe function and by moving bus init function +after interrupt handling setup. + +Signed-off-by: Jae Hyun Yoo +--- + drivers/i2c/busses/i2c-aspeed.c | 20 +++++++++----------- + 1 file changed, 9 insertions(+), 11 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c +index 0070366e9d6d..ab771a57a252 100644 +--- a/drivers/i2c/busses/i2c-aspeed.c ++++ b/drivers/i2c/busses/i2c-aspeed.c +@@ -1441,6 +1441,11 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + if (IS_ERR(bus->base)) + return PTR_ERR(bus->base); + ++ /* Disable bus and clean up any left over interrupt state. */ ++ writel(0, bus->base + ASPEED_I2C_FUN_CTRL_REG); ++ writel(0, bus->base + ASPEED_I2C_INTR_CTRL_REG); ++ writel(0xffffffff, bus->base + ASPEED_I2C_INTR_STS_REG); ++ + parent_clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(parent_clk)) + return PTR_ERR(parent_clk); +@@ -1563,17 +1568,6 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + + bus->dev = &pdev->dev; + +- /* Clean up any left over interrupt state. */ +- writel(0, bus->base + ASPEED_I2C_INTR_CTRL_REG); +- writel(0xffffffff, bus->base + ASPEED_I2C_INTR_STS_REG); +- /* +- * bus.lock does not need to be held because the interrupt handler has +- * not been enabled yet. +- */ +- ret = aspeed_i2c_init(bus, pdev); +- if (ret < 0) +- goto out_free_dma_buf; +- + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + ret = devm_request_irq(&pdev->dev, irq, aspeed_i2c_bus_irq, + 0, dev_name(&pdev->dev), bus); +@@ -1586,6 +1580,10 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) + + platform_set_drvdata(pdev, bus); + ++ ret = aspeed_i2c_init(bus, pdev); ++ if (ret < 0) ++ goto out_free_dma_buf; ++ + dev_info(bus->dev, "i2c bus %d registered (%s mode), irq %d\n", + bus->adap.nr, bus->dma_buf ? "dma" : + bus->buf_base ? "buffer" : "byte", +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0076-media-aspeed-clear-garbage-interrupts.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0076-media-aspeed-clear-garbage-interrupts.patch new file mode 100644 index 000000000..0cf9913fe --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0076-media-aspeed-clear-garbage-interrupts.patch @@ -0,0 +1,74 @@ +From 5f89fa4b6468771b5de6e73454bf0ea546249b7b Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo +Date: Thu, 26 Sep 2019 12:15:23 -0700 +Subject: [PATCH] media: aspeed: clear garbage interrupts + +CAPTURE_COMPLETE and FRAME_COMPLETE interrupts come even when these +are disabled in the VE_INTERRUPT_CTRL register and eventually this +behavior causes disabling irq itself like below: + +[10055.108784] irq 23: nobody cared (try booting with the "irqpoll" option) +[10055.115525] CPU: 0 PID: 331 Comm: swampd Tainted: G W 5.3.0-4fde000-dirty-d683e2e #1 +[10055.124565] Hardware name: Generic DT based system +[10055.129355] Backtrace: +[10055.131854] [<80107d7c>] (dump_backtrace) from [<80107fb0>] (show_stack+0x20/0x24) +[10055.139431] r7:00000017 r6:00000001 r5:00000000 r4:9d51dc00 +[10055.145120] [<80107f90>] (show_stack) from [<8074bf50>] (dump_stack+0x20/0x28) +[10055.152361] [<8074bf30>] (dump_stack) from [<80150ffc>] (__report_bad_irq+0x40/0xc0) +[10055.160109] [<80150fbc>] (__report_bad_irq) from [<80150f2c>] (note_interrupt+0x23c/0x294) +[10055.168374] r9:015b6e60 r8:00000000 r7:00000017 r6:00000001 r5:00000000 r4:9d51dc00 +[10055.176136] [<80150cf0>] (note_interrupt) from [<8014df1c>] (handle_irq_event_percpu+0x88/0x98) +[10055.184835] r10:7eff7910 r9:015b6e60 r8:00000000 r7:9d417600 r6:00000001 r5:00000002 +[10055.192657] r4:9d51dc00 r3:00000000 +[10055.196248] [<8014de94>] (handle_irq_event_percpu) from [<8014df64>] (handle_irq_event+0x38/0x4c) +[10055.205113] r5:80b56d50 r4:9d51dc00 +[10055.208697] [<8014df2c>] (handle_irq_event) from [<80151f1c>] (handle_level_irq+0xbc/0x12c) +[10055.217037] r5:80b56d50 r4:9d51dc00 +[10055.220623] [<80151e60>] (handle_level_irq) from [<8014d4b8>] (generic_handle_irq+0x30/0x44) +[10055.229052] r5:80b56d50 r4:00000017 +[10055.232648] [<8014d488>] (generic_handle_irq) from [<8014d524>] (__handle_domain_irq+0x58/0xb4) +[10055.241356] [<8014d4cc>] (__handle_domain_irq) from [<801021e4>] (avic_handle_irq+0x68/0x70) +[10055.249797] r9:015b6e60 r8:00c5387d r7:00c5387d r6:ffffffff r5:9dd33fb0 r4:9d402380 +[10055.257539] [<8010217c>] (avic_handle_irq) from [<80101e34>] (__irq_usr+0x54/0x80) +[10055.265105] Exception stack(0x9dd33fb0 to 0x9dd33ff8) +[10055.270152] 3fa0: 015d0530 00000000 00000000 015d0538 +[10055.278328] 3fc0: 015d0530 015b6e60 00000000 00000000 0052c5d0 015b6e60 7eff7910 7eff7918 +[10055.286496] 3fe0: 76ce5614 7eff7908 0050e2f4 76a3a08c 20000010 ffffffff +[10055.293104] r5:20000010 r4:76a3a08c +[10055.296673] handlers: +[10055.298967] [<79f218a5>] irq_default_primary_handler threaded [<1de88514>] aspeed_video_irq +[10055.307344] Disabling IRQ #23 + +To fix this issue, this commit makes the interrupt handler clear +these garbage interrupts. This driver enables and uses only +COMP_COMPLETE interrupt. + +Signed-off-by: Jae Hyun Yoo +--- + drivers/media/platform/aspeed-video.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c +index 455c6af81236..0473f3141329 100644 +--- a/drivers/media/platform/aspeed-video.c ++++ b/drivers/media/platform/aspeed-video.c +@@ -606,6 +606,16 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) + aspeed_video_start_frame(video); + } + ++ /* ++ * CAPTURE_COMPLETE and FRAME_COMPLETE interrupts come even when these ++ * are disabled in the VE_INTERRUPT_CTRL register so clear them to ++ * prevent unnecessary interrupt calls. ++ */ ++ if (sts & VE_INTERRUPT_CAPTURE_COMPLETE) ++ sts &= ~VE_INTERRUPT_CAPTURE_COMPLETE; ++ if (sts & VE_INTERRUPT_FRAME_COMPLETE) ++ sts &= ~VE_INTERRUPT_FRAME_COMPLETE; ++ + return sts ? IRQ_NONE : IRQ_HANDLED; + } + +-- +2.7.4 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg index 41530dd6e..2a4e87d80 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg @@ -1 +1,74 @@ CONFIG_BLK_DEV_RAM=y +CONFIG_HWMON=y +CONFIG_SENSORS_ASPEED=y +CONFIG_SPI=y +CONFIG_SPI_MASTER=y +CONFIG_IIO=y +CONFIG_SENSORS_IIO_HWMON=y +CONFIG_ASPEED_ADC=y +CONFIG_SGPIO_ASPEED=y +CONFIG_CRC8=y +CONFIG_PECI=y +CONFIG_PECI_CHARDEV=y +CONFIG_PECI_ASPEED=y +CONFIG_SENSORS_PECI_CPUTEMP=y +CONFIG_SENSORS_PECI_DIMMTEMP=y +CONFIG_CONFIGFS_FS=y +CONFIG_BLK_DEV_RAM_SIZE=49152 +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x01 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_ASPEED_ESPI_SLAVE=y +CONFIG_ASPEED_KCS_IPMI_BMC=y +CONFIG_I2C_SLAVE=y +CONFIG_I2C_SLAVE_MQUEUE=y +CONFIG_I2C_SLAVE_MQUEUE_MESSAGE_SIZE=256 +CONFIG_I2C_SLAVE_MQUEUE_QUEUE_SIZE=32 +CONFIG_ASPEED_BT_IPMI_BMC=n +CONFIG_ASPEED_LPC_CTRL=n +CONFIG_ASPEED_LPC_MBOX=y +CONFIG_ASPEED_LPC_SIO=y +CONFIG_JTAG=y +CONFIG_JTAG_ASPEED=y +CONFIG_FRAME_VECTOR=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_ASPEED=y +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_V4L2=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 +CONFIG_USB_LIBCOMPOSITE=y +CONFIG_USB_F_HID=y +CONFIG_USB_GADGET=y +CONFIG_U_SERIAL_CONSOLE=y +CONFIG_USB_ASPEED_VHUB=y +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_ASPEED_UART_ROUTING=y +CONFIG_ASPEED_VGA_SHAREDMEM=y +CONFIG_PWM=y +CONFIG_PWM_FTTMR010=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PWM_BEEPER=y +CONFIG_VFAT_FS=y +CONFIG_NLS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_15=y +CONFIG_NLS_UTF8=y +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_CIFS=y +CONFIG_CIFS_XATTR=y +CONFIG_PSTORE=y +CONFIG_PSTORE_ZLIB_COMPRESS=y +CONFIG_PSTORE_RAM=y diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend index 8ff89685b..a901ce9db 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend @@ -7,11 +7,17 @@ do_compile_prepend(){ SRC_URI += " \ file://intel.cfg \ - file://0005-arm-dts-aspeed-g5-add-espi.patch \ - file://0007-New-flash-map-for-intel.patch \ - file://0008-Add-ASPEED-SGPIO-driver.patch \ - file://0009-SGPIO-DT-and-pinctrl-fixup.patch \ - file://0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch \ + file://0001-arm-dts-add-DTS-for-Intel-platforms.patch \ + file://0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch \ + file://0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch \ + file://0006-Allow-monitoring-of-power-control-input-GPIOs.patch \ + file://0007-aspeed-pwm-tacho-change-default-fan-speed.patch \ + file://0008-Report-link-statistics-for-the-NCSI-channel.patch \ + file://0014-arm-dts-aspeed-g5-add-espi.patch \ + file://0015-New-flash-map-for-intel.patch \ + file://0016-Add-ASPEED-SGPIO-driver.patch \ + file://0017-SGPIO-DT-and-pinctrl-fixup.patch \ + file://0018-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch \ file://0019-Add-I2C-IPMB-support.patch \ file://0020-misc-aspeed-add-lpc-mbox-driver.patch \ file://0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch \ @@ -38,14 +44,19 @@ SRC_URI += " \ file://0055-Documentation-jtag-Add-ABI-documentation.patch \ file://0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch \ file://0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch \ - file://0058-i2c-aspeed-add-general-call-support.patch \ - file://0065-i2c-aspeed-fix-master-pending-state-handling.patch \ - file://0066-i2c-aspeed-add-buffer-mode-transfer-support.patch \ - file://0067-i2c-aspeed-add-DMA-mode-transfer-support.patch \ - file://0001-set-idle-disconnect-to-true-in-all-cases.patch \ + file://0060-i2c-aspeed-fix-master-pending-state-handling.patch \ + file://0061-i2c-aspeed-add-buffer-mode-transfer-support.patch \ + file://0062-i2c-aspeed-add-DMA-mode-transfer-support.patch \ + file://0063-i2c-aspeed-add-general-call-support.patch \ + file://0064-set-idle-disconnect-to-true-in-all-cases.patch \ file://0068-i2c-aspeed-add-H-W-timeout-support.patch \ file://0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch \ file://0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch \ - file://0071-peci-add-a-temporary-workaround.patch \ file://0072-pmbus-add-fault-and-beep-attributes.patch \ + file://0073-Add-IO-statistics-to-USB-Mass-storage-gadget.patch \ + file://0074-media-aspeed-refine-HSYNC-VSYNC-polarity-setting-log.patch \ + file://0075-Refine-initialization-flow-in-I2C-driver.patch \ + file://0076-media-aspeed-clear-garbage-interrupts.patch \ " + +SRC_URI += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'file://0005-128MB-flashmap-for-PFR.patch', '', d)}" -- cgit v1.2.3